tizen beta release
[framework/web/wrt-plugins-common.git] / src / modules / tizen / Contact / AddressBook.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        AddressBook.cpp
18  * @author      Lukasz Marek (l.marek@samsung.com)
19  * @version     0.1
20  */
21
22 #include <ctime>
23 #include <cstdlib>
24 #include <cstddef>
25 #include <fstream>
26 #include <sstream>
27 #include <pcrecpp.h>
28 #include <dpl/log/log.h>
29 #include <Commons/Exception.h>
30 #include <Commons/Regex.h>
31 #include <Contact/IAddressBook.h>
32 #include <Contact/Contact.h>
33 #include <Filesystem/Manager.h>
34 #include "AddressBook.h"
35 #include "ContactWrapper.h"
36
37 namespace WrtDeviceApis {
38 namespace Contact {
39
40 using namespace Api;
41
42 bool AddressBook::m_isDaInit = false;
43
44 AddressBook::AddressBook(IAddressBookObject::BookType type) :
45     IAddressBookObject(type)
46 {
47     LogDebug("entered");
48     //platform layer seems to not support different storage types yet
49     /*
50        if ( type == IAddressBookObject::PhoneBook ) {
51         LogDebug("PhoneBook");
52        }
53        else if ( type == IAddressBookObject::SIMBook ) {
54         LogDebug("SIMBook");
55        }
56        else {
57         LogError("wrong book type");
58        }
59      */
60
61     setDaClientIdByDaInit();
62 }
63
64 AddressBook::~AddressBook()
65 {
66     LogDebug("entered");
67     unsetDaClientIdByDaDeinit();
68 }
69
70 std::string AddressBook::getName() const
71 {
72     //return address book name
73     return m_name;
74 }
75
76 void AddressBook::setName(const std::string &value)
77 {
78     //set address book name
79     m_name = value;
80 }
81
82 void AddressBook::daNotifyCb(user_notify_info_t *notify_info,
83         void *user_data)
84 {
85     if (notify_info == NULL) {
86         LogDebug("notify_info is NULL!!");
87         return;
88     }
89
90     if (notify_info->state == DA_STATE_FAILED || notify_info->state ==
91         DA_STATE_CANCELED) {
92         if (user_data != NULL) {
93             DownImgInfo *downImgInfo;
94             downImgInfo = static_cast<DownImgInfo*>(user_data);
95             (downImgInfo->getWaitableEvent())->Signal();
96         }
97     }
98 }
99
100 void AddressBook::daGetDdInfoCb(user_dd_info_t* /*dd_info*/,
101                                 void* /*user_data*/)
102 {
103     /* Empty CB */
104     LogDebug("Entered!");
105 }
106
107 void AddressBook::daUpdateDownloadInfoCb(user_download_info_t *download_info,
108                                          void *user_data)
109 {
110     LogDebug("Entered!");
111
112     if (download_info != NULL && user_data != NULL) {
113         if (download_info->saved_path) {
114             LogDebug(
115                 "download_info->saved_path : " << download_info->saved_path);
116             DownImgInfo *downImgInfo = static_cast<DownImgInfo*>(user_data);
117             std::string savedPath = download_info->saved_path;
118             downImgInfo->setdownloadedImgPath(savedPath);
119             (downImgInfo->getWaitableEvent())->Signal();
120         }
121     }
122 }
123
124 void AddressBook::setDaClientIdByDaInit(void)
125 {
126     LogDebug("Entered!! m_isDaInit: " << m_isDaInit);
127     if (m_isDaInit) {
128         LogDebug("DaInit already done!");
129         return;
130     }
131     m_isDaInit = true;
132
133     int da_ret = DA_INVALID_ID;
134     da_client_cb_t da_cb;
135     memset(&da_cb, 0, sizeof(da_client_cb_t));
136
137     da_cb.user_noti_cb = &daNotifyCb;
138     da_cb.send_dd_info_cb = &daGetDdInfoCb;
139     da_cb.update_dl_info_cb = &daUpdateDownloadInfoCb;
140     da_ret = da_init(&da_cb, DA_DOWNLOAD_MANAGING_METHOD_AUTO);
141
142     if (da_ret != DA_RESULT_OK) {
143         LogDebug("Error during da_init() da_ret: " << da_ret);
144     }
145 }
146
147 void AddressBook::unsetDaClientIdByDaDeinit(void)
148 {
149     LogDebug("Entered!! m_isDaInit: " << m_isDaInit);
150     if(m_isDaInit) {
151         da_deinit();
152         m_isDaInit = false;
153     }
154 }
155
156 std::string AddressBook::getRealPath(const std::string &path) const
157 {
158     //translate provided path to real filesystem path
159     Try
160     {
161         LogDebug("path : " << path);
162         if (Commons::validate("^(http(s)?://)?\\w+.*$",
163                               path,
164                               Commons::VALIDATE_MATCH_CASELESS))
165         {
166             // if path is URL then Img will be downloaded.
167             LogDebug("path is URL. Start Image download!");
168             return downloadImage(path);
169         } else {
170             //translate provided path to real filesystem path
171             Filesystem::Api::IPathPtr currentPath =
172                 Filesystem::Api::IPath::create(path);
173             return currentPath->getFullPath();
174         }
175     }
176     Catch(Commons::Exception)
177     {
178         //probably path doesn't exist
179         LogError("invalid path");
180     }
181     //on error return empty string
182     return std::string();
183 }
184
185 std::string AddressBook::downloadImage(const std::string &imgUrl) const
186 {
187     try
188     {
189         LogDebug("URL : " << imgUrl);
190
191         DownImgInfo downImgInfo;
192         int da_ret = DA_INVALID_ID;
193         int download_id = -1;
194
195         DPL::WaitableEvent waitableEvent;
196         downImgInfo.setWaitableEvent(&waitableEvent);
197         da_ret = da_start_download_with_extension(
198                                                   imgUrl.c_str(), &download_id,
199                                                   DA_FEATURE_USER_DATA,
200                                                   static_cast<void*>(&
201                                                                      downImgInfo),
202                                                   NULL);
203         if (da_ret != DA_RESULT_OK) {
204             ThrowMsg(
205                 Commons::PlatformException,
206                 "Error during da_start_download_with_extension() da_ret: "
207                 << da_ret);
208         }
209         DPL::WaitForSingleHandle(waitableEvent.GetHandle());
210         waitableEvent.Reset();
211
212         if ((downImgInfo.getdownloadedImgPath()).empty()) {
213             ThrowMsg(Commons::Exception, "Download is Fail!");
214         }
215         return downImgInfo.getdownloadedImgPath();
216     }
217     catch (const Commons::Exception &ex)
218     {
219         LogError("Probably invalid URL. " << ex.GetMessage());
220     }
221     //on error return empty string(file path)
222     return std::string();
223 }
224
225 std::vector<std::string> AddressBook::internalExportToVCard(
226         const std::vector<ContactPtr> &contacts) const
227 {
228     //container for result files
229     std::vector<std::string> result;
230     //path for currently exporting contact
231     std::string path;
232     //platform stream
233     char *vcard_stream;
234     //contact to export
235     CTSstruct *contact;
236     //streams
237     std::fstream outputFile;
238     std::stringstream name;
239     //get current time to create unique file names
240     std::time_t t = std::time(0);
241     //iterate over all contacts to export
242     for (std::size_t i = 0; i < contacts.size(); ++i) {
243         //create new file name for current contact
244         name.clear();
245         name << "/Others/contacts_" << i << "_" << t << ".vcf";
246         //translate path for real filesystem
247         path = getRealPath(name.str());
248         if (path.empty()) {
249             LogError("Cannot convert path to real file system path");
250             return std::vector<std::string>();
251         }
252         LogDebug("filename: " << path);
253         Try
254         {
255             //check if file exists and return if does
256             if (Filesystem::Manager::fileExists(path)) {
257                 LogError("File already exists");
258                 return std::vector<std::string>();
259             }
260         }
261         Catch(Commons::PlatformException)
262         {
263             //error during check, return
264             LogError("Cannot validate if file exists.");
265             return std::vector<std::string>();
266         }
267         //create and open new file
268         outputFile.open(path.c_str(), std::fstream::out | std::fstream::app);
269         if (!outputFile.fail()) {
270             //when failes is created then continue with processing a contact
271             //convert file into platform struct
272             ContactWrapperPtr wrapper(new ContactWrapper(m_bookType));
273             wrapper->setAbstractContact(contacts[i]);
274             contact = wrapper->getPlatformContact();
275             //call API function to get VCard stresm
276             if (CTS_SUCCESS ==
277                 contacts_svc_get_vcard_from_contact(contact,
278                                                     &vcard_stream)) {
279                 //save results to file
280                 outputFile.write(vcard_stream, strlen(vcard_stream));
281             }
282             //add file to results
283             result.push_back(name.str());
284         } else {
285             //return if cannot create file
286             LogError("cannot open file");
287             return std::vector<std::string>();
288         }
289         //close file
290         outputFile.close();
291     }
292     //return file names
293     return result;
294 }
295
296 void AddressBook::internalAddGroup(const std::string &groupName) const
297 {
298     LogDebug("entered");
299     //dont add group when already exists
300     if (getGroupId(groupName) != -1) {
301         LogWarning("group already exists");
302         return;
303     }
304     //create plaform struct describing group
305     CTSvalue *group = contacts_svc_value_new(CTS_VALUE_GROUP);
306     if (group) {
307         //set group name
308         contacts_svc_value_set_str(group,
309                                    CTS_GROUP_VAL_NAME_STR,
310                                    groupName.c_str());
311         //set default ring tone
312         contacts_svc_value_set_str(group, CTS_GROUP_VAL_RINGTONE_STR, "");
313         //try to add new group
314         if (contacts_svc_insert_group(0, group) < CTS_SUCCESS) {
315             //failed, free data and throw exception
316             contacts_svc_value_free(group);
317             LogError("contacts_svc_insert_group() Failed");
318             ThrowMsg(Commons::PlatformException,
319                      "Error during executing contacts_svc_insert_group()");
320         }
321         //success, free data
322         contacts_svc_value_free(group);
323     } else {
324         //throw exception
325         ThrowMsg(Commons::PlatformException, "Group object not created");
326     }
327 }
328
329 void AddressBook::internalDeleteGroup(const std::string &groupName) const
330 {
331     LogDebug("entered");
332     int groupId = getGroupId(groupName);
333     if (groupId != -1) {
334         LogDebug("deleting group, id " << groupId);
335         if (CTS_SUCCESS != contacts_svc_delete_group(groupId)) {
336             ThrowMsg(Commons::PlatformException,
337                      "Error during deleting a group");
338         }
339     }
340 }
341
342 int AddressBook::getGroupId(const std::string &groupName)
343 {
344     LogDebug("entered with group name " << groupName);
345     CTSiter *iter = NULL;
346     if (CTS_SUCCESS == contacts_svc_get_list(CTS_LIST_ALL_GROUP, &iter)) {
347         while (CTS_SUCCESS == contacts_svc_iter_next(iter)) {
348             CTSvalue *group = contacts_svc_iter_get_info(iter);
349             if (group) {
350                 const char *foundGroupName = contacts_svc_value_get_str(
351                         group,
352                         CTS_LIST_GROUP_NAME_STR);
353                 if (foundGroupName && groupName == foundGroupName) {
354                     int groupId = contacts_svc_value_get_int(
355                             group,
356                             CTS_LIST_GROUP_ID_INT);
357                     contacts_svc_value_free(group);
358                     contacts_svc_iter_remove(iter);
359                     return groupId;
360                 }
361                 contacts_svc_value_free(group);
362             }
363         }
364         contacts_svc_iter_remove(iter);
365     }
366     return -1;
367 }
368
369 std::vector<std::string> AddressBook::internalFindGroup(
370         const std::string &groupName) const
371 {
372     LogDebug("entered with group filter: " << groupName);
373     std::vector<std::string> result;
374     CTSiter *iter = NULL;
375     if (CTS_SUCCESS == contacts_svc_get_list(CTS_LIST_ALL_GROUP, &iter)) {
376         while (CTS_SUCCESS == contacts_svc_iter_next(iter)) {
377             CTSvalue *group = contacts_svc_iter_get_info(iter);
378             if (group) {
379                 const char *foundGroupName = contacts_svc_value_get_str(
380                         group,
381                         CTS_LIST_GROUP_NAME_STR);
382                 if (foundGroupName) {
383                     if (groupName.empty() ||
384                         Commons::validate(groupName,
385                                           foundGroupName,
386                                           Commons::VALIDATE_MATCH_CASELESS))
387                     {
388                         LogDebug("found group " << foundGroupName);
389                         result.push_back(foundGroupName);
390                     }
391                 }
392                 contacts_svc_value_free(group);
393             }
394         }
395         contacts_svc_iter_remove(iter);
396     }
397     return result;
398 }
399
400 void AddressBook::internalAddContact(const ContactPtr &newContact) const
401 {
402     LogDebug("entered");
403
404     //translate provided path to real filesystem path
405     if (newContact->getPhotoIsSet()) {
406         std::string realpath = getRealPath(newContact->getPhotoUri());
407         newContact->setPhotoUri(realpath);
408     }
409
410     ContactWrapperPtr contactWrapper(new ContactWrapper(m_bookType));
411     contactWrapper->setAbstractContact(newContact);
412     CTSstruct* contact = contactWrapper->getPlatformContact();
413     if (!contact) {
414         LogError("Error during converting contact object");
415         ThrowMsg(Commons::PlatformException,
416                  "Error during converting contact object");
417     }
418     int id = contacts_svc_insert_contact(0, contact);
419     if (id < 0) {
420         LogError("error code " << id);
421         ThrowMsg(Commons::PlatformException,
422                  "Error during executing contacts_svc_insert_contact()");
423     }
424     newContact->setId(id);
425 }
426
427 void AddressBook::internalUpdateContact(const Api::ContactPtr &updatedContact)
428 const
429 {
430     LogDebug("entered");
431     if (!updatedContact) {
432         ThrowMsg(Commons::PlatformException, "Contact is NULL");
433     }
434     if (!updatedContact->getIdIsSet()) {
435         ThrowMsg(Commons::PlatformException, "Contact is not saved yet");
436     }
437     LogDebug("update contact with id " << updatedContact->getId());
438     ContactWrapperPtr contactWrapper(new ContactWrapper(m_bookType));
439     contactWrapper->setAbstractContact(updatedContact);
440     CTSstruct* contact = contactWrapper->getPlatformContact();
441     if (!contact) {
442         LogError("Error during converting contact object");
443         ThrowMsg(Commons::PlatformException,
444                  "Error during converting contact object");
445     }
446     if (CTS_SUCCESS != contacts_svc_update_contact(contact)) {
447         ThrowMsg(Commons::PlatformException,
448                  "Error during executing contacts_svc_update_contact()");
449     }
450     LogDebug("update successful");
451 }
452
453 ContactPtr AddressBook::internalFindContactById(int id) const
454 {
455     LogDebug("entered with id " << id);
456     CTSstruct *contact = NULL;
457     int errorCode = contacts_svc_get_contact(id, &contact);
458     if (CTS_SUCCESS == errorCode) {
459         ContactWrapperPtr contactWrapper(new ContactWrapper(m_bookType));
460         contactWrapper->setPlatformContact(contact);
461         ContactPtr contact = contactWrapper->getAbstractContact();
462         if (!contact) {
463             ThrowMsg(Commons::PlatformException,
464                      "Error during converting contact object");
465         }
466         return contact;
467     } else if (CTS_ERR_DB_RECORD_NOT_FOUND == errorCode) {
468         LogWarning("record not found");
469         return ContactPtr(NULL);
470     } else {
471         ThrowMsg(Commons::PlatformException,
472                  "Error during executing contacts_svc_get_contact()");
473     }
474 }
475
476 std::vector<ContactPtr> AddressBook::internalFindContactByFilter(
477         const ContactFilterPtr &filter,
478         int startIndex,
479         int endIndex,
480         bool caseSensitive) const
481 {
482     LogDebug("entered");
483     std::vector<ContactPtr> result;
484     int count = 0;
485     CTSvalue *platformContact = NULL;
486     CTSiter *iter = NULL;
487     if (CTS_SUCCESS == contacts_svc_get_list(CTS_LIST_ALL_CONTACT, &iter)) {
488         while (CTS_SUCCESS == contacts_svc_iter_next(iter)) {
489             platformContact = contacts_svc_iter_get_info(iter);
490             if (platformContact) {
491                 int contactId = contacts_svc_value_get_int(
492                         platformContact,
493                         CTS_LIST_CONTACT_ID_INT);
494                 ContactPtr contact = internalFindContactById(contactId);
495                 /*Compare the contact to the filter*/
496                 if (contact && matchToFilter(filter, contact, caseSensitive)) {
497                     LogDebug("found contact by filter");
498                     if (count >= startIndex) {
499                         result.push_back(contact);
500                     }
501                     ++count;
502                 }
503                 contacts_svc_value_free(platformContact);
504                 if (endIndex != -1 && count > endIndex) {
505                     contacts_svc_iter_remove(iter);
506                     return result;
507                 }
508             }
509         }
510         contacts_svc_iter_remove(iter);
511     }
512     return result;
513 }
514
515 std::vector<ContactPtr> AddressBook::internalFindContactByGroup(
516         const std::string &groupName) const
517 {
518     LogDebug("entered with group: " << groupName);
519     std::vector<ContactPtr> result;
520     CTSvalue *platformContact = NULL;
521     CTSiter *iter = NULL;
522     if (CTS_SUCCESS == contacts_svc_get_list(CTS_LIST_ALL_CONTACT, &iter)) {
523         while (CTS_SUCCESS == contacts_svc_iter_next(iter)) {
524             platformContact = contacts_svc_iter_get_info(iter);
525             if (platformContact) {
526                 int contactId = contacts_svc_value_get_int(
527                         platformContact,
528                         CTS_LIST_CONTACT_ID_INT);
529                 ContactPtr contact = internalFindContactById(contactId);
530                 if (contact) {
531                     std::vector<std::string>::const_iterator found =
532                         find(contact->getGroups().begin(),
533                              contact->getGroups().end(), groupName);
534                     if (found != contact->getGroups().end()) {
535                         LogDebug("found contact in group");
536                         result.push_back(contact);
537                     }
538                 }
539                 contacts_svc_value_free(platformContact);
540             }
541         }
542         contacts_svc_iter_remove(iter);
543     }
544     return result;
545 }
546
547 void AddressBook::internalDeleteContactById(int id) const
548 {
549     LogDebug("entered with id " << id);
550     if (id != -1) {
551         CTSstruct *contact = NULL;
552         /*If the contact is not existed, throw NotFoundException*/
553         if (CTS_SUCCESS != contacts_svc_get_contact(id, &contact)) {
554             ThrowMsg(Commons::NotFoundException,
555                      "Can't delete contact, contact doesn't exist. Error code");
556         }
557
558         if (CTS_SUCCESS != contacts_svc_delete_contact(id)) {
559             ThrowMsg(Commons::PlatformException,
560                      "Error during executing contacts_svc_delete_contact()");
561         }
562     }
563 }
564
565 unsigned int AddressBook::internalGetNumberOfContacts() const
566 {
567     LogDebug("entered");
568     int result = contacts_svc_count_with_int(
569             CTS_GET_COUNT_CONTACTS_IN_ADDRESSBOOK,
570             0);
571     if (result < 0) {
572         ThrowMsg(Commons::PlatformException,
573                  "Error during executing contacts_svc_count_with_int()");
574     }
575     return result;
576 }
577
578 std::vector<ContactPtr> AddressBook::mergeRecords(
579         const std::vector<ContactPtr> &contacts) const
580 {
581     LogDebug("entered");
582     std::vector<ContactPtr> merged;
583     std::vector<ContactPtr>::const_iterator it;
584     for (it = contacts.begin(); it != contacts.end(); ++it) {
585         ContactPtr copy = (*it)->clone();
586         /*Merge types of emails with the same email address*/
587         copy->setEmails(mergeEmails(copy->getEmails()));
588         /*Merge types of phonenumbers with the same number*/
589         copy->setPhoneNumbers(mergePhoneNumbers(copy->getPhoneNumbers()));
590         /*Merge types of addresses with the same address info*/
591         copy->setAddresses(mergeAddresses(copy->getAddresses()));
592         merged.push_back(copy);
593     }
594     return merged;
595 }
596
597 std::vector<ContactEmailPtr> AddressBook::mergeEmails(
598         const std::vector<ContactEmailPtr> &emails) const
599 {
600     LogDebug("entered");
601     std::vector<ContactEmailPtr> merged;
602     std::vector<ContactEmailPtr>::const_iterator it;
603     std::vector<ContactEmailPtr>::const_iterator mergedIt;
604     std::vector<ContactEmail::ContactEmailType>::const_iterator typesIt;
605     bool found;
606     for (it = emails.begin(); it != emails.end(); ++it) {
607         found = false;
608         for (mergedIt = merged.begin(); mergedIt != merged.end(); ++mergedIt) {
609             if ((*mergedIt)->getEmail() == (*it)->getEmail()) {
610                 LogDebug("found the same email " << (*mergedIt)->getEmail());
611                 //the same emails, check types and add if needed
612                 const std::vector<ContactEmail::ContactEmailType> &types =
613                     (*it)->getTypes();
614                 for (typesIt = types.begin(); typesIt != types.end();
615                      ++typesIt) {
616                     if (!(*mergedIt)->isTypeOf(*typesIt)) {
617                         (*mergedIt)->addType(*typesIt);
618                         LogInfo("merged email type " << *typesIt);
619                     }
620                 }
621                 found = true;
622                 break;
623             }
624         }
625         if (!found) {
626             LogInfo("copy email");
627             merged.push_back((*it)->clone());
628         }
629     }
630     return merged;
631 }
632
633 std::vector<ContactPhoneNumberPtr> AddressBook::mergePhoneNumbers(
634         const std::vector<ContactPhoneNumberPtr> &phoneNumbers) const
635 {
636     LogDebug("entered");
637     std::vector<ContactPhoneNumberPtr> merged;
638     std::vector<ContactPhoneNumberPtr>::const_iterator it;
639     std::vector<ContactPhoneNumberPtr>::const_iterator mergedIt;
640     std::vector<ContactPhoneNumber::ContactPhoneNumberType>::const_iterator
641         typesIt;
642     bool found;
643     for (it = phoneNumbers.begin(); it != phoneNumbers.end(); ++it) {
644         found = false;
645         for (mergedIt = merged.begin(); mergedIt != merged.end(); ++mergedIt) {
646             if ((*mergedIt)->getNumber() == (*it)->getNumber()) {
647                 LogDebug(
648                     "found the same phone number " << (*mergedIt)->getNumber());
649                 //the same emails, check types and add if needed
650                 const std::vector<ContactPhoneNumber::ContactPhoneNumberType> &
651                 types = (*it)->getTypes();
652                 for (typesIt = types.begin(); typesIt != types.end();
653                      ++typesIt) {
654                     if (!(*mergedIt)->isTypeOf(*typesIt)) {
655                         LogInfo("merged phone type " << *typesIt);
656                         (*mergedIt)->addType(*typesIt);
657                     }
658                 }
659                 found = true;
660                 break;
661             }
662         }
663         if (!found) {
664             LogInfo("copy phone");
665             merged.push_back((*it)->clone());
666         }
667     }
668     return merged;
669 }
670
671 std::vector<ContactAddressPtr> AddressBook::mergeAddresses(
672         const std::vector<ContactAddressPtr> &addresses) const
673 {
674     LogDebug("entered");
675     std::vector<ContactAddressPtr> merged;
676     std::vector<ContactAddressPtr>::const_iterator it;
677     std::vector<ContactAddressPtr>::const_iterator mergedIt;
678     std::vector<ContactAddress::ContactAddressType>::const_iterator typesIt;
679     bool found;
680     for (it = addresses.begin(); it != addresses.end(); ++it) {
681         found = false;
682         for (mergedIt = merged.begin(); mergedIt != merged.end(); ++mergedIt) {
683             if ((*mergedIt)->compareTo((*it))) {
684                 LogDebug("found the same address");
685                 //the same emails, check types and add if needed
686                 const std::vector<ContactAddress::ContactAddressType> &types =
687                     (*it)->getTypes();
688                 for (typesIt = types.begin(); typesIt != types.end();
689                      ++typesIt) {
690                     if (!(*mergedIt)->isTypeOf(*typesIt)) {
691                         LogInfo("merged address type " << *typesIt);
692                         (*mergedIt)->addType(*typesIt);
693                     }
694                 }
695                 found = true;
696                 break;
697             }
698         }
699         if (!found) {
700             LogInfo("copy address");
701             merged.push_back((*it)->clone());
702         }
703     }
704     return merged;
705 }
706
707 bool AddressBook::matchToFilter(const ContactFilterPtr &filter,
708         const ContactPtr &contact,
709         bool caseSensitive) const
710 {
711     LogDebug("entered");
712     if (!contact) {
713         //no object provided
714         return false;
715     }
716     if (!filter) {
717         //pass all when no filter
718         return true;
719     }
720     unsigned int matchOptions =
721         caseSensitive ? 0 : Commons::VALIDATE_MATCH_CASELESS;
722     if (filter->getFullNameIsSet()) {
723         if (!Commons::validate(filter->getFullNameFilter(),
724                                contact->getFullName(),
725                                matchOptions))
726         {
727             LogDebug("rejected FullName");
728             return false;
729         }
730     }
731     if (filter->getFirstNameIsSet()) {
732         if (!Commons::validate(filter->getFirstNameFilter(),
733                                contact->getFirstName(),
734                                matchOptions))
735         {
736             LogDebug("rejected First Name");
737             return false;
738         }
739     }
740     if (filter->getLastNameIsSet()) {
741         if (!Commons::validate(filter->getLastNameFilter(),
742                                contact->getLastName(),
743                                matchOptions))
744         {
745             LogDebug("rejected Last Name");
746             return false;
747         }
748     }
749     if (filter->getCompanyIsSet()) {
750         if (!Commons::validate(filter->getCompanyFilter(),
751                                contact->getCompany(),
752                                matchOptions))
753         {
754             LogDebug("rejected company");
755             return false;
756         }
757     }
758     if (filter->getTitleIsSet()) {
759         if (!Commons::validate(filter->getTitleFilter(),
760                                contact->getTitle(),
761                                matchOptions))
762         {
763             LogDebug("rejected title");
764             return false;
765         }
766     }
767     if (filter->getPhoneticNameIsSet()) {
768         if (!Commons::validate(filter->getPhoneticNameFilter(),
769                                contact->getPhoneticName(),
770                                matchOptions))
771         {
772             LogDebug("rejected PhoneticName");
773             return false;
774         }
775     }
776     if (!matchToFilterEmail(filter, contact, caseSensitive)) {
777         return false;
778     }
779     if (!matchToFilterAddress(filter, contact, caseSensitive)) {
780         return false;
781     }
782     if (!matchToFilterPhoneNumber(filter, contact, caseSensitive)) {
783         return false;
784     }
785     if (!matchToFilterNickname(filter, contact, caseSensitive)) {
786         return false;
787     }
788     return true;
789 }
790
791 bool AddressBook::matchToFilterAddress(const Api::ContactFilterPtr &filter,
792         const Api::ContactPtr &contact,
793         bool caseSensitive) const
794 {
795     if (filter->getAddressIsSet()) {
796         bool found;
797         unsigned int matchOptions =
798             caseSensitive ? 0 : Commons::VALIDATE_MATCH_CASELESS;
799         LogDebug("filtering by address");
800         const std::vector<ContactAddressPtr> &addressFilter =
801             filter->getAddressFilter();
802         const std::vector<ContactAddressPtr> &addresses = contact->getAddresses();
803         for (std::size_t i = 0; i < addressFilter.size(); ++i) {
804             found = false;
805             const std::vector<ContactAddress::ContactAddressType> &
806             addrFilterTypes = addressFilter[i]->getTypes();
807             for (std::size_t j = 0; j < addresses.size(); ++j) {
808                 if (!addrFilterTypes.empty()) {
809                     if (!addresses[j]->isTypeOf(addressFilter[i]->getTypeFilter()))
810                     {
811                         LogDebug("rejected by Type!");
812                         continue;
813                     }
814                 }
815                 if (addressFilter[i]->getCountryIsSet()) {
816                     if (!Commons::validate(addressFilter[i]->getCountry(),
817                                            addresses[j]->getCountry(),
818                                            matchOptions))
819                     {
820                         LogDebug("rejected by address");
821                         continue;
822                         //return false;
823                     }
824                 }
825                 if (addressFilter[i]->getRegionIsSet()) {
826                     if (!Commons::validate(addressFilter[i]->getRegion(),
827                                            addresses[j]->getRegion(),
828                                            matchOptions))
829                     {
830                         LogDebug("rejected by address");
831                         continue;
832                         //return false;
833                     }
834                 }
835                 if (addressFilter[i]->getCountyIsSet()) {
836                     if (!Commons::validate(addressFilter[i]->getCounty(),
837                                            addresses[j]->getCounty(),
838                                            matchOptions))
839                     {
840                         LogDebug("rejected by address");
841                         continue;
842                         //return false;
843                     }
844                 }
845                 if (addressFilter[i]->getCityIsSet()) {
846                     if (!Commons::validate(addressFilter[i]->getCity(),
847                                            addresses[j]->getCity(),
848                                            matchOptions))
849                     {
850                         LogDebug("rejected by address");
851                         continue;
852                         //return false;
853                     }
854                 }
855                 if (addressFilter[i]->getStreetIsSet()) {
856                     if (!Commons::validate(addressFilter[i]->getStreet(),
857                                            addresses[j]->getStreet(),
858                                            matchOptions))
859                     {
860                         LogDebug("rejected by address");
861                         continue;
862                         //return false;
863                     }
864                 }
865                 if (addressFilter[i]->getStreetNumberIsSet()) {
866                     if (!Commons::validate(addressFilter[i]->getStreetNumber(),
867                                            addresses[j]->getStreetNumber(),
868                                            matchOptions))
869                     {
870                         LogDebug("rejected by address");
871                         continue;
872                         //return false;
873                     }
874                 }
875                 if (addressFilter[i]->getPremisesIsSet()) {
876                     if (!Commons::validate(addressFilter[i]->getPremises(),
877                                            addresses[j]->getPremises(),
878                                            matchOptions))
879                     {
880                         LogDebug("rejected by address");
881                         continue;
882                         //return false;
883                     }
884                 }
885                 if (addressFilter[i]->getAdditionalInformationIsSet()) {
886                     if (!Commons::validate(
887                             addressFilter[i]->getAdditionalInformation(),
888                             addresses[j]->getAdditionalInformation(),
889                             matchOptions))
890                     {
891                         LogDebug("rejected by address");
892                         continue;
893                         //return false;
894                     }
895                 }
896                 if (addressFilter[i]->getPostalCodeIsSet()) {
897                     if (!Commons::validate(addressFilter[i]->getPostalCode(),
898                                            addresses[j]->getPostalCode(),
899                                            matchOptions))
900                     {
901                         LogDebug("rejected by address");
902                         continue;
903                         //return false;
904                     }
905                 }
906                 found = true;
907                 break;
908             }
909             if (!found) {
910                 LogDebug("rejected by address");
911                 return false;
912             }
913         }
914     }
915     return true;
916 }
917
918 bool AddressBook::matchToFilterEmail(const Api::ContactFilterPtr &filter,
919         const Api::ContactPtr &contact,
920         bool caseSensitive) const
921 {
922     if (filter->getEmailIsSet()) {
923         bool found;
924         unsigned int matchOptions =
925             caseSensitive ? 0 : Commons::VALIDATE_MATCH_CASELESS;
926         LogDebug("filtering by email");
927         const std::vector<ContactEmailPtr> &emailFilter =
928             filter->getEmailFilter();
929         const std::vector<ContactEmailPtr> &emails = contact->getEmails();
930         for (std::size_t i = 0; i < emailFilter.size(); ++i) {
931             found = false;
932             const std::vector<ContactEmail::ContactEmailType> &emailFilterTypes
933                 = emailFilter[i]->getTypes();
934             for (std::size_t j = 0; j < emails.size(); ++j) {
935                 if (!emailFilterTypes.empty()) {
936                     if (!emails[j]->isTypeOf(emailFilter[i]->getTypeFilter()))
937                     {
938                         LogDebug("type error!!!");
939                         continue;
940                     }
941                 }
942                 if (!Commons::validate(emailFilter[i]->getEmail(),
943                                        emails[j]->getEmail(),
944                                        matchOptions))
945                 {
946                     LogDebug("rejected by email, different email");
947                     continue;
948                 }
949                 found = true;
950                 break;
951             }
952             if (!found) {
953                 LogDebug("rejected by email, not found email");
954                 return false;
955             }
956         }
957     }
958     return true;
959 }
960
961 bool AddressBook::matchToFilterPhoneNumber(const Api::ContactFilterPtr &filter,
962         const Api::ContactPtr &contact,
963         bool caseSensitive) const
964 {
965     if (filter->getPhoneNumberIsSet()) {
966         bool found;
967         unsigned int matchOptions =
968             caseSensitive ? 0 : Commons::VALIDATE_MATCH_CASELESS;
969         LogDebug("filtering by phone number");
970         const std::vector<ContactPhoneNumberPtr> &phoneNumberFilter =
971             filter->getPhoneNumberFilter();
972         const std::vector<ContactPhoneNumberPtr> &phoneNumber =
973             contact->getPhoneNumbers();
974         for (std::size_t i = 0; i < phoneNumberFilter.size(); ++i) {
975             found = false;
976             const std::vector<ContactPhoneNumber::ContactPhoneNumberType> &
977             phoneNumberFilterTypes = phoneNumberFilter[i]->getTypes();
978             for (std::size_t j = 0; j < phoneNumber.size(); ++j) {
979                 if (!phoneNumberFilterTypes.empty()) {
980                     if (!phoneNumber[j]->isTypeOf(phoneNumberFilter[i]->
981                                                       getTypeFilter()))
982                     {
983                         LogDebug("rejected by phone type");
984                         continue;
985                     }
986                 }
987                 if (!Commons::validate(phoneNumberFilter[i]->getNumber(),
988                                        phoneNumber[j]->getNumber(),
989                                        matchOptions))
990                 {
991                     LogDebug("rejected by phone number");
992                     continue;
993                 }
994                 found = true;
995                 break;
996             }
997             if (!found) {
998                 LogDebug("rejected by phone number");
999                 return false;
1000             }
1001         }
1002     }
1003     return true;
1004 }
1005
1006 bool AddressBook::matchToFilterNickname(const Api::ContactFilterPtr &filter,
1007         const Api::ContactPtr &contact,
1008         bool caseSensitive) const
1009 {
1010     if (filter->getNickNameIsSet()) {
1011         bool found;
1012         unsigned int matchOptions =
1013             caseSensitive ? 0 : Commons::VALIDATE_MATCH_CASELESS;
1014         LogDebug("filtering by nickname");
1015         const std::vector<std::string> &nicknameFilter =
1016             filter->getNickNameFilter();
1017         const std::vector<std::string> &nickname = contact->getNickNames();
1018         for (std::size_t i = 0; i < nicknameFilter.size(); ++i) {
1019             found = false;
1020             for (std::size_t j = 0; j < nickname.size(); ++j) {
1021                 if (!Commons::validate(nicknameFilter[i],
1022                                        nickname[j],
1023                                        matchOptions))
1024                 {
1025                     continue;
1026                 }
1027                 found = true;
1028                 break;
1029             }
1030             if (!found) {
1031                 LogDebug("rejected by nickname");
1032                 return false;
1033             }
1034         }
1035     }
1036     return true;
1037 }
1038
1039 //**************************************
1040 //*             Events                 *
1041 //**************************************
1042
1043 void AddressBook::OnRequestReceived(const Api::EventAddContactPtr &event)
1044 {
1045     LogDebug("entered");
1046     try
1047     {
1048         const ContactPtr &contact = event->getContact();
1049         if (contact) {
1050             internalAddContact(contact);
1051             event->setResult(true);
1052         }
1053     }
1054     catch (const Commons::PlatformException &ex)
1055     {
1056         LogError("Error during adding contact.");
1057         LogError(ex.GetMessage());
1058     }
1059 }
1060
1061 void AddressBook::OnRequestReceived(const Api::EventUpdateContactPtr &event)
1062 {
1063     LogDebug("entered");
1064     try
1065     {
1066         const ContactPtr &contact = event->getContact();
1067         if (contact) {
1068             internalUpdateContact(contact);
1069             event->setResult(true);
1070         }
1071     }
1072     catch (const Commons::PlatformException &ex)
1073     {
1074         LogError("Error during updating contact.");
1075         LogError(ex.GetMessage());
1076     }
1077 }
1078
1079 void AddressBook::OnRequestReceived(const Api::EventDeleteContactPtr &event)
1080 {
1081     LogDebug("entered");
1082     try
1083     {
1084         const ContactFilterPtr &filter = event->getFilter();
1085         if (filter && filter->getIdIsSet()) {
1086             internalDeleteContactById(filter->getIdFilter());
1087             event->setResult(true);
1088         }
1089     }
1090     catch (const Commons::NotFoundException &ex)
1091     {
1092         LogError("Contact doesn't exist");
1093         event->setResult(false);
1094         event->setExceptionCode(Commons::ExceptionCodes::NotFoundException);
1095     }
1096     catch (const Commons::PlatformException &ex)
1097     {
1098         LogError("Error during deleting contact.");
1099         LogError(ex.GetMessage());
1100         event->setResult(false);
1101     }
1102 }
1103
1104 void AddressBook::OnRequestReceived(const Api::EventFindContactsPtr &event)
1105 {
1106     LogDebug("entered");
1107     ContactFilterPtr filter = event->getFilter();
1108     try
1109     {
1110         if (filter && filter->getIdIsSet()) {
1111             LogDebug("searching for contact by id");
1112             ContactPtr contact = internalFindContactById(filter->getIdFilter());
1113             if (contact) {
1114                 event->addContact(contact);
1115             }
1116             event->setResult(true);
1117         } else if (filter && filter->getGroupIsSet()) {
1118             LogDebug("searching for contact by group");
1119             const std::vector<ContactPtr> &contacts =
1120                 internalFindContactByGroup(filter->getGroupFilter());
1121             event->setContacts(contacts);
1122             event->setResult(true);
1123         } else {
1124             LogDebug("searching for contact by filter");
1125             const std::vector<ContactPtr> &contacts =
1126                 internalFindContactByFilter(filter,
1127                                             event->getStartIndex(),
1128                                             event->getEndIndex(), false);
1129             event->setContacts(contacts);
1130             event->setResult(true);
1131         }
1132         if (!event->getUseSignleTypes()) {
1133             const std::vector<ContactPtr> &contacts = event->getContacts();
1134             std::vector<ContactPtr> merged = mergeRecords(contacts);
1135             event->setContacts(merged);
1136         }
1137     }
1138     catch (const Commons::PlatformException &ex)
1139     {
1140         LogError("Error during getting contact.");
1141         LogError(ex.GetMessage());
1142     }
1143 }
1144
1145 void AddressBook::OnRequestReceived(
1146         const Api::EventGetAddressBookItemCountPtr &event)
1147 {
1148     LogDebug("entered");
1149     try
1150     {
1151         unsigned int count = internalGetNumberOfContacts();
1152         event->setNumberOfAddressBookItems(count);
1153         event->setResult(true);
1154     }
1155     catch (const Commons::PlatformException &ex)
1156     {
1157         LogError("Error during getting contact.");
1158         LogError(ex.GetMessage());
1159     }
1160 }
1161
1162 void AddressBook::OnRequestReceived(const Api::EventAddGroupPtr &event)
1163 {
1164     LogDebug("entered");
1165     try
1166     {
1167         internalAddGroup(event->getGroupName());
1168         event->setResult(true);
1169     }
1170     catch (const Commons::PlatformException &ex)
1171     {
1172         LogError("Error during adding group.");
1173         LogError(ex.GetMessage());
1174     }
1175 }
1176
1177 void AddressBook::OnRequestReceived(const Api::EventDeleteGroupPtr &event)
1178 {
1179     LogDebug("entered");
1180     try
1181     {
1182         internalDeleteGroup(event->getGroupName());
1183         event->setResult(true);
1184     }
1185     catch (const Commons::PlatformException &ex)
1186     {
1187         LogError("Error during getting contact.");
1188         LogError(ex.GetMessage());
1189     }
1190 }
1191
1192 void AddressBook::OnRequestReceived(const Api::EventFindGroupPtr &event)
1193 {
1194     LogDebug("entered");
1195     try
1196     {
1197         std::vector<std::string> groups = internalFindGroup(event->getGroupName());
1198         event->setFoundGroups(groups);
1199         event->setResult(true);
1200     }
1201     catch (const Commons::PlatformException &ex)
1202     {
1203         LogError("Error during getting groups.");
1204         LogError(ex.GetMessage());
1205     }
1206 }
1207
1208 void AddressBook::OnRequestReceived(const Api::EventExportVCardPtr &event)
1209 {
1210     LogDebug("entered");
1211     try
1212     {
1213         const std::vector<ContactPtr> &contacts = event->getContacts();
1214         LogDebug("number of contacts to export: " << contacts.size());
1215         if (contacts.size() == 0) {
1216             event->setResult(true);
1217             return;
1218         }
1219         std::vector<std::string> paths = internalExportToVCard(contacts);
1220         if (paths.size() > 0) {
1221             event->setResult(true);
1222             event->setPathToFiles(paths);
1223         }
1224     }
1225     catch (const Commons::PlatformException &ex)
1226     {
1227         LogError("Error during getting groups.");
1228         LogError(ex.GetMessage());
1229     }
1230 }
1231 }
1232 }
1233