/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_tools.hxx" #include #include #ifndef _TOOLS_INETMIME_HXX #include #endif #include #include #include #include //======================================================================= inline sal_Bool ascii_isDigit( sal_Unicode ch ) { return ((ch >= 0x0030) && (ch <= 0x0039)); } inline sal_Bool ascii_isLetter( sal_Unicode ch ) { return (( (ch >= 0x0041) && (ch <= 0x005A)) || ((ch >= 0x0061) && (ch <= 0x007A))); } inline sal_Unicode ascii_toLowerCase( sal_Unicode ch ) { if ( (ch >= 0x0041) && (ch <= 0x005A) ) return ch + 0x20; else return ch; } /*======================================================================= * * INetMessage Implementation. * *=====================================================================*/ #define CONSTASCII_STRINGPARAM(a) (a), RTL_TEXTENCODING_ASCII_US #define HEADERFIELD INetMessageHeader /* * ~INetMessage. */ INetMessage::~INetMessage (void) { ListCleanup_Impl(); } /* * ListCleanup_Impl. */ void INetMessage::ListCleanup_Impl (void) { // Cleanup. sal_uIntPtr i, n = m_aHeaderList.Count(); for (i = 0; i < n; i++) delete ((HEADERFIELD*)(m_aHeaderList.GetObject(i))); m_aHeaderList.Clear(); } /* * ListCopy. */ void INetMessage::ListCopy (const INetMessage &rMsg) { if (!(this == &rMsg)) { // Cleanup. ListCleanup_Impl(); // Copy. sal_uIntPtr i, n = rMsg.GetHeaderCount(); for (i = 0; i < n; i++) { HEADERFIELD *p = (HEADERFIELD*)(rMsg.m_aHeaderList.GetObject(i)); m_aHeaderList.Insert (new HEADERFIELD(*p), LIST_APPEND); } } } /* * SetHeaderField_Impl. */ void INetMessage::SetHeaderField_Impl ( INetMIME::HeaderFieldType eType, const ByteString &rName, const UniString &rValue, sal_uIntPtr &rnIndex) { INetMIMEStringOutputSink aSink (0, STRING_MAXLEN); INetMIME::writeHeaderFieldBody ( aSink, eType, rValue, gsl_getSystemTextEncoding(), false); SetHeaderField_Impl ( INetMessageHeader (rName, aSink.takeBuffer()), rnIndex); } /* * SetHeaderField. */ sal_uIntPtr INetMessage::SetHeaderField ( const UniString& rName, const UniString& rValue, sal_uIntPtr nIndex) { sal_uIntPtr nResult = nIndex; SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, ByteString (rName, RTL_TEXTENCODING_ASCII_US), rValue, nResult); return nResult; } /* * SetHeaderField. */ sal_uIntPtr INetMessage::SetHeaderField ( const INetMessageHeader &rHeader, sal_uIntPtr nIndex) { sal_uIntPtr nResult = nIndex; SetHeaderField_Impl (rHeader, nResult); return nResult; } /* * operator<< */ SvStream& INetMessage::operator<< (SvStream& rStrm) const { rStrm << static_cast(m_nDocSize); rStrm.WriteByteString (m_aDocName, RTL_TEXTENCODING_UTF8); sal_uIntPtr i, n = m_aHeaderList.Count(); rStrm << static_cast(n); for (i = 0; i < n; i++) rStrm << *((HEADERFIELD *)(m_aHeaderList.GetObject(i))); return rStrm; } /* * operator>> */ SvStream& INetMessage::operator>> (SvStream& rStrm) { // Cleanup. m_nDocSize = 0; m_xDocLB.Clear(); ListCleanup_Impl(); sal_uInt32 nTemp; // Copy. rStrm >> nTemp; m_nDocSize = nTemp; rStrm.ReadByteString (m_aDocName, RTL_TEXTENCODING_UTF8); sal_uIntPtr i, n = 0; rStrm >> nTemp; n = nTemp; for (i = 0; i < n; i++) { HEADERFIELD *p = new HEADERFIELD(); rStrm >> *p; m_aHeaderList.Insert (p, LIST_APPEND); } // Done. return rStrm; } /*======================================================================= * * INetMessageHeaderIterator Implementation. * *=====================================================================*/ INetMessageHeaderIterator::INetMessageHeaderIterator ( const INetMessage& rMsg, const UniString& rHdrName) { sal_uIntPtr i, n = rMsg.GetHeaderCount(); for (i = 0; i < n; i++) { if (rHdrName.CompareIgnoreCaseToAscii (rMsg.GetHeaderName(i)) == 0) { UniString *pValue = new UniString (rMsg.GetHeaderValue(i)); aValueList.Insert (pValue, LIST_APPEND); } } nValueCount = aValueList.Count(); } INetMessageHeaderIterator::~INetMessageHeaderIterator (void) { sal_uIntPtr i, n = aValueList.Count(); for (i = 0; i < n; i++) delete ((UniString*)(aValueList.GetObject(i))); aValueList.Clear(); } /*======================================================================= * * INetRFC822Message Implementation. * *=====================================================================*/ /* * ImplINetRFC822MessageHeaderData. */ namespace { struct ImplINetRFC822MessageHeaderDataImpl { const ByteString* operator()() { static const ByteString _ImplINetRFC822MessageHeaderData[] = { ByteString ("BCC"), ByteString ("CC"), ByteString ("Comments"), ByteString ("Date"), ByteString ("From"), ByteString ("In-Reply-To"), ByteString ("Keywords"), ByteString ("Message-ID"), ByteString ("References"), ByteString ("Reply-To"), ByteString ("Return-Path"), ByteString ("Subject"), ByteString ("Sender"), ByteString ("To"), ByteString ("X-Mailer"), ByteString ("Return-Receipt-To") }; return &_ImplINetRFC822MessageHeaderData[0]; } }; struct ImplINetRFC822MessageHeaderData : public rtl::StaticAggregate< const ByteString, ImplINetRFC822MessageHeaderDataImpl > {}; } #define HDR(n) ImplINetRFC822MessageHeaderData::get()[(n)] /* * _ImplINetRFC822MessageHeaderState. */ enum _ImplINetRFC822MessageHeaderState { INETMSG_RFC822_BEGIN, INETMSG_RFC822_CHECK, INETMSG_RFC822_OK, INETMSG_RFC822_JUNK, INETMSG_RFC822_TOKEN_RE, INETMSG_RFC822_TOKEN_RETURNMINUS, INETMSG_RFC822_TOKEN_XMINUS, INETMSG_RFC822_LETTER_C, INETMSG_RFC822_LETTER_S }; /* * INetRFC822Message. */ INetRFC822Message::INetRFC822Message (void) : INetMessage() { for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++) m_nIndex[i] = LIST_ENTRY_NOTFOUND; } INetRFC822Message::INetRFC822Message (const INetRFC822Message& rMsg) : INetMessage (rMsg) { for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++) m_nIndex[i] = rMsg.m_nIndex[i]; } /* * operator= */ INetRFC822Message& INetRFC822Message::operator= (const INetRFC822Message& rMsg) { if (this != &rMsg) { INetMessage::operator= (rMsg); for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++) m_nIndex[i] = rMsg.m_nIndex[i]; } return *this; } /* * ~INetRFC822Message. */ INetRFC822Message::~INetRFC822Message (void) { } /* * DateField and local helper functions. * * GenerateDateField. * Generates a String from Date and Time objects in format: * Wkd, 00 Mon 0000 00:00:00 [GMT] (rfc822, rfc1123) * * ParseDateField. * Parses a String in (implied) GMT format into class Date and Time objects. * Four formats are accepted: * * [Wkd,] 1*2DIGIT Mon 2*4DIGIT 00:00:00 [GMT] (rfc1123) * [Wkd,] 00 Mon 0000 00:00:00 [GMT]) (rfc822, rfc1123) * Weekday, 00-Mon-00 00:00:00 [GMT] (rfc850, rfc1036) * Wkd Mon 00 00:00:00 0000 [GMT] (ctime) * 1*DIGIT (delta seconds) * */ // Months and Weekdays. static const sal_Char *months[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static const sal_Char *wkdays[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; /* * GenerateDateField. */ sal_Bool INetRFC822Message::GenerateDateField ( const DateTime& rDateTime, UniString& rDateFieldW) { // Check arguments. if (!rDateTime.IsValid() || (rDateTime.GetSec() > 59) || (rDateTime.GetMin() > 59) || (rDateTime.GetHour() > 23) ) return sal_False; // Prepare output string. ByteString rDateField; // Insert Date. rDateField += wkdays[(sal_uInt16)(rDateTime.GetDayOfWeek())]; rDateField += ", "; sal_uInt16 nNum = rDateTime.GetDay(); if (nNum < 10) rDateField += '0'; rDateField += ByteString::CreateFromInt32(nNum); rDateField += ' '; rDateField += months[(sal_uInt16)(rDateTime.GetMonth() - 1)]; rDateField += ' '; rDateField += ByteString::CreateFromInt32(rDateTime.GetYear()); rDateField += ' '; // Insert Time. nNum = rDateTime.GetHour(); if (nNum < 10) rDateField += '0'; rDateField += ByteString::CreateFromInt32(nNum); rDateField += ':'; nNum = rDateTime.GetMin(); if (nNum < 10) rDateField += '0'; rDateField += ByteString::CreateFromInt32(nNum); rDateField += ':'; nNum = rDateTime.GetSec(); if (nNum < 10) rDateField += '0'; rDateField += ByteString::CreateFromInt32(nNum); rDateField += " GMT"; // Done. rDateFieldW = UniString (rDateField, RTL_TEXTENCODING_ASCII_US); return sal_True; } /* * ParseDateField and local helper functions. */ static sal_uInt16 ParseNumber (const ByteString& rStr, sal_uInt16& nIndex) { sal_uInt16 n = nIndex; while ((n < rStr.Len()) && ascii_isDigit(rStr.GetChar(n))) n++; ByteString aNum (rStr.Copy (nIndex, (n - nIndex))); nIndex = n; return (sal_uInt16)(aNum.ToInt32()); } static sal_uInt16 ParseMonth (const ByteString& rStr, sal_uInt16& nIndex) { sal_uInt16 n = nIndex; while ((n < rStr.Len()) && ascii_isLetter(rStr.GetChar(n))) n++; ByteString aMonth (rStr.Copy (nIndex, 3)); nIndex = n; sal_uInt16 i; for (i = 0; i < 12; i++) if (aMonth.CompareIgnoreCaseToAscii (months[i]) == 0) break; return (i + 1); } sal_Bool INetRFC822Message::ParseDateField ( const UniString& rDateFieldW, DateTime& rDateTime) { ByteString rDateField (rDateFieldW, RTL_TEXTENCODING_ASCII_US); if (rDateField.Len() == 0) return sal_False; if (rDateField.Search (':') != STRING_NOTFOUND) { // Some DateTime format. sal_uInt16 nIndex = 0; // Skip over or , leading and trailing space. while ((nIndex < rDateField.Len()) && (rDateField.GetChar(nIndex) == ' ')) nIndex++; while ( (nIndex < rDateField.Len()) && (ascii_isLetter (rDateField.GetChar(nIndex)) || (rDateField.GetChar(nIndex) == ',') )) nIndex++; while ((nIndex < rDateField.Len()) && (rDateField.GetChar(nIndex) == ' ')) nIndex++; if (ascii_isLetter (rDateField.GetChar(nIndex))) { // Format: ctime(). if ((rDateField.Len() - nIndex) < 20) return sal_False; rDateTime.SetMonth (ParseMonth (rDateField, nIndex)); nIndex++; rDateTime.SetDay (ParseNumber (rDateField, nIndex)); nIndex++; rDateTime.SetHour (ParseNumber (rDateField, nIndex)); nIndex++; rDateTime.SetMin (ParseNumber (rDateField, nIndex)); nIndex++; rDateTime.SetSec (ParseNumber (rDateField, nIndex)); nIndex++; rDateTime.Set100Sec (0); sal_uInt16 nYear = ParseNumber (rDateField, nIndex); if (nYear < 100) nYear += 1900; rDateTime.SetYear (nYear); } else { // Format: RFC1036 or RFC1123. if ((rDateField.Len() - nIndex) < 17) return sal_False; rDateTime.SetDay (ParseNumber (rDateField, nIndex)); nIndex++; rDateTime.SetMonth (ParseMonth (rDateField, nIndex)); nIndex++; sal_uInt16 nYear = ParseNumber (rDateField, nIndex); nIndex++; if (nYear < 100) nYear += 1900; rDateTime.SetYear (nYear); rDateTime.SetHour (ParseNumber (rDateField, nIndex)); nIndex++; rDateTime.SetMin (ParseNumber (rDateField, nIndex)); nIndex++; rDateTime.SetSec (ParseNumber (rDateField, nIndex)); nIndex++; rDateTime.Set100Sec (0); if ((rDateField.GetChar(nIndex) == '+') || (rDateField.GetChar(nIndex) == '-') ) { // Offset from GMT: "(+|-)HHMM". sal_Bool bEast = (rDateField.GetChar(nIndex++) == '+'); sal_uInt16 nOffset = ParseNumber (rDateField, nIndex); if (nOffset > 0) { Time aDiff; aDiff.SetHour (nOffset / 100); aDiff.SetMin (nOffset % 100); aDiff.SetSec (0); aDiff.Set100Sec (0); if (bEast) rDateTime -= aDiff; else rDateTime += aDiff; } } } } else if (rDateField.IsNumericAscii()) { // Format: delta seconds. Time aDelta (0); aDelta.SetTime (rDateField.ToInt32() * 100); DateTime aNow; aNow += aDelta; aNow.ConvertToUTC(); rDateTime.SetDate (aNow.GetDate()); rDateTime.SetTime (aNow.GetTime()); } else { // Junk. return sal_False; } return (rDateTime.IsValid() && !((rDateTime.GetSec() > 59) || (rDateTime.GetMin() > 59) || (rDateTime.GetHour() > 23) )); } /* * SetHeaderField. * (Header Field Parser). */ sal_uIntPtr INetRFC822Message::SetHeaderField ( const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex) { ByteString aName (rHeader.GetName()); const sal_Char *pData = aName.GetBuffer(); const sal_Char *pStop = pData + aName.Len() + 1; const sal_Char *check = ""; sal_uIntPtr nIdx = LIST_APPEND; int eState = INETMSG_RFC822_BEGIN; int eOkState = INETMSG_RFC822_OK; while (pData < pStop) { switch (eState) { case INETMSG_RFC822_BEGIN: eState = INETMSG_RFC822_CHECK; eOkState = INETMSG_RFC822_OK; switch (ascii_toLowerCase (*pData)) { case 'b': check = "cc"; nIdx = INETMSG_RFC822_BCC; break; case 'c': eState = INETMSG_RFC822_LETTER_C; break; case 'd': check = "ate"; nIdx = INETMSG_RFC822_DATE; break; case 'f': check = "rom"; nIdx = INETMSG_RFC822_FROM; break; case 'i': check = "n-reply-to"; nIdx = INETMSG_RFC822_IN_REPLY_TO; break; case 'k': check = "eywords"; nIdx = INETMSG_RFC822_KEYWORDS; break; case 'm': check = "essage-id"; nIdx = INETMSG_RFC822_MESSAGE_ID; break; case 'r': check = "e"; eOkState = INETMSG_RFC822_TOKEN_RE; break; case 's': eState = INETMSG_RFC822_LETTER_S; break; case 't': check = "o"; nIdx = INETMSG_RFC822_TO; break; case 'x': check = "-"; eOkState = INETMSG_RFC822_TOKEN_XMINUS; break; default: eState = INETMSG_RFC822_JUNK; break; } pData++; break; case INETMSG_RFC822_TOKEN_RE: eState = INETMSG_RFC822_CHECK; eOkState = INETMSG_RFC822_OK; switch (ascii_toLowerCase (*pData)) { case 'f': check = "erences"; nIdx = INETMSG_RFC822_REFERENCES; break; case 'p': check = "ly-to"; nIdx = INETMSG_RFC822_REPLY_TO; break; case 't': check = "urn-"; eOkState = INETMSG_RFC822_TOKEN_RETURNMINUS; break; default: eState = INETMSG_RFC822_JUNK; break; } pData++; break; case INETMSG_RFC822_TOKEN_RETURNMINUS: eState = INETMSG_RFC822_CHECK; eOkState = INETMSG_RFC822_OK; switch (ascii_toLowerCase (*pData)) { case 'p': check = "ath"; nIdx = INETMSG_RFC822_RETURN_PATH; break; case 'r': check = "eceipt-to"; nIdx = INETMSG_RFC822_RETURN_RECEIPT_TO; break; default: eState = INETMSG_RFC822_JUNK; break; } pData++; break; case INETMSG_RFC822_TOKEN_XMINUS: eState = INETMSG_RFC822_CHECK; eOkState = INETMSG_RFC822_OK; switch (ascii_toLowerCase (*pData)) { case 'm': check = "ailer"; nIdx = INETMSG_RFC822_X_MAILER; break; #if 0 /* NYI */ case 'p': check = "riority"; eOkState = INETMSG_RFC822_X_PRIORITY; break; #endif /* NYI */ default: eState = INETMSG_RFC822_JUNK; break; } pData++; break; case INETMSG_RFC822_LETTER_C: eState = INETMSG_RFC822_CHECK; eOkState = INETMSG_RFC822_OK; switch (ascii_toLowerCase (*pData)) { case 'c': check = ""; nIdx = INETMSG_RFC822_CC; break; case 'o': check = "mments"; nIdx = INETMSG_RFC822_COMMENTS; break; default: eState = INETMSG_RFC822_JUNK; break; } pData++; break; case INETMSG_RFC822_LETTER_S: eState = INETMSG_RFC822_CHECK; eOkState = INETMSG_RFC822_OK; switch (ascii_toLowerCase (*pData)) { case 'e': check = "nder"; nIdx = INETMSG_RFC822_SENDER; break; case 'u': check = "bject"; nIdx = INETMSG_RFC822_SUBJECT; break; default: eState = INETMSG_RFC822_JUNK; break; } pData++; break; case INETMSG_RFC822_CHECK: if (*check) { while (*pData && *check && (ascii_toLowerCase (*pData) == *check)) { pData++; check++; } } else { check = pData; } eState = (*check == '\0') ? eOkState : INETMSG_RFC822_JUNK; break; case INETMSG_RFC822_OK: pData = pStop; SetHeaderField_Impl ( HEADERFIELD (HDR(nIdx), rHeader.GetValue()), m_nIndex[nIdx]); nNewIndex = m_nIndex[nIdx]; break; default: // INETMSG_RFC822_JUNK pData = pStop; nNewIndex = INetMessage::SetHeaderField (rHeader, nNewIndex); break; } } return nNewIndex; } /* * Specific Set-Methods. */ void INetRFC822Message::SetBCC (const UniString& rBCC) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_ADDRESS, HDR(INETMSG_RFC822_BCC), rBCC, m_nIndex[INETMSG_RFC822_BCC]); } void INetRFC822Message::SetCC (const UniString& rCC) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_ADDRESS, HDR(INETMSG_RFC822_CC), rCC, m_nIndex[INETMSG_RFC822_CC]); } void INetRFC822Message::SetComments (const UniString& rComments) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, HDR(INETMSG_RFC822_COMMENTS), rComments, m_nIndex[INETMSG_RFC822_COMMENTS]); } void INetRFC822Message::SetDate (const UniString& rDate) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_STRUCTURED, HDR(INETMSG_RFC822_DATE), rDate, m_nIndex[INETMSG_RFC822_DATE]); } void INetRFC822Message::SetFrom (const UniString& rFrom) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_ADDRESS, HDR(INETMSG_RFC822_FROM), rFrom, m_nIndex[INETMSG_RFC822_FROM]); } void INetRFC822Message::SetInReplyTo (const UniString& rInReplyTo) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_ADDRESS, // ??? MESSAGE_ID ??? HDR(INETMSG_RFC822_IN_REPLY_TO), rInReplyTo, m_nIndex[INETMSG_RFC822_IN_REPLY_TO]); } void INetRFC822Message::SetKeywords (const UniString& rKeywords) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_PHRASE, HDR(INETMSG_RFC822_KEYWORDS), rKeywords, m_nIndex[INETMSG_RFC822_KEYWORDS]); } void INetRFC822Message::SetMessageID (const UniString& rMessageID) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_MESSAGE_ID, HDR(INETMSG_RFC822_MESSAGE_ID), rMessageID, m_nIndex[INETMSG_RFC822_MESSAGE_ID]); } void INetRFC822Message::SetReferences (const UniString& rReferences) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_MESSAGE_ID, HDR(INETMSG_RFC822_REFERENCES), rReferences, m_nIndex[INETMSG_RFC822_REFERENCES]); } void INetRFC822Message::SetReplyTo (const UniString& rReplyTo) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_ADDRESS, HDR(INETMSG_RFC822_REPLY_TO), rReplyTo, m_nIndex[INETMSG_RFC822_REPLY_TO]); } void INetRFC822Message::SetReturnPath (const UniString& rReturnPath) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_ADDRESS, HDR(INETMSG_RFC822_RETURN_PATH), rReturnPath, m_nIndex[INETMSG_RFC822_RETURN_PATH]); } void INetRFC822Message::SetReturnReceiptTo (const UniString& rValue) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_ADDRESS, HDR(INETMSG_RFC822_RETURN_RECEIPT_TO), rValue, m_nIndex[INETMSG_RFC822_RETURN_RECEIPT_TO]); } void INetRFC822Message::SetSender (const UniString& rSender) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_ADDRESS, HDR(INETMSG_RFC822_SENDER), rSender, m_nIndex[INETMSG_RFC822_SENDER]); } void INetRFC822Message::SetSubject (const UniString& rSubject) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, HDR(INETMSG_RFC822_SUBJECT), rSubject, m_nIndex[INETMSG_RFC822_SUBJECT]); } void INetRFC822Message::SetTo (const UniString& rTo) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_ADDRESS, HDR(INETMSG_RFC822_TO), rTo, m_nIndex[INETMSG_RFC822_TO]); } void INetRFC822Message::SetXMailer (const UniString& rXMailer) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, HDR(INETMSG_RFC822_X_MAILER), rXMailer, m_nIndex[INETMSG_RFC822_X_MAILER]); } /* * operator<< */ SvStream& INetRFC822Message::operator<< (SvStream& rStrm) const { INetMessage::operator<< (rStrm); for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++) rStrm << static_cast(m_nIndex[i]); return rStrm; } /* * operator>> */ SvStream& INetRFC822Message::operator>> (SvStream& rStrm) { INetMessage::operator>> (rStrm); sal_uInt32 nTemp; for (sal_uInt16 i = 0; i < INETMSG_RFC822_NUMHDR; i++) { rStrm >> nTemp; m_nIndex[i] = nTemp; } return rStrm; } /*======================================================================= * * INetMIMEMessage Implementation. * *=====================================================================*/ /* * _ImplINetMIMEMessageHeaderData. */ namespace { struct ImplINetMIMEMessageHeaderDataImpl { const ByteString* operator()() { static const ByteString _ImplINetMIMEMessageHeaderData[] = { ByteString ("MIME-Version"), ByteString ("Content-Description"), ByteString ("Content-Disposition"), ByteString ("Content-ID"), ByteString ("Content-Type"), ByteString ("Content-Transfer-Encoding") }; return &_ImplINetMIMEMessageHeaderData[0]; } }; struct ImplINetMIMEMessageHeaderData : public rtl::StaticAggregate< const ByteString, ImplINetMIMEMessageHeaderDataImpl > {}; } #define MIMEHDR(n) ImplINetMIMEMessageHeaderData::get()[(n)] /* * _ImplINetMIMEMessageHeaderState. */ enum _ImplINetMIMEMessageHeaderState { INETMSG_MIME_BEGIN, INETMSG_MIME_CHECK, INETMSG_MIME_OK, INETMSG_MIME_JUNK, INETMSG_MIME_TOKEN_CONTENT, INETMSG_MIME_TOKEN_CONTENT_D, INETMSG_MIME_TOKEN_CONTENT_T }; /* * INetMIMEMessage. */ INetMIMEMessage::INetMIMEMessage (void) : INetRFC822Message (), pParent (NULL), nNumChildren (0), bHeaderParsed (sal_False) { for (sal_uInt16 i = 0; i < INETMSG_MIME_NUMHDR; i++) m_nIndex[i] = LIST_ENTRY_NOTFOUND; } INetMIMEMessage::INetMIMEMessage (const INetMIMEMessage& rMsg) : INetRFC822Message (rMsg) { // Copy. CopyImp (rMsg); } /* * operator= */ INetMIMEMessage& INetMIMEMessage::operator= ( const INetMIMEMessage& rMsg) { if (this != &rMsg) { // Assign base. INetRFC822Message::operator= (rMsg); // Cleanup. CleanupImp(); // Copy. CopyImp (rMsg); } return *this; } /* * ~INetMIMEMessage. */ INetMIMEMessage::~INetMIMEMessage (void) { // Cleanup. CleanupImp(); } /* * CleanupImp. */ void INetMIMEMessage::CleanupImp (void) { INetMIMEMessage *pChild = NULL; while ((pChild = (INetMIMEMessage *)(aChildren.Remove())) != NULL) if (pChild->pParent == this) delete pChild; } /* * CopyImp. */ void INetMIMEMessage::CopyImp (const INetMIMEMessage& rMsg) { bHeaderParsed = rMsg.bHeaderParsed; sal_uInt16 i; for (i = 0; i < INETMSG_MIME_NUMHDR; i++) m_nIndex[i] = rMsg.m_nIndex[i]; m_aBoundary = rMsg.m_aBoundary; nNumChildren = rMsg.nNumChildren; for (i = 0; i < rMsg.aChildren.Count(); i++) { INetMIMEMessage *pChild = (INetMIMEMessage *)(rMsg.aChildren.GetObject (i)); if (pChild->pParent == &rMsg) { pChild = pChild->CreateMessage (*pChild); pChild->pParent = this; } aChildren.Insert (pChild, LIST_APPEND); } } /* * CreateMessage. */ INetMIMEMessage *INetMIMEMessage::CreateMessage ( const INetMIMEMessage& rMsg) const { return (new INetMIMEMessage (rMsg)); } /* * SetHeaderField. * (Header Field Parser). */ sal_uIntPtr INetMIMEMessage::SetHeaderField ( const INetMessageHeader &rHeader, sal_uIntPtr nNewIndex) { ByteString aName (rHeader.GetName()); const sal_Char *pData = aName.GetBuffer(); const sal_Char *pStop = pData + aName.Len() + 1; const sal_Char *check = ""; sal_uIntPtr nIdx = LIST_APPEND; int eState = INETMSG_MIME_BEGIN; int eOkState = INETMSG_MIME_OK; while (pData < pStop) { switch (eState) { case INETMSG_MIME_BEGIN: eState = INETMSG_MIME_CHECK; eOkState = INETMSG_MIME_OK; switch (ascii_toLowerCase (*pData)) { case 'c': check = "ontent-"; eOkState = INETMSG_MIME_TOKEN_CONTENT; break; case 'm': check = "ime-version"; nIdx = INETMSG_MIME_VERSION; break; default: eState = INETMSG_MIME_JUNK; break; } pData++; break; case INETMSG_MIME_TOKEN_CONTENT: eState = INETMSG_MIME_CHECK; eOkState = INETMSG_MIME_OK; switch (ascii_toLowerCase (*pData)) { case 'd': eState = INETMSG_MIME_TOKEN_CONTENT_D; break; case 'i': check = "d"; nIdx = INETMSG_MIME_CONTENT_ID; break; case 't': eState = INETMSG_MIME_TOKEN_CONTENT_T; break; default: eState = INETMSG_MIME_JUNK; break; } pData++; break; case INETMSG_MIME_TOKEN_CONTENT_D: eState = INETMSG_MIME_CHECK; eOkState = INETMSG_MIME_OK; switch (ascii_toLowerCase (*pData)) { case 'e': check = "scription"; nIdx = INETMSG_MIME_CONTENT_DESCRIPTION; break; case 'i': check = "sposition"; nIdx = INETMSG_MIME_CONTENT_DISPOSITION; break; default: eState = INETMSG_MIME_JUNK; break; } pData++; break; case INETMSG_MIME_TOKEN_CONTENT_T: eState = INETMSG_MIME_CHECK; eOkState = INETMSG_MIME_OK; switch (ascii_toLowerCase (*pData)) { case 'r': check = "ansfer-encoding"; nIdx = INETMSG_MIME_CONTENT_TRANSFER_ENCODING; break; case 'y': check = "pe"; nIdx = INETMSG_MIME_CONTENT_TYPE; break; default: eState = INETMSG_MIME_JUNK; break; } pData++; break; case INETMSG_MIME_CHECK: if (*check) { while (*pData && *check && (ascii_toLowerCase (*pData) == *check)) { pData++; check++; } } else { check = pData; } eState = (*check == '\0') ? eOkState : INETMSG_MIME_JUNK; break; case INETMSG_MIME_OK: pData = pStop; SetHeaderField_Impl ( HEADERFIELD (MIMEHDR(nIdx), rHeader.GetValue()), m_nIndex[nIdx]); nNewIndex = m_nIndex[nIdx]; break; default: // INETMSG_MIME_JUNK pData = pStop; nNewIndex = INetRFC822Message::SetHeaderField ( rHeader, nNewIndex); break; } } return nNewIndex; } /* * Specific Set-Methods. */ void INetMIMEMessage::SetMIMEVersion (const UniString& rVersion) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, MIMEHDR(INETMSG_MIME_VERSION), rVersion, m_nIndex[INETMSG_MIME_VERSION]); } void INetMIMEMessage::SetContentDescription (const String& rDescription) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, MIMEHDR(INETMSG_MIME_CONTENT_DESCRIPTION), rDescription, m_nIndex[INETMSG_MIME_CONTENT_DESCRIPTION]); } void INetMIMEMessage::SetContentDisposition (const String& rDisposition) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, MIMEHDR(INETMSG_MIME_CONTENT_DISPOSITION), rDisposition, m_nIndex[INETMSG_MIME_CONTENT_DISPOSITION]); } void INetMIMEMessage::SetContentID (const String& rID) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, MIMEHDR(INETMSG_MIME_CONTENT_ID), rID, m_nIndex[INETMSG_MIME_CONTENT_ID]); } void INetMIMEMessage::SetContentType (const String& rType) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, MIMEHDR(INETMSG_MIME_CONTENT_TYPE), rType, m_nIndex[INETMSG_MIME_CONTENT_TYPE]); } void INetMIMEMessage::SetContentTransferEncoding ( const String& rEncoding) { SetHeaderField_Impl ( INetMIME::HEADER_FIELD_TEXT, MIMEHDR(INETMSG_MIME_CONTENT_TRANSFER_ENCODING), rEncoding, m_nIndex[INETMSG_MIME_CONTENT_TRANSFER_ENCODING]); } /* * GetDefaultContentType. */ void INetMIMEMessage::GetDefaultContentType (String& rContentType) { String aDefaultCT ( "text/plain; charset=us-ascii", RTL_TEXTENCODING_ASCII_US); if (pParent == NULL) { rContentType = aDefaultCT; } else { String aParentCT (pParent->GetContentType()); if (aParentCT.Len() == 0) pParent->GetDefaultContentType (aParentCT); if (aParentCT.CompareIgnoreCaseToAscii ("message/", 8) == 0) { rContentType = aDefaultCT; } else if (aParentCT.CompareIgnoreCaseToAscii ("multipart/", 10) == 0) { if (aParentCT.CompareIgnoreCaseToAscii ("multipart/digest") == 0) rContentType.AssignAscii ("message/rfc822"); else rContentType = aDefaultCT; } else { rContentType = aDefaultCT; } } } /* * EnableAttachChild. */ sal_Bool INetMIMEMessage::EnableAttachChild (INetMessageContainerType eType) { // Check context. if (IsContainer()) return sal_False; // Setup Content-Type header field. ByteString aContentType; switch (eType) { case INETMSG_MESSAGE_RFC822: aContentType = "message/rfc822"; break; case INETMSG_MULTIPART_ALTERNATIVE: aContentType = "multipart/alternative"; break; case INETMSG_MULTIPART_DIGEST: aContentType = "multipart/digest"; break; case INETMSG_MULTIPART_PARALLEL: aContentType = "multipart/parallel"; break; case INETMSG_MULTIPART_RELATED: aContentType = "multipart/related"; break; case INETMSG_MULTIPART_FORM_DATA: aContentType = "multipart/form-data"; break; default: aContentType = "multipart/mixed"; break; } // Setup boundary for multipart types. if (aContentType.CompareIgnoreCaseToAscii ("multipart/", 10) == 0) { // Generate a unique boundary from current time. sal_Char sTail[16 + 1]; Time aCurTime; sal_uInt64 nThis = reinterpret_cast< sal_uIntPtr >( this ); // we can be on a 64bit architecture nThis = ( ( nThis >> 32 ) ^ nThis ) & SAL_MAX_UINT32; sprintf (sTail, "%08X%08X", static_cast< unsigned int >(aCurTime.GetTime()), static_cast< unsigned int >(nThis)); m_aBoundary = "------------_4D48"; m_aBoundary += sTail; // Append boundary as ContentType parameter. aContentType += "; boundary="; aContentType += m_aBoundary; } // Set header fields. SetMIMEVersion (String (CONSTASCII_STRINGPARAM("1.0"))); SetContentType (String (aContentType, RTL_TEXTENCODING_ASCII_US)); SetContentTransferEncoding (String (CONSTASCII_STRINGPARAM("7bit"))); // Done. return sal_True; } /* * AttachChild. */ sal_Bool INetMIMEMessage::AttachChild ( INetMIMEMessage& rChildMsg, sal_Bool bOwner) { if (IsContainer() /*&& rChildMsg.GetContentType().Len() */) { if (bOwner) rChildMsg.pParent = this; aChildren.Insert (&rChildMsg, LIST_APPEND); nNumChildren = aChildren.Count(); return sal_True; } return sal_False; } /* * DetachChild. */ sal_Bool INetMIMEMessage::DetachChild ( sal_uIntPtr nIndex, INetMIMEMessage& rChildMsg) const { if (IsContainer()) { // Check document stream. if (GetDocumentLB() == NULL) return sal_False; SvStream *pDocStrm = new SvStream (GetDocumentLB()); // Initialize message buffer. char pMsgBuffer[1024]; char *pMsgRead, *pMsgWrite; pMsgRead = pMsgWrite = pMsgBuffer; // Initialize message parser stream. INetMIMEMessageStream *pMsgStrm = NULL; // Check for "multipart/uvw" or "message/xyz". if (IsMultipart()) { // Multipart message body. Initialize multipart delimiters. ByteString aDelim ("--"); aDelim += GetMultipartBoundary(); ByteString aClose = aDelim; aClose += "--"; // Initialize line buffer. SvMemoryStream aLineBuf; // Initialize control variables. INetMessageStreamState eState = INETMSG_EOL_SCR; int nCurIndex = -1; // Go! while (nCurIndex < (int)(nIndex + 1)) { if ((pMsgRead - pMsgWrite) > 0) { // Bytes still in buffer. if (eState == INETMSG_EOL_FCR) { // Check for 2nd line break character. if ((*pMsgWrite == '\r') || (*pMsgWrite == '\n')) aLineBuf << *pMsgWrite++; // Check current index. if (nCurIndex == (int)nIndex) { // Found requested part. if (pMsgStrm == NULL) { // Create message parser stream. pMsgStrm = new INetMIMEMessageStream; pMsgStrm->SetTargetMessage (&rChildMsg); } // Put message down-stream. int status = pMsgStrm->Write ( (const sal_Char *) aLineBuf.GetData(), aLineBuf.Tell()); if (status != INETSTREAM_STATUS_OK) { // Cleanup. delete pDocStrm; delete pMsgStrm; // Finish. return (!(status == INETSTREAM_STATUS_OK)); } } // Reset to . aLineBuf.Seek (STREAM_SEEK_TO_BEGIN); eState = INETMSG_EOL_SCR; } else if ((*pMsgWrite == '\r') || (*pMsgWrite == '\n')) { /* * Found any line break character. * Compare buffered line with part/close delimiter. * Increment current part index upon match. */ sal_uInt16 nLen = (sal_uInt16)(aLineBuf.Tell() & 0xffff); if (nLen == aDelim.Len()) { if (aDelim.CompareTo ((const sal_Char *) aLineBuf.GetData(), nLen) == COMPARE_EQUAL) nCurIndex++; } else if (nLen == aClose.Len()) { if (aClose.CompareTo ((const sal_Char *) aLineBuf.GetData(), nLen) == COMPARE_EQUAL) nCurIndex++; } aLineBuf << *pMsgWrite++; eState = INETMSG_EOL_FCR; } else { // Insert into line buffer. aLineBuf << *pMsgWrite; } } else { // Buffer empty. Reset to . pMsgRead = pMsgWrite = pMsgBuffer; // Read document stream. sal_uIntPtr nRead = pDocStrm->Read ( pMsgBuffer, sizeof (pMsgBuffer)); if (nRead > 0) { // Set read pointer. pMsgRead += nRead; } else { // Premature end. if (pMsgStrm) { // Assume end of requested part. nCurIndex++; } else { // Requested part not found. delete pDocStrm; return sal_False; } } } } // while (nCurIndex < (nIndex + 1)) } else { // Encapsulated message body. Create message parser stream. pMsgStrm = new INetMIMEMessageStream; pMsgStrm->SetTargetMessage (&rChildMsg); // Initialize control variables. INetMessageStreamState eState = INETMSG_EOL_BEGIN; // Go. while (eState == INETMSG_EOL_BEGIN) { if ((pMsgRead - pMsgWrite) > 0) { // Bytes still in buffer. Put message down-stream. int status = pMsgStrm->Write ( pMsgBuffer, (pMsgRead - pMsgWrite)); if (status != INETSTREAM_STATUS_OK) { // Cleanup. delete pDocStrm; delete pMsgStrm; // Finish. return (!(status == INETSTREAM_STATUS_ERROR)); } pMsgWrite = pMsgBuffer + (pMsgRead - pMsgWrite); } else { // Buffer empty. Reset to . pMsgRead = pMsgWrite = pMsgBuffer; // Read document stream. sal_uIntPtr nRead = pDocStrm->Read ( pMsgBuffer, sizeof (pMsgBuffer)); if (nRead > 0) { // Set read pointer. pMsgRead += nRead; } else { // Mark we're done. eState = INETMSG_EOL_DONE; } } } // while (eState == INETMSG_EOL_BEGIN) } // Done. if (pDocStrm) delete pDocStrm; if (pMsgStrm) delete pMsgStrm; return sal_True; } return sal_False; } /* * operator<< */ SvStream& INetMIMEMessage::operator<< (SvStream& rStrm) const { INetRFC822Message::operator<< (rStrm); for (sal_uInt16 i = 0; i < INETMSG_MIME_NUMHDR; i++) rStrm << static_cast(m_nIndex[i]); #ifdef ENABLE_BYTESTRING_STREAM_OPERATORS rStrm << m_aBoundary; #else rStrm.WriteByteString (m_aBoundary); #endif rStrm << static_cast(nNumChildren); return rStrm; } /* * operator>> */ SvStream& INetMIMEMessage::operator>> (SvStream& rStrm) { INetRFC822Message::operator>> (rStrm); sal_uInt32 nTemp; for (sal_uInt16 i = 0; i < INETMSG_MIME_NUMHDR; i++) { rStrm >> nTemp; m_nIndex[i] = nTemp; } #ifdef ENABLE_BYTESTRING_STREAM_OPERATORS rStrm >> m_aBoundary; #else rStrm.ReadByteString (m_aBoundary); #endif rStrm >> nTemp; nNumChildren = nTemp; return rStrm; }