File indexing completed on 2024-12-22 04:57:01
0001 /* 0002 SPDX-FileCopyrightText: 2015-2017 Krzysztof Nowicki <krissn@op.pl> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "ewsfinditemrequest.h" 0008 0009 #include <memory> 0010 0011 #include <QXmlStreamWriter> 0012 0013 #include "ewsclient_debug.h" 0014 0015 static const QString traversalTypeNames[] = { 0016 QStringLiteral("Shallow"), 0017 QStringLiteral("Deep"), 0018 QStringLiteral("SoftDeleted"), 0019 QStringLiteral("Associated"), 0020 }; 0021 0022 class EwsFindItemResponse : public EwsRequest::Response 0023 { 0024 public: 0025 EwsFindItemResponse(QXmlStreamReader &reader); 0026 bool parseRootFolder(QXmlStreamReader &reader); 0027 EwsItem *readItem(QXmlStreamReader &reader); 0028 0029 QList<EwsItem> mItems; 0030 unsigned mTotalItems; 0031 int mNextOffset; 0032 int mNextNumerator; 0033 int mNextDenominator; 0034 bool mIncludesLastItem; 0035 }; 0036 0037 EwsFindItemRequest::EwsFindItemRequest(EwsClient &client, QObject *parent) 0038 : EwsRequest(client, parent) 0039 , mTraversal(EwsTraversalShallow) 0040 , mPagination(false) 0041 , mPageBasePoint(EwsBasePointBeginning) 0042 , mPageOffset(0) 0043 , mFractional(false) 0044 , mMaxItems(-1) 0045 , mFracNumerator(0) 0046 , mFracDenominator(0) 0047 , mTotalItems(0) 0048 , mNextOffset(-1) 0049 , mNextNumerator(-1) 0050 , mNextDenominator(-1) 0051 , mIncludesLastItem(false) 0052 { 0053 } 0054 0055 EwsFindItemRequest::~EwsFindItemRequest() 0056 { 0057 } 0058 0059 void EwsFindItemRequest::setFolderId(const EwsId &id) 0060 { 0061 mFolderId = id; 0062 } 0063 0064 void EwsFindItemRequest::setItemShape(const EwsItemShape &shape) 0065 { 0066 mShape = shape; 0067 } 0068 0069 void EwsFindItemRequest::start() 0070 { 0071 QString reqString; 0072 QXmlStreamWriter writer(&reqString); 0073 0074 startSoapDocument(writer); 0075 0076 writer.writeStartElement(ewsMsgNsUri, QStringLiteral("FindItem")); 0077 writer.writeAttribute(QStringLiteral("Traversal"), traversalTypeNames[mTraversal]); 0078 0079 mShape.write(writer); 0080 0081 if (mPagination) { 0082 writer.writeStartElement(ewsMsgNsUri, QStringLiteral("IndexedPageItemView")); 0083 if (mMaxItems > 0) { 0084 writer.writeAttribute(QStringLiteral("MaxEntriesReturned"), QString::number(mMaxItems)); 0085 } 0086 writer.writeAttribute(QStringLiteral("Offset"), QString::number(mPageOffset)); 0087 writer.writeAttribute(QStringLiteral("BasePoint"), (mPageBasePoint == EwsBasePointEnd) ? QStringLiteral("End") : QStringLiteral("Beginning")); 0088 writer.writeEndElement(); 0089 } else if (mFractional) { 0090 writer.writeStartElement(ewsMsgNsUri, QStringLiteral("FractionalPageItemView")); 0091 if (mMaxItems > 0) { 0092 writer.writeAttribute(QStringLiteral("MaxEntriesReturned"), QString::number(mMaxItems)); 0093 } 0094 writer.writeAttribute(QStringLiteral("Numerator"), QString::number(mFracNumerator)); 0095 writer.writeAttribute(QStringLiteral("Denominator"), QString::number(mFracDenominator)); 0096 writer.writeEndElement(); 0097 } 0098 0099 writer.writeStartElement(ewsMsgNsUri, QStringLiteral("ParentFolderIds")); 0100 mFolderId.writeFolderIds(writer); 0101 writer.writeEndElement(); 0102 0103 writer.writeEndElement(); 0104 0105 endSoapDocument(writer); 0106 0107 qCDebug(EWSCLI_PROTO_LOG) << reqString; 0108 0109 qCDebugNC(EWSCLI_REQUEST_LOG) << QStringLiteral("Starting FindItems request (folder: ") << mFolderId << QStringLiteral(")"); 0110 0111 prepare(reqString); 0112 0113 doSend(); 0114 } 0115 0116 bool EwsFindItemRequest::parseResult(QXmlStreamReader &reader) 0117 { 0118 return parseResponseMessage(reader, QStringLiteral("FindItem"), [this](QXmlStreamReader &reader) { 0119 return parseItemsResponse(reader); 0120 }); 0121 } 0122 0123 bool EwsFindItemRequest::parseItemsResponse(QXmlStreamReader &reader) 0124 { 0125 auto resp = new EwsFindItemResponse(reader); 0126 if (resp->responseClass() == EwsResponseUnknown) { 0127 return false; 0128 } 0129 0130 mItems = resp->mItems; 0131 mTotalItems = resp->mTotalItems; 0132 mNextOffset = resp->mNextOffset; 0133 mNextNumerator = resp->mNextNumerator; 0134 mNextDenominator = resp->mNextDenominator; 0135 mIncludesLastItem = resp->mIncludesLastItem; 0136 0137 if (EWSCLI_REQUEST_LOG().isDebugEnabled()) { 0138 if (resp->isSuccess()) { 0139 qCDebugNC(EWSCLI_REQUEST_LOG) << QStringLiteral("Got FindItems response (%1 items, last included: %2)") 0140 .arg(mItems.size()) 0141 .arg(mIncludesLastItem ? QStringLiteral("true") : QStringLiteral("false")); 0142 } else { 0143 qCDebug(EWSCLI_REQUEST_LOG) << QStringLiteral("Got FindItems response - %1").arg(resp->responseMessage()); 0144 } 0145 } 0146 0147 return true; 0148 } 0149 0150 EwsFindItemResponse::EwsFindItemResponse(QXmlStreamReader &reader) 0151 : EwsRequest::Response(reader) 0152 { 0153 while (reader.readNextStartElement()) { 0154 if (reader.namespaceUri() != ewsMsgNsUri && reader.namespaceUri() != ewsTypeNsUri) { 0155 setErrorMsg(QStringLiteral("Unexpected namespace in %1 element: %2").arg(QStringLiteral("ResponseMessage"), reader.namespaceUri().toString())); 0156 return; 0157 } 0158 0159 if (reader.name() == QLatin1StringView("RootFolder")) { 0160 if (!parseRootFolder(reader)) { 0161 return; 0162 } 0163 } else if (!readResponseElement(reader)) { 0164 setErrorMsg(QStringLiteral("Failed to read EWS request - invalid response element.")); 0165 return; 0166 } 0167 } 0168 } 0169 0170 bool EwsFindItemResponse::parseRootFolder(QXmlStreamReader &reader) 0171 { 0172 if (reader.namespaceUri() != ewsMsgNsUri || reader.name() != QLatin1StringView("RootFolder")) { 0173 return setErrorMsg( 0174 QStringLiteral("Failed to read EWS request - expected %1 element (got %2).").arg(QStringLiteral("RootFolder"), reader.qualifiedName().toString())); 0175 } 0176 0177 if (!reader.attributes().hasAttribute(QStringLiteral("TotalItemsInView")) || !reader.attributes().hasAttribute(QStringLiteral("TotalItemsInView"))) { 0178 return setErrorMsg(QStringLiteral("Failed to read EWS request - missing attributes of %1 element.").arg(QStringLiteral("RootFolder"))); 0179 } 0180 bool ok; 0181 QXmlStreamAttributes attrs = reader.attributes(); 0182 mTotalItems = attrs.value(QStringLiteral("TotalItemsInView")).toUInt(&ok); 0183 if (!ok) { 0184 return setErrorMsg(QStringLiteral("Failed to read EWS request - failed to read %1 attribute.").arg(QStringLiteral("TotalItemsInView"))); 0185 } 0186 mIncludesLastItem = attrs.value(QStringLiteral("IncludesLastItemInRange")) == QLatin1StringView("true"); 0187 0188 if (attrs.hasAttribute(QStringLiteral("IndexedPagingOffset"))) { 0189 mNextOffset = attrs.value(QStringLiteral("IndexedPagingOffset")).toInt(&ok); 0190 if (!ok) { 0191 return setErrorMsg(QStringLiteral("Failed to read EWS request - failed to read %1 attribute.").arg(QStringLiteral("IndexedPagingOffset"))); 0192 } 0193 } 0194 0195 if (attrs.hasAttribute(QStringLiteral("NumeratorOffset"))) { 0196 mNextNumerator = attrs.value(QStringLiteral("NumeratorOffset")).toInt(&ok); 0197 if (!ok) { 0198 return setErrorMsg(QStringLiteral("Failed to read EWS request - failed to read %1 attribute.").arg(QStringLiteral("NumeratorOffset"))); 0199 } 0200 } 0201 0202 if (attrs.hasAttribute(QStringLiteral("AbsoluteDenominator"))) { 0203 mNextDenominator = attrs.value(QStringLiteral("AbsoluteDenominator")).toInt(&ok); 0204 if (!ok) { 0205 return setErrorMsg(QStringLiteral("Failed to read EWS request - failed to read %1 attribute.").arg(QStringLiteral("AbsoluteDenominator"))); 0206 } 0207 } 0208 0209 if (!reader.readNextStartElement()) { 0210 return setErrorMsg(QStringLiteral("Failed to read EWS request - expected a child element in %1 element.").arg(QStringLiteral("RootFolder"))); 0211 } 0212 0213 if (reader.namespaceUri() != ewsTypeNsUri || reader.name() != QLatin1StringView("Items")) { 0214 return setErrorMsg( 0215 QStringLiteral("Failed to read EWS request - expected %1 element (got %2).").arg(QStringLiteral("Items"), reader.qualifiedName().toString())); 0216 } 0217 0218 if (!reader.readNextStartElement()) { 0219 // An empty Items element means no items. 0220 reader.skipCurrentElement(); 0221 return true; 0222 } 0223 0224 if (reader.namespaceUri() != ewsTypeNsUri) { 0225 return setErrorMsg(QStringLiteral("Failed to read EWS request - expected child element from types namespace.")); 0226 } 0227 0228 do { 0229 EwsItem *item = readItem(reader); 0230 if (item) { 0231 mItems.append(*item); 0232 } 0233 } while (reader.readNextStartElement()); 0234 0235 // Finish the Items element 0236 reader.skipCurrentElement(); 0237 0238 // Finish the RootFolder element 0239 reader.skipCurrentElement(); 0240 0241 return true; 0242 } 0243 0244 EwsItem *EwsFindItemResponse::readItem(QXmlStreamReader &reader) 0245 { 0246 EwsItem *item = nullptr; 0247 const QStringView readerName = reader.name(); 0248 if (readerName == QLatin1StringView("Item") || readerName == QLatin1StringView("Message") || readerName == QLatin1StringView("CalendarItem") 0249 || readerName == QLatin1StringView("Contact") || readerName == QLatin1StringView("DistributionList") 0250 || readerName == QLatin1StringView("MeetingMessage") || readerName == QLatin1StringView("MeetingRequest") 0251 || readerName == QLatin1StringView("MeetingResponse") || readerName == QLatin1StringView("MeetingCancellation") 0252 || readerName == QLatin1StringView("Task")) { 0253 qCDebug(EWSCLI_LOG).noquote() << QStringLiteral("Processing %1").arg(readerName.toString()); 0254 item = new EwsItem(reader); 0255 if (!item->isValid()) { 0256 setErrorMsg(QStringLiteral("Failed to read EWS request - invalid %1 element.").arg(readerName.toString())); 0257 delete item; 0258 return nullptr; 0259 } 0260 } else { 0261 qCWarning(EWSCLI_LOG).noquote() << QStringLiteral("Unsupported folder type %1").arg(readerName.toString()); 0262 reader.skipCurrentElement(); 0263 } 0264 0265 return item; 0266 } 0267 0268 #include "moc_ewsfinditemrequest.cpp"