Branch libreoffice-5-0-4
[LibreOffice.git] / tools / source / inet / inetstrm.cxx
blob80d68a07817f27deecbbbbceaa9eab2c0a89d8ce
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
27 #include <ctype.h>
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
37 SvStream* pMsgStrm;
39 sal_uIntPtr nMsgBufSiz;
40 sal_Char* pMsgBuffer;
41 sal_Char* pMsgRead;
42 sal_Char* pMsgWrite;
44 sal_uIntPtr nTokBufSiz;
45 sal_Char* pTokBuffer;
46 sal_Char* pTokRead;
47 sal_Char* pTokWrite;
49 INetMessageStreamState eState;
50 bool bDone;
52 virtual int GetMsgLine(sal_Char* pData, sal_uIntPtr nSize) SAL_OVERRIDE;
54 public:
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;
70 public:
71 INetMessageDecodeQPStream_Impl();
72 virtual ~INetMessageDecodeQPStream_Impl();
75 /** Base64 Encoding */
76 class INetMessageEncode64Stream_Impl : public INetMessageIStream
78 SvStream* pMsgStrm;
80 sal_uIntPtr nMsgBufSiz;
81 sal_uInt8* pMsgBuffer;
82 sal_uInt8* pMsgRead;
83 sal_uInt8* pMsgWrite;
85 sal_uIntPtr nTokBufSiz;
86 sal_Char* pTokBuffer;
87 sal_Char* pTokRead;
88 sal_Char* pTokWrite;
90 bool bDone;
92 virtual int GetMsgLine(sal_Char* pData, sal_uIntPtr nSize) SAL_OVERRIDE;
94 public:
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;
106 sal_Char* pMsgRead;
107 sal_Char* pMsgWrite;
109 virtual int PutMsgLine(const sal_Char* pData, sal_uIntPtr nSize) SAL_OVERRIDE;
111 public:
112 INetMessageDecode64Stream_Impl(sal_uIntPtr nMsgBufferSize = 128);
113 virtual ~INetMessageDecode64Stream_Impl();
116 // INetMessageIStream
118 INetMessageIStream::INetMessageIStream(sal_uIntPtr nBufferSize)
119 : pSourceMsg(NULL)
120 , bHeaderGenerated(false)
121 , nBufSiz(nBufferSize)
122 , pMsgStrm(NULL)
123 , pMsgBuffer(new SvMemoryStream)
124 , pMsgRead(NULL)
125 , pMsgWrite(NULL)
127 pMsgBuffer->SetStreamCharSet(RTL_TEXTENCODING_ASCII_US);
128 pBuffer = new sal_Char[nBufSiz];
129 pRead = pWrite = pBuffer;
132 INetMessageIStream::~INetMessageIStream()
134 delete [] pBuffer;
135 delete pMsgBuffer;
136 delete pMsgStrm;
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;
150 if (n > 0)
152 // Bytes still in buffer.
153 sal_uIntPtr m = pWEnd - pWBuf;
154 if (m < n) n = m;
155 for (sal_uIntPtr i = 0; i < n; i++) *pWBuf++ = *pWrite++;
157 else
159 // Buffer empty. Reset to <Begin-of-Buffer>.
160 pRead = pWrite = pBuffer;
162 // Read next message line.
163 int nRead = GetMsgLine(pBuffer, nBufSiz);
164 if (nRead > 0)
166 // Set read pointer.
167 pRead = pBuffer + nRead;
169 else
171 if (!bHeaderGenerated)
173 // Header generated. Insert empty line.
174 bHeaderGenerated = true;
175 *pRead++ = '\r';
176 *pRead++ = '\n';
178 else
180 // Body generated.
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)
198 sal_uIntPtr i, n;
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;
222 if (n > 0)
224 // Move to caller.
225 if (nSize < n) n = nSize;
226 for (i = 0; i < n; i++) *pWBuf++ = *pMsgWrite++;
228 else
230 // Reset buffer.
231 pMsgBuffer->Seek(STREAM_SEEK_TO_BEGIN);
234 else
236 if (pSourceMsg->GetDocumentLB())
238 if (pMsgStrm == NULL)
239 pMsgStrm = new SvStream (pSourceMsg->GetDocumentLB());
241 sal_uIntPtr nRead = pMsgStrm->Read(pWBuf, (pWEnd - pWBuf));
242 pWBuf += nRead;
245 return (pWBuf - pData);
248 // INetMessageOStream
250 INetMessageOStream::INetMessageOStream()
251 : pTargetMsg (NULL),
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());
262 delete pMsgBuffer;
264 if (pTargetMsg)
266 SvOpenLockBytes* pLB = PTR_CAST(SvOpenLockBytes, pTargetMsg->GetDocumentLB());
267 if (pLB)
269 pLB->Flush();
270 pLB->Terminate();
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).
292 pData++;
293 if ((pData < pStop) && ((*pData == '\r') || (*pData == '\n')))
294 pData++;
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()),
301 pMsgBuffer->Tell());
302 if (status != INETSTREAM_STATUS_OK) return status;
305 // Reset to begin.
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( ' ' );
316 pData++;
318 else
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()),
326 pMsgBuffer->Tell());
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.
343 pData++;
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.
360 pData++;
362 else
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(':');
388 if (nPos != -1)
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));
397 else
399 SvOpenLockBytes *pLB = PTR_CAST(SvOpenLockBytes, pTargetMsg->GetDocumentLB());
400 if (pLB == NULL)
401 return INETSTREAM_STATUS_WOULDBLOCK;
403 sal_Size nDocSiz = pTargetMsg->GetDocumentSize();
404 sal_Size nWrite = 0;
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 (),
423 pMsgStrm (NULL),
424 nMsgBufSiz (nMsgBufferSize),
425 nTokBufSiz (80),
426 eState (INETMSG_EOL_SCR),
427 bDone (false)
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()
440 delete pMsgStrm;
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.
470 *pTokRead++ = '\n';
472 *pTokRead++ = *pMsgWrite++;
474 else if ((*pMsgWrite == ' ') || (*pMsgWrite == '\t'))
476 eState = INETMSG_EOL_FSP;
477 *pTokRead++ = *pMsgWrite++;
479 else if (*pMsgWrite == '\r')
481 // Found <CR>.
482 if (eState == INETMSG_EOL_FSP)
484 // Encode last (trailing space) character.
485 sal_uInt8 c = (sal_uInt8)(*(--pTokRead));
486 *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')
495 // Found <LF> only.
496 if (eState == INETMSG_EOL_FSP)
498 // Encode last (trailing space) character.
499 sal_uInt8 c = (sal_uInt8)(*(--pTokRead));
500 *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.
507 *pTokRead++ = '\r';
508 *pTokRead++ = *pMsgWrite++;
510 else if (*pMsgWrite == '=')
512 // Escape character itself MUST be encoded, of course.
513 sal_uInt8 c = (sal_uInt8)(*pMsgWrite++);
514 *pTokRead++ = '=';
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;
530 else
532 // Encode any other character.
533 sal_uInt8 c = (sal_uInt8)(*pMsgWrite++);
534 *pTokRead++ = '=';
535 *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
536 *pTokRead++ = hex2pr[((c & 0x0f) )];
538 eState = INETMSG_EOL_SCR;
541 else
543 // Check for maximum line length.
544 if (eState != INETMSG_EOL_BEGIN)
546 // Insert soft line break.
547 *pTokRead++ = '=';
548 *pTokRead++ = '\r';
549 *pTokRead++ = '\n';
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++;
560 else
562 // Token buffer empty. Reset to <Begin-of-Buffer>.
563 pTokRead = pTokWrite = pTokBuffer;
564 eState = INETMSG_EOL_SCR;
568 else
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);
575 if (nRead > 0)
577 // Set read pointer.
578 pMsgRead = (pMsgBuffer + nRead);
580 else
582 // Nothing more ro read.
583 if (!bDone)
585 // Append final <CR><LF> and mark we're done.
586 *pTokRead++ = '\r';
587 *pTokRead++ = '\n';
589 bDone = true;
591 else
593 // Already done all encoding.
594 if ((pTokRead - pTokWrite) > 0)
596 // Bytes still in token buffer.
597 *pWBuf++ = *pTokWrite++;
599 else
601 // Token buffer empty. Reset to <Begin-of-Buffer>.
602 pTokRead = pTokWrite = pTokBuffer;
604 // Return.
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),
642 nTokBufLen (0)
644 ParseHeader(false);
647 INetMessageDecodeQPStream_Impl::~INetMessageDecodeQPStream_Impl()
649 delete pMsgBuffer;
652 int INetMessageDecodeQPStream_Impl::PutMsgLine( const sal_Char* pData,
653 sal_uIntPtr nSize)
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));
667 pData++;
668 if (nTokBufLen == 2)
670 if ((*pTokBuffer == '\r') || (*pTokBuffer == '\n'))
672 // Soft line break (=<CR><LF>). Emit buffer now.
673 eState = INETMSG_EOL_BEGIN;
675 else
677 // Decode token.
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.
687 nTokBufLen = 0;
690 else if (*pData == '=')
692 // Found escape character.
693 pData++;
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;
706 else
708 pMsgBuffer->WriteChar( *pData++ );
711 if (eState == INETMSG_EOL_BEGIN)
713 sal_Size nRead = pMsgBuffer->Tell();
714 if (nRead > 0)
716 // Emit buffer.
717 sal_Size nDocSiz = pMsg->GetDocumentSize();
718 sal_Size nWrite = 0;
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(),
746 pMsgStrm (NULL),
747 nMsgBufSiz (nMsgBufferSize),
748 nTokBufSiz (80),
749 bDone (false)
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()
762 delete pMsgStrm;
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)
787 case 0:
788 *pTokRead++ = six2pr[(int)(*pMsgWrite >> 2)];
789 break;
791 case 1:
792 *pTokRead++ = six2pr[ (int)(((*pMsgWrite << 4) & 060) |
793 (((*(pMsgWrite + 1)) >> 4) & 017))];
794 pMsgWrite++;
795 break;
797 case 2:
798 *pTokRead++ = six2pr[ (int)(((*pMsgWrite << 2) & 074) |
799 (((*(pMsgWrite + 1)) >> 6) & 003))];
800 pMsgWrite++;
801 break;
803 default: // == case 3
804 *pTokRead++ = six2pr[(int)(*pMsgWrite & 077)];
805 pMsgWrite++;
806 break;
809 else if ((pTokRead - pTokBuffer) == 72)
811 // Maximum line length. Append <CR><LF>.
812 *pTokRead++ = '\r';
813 *pTokRead++ = '\n';
815 else
817 if ((pTokRead - pTokWrite) > 0)
819 // Bytes still in token buffer.
820 *pWBuf++ = *pTokWrite++;
822 else
824 // Token buffer empty. Reset to <Begin-of-Buffer>.
825 pTokRead = pTokWrite = pTokBuffer;
829 else
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);
836 if (nRead > 0)
838 // Set read pointer.
839 pMsgRead = (pMsgBuffer + nRead);
841 else
843 // Nothing more to read.
844 if (!bDone)
846 // Append pad character(s) and final <CR><LF>.
847 switch ((pTokRead - pTokBuffer) % 4)
849 case 2:
850 *pTokRead++ = '=';
851 // Fall through for 2nd pad character.
852 case 3:
853 *pTokRead++ = '=';
854 break;
856 default:
857 break;
859 *pTokRead++ = '\r';
860 *pTokRead++ = '\n';
862 // Mark we're done.
863 bDone = true;
865 else
867 // Already done all encoding.
868 if ((pTokRead - pTokWrite) > 0)
870 // Bytes still in token buffer.
871 *pWBuf++ = *pTokWrite++;
873 else
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;
881 // Return.
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)
941 ParseHeader(false);
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,
953 sal_uIntPtr nSize)
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.
970 if (*pData == '=')
972 // Final pad character -> Done.
973 sal_Size nDocSiz = pMsg->GetDocumentSize();
974 sal_Size nRead = pMsgWrite - pMsgBuffer;
975 sal_Size nWrite = 0;
977 pLB->FillAppend(pMsgBuffer, nRead, &nWrite);
978 pMsg->SetDocumentSize(nDocSiz + nWrite);
980 if (nWrite < nRead)
981 return INETSTREAM_STATUS_ERROR;
982 else
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;
993 sal_Size nWrite = 0;
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.
1007 pData++;
1008 eState = INETMSG_EOL_FCR;
1010 else
1012 // Skip any junk character (may be transmission error).
1013 pData++;
1016 else
1018 // Decode any other character into message buffer.
1019 switch ((pMsgRead - pMsgBuffer) % 4)
1021 case 0:
1022 *pMsgWrite = (pr2six[(int)(*pData++)] << 2);
1023 pMsgRead++;
1024 break;
1026 case 1:
1027 *pMsgWrite++ |= (pr2six[(int)(*pData )] >> 4);
1028 *pMsgWrite = (pr2six[(int)(*pData++)] << 4);
1029 pMsgRead++;
1030 break;
1032 case 2:
1033 *pMsgWrite++ |= (pr2six[(int)(*pData )] >> 2);
1034 *pMsgWrite = (pr2six[(int)(*pData++)] << 6);
1035 pMsgRead++;
1036 break;
1038 default: // == case 3
1039 *pMsgWrite++ |= (pr2six[(int)(*pData++)]);
1040 pMsgRead = pMsgBuffer;
1041 break;
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),
1053 nChildIndex (0),
1054 pChildStrm (NULL),
1055 eEncoding (INETMSG_ENCODING_BINARY),
1056 pEncodeStrm (NULL),
1057 pDecodeStrm (NULL),
1058 pMsgBuffer (NULL)
1062 INetMIMEMessageStream::~INetMIMEMessageStream()
1064 delete pChildStrm;
1065 delete pEncodeStrm;
1066 delete pDecodeStrm;
1067 delete pMsgBuffer;
1070 INetMessageEncoding
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;
1090 else
1091 return INETMSG_ENCODING_QUOTED;
1093 else
1094 return INETMSG_ENCODING_7BIT;
1096 else
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");
1121 else
1122 pMsg->SetMIMEVersion(OUString());
1124 else
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());
1143 // Check Encoding.
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;
1156 else
1158 eEncoding = INETMSG_ENCODING_7BIT;
1161 else
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)
1175 // Base64.
1176 pMsg->SetContentTransferEncoding("base64");
1178 else if (eEncoding == INETMSG_ENCODING_QUOTED)
1180 // Quoted-Printable.
1181 pMsg->SetContentTransferEncoding("quoted-printable");
1183 else
1185 // No need to specify default.
1186 pMsg->SetContentTransferEncoding(OUString());
1189 // Mark we're done.
1190 eState = INETMSG_EOL_DONE;
1193 // Generate the message header.
1194 int nRead = INetMessageIStream::GetMsgLine(pData, nSize);
1195 if (nRead <= 0)
1197 // Reset state.
1198 eState = INETMSG_EOL_BEGIN;
1200 return nRead;
1202 else
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);
1213 if (pChild)
1215 // Increment child index.
1216 nChildIndex++;
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();
1234 else
1236 // No more parts. Mark we're done.
1237 eState = INETMSG_EOL_DONE;
1238 nChildIndex = 0;
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();
1253 else
1255 // Read current child stream.
1256 int nRead = pChildStrm->Read(pData, nSize);
1257 if (nRead > 0)
1259 return nRead;
1261 else
1263 // Cleanup exhausted child stream.
1264 delete pChildStrm;
1265 pChildStrm = NULL;
1269 return 0;
1271 else
1273 // Single part message body.
1274 if (pMsg->GetDocumentLB() == NULL)
1276 // Empty message body.
1277 return 0;
1280 // Check whether message body needs to be encoded.
1281 if (eEncoding == INETMSG_ENCODING_7BIT)
1283 // No Encoding.
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;
1298 else
1300 // Base64 Encoding.
1301 pEncodeStrm = new INetMessageEncode64Stream_Impl;
1303 pEncodeStrm->SetSourceMessage(pMsg);
1306 // Read encoded message.
1307 int nRead = pEncodeStrm->Read(pData, nSize);
1308 if (nRead > 0)
1310 return nRead;
1312 else
1314 // Cleanup exhausted encoder stream.
1315 delete pEncodeStrm;
1316 pEncodeStrm = NULL;
1318 // Mark we're done.
1319 eState = INETMSG_EOL_DONE;
1322 return 0;
1327 /// Message Parser
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);
1339 return nRet;
1341 else
1343 pMsg->SetHeaderParsed();
1344 // Parse the message body.
1345 if (pMsg->IsContainer())
1348 // Content-Transfer-Encoding MUST be "7bit" (RFC1521).
1349 if (pMsg->IsMessage())
1351 if( !pChildStrm )
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;
1365 if ( nSize > 0)
1367 // Bytes still in buffer. Put message down-stream.
1368 int status = pChildStrm->Write( pData, nSize );
1369 if (status != INETSTREAM_STATUS_OK)
1370 return status;
1373 return INetMessageOStream::PutMsgLine(pData, nSize);
1375 else
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, '"');
1393 // Save boundary.
1394 pMsg->SetMultipartBoundary(aBoundary);
1397 OString aPlainDelim(pMsg->GetMultipartBoundary());
1398 OString aDelim = OStringBuffer("--").
1399 append(aPlainDelim).
1400 makeStringAndClear();
1401 OString aPlainClose = OStringBuffer(
1402 aPlainDelim).
1403 append("--").
1404 makeStringAndClear();
1405 OString aClose = OStringBuffer(
1406 aDelim).
1407 append("--").
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;
1416 int status;
1417 for( pOldPos = pChar = static_cast<const sal_Char*>(pMsgBuffer->GetData()); nBufSize--;
1418 pChar++ )
1420 if( *pChar == '\r' || *pChar == '\n' )
1422 if( aDelim.compareTo(pOldPos, aDelim.getLength())
1423 != -1 &&
1424 aClose.compareTo(pOldPos, aClose.getLength())
1425 != -1 &&
1426 aPlainDelim.compareTo(pOldPos, aPlainDelim.getLength())
1427 != -1 &&
1428 aPlainClose.compareTo(pOldPos, aPlainClose.getLength())
1429 != -1 )
1431 if( nBufSize &&
1432 ( pChar[1] == '\r' || pChar[1] == '\n' ) )
1433 nBufSize--, pChar++;
1434 if( pChildStrm )
1436 status = pChildStrm->Write(
1437 pOldPos, pChar - pOldPos + 1 );
1438 if( status != INETSTREAM_STATUS_OK )
1439 return status;
1441 else {
1442 SAL_WARN( "tools.stream", "Boundary not found." );
1444 status = INetMessageOStream::PutMsgLine(
1445 pOldPos, pChar - pOldPos + 1 );
1446 if( status != INETSTREAM_STATUS_OK )
1447 return status;
1448 pOldPos = pChar + 1;
1450 else
1452 if( nBufSize &&
1453 ( pChar[1] == '\r' || pChar[1] == '\n' ) )
1454 nBufSize--, pChar++;
1455 pOldPos = pChar + 1;
1456 DELETEZ( pChildStrm );
1458 if (aClose.compareTo(pOldPos, aClose.getLength())
1459 != -1 &&
1460 aPlainClose.compareTo(pOldPos, aClose.getLength())
1461 != -1 )
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 )
1482 return status;
1486 if( pOldPos < pChar )
1488 SvMemoryStream* pNewStream = new SvMemoryStream;
1489 pNewStream->Write( pOldPos, pChar - pOldPos );
1490 SvMemoryStream* pTmp = pMsgBuffer;
1491 pMsgBuffer = pNewStream;
1492 delete pTmp;
1494 else
1496 pMsgBuffer->Seek( 0L );
1497 pMsgBuffer->SetStreamSize( 0 );
1499 return INETSTREAM_STATUS_OK;
1502 else
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;
1524 else
1526 eEncoding = INETMSG_ENCODING_7BIT;
1530 if (eEncoding == INETMSG_ENCODING_7BIT)
1532 // No decoding necessary.
1533 return INetMessageOStream::PutMsgLine(pData, nSize);
1535 else
1537 if (pDecodeStrm == NULL)
1539 if (eEncoding == INETMSG_ENCODING_QUOTED)
1541 pDecodeStrm = new INetMessageDecodeQPStream_Impl;
1543 else
1545 pDecodeStrm = new INetMessageDecode64Stream_Impl;
1547 pDecodeStrm->SetTargetMessage(pMsg);
1549 return pDecodeStrm->Write(pData, nSize);
1555 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */