Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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>
30 :
31 : #include <stdio.h>
32 : #include <map>
33 :
34 0 : inline bool ascii_isDigit( sal_Unicode ch )
35 : {
36 0 : return ((ch >= 0x0030) && (ch <= 0x0039));
37 : }
38 :
39 0 : inline bool ascii_isLetter( sal_Unicode ch )
40 : {
41 0 : return (( (ch >= 0x0041) && (ch <= 0x005A)) || ((ch >= 0x0061) && (ch <= 0x007A)));
42 : }
43 :
44 0 : inline sal_Unicode ascii_toLowerCase( sal_Unicode ch )
45 : {
46 0 : if ( (ch >= 0x0041) && (ch <= 0x005A) )
47 0 : return ch + 0x20;
48 : else
49 0 : return ch;
50 : }
51 :
52 0 : void INetMIMEMessage::ListCleanup_Impl()
53 : {
54 : // Cleanup.
55 0 : sal_uIntPtr i, n = m_aHeaderList.size();
56 0 : for (i = 0; i < n; i++)
57 0 : delete m_aHeaderList[ i ];
58 0 : m_aHeaderList.clear();
59 0 : }
60 :
61 0 : void INetMIMEMessage::ListCopy (const INetMIMEMessage &rMsg)
62 : {
63 0 : if (!(this == &rMsg))
64 : {
65 : // Cleanup.
66 0 : ListCleanup_Impl();
67 :
68 : // Copy.
69 0 : sal_uIntPtr i, n = rMsg.GetHeaderCount();
70 0 : for (i = 0; i < n; i++)
71 : {
72 0 : INetMessageHeader *p = rMsg.m_aHeaderList[ i ];
73 0 : m_aHeaderList.push_back( new INetMessageHeader(*p) );
74 : }
75 : }
76 0 : }
77 :
78 0 : void INetMIMEMessage::SetHeaderField_Impl (
79 : INetMIME::HeaderFieldType eType,
80 : const OString &rName,
81 : const OUString &rValue,
82 : sal_uIntPtr &rnIndex)
83 : {
84 0 : INetMIMEStringOutputSink aSink (0, 32767); /* weird the mime standard says that aline MUST not be longeur that 998 */
85 : INetMIME::writeHeaderFieldBody (
86 0 : aSink, eType, rValue, osl_getThreadTextEncoding(), false);
87 : SetHeaderField_Impl (
88 0 : INetMessageHeader (rName, aSink.takeBuffer()), rnIndex);
89 0 : }
90 :
91 700 : static const std::map<InetMessageField, const char *> ImplINetRFC822MessageHeaderData =
92 : {
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" } ,
109 : };
110 :
111 : /*
112 : State of RFC822 header parsing
113 : */
114 : enum class HeaderState
115 : {
116 : BEGIN,
117 : CHECK,
118 : OK,
119 : JUNK,
120 :
121 : TOKEN_RE,
122 : TOKEN_RETURNMINUS,
123 : TOKEN_XMINUS,
124 : LETTER_C,
125 : LETTER_S
126 : };
127 :
128 : /* ParseDateField and local helper functions.
129 : *
130 : * Parses a String in (implied) GMT format into class Date and tools::Time objects.
131 : * Four formats are accepted:
132 : *
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)
138 : */
139 :
140 : static const sal_Char *months[12] =
141 : {
142 : "Jan", "Feb", "Mar", "Apr", "May", "Jun",
143 : "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
144 : };
145 :
146 0 : static sal_uInt16 ParseNumber(const OString& rStr, sal_uInt16& nIndex)
147 : {
148 0 : sal_uInt16 n = nIndex;
149 0 : while ((n < rStr.getLength()) && ascii_isDigit(rStr[n])) n++;
150 :
151 0 : OString aNum(rStr.copy(nIndex, (n - nIndex)));
152 0 : nIndex = n;
153 :
154 0 : return (sal_uInt16)(aNum.toInt32());
155 : }
156 :
157 0 : static sal_uInt16 ParseMonth(const OString& rStr, sal_uInt16& nIndex)
158 : {
159 0 : sal_uInt16 n = nIndex;
160 0 : while ((n < rStr.getLength()) && ascii_isLetter(rStr[n])) n++;
161 :
162 0 : OString aMonth(rStr.copy(nIndex, 3));
163 0 : nIndex = n;
164 :
165 : sal_uInt16 i;
166 0 : for (i = 0; i < 12; i++)
167 0 : if (aMonth.equalsIgnoreAsciiCase(months[i])) break;
168 0 : return (i + 1);
169 : }
170 :
171 0 : bool INetMIMEMessage::ParseDateField (
172 : const OUString& rDateFieldW, DateTime& rDateTime)
173 : {
174 : OString aDateField(OUStringToOString(rDateFieldW,
175 0 : RTL_TEXTENCODING_ASCII_US));
176 :
177 0 : if (aDateField.isEmpty()) return false;
178 :
179 0 : if (aDateField.indexOf(':') != -1)
180 : {
181 : // Some DateTime format.
182 0 : sal_uInt16 nIndex = 0;
183 :
184 : // Skip over <Wkd> or <Weekday>, leading and trailing space.
185 0 : while ((nIndex < aDateField.getLength()) &&
186 0 : (aDateField[nIndex] == ' '))
187 0 : nIndex++;
188 :
189 0 : while (
190 0 : (nIndex < aDateField.getLength()) &&
191 0 : (ascii_isLetter (aDateField[nIndex]) ||
192 0 : (aDateField[nIndex] == ',') ))
193 0 : nIndex++;
194 :
195 0 : while ((nIndex < aDateField.getLength()) &&
196 0 : (aDateField[nIndex] == ' '))
197 0 : nIndex++;
198 :
199 0 : if (ascii_isLetter (aDateField[nIndex]))
200 : {
201 : // Format: ctime().
202 0 : if ((aDateField.getLength() - nIndex) < 20) return false;
203 :
204 0 : rDateTime.SetMonth (ParseMonth (aDateField, nIndex)); nIndex++;
205 0 : rDateTime.SetDay (ParseNumber (aDateField, nIndex)); nIndex++;
206 :
207 0 : rDateTime.SetHour (ParseNumber (aDateField, nIndex)); nIndex++;
208 0 : rDateTime.SetMin (ParseNumber (aDateField, nIndex)); nIndex++;
209 0 : rDateTime.SetSec (ParseNumber (aDateField, nIndex)); nIndex++;
210 0 : rDateTime.SetNanoSec (0);
211 :
212 0 : sal_uInt16 nYear = ParseNumber (aDateField, nIndex);
213 0 : if (nYear < 100) nYear += 1900;
214 0 : rDateTime.SetYear (nYear);
215 : }
216 : else
217 : {
218 : // Format: RFC1036 or RFC1123.
219 0 : if ((aDateField.getLength() - nIndex) < 17) return false;
220 :
221 0 : rDateTime.SetDay (ParseNumber (aDateField, nIndex)); nIndex++;
222 0 : rDateTime.SetMonth (ParseMonth (aDateField, nIndex)); nIndex++;
223 :
224 0 : sal_uInt16 nYear = ParseNumber (aDateField, nIndex); nIndex++;
225 0 : if (nYear < 100) nYear += 1900;
226 0 : rDateTime.SetYear (nYear);
227 :
228 0 : rDateTime.SetHour (ParseNumber (aDateField, nIndex)); nIndex++;
229 0 : rDateTime.SetMin (ParseNumber (aDateField, nIndex)); nIndex++;
230 0 : rDateTime.SetSec (ParseNumber (aDateField, nIndex)); nIndex++;
231 0 : rDateTime.SetNanoSec (0);
232 :
233 0 : const char cPossiblePlusMinus = nIndex < aDateField.getLength() ? aDateField[nIndex] : 0;
234 0 : if (cPossiblePlusMinus == '+' || cPossiblePlusMinus == '-')
235 : {
236 : // Offset from GMT: "(+|-)HHMM".
237 0 : bool bEast = (aDateField[nIndex++] == '+');
238 0 : sal_uInt16 nOffset = ParseNumber (aDateField, nIndex);
239 0 : if (nOffset > 0)
240 : {
241 0 : tools::Time aDiff( tools::Time::EMPTY );
242 0 : aDiff.SetHour (nOffset / 100);
243 0 : aDiff.SetMin (nOffset % 100);
244 0 : aDiff.SetSec (0);
245 0 : aDiff.SetNanoSec (0);
246 :
247 0 : if (bEast)
248 0 : rDateTime -= aDiff;
249 : else
250 0 : rDateTime += aDiff;
251 : }
252 : }
253 : }
254 : }
255 0 : else if (comphelper::string::isdigitAsciiString(aDateField))
256 : {
257 : // Format: delta seconds.
258 0 : tools::Time aDelta (0);
259 0 : aDelta.SetTime (aDateField.toInt32() * 100);
260 :
261 0 : DateTime aNow( DateTime::SYSTEM );
262 0 : aNow += aDelta;
263 0 : aNow.ConvertToUTC();
264 :
265 0 : rDateTime.SetDate (aNow.GetDate());
266 0 : rDateTime.SetTime (aNow.GetTime());
267 : }
268 : else
269 : {
270 : // Junk.
271 0 : return false;
272 : }
273 :
274 0 : return (rDateTime.IsValidAndGregorian() &&
275 0 : !((rDateTime.GetSec() > 59) ||
276 0 : (rDateTime.GetMin() > 59) ||
277 0 : (rDateTime.GetHour() > 23) ));
278 : }
279 :
280 : // Header Field Parser
281 0 : sal_uIntPtr INetMIMEMessage::SetRFC822HeaderField (
282 : const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex)
283 : {
284 0 : OString aName (rHeader.GetName());
285 0 : const sal_Char *pData = aName.getStr();
286 0 : const sal_Char *pStop = pData + aName.getLength() + 1;
287 0 : const sal_Char *check = "";
288 :
289 0 : InetMessageField nIdx = static_cast<InetMessageField>(CONTAINER_APPEND);
290 0 : HeaderState eState = HeaderState::BEGIN;
291 0 : HeaderState eOkState = HeaderState::OK;
292 :
293 0 : while (pData < pStop)
294 : {
295 0 : switch (eState)
296 : {
297 : case HeaderState::BEGIN:
298 0 : eState = HeaderState::CHECK;
299 0 : eOkState = HeaderState::OK;
300 :
301 0 : switch (ascii_toLowerCase (*pData))
302 : {
303 : case 'b':
304 0 : check = "cc";
305 0 : nIdx = InetMessageField::BCC;
306 0 : break;
307 :
308 : case 'c':
309 0 : eState = HeaderState::LETTER_C;
310 0 : break;
311 :
312 : case 'd':
313 0 : check = "ate";
314 0 : nIdx = InetMessageField::DATE;
315 0 : break;
316 :
317 : case 'f':
318 0 : check = "rom";
319 0 : nIdx = InetMessageField::FROM;
320 0 : break;
321 :
322 : case 'i':
323 0 : check = "n-reply-to";
324 0 : nIdx = InetMessageField::IN_REPLY_TO;
325 0 : break;
326 :
327 : case 'k':
328 0 : check = "eywords";
329 0 : nIdx = InetMessageField::KEYWORDS;
330 0 : break;
331 :
332 : case 'm':
333 0 : check = "essage-id";
334 0 : nIdx = InetMessageField::MESSAGE_ID;
335 0 : break;
336 :
337 : case 'r':
338 0 : check = "e";
339 0 : eOkState = HeaderState::TOKEN_RE;
340 0 : break;
341 :
342 : case 's':
343 0 : eState = HeaderState::LETTER_S;
344 0 : break;
345 :
346 : case 't':
347 0 : check = "o";
348 0 : nIdx = InetMessageField::TO;
349 0 : break;
350 :
351 : case 'x':
352 0 : check = "-";
353 0 : eOkState = HeaderState::TOKEN_XMINUS;
354 0 : break;
355 :
356 : default:
357 0 : eState = HeaderState::JUNK;
358 0 : break;
359 : }
360 0 : pData++;
361 0 : break;
362 :
363 : case HeaderState::TOKEN_RE:
364 0 : eState = HeaderState::CHECK;
365 0 : eOkState = HeaderState::OK;
366 :
367 0 : switch (ascii_toLowerCase (*pData))
368 : {
369 : case 'f':
370 0 : check = "erences";
371 0 : nIdx = InetMessageField::REFERENCES;
372 0 : break;
373 :
374 : case 'p':
375 0 : check = "ly-to";
376 0 : nIdx = InetMessageField::REPLY_TO;
377 0 : break;
378 :
379 : case 't':
380 0 : check = "urn-";
381 0 : eOkState = HeaderState::TOKEN_RETURNMINUS;
382 0 : break;
383 :
384 : default:
385 0 : eState = HeaderState::JUNK;
386 0 : break;
387 : }
388 0 : pData++;
389 0 : break;
390 :
391 : case HeaderState::TOKEN_RETURNMINUS:
392 0 : eState = HeaderState::CHECK;
393 0 : eOkState = HeaderState::OK;
394 :
395 0 : switch (ascii_toLowerCase (*pData))
396 : {
397 : case 'p':
398 0 : check = "ath";
399 0 : nIdx = InetMessageField::RETURN_PATH;
400 0 : break;
401 :
402 : case 'r':
403 0 : check = "eceipt-to";
404 0 : nIdx = InetMessageField::RETURN_RECEIPT_TO;
405 0 : break;
406 :
407 : default:
408 0 : eState = HeaderState::JUNK;
409 0 : break;
410 : }
411 0 : pData++;
412 0 : break;
413 :
414 : case HeaderState::TOKEN_XMINUS:
415 0 : eState = HeaderState::CHECK;
416 0 : eOkState = HeaderState::OK;
417 :
418 0 : switch (ascii_toLowerCase (*pData))
419 : {
420 : case 'm':
421 0 : check = "ailer";
422 0 : nIdx = InetMessageField::X_MAILER;
423 0 : break;
424 :
425 : default:
426 0 : eState = HeaderState::JUNK;
427 0 : break;
428 : }
429 0 : pData++;
430 0 : break;
431 :
432 : case HeaderState::LETTER_C:
433 0 : eState = HeaderState::CHECK;
434 0 : eOkState = HeaderState::OK;
435 :
436 0 : switch (ascii_toLowerCase (*pData))
437 : {
438 : case 'c':
439 0 : check = "";
440 0 : nIdx = InetMessageField::CC;
441 0 : break;
442 :
443 : case 'o':
444 0 : check = "mments";
445 0 : nIdx = InetMessageField::COMMENTS;
446 0 : break;
447 :
448 : default:
449 0 : eState = HeaderState::JUNK;
450 0 : break;
451 : }
452 0 : pData++;
453 0 : break;
454 :
455 : case HeaderState::LETTER_S:
456 0 : eState = HeaderState::CHECK;
457 0 : eOkState = HeaderState::OK;
458 :
459 0 : switch (ascii_toLowerCase (*pData))
460 : {
461 : case 'e':
462 0 : check = "nder";
463 0 : nIdx = InetMessageField::SENDER;
464 0 : break;
465 :
466 : case 'u':
467 0 : check = "bject";
468 0 : nIdx = InetMessageField::SUBJECT;
469 0 : break;
470 :
471 : default:
472 0 : eState = HeaderState::JUNK;
473 0 : break;
474 : }
475 0 : pData++;
476 0 : break;
477 :
478 : case HeaderState::CHECK:
479 0 : if (*check)
480 : {
481 0 : while (*pData && *check &&
482 0 : (ascii_toLowerCase (*pData) == *check))
483 : {
484 0 : pData++;
485 0 : check++;
486 : }
487 : }
488 : else
489 : {
490 0 : check = pData;
491 : }
492 0 : eState = (*check == '\0') ? eOkState : HeaderState::JUNK;
493 0 : break;
494 :
495 : case HeaderState::OK:
496 0 : pData = pStop;
497 : SetHeaderField_Impl (
498 0 : INetMessageHeader( ImplINetRFC822MessageHeaderData.at(nIdx), rHeader.GetValue() ),
499 0 : m_nRFC822Index[nIdx]);
500 0 : nNewIndex = m_nRFC822Index[nIdx];
501 0 : break;
502 :
503 : default: // INETMSG_RFC822_JUNK
504 0 : pData = pStop;
505 0 : SetHeaderField_Impl(rHeader, nNewIndex);
506 0 : break;
507 : }
508 : }
509 0 : return nNewIndex;
510 : }
511 :
512 700 : static const std::map<InetMessageMime, const char*> ImplINetMIMEMessageHeaderData =
513 : {
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"}
520 : };
521 :
522 : enum _ImplINetMIMEMessageHeaderState
523 : {
524 : INETMSG_MIME_BEGIN,
525 : INETMSG_MIME_CHECK,
526 : INETMSG_MIME_OK,
527 : INETMSG_MIME_JUNK,
528 :
529 : INETMSG_MIME_TOKEN_CONTENT,
530 : INETMSG_MIME_TOKEN_CONTENT_D,
531 : INETMSG_MIME_TOKEN_CONTENT_T
532 : };
533 :
534 0 : INetMIMEMessage::INetMIMEMessage()
535 : : m_nDocSize(0),
536 : pParent(NULL),
537 0 : bHeaderParsed(false)
538 : {
539 0 : for (sal_uInt16 i = 0; i < static_cast<int>(InetMessageField::NUMHDR); i++)
540 0 : m_nRFC822Index[static_cast<InetMessageField>(i)] = CONTAINER_ENTRY_NOTFOUND;
541 0 : for (sal_uInt16 i = 0; i < static_cast<int>(InetMessageMime::NUMHDR); i++)
542 0 : m_nMIMEIndex[static_cast<InetMessageMime>(i)] = CONTAINER_ENTRY_NOTFOUND;
543 0 : }
544 :
545 0 : INetMIMEMessage::INetMIMEMessage (const INetMIMEMessage& rMsg)
546 : : m_nDocSize(rMsg.m_nDocSize),
547 : m_aDocName(rMsg.m_aDocName),
548 : m_xDocLB(rMsg.m_xDocLB),
549 0 : pParent(NULL)
550 : {
551 0 : ListCopy (rMsg);
552 0 : m_nRFC822Index = rMsg.m_nRFC822Index;
553 0 : CopyImp (rMsg);
554 0 : }
555 :
556 0 : INetMIMEMessage& INetMIMEMessage::operator= (
557 : const INetMIMEMessage& rMsg)
558 : {
559 0 : if (this != &rMsg)
560 : {
561 0 : m_nDocSize = rMsg.m_nDocSize;
562 0 : m_aDocName = rMsg.m_aDocName;
563 0 : m_xDocLB = rMsg.m_xDocLB;
564 0 : ListCopy (rMsg);
565 0 : m_nRFC822Index = rMsg.m_nRFC822Index;
566 0 : CleanupImp();
567 0 : CopyImp (rMsg);
568 : }
569 0 : return *this;
570 : }
571 :
572 0 : INetMIMEMessage::~INetMIMEMessage()
573 : {
574 0 : ListCleanup_Impl();
575 0 : CleanupImp();
576 0 : }
577 :
578 0 : void INetMIMEMessage::CleanupImp()
579 : {
580 0 : for( size_t i = 0, n = aChildren.size(); i < n; ++i ) {
581 0 : delete aChildren[ i ];
582 : }
583 0 : aChildren.clear();
584 0 : }
585 :
586 0 : void INetMIMEMessage::CopyImp (const INetMIMEMessage& rMsg)
587 : {
588 0 : bHeaderParsed = rMsg.bHeaderParsed;
589 :
590 : size_t i;
591 0 : m_nMIMEIndex = rMsg.m_nMIMEIndex;
592 0 : m_aBoundary = rMsg.m_aBoundary;
593 :
594 0 : for (i = 0; i < rMsg.aChildren.size(); i++)
595 : {
596 0 : INetMIMEMessage *pChild = rMsg.aChildren[ i ];
597 :
598 0 : if (pChild->pParent == &rMsg)
599 : {
600 0 : pChild = INetMIMEMessage::CreateMessage (*pChild);
601 0 : pChild->pParent = this;
602 : }
603 0 : aChildren.push_back( pChild );
604 : }
605 0 : }
606 :
607 0 : INetMIMEMessage *INetMIMEMessage::CreateMessage (
608 : const INetMIMEMessage& rMsg)
609 : {
610 0 : return new INetMIMEMessage (rMsg);
611 : }
612 :
613 : // Header Field Parser
614 0 : sal_uIntPtr INetMIMEMessage::SetHeaderField (
615 : const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex)
616 : {
617 0 : OString aName (rHeader.GetName());
618 0 : const sal_Char *pData = aName.getStr();
619 0 : const sal_Char *pStop = pData + aName.getLength() + 1;
620 0 : const sal_Char *check = "";
621 :
622 0 : InetMessageMime nIdx = static_cast<InetMessageMime>(CONTAINER_APPEND);
623 0 : int eState = INETMSG_MIME_BEGIN;
624 0 : int eOkState = INETMSG_MIME_OK;
625 :
626 0 : while (pData < pStop)
627 : {
628 0 : switch (eState)
629 : {
630 : case INETMSG_MIME_BEGIN:
631 0 : eState = INETMSG_MIME_CHECK;
632 0 : eOkState = INETMSG_MIME_OK;
633 :
634 0 : switch (ascii_toLowerCase (*pData))
635 : {
636 : case 'c':
637 0 : check = "ontent-";
638 0 : eOkState = INETMSG_MIME_TOKEN_CONTENT;
639 0 : break;
640 :
641 : case 'm':
642 0 : check = "ime-version";
643 0 : nIdx = InetMessageMime::VERSION;
644 0 : break;
645 :
646 : default:
647 0 : eState = INETMSG_MIME_JUNK;
648 0 : break;
649 : }
650 0 : pData++;
651 0 : break;
652 :
653 : case INETMSG_MIME_TOKEN_CONTENT:
654 0 : eState = INETMSG_MIME_CHECK;
655 0 : eOkState = INETMSG_MIME_OK;
656 :
657 0 : switch (ascii_toLowerCase (*pData))
658 : {
659 : case 'd':
660 0 : eState = INETMSG_MIME_TOKEN_CONTENT_D;
661 0 : break;
662 :
663 : case 'i':
664 0 : check = "d";
665 0 : nIdx = InetMessageMime::CONTENT_ID;
666 0 : break;
667 :
668 : case 't':
669 0 : eState = INETMSG_MIME_TOKEN_CONTENT_T;
670 0 : break;
671 :
672 : default:
673 0 : eState = INETMSG_MIME_JUNK;
674 0 : break;
675 : }
676 0 : pData++;
677 0 : break;
678 :
679 : case INETMSG_MIME_TOKEN_CONTENT_D:
680 0 : eState = INETMSG_MIME_CHECK;
681 0 : eOkState = INETMSG_MIME_OK;
682 :
683 0 : switch (ascii_toLowerCase (*pData))
684 : {
685 : case 'e':
686 0 : check = "scription";
687 0 : nIdx = InetMessageMime::CONTENT_DESCRIPTION;
688 0 : break;
689 :
690 : case 'i':
691 0 : check = "sposition";
692 0 : nIdx = InetMessageMime::CONTENT_DISPOSITION;
693 0 : break;
694 :
695 : default:
696 0 : eState = INETMSG_MIME_JUNK;
697 0 : break;
698 : }
699 0 : pData++;
700 0 : break;
701 :
702 : case INETMSG_MIME_TOKEN_CONTENT_T:
703 0 : eState = INETMSG_MIME_CHECK;
704 0 : eOkState = INETMSG_MIME_OK;
705 :
706 0 : switch (ascii_toLowerCase (*pData))
707 : {
708 : case 'r':
709 0 : check = "ansfer-encoding";
710 0 : nIdx = InetMessageMime::CONTENT_TRANSFER_ENCODING;
711 0 : break;
712 :
713 : case 'y':
714 0 : check = "pe";
715 0 : nIdx = InetMessageMime::CONTENT_TYPE;
716 0 : break;
717 :
718 : default:
719 0 : eState = INETMSG_MIME_JUNK;
720 0 : break;
721 : }
722 0 : pData++;
723 0 : break;
724 :
725 : case INETMSG_MIME_CHECK:
726 0 : if (*check)
727 : {
728 0 : while (*pData && *check &&
729 0 : (ascii_toLowerCase (*pData) == *check))
730 : {
731 0 : pData++;
732 0 : check++;
733 : }
734 : }
735 : else
736 : {
737 0 : check = pData;
738 : }
739 0 : eState = (*check == '\0') ? eOkState : INETMSG_MIME_JUNK;
740 0 : break;
741 :
742 : case INETMSG_MIME_OK:
743 0 : pData = pStop;
744 : SetHeaderField_Impl (
745 0 : INetMessageHeader( ImplINetMIMEMessageHeaderData.at(nIdx), rHeader.GetValue()),
746 0 : m_nMIMEIndex[nIdx]);
747 0 : nNewIndex = m_nMIMEIndex[nIdx];
748 0 : break;
749 :
750 : default: // INETMSG_MIME_JUNK
751 0 : pData = pStop;
752 0 : nNewIndex = SetRFC822HeaderField(rHeader, nNewIndex);
753 0 : break;
754 : }
755 : }
756 0 : return nNewIndex;
757 : }
758 :
759 0 : void INetMIMEMessage::SetMIMEVersion (const OUString& rVersion)
760 : {
761 : SetHeaderField_Impl (
762 : INetMIME::HEADER_FIELD_TEXT,
763 0 : ImplINetMIMEMessageHeaderData.at(InetMessageMime::VERSION), rVersion,
764 0 : m_nMIMEIndex[InetMessageMime::VERSION]);
765 0 : }
766 :
767 0 : void INetMIMEMessage::SetContentDisposition (const OUString& rDisposition)
768 : {
769 : SetHeaderField_Impl (
770 : INetMIME::HEADER_FIELD_TEXT,
771 0 : ImplINetMIMEMessageHeaderData.at(InetMessageMime::CONTENT_DISPOSITION), rDisposition,
772 0 : m_nMIMEIndex[InetMessageMime::CONTENT_DISPOSITION]);
773 0 : }
774 :
775 0 : void INetMIMEMessage::SetContentType (const OUString& rType)
776 : {
777 : SetHeaderField_Impl (
778 : INetMIME::HEADER_FIELD_TEXT,
779 0 : ImplINetMIMEMessageHeaderData.at(InetMessageMime::CONTENT_TYPE), rType,
780 0 : m_nMIMEIndex[InetMessageMime::CONTENT_TYPE]);
781 0 : }
782 :
783 0 : void INetMIMEMessage::SetContentTransferEncoding (
784 : const OUString& rEncoding)
785 : {
786 : SetHeaderField_Impl (
787 : INetMIME::HEADER_FIELD_TEXT,
788 0 : ImplINetMIMEMessageHeaderData.at(InetMessageMime::CONTENT_TRANSFER_ENCODING), rEncoding,
789 0 : m_nMIMEIndex[InetMessageMime::CONTENT_TRANSFER_ENCODING]);
790 0 : }
791 :
792 0 : OUString INetMIMEMessage::GetDefaultContentType()
793 : {
794 0 : if (pParent != NULL)
795 : {
796 0 : OUString aParentCT (pParent->GetContentType());
797 0 : if (aParentCT.isEmpty())
798 0 : aParentCT = pParent->GetDefaultContentType();
799 :
800 0 : if (aParentCT.equalsIgnoreAsciiCase("multipart/digest"))
801 0 : return OUString("message/rfc822");
802 : }
803 0 : return OUString("text/plain; charset=us-ascii");
804 : }
805 :
806 0 : bool INetMIMEMessage::EnableAttachChild (INetMessageContainerType eType)
807 : {
808 : // Check context.
809 0 : if (IsContainer())
810 0 : return false;
811 :
812 : // Setup Content-Type header field.
813 0 : OStringBuffer aContentType;
814 0 : switch (eType)
815 : {
816 : case INETMSG_MESSAGE_RFC822:
817 0 : aContentType.append("message/rfc822");
818 0 : break;
819 :
820 : case INETMSG_MULTIPART_ALTERNATIVE:
821 0 : aContentType.append("multipart/alternative");
822 0 : break;
823 :
824 : case INETMSG_MULTIPART_DIGEST:
825 0 : aContentType.append("multipart/digest");
826 0 : break;
827 :
828 : case INETMSG_MULTIPART_PARALLEL:
829 0 : aContentType.append("multipart/parallel");
830 0 : break;
831 :
832 : case INETMSG_MULTIPART_RELATED:
833 0 : aContentType.append("multipart/related");
834 0 : break;
835 :
836 : case INETMSG_MULTIPART_FORM_DATA:
837 0 : aContentType.append("multipart/form-data");
838 0 : break;
839 :
840 : default:
841 0 : aContentType.append("multipart/mixed");
842 0 : break;
843 : }
844 :
845 : // Setup boundary for multipart types.
846 0 : if (aContentType.toString().equalsIgnoreAsciiCase("multipart/"))
847 : {
848 : // Generate a unique boundary from current time.
849 : sal_Char sTail[16 + 1];
850 0 : tools::Time aCurTime( tools::Time::SYSTEM );
851 0 : sal_uInt64 nThis = reinterpret_cast< sal_uIntPtr >( this ); // we can be on a 64bit architecture
852 0 : nThis = ( ( nThis >> 32 ) ^ nThis ) & SAL_MAX_UINT32;
853 : sprintf (sTail, "%08X%08X",
854 0 : static_cast< unsigned int >(aCurTime.GetTime()),
855 0 : static_cast< unsigned int >(nThis));
856 0 : m_aBoundary = "------------_4D48";
857 0 : m_aBoundary += sTail;
858 :
859 : // Append boundary as ContentType parameter.
860 0 : aContentType.append("; boundary=");
861 0 : aContentType.append(m_aBoundary);
862 : }
863 :
864 : // Set header fields.
865 0 : SetMIMEVersion(OUString("1.0"));
866 0 : SetContentType(OStringToOUString(aContentType.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US));
867 0 : SetContentTransferEncoding(OUString("7bit"));
868 :
869 : // Done.
870 0 : return true;
871 : }
872 :
873 0 : bool INetMIMEMessage::AttachChild(INetMIMEMessage& rChildMsg, bool bOwner)
874 : {
875 0 : if (IsContainer())
876 : {
877 0 : if (bOwner) rChildMsg.pParent = this;
878 0 : aChildren.push_back( &rChildMsg );
879 :
880 0 : return true;
881 : }
882 0 : return false;
883 2100 : }
884 :
885 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|