Page MenuHome GnuPG

ewsrequest.cpp
No OneTemporary

ewsrequest.cpp

/*
SPDX-FileCopyrightText: 2015-2019 Krzysztof Nowicki <krissn@op.pl>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "ewsrequest.h"
#include <QNetworkReply>
#include <QTemporaryFile>
#include <QUuid>
#include "ewsclient_debug.h"
#include "websocketclient.h"
using namespace Qt::StringLiterals;
EwsRequest::EwsRequest(const EwsClient &client, QObject *parent)
: EwsJob(parent)
, mClient(client)
, mServerVersion(EwsServerVersion::ewsVersion2007Sp1)
{
}
EwsRequest::~EwsRequest() = default;
void EwsRequest::doSend()
{
if (mClient.token.isEmpty()) {
auto &client = WebsocketClient::self();
client.sendEWSRequest(mClient.email, mRequestId, mBody);
connect(&client, &WebsocketClient::ewsResponseReceived, this, [this](const QString &requestId, const QString &responseBody) {
if (requestId == mRequestId) {
requestResult(responseBody);
}
});
} else {
QNetworkRequest request(QUrl(u"https://outlook.office365.com/EWS/Exchange.asmx"_s));
request.setRawHeader("Authorization", "Bearer " + mClient.token);
request.setHeader(QNetworkRequest::ContentTypeHeader, u"text/xml"_s);
auto reply = mClient.qnam->post(request, mBody.toUtf8());
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
reply->deleteLater();
const auto body = reply->readAll();
if (body.isEmpty()) {
qWarning() << metaObject()->className() << reply->error() << reply->errorString() << reply->readAll() << reply->rawHeaderPairs();
setErrorMsg(reply->errorString());
emitResult();
return;
}
requestResult(QString::fromUtf8(body));
});
}
}
void EwsRequest::startSoapDocument(QXmlStreamWriter &writer)
{
writer.writeStartDocument();
writer.writeNamespace(soapEnvNsUri, QStringLiteral("soap"));
writer.writeNamespace(ewsMsgNsUri, QStringLiteral("m"));
writer.writeNamespace(ewsTypeNsUri, QStringLiteral("t"));
// SOAP Envelope
writer.writeStartElement(soapEnvNsUri, QStringLiteral("Envelope"));
// SOAP Header
writer.writeStartElement(soapEnvNsUri, QStringLiteral("Header"));
mServerVersion.writeRequestServerVersion(writer);
writer.writeEndElement();
// SOAP Body
writer.writeStartElement(soapEnvNsUri, QStringLiteral("Body"));
}
void EwsRequest::endSoapDocument(QXmlStreamWriter &writer)
{
// End SOAP Body
writer.writeEndElement();
// End SOAP Envelope
writer.writeEndElement();
writer.writeEndDocument();
}
void EwsRequest::prepare(const QString &body)
{
mBody = body;
mRequestId = QUuid::createUuid().toString(QUuid::WithoutBraces);
}
void EwsRequest::start()
{
}
void EwsRequest::requestResult(const QString &responseBody)
{
mResponseData = responseBody.toUtf8();
QXmlStreamReader reader(mResponseData);
readResponse(reader);
emitResult();
}
bool EwsRequest::readResponse(QXmlStreamReader &reader)
{
if (!reader.readNextStartElement()) {
return setErrorMsg(QStringLiteral("Failed to read EWS request XML"));
}
if ((reader.name() != QLatin1StringView("Envelope")) || (reader.namespaceUri() != soapEnvNsUri)) {
return setErrorMsg(QStringLiteral("Failed to read EWS request - not a SOAP XML"));
}
while (reader.readNextStartElement()) {
if (reader.namespaceUri() != soapEnvNsUri) {
return setErrorMsg(QStringLiteral("Failed to read EWS request - not a SOAP XML"));
}
if (reader.name() == QLatin1StringView("Body")) {
if (!readSoapBody(reader)) {
return false;
}
} else if (reader.name() == QLatin1StringView("Header")) {
if (!readHeader(reader)) {
return false;
}
}
}
return true;
}
bool EwsRequest::readSoapBody(QXmlStreamReader &reader)
{
while (reader.readNextStartElement()) {
if ((reader.name() == QLatin1StringView("Fault")) && (reader.namespaceUri() == soapEnvNsUri)) {
return readSoapFault(reader);
}
if (!parseResult(reader)) {
return false;
}
}
return true;
}
QPair<QStringView, QString> EwsRequest::parseNamespacedString(const QString &str, const QXmlStreamNamespaceDeclarations &namespaces)
{
const auto tokens = str.split(QLatin1Char(':'));
switch (tokens.count()) {
case 1:
return {QStringView(), str};
case 2:
for (const auto &ns : namespaces) {
if (ns.prefix() == tokens[0]) {
return {ns.namespaceUri(), tokens[1]};
}
}
/* fall through */
default:
return {};
}
}
EwsResponseCode EwsRequest::parseEwsResponseCode(const QPair<QStringView, QString> &code)
{
if (code.first == ewsTypeNsUri) {
return decodeEwsResponseCode(code.second);
} else {
return EwsResponseCodeUnknown;
}
}
bool EwsRequest::readSoapFault(QXmlStreamReader &reader)
{
QString faultCode;
QString faultString;
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1StringView("faultcode")) {
const auto rawCode = reader.readElementText();
const auto parsedCode = parseEwsResponseCode(parseNamespacedString(rawCode, reader.namespaceDeclarations()));
if (parsedCode != EwsResponseCodeUnknown) {
setEwsResponseCode(parsedCode);
}
faultCode = rawCode;
} else if (reader.name() == QLatin1StringView("faultstring")) {
faultString = reader.readElementText();
}
}
qCWarning(EWSCLI_LOG) << "readSoapFault" << faultCode << metaObject()->className();
setErrorMsg(faultCode + QStringLiteral(": ") + faultString);
return false;
}
bool EwsRequest::parseResponseMessage(QXmlStreamReader &reader, const QString &reqName, ContentReaderFn contentReader)
{
if (reader.name().toString() != reqName + QStringLiteral("Response") || reader.namespaceUri() != ewsMsgNsUri) {
return setErrorMsg(QStringLiteral("Failed to read EWS request - expected %1 element.").arg(reqName + QStringLiteral("Response")));
}
if (!reader.readNextStartElement()) {
return setErrorMsg(QStringLiteral("Failed to read EWS request - expected a child element in %1 element.").arg(reqName + QStringLiteral("Response")));
}
if (reader.name().toString() != QLatin1StringView("ResponseMessages") || reader.namespaceUri() != ewsMsgNsUri) {
return setErrorMsg(QStringLiteral("Failed to read EWS request - expected %1 element.").arg(QStringLiteral("ResponseMessages")));
}
while (reader.readNextStartElement()) {
if (reader.name().toString() != reqName + QStringLiteral("ResponseMessage") || reader.namespaceUri() != ewsMsgNsUri) {
return setErrorMsg(QStringLiteral("Failed to read EWS request - expected %1 element.").arg(reqName + QStringLiteral("ResponseMessage")));
}
if (!contentReader(reader)) {
return false;
}
}
return true;
}
void EwsRequest::setServerVersion(const EwsServerVersion &version)
{
mServerVersion = version;
}
EwsRequest::Response::Response(QXmlStreamReader &reader)
{
static constexpr auto respClasses = std::to_array({
QLatin1StringView("Success"),
QLatin1StringView("Warning"),
QLatin1StringView("Error"),
});
auto respClassRef = reader.attributes().value(QStringLiteral("ResponseClass"));
if (respClassRef.isNull()) {
mClass = EwsResponseParseError;
qCWarning(EWSCLI_LOG) << "ResponseClass attribute not found in response element";
return;
}
unsigned i = 0;
for (const auto &respClass : respClasses) {
if (respClass == respClassRef) {
mClass = static_cast<EwsResponseClass>(i);
break;
}
i++;
}
}
bool EwsRequest::Response::readResponseElement(QXmlStreamReader &reader)
{
if (reader.namespaceUri() != ewsMsgNsUri) {
return false;
}
if (reader.name() == QLatin1StringView("ResponseCode")) {
mCode = reader.readElementText();
} else if (reader.name() == QLatin1StringView("MessageText")) {
mMessage = reader.readElementText();
} else if (reader.name() == QLatin1StringView("DescriptiveLinkKey")) {
reader.skipCurrentElement();
} else if (reader.name() == QLatin1StringView("MessageXml")) {
reader.skipCurrentElement();
} else if (reader.name() == QLatin1StringView("ErrorSubscriptionIds")) {
reader.skipCurrentElement();
} else {
return false;
}
return true;
}
bool EwsRequest::readHeader(QXmlStreamReader &reader)
{
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1StringView("ServerVersionInfo") && reader.namespaceUri() == ewsTypeNsUri) {
EwsServerVersion version(reader);
if (!version.isValid()) {
qCWarningNC(EWSCLI_LOG) << QStringLiteral("Failed to read EWS request - error parsing server version.");
return false;
}
mServerVersion = version;
reader.skipCurrentElement();
} else {
reader.skipCurrentElement();
}
}
return true;
}
bool EwsRequest::Response::setErrorMsg(const QString &msg)
{
mClass = EwsResponseParseError;
mCode = QStringLiteral("ResponseParseError");
mMessage = msg;
qCWarningNC(EWSCLI_LOG) << msg;
return false;
}
void EwsRequest::dump() const
{
ewsLogDir.setAutoRemove(false);
if (ewsLogDir.isValid()) {
QTemporaryFile reqDumpFile(ewsLogDir.path() + QStringLiteral("/ews_xmlreqdump_XXXXXXX.xml"));
reqDumpFile.open();
reqDumpFile.setAutoRemove(false);
reqDumpFile.write(mBody.toUtf8());
reqDumpFile.close();
QTemporaryFile resDumpFile(ewsLogDir.path() + QStringLiteral("/ews_xmlresdump_XXXXXXX.xml"));
resDumpFile.open();
resDumpFile.setAutoRemove(false);
resDumpFile.write(mResponseData);
resDumpFile.close();
qCDebug(EWSCLI_LOG) << "request dumped to" << reqDumpFile.fileName();
qCDebug(EWSCLI_LOG) << "response dumped to" << resDumpFile.fileName();
} else {
qCWarning(EWSCLI_LOG) << "failed to dump request and response";
}
}
#include "moc_ewsrequest.cpp"

File Metadata

Mime Type
text/x-c
Expires
Fri, Dec 19, 2:10 PM (22 h, 15 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
78/e1/4be2b9ac4ba750b0a3c048087bf5

Event Timeline