xref: /aoo41x/main/tools/source/inet/inetstrm.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 #include <sal/types.h>
31 #include <rtl/memory.h>
32 #include <tools/cachestr.hxx>
33 #include <tools/debug.hxx>
34 #include <tools/inetmsg.hxx>
35 #include <tools/inetstrm.hxx>
36 
37 #include <ctype.h> // toupper
38 
39 inline sal_Bool SAL_CALL ascii_isWhitespace( sal_Unicode ch )
40 {
41     return ((ch <= 0x20) && ch);
42 }
43 
44 #define CONSTASCII_STRINGPARAM(a) (a), RTL_TEXTENCODING_ASCII_US
45 
46 /*=======================================================================
47  *
48  * INetMessageEncodeQPStream Interface.
49  * (Quoted-Printable Encoding)
50  *
51  *=====================================================================*/
52 class INetMessageEncodeQPStream_Impl : public INetMessageIStream
53 {
54     SvStream               *pMsgStrm;
55 
56     sal_uIntPtr                   nMsgBufSiz;
57     sal_Char               *pMsgBuffer;
58     sal_Char               *pMsgRead;
59     sal_Char               *pMsgWrite;
60 
61     sal_uIntPtr                   nTokBufSiz;
62     sal_Char               *pTokBuffer;
63     sal_Char               *pTokRead;
64     sal_Char               *pTokWrite;
65 
66     INetMessageStreamState  eState;
67     sal_Bool                    bDone;
68 
69     virtual int GetMsgLine (sal_Char *pData, sal_uIntPtr nSize);
70 
71 public:
72     INetMessageEncodeQPStream_Impl (sal_uIntPtr nMsgBufferSize = 1024);
73     virtual ~INetMessageEncodeQPStream_Impl (void);
74 };
75 
76 /*=====================================================================
77  *
78  * INetMessageDecodeQPStream Interface.
79  * (Quoted-Printable Decoding)
80  *
81  *====================================================================*/
82 class INetMessageDecodeQPStream_Impl : public INetMessageOStream
83 {
84     INetMessageStreamState  eState;
85     SvMemoryStream         *pMsgBuffer;
86 
87     sal_uIntPtr                   nTokBufLen;
88     sal_Char                pTokBuffer[4];
89 
90     virtual int PutMsgLine (const sal_Char *pData, sal_uIntPtr nSize);
91 
92 public:
93     INetMessageDecodeQPStream_Impl (void);
94     virtual ~INetMessageDecodeQPStream_Impl (void);
95 };
96 
97 /*======================================================================
98  *
99  * INetMessageEncode64Stream Interface.
100  * (Base64 Encoding)
101  *
102  *====================================================================*/
103 class INetMessageEncode64Stream_Impl : public INetMessageIStream
104 {
105     SvStream  *pMsgStrm;
106 
107     sal_uIntPtr      nMsgBufSiz;
108     sal_uInt8 *pMsgBuffer;
109     sal_uInt8 *pMsgRead;
110     sal_uInt8 *pMsgWrite;
111 
112     sal_uIntPtr      nTokBufSiz;
113     sal_Char  *pTokBuffer;
114     sal_Char  *pTokRead;
115     sal_Char  *pTokWrite;
116 
117     sal_Bool       bDone;
118 
119     virtual int GetMsgLine (sal_Char *pData, sal_uIntPtr nSize);
120 
121 public:
122     INetMessageEncode64Stream_Impl (sal_uIntPtr nMsgBufferSize = 2048);
123     virtual ~INetMessageEncode64Stream_Impl (void);
124 };
125 
126 /*======================================================================
127  *
128  * INetMessageDecode64Stream Interface.
129  * (Base64 Decoding)
130  *
131  *====================================================================*/
132 class INetMessageDecode64Stream_Impl : public INetMessageOStream
133 {
134     INetMessageStreamState  eState;
135 
136     sal_uIntPtr                   nMsgBufSiz;
137     sal_Char               *pMsgBuffer;
138     sal_Char               *pMsgRead;
139     sal_Char               *pMsgWrite;
140 
141     virtual int PutMsgLine (const sal_Char *pData, sal_uIntPtr nSize);
142 
143 public:
144     INetMessageDecode64Stream_Impl (sal_uIntPtr nMsgBufferSize = 128);
145     virtual ~INetMessageDecode64Stream_Impl (void);
146 };
147 
148 /*=========================================================================
149  *
150  * INetIStream Implementation.
151  *
152  *=======================================================================*/
153 /*
154  * INetIStream.
155  */
156 INetIStream::INetIStream ()
157 {
158 }
159 
160 /*
161  * ~INetIStream.
162  */
163 INetIStream::~INetIStream (void)
164 {
165 }
166 
167 /*
168  * Read.
169  */
170 int INetIStream::Read (sal_Char *pData, sal_uIntPtr nSize)
171 {
172     return GetData (pData, nSize);
173 }
174 
175 /*
176  * Decode64.
177  */
178 void INetIStream::Decode64 (SvStream& rIn, SvStream& rOut)
179 {
180     INetMessage aMsg;
181     aMsg.SetDocumentLB(new SvAsyncLockBytes(&rOut, sal_False));
182 
183     INetMessageDecode64Stream_Impl aStream (8192);
184     aStream.SetTargetMessage (&aMsg);
185 
186     sal_Char* pBuf = new sal_Char[8192];
187 
188     int nRead = 0;
189     while ((nRead = rIn.Read (pBuf, 8192)) > 0)
190         aStream.Write( pBuf, nRead );
191     aStream.Write ("\r\n", 2);
192 
193     delete[] pBuf;
194 }
195 
196 /*
197  * Encode64.
198  */
199 void INetIStream::Encode64 (SvStream& rIn, SvStream& rOut)
200 {
201     INetMessage aMsg;
202     aMsg.SetDocumentLB (
203         new SvLockBytes (&rIn, sal_False));
204 
205     INetMessageEncode64Stream_Impl aStream (8192);
206     aStream.SetSourceMessage (&aMsg);
207 
208     sal_Char* pBuf = new sal_Char[8192];
209 
210     int nRead = 0;
211     while ((nRead = aStream.Read (pBuf, 8192)) > 0)
212         rOut.Write( pBuf, nRead );
213 
214     delete[] pBuf;
215 }
216 
217 /*=========================================================================
218  *
219  * INetOStream Implementation.
220  *
221  *=======================================================================*/
222 /*
223  * INetOStream.
224  */
225 INetOStream::INetOStream ()
226 {
227 }
228 
229 /*
230  * ~INetOStream.
231  */
232 INetOStream::~INetOStream (void)
233 {
234 }
235 
236 /*
237  * Write.
238  */
239 int INetOStream::Write (const sal_Char *pData, sal_uIntPtr nSize)
240 {
241     return PutData (pData, nSize);
242 }
243 
244 /*=========================================================================
245  *
246  * INetMessageIStream Implementation.
247  *
248  *=======================================================================*/
249 /*
250  * INetMessageIStream.
251  */
252 INetMessageIStream::INetMessageIStream (sal_uIntPtr nBufferSize)
253     : pSourceMsg       (NULL),
254       bHeaderGenerated (sal_False),
255       nBufSiz          (nBufferSize),
256       pMsgStrm         (NULL),
257       pMsgBuffer       (new SvMemoryStream)
258 {
259     pMsgBuffer->SetStreamCharSet (RTL_TEXTENCODING_ASCII_US);
260     pBuffer = new sal_Char[nBufSiz];
261     pRead = pWrite = pBuffer;
262 }
263 
264 /*
265  * ~INetMessageIStream.
266  */
267 INetMessageIStream::~INetMessageIStream (void)
268 {
269     delete [] pBuffer;
270     delete pMsgBuffer;
271     delete pMsgStrm;
272 }
273 
274 /*
275  * GetData.
276  */
277 int INetMessageIStream::GetData (sal_Char *pData, sal_uIntPtr nSize)
278 {
279     if (pSourceMsg == NULL) return INETSTREAM_STATUS_ERROR;
280 
281     sal_Char *pWBuf = pData;
282     sal_Char *pWEnd = pData + nSize;
283 
284     while (pWBuf < pWEnd)
285     {
286         // Caller's buffer not yet filled.
287         sal_uIntPtr n = pRead - pWrite;
288         if (n > 0)
289         {
290             // Bytes still in buffer.
291             sal_uIntPtr m = pWEnd - pWBuf;
292             if (m < n) n = m;
293             for (sal_uIntPtr i = 0; i < n; i++) *pWBuf++ = *pWrite++;
294         }
295         else
296         {
297             // Buffer empty. Reset to <Begin-of-Buffer>.
298             pRead = pWrite = pBuffer;
299 
300             // Read next message line.
301             int nRead = GetMsgLine (pBuffer, nBufSiz);
302             if (nRead > 0)
303             {
304                 // Set read pointer.
305                 pRead = pBuffer + nRead;
306             }
307             else
308             {
309                 if (!bHeaderGenerated)
310                 {
311                     // Header generated. Insert empty line.
312                     bHeaderGenerated = sal_True;
313                     *pRead++ = '\r';
314                     *pRead++ = '\n';
315                 }
316                 else
317                 {
318                     // Body generated.
319                     return (pWBuf - pData);
320                 }
321             }
322         }
323     }
324     return (pWBuf - pData);
325 }
326 
327 /*
328  * GetMsgLine.
329  */
330 int INetMessageIStream::GetMsgLine (sal_Char *pData, sal_uIntPtr nSize)
331 {
332     if (pSourceMsg == NULL) return INETSTREAM_STATUS_ERROR;
333 
334     sal_Char *pWBuf = pData;
335     sal_Char *pWEnd = pData + nSize;
336 
337     if (!bHeaderGenerated)
338     {
339         sal_uIntPtr i, n;
340 
341         if (pMsgBuffer->Tell() == 0)
342         {
343             // Insert formatted header into buffer.
344             n = pSourceMsg->GetHeaderCount();
345             for (i = 0; i < n; i++)
346             {
347                 INetMessageHeader aHeader (pSourceMsg->GetHeaderField(i));
348                 if (aHeader.GetValue().Len())
349                 {
350                     // NYI: Folding long lines.
351                     *pMsgBuffer << (sal_Char*)(aHeader.GetName().GetBuffer());
352                     *pMsgBuffer << ": ";
353                     *pMsgBuffer << (sal_Char*)(aHeader.GetValue().GetBuffer());
354                     *pMsgBuffer << "\r\n";
355                 }
356             }
357 
358             pMsgWrite = (sal_Char *)(pMsgBuffer->GetData());
359             pMsgRead  = pMsgWrite + pMsgBuffer->Tell();
360         }
361 
362         n = pMsgRead - pMsgWrite;
363         if (n > 0)
364         {
365             // Move to caller.
366             if (nSize < n) n = nSize;
367             for (i = 0; i < n; i++) *pWBuf++ = *pMsgWrite++;
368         }
369         else
370         {
371             // Reset buffer.
372             pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
373         }
374     }
375     else
376     {
377         if (pSourceMsg->GetDocumentLB())
378         {
379             if (pMsgStrm == NULL)
380                 pMsgStrm = new SvStream (pSourceMsg->GetDocumentLB());
381 
382             sal_uIntPtr nRead = pMsgStrm->Read (pWBuf, (pWEnd - pWBuf));
383             pWBuf += nRead;
384         }
385     }
386     return (pWBuf - pData);
387 }
388 
389 /*=========================================================================
390  *
391  * INetMessageOStream Implementation.
392  *
393  *=======================================================================*/
394 /*
395  * INetMessageOStream.
396  */
397 INetMessageOStream::INetMessageOStream (void)
398     : pTargetMsg    (NULL),
399       bHeaderParsed (sal_False),
400       eOState       (INETMSG_EOL_BEGIN),
401       pMsgBuffer    (new SvMemoryStream)
402 {
403 }
404 
405 /*
406  * ~INetMessageOStream.
407  */
408 INetMessageOStream::~INetMessageOStream (void)
409 {
410     if (pMsgBuffer->Tell() > 0)
411         PutMsgLine ((const sal_Char *) pMsgBuffer->GetData(), pMsgBuffer->Tell());
412     delete pMsgBuffer;
413 
414     if (pTargetMsg)
415     {
416         SvOpenLockBytes *pLB =
417             PTR_CAST (SvOpenLockBytes, pTargetMsg->GetDocumentLB());
418         if (pLB)
419         {
420             pLB->Flush();
421             pLB->Terminate();
422         }
423     }
424 }
425 
426 /*
427  * PutData.
428  * (Simple Field Parsing (RFC822, Appendix B)).
429  */
430 int INetMessageOStream::PutData (const sal_Char *pData, sal_uIntPtr nSize)
431 {
432     if (pTargetMsg == NULL) return INETSTREAM_STATUS_ERROR;
433 
434     const sal_Char *pStop = (pData + nSize);
435 
436     while (!bHeaderParsed && (pData < pStop))
437     {
438         if (eOState == INETMSG_EOL_BEGIN)
439         {
440             if ((*pData == '\r') || (*pData == '\n'))
441             {
442                 /*
443                  * Empty Line. Separates header fields from message body.
444                  * Skip this and any 2nd line break character (if any).
445                  */
446                 pData++;
447                 if ((pData < pStop) && ((*pData == '\r') || (*pData == '\n')))
448                     pData++;
449 
450                 // Emit any buffered last header field.
451                 if (pMsgBuffer->Tell() > 0)
452                 {
453                     *pMsgBuffer << '\0';
454                     int status = PutMsgLine (
455                         (const sal_Char *) pMsgBuffer->GetData(),
456                         pMsgBuffer->Tell());
457                     if (status != INETSTREAM_STATUS_OK) return status;
458                 }
459 
460                 // Reset to begin.
461                 eOState = INETMSG_EOL_BEGIN;
462                 pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
463 
464                 // Mark header parsed.
465                 bHeaderParsed = sal_True;
466             }
467             else if ((*pData == ' ') || (*pData == '\t'))
468             {
469                 // Continuation line. Unfold multi-line field-body.
470                 *pMsgBuffer << ' ';
471                 pData++;
472             }
473             else
474             {
475                 // Begin of new header field.
476                 if (pMsgBuffer->Tell() > 0)
477                 {
478                     // Emit buffered header field now.
479                     *pMsgBuffer << '\0';
480                     int status = PutMsgLine (
481                         (const sal_Char *) pMsgBuffer->GetData(),
482                         pMsgBuffer->Tell());
483                     if (status != INETSTREAM_STATUS_OK) return status;
484                 }
485 
486                 // Reset to begin of buffer.
487                 pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
488 
489                 // Insert current character into buffer.
490                 *pMsgBuffer << *pData++;
491             }
492 
493             // Search for next line break character.
494             if (!bHeaderParsed) eOState = INETMSG_EOL_SCR;
495         }
496         else if (eOState == INETMSG_EOL_FCR)
497         {
498             // Skip line break character.
499             pData++;
500 
501             // Mark begin of line.
502             eOState = INETMSG_EOL_BEGIN;
503         }
504         else if ((*pData == '\r') || (*pData == '\n'))
505         {
506             if (*pData == '\r') pData++;
507             eOState = INETMSG_EOL_FCR;
508         }
509         else if (ascii_isWhitespace (*pData & 0x7f))
510         {
511             // Any <LWS> is folded into a single <SP> character.
512             sal_Char c = *((const sal_Char *) pMsgBuffer->GetData() + pMsgBuffer->Tell() - 1);
513             if (!ascii_isWhitespace (c & 0x7f)) *pMsgBuffer << ' ';
514 
515             // Skip over this <LWS> character.
516             pData++;
517         }
518         else
519         {
520             // Any other character is inserted into line buffer.
521             *pMsgBuffer << *pData++;
522         }
523     }
524 
525     if (bHeaderParsed && (pData < pStop))
526     {
527         // Put message body down-stream.
528         return PutMsgLine (pData, (pStop - pData));
529     }
530 
531     return INETSTREAM_STATUS_OK;
532 }
533 
534 /*
535  * PutMsgLine.
536  */
537 int INetMessageOStream::PutMsgLine (const sal_Char *pData, sal_uIntPtr nSize)
538 {
539     // Check for message container.
540     if (pTargetMsg == NULL) return INETSTREAM_STATUS_ERROR;
541 
542     // Check for header or body.
543     if (!IsHeaderParsed())
544     {
545         ByteString aField (pData);
546         sal_uInt16 nPos = aField.Search (':');
547         if (nPos != STRING_NOTFOUND)
548         {
549             ByteString aName (
550                 aField.Copy (0, nPos));
551             ByteString aValue (
552                 aField.Copy (nPos + 1, aField.Len() - nPos + 1));
553             aValue.EraseLeadingChars (' ');
554 
555             pTargetMsg->SetHeaderField (
556                 INetMessageHeader (aName, aValue));
557         }
558     }
559     else
560     {
561         SvOpenLockBytes *pLB =
562             PTR_CAST(SvOpenLockBytes, pTargetMsg->GetDocumentLB());
563         if (pLB == NULL)
564             return INETSTREAM_STATUS_WOULDBLOCK;
565 
566         sal_Size nDocSiz = pTargetMsg->GetDocumentSize();
567         sal_Size nWrite  = 0;
568 
569         pLB->FillAppend ((sal_Char *)pData, nSize, &nWrite);
570         pTargetMsg->SetDocumentSize (nDocSiz + nWrite);
571 
572         if (nWrite < nSize) return INETSTREAM_STATUS_ERROR;
573     }
574     return INETSTREAM_STATUS_OK;
575 }
576 
577 /*=========================================================================
578  *
579  * INetMessageIOStream Implementation.
580  *
581  *=======================================================================*/
582 /*
583  * INetMessageIOStream.
584  */
585 INetMessageIOStream::INetMessageIOStream (sal_uIntPtr nBufferSize)
586     : INetMessageIStream (nBufferSize),
587       INetMessageOStream ()
588 {
589 }
590 
591 /*
592  * ~INetMessageIOStream.
593  */
594 INetMessageIOStream::~INetMessageIOStream (void)
595 {
596 }
597 
598 /*=======================================================================
599  *
600  * INetMessageEncodeQPStream_Impl Implementation.
601  * (Quoted-Printable Encoding)
602  *
603  *=====================================================================*/
604 static const sal_Char hex2pr[16] = {
605     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
606     'A', 'B', 'C', 'D', 'E', 'F'
607 };
608 
609 static const sal_Char ebcdic[] = {
610     '!', '"', '#', '$', '@', '[', '\\', ']', '^', '`', '{', '|', '}', '~'
611 };
612 
613 /*
614  * INetMessageEncodeQPStream_Impl.
615  */
616 INetMessageEncodeQPStream_Impl::INetMessageEncodeQPStream_Impl (
617     sal_uIntPtr nMsgBufferSize)
618     : INetMessageIStream (),
619       pMsgStrm   (NULL),
620       nMsgBufSiz (nMsgBufferSize),
621       nTokBufSiz (80),
622       eState     (INETMSG_EOL_SCR),
623       bDone      (sal_False)
624 {
625     GenerateHeader (sal_False);
626 
627     pMsgBuffer = new sal_Char[nMsgBufSiz];
628     pMsgRead = pMsgWrite = pMsgBuffer;
629 
630     pTokBuffer = new sal_Char[nTokBufSiz];
631     pTokRead = pTokWrite = pTokBuffer;
632 }
633 
634 /*
635  * ~INetMessageEncodeQPStream_Impl.
636  */
637 INetMessageEncodeQPStream_Impl::~INetMessageEncodeQPStream_Impl (void)
638 {
639     delete pMsgStrm;
640     delete [] pMsgBuffer;
641     delete [] pTokBuffer;
642 }
643 
644 /*
645  * GetMsgLine.
646  */
647 int INetMessageEncodeQPStream_Impl::GetMsgLine (sal_Char *pData, sal_uIntPtr nSize)
648 {
649     INetMessage *pMsg = GetSourceMessage ();
650     if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
651 
652     if (pMsg->GetDocumentLB() == NULL) return 0;
653     if (pMsgStrm == NULL) pMsgStrm = new SvStream (pMsg->GetDocumentLB());
654 
655     sal_Char *pWBuf = pData;
656     while (pWBuf < (pData + nSize))
657     {
658         // Caller's buffer not yet filled.
659         if ((pMsgRead - pMsgWrite) > 0)
660         {
661             // Bytes still in message buffer.
662             if ((eState != INETMSG_EOL_BEGIN) &&
663                 ((pTokRead - pTokBuffer) < 72))
664             {
665                 // Token buffer not yet filled.
666                 if (eState == INETMSG_EOL_FCR)
667                 {
668                     eState = INETMSG_EOL_BEGIN;
669                     if (*pMsgWrite != '\n')
670                     {
671                         // Convert orphant <CR> into <CR><LF> sequence.
672                         *pTokRead++ = '\n';
673                     }
674                     *pTokRead++ = *pMsgWrite++;
675                 }
676                 else if ((*pMsgWrite == ' ') || (*pMsgWrite == '\t'))
677                 {
678                     eState = INETMSG_EOL_FSP;
679                     *pTokRead++ = *pMsgWrite++;
680                 }
681                 else if (*pMsgWrite == '\r')
682                 {
683                     // Found <CR>.
684                     if (eState == INETMSG_EOL_FSP)
685                     {
686                         // Encode last (trailing space) character.
687                         sal_uInt8 c = (sal_uInt8)(*(--pTokRead));
688                         *pTokRead++ = '=';
689                         *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
690                         *pTokRead++ = hex2pr[((c & 0x0f)     )];
691                     }
692                     eState = INETMSG_EOL_FCR;
693                     *pTokRead++ = *pMsgWrite++;
694                 }
695                 else if (*pMsgWrite == '\n')
696                 {
697                     // Found <LF> only.
698                     if (eState == INETMSG_EOL_FSP)
699                     {
700                         // Encode last (trailing space) character.
701                         sal_uInt8 c = (sal_uInt8)(*(--pTokRead));
702                         *pTokRead++ = '=';
703                         *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
704                         *pTokRead++ = hex2pr[((c & 0x0f)     )];
705                     }
706                     eState = INETMSG_EOL_BEGIN;
707 
708                     // Convert orphant <LF> into <CR><LF> sequence.
709                     *pTokRead++ = '\r';
710                     *pTokRead++ = *pMsgWrite++;
711                 }
712                 else if (*pMsgWrite == '=')
713                 {
714                     // Escape character itself MUST be encoded, of course.
715                     sal_uInt8 c = (sal_uInt8)(*pMsgWrite++);
716                     *pTokRead++ = '=';
717                     *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
718                     *pTokRead++ = hex2pr[((c & 0x0f)     )];
719 
720                     eState = INETMSG_EOL_SCR;
721                 }
722                 else if (((sal_uInt8)(*pMsgWrite) > 0x20) &&
723                          ((sal_uInt8)(*pMsgWrite) < 0x7f)    )
724                 {
725                     /*
726                      * Some printable ASCII character.
727                      * (Encode EBCDIC special characters (NYI)).
728                      */
729                     *pTokRead++ = *pMsgWrite++;
730                     eState = INETMSG_EOL_SCR;
731                 }
732                 else
733                 {
734                     // Encode any other character.
735                     sal_uInt8 c = (sal_uInt8)(*pMsgWrite++);
736                     *pTokRead++ = '=';
737                     *pTokRead++ = hex2pr[((c & 0xf0) >> 4)];
738                     *pTokRead++ = hex2pr[((c & 0x0f)     )];
739 
740                     eState = INETMSG_EOL_SCR;
741                 }
742             }
743             else
744             {
745                 // Check for maximum line length.
746                 if (eState != INETMSG_EOL_BEGIN)
747                 {
748                     // Insert soft line break.
749                     *pTokRead++ = '=';
750                     *pTokRead++ = '\r';
751                     *pTokRead++ = '\n';
752 
753                     eState = INETMSG_EOL_BEGIN;
754                 }
755 
756                 // Copy to caller's buffer.
757                 if ((pTokRead - pTokWrite) > 0)
758                 {
759                     // Bytes still in token buffer.
760                     *pWBuf++ = *pTokWrite++;
761                 }
762                 else
763                 {
764                     // Token buffer empty. Reset to <Begin-of-Buffer>.
765                     pTokRead = pTokWrite = pTokBuffer;
766                     eState = INETMSG_EOL_SCR;
767                 }
768             }
769         }
770         else
771         {
772             // Message buffer empty. Reset to <Begin-of-Buffer>.
773             pMsgRead = pMsgWrite = pMsgBuffer;
774 
775             // Read next message block.
776             sal_uIntPtr nRead = pMsgStrm->Read (pMsgBuffer, nMsgBufSiz);
777             if (nRead > 0)
778             {
779                 // Set read pointer.
780                 pMsgRead = (pMsgBuffer + nRead);
781             }
782             else
783             {
784                 // Nothing more ro read.
785                 if (!bDone)
786                 {
787                     // Append final <CR><LF> and mark we're done.
788                     *pTokRead++ = '\r';
789                     *pTokRead++ = '\n';
790 
791                     bDone = sal_True;
792                 }
793                 else
794                 {
795                     // Already done all encoding.
796                     if ((pTokRead - pTokWrite) > 0)
797                     {
798                         // Bytes still in token buffer.
799                         *pWBuf++ = *pTokWrite++;
800                     }
801                     else
802                     {
803                         // Token buffer empty. Reset to <Begin-of-Buffer>.
804                         pTokRead = pTokWrite = pTokBuffer;
805 
806                         // Return.
807                         return (pWBuf - pData);
808                     }
809                 }
810             }
811         }
812     }
813     return (pWBuf - pData);
814 }
815 
816 /*=====================================================================
817  *
818  * INetMessageDecodeQPStream_Impl Implementation.
819  * (Quoted-Printable Decoding)
820  *
821  *====================================================================*/
822 static const sal_uInt8 pr2hex[128] = {
823     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
824     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
825     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
826     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
827 
828     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
829     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
830     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
831     0x08, 0x09, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
832 
833     0x10, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
834     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
835     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
836     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
837 
838     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
839     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
840     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
841     0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
842 };
843 
844 /*
845  * INetMessageDecodeQPStream_Impl.
846  */
847 INetMessageDecodeQPStream_Impl::INetMessageDecodeQPStream_Impl (void)
848     : INetMessageOStream (),
849       eState     (INETMSG_EOL_BEGIN),
850       pMsgBuffer (new SvMemoryStream),
851       nTokBufLen (0)
852 {
853     ParseHeader (sal_False);
854 }
855 
856 /*
857  * ~INetMessageDecodeQPStream_Impl.
858  */
859 INetMessageDecodeQPStream_Impl::~INetMessageDecodeQPStream_Impl (void)
860 {
861     delete pMsgBuffer;
862 }
863 
864 /*
865  * PutMsgLine.
866  */
867 int INetMessageDecodeQPStream_Impl::PutMsgLine (
868     const sal_Char *pData, sal_uIntPtr nSize)
869 {
870     INetMessage *pMsg = GetTargetMessage();
871     if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
872 
873     SvOpenLockBytes * pLB = PTR_CAST(SvOpenLockBytes, pMsg->GetDocumentLB());
874     if (pLB == NULL) return INETSTREAM_STATUS_WOULDBLOCK;
875 
876     const sal_Char *pStop = pData + nSize;
877     while (pData < pStop)
878     {
879         if (eState == INETMSG_EOL_FESC)
880         {
881             *(pTokBuffer + nTokBufLen++) = static_cast< char >(toupper(*pData));
882             pData++;
883             if (nTokBufLen == 2)
884             {
885                 if ((*pTokBuffer == '\r') || (*pTokBuffer == '\n'))
886                 {
887                     // Soft line break (=<CR><LF>). Emit buffer now.
888                     eState = INETMSG_EOL_BEGIN;
889                 }
890                 else
891                 {
892                     // Decode token.
893                     *pMsgBuffer << sal_uInt8 (
894                         (pr2hex[(int)(pTokBuffer[0] & 0x7f)] << 4) |
895                         (pr2hex[(int)(pTokBuffer[1] & 0x7f)] & 15)   );
896 
897                     // Search for next <CR>.
898                     eState = INETMSG_EOL_SCR;
899                 }
900 
901                 // Reset token buffer.
902                 nTokBufLen = 0;
903             }
904         }
905         else if (*pData == '=')
906         {
907             // Found escape character.
908             pData++;
909             eState = INETMSG_EOL_FESC;
910         }
911         else if (eState == INETMSG_EOL_FCR)
912         {
913             *pMsgBuffer << *pData++;
914             eState = INETMSG_EOL_BEGIN;
915         }
916         else if (*pData == '\r')
917         {
918             *pMsgBuffer << *pData++;
919             eState = INETMSG_EOL_FCR;
920         }
921         else
922         {
923             *pMsgBuffer << *pData++;
924         }
925 
926         if (eState == INETMSG_EOL_BEGIN)
927         {
928             sal_Size nRead = pMsgBuffer->Tell();
929             if (nRead > 0)
930             {
931                 // Emit buffer.
932                 sal_Size nDocSiz = pMsg->GetDocumentSize();
933                 sal_Size nWrite  = 0;
934 
935                 pLB->FillAppend (
936                     (sal_Char *)(pMsgBuffer->GetData()), nRead, &nWrite);
937                 pMsg->SetDocumentSize (nDocSiz + nWrite);
938 
939                 if (nWrite < nRead) return INETSTREAM_STATUS_ERROR;
940 
941                 pMsgBuffer->Seek (STREAM_SEEK_TO_BEGIN);
942             }
943             eState = INETMSG_EOL_SCR;
944         }
945     }
946     return INETSTREAM_STATUS_OK;
947 }
948 
949 /*======================================================================
950  *
951  * INetMessageEncode64Stream_Impl Implementation.
952  * (Base64 Encoding)
953  *
954  *====================================================================*/
955 static const sal_Char six2pr[64] = {
956     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
957     'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
958     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
959     'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
960     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
961 };
962 
963 /*
964  * INetMessageEncode64Stream_Impl.
965  */
966 INetMessageEncode64Stream_Impl::INetMessageEncode64Stream_Impl (
967     sal_uIntPtr nMsgBufferSize)
968     : INetMessageIStream (),
969       pMsgStrm   (NULL),
970       nMsgBufSiz (nMsgBufferSize),
971       nTokBufSiz (80),
972       bDone      (sal_False)
973 {
974     GenerateHeader (sal_False);
975 
976     pMsgBuffer = new sal_uInt8[nMsgBufSiz];
977     pMsgRead = pMsgWrite = pMsgBuffer;
978 
979     pTokBuffer = new sal_Char[nTokBufSiz];
980     pTokRead = pTokWrite = pTokBuffer;
981 }
982 
983 /*
984  * ~INetMessageEncode64Stream_Impl.
985  */
986 INetMessageEncode64Stream_Impl::~INetMessageEncode64Stream_Impl (void)
987 {
988     delete pMsgStrm;
989     delete [] pMsgBuffer;
990     delete [] pTokBuffer;
991 }
992 
993 /*
994  * GetMsgLine.
995  */
996 int INetMessageEncode64Stream_Impl::GetMsgLine (sal_Char *pData, sal_uIntPtr nSize)
997 {
998     INetMessage *pMsg = GetSourceMessage ();
999     if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
1000 
1001     if (pMsg->GetDocumentLB() == NULL) return 0;
1002     if (pMsgStrm == NULL) pMsgStrm = new SvStream (pMsg->GetDocumentLB());
1003 
1004     sal_Char *pWBuf = pData;
1005     while (pWBuf < (pData + nSize))
1006     {
1007         // Caller's buffer not yet filled.
1008         if ((pMsgRead - pMsgWrite) > 0)
1009         {
1010             // Bytes still in message buffer.
1011             if ((pTokRead - pTokBuffer) < 72)
1012             {
1013                 // Token buffer not yet filled.
1014                 switch ((pTokRead - pTokBuffer) % 4)
1015                 {
1016                     case 0:
1017                         *pTokRead++ = six2pr[(int)(*pMsgWrite >> 2)];
1018                         break;
1019 
1020                     case 1:
1021                         *pTokRead++ = six2pr[
1022                             (int)(((*pMsgWrite << 4) & 060) |
1023                                   (((*(pMsgWrite + 1)) >> 4) & 017))];
1024                         pMsgWrite++;
1025                         break;
1026 
1027                     case 2:
1028                         *pTokRead++ = six2pr[
1029                             (int)(((*pMsgWrite << 2) & 074) |
1030                                   (((*(pMsgWrite + 1)) >> 6) & 003))];
1031                         pMsgWrite++;
1032                         break;
1033 
1034                     default: // == case 3
1035                         *pTokRead++ = six2pr[(int)(*pMsgWrite & 077)];
1036                         pMsgWrite++;
1037                         break;
1038                 }
1039             }
1040             else if ((pTokRead - pTokBuffer) == 72)
1041             {
1042                 // Maximum line length. Append <CR><LF>.
1043                 *pTokRead++ = '\r';
1044                 *pTokRead++ = '\n';
1045             }
1046             else
1047             {
1048                 if ((pTokRead - pTokWrite) > 0)
1049                 {
1050                     // Bytes still in token buffer.
1051                     *pWBuf++ = *pTokWrite++;
1052                 }
1053                 else
1054                 {
1055                     // Token buffer empty. Reset to <Begin-of-Buffer>.
1056                     pTokRead = pTokWrite = pTokBuffer;
1057                 }
1058             }
1059         }
1060         else
1061         {
1062             // Message buffer empty. Reset to <Begin-of-Buffer>.
1063             pMsgRead = pMsgWrite = pMsgBuffer;
1064 
1065             // Read next message block.
1066             sal_uIntPtr nRead = pMsgStrm->Read (pMsgBuffer, nMsgBufSiz);
1067             if (nRead > 0)
1068             {
1069                 // Set read pointer.
1070                 pMsgRead = (pMsgBuffer + nRead);
1071             }
1072             else
1073             {
1074                 // Nothing more to read.
1075                 if (!bDone)
1076                 {
1077                     // Append pad character(s) and final <CR><LF>.
1078                     switch ((pTokRead - pTokBuffer) % 4)
1079                     {
1080                         case 2:
1081                             *pTokRead++ = '=';
1082                             // Fall through for 2nd pad character.
1083 
1084                         case 3:
1085                             *pTokRead++ = '=';
1086                             break;
1087 
1088                         default:
1089                             break;
1090                     }
1091                     *pTokRead++ = '\r';
1092                     *pTokRead++ = '\n';
1093 
1094                     // Mark we're done.
1095                     bDone = sal_True;
1096                 }
1097                 else
1098                 {
1099                     // Already done all encoding.
1100                     if ((pTokRead - pTokWrite) > 0)
1101                     {
1102                         // Bytes still in token buffer.
1103                         *pWBuf++ = *pTokWrite++;
1104                     }
1105                     else
1106                     {
1107                         // Token buffer empty. Reset to <Begin-of-Buffer>.
1108                         pTokRead = pTokWrite = pTokBuffer;
1109 
1110                         // Reset done flag, if everything has been done.
1111                         // if (pWBuf == pData) bDone = sal_False;
1112 
1113                         // Return.
1114                         return (pWBuf - pData);
1115                     }
1116                 }
1117             }
1118         }
1119     } // while (pWBuf < (pData + nSize))
1120     return (pWBuf - pData);
1121 }
1122 
1123 /*======================================================================
1124  *
1125  * INetMessageDecode64Stream_Impl Implementation.
1126  * (Base64 Decoding)
1127  *
1128  *====================================================================*/
1129 static const sal_uInt8 pr2six[256] = {
1130     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1131     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1132     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1133     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1134 
1135     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1136     0x40, 0x40, 0x40, 0x3E, 0x40, 0x40, 0x40, 0x3F,
1137     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
1138     0x3C, 0x3D, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1139 
1140     0x40, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
1141     0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
1142     0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
1143     0x17, 0x18, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40,
1144 
1145     0x40, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
1146     0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
1147     0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
1148     0x31, 0x32, 0x33, 0x40, 0x40, 0x40, 0x40, 0x40,
1149 
1150     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1151     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1152     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1153     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1154 
1155     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1156     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1157     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1158     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1159 
1160     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1161     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1162     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1163     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1164 
1165     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1166     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1167     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
1168     0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
1169 };
1170 
1171 /*
1172  * INetMessageDecode64Stream_Impl.
1173  */
1174 INetMessageDecode64Stream_Impl::INetMessageDecode64Stream_Impl (
1175     sal_uIntPtr nMsgBufferSize)
1176     : INetMessageOStream (),
1177       eState     (INETMSG_EOL_SCR),
1178       nMsgBufSiz (nMsgBufferSize)
1179 {
1180     ParseHeader (sal_False);
1181 
1182     pMsgBuffer = new sal_Char[nMsgBufSiz];
1183     pMsgRead = pMsgWrite = pMsgBuffer;
1184 }
1185 
1186 /*
1187  * ~INetMessageDecode64Stream_Impl.
1188  */
1189 INetMessageDecode64Stream_Impl::~INetMessageDecode64Stream_Impl (void)
1190 {
1191     delete [] pMsgBuffer;
1192 }
1193 
1194 /*
1195  * PutMsgLine.
1196  */
1197 int INetMessageDecode64Stream_Impl::PutMsgLine (
1198     const sal_Char *pData, sal_uIntPtr nSize)
1199 {
1200     INetMessage *pMsg = GetTargetMessage ();
1201     if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
1202 
1203     SvOpenLockBytes * pLB = PTR_CAST(SvOpenLockBytes, pMsg->GetDocumentLB());
1204     if (pLB == NULL) return INETSTREAM_STATUS_WOULDBLOCK;
1205 
1206     const sal_Char *pStop = (pData + nSize);
1207     while (pData < pStop)
1208     {
1209         if (pr2six[(int)(*pData)] > 63)
1210         {
1211             /*
1212              * Character not in base64 alphabet.
1213              * Check for <End-of-Stream> or Junk.
1214              */
1215             if (*pData == '=')
1216             {
1217                 // Final pad character -> Done.
1218                 sal_Size nDocSiz = pMsg->GetDocumentSize();
1219                 sal_Size nRead   = pMsgWrite - pMsgBuffer;
1220                 sal_Size nWrite  = 0;
1221 
1222                 pLB->FillAppend (pMsgBuffer, nRead, &nWrite);
1223                 pMsg->SetDocumentSize (nDocSiz + nWrite);
1224 
1225                 if (nWrite < nRead)
1226                     return INETSTREAM_STATUS_ERROR;
1227                 else
1228                     return INETSTREAM_STATUS_LOADED;
1229             }
1230             else if (eState == INETMSG_EOL_FCR)
1231             {
1232                 // Skip any line break character.
1233                 if ((*pData == '\r') || (*pData == '\n')) pData++;
1234 
1235                 // Store decoded message buffer contents.
1236                 sal_Size nDocSiz = pMsg->GetDocumentSize();
1237                 sal_Size nRead   = pMsgWrite - pMsgBuffer;
1238                 sal_Size nWrite  = 0;
1239 
1240                 pLB->FillAppend (pMsgBuffer, nRead, &nWrite);
1241                 pMsg->SetDocumentSize (nDocSiz + nWrite);
1242 
1243                 if (nWrite < nRead) return INETSTREAM_STATUS_ERROR;
1244 
1245                 // Reset to <Begin-of-Buffer>.
1246                 pMsgWrite = pMsgBuffer;
1247                 eState = INETMSG_EOL_SCR;
1248             }
1249             else if ((*pData == '\r') || (*pData == '\n'))
1250             {
1251                 // Skip any line break character.
1252                 pData++;
1253                 eState = INETMSG_EOL_FCR;
1254             }
1255             else
1256             {
1257                 // Skip any junk character (may be transmission error).
1258                 pData++;
1259             }
1260         }
1261         else
1262         {
1263             // Decode any other character into message buffer.
1264             switch ((pMsgRead - pMsgBuffer) % 4)
1265             {
1266                 case 0:
1267                     *pMsgWrite    = (pr2six[(int)(*pData++)] << 2);
1268                     pMsgRead++;
1269                     break;
1270 
1271                 case 1:
1272                     *pMsgWrite++ |= (pr2six[(int)(*pData  )] >> 4);
1273                     *pMsgWrite    = (pr2six[(int)(*pData++)] << 4);
1274                     pMsgRead++;
1275                     break;
1276 
1277                 case 2:
1278                     *pMsgWrite++ |= (pr2six[(int)(*pData  )] >> 2);
1279                     *pMsgWrite    = (pr2six[(int)(*pData++)] << 6);
1280                     pMsgRead++;
1281                     break;
1282 
1283                 default: // == case 3
1284                     *pMsgWrite++ |= (pr2six[(int)(*pData++)]);
1285                     pMsgRead = pMsgBuffer;
1286                     break;
1287             } // switch ((pMsgRead - pMsgBuffer) % 4)
1288         }
1289     } // while (pData < pStop)
1290     return INETSTREAM_STATUS_OK;
1291 }
1292 
1293 /*=========================================================================
1294  *
1295  * INetMIMEMessageStream Implementation.
1296  *
1297  *=======================================================================*/
1298 /*
1299  * INetMIMEMessageStream.
1300  */
1301 INetMIMEMessageStream::INetMIMEMessageStream (sal_uIntPtr nBufferSize)
1302     : INetMessageIOStream (nBufferSize),
1303       eState      (INETMSG_EOL_BEGIN),
1304       nChildIndex (0),
1305       pChildStrm  (NULL),
1306       eEncoding   (INETMSG_ENCODING_BINARY),
1307       pEncodeStrm (NULL),
1308       pDecodeStrm (NULL),
1309       pMsgBuffer  (NULL)
1310 {
1311 }
1312 
1313 /*
1314  * ~INetMIMEMessageStream.
1315  */
1316 INetMIMEMessageStream::~INetMIMEMessageStream (void)
1317 {
1318     delete pChildStrm;
1319     delete pEncodeStrm;
1320     delete pDecodeStrm;
1321     delete pMsgBuffer;
1322 }
1323 
1324 /*
1325  * GetMsgEncoding.
1326  */
1327 INetMessageEncoding
1328 INetMIMEMessageStream::GetMsgEncoding (const String& rContentType)
1329 {
1330     if ((rContentType.CompareIgnoreCaseToAscii ("message"  , 7) == 0) ||
1331         (rContentType.CompareIgnoreCaseToAscii ("multipart", 9) == 0)    )
1332         return INETMSG_ENCODING_7BIT;
1333 
1334     if (rContentType.CompareIgnoreCaseToAscii ("text", 4) == 0)
1335     {
1336         if (rContentType.CompareIgnoreCaseToAscii ("text/plain", 10) == 0)
1337         {
1338             if (rContentType.GetTokenCount ('=') > 1)
1339             {
1340                 String aCharset (rContentType.GetToken (1, '='));
1341                 aCharset.EraseLeadingChars (' ');
1342                 aCharset.EraseLeadingChars ('"');
1343 
1344                 if (aCharset.CompareIgnoreCaseToAscii ("us-ascii", 8) == 0)
1345                     return INETMSG_ENCODING_7BIT;
1346                 else
1347                     return INETMSG_ENCODING_QUOTED;
1348             }
1349             else
1350                 return INETMSG_ENCODING_7BIT;
1351         }
1352         else
1353             return INETMSG_ENCODING_QUOTED;
1354     }
1355 
1356     return INETMSG_ENCODING_BASE64;
1357 }
1358 
1359 /*
1360  * GetMsgLine.
1361  * (Message Generator).
1362  */
1363 int INetMIMEMessageStream::GetMsgLine (sal_Char *pData, sal_uIntPtr nSize)
1364 {
1365     // Check for message container.
1366     INetMIMEMessage *pMsg = GetSourceMessage();
1367     if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
1368 
1369     // Check for header or body.
1370     if (!IsHeaderGenerated())
1371     {
1372         if (eState == INETMSG_EOL_BEGIN)
1373         {
1374             // Prepare special header fields.
1375             if (pMsg->GetParent())
1376             {
1377                 String aPCT (pMsg->GetParent()->GetContentType());
1378                 if (aPCT.CompareIgnoreCaseToAscii ("message/rfc822", 14) == 0)
1379                     pMsg->SetMIMEVersion (
1380                         String(CONSTASCII_STRINGPARAM("1.0")));
1381                 else
1382                     pMsg->SetMIMEVersion (String());
1383             }
1384             else
1385             {
1386                 pMsg->SetMIMEVersion (String(CONSTASCII_STRINGPARAM("1.0")));
1387             }
1388 
1389             // Check ContentType.
1390             String aContentType (pMsg->GetContentType());
1391             if (aContentType.Len())
1392             {
1393                 // Determine default Content-Type.
1394                 String aDefaultType;
1395                 pMsg->GetDefaultContentType (aDefaultType);
1396 
1397                 if (aDefaultType.CompareIgnoreCaseToAscii (
1398                     aContentType, aContentType.Len()) == 0)
1399                 {
1400                     // No need to specify default.
1401                     pMsg->SetContentType (String());
1402                 }
1403             }
1404 
1405             // Check Encoding.
1406             String aEncoding (pMsg->GetContentTransferEncoding());
1407             if (aEncoding.Len())
1408             {
1409                 // Use given Encoding.
1410                 if (aEncoding.CompareIgnoreCaseToAscii (
1411                     "base64", 6) == 0)
1412                     eEncoding = INETMSG_ENCODING_BASE64;
1413                 else if (aEncoding.CompareIgnoreCaseToAscii (
1414                     "quoted-printable", 16) == 0)
1415                     eEncoding = INETMSG_ENCODING_QUOTED;
1416                 else
1417                     eEncoding = INETMSG_ENCODING_7BIT;
1418             }
1419             else
1420             {
1421                 // Use default Encoding for (given|default) Content-Type.
1422                 if (aContentType.Len() == 0)
1423                 {
1424                     // Determine default Content-Type.
1425                     pMsg->GetDefaultContentType (aContentType);
1426                 }
1427                 eEncoding = GetMsgEncoding (aContentType);
1428             }
1429 
1430             // Set Content-Transfer-Encoding header.
1431             if (eEncoding == INETMSG_ENCODING_BASE64)
1432             {
1433                 // Base64.
1434                 pMsg->SetContentTransferEncoding (
1435                     String(CONSTASCII_STRINGPARAM("base64")));
1436             }
1437             else if (eEncoding == INETMSG_ENCODING_QUOTED)
1438             {
1439                 // Quoted-Printable.
1440                 pMsg->SetContentTransferEncoding (
1441                     String(CONSTASCII_STRINGPARAM("quoted-printable")));
1442             }
1443             else
1444             {
1445                 // No need to specify default.
1446                 pMsg->SetContentTransferEncoding (String());
1447             }
1448 
1449             // Mark we're done.
1450             eState = INETMSG_EOL_DONE;
1451         }
1452 
1453         // Generate the message header.
1454         int nRead = INetMessageIOStream::GetMsgLine (pData, nSize);
1455         if (nRead <= 0)
1456         {
1457             // Reset state.
1458             eState = INETMSG_EOL_BEGIN;
1459         }
1460         return nRead;
1461     }
1462     else
1463     {
1464         // Generate the message body.
1465         if (pMsg->IsContainer())
1466         {
1467             // Encapsulated message body.
1468             while (eState == INETMSG_EOL_BEGIN)
1469             {
1470                 if (pChildStrm == NULL)
1471                 {
1472                     INetMIMEMessage *pChild = pMsg->GetChild (nChildIndex);
1473                     if (pChild)
1474                     {
1475                         // Increment child index.
1476                         nChildIndex++;
1477 
1478                         // Create child stream.
1479                         pChildStrm = new INetMIMEMessageStream;
1480                         pChildStrm->SetSourceMessage (pChild);
1481 
1482                         if (pMsg->IsMultipart())
1483                         {
1484                             // Insert multipart delimiter.
1485                             ByteString aDelim ("--");
1486                             aDelim += pMsg->GetMultipartBoundary();
1487                             aDelim += "\r\n";
1488 
1489                             rtl_copyMemory (
1490                                 pData, aDelim.GetBuffer(), aDelim.Len());
1491                             return aDelim.Len();
1492                         }
1493                     }
1494                     else
1495                     {
1496                         // No more parts. Mark we're done.
1497                         eState = INETMSG_EOL_DONE;
1498                         nChildIndex = 0;
1499 
1500                         if (pMsg->IsMultipart())
1501                         {
1502                             // Insert close delimiter.
1503                             ByteString aDelim ("--");
1504                             aDelim += pMsg->GetMultipartBoundary();
1505                             aDelim += "--\r\n";
1506 
1507                             rtl_copyMemory (
1508                                 pData, aDelim.GetBuffer(), aDelim.Len());
1509                             return aDelim.Len();
1510                         }
1511                     }
1512                 }
1513                 else
1514                 {
1515                     // Read current child stream.
1516                     int nRead = pChildStrm->Read (pData, nSize);
1517                     if (nRead > 0)
1518                     {
1519                         return nRead;
1520                     }
1521                     else
1522                     {
1523                         // Cleanup exhausted child stream.
1524                         delete pChildStrm;
1525                         pChildStrm = NULL;
1526                     }
1527                 }
1528             }
1529             return 0;
1530         }
1531         else
1532         {
1533             // Single part message body.
1534             if (pMsg->GetDocumentLB() == NULL)
1535             {
1536                 // Empty message body.
1537                 return 0;
1538             }
1539             else
1540             {
1541                 // Check whether message body needs to be encoded.
1542                 if (eEncoding == INETMSG_ENCODING_7BIT)
1543                 {
1544                     // No Encoding.
1545                     return INetMessageIOStream::GetMsgLine (pData, nSize);
1546                 }
1547                 else
1548                 {
1549                     // Apply appropriate Encoding.
1550                     while (eState == INETMSG_EOL_BEGIN)
1551                     {
1552                         if (pEncodeStrm == NULL)
1553                         {
1554                             // Create encoder stream.
1555                             if (eEncoding == INETMSG_ENCODING_QUOTED)
1556                             {
1557                                 // Quoted-Printable Encoding.
1558                                 pEncodeStrm
1559                                  = new INetMessageEncodeQPStream_Impl;
1560                             }
1561                             else
1562                             {
1563                                 // Base64 Encoding.
1564                                 pEncodeStrm
1565                                  = new INetMessageEncode64Stream_Impl;
1566                             }
1567                             pEncodeStrm->SetSourceMessage (pMsg);
1568                         }
1569 
1570                         // Read encoded message.
1571                         int nRead = pEncodeStrm->Read (pData, nSize);
1572                         if (nRead > 0)
1573                         {
1574                             return nRead;
1575                         }
1576                         else
1577                         {
1578                             // Cleanup exhausted encoder stream.
1579                             delete pEncodeStrm;
1580                             pEncodeStrm = NULL;
1581 
1582                             // Mark we're done.
1583                             eState = INETMSG_EOL_DONE;
1584                         }
1585                     }
1586                     return 0;
1587                 }
1588             }
1589         }
1590     }
1591 }
1592 
1593 /*
1594  * PutMsgLine.
1595  * (Message Parser).
1596  */
1597 int INetMIMEMessageStream::PutMsgLine (const sal_Char *pData, sal_uIntPtr nSize)
1598 {
1599     // Check for message container.
1600     INetMIMEMessage *pMsg = GetTargetMessage();
1601     if (pMsg == NULL) return INETSTREAM_STATUS_ERROR;
1602 
1603     // Check for header or body.
1604     if (!IsHeaderParsed())
1605     {
1606         // Parse the message header.
1607         int nRet = INetMessageIOStream::PutMsgLine (pData, nSize);
1608         return nRet;
1609     }
1610     else
1611     {
1612         pMsg->SetHeaderParsed();
1613         // Parse the message body.
1614         if (pMsg->IsContainer())
1615         {
1616 
1617             // Content-Transfer-Encoding MUST be "7bit" (RFC1521).
1618             if (pMsg->IsMessage())
1619             {
1620                 if( !pChildStrm )
1621                 {
1622                     // Encapsulated message.
1623                     pMsg->SetChildCount( pMsg->GetChildCount() + 1);
1624                     INetMIMEMessage* pNewMessage = new INetMIMEMessage;
1625                     pNewMessage->SetDocumentLB (
1626                         new SvAsyncLockBytes(new SvCacheStream, sal_False));
1627                     pMsg->AttachChild( *pNewMessage, sal_True );
1628 
1629                     // Encapsulated message body. Create message parser stream.
1630                     pChildStrm = new INetMIMEMessageStream;
1631                     pChildStrm->SetTargetMessage ( pNewMessage );
1632 
1633                     // Initialize control variables.
1634                     eState = INETMSG_EOL_BEGIN;
1635                 }
1636                 if ( nSize > 0)
1637                 {
1638                     // Bytes still in buffer. Put message down-stream.
1639                     int status = pChildStrm->Write( pData, nSize );
1640                     if (status != INETSTREAM_STATUS_OK)
1641                         return status;
1642                 }
1643 
1644                 return INetMessageIOStream::PutMsgLine (pData, nSize);
1645             }
1646             else
1647             {
1648 
1649                 // Multipart message body. Initialize multipart delimiters.
1650                 // Multipart message.
1651                 if (pMsg->GetMultipartBoundary().Len() == 0)
1652                 {
1653                     // Determine boundary.
1654                     ByteString aType (
1655                         pMsg->GetContentType(), RTL_TEXTENCODING_ASCII_US);
1656                     ByteString aLowerType (aType);
1657                     aLowerType.ToLowerAscii();
1658 
1659                     sal_uInt16 nPos = aLowerType.Search ("boundary=");
1660                     ByteString aBoundary (aType.Copy (nPos + 9));
1661 
1662                     aBoundary.EraseLeadingAndTrailingChars (' ');
1663                     aBoundary.EraseLeadingAndTrailingChars ('"');
1664 
1665                     // Save boundary.
1666                     pMsg->SetMultipartBoundary (aBoundary);
1667                 }
1668 
1669                 ByteString aPlainDelim (pMsg->GetMultipartBoundary());
1670                 ByteString aDelim ("--");
1671                 aDelim += aPlainDelim;
1672 
1673                 ByteString aPlainClose (aPlainDelim);
1674                 aPlainClose += "--";
1675 
1676                 ByteString aClose (aDelim);
1677                 aClose += "--";
1678 
1679                 if (pMsgBuffer == NULL) pMsgBuffer = new SvMemoryStream;
1680                 pMsgBuffer->Write (pData, nSize);
1681                 sal_uIntPtr nBufSize = pMsgBuffer->Tell();
1682 
1683                 const sal_Char* pChar;
1684                 const sal_Char* pOldPos;
1685                 for( pOldPos = pChar = (const sal_Char *) pMsgBuffer->GetData(); nBufSize--;
1686                      pChar++ )
1687                 {
1688                     int status;
1689                     if( *pChar == '\r' || *pChar == '\n' )
1690                     {
1691                         if( aDelim.CompareTo (pOldPos, aDelim.Len())
1692                             != COMPARE_EQUAL &&
1693                             aClose.CompareTo (pOldPos, aClose.Len())
1694                             != COMPARE_EQUAL &&
1695                             aPlainDelim.CompareTo (pOldPos, aPlainDelim.Len())
1696                             != COMPARE_EQUAL &&
1697                             aPlainClose.CompareTo(pOldPos, aPlainClose.Len())
1698                             != COMPARE_EQUAL )
1699                         {
1700                             if( nBufSize &&
1701                                 ( pChar[1] == '\r' || pChar[1] == '\n' ) )
1702                                 nBufSize--, pChar++;
1703                             if( pChildStrm )
1704                             {
1705                                 status = pChildStrm->Write(
1706                                     pOldPos, pChar - pOldPos + 1 );
1707                                 if( status != INETSTREAM_STATUS_OK )
1708                                     return status;
1709                             }
1710                             else {
1711                                 DBG_ERRORFILE( "Die Boundary nicht gefunden" );
1712                             }
1713                             status = INetMessageIOStream::PutMsgLine(
1714                                 pOldPos, pChar - pOldPos + 1 );
1715                             if( status != INETSTREAM_STATUS_OK )
1716                                 return status;
1717                             pOldPos = pChar + 1;
1718                         }
1719                         else
1720                         {
1721                             if( nBufSize &&
1722                                 ( pChar[1] == '\r' || pChar[1] == '\n' ) )
1723                                 nBufSize--, pChar++;
1724                             pOldPos = pChar + 1;
1725                             DELETEZ( pChildStrm );
1726 
1727                             if (aClose.CompareTo (pOldPos, aClose.Len())
1728                                 != COMPARE_EQUAL &&
1729                                 aPlainClose.CompareTo (pOldPos, aClose.Len())
1730                                 != COMPARE_EQUAL )
1731                             {
1732                                 // Encapsulated message.
1733                                 pMsg->SetChildCount(pMsg->GetChildCount() + 1);
1734                                 INetMIMEMessage* pNewMessage =
1735                                     new INetMIMEMessage;
1736                                 pNewMessage->SetDocumentLB (
1737                                     new SvAsyncLockBytes (
1738                                         new SvCacheStream, sal_False));
1739 
1740                                 pMsg->AttachChild( *pNewMessage, sal_True );
1741 
1742                                 // Encapsulated message body. Create message parser stream.
1743                                 pChildStrm = new INetMIMEMessageStream;
1744                                 pChildStrm->SetTargetMessage ( pNewMessage );
1745 
1746                                 // Initialize control variables.
1747                             }
1748                             eState = INETMSG_EOL_BEGIN;
1749                             status = INetMessageIOStream::PutMsgLine(
1750                                 pOldPos, pChar - pOldPos + 1 );
1751                             if( status != INETSTREAM_STATUS_OK )
1752                                 return status;
1753                         }
1754                     }
1755                 }
1756                 if( pOldPos < pChar )
1757                 {
1758                     SvMemoryStream* pNewStream = new SvMemoryStream;
1759                     pNewStream->Write( pOldPos, pChar - pOldPos );
1760                     SvMemoryStream* pTmp = pMsgBuffer;
1761                     pMsgBuffer = pNewStream;
1762                     delete pTmp;
1763                 }
1764                 else
1765                 {
1766                     pMsgBuffer->Seek( 0L );
1767                     pMsgBuffer->SetStreamSize( 0 );
1768                 }
1769                 return INETSTREAM_STATUS_OK;
1770             }
1771         }
1772         else
1773         {
1774             /*
1775              * Single part message.
1776              * Remove any ContentTransferEncoding.
1777              */
1778             if (pMsg->GetContentType().Len() == 0)
1779             {
1780                 String aDefaultCT;
1781                 pMsg->GetDefaultContentType (aDefaultCT);
1782                 pMsg->SetContentType (aDefaultCT);
1783             }
1784 
1785             if (eEncoding == INETMSG_ENCODING_BINARY)
1786             {
1787                 String aEncoding (pMsg->GetContentTransferEncoding());
1788                 if (aEncoding.CompareIgnoreCaseToAscii (
1789                     "base64", 6) == COMPARE_EQUAL)
1790                     eEncoding = INETMSG_ENCODING_BASE64;
1791                 else if (aEncoding.CompareIgnoreCaseToAscii (
1792                     "quoted-printable", 16) == COMPARE_EQUAL)
1793                     eEncoding = INETMSG_ENCODING_QUOTED;
1794                 else
1795                     eEncoding = INETMSG_ENCODING_7BIT;
1796             }
1797 
1798             if (eEncoding == INETMSG_ENCODING_7BIT)
1799             {
1800                 // No decoding necessary.
1801                 return INetMessageIOStream::PutMsgLine (pData, nSize);
1802             }
1803             else
1804             {
1805                 if (pDecodeStrm == NULL)
1806                 {
1807                     if (eEncoding == INETMSG_ENCODING_QUOTED)
1808                         pDecodeStrm = new INetMessageDecodeQPStream_Impl;
1809                     else
1810                         pDecodeStrm = new INetMessageDecode64Stream_Impl;
1811 
1812                     pDecodeStrm->SetTargetMessage (pMsg);
1813                 }
1814                 return pDecodeStrm->Write (pData, nSize);
1815             }
1816         }
1817     }
1818 }
1819 
1820 
1821 
1822