blob: e53e5760f478899a30abba92fe0feabf8e6905da [file] [log] [blame]
/**************************************************************
*
* 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 <sal/types.h>
#include <tools/datetime.hxx>
#ifndef _TOOLS_INETMIME_HXX
#include <tools/inetmime.hxx>
#endif
#include <tools/inetmsg.hxx>
#include <tools/inetstrm.hxx>
#include <rtl/instance.hxx>
#include <stdio.h>
//=======================================================================
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<sal_uInt32>(m_nDocSize);
rStrm.WriteByteString (m_aDocName, RTL_TEXTENCODING_UTF8);
sal_uIntPtr i, n = m_aHeaderList.Count();
rStrm << static_cast<sal_uInt32>(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)
{
}
/*
* <Generate|Parse>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 <Wkd> or <Weekday>, 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<sal_uInt32>(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 <Begin-of-Line>.
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 <Begin-of-Buffer>.
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 <Begin-of-Buffer>.
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<sal_uInt32>(m_nIndex[i]);
#ifdef ENABLE_BYTESTRING_STREAM_OPERATORS
rStrm << m_aBoundary;
#else
rStrm.WriteByteString (m_aBoundary);
#endif
rStrm << static_cast<sal_uInt32>(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;
}