Example #1
0
Question XmlUtil::parseIdentificationQuestion(QXmlStreamReader &reader) {
	assert(reader.name() == "identification");
	const QXmlStreamAttributes &attrs = reader.attributes();

	Question q;
	q.type = Question::IDENTIFICATION;
	optional_assign(attrs, "score", q.score, reader);
	optional_assign(attrs, "time_limit", q.time_limit, reader);
	optional_assign(attrs, "id", q.id, reader);

	while ( !reader.atEnd() ) {
		reader.readNext();
		{
			const QStringRef &ns = reader.namespaceUri();
			if ( !ns.isEmpty() && ns != XML_NS ) continue;
		}
		if ( reader.isStartElement() ) {
			if ( reader.name() == "q" ) {
				q.question = reader.readElementText();
			} else if ( reader.name() == "a" )  {
				QString answer = reader.readElementText();
				q.answer_key.push_back(Question::AnswerKeyEntry(answer, true));
				q.answer.append(answer+" - ");
			} else if ( reader.name() == "identification" ) {
				throw InvalidXmlException("'identification' tag found inside 'identification'.", reader);
			} else {
				//barf?
			}
		} else if ( reader.isEndElement() && reader.name() == "identification" )
			break;
	}
	return q;
}
EwsFindFolderResponse::EwsFindFolderResponse(QXmlStreamReader &reader)
    : EwsRequest::Response(reader)
{
    while (reader.readNextStartElement()) {
        if (reader.namespaceUri() != ewsMsgNsUri && reader.namespaceUri() != ewsTypeNsUri) {
            setErrorMsg(QStringLiteral("Unexpected namespace in %1 element: %2")
                .arg(QStringLiteral("ResponseMessage")).arg(reader.namespaceUri().toString()));
            return;
        }

        if (reader.name() == QStringLiteral("RootFolder")) {
            if (!parseRootFolder(reader)) {
                return;
            }
        }
        else if (!readResponseElement(reader)) {
            setErrorMsg(QStringLiteral("Failed to read EWS request - invalid response element."));
            return;
        }
    }
}
Example #3
0
EwsAttendee::EwsAttendee(QXmlStreamReader &reader)
    : d(new EwsAttendeePrivate())
{
    while (reader.readNextStartElement()) {
        if (reader.namespaceUri() != ewsTypeNsUri) {
            qCWarningNC(EWSRES_LOG) << QStringLiteral("Unexpected namespace in mailbox element:")
                            << reader.namespaceUri();
            return;
        }

        if (reader.name() == QStringLiteral("Mailbox")) {
            d->mMailbox = EwsMailbox(reader);
            if (!d->mMailbox.isValid()) {
                qCWarning(EWSRES_LOG) << QStringLiteral("Failed to read EWS request - invalid attendee %1 element.")
                                .arg(reader.name().toString());
                return;
            }
        }
        else if (reader.name() == QStringLiteral("ResponseType")) {
            bool ok;
            d->mResponse = decodeEnumString<EwsEventResponseType>(reader.readElementText(),
                                responseTypeNames, responseTypeNameCount, &ok);
            if (reader.error() != QXmlStreamReader::NoError || !ok) {
                qCWarning(EWSRES_LOG) << QStringLiteral("Failed to read EWS request - invalid attendee %1 element.")
                                .arg(reader.name().toString());
                return;
            }
        }
        else if (reader.name() == QStringLiteral("LastResponseTime")) {
            // Unsupported - ignore
            //qCWarningNC(EWSCLIENT_LOG) << QStringLiteral("Unsupported mailbox element %1").arg(reader.name().toString());
            reader.skipCurrentElement();
        }
    }

    d->mValid = true;
}
Example #4
0
Question XmlUtil::parseChooseQuestion(QXmlStreamReader &reader) {
	assert(reader.name() == "choose");

	const QXmlStreamAttributes &attrs = reader.attributes();
	Question q;
	q.type = Question::CHOOSE_ONE;
	optional_assign(attrs, "score", q.score, reader);
	optional_assign(attrs, "time_limit", q.time_limit, reader);
	optional_assign(attrs, "id", q.id, reader);

	{
		bool multiple = false;
		optional_assign(attrs, "multiple", multiple, reader);
		if ( multiple )
			q.type = Question::CHOOSE_ANY;
	}

	while ( !reader.atEnd() ) {
		reader.readNext();
		{
			const QStringRef &ns = reader.namespaceUri();
			if ( !ns.isEmpty() && ns != XML_NS ) continue;
		}
		if ( reader.isStartElement() ) {
			if ( reader.name() == "q" ) {
				q.question = reader.readElementText();
			} else if ( reader.name() == "choice" )  {
				bool is_answer = false;
				optional_assign(reader.attributes(), "answer", is_answer, reader);
				QString answer = reader.readElementText();
				q.answer_key.push_back(Question::AnswerKeyEntry(answer, is_answer));
				if( is_answer ) q.answer.append(answer+" - ");

			} else if ( reader.name() == "choose" ) {
				throw InvalidXmlException("'choose' tag found inside 'choose'.", reader);
			} else {
				//barf?
			}
		} else if ( reader.isEndElement() && reader.name() == "choose" )
			break;
	}
	return q;
}
Example #5
0
static Episode parseEpisode(QXmlStreamReader &reader)
{
    Episode ep;
    bool isAudio=false;
    QUrl guidUrl;

    while (!reader.atEnd()) {
        reader.readNext();
        const QStringRef name = reader.name();
        if (reader.isStartElement()) {
            if (QLatin1String("title")==name) {
                ep.name=reader.readElementText();
            } else if (QLatin1String("duration")==name && constITunesNameSpace==reader.namespaceUri()) {
                QStringList parts = reader.readElementText().split(':');
                if (2==parts.count()) {
                    ep.duration=(parts[0].toInt() * 60) + parts[1].toInt();
                } else if (parts.count()>=3) {
                    ep.duration=(parts[0].toInt() * 60*60) + (parts[1].toInt() * 60) + parts[2].toInt();
                }
            } else if (0==ep.duration && QLatin1String("content")==name && constMediaNameSpace==reader.namespaceUri()) {
                ep.duration=reader.attributes().value(QLatin1String("duration")).toString().toUInt();
                consumeCurrentElement(reader);
            } else if (QLatin1String("enclosure")==name) {
                static QSet<QString> audioFormats;
                if (audioFormats.isEmpty()) {
                    audioFormats.insert(QLatin1String("mp3")); audioFormats.insert(QLatin1String("MP3"));
                    audioFormats.insert(QLatin1String("ogg")); audioFormats.insert(QLatin1String("OGG"));
                    audioFormats.insert(QLatin1String("wma")); audioFormats.insert(QLatin1String("WMA"));
                }
                QString type=reader.attributes().value(QLatin1String("type")).toString();
                if (type.startsWith(QLatin1String("audio/")) || audioFormats.contains(type)) {
                    isAudio=true;
                    ep.url=QUrl::fromEncoded(reader.attributes().value(QLatin1String("url")).toString().toLatin1());
                } else if (type.startsWith(QLatin1String("video/")) ) {
                    // At least one broken feed (BUG: 588) has the audio podcast listed as video/mp4,
                    // ...but the path ends in .mp3 !!!
                    QUrl url=QUrl::fromEncoded(reader.attributes().value(QLatin1String("url")).toString().toLatin1());
                    QString path=url.path();
                    if (path.endsWith(QLatin1String(".mp3"), Qt::CaseInsensitive) ||
                        path.endsWith(QLatin1String(".ogg"), Qt::CaseInsensitive) ||
                        path.endsWith(QLatin1String(".wma"), Qt::CaseInsensitive)) {
                        ep.url=url;
                    } else {
                        ep.video=true;
                    }
                }
                consumeCurrentElement(reader);
            } else if (QLatin1String("guid")==name) {
                guidUrl=QUrl(reader.readElementText());
            } else if (QLatin1String("pubDate")==name) {
                 ep.publicationDate=parseRfc822DateTime(reader.readElementText());
            } else {
                consumeCurrentElement(reader);
            }
        } else if (reader.isEndElement()) {
            break;
        }
    }

    // Sometimes the url entry in 'enclusure' is empty, but there is a url in 'guid' - so use
    // that if present (BUG: 602)
    if (isAudio && ep.url.isEmpty() && !guidUrl.isEmpty()) {
        ep.url=guidUrl;
    }
    return ep;
}
void LinNativeDisplayForm::parseRSSItem(
  QString &htmlOutput,
  QXmlStreamReader &textReader)
{
  QString title;
  QString link;
  QString imageUrl;
  QString enclosureUrl;
  QString enclosureType;
  QString mediaContentType;
  QString description;
  QString pubDate;
  bool mediaContentAlreadySeen = false;

  while (!textReader.atEnd())
  {
    textReader.readNext();

    if (textReader.isStartElement())
    {
      if (textReader.name() == "title")
      {
        title = parseText("title", textReader);
      }
      else if (textReader.name() == "link")
      {
        link = parseText("link", textReader);
      }
      else if (textReader.name() == "enclosure")
      {
        if (textReader.attributes().hasAttribute("type"))
        {
          enclosureType = textReader.attributes().value("type").toString();
        }

        if (textReader.attributes().hasAttribute("url"))
        {
          if (enclosureType == "image/jpeg")
          {
            // Use the enclosure as our image:
            imageUrl = textReader.attributes().value("url").toString();
          }
          else
          {
            enclosureUrl = textReader.attributes().value("url").toString();
          }
        }
      }
      else if (textReader.name() == "thumbnail")
      {
        // For some reason, BBC throws two thumbnails into each item.
        // The second one is always bigger, so we'll just let it overwrite
        // the first one.
        // Also, the Australian BC puts both "content" and "thumbnail"
        // images into its rss; if content has already been seen, I'll just
        // ignore the thumbnail:
        if ( !mediaContentAlreadySeen
          && QString::compare(
            textReader.namespaceUri().toString(),
            MEDIA_NS,
            Qt::CaseInsensitive) == 0
          && textReader.attributes().hasAttribute("url"))
        {
          imageUrl = textReader.attributes().value("url").toString();
        }
      }
      else if (textReader.name() == "content")
      {
        if (textReader.attributes().hasAttribute("medium"))
        {
          mediaContentType = textReader.attributes().value("medium").toString();
        }

        // If there are multiple content items, choose the first one:
        if ( !mediaContentAlreadySeen
          && QString::compare(
            textReader.namespaceUri().toString(),
            MEDIA_NS,
            Qt::CaseInsensitive) == 0
          && textReader.attributes().hasAttribute("url"))
        {
          if (mediaContentType == "image")
          {
            imageUrl = textReader.attributes().value("url").toString();
          }
          else
          {
            enclosureUrl = textReader.attributes().value("url").toString();
          }
          mediaContentAlreadySeen = true;
        }
      }
      else if (textReader.name() == "description")
      {
        description = parseText("description", textReader);
      }
      else if (textReader.name() == "pubDate")
      {
        pubDate = parseText("pubDate", textReader);
      }
    }

    else if (textReader.isEndElement())
    {
      if (textReader.name() == "item")
      {
        // marshal the entire item into the HTML display:
        if (!title.isEmpty())
        {
          htmlOutput += "<b>";

          if (!link.isEmpty())
          {
            htmlOutput += "<a href=\"";
            htmlOutput += link;
            htmlOutput += "\">";
            htmlOutput += title;
            htmlOutput += "</a>";
          }
          else
          {
            htmlOutput += title;
          }
          htmlOutput += "</b>";
        }

        htmlOutput += "<p>";

        if (!imageUrl.isEmpty() && !hideImages)
        {
          htmlOutput += "<img class=\"main\" src=\"";
          htmlOutput += imageUrl;
          htmlOutput += "\"/>\n";
        }

        if (!enclosureUrl.isEmpty())
        {
          htmlOutput += "<a href=\"";
          htmlOutput += enclosureUrl;
          htmlOutput += "\"><img src=\"qrc:/icons/blue-play.svg\" width=\"64px\" height=\"64px\"/></a>\n";
        }

        if (!description.isEmpty())
        {
          htmlOutput += description;
        }

        htmlOutput += "</p>\n";

        if (!faviconUrl.isEmpty())
        {
          htmlOutput += "<img class=\"footer\" src=\"";
          htmlOutput += faviconUrl;
          htmlOutput += "\"/>";
          if (pubDate.isEmpty())
          {
            htmlOutput += "<br>\n";
          }
          else
          {
            htmlOutput += " &nbsp; ";
          }
        }

        if (!pubDate.isEmpty())
        {
          htmlOutput += "<small>";
          htmlOutput += pubDate;
          htmlOutput += "</small><br>\n";
        }

        htmlOutput += "<hr width=\"60%\"/>";

        break;
      }
    }
  }
}
Example #7
0
bool EwsPropertyField::read(QXmlStreamReader &reader)
{
    if (reader.namespaceUri() != ewsTypeNsUri) {
        qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - invalid namespace.");
        return false;
    }

    QXmlStreamAttributes attrs = reader.attributes();
    bool ok;

    // First check the property type
    if (reader.name() == QStringLiteral("FieldURI")) {
        if (!attrs.hasAttribute(QStringLiteral("FieldURI"))) {
            qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - missing %1 attribute.")
                            .arg(QStringLiteral("FieldURI"));
            return false;
        }
        d->mPropType = Field;
        d->mUri = attrs.value(QStringLiteral("FieldURI")).toString();
    }
    else if (reader.name() == QStringLiteral("IndexedFieldURI")) {
        if (!attrs.hasAttribute(QStringLiteral("FieldURI"))) {
            qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - missing %1 attribute.")
                            .arg(QStringLiteral("FieldURI"));
            return false;
        }
        if (!attrs.hasAttribute(QStringLiteral("FieldIndex"))) {
            qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - missing %1 attribute.")
                            .arg(QStringLiteral("FieldIndex"));
            return false;
        }
        QString uri = attrs.value(QStringLiteral("FieldURI")).toString();
        QStringList tokens = uri.split(':');
        QString indexStr = attrs.value(QStringLiteral("FieldIndex")).toString();
        if (!indexStr.startsWith(tokens[1])) {
            qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - malformed %1 attribute.")
                                        .arg(QStringLiteral("FieldIndex"));
            return false;
        }
        unsigned index = indexStr.mid(tokens[1].size()).toUInt(&ok, 0);
        if (!ok) {
            qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - error reading %1 attribute.")
                            .arg(QStringLiteral("FieldIndex"));
            return false;
        }
        d->mPropType = IndexedField;
        d->mUri = uri;
        d->mIndex = index;
    }
    else if (reader.name() == QStringLiteral("ExtendedFieldURI")) {
        if (!attrs.hasAttribute(QStringLiteral("PropertyType"))) {
            qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - missing %1 attribute.")
                            .arg(QStringLiteral("PropertyType"));
            return false;
        }
        QStringRef propTypeText = attrs.value(QStringLiteral("PropertyType"));
        unsigned i;
        EwsPropertyType propType;
        for (i = 0; i < sizeof(propertyTypeNames) / sizeof(propertyTypeNames[0]); i++) {
            if (propTypeText == propertyTypeNames[i]) {
                propType = static_cast<EwsPropertyType>(i);
                break;
            }
        }
        if (i == sizeof(propertyTypeNames) / sizeof(propertyTypeNames[0])) {
            qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - error reading %1 attribute.")
                            .arg(QStringLiteral("PropertyType"));
            return false;
        }

        if (attrs.hasAttribute(QStringLiteral("PropertyTag"))) {

            unsigned tag = attrs.value(QStringLiteral("PropertyTag")).toUInt(&ok, 0);
            if (!ok) {
                qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - error reading %1 attribute.")
                                .arg(QStringLiteral("PropertyTag"));
                return false;
            }
            d->mHasTag = true;
            d->mTag = tag;
        }
        else {
            EwsPropertyFieldPrivate::PropSetIdType psIdType;
            EwsDistinguishedPropSetId psDid;
            QString psId;

            EwsPropertyFieldPrivate::PropIdType idType;
            unsigned id;
            QString name;
            if (attrs.hasAttribute(QStringLiteral("PropertyId"))) {
                id = attrs.value(QStringLiteral("PropertyId")).toUInt(&ok, 0);
                if (!ok) {
                    qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - error reading %1 attribute.")
                                    .arg(QStringLiteral("PropertyId"));
                    return false;
                }
                idType = EwsPropertyFieldPrivate::PropId;
            }
            else if (attrs.hasAttribute(QStringLiteral("PropertyName"))) {
                name = attrs.value(QStringLiteral("PropertyName")).toString();
                idType = EwsPropertyFieldPrivate::PropName;
            }
            else {
                qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - missing one of %1 or %2 attributes.")
                                .arg(QStringLiteral("PropertyId").arg(QStringLiteral("PropertyName")));
                return false;
            }

            if (attrs.hasAttribute(QStringLiteral("DistinguishedPropertySetId"))) {
                QStringRef didText = attrs.value(QStringLiteral("DistinguishedPropertySetId"));
                unsigned i;
                for (i = 0; i < sizeof(distinguishedPropSetIdNames) / sizeof(distinguishedPropSetIdNames[0]); i++) {
                    if (didText == distinguishedPropSetIdNames[i]) {
                        psDid = static_cast<EwsDistinguishedPropSetId>(i);
                        break;
                    }
                }
                if (i == sizeof(distinguishedPropSetIdNames) / sizeof(distinguishedPropSetIdNames[0])) {
                    qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - error reading %1 attribute.")
                                    .arg(QStringLiteral("DistinguishedPropertySetId"));
                    return false;
                }
                psIdType = EwsPropertyFieldPrivate::DistinguishedPropSet;
            }
            else if (attrs.hasAttribute(QStringLiteral("PropertySetId"))) {
                psId = attrs.value(QStringLiteral("PropertySetId")).toString();
                psIdType = EwsPropertyFieldPrivate::RealPropSet;
            }
            else {
                qCWarningNC(EWSRES_LOG) << QStringLiteral("Error reading property field - missing one of %1 or %2 attributes.")
                                .arg(QStringLiteral("DistinguishedPropertySetId").arg(QStringLiteral("PropertySetId")));
                return false;
            }
            d->mPsIdType = psIdType;
            d->mPsDid = psDid;
            d->mPsId = psId;
            d->mIdType = idType;
            d->mId = id;
            d->mName = name;
        }

        d->mType = propType;
        d->mPropType = ExtendedField;
    }
    d->recalcHash();
    return true;
}
Example #8
0
/**
 * @brief  Convert an XML stream to a hierarchical QVariantMap.
 *
 * This function is used internally to embed opaque XML structures, such as the
 * SQS service's ErrorResponse::Error::Detail, which the SQS schema defines as
 * an arbitrary complex type.
 *
 * @note   This static function exists within the AwsAbstractResponse for
 *         historic reasons.  It should probably be moved our of this class, and
 *         into a more generic utility space at some point.
 *
 * @param  xml       XML stream to convert.
 * @param  prefix    Prefix to apply to special (non-element) child entry names.
 * @param  maxDepth  Maximum depth to traverse before truncating the tree.
 *
 * @return A QVariantMap representing the \a xml XML fragment.
 *
 * @todo   Move this toVariant function to somewhere more generic.
 */
QVariantMap AwsAbstractResponse::toVariant(
    QXmlStreamReader &xml, const QString &prefix, const int maxDepth)
{
    if (maxDepth < 0) {
        qWarning() << QObject::tr("max depth exceeded");
        return QVariantMap();
    }

    if (xml.hasError()) {
        qWarning() << xml.errorString();
        return QVariantMap();
    }

    if (xml.tokenType() == QXmlStreamReader::NoToken)
        xml.readNext();

    if ((xml.tokenType() != QXmlStreamReader::StartDocument) &&
        (xml.tokenType() != QXmlStreamReader::StartElement)) {
        qWarning() << QObject::tr("unexpected XML tokenType %1 (%2)")
                      .arg(xml.tokenString()).arg(xml.tokenType());
        return QVariantMap();
    }

    QVariantMap map;
    if (xml.tokenType() == QXmlStreamReader::StartDocument) {
        map.insert(prefix + QLatin1String("DocumentEncoding"), xml.documentEncoding().toString());
        map.insert(prefix + QLatin1String("DocumentVersion"), xml.documentVersion().toString());
        map.insert(prefix + QLatin1String("StandaloneDocument"), xml.isStandaloneDocument());
    } else {
        if (!xml.namespaceUri().isEmpty())
            map.insert(prefix + QLatin1String("NamespaceUri"), xml.namespaceUri().toString());
        foreach (const QXmlStreamAttribute &attribute, xml.attributes()) {
            QVariantMap attributeMap;
            attributeMap.insert(QLatin1String("Value"), attribute.value().toString());
            if (!attribute.namespaceUri().isEmpty())
                attributeMap.insert(QLatin1String("NamespaceUri"), attribute.namespaceUri().toString());
            if (!attribute.prefix().isEmpty())
                attributeMap.insert(QLatin1String("Prefix"), attribute.prefix().toString());
            attributeMap.insert(QLatin1String("QualifiedName"), attribute.qualifiedName().toString());
            map.insertMulti(prefix + attribute.name().toString(), attributeMap);
        }
    }

    for (xml.readNext(); (!xml.atEnd()) && (xml.tokenType() != QXmlStreamReader::EndElement)
          && (xml.tokenType() != QXmlStreamReader::EndDocument); xml.readNext()) {
        switch (xml.tokenType()) {
        case QXmlStreamReader::Characters:
        case QXmlStreamReader::Comment:
        case QXmlStreamReader::DTD:
        case QXmlStreamReader::EntityReference:
            map.insertMulti(prefix + xml.tokenString(), xml.text().toString());
            break;
        case QXmlStreamReader::ProcessingInstruction:
            map.insertMulti(prefix + xml.processingInstructionTarget().toString(),
                            xml.processingInstructionData().toString());
            break;
        case QXmlStreamReader::StartElement: {
            const QString elementName = xml.name().toString();
            map.insertMulti(elementName, toVariant(xml, prefix, maxDepth-1));
            break;
        }
        default:
            qWarning() << QObject::tr("unexpected XML tokenType %1 (%2)")
                          .arg(xml.tokenString()).arg(xml.tokenType());
        }
    }
    return map;
}
bool EwsFindFolderResponse::parseRootFolder(QXmlStreamReader &reader)
{
    if (reader.namespaceUri() != ewsMsgNsUri || reader.name() != QStringLiteral("RootFolder")) {
        return setErrorMsg(QStringLiteral("Failed to read EWS request - expected %1 element (got %2).")
                        .arg(QStringLiteral("RootFolder")).arg(reader.qualifiedName().toString()));
    }

    if (!reader.attributes().hasAttribute(QStringLiteral("TotalItemsInView"))
        || !reader.attributes().hasAttribute(QStringLiteral("TotalItemsInView"))) {
        return setErrorMsg(QStringLiteral("Failed to read EWS request - missing attributes of %1 element.")
                                .arg(QStringLiteral("RootFolder")));
    }
    bool ok;
    unsigned totalItems = reader.attributes().value(QStringLiteral("TotalItemsInView")).toUInt(&ok);
    if (!ok) {
        return setErrorMsg(QStringLiteral("Failed to read EWS request - failed to read %1 attribute.")
                                        .arg(QStringLiteral("TotalItemsInView")));
    }

    if (!reader.readNextStartElement()) {
        return setErrorMsg(QStringLiteral("Failed to read EWS request - expected a child element in %1 element.")
                        .arg(QStringLiteral("RootFolder")));
    }

    if (reader.namespaceUri() != ewsTypeNsUri || reader.name() != QStringLiteral("Folders")) {
        return setErrorMsg(QStringLiteral("Failed to read EWS request - expected %1 element (got %2).")
                        .arg(QStringLiteral("Folders")).arg(reader.qualifiedName().toString()));
    }

    if (!reader.readNextStartElement()) {
        return setErrorMsg(QStringLiteral("Failed to read EWS request - expected a child element in %1 element.")
                        .arg(QStringLiteral("Folders")));
    }

    if (reader.namespaceUri() != ewsTypeNsUri) {
        return setErrorMsg(QStringLiteral("Failed to read EWS request - expected child element from types namespace."));
    }

    unsigned i = 0;
    for (i = 0; i < totalItems; i++) {
        EwsFolder *folder = readFolder(reader);
        reader.readNextStartElement();
        if (folder) {
            bool ok;
            int childCount = (*folder)[EwsFolderFieldChildFolderCount].toUInt(&ok);
            if (childCount > 0) {
                unsigned readCount = readChildFolders(*folder, childCount, reader);
                if (readCount == 0)
                    return false;
                i += readCount;
            }
            mFolders.append(*folder);
        }
    }

    // Finish the Folders element
    reader.skipCurrentElement();

    // Finish the RootFolder element
    reader.skipCurrentElement();

    return true;
}