Changes: Use Latin1 instead of Ascii as there is the chance that it's not real Ascii...
[qtcontacts-tracker:qtcontacts-tracker.git] / src / dao / subject.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the Qt Mobility Components.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "subject.h"
43 #include "conversion.h"
44 #include "logger.h"
45 #include "support.h"
46
47 ///////////////////////////////////////////////////////////////////////////////////////////////////
48
49 CUBI_USE_NAMESPACE_RESOURCES
50
51 ///////////////////////////////////////////////////////////////////////////////////////////////////
52
53 static QVariant
54 toVariant(const QUuid &uuid)
55 {
56     if (not uuid.isNull()) {
57         return uuid.toString();
58     }
59
60     return QVariant();
61 }
62
63 ///////////////////////////////////////////////////////////////////////////////////////////////////
64
65 bool
66 QTrackerContactSubject::isContentScheme(Scheme scheme)
67 {
68     switch(scheme) {
69     case None:
70     case Anonymous:
71         break;
72
73     case EmailAddress:
74     case Telepathy:
75     case Presence:
76         return true;
77     }
78
79     return false;
80 }
81
82
83 QVariant
84 QTrackerContactSubject::parseIri(Scheme scheme, const QString &iri, bool *ok)
85 {
86     switch(scheme) {
87     case None:
88     case Anonymous:
89         return toVariant(parseAnonymousIri(iri, ok));
90
91     case EmailAddress:
92         return parseEmailAddressIri(iri, ok);
93
94     case Telepathy:
95         return QVariant::fromValue(parseTelepathyIri(iri, ok));
96
97     case Presence:
98         return QVariant::fromValue(parsePresenceIri(iri, ok));
99     }
100
101     return qctPropagate(false, ok), QVariant();
102 }
103
104 QString
105 QTrackerContactSubject::makeIri(Scheme scheme, const QVariantList &values)
106 {
107     switch(scheme) {
108     case None:
109     case Anonymous:
110         if (1 != values.count()) {
111 #ifndef QT_NO_DEBUG
112             qWarning() << Q_FUNC_INFO << "invalid arguments for anonymous subject:" << values;
113 #endif // QT_NO_DEBUG
114             break;
115         }
116
117         return makeAnonymousIri(values.first().toString());
118
119     case EmailAddress:
120         if (1 != values.count()) {
121 #ifndef QT_NO_DEBUG
122             qWarning() << Q_FUNC_INFO << "invalid arguments for email address subject:" << values;
123 #endif // QT_NO_DEBUG
124             break;
125         }
126
127         return makeEmailAddressIri(values.first().toString());
128
129     case Telepathy:
130         if (2 == values.count()) {
131             return makeTelepathyIri(values[0].toString(), values[1].toString());
132         }
133
134         if (1 == values.count()) {
135             return makeTelepathyIri(values.first().toString());
136         }
137
138 #ifndef QT_NO_DEBUG
139         qWarning() << Q_FUNC_INFO << "invalid arguments for online account subject:" << values;
140 #endif // QT_NO_DEBUG
141         break;
142
143     case Presence:
144         if (2 == values.count()) {
145             return makePresenceIri(values[0].toString(), values[1].toString());
146         }
147
148         if (1 == values.count()) {
149             return makePresenceIri(values.first().toString());
150         }
151
152 #ifndef QT_NO_DEBUG
153         qWarning() << Q_FUNC_INFO << "invalid arguments for presence subject:" << values;
154 #endif // QT_NO_DEBUG
155         break;
156     }
157
158     return QString();
159 }
160
161 ////////////////////////////////////////////////////////////////////////////////////////////////////
162
163 QUuid
164 parseAnonymousIri(const QString &iri, bool *ok)
165 {
166     static const QString prefix(QLatin1String("urn:uuid:"));
167     QUuid uuid;
168
169     if (iri.startsWith(prefix)) {
170         const QString suffix(iri.mid(prefix.length()));
171         const QString value(QUrl::fromPercentEncoding(suffix.toLatin1()));
172         uuid = QUuid(QLatin1Char('{') + value + QLatin1Char('}'));
173     }
174
175     return qctPropagate(not uuid.isNull(), ok), uuid;
176 }
177
178 static QString
179 parseTextIri(const QString &prefix, const QString &iri, bool *ok)
180 {
181     QString value;
182
183     if (iri.startsWith(prefix)) {
184         const QString suffix(iri.mid(prefix.length()));
185         value = QUrl::fromPercentEncoding(suffix.toLatin1());
186     }
187
188     return qctPropagate(not value.isEmpty(), ok), value;
189 }
190
191 QString
192 parseEmailAddressIri(const QString &iri, bool *ok)
193 {
194     static const QString prefix(QLatin1String("mailto:"));
195     return parseTextIri(prefix, iri, ok);
196 }
197
198 QString
199 parseTelepathyIri(const QString &iri, bool *ok)
200 {
201     static const QString prefix(QLatin1String("telepathy:"));
202     return parseTextIri(prefix, iri, ok);
203 }
204
205 QString
206 parsePresenceIri(const QString &iri, bool *ok)
207 {
208     static const QString prefix(QLatin1String("presence:"));
209     return parseTextIri(prefix, iri, ok);
210 }
211
212 ///////////////////////////////////////////////////////////////////////////////////////////////////
213
214 static const QByteArray phoneNumberSpecials("+");
215 static const QByteArray emailAddressSpecials("@");
216 static const QByteArray accountPathSpecials("/");
217 static const QByteArray imAddressSpecials("@");
218
219 static QString
220 urlEncoded(const QString &text,
221            const QByteArray &exclude = QByteArray(),
222            const QByteArray &include = QByteArray(" "))
223 {
224     const QByteArray encodedText = QUrl::toPercentEncoding(text.trimmed(), exclude, include);
225     return QString::fromLatin1(encodedText.data(), encodedText.length());
226 }
227
228 ///////////////////////////////////////////////////////////////////////////////////////////////////
229
230 QString
231 makeAnonymousIri(const QUuid &uuid)
232 {
233     if (uuid.isNull()) {
234         return QString();
235     }
236
237     static const QString pattern(QLatin1String("urn:uuid:%1"));
238     return pattern.arg(qctUuidString(uuid));
239 }
240
241 QString
242 makeEmailAddressIri(const QString &emailAddress)
243 {
244     static const QString pattern(QLatin1String("mailto:%1"));
245     return pattern.arg(urlEncoded(emailAddress, emailAddressSpecials));
246 }
247
248 QString
249 makeTelepathyIri(const QString &accountPath, const QString &imAddress)
250 {
251     if (not accountPath.startsWith(QLatin1Char('/'))) {
252 #ifndef QT_NO_DEBUG
253         qctWarn(QString::fromLatin1("Invalid account path: %1").arg(accountPath));
254 #endif // QT_NO_DEBUG
255         return QString();
256     }
257
258     if (imAddress.isEmpty()) {
259         static const QString pattern(QLatin1String("telepathy:%1"));
260         return pattern.arg(urlEncoded(accountPath, accountPathSpecials));
261     }
262
263     static const QString pattern(QLatin1String("telepathy:%1!%2"));
264     return pattern.arg(urlEncoded(accountPath, accountPathSpecials),
265                        urlEncoded(imAddress, imAddressSpecials));
266 }
267
268 QString
269 makeTelepathyIri(const QString &connectionPath)
270 {
271     const int separatorIndex = connectionPath.indexOf(QLatin1Char('!'));
272
273     if (separatorIndex >= 0) {
274         return makeTelepathyIri(connectionPath.left(separatorIndex),
275                                 connectionPath.mid(separatorIndex + 1));
276     }
277
278     return makeTelepathyIri(connectionPath, QString());
279 }
280
281 QString
282 makePresenceIri(const QString &accountPath, const QString &imAddress)
283 {
284     // Notice to asymmetry with makeTelepathyIri():
285     // - "telepathy:" IRIs can point to accounts and to connections
286     // - "presence:" IRIs will always point to connections
287
288     if (not accountPath.startsWith(QLatin1Char('/'))) {
289 #ifndef QT_NO_DEBUG
290         qctWarn(QString::fromLatin1("Invalid account path: %1").arg(accountPath));
291 #endif // QT_NO_DEBUG
292         return QString();
293     }
294
295     if (imAddress.isEmpty()) {
296 #ifndef QT_NO_DEBUG
297         qctWarn(QString::fromLatin1("IM address cannot be empty: %1").arg(accountPath));
298 #endif // QT_NO_DEBUG
299         return QString();
300     }
301
302
303     static const QString pattern(QLatin1String("presence:%1!%2"));
304     return pattern.arg(urlEncoded(accountPath, accountPathSpecials),
305                        urlEncoded(imAddress, imAddressSpecials));
306 }
307
308 QString
309 makePresenceIri(const QString &connectionPath)
310 {
311     const int separatorIndex = connectionPath.indexOf(QLatin1Char('!'));
312
313     if (-1 == separatorIndex) {
314 #ifndef QT_NO_DEBUG
315         qctWarn(QString::fromLatin1("Invalid connection path").arg(connectionPath));
316 #endif // QT_NO_DEBUG
317         return QString();
318     }
319
320     return makePresenceIri(connectionPath.left(separatorIndex),
321                            connectionPath.mid(separatorIndex + 1));
322 }