protocolhelper_p.h 8.79 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
#include "cachepolicy.h"
#include "collection.h"
25
#include "collectionutils.h"
Daniel Vrátil's avatar
Daniel Vrátil committed
26 27 28 29 30
#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
      @param requireParent Wether or not we require a parent as part of the data.
101 102
      @returns Position in data after the collection description.
    */
103
    static int parseCollection(const QByteArray &data, Collection &collection, int start = 0, bool requireParent = true);
104

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

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

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

    /**
      Converts the given set of items into a protocol representation.
      @throws A Akonadi::Exception if the item set contains items with missing/invalid identifiers.
    */
125
    template <typename T>
Guy Maurel's avatar
Guy Maurel committed
126
    static QByteArray entitySetToByteArray(const QList<T> &_objects, const QByteArray &command)
127
    {
Guy Maurel's avatar
Guy Maurel committed
128 129
        if (_objects.isEmpty()) {
            throw Exception("No objects specified");
130
        }
Guy Maurel's avatar
Guy Maurel committed
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 183

        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 += ' ';
184
        }
Guy Maurel's avatar
Guy Maurel committed
185 186 187
        rv += '(';
        rv += ImapParser::join(rids, " ");
        rv += ')';
Volker Krause's avatar
Volker Krause committed
188
        return rv;
189
    }
190

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

Guy Maurel's avatar
Guy Maurel committed
193 194
    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
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

Christian Mollekopf's avatar
Christian Mollekopf committed
226 227 228
    /**
      Converts a given TagFetchScope object into a protocol representation.
    */
Guy Maurel's avatar
Guy Maurel committed
229
    static QByteArray tagFetchScopeToByteArray(const TagFetchScope &fetchScope);
Christian Mollekopf's avatar
Christian Mollekopf committed
230

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

238 239 240 241
    static QString akonadiStoragePath();
    static QString absolutePayloadFilePath(const QString &fileName);

    static bool streamPayloadToFile(const QByteArray &command, const QByteArray &data, QByteArray &error);
242 243 244

    static QByteArray listPreference(Collection::ListPurpose purpose, Collection::ListPreference preference);
    static QByteArray enabled(bool);
245
    static QByteArray referenced(bool);
246 247 248 249 250
};

}

#endif