|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 "qcontactmaemo5backend_p.h" |
|
43 #include "qcontactabook_p.h" |
|
44 |
|
45 #include <QEventLoop> |
|
46 #include <libebook/e-book-util.h> |
|
47 |
|
48 |
|
49 /* Error handling Macros */ |
|
50 #define FATAL_IF_ERROR(x) if(x) { \ |
|
51 QString message(x->message); \ |
|
52 g_error_free(x); \ |
|
53 qFatal(qPrintable(message)); \ |
|
54 } |
|
55 #define WARNING_IF_ERROR(x) if(x) { \ |
|
56 QString message(x->message); \ |
|
57 g_error_free(x); \ |
|
58 qWarning(qPrintable(message)); \ |
|
59 } |
|
60 |
|
61 /* Casting Macros */ |
|
62 #define A_CONTACT(x) reinterpret_cast<OssoABookContact*>(x) |
|
63 #define A_ROSTER(x) reinterpret_cast<OssoABookRoster*>(x) |
|
64 #define CONST_CHAR(x) static_cast<const char*>(x) |
|
65 #define FREE(x) free((void*)x) |
|
66 |
|
67 struct cbSharedData{ |
|
68 QContactIDsHash* hash; |
|
69 QContactABook *that; |
|
70 }; |
|
71 |
|
72 struct jobSharedData{ |
|
73 QContactABook* that; |
|
74 bool *result; |
|
75 char *uid; |
|
76 }; |
|
77 |
|
78 /* QContactABook */ |
|
79 QContactABook::QContactABook(QObject* parent) :QObject(parent), m_cbSD(0), m_deleteJobSD(0), m_saveJobSD(0) |
|
80 { |
|
81 //Initialize QContactDetail context list |
|
82 initAddressBook(); |
|
83 } |
|
84 |
|
85 QContactABook::~QContactABook() |
|
86 { |
|
87 OssoABookAggregator *roster = reinterpret_cast<OssoABookAggregator*>(m_abookAgregator); |
|
88 if (g_signal_handler_is_connected(roster, m_contactAddedHandlerId)) |
|
89 g_signal_handler_disconnect(roster, m_contactAddedHandlerId); |
|
90 if (g_signal_handler_is_connected(roster, m_contactChangedHandlerId)) |
|
91 g_signal_handler_disconnect(roster, m_contactChangedHandlerId); |
|
92 if (g_signal_handler_is_connected(roster, m_contactRemovedHandlerId)) |
|
93 g_signal_handler_disconnect(roster, m_contactRemovedHandlerId); |
|
94 |
|
95 // XXX FIXME: memory leak? |
|
96 //g_object_unref(m_abookAgregator); |
|
97 delete m_cbSD; |
|
98 m_cbSD = 0; |
|
99 delete m_deleteJobSD; |
|
100 m_deleteJobSD = 0; |
|
101 delete m_saveJobSD; |
|
102 m_saveJobSD = 0; |
|
103 } |
|
104 |
|
105 static void contactsAddedCB(OssoABookRoster *roster, OssoABookContact **contacts, gpointer data) |
|
106 { |
|
107 QCM5_DEBUG << "CONTACT ADDED"; |
|
108 Q_UNUSED(roster) |
|
109 |
|
110 cbSharedData* d = static_cast<cbSharedData*>(data); |
|
111 if (!d){ |
|
112 qWarning() << "d has been deleted"; |
|
113 return; |
|
114 } |
|
115 |
|
116 OssoABookContact **p; |
|
117 QList<QContactLocalId> contactIds; |
|
118 |
|
119 for (p = contacts; *p; ++p) { |
|
120 if (osso_abook_contact_is_roster_contact(*p)) |
|
121 continue; |
|
122 |
|
123 // Add a new localID to the local ID hash |
|
124 const char* uid = CONST_CHAR(e_contact_get_const(E_CONTACT(*p), E_CONTACT_UID)); |
|
125 QContactLocalId id = d->hash->append(uid); |
|
126 |
|
127 if (id) |
|
128 contactIds << id; |
|
129 } |
|
130 d->that->_contactsAdded(contactIds); |
|
131 } |
|
132 |
|
133 static void contactsChangedCB(OssoABookRoster *roster, OssoABookContact **contacts, gpointer data) |
|
134 { |
|
135 QCM5_DEBUG << "CONTACT CHANGED"; |
|
136 Q_UNUSED(roster) |
|
137 |
|
138 cbSharedData* d = static_cast<cbSharedData*>(data); |
|
139 if (!d){ |
|
140 qWarning() << "d has been deleted"; |
|
141 return; |
|
142 } |
|
143 |
|
144 OssoABookContact **p; |
|
145 QList<QContactLocalId> contactIds; |
|
146 |
|
147 for (p = contacts; *p; ++p) { |
|
148 if (osso_abook_contact_is_roster_contact(*p)) |
|
149 continue; |
|
150 |
|
151 const char* uid = CONST_CHAR(e_contact_get_const(E_CONTACT(*p), E_CONTACT_UID)); |
|
152 QContactLocalId id = d->hash->find(uid); |
|
153 //FREE(uid); |
|
154 if (id) |
|
155 contactIds << id; |
|
156 } |
|
157 d->that->_contactsChanged(contactIds); |
|
158 } |
|
159 |
|
160 static void contactsRemovedCB(OssoABookRoster *roster, const char **ids, gpointer data) |
|
161 { |
|
162 QCM5_DEBUG << "CONTACT REMOVED"; |
|
163 Q_UNUSED(roster) |
|
164 |
|
165 cbSharedData* d = static_cast<cbSharedData*>(data); |
|
166 if (!d){ |
|
167 qWarning() << "d has been deleted"; |
|
168 return; |
|
169 } |
|
170 |
|
171 const char **p; |
|
172 QList<QContactLocalId> contactIds; |
|
173 |
|
174 for (p = ids; *p; ++p) { |
|
175 QContactLocalId id = d->hash->take(*p); |
|
176 QCM5_DEBUG << "Contact" << id << "has been removed"; |
|
177 if (id) |
|
178 contactIds << id; |
|
179 } |
|
180 |
|
181 d->that->_contactsRemoved(contactIds); |
|
182 } |
|
183 |
|
184 void QContactABook::initAddressBook(){ |
|
185 /* Open AddressBook */ |
|
186 GError *gError = NULL; |
|
187 OssoABookRoster* roster = NULL; |
|
188 |
|
189 roster = osso_abook_aggregator_get_default(&gError); |
|
190 FATAL_IF_ERROR(gError) |
|
191 |
|
192 osso_abook_waitable_run((OssoABookWaitable *) roster, g_main_context_default(), &gError); |
|
193 FATAL_IF_ERROR(gError) |
|
194 |
|
195 if (!osso_abook_waitable_is_ready ((OssoABookWaitable *) roster, &gError)) |
|
196 FATAL_IF_ERROR(gError) |
|
197 |
|
198 m_abookAgregator = reinterpret_cast<OssoABookAggregator*>(roster); |
|
199 |
|
200 /* Initialize local Id Hash */ |
|
201 initLocalIdHash(); |
|
202 |
|
203 /* Initialize callbacks shared data */ |
|
204 m_cbSD = new cbSharedData; |
|
205 m_cbSD->hash = &m_localIds; |
|
206 m_cbSD->that = this; |
|
207 |
|
208 /* Setup signals */ |
|
209 m_contactAddedHandlerId = g_signal_connect(roster, "contacts-added", |
|
210 G_CALLBACK (contactsAddedCB), m_cbSD); |
|
211 m_contactChangedHandlerId = g_signal_connect(roster, "contacts-changed", |
|
212 G_CALLBACK (contactsChangedCB), m_cbSD); |
|
213 m_contactRemovedHandlerId = g_signal_connect(roster, "contacts-removed", |
|
214 G_CALLBACK (contactsRemovedCB), m_cbSD); |
|
215 |
|
216 #if 0 |
|
217 //TEST List supported fields |
|
218 EBook *book = NULL; |
|
219 GList *l; |
|
220 book = osso_abook_roster_get_book(roster); |
|
221 e_book_get_supported_fields (book, &l, NULL); |
|
222 while (l) { |
|
223 qDebug() << "SUPPORTED FIELD" << (const char*)l->data; |
|
224 l = l->next; |
|
225 } |
|
226 g_list_free(l); |
|
227 #endif |
|
228 } |
|
229 |
|
230 /*! Fill LocalId Hash associating an internal QContactLocalId to any |
|
231 * master contact ID. |
|
232 * NOTE: master contact IDs are string like "1" or "osso-abook-tmc1". |
|
233 */ |
|
234 void QContactABook::initLocalIdHash() |
|
235 { |
|
236 GList *contactList = NULL; |
|
237 GList *node; |
|
238 |
|
239 contactList = osso_abook_aggregator_list_master_contacts(m_abookAgregator); |
|
240 |
|
241 if (!contactList) { |
|
242 qWarning() << "There are no Master contacts. LocalId hash is empty."; |
|
243 return; |
|
244 } |
|
245 |
|
246 for (node = contactList; node != NULL; node = g_list_next (node)) { |
|
247 EContact *contact = E_CONTACT(node->data); |
|
248 const char* data = CONST_CHAR(e_contact_get_const(contact, E_CONTACT_UID)); |
|
249 QByteArray eContactUID(data); |
|
250 //FREE(data); |
|
251 m_localIds << eContactUID; //FIXME MemLeak |
|
252 QCM5_DEBUG << "eContactID " << eContactUID << "has been stored in m_localIDs with key" << m_localIds[eContactUID]; |
|
253 |
|
254 // Useful for debugging. |
|
255 if (QCM5_DEBUG_ENABLED) e_vcard_dump_structure((EVCard*)contact); |
|
256 } |
|
257 |
|
258 g_list_free(contactList); |
|
259 } |
|
260 |
|
261 QList<QContactLocalId> QContactABook::contactIds(const QContactFilter& filter, const QList<QContactSortOrder>& sortOrders, QContactManager::Error* error) const |
|
262 { |
|
263 QList<QContactLocalId> rtn; |
|
264 |
|
265 /* Sorting */ |
|
266 //NOTE Native sorting is possible thanks to g_list_sort. |
|
267 // It's limited just to one filter. |
|
268 // Multi filters support need non native sorting. |
|
269 // Native filtering needs a lot of coding since we need |
|
270 // detailDefinitionName * detailFieldName functions |
|
271 // to compare couple of contacts |
|
272 if (sortOrders.count()){ |
|
273 QCM5_DEBUG << "Sorting..."; |
|
274 // We don't need |
|
275 // Fill Ids |
|
276 QList<QContactLocalId> Ids; |
|
277 { |
|
278 QList<QContactSortOrder> so; |
|
279 QContactManager::Error e; |
|
280 Ids = contactIds(filter, so, &e); |
|
281 } |
|
282 |
|
283 // Fill Contact List |
|
284 QList<QContact> contacts; |
|
285 foreach(QContactLocalId id, Ids){ |
|
286 QContact *c; |
|
287 QContactManager::Error e; |
|
288 c = getQContact(id, &e); |
|
289 if (e == QContactManager::NoError) |
|
290 contacts << *c; |
|
291 else |
|
292 *error = e; |
|
293 } |
|
294 |
|
295 // Non native sorting |
|
296 return QContactManagerEngine::sortContacts(contacts, sortOrders); |
|
297 } |
|
298 |
|
299 /* Matching action filter */ |
|
300 //NOTE The code was not really tested */ |
|
301 if(filter.type() == QContactFilter::ActionFilter){ |
|
302 QContactActionFilter af(filter); |
|
303 /* This looks a bit strange for me */ |
|
304 QList<QContactActionDescriptor> descriptors = QContactAction::actionDescriptors(af.actionName(), af.vendorName(), af.implementationVersion()); |
|
305 |
|
306 GList *masterContacts = osso_abook_aggregator_list_master_contacts(m_abookAgregator); |
|
307 for(; masterContacts; ){ |
|
308 OssoABookContact *masterContact = A_CONTACT(masterContacts->data); |
|
309 bool match = contactActionsMatch(masterContact, descriptors); |
|
310 if(!match) { |
|
311 GList *rosterContacts = osso_abook_contact_get_roster_contacts(masterContact); |
|
312 for(; rosterContacts && !match; ){ |
|
313 OssoABookContact *rosterContact = A_CONTACT(rosterContacts->data); |
|
314 match = contactActionsMatch(rosterContact, descriptors); |
|
315 rosterContacts = g_list_delete_link(rosterContacts, rosterContacts); |
|
316 } |
|
317 g_list_free(rosterContacts); |
|
318 } |
|
319 if(match){ |
|
320 EContact *contact = E_CONTACT(masterContact); |
|
321 const char* data = CONST_CHAR(e_contact_get_const(contact, E_CONTACT_UID)); |
|
322 QByteArray localId(data); |
|
323 m_localIds << localId; |
|
324 rtn.append(m_localIds[localId]); |
|
325 QCM5_DEBUG << "eContactID " << localId << "has been stored in m_localIDs with key" << m_localIds[localId]; |
|
326 } |
|
327 masterContacts = g_list_delete_link(masterContacts, masterContacts); |
|
328 } |
|
329 *error = QContactManager::NoError; |
|
330 return rtn; |
|
331 } |
|
332 |
|
333 EBookQuery* query = convert(filter); |
|
334 |
|
335 GList* l = osso_abook_aggregator_find_contacts(m_abookAgregator, query); |
|
336 if (query) |
|
337 e_book_query_unref(query); |
|
338 |
|
339 while (l){ |
|
340 EContact *contact = E_CONTACT(l->data); |
|
341 const char* data = CONST_CHAR(e_contact_get_const(contact, E_CONTACT_UID)); |
|
342 QByteArray localId(data); |
|
343 m_localIds << localId; |
|
344 rtn.append(m_localIds[localId]); |
|
345 QCM5_DEBUG << "eContactID " << localId << "has been stored in m_localIDs with key" << m_localIds[localId]; |
|
346 l = g_list_delete_link(l, l); |
|
347 } |
|
348 |
|
349 *error = QContactManager::NoError; |
|
350 return rtn; |
|
351 } |
|
352 |
|
353 QContact* QContactABook::getQContact(const QContactLocalId& contactId, QContactManager::Error* error) const |
|
354 { |
|
355 QContact *rtn; |
|
356 OssoABookContact* aContact = getAContact(contactId); |
|
357 if (!aContact) { |
|
358 qWarning() << "Unable to get a valid AContact"; |
|
359 *error = QContactManager::DoesNotExistError; |
|
360 return new QContact; |
|
361 } |
|
362 |
|
363 //Convert aContact => qContact |
|
364 rtn = convert(E_CONTACT(aContact)); |
|
365 return rtn; |
|
366 } |
|
367 |
|
368 static void delContactCB(EBook *book, EBookStatus status, gpointer closure) |
|
369 { |
|
370 Q_UNUSED(book); |
|
371 QCM5_DEBUG << "Contact Removed"; |
|
372 |
|
373 jobSharedData *sd = static_cast<jobSharedData*>(closure); |
|
374 if (!sd) |
|
375 return; |
|
376 |
|
377 *sd->result = (status != E_BOOK_ERROR_OK && |
|
378 status != E_BOOK_ERROR_CONTACT_NOT_FOUND) ? false : true; |
|
379 sd->that->_jobRemovingCompleted(); |
|
380 } |
|
381 |
|
382 //### FIXME error is not managed |
|
383 bool QContactABook::removeContact(const QContactLocalId& contactId, QContactManager::Error* error) |
|
384 { |
|
385 Q_UNUSED(error); |
|
386 QMutexLocker locker(&m_delContactMutex); |
|
387 |
|
388 bool ok = false; |
|
389 |
|
390 OssoABookRoster *roster = A_ROSTER(m_abookAgregator); |
|
391 EBook *book = osso_abook_roster_get_book(roster); |
|
392 OssoABookContact *aContact = getAContact(contactId); |
|
393 if (!OSSO_ABOOK_IS_CONTACT(aContact)){ |
|
394 qWarning() << "aCtontact is not a valid ABook contact"; |
|
395 return false; |
|
396 } |
|
397 |
|
398 // ASync => Sync |
|
399 QEventLoop loop; |
|
400 connect(this, SIGNAL(jobRemovingCompleted()), &loop, SLOT(quit())); |
|
401 |
|
402 // Prepare shared data |
|
403 if (m_deleteJobSD){ |
|
404 delete m_deleteJobSD; |
|
405 m_deleteJobSD = 0; |
|
406 } |
|
407 m_deleteJobSD = new jobSharedData; |
|
408 m_deleteJobSD->that = this; |
|
409 m_deleteJobSD->result = &ok; |
|
410 |
|
411 //Remove photos |
|
412 EContactPhoto *photo = NULL; |
|
413 GFile *file = NULL; |
|
414 photo = (EContactPhoto*) e_contact_get(E_CONTACT (aContact), E_CONTACT_PHOTO); |
|
415 if (photo) { |
|
416 if (photo->type == E_CONTACT_PHOTO_TYPE_URI && photo->data.uri) { |
|
417 file = g_file_new_for_uri(photo->data.uri); |
|
418 g_file_delete(file, NULL, NULL); |
|
419 g_object_unref (file); |
|
420 } |
|
421 e_contact_photo_free (photo); |
|
422 } |
|
423 |
|
424 //Remove all roster contacts from their roster |
|
425 GList* rosterContacts = NULL; |
|
426 rosterContacts = osso_abook_contact_get_roster_contacts(aContact); |
|
427 const char *masterUid = CONST_CHAR(e_contact_get_const(E_CONTACT(aContact), E_CONTACT_UID)); |
|
428 while(rosterContacts){ |
|
429 OssoABookContact *rosterContact = A_CONTACT(rosterContacts->data); |
|
430 osso_abook_contact_reject_for_uid(rosterContact, masterUid, NULL); |
|
431 rosterContacts = rosterContacts->next; |
|
432 } |
|
433 |
|
434 // Remove contact |
|
435 e_book_async_remove_contact(book, E_CONTACT(aContact), |
|
436 delContactCB, m_deleteJobSD); |
|
437 |
|
438 loop.exec(QEventLoop::AllEvents|QEventLoop::WaitForMoreEvents); |
|
439 |
|
440 return ok; |
|
441 } |
|
442 |
|
443 static void commitContactCB(EBook* book, EBookStatus status, gpointer user_data) |
|
444 { |
|
445 Q_UNUSED(book) |
|
446 jobSharedData *sd = static_cast<jobSharedData*>(user_data); |
|
447 |
|
448 *sd->result = (status == E_BOOK_ERROR_OK) ? true : false; |
|
449 sd->that->_jobSavingCompleted(); |
|
450 } |
|
451 |
|
452 static void addContactCB(EBook* book, EBookStatus status, const char *uid, gpointer user_data) |
|
453 { |
|
454 jobSharedData *sd = static_cast<jobSharedData*>(user_data); |
|
455 if (uid) |
|
456 sd->uid = strdup(uid); |
|
457 |
|
458 //osso_abook_contact_set_roster(OssoABookContact *contact, OssoABookRoster *roster) |
|
459 commitContactCB(book, status, user_data); |
|
460 } |
|
461 |
|
462 bool QContactABook::saveContact(QContact* contact, QContactManager::Error* error) |
|
463 { |
|
464 QMutexLocker locker(&m_saveContactMutex); |
|
465 |
|
466 if (!contact) { |
|
467 *error = QContactManager::BadArgumentError; |
|
468 return false; |
|
469 } |
|
470 |
|
471 bool ok = false; |
|
472 |
|
473 OssoABookContact *aContact = NULL; |
|
474 const char *uid; |
|
475 EBook *book; |
|
476 { |
|
477 OssoABookRoster* roster = reinterpret_cast<OssoABookRoster*>(m_abookAgregator); |
|
478 book = osso_abook_roster_get_book(roster); |
|
479 } |
|
480 |
|
481 // Conver QContact to AContact |
|
482 aContact = convert(contact); |
|
483 if (!aContact){ |
|
484 *error = QContactManager::UnspecifiedError; |
|
485 return false; |
|
486 } |
|
487 |
|
488 // ASync => Sync |
|
489 QEventLoop loop; |
|
490 connect(this, SIGNAL(jobSavingCompleted()), &loop, SLOT(quit())); |
|
491 |
|
492 // Prepare shared data |
|
493 if (m_saveJobSD){ |
|
494 delete m_saveJobSD; |
|
495 m_saveJobSD = 0; |
|
496 } |
|
497 m_saveJobSD = new jobSharedData; |
|
498 m_saveJobSD->that = this; |
|
499 m_saveJobSD->result = &ok; |
|
500 |
|
501 // Add/Commit the contact |
|
502 uid = CONST_CHAR(e_contact_get_const(E_CONTACT (aContact), E_CONTACT_UID)); |
|
503 if (uid) { |
|
504 osso_abook_contact_async_commit(aContact, book, commitContactCB, m_saveJobSD); |
|
505 } else { |
|
506 osso_abook_contact_async_add(aContact, book, addContactCB, m_saveJobSD); |
|
507 } |
|
508 |
|
509 loop.exec(QEventLoop::AllEvents|QEventLoop::WaitForMoreEvents); |
|
510 |
|
511 // set the id of the contact. |
|
512 QContactId cId; |
|
513 cId.setLocalId(m_localIds[m_saveJobSD->uid]); |
|
514 contact->setId(cId); |
|
515 //free(m_saveJobSD->uid); |
|
516 |
|
517 return ok; |
|
518 } |
|
519 |
|
520 QContactLocalId QContactABook::selfContactId(QContactManager::Error* errors) const |
|
521 { |
|
522 QContactLocalId id; |
|
523 EContact *self = E_CONTACT(osso_abook_self_contact_get_default()); |
|
524 if (self) { |
|
525 *errors = QContactManager::NoError; |
|
526 const char* data = CONST_CHAR(e_contact_get_const(self, E_CONTACT_UID)); |
|
527 const QByteArray eContactUID(data); |
|
528 QContactLocalId localId = m_localIds[eContactUID]; |
|
529 if (localId) |
|
530 id = localId; |
|
531 else { |
|
532 m_localIds << eContactUID; //FIXME MemLeak |
|
533 id = m_localIds[eContactUID]; |
|
534 QCM5_DEBUG << "eContactID " << eContactUID << "has been stored in m_localIDs with key" << id; |
|
535 } |
|
536 } else { |
|
537 qWarning() << "Cannot find self contact"; |
|
538 *errors = QContactManager::DoesNotExistError; |
|
539 id = 0; |
|
540 } |
|
541 g_object_unref(self); |
|
542 return id; |
|
543 } |
|
544 |
|
545 bool QContactABook::contactActionsMatch(OssoABookContact *contact, QList<QContactActionDescriptor> descriptors) const |
|
546 { |
|
547 OssoABookCapsFlags capsFlags = osso_abook_caps_get_capabilities(OSSO_ABOOK_CAPS(contact)); |
|
548 |
|
549 if(capsFlags & OSSO_ABOOK_CAPS_NONE) |
|
550 return false; |
|
551 |
|
552 /* ActionNames could be incorrect */ |
|
553 OssoABookCapsFlags actionFlags = OSSO_ABOOK_CAPS_NONE; |
|
554 for(int i = 0; i < descriptors.size(); i++){ |
|
555 QString actionName = descriptors.at(i).actionName(); |
|
556 QCM5_DEBUG << actionName; |
|
557 if(!actionName.compare("Phone")) |
|
558 actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_PHONE); |
|
559 else if(!actionName.compare("Voice")) |
|
560 actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_VOICE); |
|
561 else if(!actionName.compare("SendEmail")) |
|
562 actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_EMAIL); |
|
563 else if(!actionName.compare("Chat")) |
|
564 actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_CHAT); |
|
565 else if(!actionName.compare("ChatAdditional")) |
|
566 actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_CHAT_ADDITIONAL); |
|
567 else if(!actionName.compare("VoiceAdditional")) |
|
568 actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_VOICE_ADDITIONAL); |
|
569 else if(!actionName.compare("Video")) |
|
570 actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_VIDEO); |
|
571 else if(!actionName.compare("Addressbook")) |
|
572 actionFlags = (OssoABookCapsFlags)(actionFlags | OSSO_ABOOK_CAPS_ADDRESSBOOK); |
|
573 } |
|
574 return ((actionFlags & capsFlags) == actionFlags); |
|
575 } |
|
576 |
|
577 EBookQuery* QContactABook::convert(const QContactFilter& filter) const |
|
578 { |
|
579 EBookQuery* query = NULL; |
|
580 |
|
581 switch(filter.type()){ |
|
582 case QContactFilter::DefaultFilter: |
|
583 { |
|
584 QCM5_DEBUG << "QContactFilter::DefaultFilter"; |
|
585 query = e_book_query_any_field_contains(""); //Match all contacts |
|
586 } break; |
|
587 case QContactFilter::LocalIdFilter: |
|
588 { |
|
589 QCM5_DEBUG << "LocalIdFilter"; |
|
590 const QContactLocalIdFilter f(filter); |
|
591 QList<QContactLocalId> ids = f.ids(); |
|
592 if (ids.isEmpty()) |
|
593 return NULL; |
|
594 |
|
595 query= NULL; |
|
596 foreach(const QContactLocalId id, ids){ |
|
597 EBookQuery* q = NULL; |
|
598 |
|
599 // Looking for the eContact local id inside the localId hash |
|
600 const char* eContactId = m_localIds[id]; |
|
601 if (!eContactId[0]) |
|
602 return NULL; |
|
603 |
|
604 q = e_book_query_field_test(E_CONTACT_UID, E_BOOK_QUERY_IS, eContactId); |
|
605 if (!q) |
|
606 continue; |
|
607 if (query) |
|
608 query = e_book_query_orv(query, q, NULL); |
|
609 else |
|
610 query = q; |
|
611 } |
|
612 } break; |
|
613 case QContactFilter::ContactDetailFilter: |
|
614 { |
|
615 QCM5_DEBUG << "ContactDetailFilter"; |
|
616 const QContactDetailFilter f(filter); |
|
617 QString queryStr; |
|
618 if (!f.value().isValid()) |
|
619 return NULL; |
|
620 switch (f.matchFlags()){ |
|
621 case QContactFilter::MatchContains: queryStr = "contains"; break; |
|
622 case QContactFilter::MatchFixedString: |
|
623 case QContactFilter::MatchCaseSensitive: |
|
624 case QContactFilter::MatchExactly: queryStr = "is"; break; |
|
625 case QContactFilter::MatchStartsWith: queryStr = "beginswith"; break; |
|
626 case QContactFilter::MatchEndsWith: queryStr = "endswith"; break; |
|
627 default: |
|
628 queryStr = "contains"; |
|
629 qWarning() << "Match flag not supported"; |
|
630 } |
|
631 static QHash<QString,QString> hash; |
|
632 if (hash.isEmpty()){ |
|
633 hash[QContactAddress::DefinitionName] = "address"; |
|
634 hash[QContactBirthday::DefinitionName] = "birth-date"; |
|
635 hash[QContactDisplayLabel::DefinitionName] = "full-name"; //hack |
|
636 hash[QContactEmailAddress::DefinitionName] = "email"; |
|
637 hash[QContactName::DefinitionName] = "full-name"; |
|
638 hash[QContactNickname::DefinitionName] = "nickname"; |
|
639 hash[QContactNote::DefinitionName] = "note"; |
|
640 hash[QContactOrganization::DefinitionName] = "title"; |
|
641 hash[QContactPhoneNumber::DefinitionName] = "phone"; |
|
642 hash[QContactUrl::DefinitionName] = "homepage-url"; |
|
643 } |
|
644 |
|
645 QString eDetail = hash[f.detailDefinitionName()]; |
|
646 if (eDetail.isEmpty()){ |
|
647 qWarning() << "Unable to found an ebook detail for " << f.detailDefinitionName(); |
|
648 return NULL; |
|
649 } |
|
650 queryStr = queryStr + " \"" + eDetail + "\" \"" + f.value().toString() + "\""; |
|
651 query = e_book_query_from_string(qPrintable(queryStr)); |
|
652 } break; |
|
653 case QContactFilter::ActionFilter: |
|
654 QCM5_DEBUG << "ActionFilter"; //eQuery doesn't support ActionFilter |
|
655 break; |
|
656 case QContactFilter::IntersectionFilter: |
|
657 { |
|
658 QCM5_DEBUG << "IntersectionFilter"; |
|
659 const QContactIntersectionFilter f(filter); |
|
660 const QList<QContactFilter> fs= f.filters(); |
|
661 QContactFilter i; |
|
662 foreach(i, fs){ |
|
663 EBookQuery* q = convert(i); |
|
664 if (!q){ |
|
665 qWarning() << "Query is null"; |
|
666 continue; |
|
667 } |
|
668 if (query) |
|
669 query = e_book_query_andv(query, q, NULL); |
|
670 else |
|
671 query = q; |
|
672 } |
|
673 } break; |
|
674 case QContactFilter::UnionFilter: |
|
675 { |
|
676 QCM5_DEBUG << "UnionFilter"; |
|
677 const QContactUnionFilter f(filter); |
|
678 const QList<QContactFilter> fs= f.filters(); |
|
679 QContactFilter i; |
|
680 foreach(i, fs){ |
|
681 EBookQuery* q = convert(i); |
|
682 if (!q){ |
|
683 qWarning() << "Query is null"; |
|
684 continue; |
|
685 } |
|
686 if (query) |
|
687 query = e_book_query_orv(query, q, NULL); |
|
688 else |
|
689 query = q; |
|
690 } |
|
691 } break; |
|
692 case QContactFilter::InvalidFilter: |
|
693 { |
|
694 QCM5_DEBUG << "InvalidFilter"; |
|
695 query = e_book_query_from_string("(is \"id\" \"-1\")"); |
|
696 } break; |
|
697 default: |
|
698 QCM5_DEBUG << "Filter not supported"; |
|
699 } |
|
700 |
|
701 //Debugging |
|
702 const char *queryString = e_book_query_to_string(query); |
|
703 QCM5_DEBUG << "QUERY" << queryString; |
|
704 FREE(queryString); |
|
705 |
|
706 return query; |
|
707 } |
|
708 |
|
709 QContact* QContactABook::convert(EContact *eContact) const |
|
710 { |
|
711 QContact *contact = new QContact(); |
|
712 QList<QContactDetail*> detailList; |
|
713 |
|
714 /* Id */ |
|
715 contact->setId(getContactId(eContact)); |
|
716 |
|
717 /* Address */ |
|
718 QList<QContactAddress*> addressList = getAddressDetail(eContact); |
|
719 QContactAddress* address; |
|
720 foreach(address, addressList) |
|
721 detailList << address; |
|
722 |
|
723 /* Avatar */ |
|
724 detailList << getAvatarDetail(eContact); // XXX TODO: FIXME |
|
725 detailList << getThumbnailDetail(eContact); |
|
726 |
|
727 /* BirthDay */ |
|
728 detailList << getBirthdayDetail(eContact); |
|
729 |
|
730 /* Email */ |
|
731 QList<QContactEmailAddress*> emailList = getEmailDetail(eContact); |
|
732 QContactEmailAddress* email; |
|
733 foreach(email, emailList) |
|
734 detailList << email; |
|
735 |
|
736 /* Gender */ |
|
737 detailList << getGenderDetail(eContact); |
|
738 |
|
739 /* Global UID*/ |
|
740 detailList << getGuidDetail(eContact); |
|
741 |
|
742 /* Name & NickName*/ |
|
743 detailList << getNameDetail(eContact); |
|
744 detailList << getNicknameDetail(eContact); |
|
745 |
|
746 /* Note */ |
|
747 detailList << getNoteDetail(eContact); |
|
748 |
|
749 /* Online Account */ |
|
750 QList<QContactOnlineAccount*> onlineAccountList = getOnlineAccountDetail(eContact); |
|
751 QContactOnlineAccount* onlineAccount; |
|
752 foreach(onlineAccount, onlineAccountList) |
|
753 detailList << onlineAccount; |
|
754 |
|
755 /* Organization */ |
|
756 detailList << getOrganizationDetail(eContact); |
|
757 |
|
758 /* Phone*/ |
|
759 QList<QContactPhoneNumber*> phoneNumberList = getPhoneDetail(eContact); |
|
760 QContactPhoneNumber* phoneNumber; |
|
761 foreach(phoneNumber, phoneNumberList) |
|
762 detailList << phoneNumber; |
|
763 |
|
764 /* TimeStamp */ |
|
765 detailList << getTimestampDetail(eContact); |
|
766 |
|
767 /* Url */ |
|
768 detailList << getUrlDetail(eContact); |
|
769 |
|
770 bool ok; |
|
771 QContactDetail* detail; |
|
772 |
|
773 foreach(detail, detailList){ |
|
774 if (detail->isEmpty()){ |
|
775 delete detail; |
|
776 continue; |
|
777 } |
|
778 |
|
779 ok = contact->saveDetail(detail); |
|
780 if (!ok){ |
|
781 qWarning() << "Detail can't be saved into QContact"; |
|
782 delete detail; |
|
783 continue; |
|
784 } |
|
785 delete detail; |
|
786 } |
|
787 |
|
788 return contact; |
|
789 } |
|
790 |
|
791 bool QContactABook::setDetailValues(const QVariantMap& data, QContactDetail* detail) const |
|
792 { |
|
793 QMapIterator<QString, QVariant> i(data); |
|
794 QVariant value; |
|
795 while (i.hasNext()) { |
|
796 i.next(); |
|
797 value = i.value(); |
|
798 |
|
799 if (value.isNull()) |
|
800 continue; |
|
801 |
|
802 if (value.canConvert<QString>() && value.toString().isEmpty()) |
|
803 continue; |
|
804 |
|
805 QCM5_DEBUG << "Set" << i.key() << i.value(); |
|
806 detail->setValue(i.key(), i.value()); |
|
807 |
|
808 } |
|
809 |
|
810 if (detail->isEmpty()) |
|
811 return false; |
|
812 return true; |
|
813 } |
|
814 |
|
815 OssoABookContact* QContactABook::getAContact(const QContactLocalId& contactId) const |
|
816 { |
|
817 OssoABookContact* rtn = NULL; |
|
818 |
|
819 QCM5_DEBUG << "Getting aContact with id " << m_localIds[contactId] << "local contactId is" << contactId; |
|
820 |
|
821 if(QString(m_localIds[contactId]).compare("osso-abook-self") == 0) { |
|
822 rtn = A_CONTACT(osso_abook_self_contact_get_default()); |
|
823 } else { |
|
824 EBookQuery* query; |
|
825 GList* contacts; |
|
826 |
|
827 query = e_book_query_field_test(E_CONTACT_UID, E_BOOK_QUERY_IS, m_localIds[contactId]); |
|
828 contacts = osso_abook_aggregator_find_contacts(m_abookAgregator, query); |
|
829 if (query) |
|
830 e_book_query_unref(query); |
|
831 |
|
832 if (g_list_length(contacts) == 1) { |
|
833 rtn = A_CONTACT(contacts->data); |
|
834 } else { |
|
835 qWarning("List is empty or several contacts have the same UID or contactId belongs to a roster contact."); |
|
836 } |
|
837 if (contacts) |
|
838 g_list_free(contacts); |
|
839 } |
|
840 |
|
841 return rtn; |
|
842 } |
|
843 |
|
844 QContactId QContactABook::getContactId(EContact *eContact) const |
|
845 { |
|
846 QContactId rtn; |
|
847 /* Set LocalId */ |
|
848 { |
|
849 const char* data = CONST_CHAR(e_contact_get_const(eContact, E_CONTACT_UID)); |
|
850 const QByteArray eContactUID(data); |
|
851 QContactLocalId localId = m_localIds[eContactUID]; |
|
852 if (!localId) |
|
853 qWarning("Unable to get valid localId for the specified eContaact UID"); |
|
854 rtn.setLocalId(localId); |
|
855 } |
|
856 return rtn; |
|
857 } |
|
858 |
|
859 QList<QContactAddress*> QContactABook::getAddressDetail(EContact *eContact) const |
|
860 { |
|
861 QList<QContactAddress*> rtnList; |
|
862 |
|
863 //Ordered list of Fields |
|
864 QStringList addressFields; |
|
865 addressFields << QContactAddress::FieldPostOfficeBox |
|
866 << "Estension" //FIXME I'm not sure we have to use a new field |
|
867 << QContactAddress::FieldStreet |
|
868 << QContactAddress::FieldLocality |
|
869 << QContactAddress::FieldRegion |
|
870 << QContactAddress::FieldPostcode |
|
871 << QContactAddress::FieldCountry; |
|
872 |
|
873 GList* attrList = osso_abook_contact_get_attributes(eContact, EVC_ADR); |
|
874 |
|
875 for (GList *node = g_list_last(attrList); node != NULL; node = g_list_previous(node)) { |
|
876 QContactAddress *address = new QContactAddress; |
|
877 QVariantMap map; |
|
878 |
|
879 EVCardAttribute *attr = static_cast<EVCardAttribute*>(node->data); |
|
880 |
|
881 |
|
882 // Set Address Context using attribute parameter value |
|
883 EVCardAttributeParam *param = NULL; |
|
884 GList* p = e_vcard_attribute_get_params(attr); |
|
885 |
|
886 if (p) |
|
887 param = static_cast<EVCardAttributeParam*>(p->data); |
|
888 |
|
889 if (param){ |
|
890 GList *v = e_vcard_attribute_param_get_values(param); |
|
891 QString context = CONST_CHAR(v->data); |
|
892 if (context == "HOME") |
|
893 address->setContexts(QContactDetail::ContextHome); |
|
894 else if (context == "WORK") |
|
895 address->setContexts(QContactDetail::ContextWork); |
|
896 } |
|
897 |
|
898 // Set Address Values |
|
899 GList *v = NULL; |
|
900 v =e_vcard_attribute_get_values(attr); |
|
901 if (!v) |
|
902 qFatal("ADR attribute data is corrupted"); |
|
903 if (g_list_length(v) != 7){ |
|
904 g_list_free(v); |
|
905 qCritical() << "ADR attribute data is corrupted"; |
|
906 } |
|
907 int i = 0; |
|
908 while (v){ |
|
909 map[addressFields[i]] = QString::fromLatin1(CONST_CHAR(v->data)); |
|
910 i++; |
|
911 v = v->next; |
|
912 } |
|
913 g_list_free(v); |
|
914 map[QContactDetail::FieldDetailUri] = QString::number(g_list_position(attrList, node)); |
|
915 setDetailValues(map, address); |
|
916 |
|
917 rtnList << address; |
|
918 } |
|
919 |
|
920 g_list_free(attrList); |
|
921 |
|
922 return rtnList; |
|
923 } |
|
924 |
|
925 QContactName* QContactABook::getNameDetail(EContact *eContact) const |
|
926 { |
|
927 QContactName* rtn = new QContactName; |
|
928 QVariantMap map; |
|
929 |
|
930 //Try to get the structure (looks that this is not supported in Maemo5) |
|
931 EContactName* eContactName = static_cast<EContactName*> (e_contact_get(eContact, E_CONTACT_NAME)); |
|
932 if (eContactName){ |
|
933 map[QContactName::FieldCustomLabel] = eContactName->additional; |
|
934 map[QContactName::FieldFirstName] = eContactName->given; |
|
935 map[QContactName::FieldLastName] = eContactName->family; |
|
936 //map[QContactName::FieldMiddleName] = eContactName-> |
|
937 map[QContactName::FieldPrefix] = eContactName->prefixes; |
|
938 map[QContactName::FieldSuffix] = eContactName->suffixes; |
|
939 e_contact_name_free (eContactName); |
|
940 } else { |
|
941 //Looks that Maemo use just these two fields |
|
942 map[QContactName::FieldFirstName] = CONST_CHAR(e_contact_get_const(eContact, E_CONTACT_GIVEN_NAME)); |
|
943 map[QContactName::FieldLastName] = CONST_CHAR(e_contact_get_const(eContact, E_CONTACT_FAMILY_NAME)); |
|
944 } |
|
945 setDetailValues(map, rtn); |
|
946 return rtn; |
|
947 } |
|
948 |
|
949 QContactNickname* QContactABook::getNicknameDetail(EContact *eContact) const |
|
950 { |
|
951 QContactNickname* rtn = new QContactNickname; |
|
952 QVariantMap map; |
|
953 map[QContactNickname::FieldNickname] = CONST_CHAR (e_contact_get_const(eContact, E_CONTACT_NICKNAME)); |
|
954 setDetailValues(map, rtn); |
|
955 return rtn; |
|
956 } |
|
957 |
|
958 QList<QContactEmailAddress*> QContactABook::getEmailDetail(EContact *eContact) const |
|
959 { |
|
960 QList<QContactEmailAddress*> rtnList; |
|
961 |
|
962 GList* attrList = osso_abook_contact_get_attributes(eContact, EVC_EMAIL); //FIXME MemLeak |
|
963 |
|
964 for (GList *node = g_list_last(attrList); node != NULL; node = g_list_previous(node)) { |
|
965 QContactEmailAddress *email = new QContactEmailAddress; |
|
966 QVariantMap map; |
|
967 |
|
968 EVCardAttribute *attr = static_cast<EVCardAttribute*>(node->data); |
|
969 |
|
970 // Set Address Context using attribute parameter value |
|
971 EVCardAttributeParam *param = NULL; |
|
972 GList* p = e_vcard_attribute_get_params(attr); |
|
973 |
|
974 if (p) |
|
975 param = static_cast<EVCardAttributeParam*>(p->data); |
|
976 |
|
977 if (param){ |
|
978 GList *v = e_vcard_attribute_param_get_values(param); |
|
979 QString context = CONST_CHAR(v->data); |
|
980 if (context == "HOME") |
|
981 email->setContexts(QContactDetail::ContextHome); |
|
982 else if (context == "WORK") |
|
983 email->setContexts(QContactDetail::ContextWork); |
|
984 } |
|
985 |
|
986 // Set Address Values |
|
987 GList *v = e_vcard_attribute_get_values(attr); |
|
988 int i = 0; |
|
989 while (v){ |
|
990 map[QContactEmailAddress::FieldEmailAddress] = QString::fromLatin1(CONST_CHAR(v->data)); |
|
991 i++; |
|
992 v = v->next; |
|
993 } |
|
994 g_list_free(v); |
|
995 |
|
996 map[QContactDetail::FieldDetailUri] = QString::number(g_list_position(attrList, node)); |
|
997 setDetailValues(map, email); |
|
998 rtnList << email; |
|
999 } |
|
1000 g_list_free(attrList); |
|
1001 |
|
1002 return rtnList; |
|
1003 } |
|
1004 |
|
1005 QContactAvatar* QContactABook::getAvatarDetail(EContact *eContact) const |
|
1006 { |
|
1007 Q_UNUSED(eContact); |
|
1008 // XXX TODO: FIXME |
|
1009 // QContactAvatar* rtn = new QContactAvatar; |
|
1010 // QVariantMap map; |
|
1011 // |
|
1012 // OssoABookContact *aContact = A_CONTACT(eContact); |
|
1013 // if (!aContact) |
|
1014 // return rtn; |
|
1015 // |
|
1016 // //GdkPixbuf* pixbuf = osso_abook_contact_get_avatar_pixbuf(aContact, NULL, NULL); |
|
1017 // GdkPixbuf* pixbuf = osso_abook_avatar_get_image_rounded(OSSO_ABOOK_AVATAR(aContact), 64, 64, true, 4, NULL); |
|
1018 // if (!GDK_IS_PIXBUF(pixbuf)){ |
|
1019 // FREE(pixbuf); |
|
1020 // return rtn; |
|
1021 // } |
|
1022 // |
|
1023 // const uchar* bdata = (const uchar*)gdk_pixbuf_get_pixels(pixbuf); |
|
1024 // QSize bsize(gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); |
|
1025 // |
|
1026 // //Convert GdkPixbuf to QPixmap |
|
1027 // QImage converted(bdata, bsize.width(), bsize.height(), QImage::Format_ARGB32_Premultiplied); |
|
1028 // map[QContactAvatar::FieldPixmap] = QPixmap::fromImage(converted); |
|
1029 // g_object_unref(pixbuf); |
|
1030 // setDetailValues(map, rtn); |
|
1031 // |
|
1032 // return rtn; |
|
1033 |
|
1034 QContactAvatar* empty = new QContactAvatar; |
|
1035 return empty; |
|
1036 } |
|
1037 |
|
1038 QContactBirthday* QContactABook::getBirthdayDetail(EContact *eContact) const |
|
1039 { |
|
1040 QContactBirthday* rtn = new QContactBirthday; |
|
1041 QVariantMap map; |
|
1042 EContactDate *date =static_cast<EContactDate*>(e_contact_get(eContact, E_CONTACT_BIRTH_DATE)); |
|
1043 if (!date) |
|
1044 return rtn; |
|
1045 QDate birthday(date->year, date->month, date->day); |
|
1046 e_contact_date_free(date); |
|
1047 map[QContactBirthday::FieldBirthday] = birthday; |
|
1048 setDetailValues(map, rtn); |
|
1049 return rtn; |
|
1050 } |
|
1051 |
|
1052 QContactGender* QContactABook::getGenderDetail(EContact *eContact) const |
|
1053 { |
|
1054 QContactGender* rtn = new QContactGender; |
|
1055 QVariantMap map; |
|
1056 const char* g = CONST_CHAR(osso_abook_contact_get_value(eContact, "X-GENDER")); |
|
1057 QString gender = QString::fromLatin1(g); |
|
1058 if (gender == "male") |
|
1059 gender = "Male"; |
|
1060 else if (gender == "female") |
|
1061 gender = "Female"; |
|
1062 else if (gender == "unspecified") |
|
1063 gender = "Unspecified"; |
|
1064 |
|
1065 map[QContactGender::FieldGender] = gender; |
|
1066 FREE(g); |
|
1067 setDetailValues(map, rtn); |
|
1068 return rtn; |
|
1069 } |
|
1070 |
|
1071 //NOTE Using UID as GUID |
|
1072 QContactGuid* QContactABook::getGuidDetail(EContact *eContact) const |
|
1073 { |
|
1074 QContactGuid* rtn = new QContactGuid; |
|
1075 QVariantMap map; |
|
1076 const char* uid = CONST_CHAR(e_contact_get(eContact, E_CONTACT_UID)); |
|
1077 map[QContactGuid::FieldGuid] = uid; |
|
1078 FREE(uid); |
|
1079 setDetailValues(map, rtn); |
|
1080 return rtn; |
|
1081 } |
|
1082 |
|
1083 QContactNote* QContactABook::getNoteDetail(EContact *eContact) const |
|
1084 { |
|
1085 QContactNote* rtn = new QContactNote; |
|
1086 QVariantMap map; |
|
1087 const char* note = CONST_CHAR(e_contact_get(eContact, E_CONTACT_NOTE)); |
|
1088 map[QContactNote::FieldNote] = QString::fromLatin1(note); |
|
1089 FREE(note); |
|
1090 setDetailValues(map, rtn); |
|
1091 return rtn; |
|
1092 } |
|
1093 |
|
1094 static const QStringList vcardsManagedByTelepathy(){ |
|
1095 QStringList rtn; |
|
1096 OssoABookAccountManager* accountMgr = osso_abook_account_manager_get_default(); |
|
1097 const GList *vcardFields = osso_abook_account_manager_get_primary_vcard_fields(accountMgr); |
|
1098 while (vcardFields){ |
|
1099 QString field = (const char*)vcardFields->data; |
|
1100 if (!rtn.contains(field)) |
|
1101 rtn << field; |
|
1102 vcardFields = vcardFields->next; |
|
1103 } |
|
1104 |
|
1105 return rtn; |
|
1106 } |
|
1107 |
|
1108 QList<QContactOnlineAccount*> QContactABook::getOnlineAccountDetail(EContact *eContact) const |
|
1109 { |
|
1110 QList<QContactOnlineAccount*> rtnList; |
|
1111 |
|
1112 QStringList evcardToSkip = vcardsManagedByTelepathy(); |
|
1113 |
|
1114 // Gets info of online accounts from roster contacts associated to the master one |
|
1115 if (!osso_abook_contact_is_roster_contact (A_CONTACT(eContact))) { |
|
1116 QContactOnlineAccount* rtn = new QContactOnlineAccount; |
|
1117 |
|
1118 GList *contacts = osso_abook_contact_get_roster_contacts(A_CONTACT(eContact)); |
|
1119 GList *node; |
|
1120 for (node = contacts; node != NULL; node = g_list_next(node)){ |
|
1121 OssoABookContact *rosterContact = A_CONTACT(node->data); |
|
1122 |
|
1123 McProfile* id = osso_abook_contact_get_profile(rosterContact); |
|
1124 McAccount* account = osso_abook_contact_get_account(rosterContact); |
|
1125 |
|
1126 // Avoid to look for Roster contacts into the VCard |
|
1127 QString accountVCard = QString::fromLatin1(mc_profile_get_vcard_field(id)); |
|
1128 evcardToSkip.removeOne(accountVCard); |
|
1129 |
|
1130 // Presence |
|
1131 OssoABookPresence *presence = OSSO_ABOOK_PRESENCE (rosterContact); |
|
1132 TpConnectionPresenceType presenceType = osso_abook_presence_get_presence_type (presence); |
|
1133 QString presenceTypeString; |
|
1134 QContactPresence::PresenceState presenceTypeEnum; |
|
1135 switch (presenceType) { |
|
1136 case TP_CONNECTION_PRESENCE_TYPE_UNSET: presenceTypeString = "Unset"; presenceTypeEnum = QContactPresence::PresenceUnknown; break; |
|
1137 case TP_CONNECTION_PRESENCE_TYPE_OFFLINE: presenceTypeString = "Offline"; presenceTypeEnum = QContactPresence::PresenceOffline; break; |
|
1138 case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE: presenceTypeString = "Available"; presenceTypeEnum = QContactPresence::PresenceAvailable; break; |
|
1139 case TP_CONNECTION_PRESENCE_TYPE_AWAY: presenceTypeString = "Away"; presenceTypeEnum = QContactPresence::PresenceAway; break; |
|
1140 case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY: presenceTypeString = "Extended Away"; presenceTypeEnum = QContactPresence::PresenceExtendedAway; break; |
|
1141 case TP_CONNECTION_PRESENCE_TYPE_HIDDEN: presenceTypeString = "Hidden"; presenceTypeEnum = QContactPresence::PresenceHidden; break; |
|
1142 case TP_CONNECTION_PRESENCE_TYPE_BUSY: presenceTypeString = "Busy"; presenceTypeEnum = QContactPresence::PresenceBusy; break; |
|
1143 case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN: presenceTypeString = "Unknown"; presenceTypeEnum = QContactPresence::PresenceUnknown; break; |
|
1144 case TP_CONNECTION_PRESENCE_TYPE_ERROR: presenceTypeString = "Error"; presenceTypeEnum = QContactPresence::PresenceUnknown; break; |
|
1145 default: |
|
1146 qCritical() << "Presence type is not vaild" << presenceType; |
|
1147 } |
|
1148 |
|
1149 QVariantMap map; |
|
1150 map[QContactOnlineAccount::FieldServiceProvider] = mc_profile_get_unique_name(id); |
|
1151 map[QContactOnlineAccount::FieldDetailUri] = mc_profile_get_unique_name(id); // use this as detail URI so we can link to presence. |
|
1152 map["AccountPath"] = account->name; //MCAccount name: variable part of the D-Bus object path. |
|
1153 |
|
1154 setDetailValues(map, rtn); |
|
1155 } |
|
1156 rtnList << rtn; |
|
1157 g_list_free (contacts); |
|
1158 } |
|
1159 |
|
1160 /* Users can add Online account details manually. Eg: IRC username. |
|
1161 * evcardToSkip stringlist contains evCard attributes that have been already processed. |
|
1162 */ |
|
1163 GList *attributeList = e_vcard_get_attributes((EVCard*)eContact); |
|
1164 GList *node; |
|
1165 |
|
1166 if (attributeList) { |
|
1167 for (node = attributeList; node != NULL; node = g_list_next (node)) { |
|
1168 EVCardAttribute* attr = (EVCardAttribute*)node->data; |
|
1169 if (!attr) |
|
1170 continue; |
|
1171 QString attributeName = QString::fromLatin1(e_vcard_attribute_get_name(attr)); |
|
1172 |
|
1173 // Skip attributes processed scanning roster contacts. |
|
1174 if (!evcardToSkip.contains(attributeName)) |
|
1175 continue; |
|
1176 |
|
1177 GList *params = e_vcard_attribute_get_params(attr); |
|
1178 GList *nodeP; |
|
1179 QString type; |
|
1180 // If the parameter list lenght is 1, X-OSSO-VALID is not specified |
|
1181 bool ossoValidIsOk = (g_list_length(params) == 1) ? true : false; |
|
1182 |
|
1183 for (nodeP = params; nodeP != NULL; nodeP = g_list_next (nodeP)) { |
|
1184 EVCardAttributeParam* p = (EVCardAttributeParam*) nodeP->data; |
|
1185 QString paramName = QString::fromLatin1(e_vcard_attribute_param_get_name(p)); |
|
1186 bool attrIsType = false; |
|
1187 bool attrIsOssoValid = false; |
|
1188 |
|
1189 //If type is empty check if the attribute is "TYPE" |
|
1190 if (type.isEmpty()) |
|
1191 attrIsType = paramName.contains(EVC_TYPE); |
|
1192 |
|
1193 if(!ossoValidIsOk) |
|
1194 attrIsOssoValid = paramName.contains("X-OSSO-VALID"); |
|
1195 |
|
1196 if (!attrIsType && !attrIsOssoValid) { |
|
1197 qWarning () << "Skipping attribute parameter checking for" << paramName; |
|
1198 continue; |
|
1199 } |
|
1200 |
|
1201 GList *values = e_vcard_attribute_param_get_values(p); |
|
1202 GList *node; |
|
1203 for (node = values; node != NULL; node = g_list_next (node)) { |
|
1204 QString attributeParameterValue = QString::fromLatin1(CONST_CHAR(node->data)); |
|
1205 if (attrIsOssoValid) { |
|
1206 ossoValidIsOk = (attributeParameterValue == "yes")? true : false; |
|
1207 if (!ossoValidIsOk) { |
|
1208 qWarning() << "X-OSSO-VALID is false."; |
|
1209 break; |
|
1210 } |
|
1211 } else if (type.isEmpty()) { |
|
1212 type = attributeParameterValue; |
|
1213 if (type.isEmpty()) |
|
1214 qCritical() << "TYPE is empty"; |
|
1215 } |
|
1216 } |
|
1217 |
|
1218 if (ossoValidIsOk && !type.isEmpty()) { |
|
1219 QContactOnlineAccount* rtn = new QContactOnlineAccount; |
|
1220 QVariantMap map; |
|
1221 map[QContactOnlineAccount::FieldServiceProvider] = type; |
|
1222 setDetailValues(map, rtn); |
|
1223 rtnList << rtn; |
|
1224 } |
|
1225 } |
|
1226 } |
|
1227 } |
|
1228 |
|
1229 return rtnList; |
|
1230 } |
|
1231 |
|
1232 QContactOrganization* QContactABook::getOrganizationDetail(EContact *eContact) const |
|
1233 { |
|
1234 QContactOrganization* rtn = new QContactOrganization; |
|
1235 QVariantMap map; |
|
1236 const char* title = CONST_CHAR(e_contact_get(eContact, E_CONTACT_TITLE)); |
|
1237 map[QContactOrganization::FieldTitle] = title; |
|
1238 FREE(title); |
|
1239 setDetailValues(map, rtn); |
|
1240 return rtn; |
|
1241 } |
|
1242 |
|
1243 QList<QContactPhoneNumber*> QContactABook::getPhoneDetail(EContact *eContact) const |
|
1244 { |
|
1245 QList<QContactPhoneNumber*> rtnList; |
|
1246 |
|
1247 GList *l = osso_abook_contact_get_attributes(eContact, EVC_TEL); |
|
1248 |
|
1249 for (GList *node = g_list_last(l); node != NULL; node = g_list_previous(node)) { |
|
1250 QContactPhoneNumber* phoneNumber = new QContactPhoneNumber; |
|
1251 QVariantMap map; |
|
1252 |
|
1253 EVCardAttribute *attr = static_cast<EVCardAttribute*>(node->data); |
|
1254 GList* p = e_vcard_attribute_get_param(attr, EVC_TYPE); |
|
1255 |
|
1256 //Set Contexts and SubTypes |
|
1257 while (p) { |
|
1258 QString value = QString::fromLatin1(CONST_CHAR(p->data)); |
|
1259 |
|
1260 if (value == "HOME") |
|
1261 phoneNumber->setContexts(QContactDetail::ContextHome); |
|
1262 else if (value == "WORK") |
|
1263 phoneNumber->setContexts(QContactDetail::ContextWork); |
|
1264 else |
|
1265 if (value == "CELL") |
|
1266 phoneNumber->setSubTypes(QContactPhoneNumber::SubTypeMobile); |
|
1267 else if (value == "VOICE") |
|
1268 phoneNumber->setSubTypes(QContactPhoneNumber::SubTypeVoice); |
|
1269 |
|
1270 p = p->next; |
|
1271 } |
|
1272 g_list_free(p); |
|
1273 |
|
1274 //Set Phone Number |
|
1275 GList* phoneNumbers = e_vcard_attribute_get_values(attr); |
|
1276 const char* normalized = e_normalize_phone_number(CONST_CHAR(phoneNumbers->data)); //FIXME Valgrind complains about this |
|
1277 QString phoneNumberStr(normalized); |
|
1278 FREE(normalized); |
|
1279 map[QContactPhoneNumber::FieldNumber] = phoneNumberStr; |
|
1280 map[QContactDetail::FieldDetailUri] = QString::number(g_list_position(l, node)); |
|
1281 setDetailValues(map, phoneNumber); |
|
1282 |
|
1283 rtnList << phoneNumber; |
|
1284 } |
|
1285 g_list_free(l); |
|
1286 |
|
1287 return rtnList; |
|
1288 } |
|
1289 |
|
1290 |
|
1291 QList<QContactPresence*> QContactABook::getPresenceDetail(EContact *eContact) const |
|
1292 { |
|
1293 QList<QContactPresence*> rtnList; |
|
1294 |
|
1295 QStringList evcardToSkip = vcardsManagedByTelepathy(); |
|
1296 |
|
1297 // Gets info of online accounts from roster contacts associated to the master one |
|
1298 if (!osso_abook_contact_is_roster_contact (A_CONTACT(eContact))) { |
|
1299 QContactPresence* rtn = new QContactPresence; |
|
1300 |
|
1301 GList *contacts = osso_abook_contact_get_roster_contacts(A_CONTACT(eContact)); |
|
1302 GList *node; |
|
1303 for (node = contacts; node != NULL; node = g_list_next(node)){ |
|
1304 OssoABookContact *rosterContact = A_CONTACT(node->data); |
|
1305 |
|
1306 McProfile* id = osso_abook_contact_get_profile(rosterContact); |
|
1307 McAccount* account = osso_abook_contact_get_account(rosterContact); |
|
1308 |
|
1309 // Avoid to look for Roster contacts into the VCard |
|
1310 QString accountVCard = QString::fromLatin1(mc_profile_get_vcard_field(id)); |
|
1311 evcardToSkip.removeOne(accountVCard); |
|
1312 |
|
1313 // Presence |
|
1314 OssoABookPresence *presence = OSSO_ABOOK_PRESENCE (rosterContact); |
|
1315 TpConnectionPresenceType presenceType = osso_abook_presence_get_presence_type (presence); |
|
1316 QString presenceTypeString; |
|
1317 QContactPresence::PresenceState presenceTypeEnum; |
|
1318 switch (presenceType) { |
|
1319 case TP_CONNECTION_PRESENCE_TYPE_UNSET: presenceTypeString = "Unset"; presenceTypeEnum = QContactPresence::PresenceUnknown; break; |
|
1320 case TP_CONNECTION_PRESENCE_TYPE_OFFLINE: presenceTypeString = "Offline"; presenceTypeEnum = QContactPresence::PresenceOffline; break; |
|
1321 case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE: presenceTypeString = "Available"; presenceTypeEnum = QContactPresence::PresenceAvailable; break; |
|
1322 case TP_CONNECTION_PRESENCE_TYPE_AWAY: presenceTypeString = "Away"; presenceTypeEnum = QContactPresence::PresenceAway; break; |
|
1323 case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY: presenceTypeString = "Extended Away"; presenceTypeEnum = QContactPresence::PresenceExtendedAway; break; |
|
1324 case TP_CONNECTION_PRESENCE_TYPE_HIDDEN: presenceTypeString = "Hidden"; presenceTypeEnum = QContactPresence::PresenceHidden; break; |
|
1325 case TP_CONNECTION_PRESENCE_TYPE_BUSY: presenceTypeString = "Busy"; presenceTypeEnum = QContactPresence::PresenceBusy; break; |
|
1326 case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN: presenceTypeString = "Unknown"; presenceTypeEnum = QContactPresence::PresenceUnknown; break; |
|
1327 case TP_CONNECTION_PRESENCE_TYPE_ERROR: presenceTypeString = "Error"; presenceTypeEnum = QContactPresence::PresenceUnknown; break; |
|
1328 default: |
|
1329 qCritical() << "Presence type is not valid" << presenceType; |
|
1330 } |
|
1331 |
|
1332 QVariantMap map; // XXX FIXME |
|
1333 map[QContactPresence::FieldNickname] = osso_abook_contact_get_display_name(rosterContact); |
|
1334 map[QContactPresence::FieldPresenceState] = presenceTypeEnum; |
|
1335 map[QContactPresence::FieldPresenceStateText] = QString::fromLatin1(osso_abook_presence_get_presence_status_message(presence)); |
|
1336 map[QContactPresence::FieldLinkedDetailUris] = mc_profile_get_unique_name(id); //use the unique name as a detail uri of the online account. |
|
1337 map["AccountPath"] = account->name; //MCAccount name: variable part of the D-Bus object path. |
|
1338 |
|
1339 setDetailValues(map, rtn); |
|
1340 } |
|
1341 rtnList << rtn; |
|
1342 g_list_free (contacts); |
|
1343 } |
|
1344 |
|
1345 /* Users can add Online account details manually. Eg: IRC username. |
|
1346 * evcardToSkip stringlist contains evCard attributes that have been already processed. |
|
1347 */ |
|
1348 GList *attributeList = e_vcard_get_attributes((EVCard*)eContact); |
|
1349 GList *node; |
|
1350 |
|
1351 if (attributeList) { |
|
1352 for (node = attributeList; node != NULL; node = g_list_next (node)) { |
|
1353 EVCardAttribute* attr = (EVCardAttribute*)node->data; |
|
1354 if (!attr) |
|
1355 continue; |
|
1356 QString attributeName = QString::fromLatin1(e_vcard_attribute_get_name(attr)); |
|
1357 |
|
1358 // Skip attributes processed scanning roster contacts. |
|
1359 if (!evcardToSkip.contains(attributeName)) |
|
1360 continue; |
|
1361 |
|
1362 GList *params = e_vcard_attribute_get_params(attr); |
|
1363 GList *nodeP; |
|
1364 QString type; |
|
1365 // If the parameter list lenght is 1, X-OSSO-VALID is not specified |
|
1366 bool ossoValidIsOk = (g_list_length(params) == 1) ? true : false; |
|
1367 |
|
1368 for (nodeP = params; nodeP != NULL; nodeP = g_list_next (nodeP)) { |
|
1369 EVCardAttributeParam* p = (EVCardAttributeParam*) nodeP->data; |
|
1370 QString paramName = QString::fromLatin1(e_vcard_attribute_param_get_name(p)); |
|
1371 bool attrIsType = false; |
|
1372 bool attrIsOssoValid = false; |
|
1373 |
|
1374 //If type is empty check if the attribute is "TYPE" |
|
1375 if (type.isEmpty()) |
|
1376 attrIsType = paramName.contains(EVC_TYPE); |
|
1377 |
|
1378 if(!ossoValidIsOk) |
|
1379 attrIsOssoValid = paramName.contains("X-OSSO-VALID"); |
|
1380 |
|
1381 if (!attrIsType && !attrIsOssoValid) { |
|
1382 qWarning () << "Skipping attribute parameter checking for" << paramName; |
|
1383 continue; |
|
1384 } |
|
1385 |
|
1386 GList *values = e_vcard_attribute_param_get_values(p); |
|
1387 GList *node; |
|
1388 for (node = values; node != NULL; node = g_list_next (node)) { |
|
1389 QString attributeParameterValue = QString::fromLatin1(CONST_CHAR(node->data)); |
|
1390 if (attrIsOssoValid) { |
|
1391 ossoValidIsOk = (attributeParameterValue == "yes")? true : false; |
|
1392 if (!ossoValidIsOk) { |
|
1393 qWarning() << "X-OSSO-VALID is false."; |
|
1394 break; |
|
1395 } |
|
1396 } else if (type.isEmpty()) { |
|
1397 type = attributeParameterValue; |
|
1398 if (type.isEmpty()) |
|
1399 qCritical() << "TYPE is empty"; |
|
1400 } |
|
1401 } |
|
1402 |
|
1403 if (ossoValidIsOk && !type.isEmpty()) { |
|
1404 QContactPresence* rtn = new QContactPresence; |
|
1405 QVariantMap map; |
|
1406 map[QContactPresence::FieldNickname] = QString::fromLatin1(e_vcard_attribute_get_value(attr)); |
|
1407 map[QContactPresence::FieldLinkedDetailUris] = type; // XXX FIXME |
|
1408 setDetailValues(map, rtn); |
|
1409 rtnList << rtn; |
|
1410 } |
|
1411 } |
|
1412 } |
|
1413 } |
|
1414 |
|
1415 return rtnList; |
|
1416 } |
|
1417 |
|
1418 QContactTimestamp* QContactABook::getTimestampDetail(EContact *eContact) const |
|
1419 { |
|
1420 QContactTimestamp* rtn = new QContactTimestamp; |
|
1421 QVariantMap map; |
|
1422 const char* rev = CONST_CHAR(e_contact_get(eContact, E_CONTACT_REV)); |
|
1423 map[QContactTimestamp::FieldModificationTimestamp] = QDateTime::fromString(rev, Qt::ISODate); |
|
1424 FREE(rev); |
|
1425 setDetailValues(map, rtn); |
|
1426 return rtn; |
|
1427 } |
|
1428 |
|
1429 QContactThumbnail* QContactABook::getThumbnailDetail(EContact *eContact) const |
|
1430 { |
|
1431 QContactThumbnail* rtn = new QContactThumbnail; |
|
1432 QVariantMap map; |
|
1433 |
|
1434 OssoABookContact *aContact = A_CONTACT(eContact); |
|
1435 if (!aContact) |
|
1436 return rtn; |
|
1437 |
|
1438 //GdkPixbuf* pixbuf = osso_abook_contact_get_avatar_pixbuf(aContact, NULL, NULL); |
|
1439 GdkPixbuf* pixbuf = osso_abook_avatar_get_image_rounded(OSSO_ABOOK_AVATAR(aContact), 64, 64, true, 4, NULL); |
|
1440 if (!GDK_IS_PIXBUF(pixbuf)){ |
|
1441 FREE(pixbuf); |
|
1442 return rtn; |
|
1443 } |
|
1444 |
|
1445 const uchar* bdata = (const uchar*)gdk_pixbuf_get_pixels(pixbuf); |
|
1446 QSize bsize(gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)); |
|
1447 |
|
1448 //Convert GdkPixbuf to QPixmap |
|
1449 QImage converted(bdata, bsize.width(), bsize.height(), QImage::Format_ARGB32_Premultiplied); |
|
1450 map[QContactThumbnail::FieldThumbnail] = converted; |
|
1451 g_object_unref(pixbuf); |
|
1452 setDetailValues(map, rtn); |
|
1453 |
|
1454 return rtn; |
|
1455 } |
|
1456 |
|
1457 QContactUrl* QContactABook::getUrlDetail(EContact *eContact) const |
|
1458 { |
|
1459 QContactUrl* rtn = new QContactUrl; |
|
1460 QVariantMap map; |
|
1461 const char* url = CONST_CHAR(e_contact_get(eContact, E_CONTACT_HOMEPAGE_URL)); |
|
1462 map[QContactUrl::FieldUrl] = url; |
|
1463 FREE(url); |
|
1464 setDetailValues(map, rtn); |
|
1465 return rtn; |
|
1466 } |
|
1467 |
|
1468 static void addAttributeToAContact(const OssoABookContact* contact, |
|
1469 const QString& attrName, const QStringList& attrValues, |
|
1470 const QString& paramName = QString(), const QStringList& paramValues = QStringList(), |
|
1471 bool overwrite = true, |
|
1472 const int index = 0) |
|
1473 { |
|
1474 if (!contact) |
|
1475 return; |
|
1476 |
|
1477 EVCard *vcard = E_VCARD (contact); |
|
1478 EVCardAttribute *attr = NULL; |
|
1479 EVCardAttributeParam* param = NULL; |
|
1480 |
|
1481 QCM5_DEBUG << "Adding attribute" << attrName << "AttrValues:" << attrValues |
|
1482 << "ParamName:" << paramName << "ParamValues:" << paramValues |
|
1483 << "overwrite" << overwrite << "Index" << index; |
|
1484 |
|
1485 if (overwrite) |
|
1486 { |
|
1487 GList *attributeList = osso_abook_contact_get_attributes(E_CONTACT(contact), qPrintable(attrName)); |
|
1488 |
|
1489 for (GList *node = g_list_last(attributeList); node != NULL; node = g_list_previous(node)) { |
|
1490 EVCardAttribute* eAttr = (EVCardAttribute*)node->data; |
|
1491 int pos = g_list_position(attributeList, node); |
|
1492 |
|
1493 if (index > pos){ |
|
1494 qWarning() << "Attribute doesn't found at position" << index; |
|
1495 return; |
|
1496 } |
|
1497 |
|
1498 if (index != pos) |
|
1499 continue; |
|
1500 |
|
1501 // Select the current EVCard Attribute if it contains the same parameters of |
|
1502 // attribute we want to modify/add |
|
1503 int matchedParams = 0; |
|
1504 GList* p = NULL; |
|
1505 p = e_vcard_attribute_get_param(eAttr, qPrintable(paramName)); |
|
1506 |
|
1507 while (p){ |
|
1508 foreach(QString paramV, paramValues){ |
|
1509 QString value = CONST_CHAR(p->data); |
|
1510 if (paramV == value) |
|
1511 ++matchedParams; |
|
1512 } |
|
1513 p = p->next; |
|
1514 } |
|
1515 g_list_free(p); |
|
1516 |
|
1517 if (matchedParams == paramValues.count()) { |
|
1518 attr = eAttr; |
|
1519 break; |
|
1520 } |
|
1521 } |
|
1522 } |
|
1523 |
|
1524 // Check if attrValues contains something |
|
1525 bool noValues = true; |
|
1526 foreach(QString s, attrValues){ |
|
1527 if (!s.isEmpty()){ |
|
1528 noValues = false; |
|
1529 break; |
|
1530 } |
|
1531 } |
|
1532 |
|
1533 if (attr) { |
|
1534 if (noValues){ |
|
1535 e_vcard_remove_attribute(vcard, attr); |
|
1536 return; |
|
1537 } else { |
|
1538 e_vcard_attribute_remove_values(attr); |
|
1539 } |
|
1540 } else { |
|
1541 if (noValues) |
|
1542 return; |
|
1543 |
|
1544 // Create Attribute with right parameters |
|
1545 attr = e_vcard_attribute_new(NULL, qPrintable(attrName)); |
|
1546 if (!paramName.isEmpty()){ |
|
1547 param = e_vcard_attribute_param_new(qPrintable(paramName)); |
|
1548 |
|
1549 foreach(QString paramV, paramValues) |
|
1550 e_vcard_attribute_param_add_value(param, qPrintable(paramV)); |
|
1551 |
|
1552 e_vcard_attribute_add_param(attr, param); |
|
1553 } |
|
1554 // Save the attribute to the VCard |
|
1555 e_vcard_add_attribute(vcard, attr); |
|
1556 } |
|
1557 |
|
1558 // Add values to the attribute |
|
1559 foreach(QString attrV, attrValues) { |
|
1560 e_vcard_attribute_add_value(attr, qPrintable(attrV)); |
|
1561 } |
|
1562 |
|
1563 // Debugging |
|
1564 { |
|
1565 const char* dbgStr = e_vcard_to_string(vcard, EVC_FORMAT_VCARD_30); |
|
1566 QCM5_DEBUG << "Modified VCard" << dbgStr; |
|
1567 FREE(dbgStr); |
|
1568 } |
|
1569 } |
|
1570 |
|
1571 OssoABookContact* QContactABook::convert(const QContact *contact) const |
|
1572 { |
|
1573 Q_CHECK_PTR(contact); |
|
1574 |
|
1575 OssoABookContact* rtn; |
|
1576 |
|
1577 // Get aContact if it exists or create a new one if it doesn't |
|
1578 QContactLocalId id = contact->localId(); |
|
1579 QCM5_DEBUG << "Converting QContact id:" << id << " to aContact"; |
|
1580 if (id){ |
|
1581 rtn = getAContact(id); |
|
1582 // It's not safe to commit changes to a contact that has been modified. |
|
1583 // This problem affects attributes with the same name and parameters such as |
|
1584 // EMail, Address... |
|
1585 QContactTimestamp* ts = getTimestampDetail(E_CONTACT(rtn)); |
|
1586 if (*ts != contact->detail<QContactTimestamp>()){ |
|
1587 delete ts; |
|
1588 return NULL; |
|
1589 } |
|
1590 delete ts; |
|
1591 } else { |
|
1592 rtn = osso_abook_contact_new(); |
|
1593 } |
|
1594 |
|
1595 QList<QContactDetail> allDetails = contact->details(); |
|
1596 foreach(const QContactDetail &detail, allDetails){ |
|
1597 QString definitionName = detail.definitionName(); |
|
1598 |
|
1599 QCM5_DEBUG << "Saving" << definitionName; |
|
1600 |
|
1601 //QContactDisplayLabel::DefinitionName |
|
1602 if (definitionName == QContactAddress::DefinitionName){ |
|
1603 setAddressDetail(rtn, detail); |
|
1604 } else |
|
1605 if (definitionName == QContactAvatar::DefinitionName){ |
|
1606 setAvatarDetail(rtn, detail); |
|
1607 } else |
|
1608 if (definitionName == QContactBirthday::DefinitionName){ |
|
1609 setBirthdayDetail(rtn, detail); |
|
1610 } else |
|
1611 if (definitionName == QContactEmailAddress::DefinitionName){ |
|
1612 setEmailDetail(rtn, detail); |
|
1613 } else |
|
1614 if (definitionName == QContactGender::DefinitionName){ |
|
1615 setGenderDetail(rtn, detail); |
|
1616 } else |
|
1617 if (definitionName == QContactName::DefinitionName){ |
|
1618 setNameDetail(rtn, detail); |
|
1619 } else |
|
1620 if (definitionName == QContactNickname::DefinitionName){ |
|
1621 setNicknameDetail(rtn, detail); |
|
1622 } else |
|
1623 if (definitionName == QContactNote::DefinitionName){ |
|
1624 setNoteDetail(rtn, detail); |
|
1625 } else |
|
1626 if (definitionName == QContactOnlineAccount::DefinitionName){ |
|
1627 setOnlineAccountDetail(rtn, detail); |
|
1628 } else |
|
1629 if (definitionName == QContactOrganization::DefinitionName){ |
|
1630 setOrganizationDetail(rtn, detail); |
|
1631 } else |
|
1632 if (definitionName == QContactPhoneNumber::DefinitionName){ |
|
1633 setPhoneDetail(rtn, detail); |
|
1634 } else |
|
1635 if (definitionName == QContactThumbnail::DefinitionName){ |
|
1636 setThumbnailDetail(rtn, detail); |
|
1637 } else |
|
1638 if (definitionName == QContactUrl::DefinitionName){ |
|
1639 setUrlDetail(rtn, detail); |
|
1640 } |
|
1641 } |
|
1642 |
|
1643 return rtn; |
|
1644 } |
|
1645 |
|
1646 void QContactABook::setAddressDetail(const OssoABookContact* aContact, const QContactAddress& detail) const |
|
1647 { |
|
1648 if (!aContact) return; |
|
1649 |
|
1650 uint detailUri; |
|
1651 const uint nAddressElems = 7; |
|
1652 QStringList adrAttrValues, |
|
1653 lblAttrValues, |
|
1654 paramValues; |
|
1655 |
|
1656 // Get parameters |
|
1657 foreach(QString c, detail.contexts()) |
|
1658 paramValues << c.toUpper(); |
|
1659 |
|
1660 // Initialize adrAttrValues; |
|
1661 for (uint i = 0; i < nAddressElems; ++i) |
|
1662 adrAttrValues << ""; |
|
1663 |
|
1664 // Fill adrAttrValues |
|
1665 QVariantMap vm = detail.variantValues(); |
|
1666 QMapIterator<QString, QVariant> i(vm); |
|
1667 |
|
1668 while (i.hasNext()) { |
|
1669 i.next(); |
|
1670 int index = -1; |
|
1671 QString key = i.key(); |
|
1672 |
|
1673 if (key == QContactAddress::FieldPostOfficeBox) index = 0; |
|
1674 else if (key == "Estension") index = 1; |
|
1675 else if (key == QContactAddress::FieldStreet) index = 2; |
|
1676 else if (key == QContactAddress::FieldLocality) index = 3; |
|
1677 else if (key == QContactAddress::FieldRegion) index = 4; |
|
1678 else if (key == QContactAddress::FieldPostcode) index = 5; |
|
1679 else if (key == QContactAddress::FieldCountry) index = 6; |
|
1680 else if (key == QContactDetail::FieldContext) continue; |
|
1681 else if (key == QContactDetail::FieldDetailUri) detailUri = i.value().toInt(); |
|
1682 else { |
|
1683 qWarning() << "Address contains an invalid field:" << key; |
|
1684 return; |
|
1685 } |
|
1686 |
|
1687 if (index != -1) |
|
1688 adrAttrValues[index] = i.value().toString(); |
|
1689 } |
|
1690 |
|
1691 // Fill lblAttrValues |
|
1692 QStringList labelValues; |
|
1693 labelValues << adrAttrValues[1] |
|
1694 << adrAttrValues[2] |
|
1695 << adrAttrValues[0] |
|
1696 << adrAttrValues[3] |
|
1697 << adrAttrValues[4] |
|
1698 << adrAttrValues[5] |
|
1699 << adrAttrValues[6]; |
|
1700 lblAttrValues << labelValues.join(", "); |
|
1701 |
|
1702 // Skip if adrAttrValues contains only empty strings |
|
1703 bool noValues = true; |
|
1704 foreach(QString s, adrAttrValues){ |
|
1705 if (!s.isEmpty()){ |
|
1706 noValues = false; |
|
1707 break; |
|
1708 } |
|
1709 } |
|
1710 if (noValues) |
|
1711 return; |
|
1712 |
|
1713 // Saving LABEL and ADR attributes into the VCard |
|
1714 addAttributeToAContact(aContact, EVC_ADR, adrAttrValues, EVC_TYPE, paramValues, true, detailUri); |
|
1715 |
|
1716 //BUG Label attribute contains a bug |
|
1717 //It contains TYPE(TYPE) if ADDRESS doesn't contain any parameter value. |
|
1718 if (paramValues.isEmpty()) |
|
1719 paramValues << EVC_TYPE; |
|
1720 |
|
1721 addAttributeToAContact(aContact, EVC_LABEL, lblAttrValues, EVC_TYPE, paramValues, true, detailUri); |
|
1722 } |
|
1723 |
|
1724 void QContactABook::setThumbnailDetail(const OssoABookContact* aContact, const QContactThumbnail& detail) const |
|
1725 { |
|
1726 if (!aContact) return; |
|
1727 |
|
1728 EBook *book; |
|
1729 { |
|
1730 OssoABookRoster* roster = A_ROSTER(m_abookAgregator); |
|
1731 book = osso_abook_roster_get_book(roster); |
|
1732 } |
|
1733 |
|
1734 QImage image = detail.thumbnail(); |
|
1735 |
|
1736 if (image.isNull()) |
|
1737 return; |
|
1738 |
|
1739 if (image.format() != QImage::Format_ARGB32_Premultiplied) |
|
1740 image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); |
|
1741 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(image.bits(), GDK_COLORSPACE_RGB, |
|
1742 image.hasAlphaChannel(), 8, |
|
1743 image.width(), image.height(), |
|
1744 image.bytesPerLine(), 0, 0); |
|
1745 osso_abook_contact_set_pixbuf((OssoABookContact*)aContact, pixbuf, book, 0); |
|
1746 g_object_unref(pixbuf); |
|
1747 } |
|
1748 |
|
1749 void QContactABook::setAvatarDetail(const OssoABookContact* aContact, const QContactAvatar& detail) const |
|
1750 { |
|
1751 Q_UNUSED(aContact) |
|
1752 Q_UNUSED(detail); |
|
1753 // XXX TODO: FIXME |
|
1754 // if (!aContact) return; |
|
1755 // |
|
1756 // EBook *book; |
|
1757 // { |
|
1758 // OssoABookRoster* roster = A_ROSTER(m_abookAgregator); |
|
1759 // book = osso_abook_roster_get_book(roster); |
|
1760 // } |
|
1761 // |
|
1762 // QImage image = detail.pixmap().toImage(); |
|
1763 // if (image.format() != QImage::Format_ARGB32_Premultiplied) |
|
1764 // image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); |
|
1765 // GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(image.bits(), GDK_COLORSPACE_RGB, |
|
1766 // image.hasAlphaChannel(), 8, |
|
1767 // image.width(), image.height(), |
|
1768 // image.bytesPerLine(), 0, 0); |
|
1769 // osso_abook_contact_set_pixbuf((OssoABookContact*)aContact, pixbuf, book, 0); |
|
1770 // g_object_unref(pixbuf); |
|
1771 } |
|
1772 |
|
1773 void QContactABook::setBirthdayDetail(const OssoABookContact* aContact, const QContactBirthday& detail) const |
|
1774 { |
|
1775 if (!aContact) return; |
|
1776 |
|
1777 QStringList attrValues; |
|
1778 attrValues << detail.value(QContactBirthday::FieldBirthday); |
|
1779 |
|
1780 addAttributeToAContact(aContact, EVC_BDAY, attrValues); |
|
1781 } |
|
1782 |
|
1783 void QContactABook::setEmailDetail(const OssoABookContact* aContact, const QContactEmailAddress& detail) const |
|
1784 { |
|
1785 if (!aContact) return; |
|
1786 QStringList attrValues, |
|
1787 paramValues; |
|
1788 |
|
1789 QVariantMap vm = detail.variantValues(); |
|
1790 QMapIterator<QString, QVariant> i(vm); |
|
1791 while (i.hasNext()) { |
|
1792 i.next(); |
|
1793 QString key = i.key(); |
|
1794 |
|
1795 // We don't want to save the Detail URI |
|
1796 if (key == QContactDetail::FieldDetailUri) |
|
1797 continue; |
|
1798 |
|
1799 if (key == QContactDetail::FieldContext) |
|
1800 paramValues << i.value().toString().toUpper(); |
|
1801 else |
|
1802 attrValues << i.value().toString(); |
|
1803 } |
|
1804 |
|
1805 addAttributeToAContact(aContact, EVC_EMAIL, attrValues, EVC_TYPE, paramValues, true, detail.detailUri().toInt()); |
|
1806 } |
|
1807 |
|
1808 void QContactABook::setGenderDetail(const OssoABookContact* aContact, const QContactGender& detail) const |
|
1809 { |
|
1810 if (!aContact) return; |
|
1811 |
|
1812 QStringList attrValues; |
|
1813 attrValues << detail.value(QContactGender::FieldGender).toLower(); |
|
1814 |
|
1815 addAttributeToAContact(aContact, "X-GENDER", attrValues); |
|
1816 } |
|
1817 |
|
1818 void QContactABook::setNameDetail(const OssoABookContact* aContact, const QContactName& detail) const |
|
1819 { |
|
1820 if (!aContact) return; |
|
1821 |
|
1822 QStringList attrValues; |
|
1823 // Save First and Last name in the N vcard attribute |
|
1824 { |
|
1825 QStringList supportedDetailValues; |
|
1826 supportedDetailValues << QContactName::FieldFirstName << QContactName::FieldLastName; |
|
1827 |
|
1828 foreach(QString key, supportedDetailValues){ |
|
1829 attrValues << detail.value(key); |
|
1830 } |
|
1831 |
|
1832 //REMOVE ME - We don't want to support custom label |
|
1833 if (attrValues[0].isEmpty()){ |
|
1834 qWarning() << "QContactName::FieldFirstName is empty"; |
|
1835 attrValues[0] = detail.customLabel(); |
|
1836 } |
|
1837 |
|
1838 addAttributeToAContact(aContact, EVC_N, attrValues); |
|
1839 } |
|
1840 |
|
1841 // Save Fist + Last name in the FN card attribute |
|
1842 { |
|
1843 attrValues << attrValues.join(" "); |
|
1844 addAttributeToAContact(aContact, EVC_FN, attrValues); |
|
1845 } |
|
1846 } |
|
1847 |
|
1848 void QContactABook::setNicknameDetail(const OssoABookContact* aContact, const QContactNickname& detail) const |
|
1849 { |
|
1850 if (!aContact) return; |
|
1851 |
|
1852 QStringList attrValues; |
|
1853 attrValues << detail.value(QContactNickname::FieldNickname); |
|
1854 |
|
1855 addAttributeToAContact(aContact, EVC_NICKNAME, attrValues); |
|
1856 } |
|
1857 |
|
1858 void QContactABook::setNoteDetail(const OssoABookContact* aContact, const QContactNote& detail) const |
|
1859 { |
|
1860 if (!aContact) return; |
|
1861 |
|
1862 QStringList attrValues; |
|
1863 attrValues << detail.value(QContactNote::FieldNote); |
|
1864 |
|
1865 addAttributeToAContact(aContact, EVC_NOTE, attrValues); |
|
1866 } |
|
1867 |
|
1868 /*NOTE: Online details comes from Telepathy or can be added manually by the user. |
|
1869 * OnlineDetals coming from Telepathy/Roster contacts can't be saved. |
|
1870 */ |
|
1871 void QContactABook::setOnlineAccountDetail(const OssoABookContact* aContact, const QContactOnlineAccount& detail) const |
|
1872 { |
|
1873 if (!aContact) |
|
1874 return; |
|
1875 |
|
1876 Q_UNUSED(detail); |
|
1877 } |
|
1878 |
|
1879 void QContactABook::setOrganizationDetail(const OssoABookContact* aContact, const QContactOrganization& detail) const |
|
1880 { |
|
1881 if (!aContact) return; |
|
1882 |
|
1883 QStringList attrValues; |
|
1884 attrValues << detail.value(QContactOrganization::FieldTitle); |
|
1885 |
|
1886 addAttributeToAContact(aContact, EVC_ORG, attrValues); |
|
1887 } |
|
1888 |
|
1889 void QContactABook::setPhoneDetail(const OssoABookContact* aContact, const QContactPhoneNumber& detail) const |
|
1890 { |
|
1891 if (!aContact) return; |
|
1892 QStringList attrValues, |
|
1893 paramValues; |
|
1894 |
|
1895 QVariantMap vm = detail.variantValues(); |
|
1896 QMapIterator<QString, QVariant> i(vm); |
|
1897 while (i.hasNext()) { |
|
1898 i.next(); |
|
1899 const QString key = i.key(); |
|
1900 |
|
1901 // We don't want to save the Detail URI |
|
1902 if (key == QContactDetail::FieldDetailUri) |
|
1903 continue; |
|
1904 |
|
1905 if (key == QContactDetail::FieldContext || |
|
1906 key == QContactPhoneNumber::FieldSubTypes){ |
|
1907 QString value = i.value().toString(); |
|
1908 if (value == QContactPhoneNumber::SubTypeMobile) |
|
1909 value = "CELL"; |
|
1910 paramValues << value.toUpper(); |
|
1911 } else |
|
1912 attrValues << i.value().toString(); |
|
1913 } |
|
1914 |
|
1915 // Avoid unsupported type |
|
1916 if (paramValues.isEmpty()) |
|
1917 paramValues << "VOICE"; |
|
1918 |
|
1919 addAttributeToAContact(aContact, EVC_TEL, attrValues, EVC_TYPE, paramValues, true, detail.detailUri().toInt()); |
|
1920 } |
|
1921 |
|
1922 void QContactABook::setUrlDetail(const OssoABookContact* aContact, const QContactUrl& detail) const |
|
1923 { |
|
1924 if (!aContact) return; |
|
1925 |
|
1926 QStringList attrValues; |
|
1927 attrValues << detail.value(QContactUrl::FieldUrl); |
|
1928 |
|
1929 addAttributeToAContact(aContact, EVC_URL, attrValues); |
|
1930 } |