diff options
Diffstat (limited to 'tools/source/inet/inetmsg.cxx')
-rw-r--r-- | tools/source/inet/inetmsg.cxx | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/tools/source/inet/inetmsg.cxx b/tools/source/inet/inetmsg.cxx new file mode 100644 index 000000000..b2e7f70b4 --- /dev/null +++ b/tools/source/inet/inetmsg.cxx @@ -0,0 +1,292 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +#include <sal/types.h> +#include <tools/datetime.hxx> +#include <tools/inetmsg.hxx> +#include <comphelper/string.hxx> +#include <rtl/character.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/sprintf.hxx> +#include <o3tl/string_view.hxx> + +#include <map> + +void INetMIMEMessage::SetHeaderField_Impl ( + const OString &rName, + const OUString &rValue, + sal_uInt32 &rnIndex) +{ + SetHeaderField_Impl ( + INetMessageHeader (rName, rValue.toUtf8()), rnIndex); +} + +/* ParseDateField and local helper functions. + * + * Parses a String in (implied) GMT format into class Date and tools::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) + */ + +static const char *months[12] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static sal_uInt16 ParseNumber(std::string_view rStr, size_t& nIndex) +{ + size_t n = nIndex; + while ((n < rStr.size()) + && rtl::isAsciiDigit(static_cast<unsigned char>(rStr[n]))) + n++; + + std::string_view aNum(rStr.substr(nIndex, (n - nIndex))); + nIndex = n; + + return static_cast<sal_uInt16>(o3tl::toInt32(aNum)); +} + +static sal_uInt16 ParseMonth(std::string_view rStr, size_t& nIndex) +{ + size_t n = nIndex; + while ((n < rStr.size()) + && rtl::isAsciiAlpha(static_cast<unsigned char>(rStr[n]))) + n++; + + std::string_view aMonth(rStr.substr(nIndex, 3)); + nIndex = n; + + sal_uInt16 i; + for (i = 0; i < 12; i++) + if (o3tl::equalsIgnoreAsciiCase(aMonth, months[i])) break; + return (i + 1); +} + +bool INetMIMEMessage::ParseDateField ( + std::u16string_view rDateFieldW, DateTime& rDateTime) +{ + OString aDateField(OUStringToOString(rDateFieldW, + RTL_TEXTENCODING_ASCII_US)); + + if (aDateField.isEmpty()) return false; + + if (aDateField.indexOf(':') != -1) + { + // Some DateTime format. + size_t nIndex = 0; + + // Skip over <Wkd> or <Weekday>, leading and trailing space. + while ((nIndex < o3tl::make_unsigned(aDateField.getLength())) && + (aDateField[nIndex] == ' ')) + nIndex++; + + while ( + (nIndex < o3tl::make_unsigned(aDateField.getLength())) && + (rtl::isAsciiAlpha (static_cast<unsigned char>(aDateField[nIndex])) || + (aDateField[nIndex] == ',') )) + nIndex++; + + while ((nIndex < o3tl::make_unsigned(aDateField.getLength())) && + (aDateField[nIndex] == ' ')) + nIndex++; + + if (rtl::isAsciiAlpha (static_cast<unsigned char>(aDateField[nIndex]))) + { + // Format: ctime(). + if ((aDateField.getLength() - nIndex) < 20) return false; + + rDateTime.SetMonth (ParseMonth (aDateField, nIndex)); nIndex++; + rDateTime.SetDay (ParseNumber (aDateField, nIndex)); nIndex++; + + rDateTime.SetHour (ParseNumber (aDateField, nIndex)); nIndex++; + rDateTime.SetMin (ParseNumber (aDateField, nIndex)); nIndex++; + rDateTime.SetSec (ParseNumber (aDateField, nIndex)); nIndex++; + rDateTime.SetNanoSec (0); + + sal_uInt16 nYear = ParseNumber (aDateField, nIndex); + if (nYear < 100) nYear += 1900; + rDateTime.SetYear (nYear); + } + else + { + // Format: RFC1036 or RFC1123. + if ((aDateField.getLength() - nIndex) < 17) return false; + + rDateTime.SetDay (ParseNumber (aDateField, nIndex)); nIndex++; + rDateTime.SetMonth (ParseMonth (aDateField, nIndex)); nIndex++; + + sal_uInt16 nYear = ParseNumber (aDateField, nIndex); nIndex++; + if (nYear < 100) nYear += 1900; + rDateTime.SetYear (nYear); + + rDateTime.SetHour (ParseNumber (aDateField, nIndex)); nIndex++; + rDateTime.SetMin (ParseNumber (aDateField, nIndex)); nIndex++; + rDateTime.SetSec (ParseNumber (aDateField, nIndex)); nIndex++; + rDateTime.SetNanoSec (0); + + const char cPossiblePlusMinus = nIndex < o3tl::make_unsigned(aDateField.getLength()) ? aDateField[nIndex] : 0; + if (cPossiblePlusMinus == '+' || cPossiblePlusMinus == '-') + { + // Offset from GMT: "(+|-)HHMM". + bool bEast = (aDateField[nIndex++] == '+'); + sal_uInt16 nOffset = ParseNumber (aDateField, nIndex); + if (nOffset > 0) + { + tools::Time aDiff( tools::Time::EMPTY ); + aDiff.SetHour (nOffset / 100); + aDiff.SetMin (nOffset % 100); + aDiff.SetSec (0); + aDiff.SetNanoSec (0); + + if (bEast) + rDateTime -= aDiff; + else + rDateTime += aDiff; + } + } + } + } + else if (comphelper::string::isdigitAsciiString(aDateField)) + { + // Format: delta seconds. + tools::Time aDelta (0); + aDelta.SetTime (aDateField.toInt32() * 100); + + DateTime aNow( DateTime::SYSTEM ); + aNow += aDelta; + aNow.ConvertToUTC(); + + rDateTime.SetDate (aNow.GetDate()); + rDateTime.SetTime (aNow.GetTime()); + } + else + { + // Junk. + return false; + } + + return (rDateTime.IsValidAndGregorian() && + !((rDateTime.GetSec() > 59) || + (rDateTime.GetMin() > 59) || + (rDateTime.GetHour() > 23) )); +} + +const std::map<InetMessageMime, const char*> ImplINetMIMEMessageHeaderData = +{ + { InetMessageMime::VERSION, "MIME-Version"}, + { InetMessageMime::CONTENT_DISPOSITION, "Content-Disposition"}, + { InetMessageMime::CONTENT_TYPE, "Content-Type"}, + { InetMessageMime::CONTENT_TRANSFER_ENCODING, "Content-Transfer-Encoding"} +}; + +INetMIMEMessage::INetMIMEMessage() + : pParent(nullptr) +{ + for (sal_uInt16 i = 0; i < static_cast<int>(InetMessageMime::NUMHDR); i++) + m_nMIMEIndex[static_cast<InetMessageMime>(i)] = SAL_MAX_UINT32; +} + +INetMIMEMessage::~INetMIMEMessage() +{ +} + +void INetMIMEMessage::SetMIMEVersion (const OUString& rVersion) +{ + SetHeaderField_Impl ( + ImplINetMIMEMessageHeaderData.at(InetMessageMime::VERSION), rVersion, + m_nMIMEIndex[InetMessageMime::VERSION]); +} + +void INetMIMEMessage::SetContentDisposition (const OUString& rDisposition) +{ + SetHeaderField_Impl ( + ImplINetMIMEMessageHeaderData.at(InetMessageMime::CONTENT_DISPOSITION), rDisposition, + m_nMIMEIndex[InetMessageMime::CONTENT_DISPOSITION]); +} + +void INetMIMEMessage::SetContentType (const OUString& rType) +{ + SetHeaderField_Impl ( + ImplINetMIMEMessageHeaderData.at(InetMessageMime::CONTENT_TYPE), rType, + m_nMIMEIndex[InetMessageMime::CONTENT_TYPE]); +} + +void INetMIMEMessage::SetContentTransferEncoding ( + const OUString& rEncoding) +{ + SetHeaderField_Impl ( + ImplINetMIMEMessageHeaderData.at(InetMessageMime::CONTENT_TRANSFER_ENCODING), rEncoding, + m_nMIMEIndex[InetMessageMime::CONTENT_TRANSFER_ENCODING]); +} + +OUString INetMIMEMessage::GetDefaultContentType() +{ + if (pParent != nullptr) + { + OUString aParentCT (pParent->GetContentType()); + if (aParentCT.isEmpty()) + aParentCT = pParent->GetDefaultContentType(); + + if (aParentCT.equalsIgnoreAsciiCase("multipart/digest")) + return "message/rfc822"; + } + return "text/plain; charset=us-ascii"; +} + +void INetMIMEMessage::EnableAttachMultipartFormDataChild() +{ + // Check context. + if (IsContainer()) + return; + + // Generate a unique boundary from current time. + char sTail[16 + 1]; + tools::Time aCurTime( tools::Time::SYSTEM ); + sal_uInt64 nThis = reinterpret_cast< sal_uIntPtr >( this ); // we can be on a 64bit architecture + nThis = ( ( nThis >> 32 ) ^ nThis ) & SAL_MAX_UINT32; + o3tl::sprintf (sTail, "%08X%08X", + static_cast< unsigned int >(aCurTime.GetTime()), + static_cast< unsigned int >(nThis)); + m_aBoundary = "------------_4D48"; + m_aBoundary += sTail; + + // Set header fields. + SetMIMEVersion("1.0"); + SetContentType( + "multipart/form-data; boundary=" + OUString::fromUtf8(m_aBoundary)); + SetContentTransferEncoding("7bit"); +} + +void INetMIMEMessage::AttachChild(std::unique_ptr<INetMIMEMessage> pChildMsg) +{ + assert(IsContainer()); + if (IsContainer()) + { + pChildMsg->pParent = this; + aChildren.push_back( std::move(pChildMsg) ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |