1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/string.hxx>
21 #include <sal/log.hxx>
22 #include <sal/types.h>
23 #include <rtl/strbuf.hxx>
24 #include <tools/inetmsg.hxx>
25 #include <tools/inetstrm.hxx>
29 inline bool SAL_CALL
ascii_isWhitespace( sal_Unicode ch
)
31 return ((ch
<= 0x20) && ch
);
34 /** Quoted-Printable Encoding */
35 class INetMessageEncodeQPStream_Impl
: public INetMessageIStream
39 sal_uIntPtr nMsgBufSiz
;
44 sal_uIntPtr nTokBufSiz
;
49 INetMessageStreamState eState
;
52 virtual int GetMsgLine(sal_Char
* pData
, sal_uIntPtr nSize
) SAL_OVERRIDE
;
55 INetMessageEncodeQPStream_Impl(sal_uIntPtr nMsgBufferSize
= 1024);
56 virtual ~INetMessageEncodeQPStream_Impl();
59 /** Quoted-Printable Decoding */
60 class INetMessageDecodeQPStream_Impl
: public INetMessageOStream
62 INetMessageStreamState eState
;
63 SvMemoryStream
*pMsgBuffer
;
65 sal_uIntPtr nTokBufLen
;
66 sal_Char pTokBuffer
[4];
68 virtual int PutMsgLine(const sal_Char
* pData
, sal_uIntPtr nSize
) SAL_OVERRIDE
;
71 INetMessageDecodeQPStream_Impl();
72 virtual ~INetMessageDecodeQPStream_Impl();
75 /** Base64 Encoding */
76 class INetMessageEncode64Stream_Impl
: public INetMessageIStream
80 sal_uIntPtr nMsgBufSiz
;
81 sal_uInt8
* pMsgBuffer
;
85 sal_uIntPtr nTokBufSiz
;
92 virtual int GetMsgLine(sal_Char
* pData
, sal_uIntPtr nSize
) SAL_OVERRIDE
;
95 INetMessageEncode64Stream_Impl(sal_uIntPtr nMsgBufferSize
= 2048);
96 virtual ~INetMessageEncode64Stream_Impl();
99 /** Base64 Decoding */
100 class INetMessageDecode64Stream_Impl
: public INetMessageOStream
102 INetMessageStreamState eState
;
104 sal_uIntPtr nMsgBufSiz
;
105 sal_Char
* pMsgBuffer
;
109 virtual int PutMsgLine(const sal_Char
* pData
, sal_uIntPtr nSize
) SAL_OVERRIDE
;
112 INetMessageDecode64Stream_Impl(sal_uIntPtr nMsgBufferSize
= 128);
113 virtual ~INetMessageDecode64Stream_Impl();
116 // INetMessageIStream
118 INetMessageIStream::INetMessageIStream(sal_uIntPtr nBufferSize
)
120 , bHeaderGenerated(false)
121 , nBufSiz(nBufferSize
)
123 , pMsgBuffer(new SvMemoryStream
)
127 pMsgBuffer
->SetStreamCharSet(RTL_TEXTENCODING_ASCII_US
);
128 pBuffer
= new sal_Char
[nBufSiz
];
129 pRead
= pWrite
= pBuffer
;
132 INetMessageIStream::~INetMessageIStream()
139 int INetMessageIStream::Read(sal_Char
* pData
, sal_uIntPtr nSize
)
141 if (pSourceMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
143 sal_Char
* pWBuf
= pData
;
144 sal_Char
* pWEnd
= pData
+ nSize
;
146 while (pWBuf
< pWEnd
)
148 // Caller's buffer not yet filled.
149 sal_uIntPtr n
= pRead
- pWrite
;
152 // Bytes still in buffer.
153 sal_uIntPtr m
= pWEnd
- pWBuf
;
155 for (sal_uIntPtr i
= 0; i
< n
; i
++) *pWBuf
++ = *pWrite
++;
159 // Buffer empty. Reset to <Begin-of-Buffer>.
160 pRead
= pWrite
= pBuffer
;
162 // Read next message line.
163 int nRead
= GetMsgLine(pBuffer
, nBufSiz
);
167 pRead
= pBuffer
+ nRead
;
171 if (!bHeaderGenerated
)
173 // Header generated. Insert empty line.
174 bHeaderGenerated
= true;
181 return (pWBuf
- pData
);
186 return (pWBuf
- pData
);
189 int INetMessageIStream::GetMsgLine(sal_Char
* pData
, sal_uIntPtr nSize
)
191 if (pSourceMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
193 sal_Char
* pWBuf
= pData
;
194 sal_Char
* pWEnd
= pData
+ nSize
;
196 if (!bHeaderGenerated
)
200 if (pMsgBuffer
->Tell() == 0)
202 // Insert formatted header into buffer.
203 n
= pSourceMsg
->GetHeaderCount();
204 for (i
= 0; i
< n
; i
++)
206 INetMessageHeader
aHeader (pSourceMsg
->GetHeaderField(i
));
207 if (aHeader
.GetValue().getLength())
209 // NYI: Folding long lines.
210 pMsgBuffer
->WriteCharPtr( aHeader
.GetName().getStr() );
211 pMsgBuffer
->WriteCharPtr( ": " );
212 pMsgBuffer
->WriteCharPtr( aHeader
.GetValue().getStr() );
213 pMsgBuffer
->WriteCharPtr( "\r\n" );
217 pMsgWrite
= const_cast<char *>(static_cast<sal_Char
const *>(pMsgBuffer
->GetData()));
218 pMsgRead
= pMsgWrite
+ pMsgBuffer
->Tell();
221 n
= pMsgRead
- pMsgWrite
;
225 if (nSize
< n
) n
= nSize
;
226 for (i
= 0; i
< n
; i
++) *pWBuf
++ = *pMsgWrite
++;
231 pMsgBuffer
->Seek(STREAM_SEEK_TO_BEGIN
);
236 if (pSourceMsg
->GetDocumentLB())
238 if (pMsgStrm
== NULL
)
239 pMsgStrm
= new SvStream (pSourceMsg
->GetDocumentLB());
241 sal_uIntPtr nRead
= pMsgStrm
->Read(pWBuf
, (pWEnd
- pWBuf
));
245 return (pWBuf
- pData
);
248 // INetMessageOStream
250 INetMessageOStream::INetMessageOStream()
252 bHeaderParsed (false),
253 eOState (INETMSG_EOL_BEGIN
),
254 pMsgBuffer (new SvMemoryStream
)
258 INetMessageOStream::~INetMessageOStream()
260 if (pMsgBuffer
->Tell() > 0)
261 PutMsgLine(static_cast<const sal_Char
*>(pMsgBuffer
->GetData()), pMsgBuffer
->Tell());
266 SvOpenLockBytes
* pLB
= PTR_CAST(SvOpenLockBytes
, pTargetMsg
->GetDocumentLB());
275 /// Simple Field Parsing (RFC822, Appendix B)
276 int INetMessageOStream::Write(const sal_Char
* pData
, sal_uIntPtr nSize
)
278 if (pTargetMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
280 const sal_Char
* pStop
= (pData
+ nSize
);
282 while (!bHeaderParsed
&& (pData
< pStop
))
284 if (eOState
== INETMSG_EOL_BEGIN
)
286 if ((*pData
== '\r') || (*pData
== '\n'))
289 * Empty Line. Separates header fields from message body.
290 * Skip this and any 2nd line break character (if any).
293 if ((pData
< pStop
) && ((*pData
== '\r') || (*pData
== '\n')))
296 // Emit any buffered last header field.
297 if (pMsgBuffer
->Tell() > 0)
299 pMsgBuffer
->WriteChar( '\0' );
300 int status
= PutMsgLine( static_cast<const sal_Char
*>(pMsgBuffer
->GetData()),
302 if (status
!= INETSTREAM_STATUS_OK
) return status
;
306 eOState
= INETMSG_EOL_BEGIN
;
307 pMsgBuffer
->Seek(STREAM_SEEK_TO_BEGIN
);
309 // Mark header parsed.
310 bHeaderParsed
= true;
312 else if ((*pData
== ' ') || (*pData
== '\t'))
314 // Continuation line. Unfold multi-line field-body.
315 pMsgBuffer
->WriteChar( ' ' );
320 // Begin of new header field.
321 if (pMsgBuffer
->Tell() > 0)
323 // Emit buffered header field now.
324 pMsgBuffer
->WriteChar( '\0' );
325 int status
= PutMsgLine(static_cast<const sal_Char
*>(pMsgBuffer
->GetData()),
327 if (status
!= INETSTREAM_STATUS_OK
) return status
;
330 // Reset to begin of buffer.
331 pMsgBuffer
->Seek(STREAM_SEEK_TO_BEGIN
);
333 // Insert current character into buffer.
334 pMsgBuffer
->WriteChar( *pData
++ );
337 // Search for next line break character.
338 if (!bHeaderParsed
) eOState
= INETMSG_EOL_SCR
;
340 else if (eOState
== INETMSG_EOL_FCR
)
342 // Skip line break character.
345 // Mark begin of line.
346 eOState
= INETMSG_EOL_BEGIN
;
348 else if ((*pData
== '\r') || (*pData
== '\n'))
350 if (*pData
== '\r') pData
++;
351 eOState
= INETMSG_EOL_FCR
;
353 else if (ascii_isWhitespace(*pData
& 0x7f))
355 // Any <LWS> is folded into a single <SP> character.
356 sal_Char c
= *(static_cast<const sal_Char
*>(pMsgBuffer
->GetData()) + pMsgBuffer
->Tell() - 1);
357 if (!ascii_isWhitespace(c
& 0x7f)) pMsgBuffer
->WriteChar( ' ' );
359 // Skip over this <LWS> character.
364 // Any other character is inserted into line buffer.
365 pMsgBuffer
->WriteChar( *pData
++ );
369 if (bHeaderParsed
&& (pData
< pStop
))
371 // Put message body down-stream.
372 return PutMsgLine(pData
, (pStop
- pData
));
375 return INETSTREAM_STATUS_OK
;
378 int INetMessageOStream::PutMsgLine(const sal_Char
* pData
, sal_uIntPtr nSize
)
380 // Check for message container.
381 if (pTargetMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
383 // Check for header or body.
384 if (!IsHeaderParsed())
386 OString
aField(pData
);
387 sal_Int32 nPos
= aField
.indexOf(':');
390 OString
aName( aField
.copy(0, nPos
));
391 OString
aValue( aField
.copy(nPos
+ 1, aField
.getLength() - nPos
+ 1));
392 aValue
= comphelper::string::stripStart(aValue
, ' ');
394 pTargetMsg
->SetHeaderField( INetMessageHeader (aName
, aValue
));
399 SvOpenLockBytes
*pLB
= PTR_CAST(SvOpenLockBytes
, pTargetMsg
->GetDocumentLB());
401 return INETSTREAM_STATUS_WOULDBLOCK
;
403 sal_Size nDocSiz
= pTargetMsg
->GetDocumentSize();
406 pLB
->FillAppend(pData
, nSize
, &nWrite
);
407 pTargetMsg
->SetDocumentSize(nDocSiz
+ nWrite
);
409 if (nWrite
< nSize
) return INETSTREAM_STATUS_ERROR
;
411 return INETSTREAM_STATUS_OK
;
414 // INetMessageEncodeQPStream_Impl
416 static const sal_Char hex2pr
[16] = {
417 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
418 'A', 'B', 'C', 'D', 'E', 'F'
421 INetMessageEncodeQPStream_Impl::INetMessageEncodeQPStream_Impl( sal_uIntPtr nMsgBufferSize
)
422 : INetMessageIStream (),
424 nMsgBufSiz (nMsgBufferSize
),
426 eState (INETMSG_EOL_SCR
),
429 SetHeaderGenerated();
431 pMsgBuffer
= new sal_Char
[nMsgBufSiz
];
432 pMsgRead
= pMsgWrite
= pMsgBuffer
;
434 pTokBuffer
= new sal_Char
[nTokBufSiz
];
435 pTokRead
= pTokWrite
= pTokBuffer
;
438 INetMessageEncodeQPStream_Impl::~INetMessageEncodeQPStream_Impl()
441 delete [] pMsgBuffer
;
442 delete [] pTokBuffer
;
445 int INetMessageEncodeQPStream_Impl::GetMsgLine(sal_Char
* pData
, sal_uIntPtr nSize
)
447 INetMIMEMessage
* pMsg
= GetSourceMessage();
448 if (pMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
450 if (pMsg
->GetDocumentLB() == NULL
) return 0;
451 if (pMsgStrm
== NULL
) pMsgStrm
= new SvStream(pMsg
->GetDocumentLB());
453 sal_Char
* pWBuf
= pData
;
454 while (pWBuf
< (pData
+ nSize
))
456 // Caller's buffer not yet filled.
457 if ((pMsgRead
- pMsgWrite
) > 0)
459 // Bytes still in message buffer.
460 if ((eState
!= INETMSG_EOL_BEGIN
) &&
461 ((pTokRead
- pTokBuffer
) < 72))
463 // Token buffer not yet filled.
464 if (eState
== INETMSG_EOL_FCR
)
466 eState
= INETMSG_EOL_BEGIN
;
467 if (*pMsgWrite
!= '\n')
469 // Convert orphant <CR> into <CR><LF> sequence.
472 *pTokRead
++ = *pMsgWrite
++;
474 else if ((*pMsgWrite
== ' ') || (*pMsgWrite
== '\t'))
476 eState
= INETMSG_EOL_FSP
;
477 *pTokRead
++ = *pMsgWrite
++;
479 else if (*pMsgWrite
== '\r')
482 if (eState
== INETMSG_EOL_FSP
)
484 // Encode last (trailing space) character.
485 sal_uInt8 c
= (sal_uInt8
)(*(--pTokRead
));
487 *pTokRead
++ = hex2pr
[((c
& 0xf0) >> 4)];
488 *pTokRead
++ = hex2pr
[((c
& 0x0f) )];
490 eState
= INETMSG_EOL_FCR
;
491 *pTokRead
++ = *pMsgWrite
++;
493 else if (*pMsgWrite
== '\n')
496 if (eState
== INETMSG_EOL_FSP
)
498 // Encode last (trailing space) character.
499 sal_uInt8 c
= (sal_uInt8
)(*(--pTokRead
));
501 *pTokRead
++ = hex2pr
[((c
& 0xf0) >> 4)];
502 *pTokRead
++ = hex2pr
[((c
& 0x0f) )];
504 eState
= INETMSG_EOL_BEGIN
;
506 // Convert orphant <LF> into <CR><LF> sequence.
508 *pTokRead
++ = *pMsgWrite
++;
510 else if (*pMsgWrite
== '=')
512 // Escape character itself MUST be encoded, of course.
513 sal_uInt8 c
= (sal_uInt8
)(*pMsgWrite
++);
515 *pTokRead
++ = hex2pr
[((c
& 0xf0) >> 4)];
516 *pTokRead
++ = hex2pr
[((c
& 0x0f) )];
518 eState
= INETMSG_EOL_SCR
;
520 else if (((sal_uInt8
)(*pMsgWrite
) > 0x20) &&
521 ((sal_uInt8
)(*pMsgWrite
) < 0x7f) )
524 * Some printable ASCII character.
525 * (Encode EBCDIC special characters (NYI)).
527 *pTokRead
++ = *pMsgWrite
++;
528 eState
= INETMSG_EOL_SCR
;
532 // Encode any other character.
533 sal_uInt8 c
= (sal_uInt8
)(*pMsgWrite
++);
535 *pTokRead
++ = hex2pr
[((c
& 0xf0) >> 4)];
536 *pTokRead
++ = hex2pr
[((c
& 0x0f) )];
538 eState
= INETMSG_EOL_SCR
;
543 // Check for maximum line length.
544 if (eState
!= INETMSG_EOL_BEGIN
)
546 // Insert soft line break.
551 eState
= INETMSG_EOL_BEGIN
;
554 // Copy to caller's buffer.
555 if ((pTokRead
- pTokWrite
) > 0)
557 // Bytes still in token buffer.
558 *pWBuf
++ = *pTokWrite
++;
562 // Token buffer empty. Reset to <Begin-of-Buffer>.
563 pTokRead
= pTokWrite
= pTokBuffer
;
564 eState
= INETMSG_EOL_SCR
;
570 // Message buffer empty. Reset to <Begin-of-Buffer>.
571 pMsgRead
= pMsgWrite
= pMsgBuffer
;
573 // Read next message block.
574 sal_uIntPtr nRead
= pMsgStrm
->Read(pMsgBuffer
, nMsgBufSiz
);
578 pMsgRead
= (pMsgBuffer
+ nRead
);
582 // Nothing more ro read.
585 // Append final <CR><LF> and mark we're done.
593 // Already done all encoding.
594 if ((pTokRead
- pTokWrite
) > 0)
596 // Bytes still in token buffer.
597 *pWBuf
++ = *pTokWrite
++;
601 // Token buffer empty. Reset to <Begin-of-Buffer>.
602 pTokRead
= pTokWrite
= pTokBuffer
;
605 return (pWBuf
- pData
);
611 return (pWBuf
- pData
);
614 // INetMessageDecodeQPStream_Impl
616 static const sal_uInt8 pr2hex
[128] = {
617 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
618 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
619 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
620 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
622 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
623 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
624 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
625 0x08, 0x09, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
627 0x10, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
628 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
629 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
630 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
632 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
633 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
634 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
635 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
638 INetMessageDecodeQPStream_Impl::INetMessageDecodeQPStream_Impl()
639 : INetMessageOStream(),
640 eState (INETMSG_EOL_BEGIN
),
641 pMsgBuffer (new SvMemoryStream
),
647 INetMessageDecodeQPStream_Impl::~INetMessageDecodeQPStream_Impl()
652 int INetMessageDecodeQPStream_Impl::PutMsgLine( const sal_Char
* pData
,
655 INetMIMEMessage
* pMsg
= GetTargetMessage();
656 if (pMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
658 SvOpenLockBytes
* pLB
= PTR_CAST(SvOpenLockBytes
, pMsg
->GetDocumentLB());
659 if (pLB
== NULL
) return INETSTREAM_STATUS_WOULDBLOCK
;
661 const sal_Char
* pStop
= pData
+ nSize
;
662 while (pData
< pStop
)
664 if (eState
== INETMSG_EOL_FESC
)
666 *(pTokBuffer
+ nTokBufLen
++) = static_cast< char >(toupper(*pData
));
670 if ((*pTokBuffer
== '\r') || (*pTokBuffer
== '\n'))
672 // Soft line break (=<CR><LF>). Emit buffer now.
673 eState
= INETMSG_EOL_BEGIN
;
678 pMsgBuffer
->WriteUChar( sal_uInt8 (
679 (pr2hex
[(int)(pTokBuffer
[0] & 0x7f)] << 4) |
680 (pr2hex
[(int)(pTokBuffer
[1] & 0x7f)] & 15) ) );
682 // Search for next <CR>.
683 eState
= INETMSG_EOL_SCR
;
686 // Reset token buffer.
690 else if (*pData
== '=')
692 // Found escape character.
694 eState
= INETMSG_EOL_FESC
;
696 else if (eState
== INETMSG_EOL_FCR
)
698 pMsgBuffer
->WriteChar( *pData
++ );
699 eState
= INETMSG_EOL_BEGIN
;
701 else if (*pData
== '\r')
703 pMsgBuffer
->WriteChar( *pData
++ );
704 eState
= INETMSG_EOL_FCR
;
708 pMsgBuffer
->WriteChar( *pData
++ );
711 if (eState
== INETMSG_EOL_BEGIN
)
713 sal_Size nRead
= pMsgBuffer
->Tell();
717 sal_Size nDocSiz
= pMsg
->GetDocumentSize();
720 pLB
->FillAppend(pMsgBuffer
->GetData(), nRead
, &nWrite
);
721 pMsg
->SetDocumentSize(nDocSiz
+ nWrite
);
723 if (nWrite
< nRead
) return INETSTREAM_STATUS_ERROR
;
725 pMsgBuffer
->Seek(STREAM_SEEK_TO_BEGIN
);
727 eState
= INETMSG_EOL_SCR
;
730 return INETSTREAM_STATUS_OK
;
733 // INetMessageEncode64Stream_Impl
735 static const sal_Char six2pr
[64] = {
736 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
737 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
738 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
739 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
740 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
743 INetMessageEncode64Stream_Impl::INetMessageEncode64Stream_Impl(
744 sal_uIntPtr nMsgBufferSize
)
745 : INetMessageIStream(),
747 nMsgBufSiz (nMsgBufferSize
),
751 SetHeaderGenerated();
753 pMsgBuffer
= new sal_uInt8
[nMsgBufSiz
];
754 pMsgRead
= pMsgWrite
= pMsgBuffer
;
756 pTokBuffer
= new sal_Char
[nTokBufSiz
];
757 pTokRead
= pTokWrite
= pTokBuffer
;
760 INetMessageEncode64Stream_Impl::~INetMessageEncode64Stream_Impl()
763 delete [] pMsgBuffer
;
764 delete [] pTokBuffer
;
767 int INetMessageEncode64Stream_Impl::GetMsgLine(sal_Char
* pData
, sal_uIntPtr nSize
)
769 INetMIMEMessage
* pMsg
= GetSourceMessage();
770 if (pMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
772 if (pMsg
->GetDocumentLB() == NULL
) return 0;
773 if (pMsgStrm
== NULL
) pMsgStrm
= new SvStream(pMsg
->GetDocumentLB());
775 sal_Char
* pWBuf
= pData
;
776 while (pWBuf
< (pData
+ nSize
))
778 // Caller's buffer not yet filled.
779 if ((pMsgRead
- pMsgWrite
) > 0)
781 // Bytes still in message buffer.
782 if ((pTokRead
- pTokBuffer
) < 72)
784 // Token buffer not yet filled.
785 switch ((pTokRead
- pTokBuffer
) % 4)
788 *pTokRead
++ = six2pr
[(int)(*pMsgWrite
>> 2)];
792 *pTokRead
++ = six2pr
[ (int)(((*pMsgWrite
<< 4) & 060) |
793 (((*(pMsgWrite
+ 1)) >> 4) & 017))];
798 *pTokRead
++ = six2pr
[ (int)(((*pMsgWrite
<< 2) & 074) |
799 (((*(pMsgWrite
+ 1)) >> 6) & 003))];
803 default: // == case 3
804 *pTokRead
++ = six2pr
[(int)(*pMsgWrite
& 077)];
809 else if ((pTokRead
- pTokBuffer
) == 72)
811 // Maximum line length. Append <CR><LF>.
817 if ((pTokRead
- pTokWrite
) > 0)
819 // Bytes still in token buffer.
820 *pWBuf
++ = *pTokWrite
++;
824 // Token buffer empty. Reset to <Begin-of-Buffer>.
825 pTokRead
= pTokWrite
= pTokBuffer
;
831 // Message buffer empty. Reset to <Begin-of-Buffer>.
832 pMsgRead
= pMsgWrite
= pMsgBuffer
;
834 // Read next message block.
835 sal_uIntPtr nRead
= pMsgStrm
->Read(pMsgBuffer
, nMsgBufSiz
);
839 pMsgRead
= (pMsgBuffer
+ nRead
);
843 // Nothing more to read.
846 // Append pad character(s) and final <CR><LF>.
847 switch ((pTokRead
- pTokBuffer
) % 4)
851 // Fall through for 2nd pad character.
867 // Already done all encoding.
868 if ((pTokRead
- pTokWrite
) > 0)
870 // Bytes still in token buffer.
871 *pWBuf
++ = *pTokWrite
++;
875 // Token buffer empty. Reset to <Begin-of-Buffer>.
876 pTokRead
= pTokWrite
= pTokBuffer
;
878 // Reset done flag, if everything has been done.
879 // if (pWBuf == pData) bDone = false;
882 return (pWBuf
- pData
);
887 } // while (pWBuf < (pData + nSize))
888 return (pWBuf
- pData
);
891 // INetMessageDecode64Stream_Impl
893 static const sal_uInt8 pr2six
[256] = {
894 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
895 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
896 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
897 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
899 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
900 0x40, 0x40, 0x40, 0x3E, 0x40, 0x40, 0x40, 0x3F,
901 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
902 0x3C, 0x3D, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
904 0x40, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
905 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
906 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
907 0x17, 0x18, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40,
909 0x40, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
910 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
911 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
912 0x31, 0x32, 0x33, 0x40, 0x40, 0x40, 0x40, 0x40,
914 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
915 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
916 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
917 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
919 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
920 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
921 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
922 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
924 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
925 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
926 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
927 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
929 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
930 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
931 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
932 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
935 INetMessageDecode64Stream_Impl::INetMessageDecode64Stream_Impl(
936 sal_uIntPtr nMsgBufferSize
)
937 : INetMessageOStream(),
938 eState (INETMSG_EOL_SCR
),
939 nMsgBufSiz (nMsgBufferSize
)
943 pMsgBuffer
= new sal_Char
[nMsgBufSiz
];
944 pMsgRead
= pMsgWrite
= pMsgBuffer
;
947 INetMessageDecode64Stream_Impl::~INetMessageDecode64Stream_Impl()
949 delete [] pMsgBuffer
;
952 int INetMessageDecode64Stream_Impl::PutMsgLine(const sal_Char
* pData
,
955 INetMIMEMessage
* pMsg
= GetTargetMessage();
956 if (pMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
958 SvOpenLockBytes
* pLB
= PTR_CAST(SvOpenLockBytes
, pMsg
->GetDocumentLB());
959 if (pLB
== NULL
) return INETSTREAM_STATUS_WOULDBLOCK
;
961 const sal_Char
* pStop
= (pData
+ nSize
);
962 while (pData
< pStop
)
964 if (pr2six
[(int)(*pData
)] > 63)
967 * Character not in base64 alphabet.
968 * Check for <End-of-Stream> or Junk.
972 // Final pad character -> Done.
973 sal_Size nDocSiz
= pMsg
->GetDocumentSize();
974 sal_Size nRead
= pMsgWrite
- pMsgBuffer
;
977 pLB
->FillAppend(pMsgBuffer
, nRead
, &nWrite
);
978 pMsg
->SetDocumentSize(nDocSiz
+ nWrite
);
981 return INETSTREAM_STATUS_ERROR
;
983 return INETSTREAM_STATUS_LOADED
;
985 else if (eState
== INETMSG_EOL_FCR
)
987 // Skip any line break character.
988 if ((*pData
== '\r') || (*pData
== '\n')) pData
++;
990 // Store decoded message buffer contents.
991 sal_Size nDocSiz
= pMsg
->GetDocumentSize();
992 sal_Size nRead
= pMsgWrite
- pMsgBuffer
;
995 pLB
->FillAppend(pMsgBuffer
, nRead
, &nWrite
);
996 pMsg
->SetDocumentSize(nDocSiz
+ nWrite
);
998 if (nWrite
< nRead
) return INETSTREAM_STATUS_ERROR
;
1000 // Reset to <Begin-of-Buffer>.
1001 pMsgWrite
= pMsgBuffer
;
1002 eState
= INETMSG_EOL_SCR
;
1004 else if ((*pData
== '\r') || (*pData
== '\n'))
1006 // Skip any line break character.
1008 eState
= INETMSG_EOL_FCR
;
1012 // Skip any junk character (may be transmission error).
1018 // Decode any other character into message buffer.
1019 switch ((pMsgRead
- pMsgBuffer
) % 4)
1022 *pMsgWrite
= (pr2six
[(int)(*pData
++)] << 2);
1027 *pMsgWrite
++ |= (pr2six
[(int)(*pData
)] >> 4);
1028 *pMsgWrite
= (pr2six
[(int)(*pData
++)] << 4);
1033 *pMsgWrite
++ |= (pr2six
[(int)(*pData
)] >> 2);
1034 *pMsgWrite
= (pr2six
[(int)(*pData
++)] << 6);
1038 default: // == case 3
1039 *pMsgWrite
++ |= (pr2six
[(int)(*pData
++)]);
1040 pMsgRead
= pMsgBuffer
;
1042 } // switch ((pMsgRead - pMsgBuffer) % 4)
1044 } // while (pData < pStop)
1045 return INETSTREAM_STATUS_OK
;
1048 // INetMIMEMessageStream
1050 INetMIMEMessageStream::INetMIMEMessageStream(sal_uIntPtr nBufferSize
)
1051 : INetMessageIStream(nBufferSize
),
1052 eState (INETMSG_EOL_BEGIN
),
1055 eEncoding (INETMSG_ENCODING_BINARY
),
1062 INetMIMEMessageStream::~INetMIMEMessageStream()
1071 INetMIMEMessageStream::GetMsgEncoding(const OUString
& rContentType
)
1073 if (rContentType
.startsWithIgnoreAsciiCase("message") ||
1074 rContentType
.startsWithIgnoreAsciiCase("multipart"))
1076 return INETMSG_ENCODING_7BIT
;
1078 if (rContentType
.startsWithIgnoreAsciiCase("text"))
1080 if (rContentType
.startsWithIgnoreAsciiCase("text/plain"))
1082 if (comphelper::string::getTokenCount(rContentType
, '=') > 1)
1084 OUString
aCharset(rContentType
.getToken(1, '='));
1085 aCharset
= comphelper::string::stripStart(aCharset
, ' ');
1086 aCharset
= comphelper::string::stripStart(aCharset
, '"');
1088 if (aCharset
.startsWithIgnoreAsciiCase("us-ascii"))
1089 return INETMSG_ENCODING_7BIT
;
1091 return INETMSG_ENCODING_QUOTED
;
1094 return INETMSG_ENCODING_7BIT
;
1097 return INETMSG_ENCODING_QUOTED
;
1100 return INETMSG_ENCODING_BASE64
;
1103 /// Message Generator
1104 int INetMIMEMessageStream::GetMsgLine(sal_Char
* pData
, sal_uIntPtr nSize
)
1106 // Check for message container.
1107 INetMIMEMessage
* pMsg
= GetSourceMessage();
1108 if (pMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
1110 // Check for header or body.
1111 if (!IsHeaderGenerated())
1113 if (eState
== INETMSG_EOL_BEGIN
)
1115 // Prepare special header fields.
1116 if (pMsg
->GetParent())
1118 OUString
aPCT(pMsg
->GetParent()->GetContentType());
1119 if (aPCT
.startsWithIgnoreAsciiCase("message/rfc822"))
1120 pMsg
->SetMIMEVersion("1.0");
1122 pMsg
->SetMIMEVersion(OUString());
1126 pMsg
->SetMIMEVersion("1.0");
1129 // Check ContentType.
1130 OUString
aContentType(pMsg
->GetContentType());
1131 if (!aContentType
.isEmpty())
1133 // Determine default Content-Type.
1134 OUString aDefaultType
= pMsg
->GetDefaultContentType();
1136 if (aDefaultType
.equalsIgnoreAsciiCase(aContentType
))
1138 // No need to specify default.
1139 pMsg
->SetContentType(OUString());
1144 OUString
aEncoding(pMsg
->GetContentTransferEncoding());
1145 if (!aEncoding
.isEmpty())
1147 // Use given Encoding.
1148 if (aEncoding
.startsWithIgnoreAsciiCase("base64"))
1150 eEncoding
= INETMSG_ENCODING_BASE64
;
1152 else if (aEncoding
.startsWithIgnoreAsciiCase("quoted-printable"))
1154 eEncoding
= INETMSG_ENCODING_QUOTED
;
1158 eEncoding
= INETMSG_ENCODING_7BIT
;
1163 // Use default Encoding for (given|default) Content-Type.
1164 if (aContentType
.isEmpty())
1166 // Determine default Content-Type.
1167 aContentType
= pMsg
->GetDefaultContentType();
1169 eEncoding
= GetMsgEncoding(aContentType
);
1172 // Set Content-Transfer-Encoding header.
1173 if (eEncoding
== INETMSG_ENCODING_BASE64
)
1176 pMsg
->SetContentTransferEncoding("base64");
1178 else if (eEncoding
== INETMSG_ENCODING_QUOTED
)
1180 // Quoted-Printable.
1181 pMsg
->SetContentTransferEncoding("quoted-printable");
1185 // No need to specify default.
1186 pMsg
->SetContentTransferEncoding(OUString());
1190 eState
= INETMSG_EOL_DONE
;
1193 // Generate the message header.
1194 int nRead
= INetMessageIStream::GetMsgLine(pData
, nSize
);
1198 eState
= INETMSG_EOL_BEGIN
;
1204 // Generate the message body.
1205 if (pMsg
->IsContainer())
1207 // Encapsulated message body.
1208 while (eState
== INETMSG_EOL_BEGIN
)
1210 if (pChildStrm
== NULL
)
1212 INetMIMEMessage
*pChild
= pMsg
->GetChild(nChildIndex
);
1215 // Increment child index.
1218 // Create child stream.
1219 pChildStrm
= new INetMIMEMessageStream
;
1220 pChildStrm
->SetSourceMessage(pChild
);
1222 if (pMsg
->IsMultipart())
1224 // Insert multipart delimiter.
1225 OStringBuffer
aDelim("--");
1226 aDelim
.append(pMsg
->GetMultipartBoundary());
1227 aDelim
.append("\r\n");
1229 memcpy(pData
, aDelim
.getStr(),
1230 aDelim
.getLength());
1231 return aDelim
.getLength();
1236 // No more parts. Mark we're done.
1237 eState
= INETMSG_EOL_DONE
;
1240 if (pMsg
->IsMultipart())
1242 // Insert close delimiter.
1243 OStringBuffer
aDelim("--");
1244 aDelim
.append(pMsg
->GetMultipartBoundary());
1245 aDelim
.append("--\r\n");
1247 memcpy(pData
, aDelim
.getStr(),
1248 aDelim
.getLength());
1249 return aDelim
.getLength();
1255 // Read current child stream.
1256 int nRead
= pChildStrm
->Read(pData
, nSize
);
1263 // Cleanup exhausted child stream.
1273 // Single part message body.
1274 if (pMsg
->GetDocumentLB() == NULL
)
1276 // Empty message body.
1280 // Check whether message body needs to be encoded.
1281 if (eEncoding
== INETMSG_ENCODING_7BIT
)
1284 return INetMessageIStream::GetMsgLine(pData
, nSize
);
1287 // Apply appropriate Encoding.
1288 while (eState
== INETMSG_EOL_BEGIN
)
1290 if (pEncodeStrm
== NULL
)
1292 // Create encoder stream.
1293 if (eEncoding
== INETMSG_ENCODING_QUOTED
)
1295 // Quoted-Printable Encoding.
1296 pEncodeStrm
= new INetMessageEncodeQPStream_Impl
;
1301 pEncodeStrm
= new INetMessageEncode64Stream_Impl
;
1303 pEncodeStrm
->SetSourceMessage(pMsg
);
1306 // Read encoded message.
1307 int nRead
= pEncodeStrm
->Read(pData
, nSize
);
1314 // Cleanup exhausted encoder stream.
1319 eState
= INETMSG_EOL_DONE
;
1328 int INetMIMEMessageStream::PutMsgLine(const sal_Char
* pData
, sal_uIntPtr nSize
)
1330 // Check for message container.
1331 INetMIMEMessage
* pMsg
= GetTargetMessage();
1332 if (pMsg
== NULL
) return INETSTREAM_STATUS_ERROR
;
1334 // Check for header or body.
1335 if (!IsHeaderParsed())
1337 // Parse the message header.
1338 int nRet
= INetMessageOStream::PutMsgLine(pData
, nSize
);
1343 pMsg
->SetHeaderParsed();
1344 // Parse the message body.
1345 if (pMsg
->IsContainer())
1348 // Content-Transfer-Encoding MUST be "7bit" (RFC1521).
1349 if (pMsg
->IsMessage())
1353 // Encapsulated message.
1354 INetMIMEMessage
* pNewMessage
= new INetMIMEMessage
;
1355 pNewMessage
->SetDocumentLB( new SvAsyncLockBytes(new SvMemoryStream(), false));
1356 pMsg
->AttachChild( *pNewMessage
, true );
1358 // Encapsulated message body. Create message parser stream.
1359 pChildStrm
= new INetMIMEMessageStream
;
1360 pChildStrm
->SetTargetMessage( pNewMessage
);
1362 // Initialize control variables.
1363 eState
= INETMSG_EOL_BEGIN
;
1367 // Bytes still in buffer. Put message down-stream.
1368 int status
= pChildStrm
->Write( pData
, nSize
);
1369 if (status
!= INETSTREAM_STATUS_OK
)
1373 return INetMessageOStream::PutMsgLine(pData
, nSize
);
1378 // Multipart message body. Initialize multipart delimiters.
1379 // Multipart message.
1380 if (pMsg
->GetMultipartBoundary().getLength() == 0)
1382 // Determine boundary.
1383 OString
aType(OUStringToOString(
1384 pMsg
->GetContentType(), RTL_TEXTENCODING_ASCII_US
));
1385 OString
aLowerType(aType
.toAsciiLowerCase());
1387 sal_Int32 nPos
= aLowerType
.indexOf("boundary=");
1388 OString
aBoundary(aType
.copy(nPos
+ 9));
1390 aBoundary
= comphelper::string::strip(aBoundary
, ' ');
1391 aBoundary
= comphelper::string::strip(aBoundary
, '"');
1394 pMsg
->SetMultipartBoundary(aBoundary
);
1397 OString
aPlainDelim(pMsg
->GetMultipartBoundary());
1398 OString aDelim
= OStringBuffer("--").
1399 append(aPlainDelim
).
1400 makeStringAndClear();
1401 OString aPlainClose
= OStringBuffer(
1404 makeStringAndClear();
1405 OString aClose
= OStringBuffer(
1408 makeStringAndClear();
1410 if (pMsgBuffer
== NULL
) pMsgBuffer
= new SvMemoryStream
;
1411 pMsgBuffer
->Write(pData
, nSize
);
1412 sal_uIntPtr nBufSize
= pMsgBuffer
->Tell();
1414 const sal_Char
* pChar
;
1415 const sal_Char
* pOldPos
;
1417 for( pOldPos
= pChar
= static_cast<const sal_Char
*>(pMsgBuffer
->GetData()); nBufSize
--;
1420 if( *pChar
== '\r' || *pChar
== '\n' )
1422 if( aDelim
.compareTo(pOldPos
, aDelim
.getLength())
1424 aClose
.compareTo(pOldPos
, aClose
.getLength())
1426 aPlainDelim
.compareTo(pOldPos
, aPlainDelim
.getLength())
1428 aPlainClose
.compareTo(pOldPos
, aPlainClose
.getLength())
1432 ( pChar
[1] == '\r' || pChar
[1] == '\n' ) )
1433 nBufSize
--, pChar
++;
1436 status
= pChildStrm
->Write(
1437 pOldPos
, pChar
- pOldPos
+ 1 );
1438 if( status
!= INETSTREAM_STATUS_OK
)
1442 SAL_WARN( "tools.stream", "Boundary not found." );
1444 status
= INetMessageOStream::PutMsgLine(
1445 pOldPos
, pChar
- pOldPos
+ 1 );
1446 if( status
!= INETSTREAM_STATUS_OK
)
1448 pOldPos
= pChar
+ 1;
1453 ( pChar
[1] == '\r' || pChar
[1] == '\n' ) )
1454 nBufSize
--, pChar
++;
1455 pOldPos
= pChar
+ 1;
1456 DELETEZ( pChildStrm
);
1458 if (aClose
.compareTo(pOldPos
, aClose
.getLength())
1460 aPlainClose
.compareTo(pOldPos
, aClose
.getLength())
1463 // Encapsulated message.
1464 INetMIMEMessage
* pNewMessage
=
1465 new INetMIMEMessage
;
1466 pNewMessage
->SetDocumentLB(
1467 new SvAsyncLockBytes(
1468 new SvMemoryStream(), false));
1470 pMsg
->AttachChild( *pNewMessage
, true );
1472 // Encapsulated message body. Create message parser stream.
1473 pChildStrm
= new INetMIMEMessageStream
;
1474 pChildStrm
->SetTargetMessage( pNewMessage
);
1476 // Initialize control variables.
1478 eState
= INETMSG_EOL_BEGIN
;
1479 status
= INetMessageOStream::PutMsgLine(
1480 pOldPos
, pChar
- pOldPos
+ 1 );
1481 if( status
!= INETSTREAM_STATUS_OK
)
1486 if( pOldPos
< pChar
)
1488 SvMemoryStream
* pNewStream
= new SvMemoryStream
;
1489 pNewStream
->Write( pOldPos
, pChar
- pOldPos
);
1490 SvMemoryStream
* pTmp
= pMsgBuffer
;
1491 pMsgBuffer
= pNewStream
;
1496 pMsgBuffer
->Seek( 0L );
1497 pMsgBuffer
->SetStreamSize( 0 );
1499 return INETSTREAM_STATUS_OK
;
1505 * Single part message.
1506 * Remove any ContentTransferEncoding.
1508 if (pMsg
->GetContentType().isEmpty())
1510 pMsg
->SetContentType(pMsg
->GetDefaultContentType());
1513 if (eEncoding
== INETMSG_ENCODING_BINARY
)
1515 OUString
aEncoding(pMsg
->GetContentTransferEncoding());
1516 if (aEncoding
.startsWithIgnoreAsciiCase("base64"))
1518 eEncoding
= INETMSG_ENCODING_BASE64
;
1520 else if (aEncoding
.startsWithIgnoreAsciiCase("quoted-printable"))
1522 eEncoding
= INETMSG_ENCODING_QUOTED
;
1526 eEncoding
= INETMSG_ENCODING_7BIT
;
1530 if (eEncoding
== INETMSG_ENCODING_7BIT
)
1532 // No decoding necessary.
1533 return INetMessageOStream::PutMsgLine(pData
, nSize
);
1537 if (pDecodeStrm
== NULL
)
1539 if (eEncoding
== INETMSG_ENCODING_QUOTED
)
1541 pDecodeStrm
= new INetMessageDecodeQPStream_Impl
;
1545 pDecodeStrm
= new INetMessageDecode64Stream_Impl
;
1547 pDecodeStrm
->SetTargetMessage(pMsg
);
1549 return pDecodeStrm
->Write(pData
, nSize
);
1555 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */