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