protocolhelper_p.h 8.03 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
    Copyright (c) 2008 Volker Krause <vkrause@kde.org>

    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.
*/

20 21
#ifndef AKONADI_PROTOCOLHELPER_P_H
#define AKONADI_PROTOCOLHELPER_P_H
22

Daniel Vrátil's avatar
Daniel Vrátil committed
23 24 25 26 27 28 29 30
#include "cachepolicy.h"
#include "collection.h"
#include "collectionutils_p.h"
#include "item.h"
#include "itemfetchscope.h"
#include "sharedvaluepool_p.h"
#include "attributeentity.h"
#include "tag.h"
31

32 33 34 35 36 37
#include <akonadi/private/imapparser_p.h>
#include <akonadi/private/protocol_p.h>

#include <boost/bind.hpp>
#include <algorithm>

38 39
namespace Akonadi {

40 41
struct ProtocolHelperValuePool
{
Guy Maurel's avatar
Guy Maurel committed
42 43
    typedef Internal::SharedValuePool<QByteArray, QVector> FlagPool;
    typedef Internal::SharedValuePool<QString, QVector> MimeTypePool;
44

Guy Maurel's avatar
Guy Maurel committed
45 46 47
    FlagPool flagPool;
    MimeTypePool mimeTypePool;
    QHash<Collection::Id, Collection> ancestorCollections;
48
};
49

50 51 52 53 54 55
/**
  @internal
  Helper methods for converting between libakonadi objects and their protocol
  representation.

  @todo Add unit tests for this.
56
  @todo Use exceptions for a useful error handling
57 58 59
*/
class ProtocolHelper
{
Guy Maurel's avatar
Guy Maurel committed
60
public:
61 62
    /** Part namespaces. */
    enum PartNamespace {
Guy Maurel's avatar
Guy Maurel committed
63 64 65
        PartGlobal,
        PartPayload,
        PartAttribute
66 67
    };

68 69
    /**
      Parse a cache policy definition.
70 71
      @param data The input data.
      @param policy The parsed cache policy.
Tobias Koenig's avatar
Tobias Koenig committed
72
      @param start Start of the data, ie. postion after the label.
73
      @returns Position in data after the cache policy description.
74
    */
Guy Maurel's avatar
Guy Maurel committed
75
    static int parseCachePolicy(const QByteArray &data, CachePolicy &policy, int start = 0);
76 77 78 79

    /**
      Convert a cache policy object into its protocol representation.
    */
Guy Maurel's avatar
Guy Maurel committed
80
    static QByteArray cachePolicyToByteArray(const CachePolicy &policy);
81

82 83 84
    /**
      Convert a ancestor chain from its protocol representation into an Entity object.
    */
Guy Maurel's avatar
Guy Maurel committed
85
    static void parseAncestors(const QByteArray &data, Entity *entity, int start = 0);
86

87 88 89 90 91 92
    /**
      Convert a ancestor chain from its protocol representation into an Entity object.

      This method allows to pass a @p valuePool which acts as cache, so ancestor paths for the
      same @p parentCollection don't have to be parsed twice.
    */
Guy Maurel's avatar
Guy Maurel committed
93
    static void parseAncestorsCached(const QByteArray &data, Entity *entity, Collection::Id parentCollection, ProtocolHelperValuePool *valuePool = 0, int start = 0);
94

95 96 97
    /**
      Parse a collection description.
      @param data The input data.
Tobias Koenig's avatar
Tobias Koenig committed
98 99
      @param collection The parsed collection.
      @param start Start of the data.
100 101
      @returns Position in data after the collection description.
    */
Guy Maurel's avatar
Guy Maurel committed
102
    static int parseCollection(const QByteArray &data, Collection &collection, int start = 0);
103

104 105 106
    /**
      Convert attributes to their protocol representation.
    */
Guy Maurel's avatar
Guy Maurel committed
107 108
    static QByteArray attributesToByteArray(const Entity &entity, bool ns = false);
    static QByteArray attributesToByteArray(const AttributeEntity &entity, bool ns = false);
109 110 111 112

    /**
      Encodes part label and namespace.
    */
Guy Maurel's avatar
Guy Maurel committed
113
    static QByteArray encodePartIdentifier(PartNamespace ns, const QByteArray &label, int version = 0);
114

115 116 117
    /**
      Decode part label and namespace.
    */
Guy Maurel's avatar
Guy Maurel committed
118
    static QByteArray decodePartIdentifier(const QByteArray &data, PartNamespace &ns);
119 120 121 122 123

    /**
      Converts the given set of items into a protocol representation.
      @throws A Akonadi::Exception if the item set contains items with missing/invalid identifiers.
    */
124
    template <typename T>
Guy Maurel's avatar
Guy Maurel committed
125
    static QByteArray entitySetToByteArray(const QList<T> &_objects, const QByteArray &command)
126
    {
Guy Maurel's avatar
Guy Maurel committed
127 128
        if (_objects.isEmpty()) {
            throw Exception("No objects specified");
129
        }
Guy Maurel's avatar
Guy Maurel committed
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182

        typename T::List objects(_objects);

        QByteArray rv;
        std::sort(objects.begin(), objects.end(), boost::bind(&T::id, _1) < boost::bind(&T::id, _2));
        if (objects.first().isValid()) {
            // all items have a uid set
            rv += " " AKONADI_CMD_UID " ";
            if (!command.isEmpty()) {
                rv += command;
                rv += ' ';
            }
            QVector<typename T::Id>  uids;
            foreach (const T &object, objects) {
                uids << object.id();
            }
            ImapSet set;
            set.add(uids);
            rv += set.toImapSequenceSet();
            return rv;
        }

        // check if all items have a remote id
        if (std::find_if(objects.constBegin(), objects.constEnd(),
                         boost::bind(&QString::isEmpty, boost::bind(&T::remoteId, _1)))
            != objects.constEnd()) {
            throw Exception("No remote identifier specified");
        }

        // check if we have RIDs or HRIDs
        if (std::find_if(objects.constBegin(), objects.constEnd(),
                         !boost::bind(static_cast<bool (*)(const T &)>(&CollectionUtils::hasValidHierarchicalRID), _1))
            == objects.constEnd() && objects.size() == 1) {  // ### HRID sets are not yet specified
            // HRIDs
            rv += " " AKONADI_CMD_HRID " ";
            if (!command.isEmpty()) {
                rv += command;
                rv += ' ';
            }
            rv += '(' + hierarchicalRidToByteArray(objects.first()) + ')';
            return rv;
        }

        // RIDs
        QList<QByteArray> rids;
        foreach (const T &object, objects) {
            rids << ImapParser::quote(object.remoteId().toUtf8());
        }

        rv += " " AKONADI_CMD_RID " ";
        if (!command.isEmpty()) {
            rv += command;
            rv += ' ';
183
        }
Guy Maurel's avatar
Guy Maurel committed
184 185 186
        rv += '(';
        rv += ImapParser::join(rids, " ");
        rv += ')';
Volker Krause's avatar
Volker Krause committed
187
        return rv;
188
    }
189

Guy Maurel's avatar
Guy Maurel committed
190
    static QByteArray entitySetToByteArray(const QList<Akonadi::Item> &_objects, const QByteArray &command);
Christian Mollekopf's avatar
Christian Mollekopf committed
191

Guy Maurel's avatar
Guy Maurel committed
192 193
    static QByteArray tagSetToImapSequenceSet(const Akonadi::Tag::List &_objects);
    static QByteArray tagSetToByteArray(const Akonadi::Tag::List &_objects, const QByteArray &command);
Christian Mollekopf's avatar
Christian Mollekopf committed
194

195 196 197 198

    static QByteArray commandContextToByteArray(const Akonadi::Collection &collection, const Akonadi::Tag &tag,
                                                const Item::List &requestedItems, const QByteArray &command);

Volker Krause's avatar
Volker Krause committed
199 200 201 202 203
    /**
      Converts the given object identifier into a protocol representation.
      @throws A Akonadi::Exception if the item set contains items with missing/invalid identifiers.
    */
    template <typename T>
Guy Maurel's avatar
Guy Maurel committed
204
    static QByteArray entityIdToByteArray(const T &object, const QByteArray &command)
Volker Krause's avatar
Volker Krause committed
205
    {
Guy Maurel's avatar
Guy Maurel committed
206
        return entitySetToByteArray(typename T::List() << object, command);
Volker Krause's avatar
Volker Krause committed
207 208
    }

209 210 211 212
    /**
      Converts the given collection's hierarchical RID into a protocol representation.
      Assumes @p col has a valid hierarchical RID, so check that before!
    */
Guy Maurel's avatar
Guy Maurel committed
213
    static QByteArray hierarchicalRidToByteArray(const Collection &col);
214

Volker Krause's avatar
Volker Krause committed
215 216 217 218
    /**
      Converts the HRID of the given item into an ASAP protocol representation.
      Assumes @p item has a valid HRID.
    */
Guy Maurel's avatar
Guy Maurel committed
219
    static QByteArray hierarchicalRidToByteArray(const Item &item);
Volker Krause's avatar
Volker Krause committed
220

221 222 223
    /**
      Converts a given ItemFetchScope object into a protocol representation.
    */
Guy Maurel's avatar
Guy Maurel committed
224
    static QByteArray itemFetchScopeToByteArray(const ItemFetchScope &fetchScope);
225 226 227 228

    /**
      Parses a single line from an item fetch job result into an Item object.
     */
Guy Maurel's avatar
Guy Maurel committed
229 230
    static void parseItemFetchResult(const QList<QByteArray> &lineTokens, Item &item, ProtocolHelperValuePool *valuePool = 0);
    static void parseTagFetchResult(const QList<QByteArray> &lineTokens, Tag &tag);
Christian Mollekopf's avatar
Christian Mollekopf committed
231

232 233 234 235 236
};

}

#endif