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 | |
38 | namespace Akonadi { |
39 | |
40 | struct 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 | */ |
58 | class ProtocolHelper |
59 | { |
60 | public: |
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 | |