office-gobmx/tools/source/inet/inetmsg.cxx
Stephan Bergmann 3bc5f0a38a Extended loplugin:ostr: tools
Change-Id: I7a585370b7d2a8021b733984e605cae8cc92c774
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160097
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <stephan.bergmann@allotropia.de>
2023-11-29 16:40:53 +01:00

292 lines
9.5 KiB
C++

/* -*- 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"_ostr;
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: */