Branch libreoffice-5-0-4
[LibreOffice.git] / tools / source / inet / inetmsg.cxx
blobec57d494a0498e2117ca67dfbf5d9658251b72d7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
21 #include <osl/thread.h>
22 #include <tools/datetime.hxx>
23 #include <tools/inetmime.hxx>
24 #include <tools/inetmsg.hxx>
25 #include <tools/inetstrm.hxx>
26 #include <tools/contnr.hxx>
27 #include <rtl/instance.hxx>
28 #include <rtl/strbuf.hxx>
29 #include <comphelper/string.hxx>
31 #include <stdio.h>
32 #include <map>
34 inline bool ascii_isDigit( sal_Unicode ch )
36 return ((ch >= 0x0030) && (ch <= 0x0039));
39 inline bool ascii_isLetter( sal_Unicode ch )
41 return (( (ch >= 0x0041) && (ch <= 0x005A)) || ((ch >= 0x0061) && (ch <= 0x007A)));
44 inline sal_Unicode ascii_toLowerCase( sal_Unicode ch )
46 if ( (ch >= 0x0041) && (ch <= 0x005A) )
47 return ch + 0x20;
48 else
49 return ch;
52 void INetMIMEMessage::ListCleanup_Impl()
54 // Cleanup.
55 sal_uIntPtr i, n = m_aHeaderList.size();
56 for (i = 0; i < n; i++)
57 delete m_aHeaderList[ i ];
58 m_aHeaderList.clear();
61 void INetMIMEMessage::ListCopy (const INetMIMEMessage &rMsg)
63 if (!(this == &rMsg))
65 // Cleanup.
66 ListCleanup_Impl();
68 // Copy.
69 sal_uIntPtr i, n = rMsg.GetHeaderCount();
70 for (i = 0; i < n; i++)
72 INetMessageHeader *p = rMsg.m_aHeaderList[ i ];
73 m_aHeaderList.push_back( new INetMessageHeader(*p) );
78 void INetMIMEMessage::SetHeaderField_Impl (
79 INetMIME::HeaderFieldType eType,
80 const OString &rName,
81 const OUString &rValue,
82 sal_uIntPtr &rnIndex)
84 INetMIMEStringOutputSink aSink (0, 32767); /* weird the mime standard says that aline MUST not be longeur that 998 */
85 INetMIME::writeHeaderFieldBody (
86 aSink, eType, rValue, osl_getThreadTextEncoding(), false);
87 SetHeaderField_Impl (
88 INetMessageHeader (rName, aSink.takeBuffer()), rnIndex);
91 static const std::map<InetMessageField, const char *> ImplINetRFC822MessageHeaderData =
93 { InetMessageField::BCC, "BCC" } ,
94 { InetMessageField::CC, "CC" } ,
95 { InetMessageField::COMMENTS, "Comments" } ,
96 { InetMessageField::DATE, "Date" } ,
97 { InetMessageField::FROM, "From" } ,
98 { InetMessageField::IN_REPLY_TO, "In-Reply-To" } ,
99 { InetMessageField::KEYWORDS, "Keywords" } ,
100 { InetMessageField::MESSAGE_ID, "Message-ID" } ,
101 { InetMessageField::REFERENCES, "References" } ,
102 { InetMessageField::REPLY_TO, "Reply-To" } ,
103 { InetMessageField::RETURN_PATH, "Return-Path" } ,
104 { InetMessageField::SUBJECT, "Subject" } ,
105 { InetMessageField::SENDER, "Sender" } ,
106 { InetMessageField::TO, "To" } ,
107 { InetMessageField::X_MAILER, "X-Mailer" } ,
108 { InetMessageField::RETURN_RECEIPT_TO, "Return-Receipt-To" } ,
112 State of RFC822 header parsing
114 enum class HeaderState
116 BEGIN,
117 CHECK,
119 JUNK,
121 TOKEN_RE,
122 TOKEN_RETURNMINUS,
123 TOKEN_XMINUS,
124 LETTER_C,
125 LETTER_S
128 /* ParseDateField and local helper functions.
130 * Parses a String in (implied) GMT format into class Date and tools::Time objects.
131 * Four formats are accepted:
133 * [Wkd,] 1*2DIGIT Mon 2*4DIGIT 00:00:00 [GMT] (rfc1123)
134 * [Wkd,] 00 Mon 0000 00:00:00 [GMT]) (rfc822, rfc1123)
135 * Weekday, 00-Mon-00 00:00:00 [GMT] (rfc850, rfc1036)
136 * Wkd Mon 00 00:00:00 0000 [GMT] (ctime)
137 * 1*DIGIT (delta seconds)
140 static const sal_Char *months[12] =
142 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
143 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
146 static sal_uInt16 ParseNumber(const OString& rStr, sal_uInt16& nIndex)
148 sal_uInt16 n = nIndex;
149 while ((n < rStr.getLength()) && ascii_isDigit(rStr[n])) n++;
151 OString aNum(rStr.copy(nIndex, (n - nIndex)));
152 nIndex = n;
154 return (sal_uInt16)(aNum.toInt32());
157 static sal_uInt16 ParseMonth(const OString& rStr, sal_uInt16& nIndex)
159 sal_uInt16 n = nIndex;
160 while ((n < rStr.getLength()) && ascii_isLetter(rStr[n])) n++;
162 OString aMonth(rStr.copy(nIndex, 3));
163 nIndex = n;
165 sal_uInt16 i;
166 for (i = 0; i < 12; i++)
167 if (aMonth.equalsIgnoreAsciiCase(months[i])) break;
168 return (i + 1);
171 bool INetMIMEMessage::ParseDateField (
172 const OUString& rDateFieldW, DateTime& rDateTime)
174 OString aDateField(OUStringToOString(rDateFieldW,
175 RTL_TEXTENCODING_ASCII_US));
177 if (aDateField.isEmpty()) return false;
179 if (aDateField.indexOf(':') != -1)
181 // Some DateTime format.
182 sal_uInt16 nIndex = 0;
184 // Skip over <Wkd> or <Weekday>, leading and trailing space.
185 while ((nIndex < aDateField.getLength()) &&
186 (aDateField[nIndex] == ' '))
187 nIndex++;
189 while (
190 (nIndex < aDateField.getLength()) &&
191 (ascii_isLetter (aDateField[nIndex]) ||
192 (aDateField[nIndex] == ',') ))
193 nIndex++;
195 while ((nIndex < aDateField.getLength()) &&
196 (aDateField[nIndex] == ' '))
197 nIndex++;
199 if (ascii_isLetter (aDateField[nIndex]))
201 // Format: ctime().
202 if ((aDateField.getLength() - nIndex) < 20) return false;
204 rDateTime.SetMonth (ParseMonth (aDateField, nIndex)); nIndex++;
205 rDateTime.SetDay (ParseNumber (aDateField, nIndex)); nIndex++;
207 rDateTime.SetHour (ParseNumber (aDateField, nIndex)); nIndex++;
208 rDateTime.SetMin (ParseNumber (aDateField, nIndex)); nIndex++;
209 rDateTime.SetSec (ParseNumber (aDateField, nIndex)); nIndex++;
210 rDateTime.SetNanoSec (0);
212 sal_uInt16 nYear = ParseNumber (aDateField, nIndex);
213 if (nYear < 100) nYear += 1900;
214 rDateTime.SetYear (nYear);
216 else
218 // Format: RFC1036 or RFC1123.
219 if ((aDateField.getLength() - nIndex) < 17) return false;
221 rDateTime.SetDay (ParseNumber (aDateField, nIndex)); nIndex++;
222 rDateTime.SetMonth (ParseMonth (aDateField, nIndex)); nIndex++;
224 sal_uInt16 nYear = ParseNumber (aDateField, nIndex); nIndex++;
225 if (nYear < 100) nYear += 1900;
226 rDateTime.SetYear (nYear);
228 rDateTime.SetHour (ParseNumber (aDateField, nIndex)); nIndex++;
229 rDateTime.SetMin (ParseNumber (aDateField, nIndex)); nIndex++;
230 rDateTime.SetSec (ParseNumber (aDateField, nIndex)); nIndex++;
231 rDateTime.SetNanoSec (0);
233 const char cPossiblePlusMinus = nIndex < aDateField.getLength() ? aDateField[nIndex] : 0;
234 if (cPossiblePlusMinus == '+' || cPossiblePlusMinus == '-')
236 // Offset from GMT: "(+|-)HHMM".
237 bool bEast = (aDateField[nIndex++] == '+');
238 sal_uInt16 nOffset = ParseNumber (aDateField, nIndex);
239 if (nOffset > 0)
241 tools::Time aDiff( tools::Time::EMPTY );
242 aDiff.SetHour (nOffset / 100);
243 aDiff.SetMin (nOffset % 100);
244 aDiff.SetSec (0);
245 aDiff.SetNanoSec (0);
247 if (bEast)
248 rDateTime -= aDiff;
249 else
250 rDateTime += aDiff;
255 else if (comphelper::string::isdigitAsciiString(aDateField))
257 // Format: delta seconds.
258 tools::Time aDelta (0);
259 aDelta.SetTime (aDateField.toInt32() * 100);
261 DateTime aNow( DateTime::SYSTEM );
262 aNow += aDelta;
263 aNow.ConvertToUTC();
265 rDateTime.SetDate (aNow.GetDate());
266 rDateTime.SetTime (aNow.GetTime());
268 else
270 // Junk.
271 return false;
274 return (rDateTime.IsValidAndGregorian() &&
275 !((rDateTime.GetSec() > 59) ||
276 (rDateTime.GetMin() > 59) ||
277 (rDateTime.GetHour() > 23) ));
280 // Header Field Parser
281 sal_uIntPtr INetMIMEMessage::SetRFC822HeaderField (
282 const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex)
284 OString aName (rHeader.GetName());
285 const sal_Char *pData = aName.getStr();
286 const sal_Char *pStop = pData + aName.getLength() + 1;
287 const sal_Char *check = "";
289 InetMessageField nIdx = static_cast<InetMessageField>(CONTAINER_APPEND);
290 HeaderState eState = HeaderState::BEGIN;
291 HeaderState eOkState = HeaderState::OK;
293 while (pData < pStop)
295 switch (eState)
297 case HeaderState::BEGIN:
298 eState = HeaderState::CHECK;
299 eOkState = HeaderState::OK;
301 switch (ascii_toLowerCase (*pData))
303 case 'b':
304 check = "cc";
305 nIdx = InetMessageField::BCC;
306 break;
308 case 'c':
309 eState = HeaderState::LETTER_C;
310 break;
312 case 'd':
313 check = "ate";
314 nIdx = InetMessageField::DATE;
315 break;
317 case 'f':
318 check = "rom";
319 nIdx = InetMessageField::FROM;
320 break;
322 case 'i':
323 check = "n-reply-to";
324 nIdx = InetMessageField::IN_REPLY_TO;
325 break;
327 case 'k':
328 check = "eywords";
329 nIdx = InetMessageField::KEYWORDS;
330 break;
332 case 'm':
333 check = "essage-id";
334 nIdx = InetMessageField::MESSAGE_ID;
335 break;
337 case 'r':
338 check = "e";
339 eOkState = HeaderState::TOKEN_RE;
340 break;
342 case 's':
343 eState = HeaderState::LETTER_S;
344 break;
346 case 't':
347 check = "o";
348 nIdx = InetMessageField::TO;
349 break;
351 case 'x':
352 check = "-";
353 eOkState = HeaderState::TOKEN_XMINUS;
354 break;
356 default:
357 eState = HeaderState::JUNK;
358 break;
360 pData++;
361 break;
363 case HeaderState::TOKEN_RE:
364 eState = HeaderState::CHECK;
365 eOkState = HeaderState::OK;
367 switch (ascii_toLowerCase (*pData))
369 case 'f':
370 check = "erences";
371 nIdx = InetMessageField::REFERENCES;
372 break;
374 case 'p':
375 check = "ly-to";
376 nIdx = InetMessageField::REPLY_TO;
377 break;
379 case 't':
380 check = "urn-";
381 eOkState = HeaderState::TOKEN_RETURNMINUS;
382 break;
384 default:
385 eState = HeaderState::JUNK;
386 break;
388 pData++;
389 break;
391 case HeaderState::TOKEN_RETURNMINUS:
392 eState = HeaderState::CHECK;
393 eOkState = HeaderState::OK;
395 switch (ascii_toLowerCase (*pData))
397 case 'p':
398 check = "ath";
399 nIdx = InetMessageField::RETURN_PATH;
400 break;
402 case 'r':
403 check = "eceipt-to";
404 nIdx = InetMessageField::RETURN_RECEIPT_TO;
405 break;
407 default:
408 eState = HeaderState::JUNK;
409 break;
411 pData++;
412 break;
414 case HeaderState::TOKEN_XMINUS:
415 eState = HeaderState::CHECK;
416 eOkState = HeaderState::OK;
418 switch (ascii_toLowerCase (*pData))
420 case 'm':
421 check = "ailer";
422 nIdx = InetMessageField::X_MAILER;
423 break;
425 default:
426 eState = HeaderState::JUNK;
427 break;
429 pData++;
430 break;
432 case HeaderState::LETTER_C:
433 eState = HeaderState::CHECK;
434 eOkState = HeaderState::OK;
436 switch (ascii_toLowerCase (*pData))
438 case 'c':
439 check = "";
440 nIdx = InetMessageField::CC;
441 break;
443 case 'o':
444 check = "mments";
445 nIdx = InetMessageField::COMMENTS;
446 break;
448 default:
449 eState = HeaderState::JUNK;
450 break;
452 pData++;
453 break;
455 case HeaderState::LETTER_S:
456 eState = HeaderState::CHECK;
457 eOkState = HeaderState::OK;
459 switch (ascii_toLowerCase (*pData))
461 case 'e':
462 check = "nder";
463 nIdx = InetMessageField::SENDER;
464 break;
466 case 'u':
467 check = "bject";
468 nIdx = InetMessageField::SUBJECT;
469 break;
471 default:
472 eState = HeaderState::JUNK;
473 break;
475 pData++;
476 break;
478 case HeaderState::CHECK:
479 if (*check)
481 while (*pData && *check &&
482 (ascii_toLowerCase (*pData) == *check))
484 pData++;
485 check++;
488 else
490 check = pData;
492 eState = (*check == '\0') ? eOkState : HeaderState::JUNK;
493 break;
495 case HeaderState::OK:
496 pData = pStop;
497 SetHeaderField_Impl (
498 INetMessageHeader( ImplINetRFC822MessageHeaderData.at(nIdx), rHeader.GetValue() ),
499 m_nRFC822Index[nIdx]);
500 nNewIndex = m_nRFC822Index[nIdx];
501 break;
503 default: // INETMSG_RFC822_JUNK
504 pData = pStop;
505 SetHeaderField_Impl(rHeader, nNewIndex);
506 break;
509 return nNewIndex;
512 static const std::map<InetMessageMime, const char*> ImplINetMIMEMessageHeaderData =
514 { InetMessageMime::VERSION, "MIME-Version"},
515 { InetMessageMime::CONTENT_DESCRIPTION, "Content-Description"},
516 { InetMessageMime::CONTENT_DISPOSITION, "Content-Disposition"},
517 { InetMessageMime::CONTENT_ID, "Content-ID"},
518 { InetMessageMime::CONTENT_TYPE, "Content-Type"},
519 { InetMessageMime::CONTENT_TRANSFER_ENCODING, "Content-Transfer-Encoding"}
522 enum _ImplINetMIMEMessageHeaderState
524 INETMSG_MIME_BEGIN,
525 INETMSG_MIME_CHECK,
526 INETMSG_MIME_OK,
527 INETMSG_MIME_JUNK,
529 INETMSG_MIME_TOKEN_CONTENT,
530 INETMSG_MIME_TOKEN_CONTENT_D,
531 INETMSG_MIME_TOKEN_CONTENT_T
534 INetMIMEMessage::INetMIMEMessage()
535 : m_nDocSize(0),
536 pParent(NULL),
537 bHeaderParsed(false)
539 for (sal_uInt16 i = 0; i < static_cast<int>(InetMessageField::NUMHDR); i++)
540 m_nRFC822Index[static_cast<InetMessageField>(i)] = CONTAINER_ENTRY_NOTFOUND;
541 for (sal_uInt16 i = 0; i < static_cast<int>(InetMessageMime::NUMHDR); i++)
542 m_nMIMEIndex[static_cast<InetMessageMime>(i)] = CONTAINER_ENTRY_NOTFOUND;
545 INetMIMEMessage::INetMIMEMessage (const INetMIMEMessage& rMsg)
546 : m_nDocSize(rMsg.m_nDocSize),
547 m_aDocName(rMsg.m_aDocName),
548 m_xDocLB(rMsg.m_xDocLB),
549 pParent(NULL)
551 ListCopy (rMsg);
552 m_nRFC822Index = rMsg.m_nRFC822Index;
553 CopyImp (rMsg);
556 INetMIMEMessage& INetMIMEMessage::operator= (
557 const INetMIMEMessage& rMsg)
559 if (this != &rMsg)
561 m_nDocSize = rMsg.m_nDocSize;
562 m_aDocName = rMsg.m_aDocName;
563 m_xDocLB = rMsg.m_xDocLB;
564 ListCopy (rMsg);
565 m_nRFC822Index = rMsg.m_nRFC822Index;
566 CleanupImp();
567 CopyImp (rMsg);
569 return *this;
572 INetMIMEMessage::~INetMIMEMessage()
574 ListCleanup_Impl();
575 CleanupImp();
578 void INetMIMEMessage::CleanupImp()
580 for( size_t i = 0, n = aChildren.size(); i < n; ++i ) {
581 delete aChildren[ i ];
583 aChildren.clear();
586 void INetMIMEMessage::CopyImp (const INetMIMEMessage& rMsg)
588 bHeaderParsed = rMsg.bHeaderParsed;
590 size_t i;
591 m_nMIMEIndex = rMsg.m_nMIMEIndex;
592 m_aBoundary = rMsg.m_aBoundary;
594 for (i = 0; i < rMsg.aChildren.size(); i++)
596 INetMIMEMessage *pChild = rMsg.aChildren[ i ];
598 if (pChild->pParent == &rMsg)
600 pChild = INetMIMEMessage::CreateMessage (*pChild);
601 pChild->pParent = this;
603 aChildren.push_back( pChild );
607 INetMIMEMessage *INetMIMEMessage::CreateMessage (
608 const INetMIMEMessage& rMsg)
610 return new INetMIMEMessage (rMsg);
613 // Header Field Parser
614 sal_uIntPtr INetMIMEMessage::SetHeaderField (
615 const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex)
617 OString aName (rHeader.GetName());
618 const sal_Char *pData = aName.getStr();
619 const sal_Char *pStop = pData + aName.getLength() + 1;
620 const sal_Char *check = "";
622 InetMessageMime nIdx = static_cast<InetMessageMime>(CONTAINER_APPEND);
623 int eState = INETMSG_MIME_BEGIN;
624 int eOkState = INETMSG_MIME_OK;
626 while (pData < pStop)
628 switch (eState)
630 case INETMSG_MIME_BEGIN:
631 eState = INETMSG_MIME_CHECK;
632 eOkState = INETMSG_MIME_OK;
634 switch (ascii_toLowerCase (*pData))
636 case 'c':
637 check = "ontent-";
638 eOkState = INETMSG_MIME_TOKEN_CONTENT;
639 break;
641 case 'm':
642 check = "ime-version";
643 nIdx = InetMessageMime::VERSION;
644 break;
646 default:
647 eState = INETMSG_MIME_JUNK;
648 break;
650 pData++;
651 break;
653 case INETMSG_MIME_TOKEN_CONTENT:
654 eState = INETMSG_MIME_CHECK;
655 eOkState = INETMSG_MIME_OK;
657 switch (ascii_toLowerCase (*pData))
659 case 'd':
660 eState = INETMSG_MIME_TOKEN_CONTENT_D;
661 break;
663 case 'i':
664 check = "d";
665 nIdx = InetMessageMime::CONTENT_ID;
666 break;
668 case 't':
669 eState = INETMSG_MIME_TOKEN_CONTENT_T;
670 break;
672 default:
673 eState = INETMSG_MIME_JUNK;
674 break;
676 pData++;
677 break;
679 case INETMSG_MIME_TOKEN_CONTENT_D:
680 eState = INETMSG_MIME_CHECK;
681 eOkState = INETMSG_MIME_OK;
683 switch (ascii_toLowerCase (*pData))
685 case 'e':
686 check = "scription";
687 nIdx = InetMessageMime::CONTENT_DESCRIPTION;
688 break;
690 case 'i':
691 check = "sposition";
692 nIdx = InetMessageMime::CONTENT_DISPOSITION;
693 break;
695 default:
696 eState = INETMSG_MIME_JUNK;
697 break;
699 pData++;
700 break;
702 case INETMSG_MIME_TOKEN_CONTENT_T:
703 eState = INETMSG_MIME_CHECK;
704 eOkState = INETMSG_MIME_OK;
706 switch (ascii_toLowerCase (*pData))
708 case 'r':
709 check = "ansfer-encoding";
710 nIdx = InetMessageMime::CONTENT_TRANSFER_ENCODING;
711 break;
713 case 'y':
714 check = "pe";
715 nIdx = InetMessageMime::CONTENT_TYPE;
716 break;
718 default:
719 eState = INETMSG_MIME_JUNK;
720 break;
722 pData++;
723 break;
725 case INETMSG_MIME_CHECK:
726 if (*check)
728 while (*pData && *check &&
729 (ascii_toLowerCase (*pData) == *check))
731 pData++;
732 check++;
735 else
737 check = pData;
739 eState = (*check == '\0') ? eOkState : INETMSG_MIME_JUNK;
740 break;
742 case INETMSG_MIME_OK:
743 pData = pStop;
744 SetHeaderField_Impl (
745 INetMessageHeader( ImplINetMIMEMessageHeaderData.at(nIdx), rHeader.GetValue()),
746 m_nMIMEIndex[nIdx]);
747 nNewIndex = m_nMIMEIndex[nIdx];
748 break;
750 default: // INETMSG_MIME_JUNK
751 pData = pStop;
752 nNewIndex = SetRFC822HeaderField(rHeader, nNewIndex);
753 break;
756 return nNewIndex;
759 void INetMIMEMessage::SetMIMEVersion (const OUString& rVersion)
761 SetHeaderField_Impl (
762 INetMIME::HEADER_FIELD_TEXT,
763 ImplINetMIMEMessageHeaderData.at(InetMessageMime::VERSION), rVersion,
764 m_nMIMEIndex[InetMessageMime::VERSION]);
767 void INetMIMEMessage::SetContentDisposition (const OUString& rDisposition)
769 SetHeaderField_Impl (
770 INetMIME::HEADER_FIELD_TEXT,
771 ImplINetMIMEMessageHeaderData.at(InetMessageMime::CONTENT_DISPOSITION), rDisposition,
772 m_nMIMEIndex[InetMessageMime::CONTENT_DISPOSITION]);
775 void INetMIMEMessage::SetContentType (const OUString& rType)
777 SetHeaderField_Impl (
778 INetMIME::HEADER_FIELD_TEXT,
779 ImplINetMIMEMessageHeaderData.at(InetMessageMime::CONTENT_TYPE), rType,
780 m_nMIMEIndex[InetMessageMime::CONTENT_TYPE]);
783 void INetMIMEMessage::SetContentTransferEncoding (
784 const OUString& rEncoding)
786 SetHeaderField_Impl (
787 INetMIME::HEADER_FIELD_TEXT,
788 ImplINetMIMEMessageHeaderData.at(InetMessageMime::CONTENT_TRANSFER_ENCODING), rEncoding,
789 m_nMIMEIndex[InetMessageMime::CONTENT_TRANSFER_ENCODING]);
792 OUString INetMIMEMessage::GetDefaultContentType()
794 if (pParent != NULL)
796 OUString aParentCT (pParent->GetContentType());
797 if (aParentCT.isEmpty())
798 aParentCT = pParent->GetDefaultContentType();
800 if (aParentCT.equalsIgnoreAsciiCase("multipart/digest"))
801 return OUString("message/rfc822");
803 return OUString("text/plain; charset=us-ascii");
806 bool INetMIMEMessage::EnableAttachChild (INetMessageContainerType eType)
808 // Check context.
809 if (IsContainer())
810 return false;
812 // Setup Content-Type header field.
813 OStringBuffer aContentType;
814 switch (eType)
816 case INETMSG_MESSAGE_RFC822:
817 aContentType.append("message/rfc822");
818 break;
820 case INETMSG_MULTIPART_ALTERNATIVE:
821 aContentType.append("multipart/alternative");
822 break;
824 case INETMSG_MULTIPART_DIGEST:
825 aContentType.append("multipart/digest");
826 break;
828 case INETMSG_MULTIPART_PARALLEL:
829 aContentType.append("multipart/parallel");
830 break;
832 case INETMSG_MULTIPART_RELATED:
833 aContentType.append("multipart/related");
834 break;
836 case INETMSG_MULTIPART_FORM_DATA:
837 aContentType.append("multipart/form-data");
838 break;
840 default:
841 aContentType.append("multipart/mixed");
842 break;
845 // Setup boundary for multipart types.
846 if (aContentType.toString().equalsIgnoreAsciiCase("multipart/"))
848 // Generate a unique boundary from current time.
849 sal_Char sTail[16 + 1];
850 tools::Time aCurTime( tools::Time::SYSTEM );
851 sal_uInt64 nThis = reinterpret_cast< sal_uIntPtr >( this ); // we can be on a 64bit architecture
852 nThis = ( ( nThis >> 32 ) ^ nThis ) & SAL_MAX_UINT32;
853 sprintf (sTail, "%08X%08X",
854 static_cast< unsigned int >(aCurTime.GetTime()),
855 static_cast< unsigned int >(nThis));
856 m_aBoundary = "------------_4D48";
857 m_aBoundary += sTail;
859 // Append boundary as ContentType parameter.
860 aContentType.append("; boundary=");
861 aContentType.append(m_aBoundary);
864 // Set header fields.
865 SetMIMEVersion(OUString("1.0"));
866 SetContentType(OStringToOUString(aContentType.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US));
867 SetContentTransferEncoding(OUString("7bit"));
869 // Done.
870 return true;
873 bool INetMIMEMessage::AttachChild(INetMIMEMessage& rChildMsg, bool bOwner)
875 if (IsContainer())
877 if (bOwner) rChildMsg.pParent = this;
878 aChildren.push_back( &rChildMsg );
880 return true;
882 return false;
885 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */