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