1/*
2 Copyright (c) 2008 Volker Krause <vkrause@kde.org>
3
4 This library is free software; you can redistribute it and/or modify it
5 under the terms of the GNU Library General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or (at your
7 option) any later version.
8
9 This library is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12 License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18*/
19
20#ifndef AKONADI_PROTOCOLHELPER_P_H
21#define AKONADI_PROTOCOLHELPER_P_H
22
23#include <akonadi/cachepolicy.h>
24#include <akonadi/collection.h>
25#include <akonadi/collectionutils_p.h>
26#include <akonadi/item.h>
27#include <akonadi/itemfetchscope.h>
28#include <akonadi/sharedvaluepool_p.h>
29#include <akonadi/attributeentity.h>
30#include <akonadi/tag.h>
31
32#include <akonadi/private/imapparser_p.h>
33#include <akonadi/private/protocol_p.h>
34
35#include <boost/bind.hpp>
36#include <algorithm>
37
38namespace Akonadi {
39
40struct ProtocolHelperValuePool
41{
42 typedef Internal::SharedValuePool<QByteArray, QVector> FlagPool;
43 typedef Internal::SharedValuePool<QString, QVector> MimeTypePool;
44
45 FlagPool flagPool;
46 MimeTypePool mimeTypePool;
47 QHash<Collection::Id, Collection> ancestorCollections;
48};
49
50/**
51 @internal
52 Helper methods for converting between libakonadi objects and their protocol
53 representation.
54
55 @todo Add unit tests for this.
56 @todo Use exceptions for a useful error handling
57*/
58class ProtocolHelper
59{
60public:
61 /** Part namespaces. */
62 enum PartNamespace {
63 PartGlobal,
64 PartPayload,
65 PartAttribute
66 };
67
68 /**
69 Parse a cache policy definition.
70 @param data The input data.
71 @param policy The parsed cache policy.
72 @param start Start of the data, ie. postion after the label.
73 @returns Position in data after the cache policy description.
74 */
75 static int parseCachePolicy(const QByteArray &data, CachePolicy &policy, int start = 0);
76
77 /**
78 Convert a cache policy object into its protocol representation.
79 */
80 static QByteArray cachePolicyToByteArray(const CachePolicy &policy);
81
82 /**
83 Convert a ancestor chain from its protocol representation into an Entity object.
84 */
85 static void parseAncestors(const QByteArray &data, Entity *entity, int start = 0);
86
87 /**
88 Convert a ancestor chain from its protocol representation into an Entity object.
89
90 This method allows to pass a @p valuePool which acts as cache, so ancestor paths for the
91 same @p parentCollection don't have to be parsed twice.
92 */
93 static void parseAncestorsCached(const QByteArray &data, Entity *entity, Collection::Id parentCollection, ProtocolHelperValuePool *valuePool = 0, int start = 0);
94
95 /**
96 Parse a collection description.
97 @param data The input data.
98 @param collection The parsed collection.
99 @param start Start of the data.
100 @returns Position in data after the collection description.
101 */
102 static int parseCollection(const QByteArray &data, Collection &collection, int start = 0);
103
104 /**
105 Convert attributes to their protocol representation.
106 */
107 static QByteArray attributesToByteArray(const Entity &entity, bool ns = false);
108 static QByteArray attributesToByteArray(const AttributeEntity &entity, bool ns = false);
109
110 /**
111 Encodes part label and namespace.
112 */
113 static QByteArray encodePartIdentifier(PartNamespace ns, const QByteArray &label, int version = 0);
114
115 /**
116 Decode part label and namespace.
117 */
118 static QByteArray decodePartIdentifier(const QByteArray &data, PartNamespace &ns);
119
120 /**
121 Converts the given set of items into a protocol representation.
122 @throws A Akonadi::Exception if the item set contains items with missing/invalid identifiers.
123 */
124 template <typename T>
125 static QByteArray entitySetToByteArray(const QList<T> &_objects, const QByteArray &command)
126 {
127 if (_objects.isEmpty()) {
128 throw Exception("No objects specified");
129 }
130
131 typename T::List objects(_objects);
132
133 QByteArray rv;
134 std::sort(objects.begin(), objects.end(), boost::bind(&T::id, _1) < boost::bind(&T::id, _2));
135 if (objects.first().isValid()) {
136 // all items have a uid set
137 rv += " " AKONADI_CMD_UID " ";
138 if (!command.isEmpty()) {
139 rv += command;
140 rv += ' ';
141 }
142 QVector<typename T::Id> uids;
143 foreach (const T &object, objects) {
144 uids << object.id();
145 }
146 ImapSet set;
147 set.add(uids);
148 rv += set.toImapSequenceSet();
149 return rv;
150 }
151
152 // check if all items have a remote id
153 if (std::find_if(objects.constBegin(), objects.constEnd(),
154 boost::bind(&QString::isEmpty, boost::bind(&T::remoteId, _1)))
155 != objects.constEnd()) {
156 throw Exception("No remote identifier specified");
157 }
158
159 // check if we have RIDs or HRIDs
160 if (std::find_if(objects.constBegin(), objects.constEnd(),
161 !boost::bind(static_cast<bool (*)(const T &)>(&CollectionUtils::hasValidHierarchicalRID), _1))
162 == objects.constEnd() && objects.size() == 1) { // ### HRID sets are not yet specified
163 // HRIDs
164 rv += " " AKONADI_CMD_HRID " ";
165 if (!command.isEmpty()) {
166 rv += command;
167 rv += ' ';
168 }
169 rv += '(' + hierarchicalRidToByteArray(objects.first()) + ')';
170 return rv;
171 }
172
173 // RIDs
174 QList<QByteArray> rids;
175 foreach (const T &object, objects) {
176 rids << ImapParser::quote(object.remoteId().toUtf8());
177 }
178
179 rv += " " AKONADI_CMD_RID " ";
180 if (!command.isEmpty()) {
181 rv += command;
182 rv += ' ';
183 }
184 rv += '(';
185 rv += ImapParser::join(rids, " ");
186 rv += ')';
187 return rv;
188 }
189
190 static QByteArray entitySetToByteArray(const QList<Akonadi::Item> &_objects, const QByteArray &command);
191
192 static QByteArray tagSetToImapSequenceSet(const Akonadi::Tag::List &_objects);
193 static QByteArray tagSetToByteArray(const Akonadi::Tag::List &_objects, const QByteArray &command);
194
195
196 static QByteArray commandContextToByteArray(const Akonadi::Collection &collection, const Akonadi::Tag &tag,
197 const Item::List &requestedItems, const QByteArray &command);
198
199 /**
200 Converts the given object identifier into a protocol representation.
201 @throws A Akonadi::Exception if the item set contains items with missing/invalid identifiers.
202 */
203 template <typename T>
204 static QByteArray entityIdToByteArray(const T &object, const QByteArray &command)
205 {
206 return entitySetToByteArray(typename T::List() << object, command);
207 }
208
209 /**
210 Converts the given collection's hierarchical RID into a protocol representation.
211 Assumes @p col has a valid hierarchical RID, so check that before!
212 */
213 static QByteArray hierarchicalRidToByteArray(const Collection &col);
214
215 /**
216 Converts the HRID of the given item into an ASAP protocol representation.
217 Assumes @p item has a valid HRID.
218 */
219 static QByteArray hierarchicalRidToByteArray(const Item &item);
220
221 /**
222 Converts a given ItemFetchScope object into a protocol representation.
223 */
224 static QByteArray itemFetchScopeToByteArray(const ItemFetchScope &fetchScope);
225
226 /**
227 Parses a single line from an item fetch job result into an Item object.
228 */
229 static void parseItemFetchResult(const QList<QByteArray> &lineTokens, Item &item, ProtocolHelperValuePool *valuePool = 0);
230 static void parseTagFetchResult(const QList<QByteArray> &lineTokens, Tag &tag);
231
232 static QString akonadiStoragePath();
233 static QString absolutePayloadFilePath(const QString &fileName);
234
235 static bool streamPayloadToFile(const QByteArray &command, const QByteArray &data, QByteArray &error);
236
237 static QByteArray listPreference(Collection::ListPurpose purpose, Collection::ListPreference preference);
238 static QByteArray enabled(bool);
239 static QByteArray referenced(bool);
240};
241
242}
243
244#endif
245