xref: /aoo41x/main/tools/source/inet/inetmsg.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 <tools/datetime.hxx>
32 #ifndef _TOOLS_INETMIME_HXX
33 #include <tools/inetmime.hxx>
34 #endif
35 #include <tools/inetmsg.hxx>
36 #include <tools/inetstrm.hxx>
37 #include <rtl/instance.hxx>
38 
39 #include <stdio.h>
40 
41 //=======================================================================
42 
43 inline sal_Bool ascii_isDigit( sal_Unicode ch )
44 {
45     return ((ch >= 0x0030) && (ch <= 0x0039));
46 }
47 
48 inline sal_Bool ascii_isLetter( sal_Unicode ch )
49 {
50     return (( (ch >= 0x0041) && (ch <= 0x005A)) || ((ch >= 0x0061) && (ch <= 0x007A)));
51 }
52 
53 inline sal_Unicode ascii_toLowerCase( sal_Unicode ch )
54 {
55     if ( (ch >= 0x0041) && (ch <= 0x005A) )
56         return ch + 0x20;
57     else
58         return ch;
59 }
60 
61 /*=======================================================================
62  *
63  * INetMessage Implementation.
64  *
65  *=====================================================================*/
66 #define CONSTASCII_STRINGPARAM(a) (a), RTL_TEXTENCODING_ASCII_US
67 #define HEADERFIELD INetMessageHeader
68 
69 /*
70  * ~INetMessage.
71  */
72 INetMessage::~INetMessage (void)
73 {
74     ListCleanup_Impl();
75 }
76 
77 /*
78  * ListCleanup_Impl.
79  */
80 void INetMessage::ListCleanup_Impl (void)
81 {
82     // Cleanup.
83     sal_uIntPtr i, n = m_aHeaderList.Count();
84     for (i = 0; i < n; i++)
85         delete ((HEADERFIELD*)(m_aHeaderList.GetObject(i)));
86     m_aHeaderList.Clear();
87 }
88 
89 /*
90  * ListCopy.
91  */
92 void INetMessage::ListCopy (const INetMessage &rMsg)
93 {
94     if (!(this == &rMsg))
95     {
96         // Cleanup.
97         ListCleanup_Impl();
98 
99         // Copy.
100         sal_uIntPtr i, n = rMsg.GetHeaderCount();
101         for (i = 0; i < n; i++)
102         {
103             HEADERFIELD *p = (HEADERFIELD*)(rMsg.m_aHeaderList.GetObject(i));
104             m_aHeaderList.Insert (new HEADERFIELD(*p), LIST_APPEND);
105         }
106     }
107 }
108 
109 /*
110  * SetHeaderField_Impl.
111  */
112 void INetMessage::SetHeaderField_Impl (
113     INetMIME::HeaderFieldType  eType,
114     const ByteString          &rName,
115     const UniString           &rValue,
116     sal_uIntPtr                     &rnIndex)
117 {
118     INetMIMEStringOutputSink aSink (0, STRING_MAXLEN);
119     INetMIME::writeHeaderFieldBody (
120         aSink, eType, rValue, gsl_getSystemTextEncoding(), false);
121     SetHeaderField_Impl (
122         INetMessageHeader (rName, aSink.takeBuffer()), rnIndex);
123 }
124 
125 /*
126  * SetHeaderField.
127  */
128 sal_uIntPtr INetMessage::SetHeaderField (
129     const UniString& rName, const UniString& rValue, sal_uIntPtr nIndex)
130 {
131     sal_uIntPtr nResult = nIndex;
132     SetHeaderField_Impl (
133         INetMIME::HEADER_FIELD_TEXT,
134         ByteString (rName, RTL_TEXTENCODING_ASCII_US), rValue,
135         nResult);
136     return nResult;
137 }
138 
139 /*
140  * SetHeaderField.
141  */
142 sal_uIntPtr INetMessage::SetHeaderField (
143     const INetMessageHeader &rHeader, sal_uIntPtr nIndex)
144 {
145     sal_uIntPtr nResult = nIndex;
146     SetHeaderField_Impl (rHeader, nResult);
147     return nResult;
148 }
149 
150 
151 /*
152  * operator<<
153  */
154 SvStream& INetMessage::operator<< (SvStream& rStrm) const
155 {
156     rStrm << static_cast<sal_uInt32>(m_nDocSize);
157     rStrm.WriteByteString (m_aDocName, RTL_TEXTENCODING_UTF8);
158 
159     sal_uIntPtr i, n = m_aHeaderList.Count();
160     rStrm << static_cast<sal_uInt32>(n);
161 
162     for (i = 0; i < n; i++)
163         rStrm << *((HEADERFIELD *)(m_aHeaderList.GetObject(i)));
164 
165     return rStrm;
166 }
167 
168 /*
169  * operator>>
170  */
171 SvStream& INetMessage::operator>> (SvStream& rStrm)
172 {
173     // Cleanup.
174     m_nDocSize = 0;
175     m_xDocLB.Clear();
176     ListCleanup_Impl();
177 
178     sal_uInt32 nTemp;
179 
180     // Copy.
181     rStrm >> nTemp;
182     m_nDocSize = nTemp;
183     rStrm.ReadByteString (m_aDocName, RTL_TEXTENCODING_UTF8);
184 
185     sal_uIntPtr i, n = 0;
186     rStrm >> nTemp;
187     n = nTemp;
188 
189     for (i = 0; i < n; i++)
190     {
191         HEADERFIELD *p = new HEADERFIELD();
192         rStrm >> *p;
193         m_aHeaderList.Insert (p, LIST_APPEND);
194     }
195 
196     // Done.
197     return rStrm;
198 }
199 
200 /*=======================================================================
201  *
202  * INetMessageHeaderIterator Implementation.
203  *
204  *=====================================================================*/
205 INetMessageHeaderIterator::INetMessageHeaderIterator (
206     const INetMessage& rMsg, const UniString& rHdrName)
207 {
208     sal_uIntPtr i, n = rMsg.GetHeaderCount();
209     for (i = 0; i < n; i++)
210     {
211         if (rHdrName.CompareIgnoreCaseToAscii (rMsg.GetHeaderName(i)) == 0)
212         {
213             UniString *pValue = new UniString (rMsg.GetHeaderValue(i));
214             aValueList.Insert (pValue, LIST_APPEND);
215         }
216     }
217     nValueCount = aValueList.Count();
218 }
219 
220 INetMessageHeaderIterator::~INetMessageHeaderIterator (void)
221 {
222     sal_uIntPtr i, n = aValueList.Count();
223     for (i = 0; i < n; i++)
224         delete ((UniString*)(aValueList.GetObject(i)));
225     aValueList.Clear();
226 }
227 
228 /*=======================================================================
229  *
230  * INetRFC822Message Implementation.
231  *
232  *=====================================================================*/
233 /*
234  * ImplINetRFC822MessageHeaderData.
235  */
236 namespace
237 {
238     struct ImplINetRFC822MessageHeaderDataImpl
239     {
240         const ByteString* operator()()
241         {
242             static const ByteString _ImplINetRFC822MessageHeaderData[] =
243             {
244                 ByteString ("BCC"),
245                 ByteString ("CC"),
246                 ByteString ("Comments"),
247                 ByteString ("Date"),
248                 ByteString ("From"),
249                 ByteString ("In-Reply-To"),
250                 ByteString ("Keywords"),
251                 ByteString ("Message-ID"),
252                 ByteString ("References"),
253                 ByteString ("Reply-To"),
254                 ByteString ("Return-Path"),
255                 ByteString ("Subject"),
256                 ByteString ("Sender"),
257                 ByteString ("To"),
258                 ByteString ("X-Mailer"),
259                 ByteString ("Return-Receipt-To")
260             };
261             return &_ImplINetRFC822MessageHeaderData[0];
262         }
263     };
264 
265     struct ImplINetRFC822MessageHeaderData
266     	: public rtl::StaticAggregate< const ByteString, ImplINetRFC822MessageHeaderDataImpl > {};
267 }
268 
269 #define HDR(n) ImplINetRFC822MessageHeaderData::get()[(n)]
270 
271 /*
272  * _ImplINetRFC822MessageHeaderState.
273  */
274 enum _ImplINetRFC822MessageHeaderState
275 {
276     INETMSG_RFC822_BEGIN,
277     INETMSG_RFC822_CHECK,
278     INETMSG_RFC822_OK,
279     INETMSG_RFC822_JUNK,
280 
281     INETMSG_RFC822_TOKEN_RE,
282     INETMSG_RFC822_TOKEN_RETURNMINUS,
283     INETMSG_RFC822_TOKEN_XMINUS,
284     INETMSG_RFC822_LETTER_C,
285     INETMSG_RFC822_LETTER_S
286 };
287 
288 /*
289  * INetRFC822Message.
290  */
291 INetRFC822Message::INetRFC822Message (void)
292     : INetMessage()
293 {
294     for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
295         m_nIndex[i] = LIST_ENTRY_NOTFOUND;
296 }
297 
298 INetRFC822Message::INetRFC822Message (const INetRFC822Message& rMsg)
299     : INetMessage (rMsg)
300 {
301     for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
302         m_nIndex[i] = rMsg.m_nIndex[i];
303 }
304 
305 /*
306  * operator=
307  */
308 INetRFC822Message& INetRFC822Message::operator= (const INetRFC822Message& rMsg)
309 {
310     if (this != &rMsg)
311     {
312         INetMessage::operator= (rMsg);
313 
314         for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
315             m_nIndex[i] = rMsg.m_nIndex[i];
316     }
317     return *this;
318 }
319 
320 /*
321  * ~INetRFC822Message.
322  */
323 INetRFC822Message::~INetRFC822Message (void)
324 {
325 }
326 
327 /*
328  * <Generate|Parse>DateField and local helper functions.
329  *
330  * GenerateDateField.
331  * Generates a String from Date and Time objects in format:
332  *   Wkd, 00 Mon 0000 00:00:00 [GMT]            (rfc822, rfc1123)
333  *
334  * ParseDateField.
335  * Parses a String in (implied) GMT format into class Date and Time objects.
336  * Four formats are accepted:
337  *
338  *  [Wkd,] 1*2DIGIT Mon 2*4DIGIT 00:00:00 [GMT]  (rfc1123)
339  *  [Wkd,] 00 Mon 0000 00:00:00 [GMT])           (rfc822, rfc1123)
340  *   Weekday, 00-Mon-00 00:00:00 [GMT]           (rfc850, rfc1036)
341  *   Wkd Mon 00 00:00:00 0000 [GMT]              (ctime)
342  *   1*DIGIT                                     (delta seconds)
343  *
344  */
345 
346 // Months and Weekdays.
347 static const sal_Char *months[12] =
348 {
349     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
350     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
351 };
352 
353 static const sal_Char *wkdays[7] =
354 {
355     "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
356 };
357 
358 /*
359  * GenerateDateField.
360  */
361 sal_Bool INetRFC822Message::GenerateDateField (
362     const DateTime& rDateTime, UniString& rDateFieldW)
363 {
364     // Check arguments.
365     if (!rDateTime.IsValid()       ||
366         (rDateTime.GetSec()  > 59) ||
367         (rDateTime.GetMin()  > 59) ||
368         (rDateTime.GetHour() > 23)    ) return sal_False;
369 
370     // Prepare output string.
371     ByteString rDateField;
372 
373     // Insert Date.
374     rDateField += wkdays[(sal_uInt16)(rDateTime.GetDayOfWeek())];
375     rDateField += ", ";
376 
377     sal_uInt16 nNum = rDateTime.GetDay();
378     if (nNum < 10) rDateField += '0';
379     rDateField += ByteString::CreateFromInt32(nNum);
380     rDateField += ' ';
381 
382     rDateField += months[(sal_uInt16)(rDateTime.GetMonth() - 1)];
383     rDateField += ' ';
384 
385     rDateField += ByteString::CreateFromInt32(rDateTime.GetYear());
386     rDateField += ' ';
387 
388     // Insert Time.
389     nNum = rDateTime.GetHour();
390     if (nNum < 10) rDateField += '0';
391     rDateField += ByteString::CreateFromInt32(nNum);
392     rDateField += ':';
393 
394     nNum = rDateTime.GetMin();
395     if (nNum < 10) rDateField += '0';
396     rDateField += ByteString::CreateFromInt32(nNum);
397     rDateField += ':';
398 
399     nNum = rDateTime.GetSec();
400     if (nNum < 10) rDateField += '0';
401     rDateField += ByteString::CreateFromInt32(nNum);
402     rDateField += " GMT";
403 
404     // Done.
405     rDateFieldW = UniString (rDateField, RTL_TEXTENCODING_ASCII_US);
406     return sal_True;
407 }
408 
409 /*
410  * ParseDateField and local helper functions.
411  */
412 static sal_uInt16 ParseNumber (const ByteString& rStr, sal_uInt16& nIndex)
413 {
414     sal_uInt16 n = nIndex;
415     while ((n < rStr.Len()) && ascii_isDigit(rStr.GetChar(n))) n++;
416 
417     ByteString aNum (rStr.Copy (nIndex, (n - nIndex)));
418     nIndex = n;
419 
420     return (sal_uInt16)(aNum.ToInt32());
421 }
422 
423 static sal_uInt16 ParseMonth (const ByteString& rStr, sal_uInt16& nIndex)
424 {
425     sal_uInt16 n = nIndex;
426     while ((n < rStr.Len()) && ascii_isLetter(rStr.GetChar(n))) n++;
427 
428     ByteString aMonth (rStr.Copy (nIndex, 3));
429     nIndex = n;
430 
431     sal_uInt16 i;
432     for (i = 0; i < 12; i++)
433         if (aMonth.CompareIgnoreCaseToAscii (months[i]) == 0) break;
434     return (i + 1);
435 }
436 
437 sal_Bool INetRFC822Message::ParseDateField (
438     const UniString& rDateFieldW, DateTime& rDateTime)
439 {
440     ByteString rDateField (rDateFieldW, RTL_TEXTENCODING_ASCII_US);
441     if (rDateField.Len() == 0) return sal_False;
442 
443     if (rDateField.Search (':') != STRING_NOTFOUND)
444     {
445         // Some DateTime format.
446         sal_uInt16 nIndex = 0;
447 
448         // Skip over <Wkd> or <Weekday>, leading and trailing space.
449         while ((nIndex < rDateField.Len()) &&
450                (rDateField.GetChar(nIndex) == ' '))
451             nIndex++;
452 
453         while (
454             (nIndex < rDateField.Len()) &&
455             (ascii_isLetter (rDateField.GetChar(nIndex)) ||
456              (rDateField.GetChar(nIndex) == ',')     ))
457             nIndex++;
458 
459         while ((nIndex < rDateField.Len()) &&
460                (rDateField.GetChar(nIndex) == ' '))
461             nIndex++;
462 
463         if (ascii_isLetter (rDateField.GetChar(nIndex)))
464         {
465             // Format: ctime().
466             if ((rDateField.Len() - nIndex) < 20) return sal_False;
467 
468             rDateTime.SetMonth  (ParseMonth  (rDateField, nIndex)); nIndex++;
469             rDateTime.SetDay    (ParseNumber (rDateField, nIndex)); nIndex++;
470 
471             rDateTime.SetHour   (ParseNumber (rDateField, nIndex)); nIndex++;
472             rDateTime.SetMin    (ParseNumber (rDateField, nIndex)); nIndex++;
473             rDateTime.SetSec    (ParseNumber (rDateField, nIndex)); nIndex++;
474             rDateTime.Set100Sec (0);
475 
476             sal_uInt16 nYear = ParseNumber (rDateField, nIndex);
477             if (nYear < 100) nYear += 1900;
478             rDateTime.SetYear   (nYear);
479         }
480         else
481         {
482             // Format: RFC1036 or RFC1123.
483             if ((rDateField.Len() - nIndex) < 17) return sal_False;
484 
485             rDateTime.SetDay    (ParseNumber (rDateField, nIndex)); nIndex++;
486             rDateTime.SetMonth  (ParseMonth  (rDateField, nIndex)); nIndex++;
487 
488             sal_uInt16 nYear  = ParseNumber (rDateField, nIndex);  nIndex++;
489             if (nYear < 100) nYear += 1900;
490             rDateTime.SetYear   (nYear);
491 
492             rDateTime.SetHour   (ParseNumber (rDateField, nIndex)); nIndex++;
493             rDateTime.SetMin    (ParseNumber (rDateField, nIndex)); nIndex++;
494             rDateTime.SetSec    (ParseNumber (rDateField, nIndex)); nIndex++;
495             rDateTime.Set100Sec (0);
496 
497             if ((rDateField.GetChar(nIndex) == '+') ||
498                 (rDateField.GetChar(nIndex) == '-')    )
499             {
500                 // Offset from GMT: "(+|-)HHMM".
501                 sal_Bool   bEast   = (rDateField.GetChar(nIndex++) == '+');
502                 sal_uInt16 nOffset = ParseNumber (rDateField, nIndex);
503                 if (nOffset > 0)
504                 {
505                     Time aDiff;
506                     aDiff.SetHour   (nOffset / 100);
507                     aDiff.SetMin    (nOffset % 100);
508                     aDiff.SetSec    (0);
509                     aDiff.Set100Sec (0);
510 
511                     if (bEast)
512                         rDateTime -= aDiff;
513                     else
514                         rDateTime += aDiff;
515                 }
516             }
517         }
518     }
519     else if (rDateField.IsNumericAscii())
520     {
521         // Format: delta seconds.
522         Time aDelta (0);
523         aDelta.SetTime (rDateField.ToInt32() * 100);
524 
525         DateTime aNow;
526         aNow += aDelta;
527         aNow.ConvertToUTC();
528 
529         rDateTime.SetDate (aNow.GetDate());
530         rDateTime.SetTime (aNow.GetTime());
531     }
532     else
533     {
534         // Junk.
535         return sal_False;
536     }
537 
538     return (rDateTime.IsValid() &&
539             !((rDateTime.GetSec()  > 59) ||
540               (rDateTime.GetMin()  > 59) ||
541               (rDateTime.GetHour() > 23)    ));
542 }
543 
544 /*
545  * SetHeaderField.
546  * (Header Field Parser).
547  */
548 sal_uIntPtr INetRFC822Message::SetHeaderField (
549     const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex)
550 {
551     ByteString aName (rHeader.GetName());
552     const sal_Char *pData = aName.GetBuffer();
553     const sal_Char *pStop = pData + aName.Len() + 1;
554     const sal_Char *check = "";
555 
556     sal_uIntPtr       nIdx     = LIST_APPEND;
557     int         eState   = INETMSG_RFC822_BEGIN;
558     int         eOkState = INETMSG_RFC822_OK;
559 
560     while (pData < pStop)
561     {
562         switch (eState)
563         {
564             case INETMSG_RFC822_BEGIN:
565                 eState = INETMSG_RFC822_CHECK;
566                 eOkState = INETMSG_RFC822_OK;
567 
568                 switch (ascii_toLowerCase (*pData))
569                 {
570                     case 'b':
571                         check = "cc";
572                         nIdx = INETMSG_RFC822_BCC;
573                         break;
574 
575                     case 'c':
576                         eState = INETMSG_RFC822_LETTER_C;
577                         break;
578 
579                     case 'd':
580                         check = "ate";
581                         nIdx = INETMSG_RFC822_DATE;
582                         break;
583 
584                     case 'f':
585                         check = "rom";
586                         nIdx = INETMSG_RFC822_FROM;
587                         break;
588 
589                     case 'i':
590                         check = "n-reply-to";
591                         nIdx = INETMSG_RFC822_IN_REPLY_TO;
592                         break;
593 
594                     case 'k':
595                         check = "eywords";
596                         nIdx = INETMSG_RFC822_KEYWORDS;
597                         break;
598 
599                     case 'm':
600                         check = "essage-id";
601                         nIdx = INETMSG_RFC822_MESSAGE_ID;
602                         break;
603 
604                     case 'r':
605                         check = "e";
606                         eOkState = INETMSG_RFC822_TOKEN_RE;
607                         break;
608 
609                     case 's':
610                         eState = INETMSG_RFC822_LETTER_S;
611                         break;
612 
613                     case 't':
614                         check = "o";
615                         nIdx = INETMSG_RFC822_TO;
616                         break;
617 
618                     case 'x':
619                         check = "-";
620                         eOkState = INETMSG_RFC822_TOKEN_XMINUS;
621                         break;
622 
623                     default:
624                         eState = INETMSG_RFC822_JUNK;
625                         break;
626                 }
627                 pData++;
628                 break;
629 
630             case INETMSG_RFC822_TOKEN_RE:
631                 eState = INETMSG_RFC822_CHECK;
632                 eOkState = INETMSG_RFC822_OK;
633 
634                 switch (ascii_toLowerCase (*pData))
635                 {
636                     case 'f':
637                         check = "erences";
638                         nIdx = INETMSG_RFC822_REFERENCES;
639                         break;
640 
641                     case 'p':
642                         check = "ly-to";
643                         nIdx = INETMSG_RFC822_REPLY_TO;
644                         break;
645 
646                     case 't':
647                         check = "urn-";
648                         eOkState = INETMSG_RFC822_TOKEN_RETURNMINUS;
649                         break;
650 
651                     default:
652                         eState = INETMSG_RFC822_JUNK;
653                         break;
654                 }
655                 pData++;
656                 break;
657 
658             case INETMSG_RFC822_TOKEN_RETURNMINUS:
659                 eState = INETMSG_RFC822_CHECK;
660                 eOkState = INETMSG_RFC822_OK;
661 
662                 switch (ascii_toLowerCase (*pData))
663                 {
664                     case 'p':
665                         check = "ath";
666                         nIdx = INETMSG_RFC822_RETURN_PATH;
667                         break;
668 
669                     case 'r':
670                         check = "eceipt-to";
671                         nIdx = INETMSG_RFC822_RETURN_RECEIPT_TO;
672                         break;
673 
674                     default:
675                         eState = INETMSG_RFC822_JUNK;
676                         break;
677                 }
678                 pData++;
679                 break;
680 
681             case INETMSG_RFC822_TOKEN_XMINUS:
682                 eState = INETMSG_RFC822_CHECK;
683                 eOkState = INETMSG_RFC822_OK;
684 
685                 switch (ascii_toLowerCase (*pData))
686                 {
687                     case 'm':
688                         check = "ailer";
689                         nIdx = INETMSG_RFC822_X_MAILER;
690                         break;
691 
692 #if 0  /* NYI */
693                     case 'p':
694                         check = "riority";
695                         eOkState = INETMSG_RFC822_X_PRIORITY;
696                         break;
697 #endif /* NYI */
698 
699                     default:
700                         eState = INETMSG_RFC822_JUNK;
701                         break;
702                 }
703                 pData++;
704                 break;
705 
706             case INETMSG_RFC822_LETTER_C:
707                 eState = INETMSG_RFC822_CHECK;
708                 eOkState = INETMSG_RFC822_OK;
709 
710                 switch (ascii_toLowerCase (*pData))
711                 {
712                     case 'c':
713                         check = "";
714                         nIdx = INETMSG_RFC822_CC;
715                         break;
716 
717                     case 'o':
718                         check = "mments";
719                         nIdx = INETMSG_RFC822_COMMENTS;
720                         break;
721 
722                     default:
723                         eState = INETMSG_RFC822_JUNK;
724                         break;
725                 }
726                 pData++;
727                 break;
728 
729             case INETMSG_RFC822_LETTER_S:
730                 eState = INETMSG_RFC822_CHECK;
731                 eOkState = INETMSG_RFC822_OK;
732 
733                 switch (ascii_toLowerCase (*pData))
734                 {
735                     case 'e':
736                         check = "nder";
737                         nIdx = INETMSG_RFC822_SENDER;
738                         break;
739 
740                     case 'u':
741                         check = "bject";
742                         nIdx = INETMSG_RFC822_SUBJECT;
743                         break;
744 
745                     default:
746                         eState = INETMSG_RFC822_JUNK;
747                         break;
748                 }
749                 pData++;
750                 break;
751 
752             case INETMSG_RFC822_CHECK:
753                 if (*check)
754                 {
755                     while (*pData && *check &&
756                            (ascii_toLowerCase (*pData) == *check))
757                     {
758                         pData++;
759                         check++;
760                     }
761                 }
762                 else
763                 {
764                     check = pData;
765                 }
766                 eState = (*check == '\0') ? eOkState : INETMSG_RFC822_JUNK;
767                 break;
768 
769             case INETMSG_RFC822_OK:
770                 pData = pStop;
771                 SetHeaderField_Impl (
772                     HEADERFIELD (HDR(nIdx), rHeader.GetValue()),
773                     m_nIndex[nIdx]);
774                 nNewIndex = m_nIndex[nIdx];
775                 break;
776 
777             default: // INETMSG_RFC822_JUNK
778                 pData = pStop;
779                 nNewIndex = INetMessage::SetHeaderField (rHeader, nNewIndex);
780                 break;
781         }
782     }
783     return nNewIndex;
784 }
785 
786 /*
787  * Specific Set-Methods.
788  */
789 void INetRFC822Message::SetBCC (const UniString& rBCC)
790 {
791     SetHeaderField_Impl (
792         INetMIME::HEADER_FIELD_ADDRESS,
793         HDR(INETMSG_RFC822_BCC), rBCC,
794         m_nIndex[INETMSG_RFC822_BCC]);
795 }
796 
797 void INetRFC822Message::SetCC (const UniString& rCC)
798 {
799     SetHeaderField_Impl (
800         INetMIME::HEADER_FIELD_ADDRESS,
801         HDR(INETMSG_RFC822_CC), rCC,
802         m_nIndex[INETMSG_RFC822_CC]);
803 }
804 
805 void INetRFC822Message::SetComments (const UniString& rComments)
806 {
807     SetHeaderField_Impl (
808         INetMIME::HEADER_FIELD_TEXT,
809         HDR(INETMSG_RFC822_COMMENTS), rComments,
810         m_nIndex[INETMSG_RFC822_COMMENTS]);
811 }
812 
813 void INetRFC822Message::SetDate (const UniString& rDate)
814 {
815     SetHeaderField_Impl (
816         INetMIME::HEADER_FIELD_STRUCTURED,
817         HDR(INETMSG_RFC822_DATE), rDate,
818         m_nIndex[INETMSG_RFC822_DATE]);
819 }
820 
821 void INetRFC822Message::SetFrom (const UniString& rFrom)
822 {
823     SetHeaderField_Impl (
824         INetMIME::HEADER_FIELD_ADDRESS,
825         HDR(INETMSG_RFC822_FROM), rFrom,
826         m_nIndex[INETMSG_RFC822_FROM]);
827 }
828 
829 void INetRFC822Message::SetInReplyTo (const UniString& rInReplyTo)
830 {
831     SetHeaderField_Impl (
832         INetMIME::HEADER_FIELD_ADDRESS, // ??? MESSAGE_ID ???
833         HDR(INETMSG_RFC822_IN_REPLY_TO), rInReplyTo,
834         m_nIndex[INETMSG_RFC822_IN_REPLY_TO]);
835 }
836 
837 void INetRFC822Message::SetKeywords (const UniString& rKeywords)
838 {
839     SetHeaderField_Impl (
840         INetMIME::HEADER_FIELD_PHRASE,
841         HDR(INETMSG_RFC822_KEYWORDS), rKeywords,
842         m_nIndex[INETMSG_RFC822_KEYWORDS]);
843 }
844 
845 void INetRFC822Message::SetMessageID (const UniString& rMessageID)
846 {
847     SetHeaderField_Impl (
848         INetMIME::HEADER_FIELD_MESSAGE_ID,
849         HDR(INETMSG_RFC822_MESSAGE_ID), rMessageID,
850         m_nIndex[INETMSG_RFC822_MESSAGE_ID]);
851 }
852 
853 void INetRFC822Message::SetReferences (const UniString& rReferences)
854 {
855     SetHeaderField_Impl (
856         INetMIME::HEADER_FIELD_MESSAGE_ID,
857         HDR(INETMSG_RFC822_REFERENCES), rReferences,
858         m_nIndex[INETMSG_RFC822_REFERENCES]);
859 }
860 
861 void INetRFC822Message::SetReplyTo (const UniString& rReplyTo)
862 {
863     SetHeaderField_Impl (
864         INetMIME::HEADER_FIELD_ADDRESS,
865         HDR(INETMSG_RFC822_REPLY_TO), rReplyTo,
866         m_nIndex[INETMSG_RFC822_REPLY_TO]);
867 }
868 
869 void INetRFC822Message::SetReturnPath (const UniString& rReturnPath)
870 {
871     SetHeaderField_Impl (
872         INetMIME::HEADER_FIELD_ADDRESS,
873         HDR(INETMSG_RFC822_RETURN_PATH), rReturnPath,
874         m_nIndex[INETMSG_RFC822_RETURN_PATH]);
875 }
876 
877 void INetRFC822Message::SetReturnReceiptTo (const UniString& rValue)
878 {
879     SetHeaderField_Impl (
880         INetMIME::HEADER_FIELD_ADDRESS,
881         HDR(INETMSG_RFC822_RETURN_RECEIPT_TO), rValue,
882         m_nIndex[INETMSG_RFC822_RETURN_RECEIPT_TO]);
883 }
884 
885 void INetRFC822Message::SetSender (const UniString& rSender)
886 {
887     SetHeaderField_Impl (
888         INetMIME::HEADER_FIELD_ADDRESS,
889         HDR(INETMSG_RFC822_SENDER), rSender,
890         m_nIndex[INETMSG_RFC822_SENDER]);
891 }
892 
893 void INetRFC822Message::SetSubject (const UniString& rSubject)
894 {
895     SetHeaderField_Impl (
896         INetMIME::HEADER_FIELD_TEXT,
897         HDR(INETMSG_RFC822_SUBJECT), rSubject,
898         m_nIndex[INETMSG_RFC822_SUBJECT]);
899 }
900 
901 void INetRFC822Message::SetTo (const UniString& rTo)
902 {
903     SetHeaderField_Impl (
904         INetMIME::HEADER_FIELD_ADDRESS,
905         HDR(INETMSG_RFC822_TO), rTo,
906         m_nIndex[INETMSG_RFC822_TO]);
907 }
908 
909 void INetRFC822Message::SetXMailer (const UniString& rXMailer)
910 {
911     SetHeaderField_Impl (
912         INetMIME::HEADER_FIELD_TEXT,
913         HDR(INETMSG_RFC822_X_MAILER), rXMailer,
914         m_nIndex[INETMSG_RFC822_X_MAILER]);
915 }
916 
917 /*
918  * operator<<
919  */
920 SvStream& INetRFC822Message::operator<< (SvStream& rStrm) const
921 {
922     INetMessage::operator<< (rStrm);
923 
924     for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
925         rStrm << static_cast<sal_uInt32>(m_nIndex[i]);
926 
927     return rStrm;
928 }
929 
930 /*
931  * operator>>
932  */
933 SvStream& INetRFC822Message::operator>> (SvStream& rStrm)
934 {
935     INetMessage::operator>> (rStrm);
936 
937     sal_uInt32 nTemp;
938     for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++)
939     {
940         rStrm >> nTemp;
941         m_nIndex[i] = nTemp;
942     }
943 
944     return rStrm;
945 }
946 
947 /*=======================================================================
948  *
949  * INetMIMEMessage Implementation.
950  *
951  *=====================================================================*/
952 /*
953  * _ImplINetMIMEMessageHeaderData.
954  */
955 namespace
956 {
957     struct ImplINetMIMEMessageHeaderDataImpl
958     {
959         const ByteString* operator()()
960         {
961             static const ByteString _ImplINetMIMEMessageHeaderData[] =
962             {
963                 ByteString ("MIME-Version"),
964                 ByteString ("Content-Description"),
965                 ByteString ("Content-Disposition"),
966                 ByteString ("Content-ID"),
967                 ByteString ("Content-Type"),
968                 ByteString ("Content-Transfer-Encoding")
969             };
970             return &_ImplINetMIMEMessageHeaderData[0];
971         }
972     };
973 
974     struct ImplINetMIMEMessageHeaderData
975         : public rtl::StaticAggregate< const ByteString, ImplINetMIMEMessageHeaderDataImpl > {};
976 }
977 
978 #define MIMEHDR(n) ImplINetMIMEMessageHeaderData::get()[(n)]
979 
980 /*
981  * _ImplINetMIMEMessageHeaderState.
982  */
983 enum _ImplINetMIMEMessageHeaderState
984 {
985     INETMSG_MIME_BEGIN,
986     INETMSG_MIME_CHECK,
987     INETMSG_MIME_OK,
988     INETMSG_MIME_JUNK,
989 
990     INETMSG_MIME_TOKEN_CONTENT,
991     INETMSG_MIME_TOKEN_CONTENT_D,
992     INETMSG_MIME_TOKEN_CONTENT_T
993 };
994 
995 /*
996  * INetMIMEMessage.
997  */
998 INetMIMEMessage::INetMIMEMessage (void)
999     : INetRFC822Message (),
1000       pParent       (NULL),
1001       nNumChildren  (0),
1002       bHeaderParsed (sal_False)
1003 {
1004     for (sal_uInt16 i = 0; i < INETMSG_MIME_NUMHDR; i++)
1005         m_nIndex[i] = LIST_ENTRY_NOTFOUND;
1006 }
1007 
1008 INetMIMEMessage::INetMIMEMessage (const INetMIMEMessage& rMsg)
1009     : INetRFC822Message (rMsg)
1010 {
1011     // Copy.
1012     CopyImp (rMsg);
1013 }
1014 
1015 /*
1016  * operator=
1017  */
1018 INetMIMEMessage& INetMIMEMessage::operator= (
1019     const INetMIMEMessage& rMsg)
1020 {
1021     if (this != &rMsg)
1022     {
1023         // Assign base.
1024         INetRFC822Message::operator= (rMsg);
1025 
1026         // Cleanup.
1027         CleanupImp();
1028 
1029         // Copy.
1030         CopyImp (rMsg);
1031     }
1032     return *this;
1033 }
1034 
1035 /*
1036  * ~INetMIMEMessage.
1037  */
1038 INetMIMEMessage::~INetMIMEMessage (void)
1039 {
1040     // Cleanup.
1041     CleanupImp();
1042 }
1043 
1044 /*
1045  * CleanupImp.
1046  */
1047 void INetMIMEMessage::CleanupImp (void)
1048 {
1049     INetMIMEMessage *pChild = NULL;
1050     while ((pChild = (INetMIMEMessage *)(aChildren.Remove())) != NULL)
1051         if (pChild->pParent == this) delete pChild;
1052 }
1053 
1054 /*
1055  * CopyImp.
1056  */
1057 void INetMIMEMessage::CopyImp (const INetMIMEMessage& rMsg)
1058 {
1059     bHeaderParsed = rMsg.bHeaderParsed;
1060 
1061     sal_uInt16 i;
1062     for (i = 0; i < INETMSG_MIME_NUMHDR; i++)
1063         m_nIndex[i] = rMsg.m_nIndex[i];
1064 
1065     m_aBoundary = rMsg.m_aBoundary;
1066     nNumChildren = rMsg.nNumChildren;
1067 
1068     for (i = 0; i < rMsg.aChildren.Count(); i++)
1069     {
1070         INetMIMEMessage *pChild =
1071             (INetMIMEMessage *)(rMsg.aChildren.GetObject (i));
1072 
1073         if (pChild->pParent == &rMsg)
1074         {
1075             pChild = pChild->CreateMessage (*pChild);
1076             pChild->pParent = this;
1077         }
1078         aChildren.Insert (pChild, LIST_APPEND);
1079     }
1080 }
1081 
1082 /*
1083  * CreateMessage.
1084  */
1085 INetMIMEMessage *INetMIMEMessage::CreateMessage (
1086     const INetMIMEMessage& rMsg) const
1087 {
1088     return (new INetMIMEMessage (rMsg));
1089 }
1090 
1091 /*
1092  * SetHeaderField.
1093  * (Header Field Parser).
1094  */
1095 sal_uIntPtr INetMIMEMessage::SetHeaderField (
1096     const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex)
1097 {
1098     ByteString aName (rHeader.GetName());
1099     const sal_Char *pData = aName.GetBuffer();
1100     const sal_Char *pStop = pData + aName.Len() + 1;
1101     const sal_Char *check = "";
1102 
1103     sal_uIntPtr      nIdx     = LIST_APPEND;
1104     int        eState   = INETMSG_MIME_BEGIN;
1105     int        eOkState = INETMSG_MIME_OK;
1106 
1107     while (pData < pStop)
1108     {
1109         switch (eState)
1110         {
1111             case INETMSG_MIME_BEGIN:
1112                 eState = INETMSG_MIME_CHECK;
1113                 eOkState = INETMSG_MIME_OK;
1114 
1115                 switch (ascii_toLowerCase (*pData))
1116                 {
1117                     case 'c':
1118                         check = "ontent-";
1119                         eOkState = INETMSG_MIME_TOKEN_CONTENT;
1120                         break;
1121 
1122                     case 'm':
1123                         check = "ime-version";
1124                         nIdx = INETMSG_MIME_VERSION;
1125                         break;
1126 
1127                     default:
1128                         eState = INETMSG_MIME_JUNK;
1129                         break;
1130                 }
1131                 pData++;
1132                 break;
1133 
1134             case INETMSG_MIME_TOKEN_CONTENT:
1135                 eState = INETMSG_MIME_CHECK;
1136                 eOkState = INETMSG_MIME_OK;
1137 
1138                 switch (ascii_toLowerCase (*pData))
1139                 {
1140                     case 'd':
1141                         eState = INETMSG_MIME_TOKEN_CONTENT_D;
1142                         break;
1143 
1144                     case 'i':
1145                         check = "d";
1146                         nIdx = INETMSG_MIME_CONTENT_ID;
1147                         break;
1148 
1149                     case 't':
1150                         eState = INETMSG_MIME_TOKEN_CONTENT_T;
1151                         break;
1152 
1153                     default:
1154                         eState = INETMSG_MIME_JUNK;
1155                         break;
1156                 }
1157                 pData++;
1158                 break;
1159 
1160             case INETMSG_MIME_TOKEN_CONTENT_D:
1161                 eState = INETMSG_MIME_CHECK;
1162                 eOkState = INETMSG_MIME_OK;
1163 
1164                 switch (ascii_toLowerCase (*pData))
1165                 {
1166                     case 'e':
1167                         check = "scription";
1168                         nIdx = INETMSG_MIME_CONTENT_DESCRIPTION;
1169                         break;
1170 
1171                     case 'i':
1172                         check = "sposition";
1173                         nIdx = INETMSG_MIME_CONTENT_DISPOSITION;
1174                         break;
1175 
1176                     default:
1177                         eState = INETMSG_MIME_JUNK;
1178                         break;
1179                 }
1180                 pData++;
1181                 break;
1182 
1183             case INETMSG_MIME_TOKEN_CONTENT_T:
1184                 eState = INETMSG_MIME_CHECK;
1185                 eOkState = INETMSG_MIME_OK;
1186 
1187                 switch (ascii_toLowerCase (*pData))
1188                 {
1189                     case 'r':
1190                         check = "ansfer-encoding";
1191                         nIdx = INETMSG_MIME_CONTENT_TRANSFER_ENCODING;
1192                         break;
1193 
1194                     case 'y':
1195                         check = "pe";
1196                         nIdx = INETMSG_MIME_CONTENT_TYPE;
1197                         break;
1198 
1199                     default:
1200                         eState = INETMSG_MIME_JUNK;
1201                         break;
1202                 }
1203                 pData++;
1204                 break;
1205 
1206             case INETMSG_MIME_CHECK:
1207                 if (*check)
1208                 {
1209                     while (*pData && *check &&
1210                            (ascii_toLowerCase (*pData) == *check))
1211                     {
1212                         pData++;
1213                         check++;
1214                     }
1215                 }
1216                 else
1217                 {
1218                     check = pData;
1219                 }
1220                 eState = (*check == '\0') ? eOkState : INETMSG_MIME_JUNK;
1221                 break;
1222 
1223             case INETMSG_MIME_OK:
1224                 pData = pStop;
1225                 SetHeaderField_Impl (
1226                     HEADERFIELD (MIMEHDR(nIdx), rHeader.GetValue()),
1227                     m_nIndex[nIdx]);
1228                 nNewIndex = m_nIndex[nIdx];
1229                 break;
1230 
1231             default: // INETMSG_MIME_JUNK
1232                 pData = pStop;
1233                 nNewIndex = INetRFC822Message::SetHeaderField (
1234                     rHeader, nNewIndex);
1235                 break;
1236         }
1237     }
1238     return nNewIndex;
1239 }
1240 
1241 /*
1242  * Specific Set-Methods.
1243  */
1244 void INetMIMEMessage::SetMIMEVersion (const UniString& rVersion)
1245 {
1246     SetHeaderField_Impl (
1247         INetMIME::HEADER_FIELD_TEXT,
1248         MIMEHDR(INETMSG_MIME_VERSION), rVersion,
1249         m_nIndex[INETMSG_MIME_VERSION]);
1250 }
1251 
1252 void INetMIMEMessage::SetContentDescription (const String& rDescription)
1253 {
1254     SetHeaderField_Impl (
1255         INetMIME::HEADER_FIELD_TEXT,
1256         MIMEHDR(INETMSG_MIME_CONTENT_DESCRIPTION), rDescription,
1257         m_nIndex[INETMSG_MIME_CONTENT_DESCRIPTION]);
1258 }
1259 
1260 void INetMIMEMessage::SetContentDisposition (const String& rDisposition)
1261 {
1262     SetHeaderField_Impl (
1263         INetMIME::HEADER_FIELD_TEXT,
1264         MIMEHDR(INETMSG_MIME_CONTENT_DISPOSITION), rDisposition,
1265         m_nIndex[INETMSG_MIME_CONTENT_DISPOSITION]);
1266 }
1267 
1268 void INetMIMEMessage::SetContentID (const String& rID)
1269 {
1270     SetHeaderField_Impl (
1271         INetMIME::HEADER_FIELD_TEXT,
1272         MIMEHDR(INETMSG_MIME_CONTENT_ID), rID,
1273         m_nIndex[INETMSG_MIME_CONTENT_ID]);
1274 }
1275 
1276 void INetMIMEMessage::SetContentType (const String& rType)
1277 {
1278     SetHeaderField_Impl (
1279         INetMIME::HEADER_FIELD_TEXT,
1280         MIMEHDR(INETMSG_MIME_CONTENT_TYPE), rType,
1281         m_nIndex[INETMSG_MIME_CONTENT_TYPE]);
1282 }
1283 
1284 void INetMIMEMessage::SetContentTransferEncoding (
1285     const String& rEncoding)
1286 {
1287     SetHeaderField_Impl (
1288         INetMIME::HEADER_FIELD_TEXT,
1289         MIMEHDR(INETMSG_MIME_CONTENT_TRANSFER_ENCODING), rEncoding,
1290         m_nIndex[INETMSG_MIME_CONTENT_TRANSFER_ENCODING]);
1291 }
1292 
1293 /*
1294  * GetDefaultContentType.
1295  */
1296 void INetMIMEMessage::GetDefaultContentType (String& rContentType)
1297 {
1298     String aDefaultCT (
1299         "text/plain; charset=us-ascii", RTL_TEXTENCODING_ASCII_US);
1300     if (pParent == NULL)
1301     {
1302         rContentType = aDefaultCT;
1303     }
1304     else
1305     {
1306         String aParentCT (pParent->GetContentType());
1307         if (aParentCT.Len() == 0)
1308             pParent->GetDefaultContentType (aParentCT);
1309 
1310         if (aParentCT.CompareIgnoreCaseToAscii ("message/", 8) == 0)
1311         {
1312             rContentType = aDefaultCT;
1313         }
1314         else if (aParentCT.CompareIgnoreCaseToAscii ("multipart/", 10) == 0)
1315         {
1316             if (aParentCT.CompareIgnoreCaseToAscii ("multipart/digest") == 0)
1317                 rContentType.AssignAscii ("message/rfc822");
1318             else
1319                 rContentType = aDefaultCT;
1320         }
1321         else
1322         {
1323             rContentType = aDefaultCT;
1324         }
1325     }
1326 }
1327 
1328 /*
1329  * EnableAttachChild.
1330  */
1331 sal_Bool INetMIMEMessage::EnableAttachChild (INetMessageContainerType eType)
1332 {
1333     // Check context.
1334     if (IsContainer())
1335         return sal_False;
1336 
1337     // Setup Content-Type header field.
1338     ByteString aContentType;
1339     switch (eType)
1340     {
1341         case INETMSG_MESSAGE_RFC822:
1342             aContentType = "message/rfc822";
1343             break;
1344 
1345         case INETMSG_MULTIPART_ALTERNATIVE:
1346             aContentType = "multipart/alternative";
1347             break;
1348 
1349         case INETMSG_MULTIPART_DIGEST:
1350             aContentType = "multipart/digest";
1351             break;
1352 
1353         case INETMSG_MULTIPART_PARALLEL:
1354             aContentType = "multipart/parallel";
1355             break;
1356 
1357         case INETMSG_MULTIPART_RELATED:
1358             aContentType = "multipart/related";
1359             break;
1360 
1361         case INETMSG_MULTIPART_FORM_DATA:
1362             aContentType = "multipart/form-data";
1363             break;
1364 
1365         default:
1366             aContentType = "multipart/mixed";
1367             break;
1368     }
1369 
1370     // Setup boundary for multipart types.
1371     if (aContentType.CompareIgnoreCaseToAscii ("multipart/", 10) == 0)
1372     {
1373         // Generate a unique boundary from current time.
1374         sal_Char sTail[16 + 1];
1375         Time aCurTime;
1376         sal_uInt64 nThis = reinterpret_cast< sal_uIntPtr >( this ); // we can be on a 64bit architecture
1377         nThis = ( ( nThis >> 32 ) ^ nThis ) & SAL_MAX_UINT32;
1378         sprintf (sTail, "%08X%08X",
1379                  static_cast< unsigned int >(aCurTime.GetTime()),
1380                  static_cast< unsigned int >(nThis));
1381         m_aBoundary = "------------_4D48";
1382         m_aBoundary += sTail;
1383 
1384         // Append boundary as ContentType parameter.
1385         aContentType += "; boundary=";
1386         aContentType += m_aBoundary;
1387     }
1388 
1389     // Set header fields.
1390     SetMIMEVersion (String (CONSTASCII_STRINGPARAM("1.0")));
1391     SetContentType (String (aContentType, RTL_TEXTENCODING_ASCII_US));
1392     SetContentTransferEncoding (String (CONSTASCII_STRINGPARAM("7bit")));
1393 
1394     // Done.
1395     return sal_True;
1396 }
1397 
1398 /*
1399  * AttachChild.
1400  */
1401 sal_Bool INetMIMEMessage::AttachChild (
1402     INetMIMEMessage& rChildMsg, sal_Bool bOwner)
1403 {
1404     if (IsContainer() /*&& rChildMsg.GetContentType().Len() */)
1405     {
1406         if (bOwner) rChildMsg.pParent = this;
1407         aChildren.Insert (&rChildMsg, LIST_APPEND);
1408         nNumChildren = aChildren.Count();
1409 
1410         return sal_True;
1411     }
1412     return sal_False;
1413 }
1414 
1415 /*
1416  * DetachChild.
1417  */
1418 sal_Bool INetMIMEMessage::DetachChild (
1419     sal_uIntPtr nIndex, INetMIMEMessage& rChildMsg) const
1420 {
1421     if (IsContainer())
1422     {
1423         // Check document stream.
1424         if (GetDocumentLB() == NULL) return sal_False;
1425         SvStream *pDocStrm = new SvStream (GetDocumentLB());
1426 
1427         // Initialize message buffer.
1428         char pMsgBuffer[1024];
1429         char *pMsgRead, *pMsgWrite;
1430         pMsgRead = pMsgWrite = pMsgBuffer;
1431 
1432         // Initialize message parser stream.
1433         INetMIMEMessageStream *pMsgStrm = NULL;
1434 
1435         // Check for "multipart/uvw" or "message/xyz".
1436         if (IsMultipart())
1437         {
1438             // Multipart message body. Initialize multipart delimiters.
1439             ByteString aDelim ("--");
1440             aDelim += GetMultipartBoundary();
1441             ByteString aClose = aDelim;
1442             aClose += "--";
1443 
1444             // Initialize line buffer.
1445             SvMemoryStream aLineBuf;
1446 
1447             // Initialize control variables.
1448             INetMessageStreamState eState = INETMSG_EOL_SCR;
1449             int nCurIndex = -1;
1450 
1451             // Go!
1452             while (nCurIndex < (int)(nIndex + 1))
1453             {
1454                 if ((pMsgRead - pMsgWrite) > 0)
1455                 {
1456                     // Bytes still in buffer.
1457                     if (eState == INETMSG_EOL_FCR)
1458                     {
1459                         // Check for 2nd line break character.
1460                         if ((*pMsgWrite == '\r') || (*pMsgWrite == '\n'))
1461                             aLineBuf << *pMsgWrite++;
1462 
1463                         // Check current index.
1464                         if (nCurIndex == (int)nIndex)
1465                         {
1466                             // Found requested part.
1467                             if (pMsgStrm == NULL)
1468                             {
1469                                 // Create message parser stream.
1470                                 pMsgStrm = new INetMIMEMessageStream;
1471                                 pMsgStrm->SetTargetMessage (&rChildMsg);
1472                             }
1473 
1474                             // Put message down-stream.
1475                             int status = pMsgStrm->Write (
1476                                 (const sal_Char *) aLineBuf.GetData(), aLineBuf.Tell());
1477                             if (status != INETSTREAM_STATUS_OK)
1478                             {
1479                                 // Cleanup.
1480                                 delete pDocStrm;
1481                                 delete pMsgStrm;
1482 
1483                                 // Finish.
1484                                 return (!(status == INETSTREAM_STATUS_OK));
1485                             }
1486                         }
1487 
1488                         // Reset to <Begin-of-Line>.
1489                         aLineBuf.Seek (STREAM_SEEK_TO_BEGIN);
1490                         eState = INETMSG_EOL_SCR;
1491                     }
1492                     else if ((*pMsgWrite == '\r') || (*pMsgWrite == '\n'))
1493                     {
1494                         /*
1495                          * Found any line break character.
1496                          * Compare buffered line with part/close delimiter.
1497                          * Increment current part index upon match.
1498                          */
1499                         sal_uInt16 nLen = (sal_uInt16)(aLineBuf.Tell() & 0xffff);
1500                         if (nLen == aDelim.Len())
1501                         {
1502                             if (aDelim.CompareTo ((const sal_Char *) aLineBuf.GetData(), nLen)
1503                                 == COMPARE_EQUAL) nCurIndex++;
1504                         }
1505                         else if (nLen == aClose.Len())
1506                         {
1507                             if (aClose.CompareTo ((const sal_Char *) aLineBuf.GetData(), nLen)
1508                                 == COMPARE_EQUAL) nCurIndex++;
1509                         }
1510                         aLineBuf << *pMsgWrite++;
1511                         eState = INETMSG_EOL_FCR;
1512                     }
1513                     else
1514                     {
1515                         // Insert into line buffer.
1516                         aLineBuf << *pMsgWrite;
1517                     }
1518                 }
1519                 else
1520                 {
1521                     // Buffer empty. Reset to <Begin-of-Buffer>.
1522                     pMsgRead = pMsgWrite = pMsgBuffer;
1523 
1524                     // Read document stream.
1525                     sal_uIntPtr nRead = pDocStrm->Read (
1526                         pMsgBuffer, sizeof (pMsgBuffer));
1527                     if (nRead > 0)
1528                     {
1529                         // Set read pointer.
1530                         pMsgRead += nRead;
1531                     }
1532                     else
1533                     {
1534                         // Premature end.
1535                         if (pMsgStrm)
1536                         {
1537                             // Assume end of requested part.
1538                             nCurIndex++;
1539                         }
1540                         else
1541                         {
1542                             // Requested part not found.
1543                             delete pDocStrm;
1544                             return sal_False;
1545                         }
1546                     }
1547                 }
1548             } // while (nCurIndex < (nIndex + 1))
1549         }
1550         else
1551         {
1552             // Encapsulated message body. Create message parser stream.
1553             pMsgStrm = new INetMIMEMessageStream;
1554             pMsgStrm->SetTargetMessage (&rChildMsg);
1555 
1556             // Initialize control variables.
1557             INetMessageStreamState eState = INETMSG_EOL_BEGIN;
1558 
1559             // Go.
1560             while (eState == INETMSG_EOL_BEGIN)
1561             {
1562                 if ((pMsgRead - pMsgWrite) > 0)
1563                 {
1564                     // Bytes still in buffer. Put message down-stream.
1565                     int status = pMsgStrm->Write (
1566                         pMsgBuffer, (pMsgRead - pMsgWrite));
1567                     if (status != INETSTREAM_STATUS_OK)
1568                     {
1569                         // Cleanup.
1570                         delete pDocStrm;
1571                         delete pMsgStrm;
1572 
1573                         // Finish.
1574                         return (!(status == INETSTREAM_STATUS_ERROR));
1575                     }
1576                     pMsgWrite = pMsgBuffer + (pMsgRead - pMsgWrite);
1577                 }
1578                 else
1579                 {
1580                     // Buffer empty. Reset to <Begin-of-Buffer>.
1581                     pMsgRead = pMsgWrite = pMsgBuffer;
1582 
1583                     // Read document stream.
1584                     sal_uIntPtr nRead = pDocStrm->Read (
1585                         pMsgBuffer, sizeof (pMsgBuffer));
1586                     if (nRead > 0)
1587                     {
1588                         // Set read pointer.
1589                         pMsgRead += nRead;
1590                     }
1591                     else
1592                     {
1593                         // Mark we're done.
1594                         eState = INETMSG_EOL_DONE;
1595                     }
1596                 }
1597             } // while (eState == INETMSG_EOL_BEGIN)
1598         }
1599 
1600         // Done.
1601         if (pDocStrm) delete pDocStrm;
1602         if (pMsgStrm) delete pMsgStrm;
1603         return sal_True;
1604     }
1605     return sal_False;
1606 }
1607 
1608 /*
1609  * operator<<
1610  */
1611 SvStream& INetMIMEMessage::operator<< (SvStream& rStrm) const
1612 {
1613     INetRFC822Message::operator<< (rStrm);
1614 
1615     for (sal_uInt16 i = 0; i < INETMSG_MIME_NUMHDR; i++)
1616         rStrm << static_cast<sal_uInt32>(m_nIndex[i]);
1617 
1618 #ifdef ENABLE_BYTESTRING_STREAM_OPERATORS
1619     rStrm << m_aBoundary;
1620 #else
1621     rStrm.WriteByteString (m_aBoundary);
1622 #endif
1623     rStrm << static_cast<sal_uInt32>(nNumChildren);
1624 
1625     return rStrm;
1626 }
1627 
1628 /*
1629  * operator>>
1630  */
1631 SvStream& INetMIMEMessage::operator>> (SvStream& rStrm)
1632 {
1633     INetRFC822Message::operator>> (rStrm);
1634 
1635     sal_uInt32 nTemp;
1636     for (sal_uInt16 i = 0; i < INETMSG_MIME_NUMHDR; i++)
1637     {
1638         rStrm >> nTemp;
1639         m_nIndex[i] = nTemp;
1640     }
1641 
1642 #ifdef ENABLE_BYTESTRING_STREAM_OPERATORS
1643     rStrm >> m_aBoundary;
1644 #else
1645     rStrm.ReadByteString (m_aBoundary);
1646 #endif
1647     rStrm >> nTemp;
1648     nNumChildren = nTemp;
1649 
1650     return rStrm;
1651 }
1652 
1653 
1654