diff --git a/resources/ews/ewsclient/ewsoauth.cpp b/resources/ews/ewsclient/ewsoauth.cpp index def9a82cb..2ba9a7ae6 100644 --- a/resources/ews/ewsclient/ewsoauth.cpp +++ b/resources/ews/ewsclient/ewsoauth.cpp @@ -1,282 +1,290 @@ /* Copyright (C) 2018 Krzysztof Nowicki This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ewsoauth.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ewsclient_debug.h" static const auto o365AuthorizationUrl = QUrl(QStringLiteral("https://login.microsoftonline.com/common/oauth2/authorize")); static const auto o365AccessTokenUrl = QUrl(QStringLiteral("https://login.microsoftonline.com/common/oauth2/token")); static const auto o365FakeUserAgent = QStringLiteral("Mozilla/5.0 (Linux; Android 7.0; SM-G930V Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.125 Mobile Safari/537.36"); static const auto o365Resource = QStringLiteral("https%3A%2F%2Foutlook.office365.com%2F"); class EwsOAuthUrlSchemeHandler final : public QWebEngineUrlSchemeHandler { Q_OBJECT public: EwsOAuthUrlSchemeHandler(QObject *parent = Q_NULLPTR) : QWebEngineUrlSchemeHandler(parent) {}; ~EwsOAuthUrlSchemeHandler() override = default; void requestStarted(QWebEngineUrlRequestJob *request) override; signals: void returnUriReceived(QUrl url); }; class EwsOAuthReplyHandler final : public QOAuthOobReplyHandler { Q_OBJECT public: EwsOAuthReplyHandler(QObject *parent, const QString &returnUri) : QOAuthOobReplyHandler(parent), mReturnUri(returnUri) {}; ~EwsOAuthReplyHandler() override = default; QString callback() const override { return mReturnUri; }; private: const QString mReturnUri; }; class EwsOAuthRequestInterceptor final : public QWebEngineUrlRequestInterceptor { Q_OBJECT public: EwsOAuthRequestInterceptor(QObject *parent, const QString &redirectUri) : QWebEngineUrlRequestInterceptor(parent), mRedirectUri(redirectUri) { }; ~EwsOAuthRequestInterceptor() override = default; void interceptRequest(QWebEngineUrlRequestInfo &info) override; Q_SIGNALS: void redirectUriIntercepted(const QUrl &url); private: const QString mRedirectUri; }; class EwsOAuthPrivate final : public QObject { Q_OBJECT public: EwsOAuthPrivate(EwsOAuth *parent, const QString &email, const QString &appId, const QString &redirectUri); ~EwsOAuthPrivate() override = default; void authenticate(); void modifyParametersFunction(QAbstractOAuth::Stage stage, QVariantMap *parameters); void authorizeWithBrowser(const QUrl &url); void redirectUriIntercepted(const QUrl &url); void granted(); void error(const QString &error, const QString &errorDescription, const QUrl &uri); QWebEngineView mWebView; QWebEngineProfile mWebProfile; QWebEnginePage mWebPage; QOAuth2AuthorizationCodeFlow mOAuth2; EwsOAuthReplyHandler mReplyHandler; EwsOAuthRequestInterceptor mRequestInterceptor; EwsOAuthUrlSchemeHandler mSchemeHandler; QString mToken; const QString mEmail; const QString mRedirectUri; EwsOAuth::State mState; + QWidget *mParentWindow; QPointer mWebDialog; EwsOAuth *q_ptr = nullptr; Q_DECLARE_PUBLIC(EwsOAuth) }; void EwsOAuthUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *request) { returnUriReceived(request->requestUrl()); } void EwsOAuthRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo &info) { const auto url = info.requestUrl(); qCDebug(EWSCLI_LOG) << QStringLiteral("Intercepted browser navigation to ") << url; if (url.toString(QUrl::RemoveQuery) == mRedirectUri) { qCDebug(EWSCLI_LOG) << QStringLiteral("Found redirect URI - blocking request"); redirectUriIntercepted(url); info.block(true); } } EwsOAuthPrivate::EwsOAuthPrivate(EwsOAuth *parent, const QString &email, const QString &appId, const QString &redirectUri) : QObject(nullptr), mWebView(nullptr), mWebProfile(), mWebPage(&mWebProfile), mReplyHandler(this, redirectUri), mRequestInterceptor(this, redirectUri), mEmail(email), mRedirectUri(redirectUri), mState(EwsOAuth::NotAuthenticated), mParentWindow(nullptr), q_ptr(parent) { mOAuth2.setReplyHandler(&mReplyHandler); mOAuth2.setAuthorizationUrl(o365AuthorizationUrl); mOAuth2.setAccessTokenUrl(o365AccessTokenUrl); mOAuth2.setClientIdentifier(appId); /* Bad bad Microsoft... * When Conditional Access is enabled on the server the OAuth2 authentication server only supports Windows, * MacOSX, Android and iOS. No option to include Linux. Support (i.e. guarantee that it works) * is one thing, but blocking unsupported browsers completely is just wrong. * Fortunately enough this can be worked around by faking the user agent to something "supported". */ mWebProfile.setHttpUserAgent(o365FakeUserAgent); mWebProfile.setRequestInterceptor(&mRequestInterceptor); mWebProfile.installUrlSchemeHandler("urn", &mSchemeHandler); mWebView.setPage(&mWebPage); mOAuth2.setModifyParametersFunction([&](QAbstractOAuth::Stage stage, QVariantMap *parameters) { modifyParametersFunction(stage, parameters); }); connect(&mOAuth2, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, this, &EwsOAuthPrivate::authorizeWithBrowser); connect(&mOAuth2, &QOAuth2AuthorizationCodeFlow::granted, this, &EwsOAuthPrivate::granted); connect(&mOAuth2, &QOAuth2AuthorizationCodeFlow::error, this, &EwsOAuthPrivate::error); connect(&mRequestInterceptor, &EwsOAuthRequestInterceptor::redirectUriIntercepted, this, &EwsOAuthPrivate::redirectUriIntercepted, Qt::QueuedConnection); } void EwsOAuthPrivate::authenticate() { qCInfoNC(EWSCLI_LOG) << QStringLiteral("Starting OAuth2 authentication"); mState = EwsOAuth::Authenticating; mOAuth2.grant(); } void EwsOAuthPrivate::modifyParametersFunction(QAbstractOAuth::Stage stage, QVariantMap *parameters) { switch (stage) { case QAbstractOAuth::Stage::RequestingAccessToken: parameters->insert(QStringLiteral("resource"), o365Resource); break; case QAbstractOAuth::Stage::RequestingAuthorization: parameters->insert(QStringLiteral("prompt"), QStringLiteral("login")); parameters->insert(QStringLiteral("login_hint"), mEmail); parameters->insert(QStringLiteral("resource"), o365Resource); break; default: break; } } void EwsOAuthPrivate::authorizeWithBrowser(const QUrl &url) { qCInfoNC(EWSCLI_LOG) << QStringLiteral("Launching browser for authentication"); - mWebDialog = new QDialog(nullptr); + mWebDialog = new QDialog(mParentWindow); mWebDialog->setObjectName(QStringLiteral("Akonadi EWS Resource - Authentication")); mWebDialog->setWindowIcon(QIcon("akonadi-ews")); mWebDialog->resize(400, 500); auto layout = new QHBoxLayout(mWebDialog); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(&mWebView); mWebView.show(); mWebView.load(url); mWebDialog->show(); } void EwsOAuthPrivate::redirectUriIntercepted(const QUrl &url) { qCDebug(EWSCLI_LOG) << QStringLiteral("Intercepted redirect URI from browser"); QUrlQuery query(url); QVariantMap varmap; for (const auto item : query.queryItems()) { varmap[item.first] = item.second; } mOAuth2.authorizationCallbackReceived(varmap); mWebView.stop(); mWebDialog->hide(); } void EwsOAuthPrivate::granted() { Q_Q(EwsOAuth); mState = EwsOAuth::Authenticated; // TODO: Store refreshUri qCInfo(EWSCLI_LOG) << QStringLiteral("Authentication succeeded"); Q_EMIT(q->granted()); } void EwsOAuthPrivate::error(const QString &error, const QString &errorDescription, const QUrl &uri) { Q_Q(EwsOAuth); mState = EwsOAuth::AuthenticationFailed; qCInfoNC(EWSCLI_LOG) << QStringLiteral("Authentication failed: ") << error << errorDescription; Q_EMIT(q->error(error, errorDescription, uri)); } EwsOAuth::EwsOAuth(QObject *parent, const QString &email, const QString &appId, const QString &redirectUri) : QObject(parent), d_ptr(new EwsOAuthPrivate(this, email, appId, redirectUri)) { } EwsOAuth::~EwsOAuth() { } void EwsOAuth::authenticate() { Q_D(EwsOAuth); d->authenticate(); } QString EwsOAuth::token() const { Q_D(const EwsOAuth); return d->mOAuth2.token(); } EwsOAuth::State EwsOAuth::state() const { Q_D(const EwsOAuth); return d->mState; } +void EwsOAuth::setParentWindow(QWidget *window) +{ + Q_D(EwsOAuth); + + d->mParentWindow = window; +} + #include "ewsoauth.moc" diff --git a/resources/ews/ewsclient/ewsoauth.h b/resources/ews/ewsclient/ewsoauth.h index 7da8d3f6e..5e1adfa1f 100644 --- a/resources/ews/ewsclient/ewsoauth.h +++ b/resources/ews/ewsclient/ewsoauth.h @@ -1,53 +1,56 @@ /* Copyright (C) 2018 Krzysztof Nowicki This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef EWSOAUTH_H #define EWSOAUTH_H #include #include +class QWidget; class EwsOAuthPrivate; class EwsOAuth : public QObject { Q_OBJECT public: enum State { NotAuthenticated, Authenticating, Authenticated, AuthenticationFailed }; EwsOAuth(QObject *parent, const QString &email, const QString &appId, const QString &redirectUri); ~EwsOAuth() override; void authenticate(); QString token() const; State state() const; + + void setParentWindow(QWidget *w); Q_SIGNALS: void granted(); void error(const QString &error, const QString &errorDescription, const QUrl &uri); private: QScopedPointer d_ptr; Q_DECLARE_PRIVATE(EwsOAuth) }; #endif /* EWSOAUTH_H */ diff --git a/resources/ews/ewsclient/ewsrequest.cpp b/resources/ews/ewsclient/ewsrequest.cpp index 78ab35cc8..018d76a4e 100644 --- a/resources/ews/ewsclient/ewsrequest.cpp +++ b/resources/ews/ewsclient/ewsrequest.cpp @@ -1,412 +1,420 @@ /* Copyright (C) 2015-2018 Krzysztof Nowicki This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ewsrequest.h" #include #include "ewsclient.h" #include "ewsclient_debug.h" #include "ewsserverversion.h" #ifdef HAVE_NETWORKAUTH #include "ewsoauth.h" #endif EwsRequest::EwsRequest(EwsClient &client, QObject *parent) - : EwsJob(parent), mClient(client), mServerVersion(EwsServerVersion::ewsVersion2007Sp1) + : EwsJob(parent), mClient(client), mServerVersion(EwsServerVersion::ewsVersion2007Sp1), mParentWindow(nullptr) { } EwsRequest::~EwsRequest() { } void EwsRequest::doSend() { Q_FOREACH (KJob *job, subjobs()) { job->start(); } } void EwsRequest::startSoapDocument(QXmlStreamWriter &writer) { writer.setCodec("UTF-8"); 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; #ifdef HAVE_NETWORKAUTH QString authToken; if (mClient.authMode() == EwsClient::OAuth2) { authToken = getOAuthToken(); if (authToken.isNull()) { return; } } #endif KIO::TransferJob *job = KIO::http_post(mClient.url(), body.toUtf8(), KIO::HideProgressInfo); job->addMetaData(QStringLiteral("content-type"), QStringLiteral("text/xml")); if (!mClient.userAgent().isEmpty()) { job->addMetaData(QStringLiteral("UserAgent"), mClient.userAgent()); } job->addMetaData(mMd); #ifdef HAVE_NETWORKAUTH if (mClient.authMode() == EwsClient::OAuth2) { job->addMetaData(QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: Bearer ") + authToken); } #endif job->addMetaData(QStringLiteral("no-auth-prompt"), QStringLiteral("true")); if (mClient.isNTLMv2Enabled()) { job->addMetaData(QStringLiteral("EnableNTLMv2Auth"), QStringLiteral("true")); } connect(job, &KIO::TransferJob::result, this, &EwsRequest::requestResult); connect(job, &KIO::TransferJob::data, this, &EwsRequest::requestData); addSubjob(job); } #ifdef HAVE_NETWORKAUTH QString EwsRequest::getOAuthToken() { auto oAuth = mClient.oAuth(); switch (oAuth->state()) { case EwsOAuth::Authenticated: return oAuth->token(); case EwsOAuth::Authenticating: /* fall through */ case EwsOAuth::NotAuthenticated: qCInfoNC(EWSCLI_LOG) << QStringLiteral("OAuth token missing - delaying request until authentication finishes"); connect(oAuth, &EwsOAuth::granted, this, [this]() { qDebug() << "EwsRequest::prepareAuth: granted"; prepare(mBody); }); connect(oAuth, &EwsOAuth::error, this, [this](const QString &error, const QString &, const QUrl &) { setErrorMsg(QStringLiteral("Failed to process EWS request - OAuth2 authentication failed - %1").arg(error)); emitResult(); }); if (oAuth->state() == EwsOAuth::NotAuthenticated) { + if (mParentWindow) { + oAuth->setParentWindow(mParentWindow); + } oAuth->authenticate(); } break; default: setErrorMsg(QStringLiteral("Failed to process EWS request - unknown OAuth2 authentication state - %1").arg(oAuth->state())); emitResult(); } return QString(); } #endif void EwsRequest::setMetaData(const KIO::MetaData &md) { mMd = md; } void EwsRequest::addMetaData(const QString &key, const QString &value) { mMd.insert(key, value); } void EwsRequest::requestResult(KJob *job) { if (EWSCLI_PROTO_LOG().isDebugEnabled()) { ewsLogDir.setAutoRemove(false); if (ewsLogDir.isValid()) { QTemporaryFile dumpFile(ewsLogDir.path() + QStringLiteral("/ews_xmldump_XXXXXXX.xml")); dumpFile.open(); dumpFile.setAutoRemove(false); dumpFile.write(mResponseData.toUtf8()); qCDebug(EWSCLI_PROTO_LOG) << "response dumped to" << dumpFile.fileName(); dumpFile.close(); } } KIO::TransferJob *trJob = qobject_cast(job); int resp = trJob->metaData()[QStringLiteral("responsecode")].toUInt(); #ifdef HAVE_NETWORKAUTH if (resp == 401) { auto oAuth = mClient.oAuth(); if (oAuth->state() == EwsOAuth::NotAuthenticated || oAuth->state() == EwsOAuth::Authenticating) { prepare(mBody); return; } } #endif if (job->error() != 0) { setErrorMsg(QStringLiteral("Failed to process EWS request: ") + job->errorString(), job->error()); } /* Don't attempt to parse the response in case of a HTTP error. The only exception is * 500 (Bad Request) as in such case the server does provide the usual SOAP response. */ else if ((resp >= 300) && (resp != 500)) { setErrorMsg(QStringLiteral("Failed to process EWS request - HTTP code %1").arg(resp)); setError(resp); } else { 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() != QStringLiteral("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() == QStringLiteral("Body")) { if (!readSoapBody(reader)) return false; } else if (reader.name() == QStringLiteral("Header")) { if (!readHeader(reader)) { return false; } } } return true; } bool EwsRequest::readSoapBody(QXmlStreamReader &reader) { while (reader.readNextStartElement()) { if ((reader.name() == QStringLiteral("Fault")) && (reader.namespaceUri() == soapEnvNsUri)) { return readSoapFault(reader); } if (!parseResult(reader)) { if (EWSCLI_FAILEDREQUEST_LOG().isDebugEnabled()) { dump(); } return false; } } return true; } bool EwsRequest::readSoapFault(QXmlStreamReader &reader) { QString faultCode; QString faultString; while (reader.readNextStartElement()) { if (reader.name() == QStringLiteral("faultcode")) { faultCode = reader.readElementText(); } else if (reader.name() == QStringLiteral("faultstring")) { faultString = reader.readElementText(); } } setErrorMsg(faultCode + QStringLiteral(": ") + faultString); if (EWSCLI_FAILEDREQUEST_LOG().isDebugEnabled()) { dump(); } return false; } void EwsRequest::requestData(KIO::Job *job, const QByteArray &data) { Q_UNUSED(job); qCDebug(EWSCLI_PROTO_LOG) << "data" << job << data; mResponseData += QString::fromUtf8(data); } bool EwsRequest::parseResponseMessage(QXmlStreamReader &reader, const QString &reqName, ContentReaderFn contentReader) { if (reader.name() != 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() != QStringLiteral("ResponseMessages") || reader.namespaceUri() != ewsMsgNsUri) { return setErrorMsg(QStringLiteral("Failed to read EWS request - expected %1 element.") .arg(QStringLiteral("ResponseMessages"))); } while (reader.readNextStartElement()) { if (reader.name() != 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 const QString respClasses[] = { QStringLiteral("Success"), QStringLiteral("Warning"), QStringLiteral("Error") }; QStringRef respClassRef = reader.attributes().value(QStringLiteral("ResponseClass")); if (respClassRef.isNull()) { mClass = EwsResponseParseError; qCWarning(EWSCLI_LOG) << "ResponseClass attribute not found in response element"; return; } unsigned i; for (i = 0; i < sizeof(respClasses) / sizeof(respClasses[0]); ++i) { if (respClassRef == respClasses[i]) { mClass = static_cast(i); break; } } } bool EwsRequest::Response::readResponseElement(QXmlStreamReader &reader) { if (reader.namespaceUri() != ewsMsgNsUri) { return false; } if (reader.name() == QStringLiteral("ResponseCode")) { mCode = reader.readElementText(); } else if (reader.name() == QStringLiteral("MessageText")) { mMessage = reader.readElementText(); } else if (reader.name() == QStringLiteral("DescriptiveLinkKey")) { reader.skipCurrentElement(); } else if (reader.name() == QStringLiteral("MessageXml")) { reader.skipCurrentElement(); } else if (reader.name() == QStringLiteral("ErrorSubscriptionIds")) { reader.skipCurrentElement(); } else { return false; } return true; } bool EwsRequest::readHeader(QXmlStreamReader &reader) { while (reader.readNextStartElement()) { if (reader.name() == QStringLiteral("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; mClient.setServerVersion(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.toUtf8()); 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"; } } + +void EwsRequest::setParentWindow(QWidget *window) +{ + mParentWindow = window; +} diff --git a/resources/ews/ewsclient/ewsrequest.h b/resources/ews/ewsclient/ewsrequest.h index 7fe8c2ade..47a7d59d8 100644 --- a/resources/ews/ewsclient/ewsrequest.h +++ b/resources/ews/ewsclient/ewsrequest.h @@ -1,114 +1,118 @@ /* Copyright (C) 2015-2018 Krzysztof Nowicki This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef EWSREQUEST_H #define EWSREQUEST_H #include #include #include #include #include #include "ewsclient.h" #include "ewsjob.h" #include "ewsserverversion.h" #include "ewstypes.h" +class QWidget; + class EwsRequest : public EwsJob { Q_OBJECT public: class Response { public: EwsResponseClass responseClass() const { return mClass; } bool isSuccess() const { return mClass == EwsResponseSuccess; } QString responseCode() const { return mCode; } QString responseMessage() const { return mMessage; } protected: Response(QXmlStreamReader &reader); bool readResponseElement(QXmlStreamReader &reader); bool setErrorMsg(const QString &msg); EwsResponseClass mClass; QString mCode; QString mMessage; }; EwsRequest(EwsClient &client, QObject *parent); ~EwsRequest() override; void setMetaData(const KIO::MetaData &md); void addMetaData(const QString &key, const QString &value); void setServerVersion(const EwsServerVersion &version); const EwsServerVersion &serverVersion() const { return mServerVersion; } void dump() const; + void setParentWindow(QWidget *w); protected: typedef std::function ContentReaderFn; void doSend(); void prepare(const QString &body); virtual bool parseResult(QXmlStreamReader &reader) = 0; void startSoapDocument(QXmlStreamWriter &writer); void endSoapDocument(QXmlStreamWriter &writer); bool parseResponseMessage(QXmlStreamReader &reader, const QString &reqName, ContentReaderFn contentReader); bool readResponse(QXmlStreamReader &reader); KIO::MetaData mMd; QString mResponseData; protected Q_SLOTS: void requestResult(KJob *job); virtual void requestData(KIO::Job *job, const QByteArray &data); private: bool readSoapBody(QXmlStreamReader &reader); bool readSoapFault(QXmlStreamReader &reader); bool readHeader(QXmlStreamReader &reader); bool readResponseAttr(const QXmlStreamAttributes &attrs, EwsResponseClass &responseClass); #ifdef HAVE_NETWORKAUTH QString getOAuthToken(); #endif QString mBody; EwsClient &mClient; EwsServerVersion mServerVersion; + QWidget *mParentWindow; }; #endif