1 /*
2 vcard.cc
3 Copyright (C) 2015 Belledonne Communications SARL
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 #include "vcard_private.h"
21 #include "belcard/belcard.hpp"
22 #include "belcard/belcard_parser.hpp"
23 #include "sal/sal.h"
24 #include <bctoolbox/crypto.h>
25 #include "private.h"
26 #include "linphone/factory.h"
27 #include "linphone/wrapper_utils.h"
28
29 #define VCARD_MD5_HASH_SIZE 16
30
31 using namespace std;
32
33 struct _LinphoneVcardContext {
34 shared_ptr<belcard::BelCardParser> parser;
35 void *user_data;
36 };
37
38 extern "C" {
39
linphone_vcard_context_new(void)40 LinphoneVcardContext* linphone_vcard_context_new(void) {
41 LinphoneVcardContext* context = ms_new0(LinphoneVcardContext, 1);
42 context->parser = belcard::BelCardParser::getInstance();
43 context->user_data = NULL;
44 return context;
45 }
46
linphone_vcard_context_destroy(LinphoneVcardContext * context)47 void linphone_vcard_context_destroy(LinphoneVcardContext *context) {
48 if (context) {
49 context->parser = nullptr;
50 ms_free(context);
51 }
52 }
53
linphone_vcard_context_get_user_data(const LinphoneVcardContext * context)54 void* linphone_vcard_context_get_user_data(const LinphoneVcardContext *context) {
55 return context ? context->user_data : NULL;
56 }
57
58
linphone_vcard_context_set_user_data(LinphoneVcardContext * context,void * data)59 void linphone_vcard_context_set_user_data(LinphoneVcardContext *context, void *data) {
60 if (context) context->user_data = data;
61 }
62
63 } // extern "C"
64
65
66 struct _LinphoneVcard {
67 belle_sip_object_t base;
68 shared_ptr<belcard::BelCard> belCard;
69 char *etag;
70 char *url;
71 unsigned char md5[VCARD_MD5_HASH_SIZE];
72 bctbx_list_t *sip_addresses_cache;
73 };
74
75 extern "C" {
76
_linphone_vcard_uninit(LinphoneVcard * vCard)77 static void _linphone_vcard_uninit(LinphoneVcard *vCard) {
78 if (vCard->etag) ms_free(vCard->etag);
79 if (vCard->url) ms_free(vCard->url);
80 linphone_vcard_clean_cache(vCard);
81 vCard->belCard.reset();
82 }
83
84 BELLE_SIP_DECLARE_VPTR_NO_EXPORT(LinphoneVcard);
85 BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(LinphoneVcard);
86 BELLE_SIP_INSTANCIATE_VPTR(LinphoneVcard, belle_sip_object_t,
87 _linphone_vcard_uninit, // destroy
88 NULL, // clone
89 NULL, // Marshall
90 FALSE
91 );
92
_linphone_vcard_new(void)93 LinphoneVcard* _linphone_vcard_new(void) {
94 LinphoneVcard* vCard = belle_sip_object_new(LinphoneVcard);
95 vCard->belCard = belcard::BelCardGeneric::create<belcard::BelCard>();
96 return vCard;
97 }
98
linphone_vcard_new(void)99 LinphoneVcard *linphone_vcard_new(void) {
100 return _linphone_vcard_new();
101 }
102
linphone_vcard_new_from_belcard(shared_ptr<belcard::BelCard> belcard)103 static LinphoneVcard* linphone_vcard_new_from_belcard(shared_ptr<belcard::BelCard> belcard) {
104 LinphoneVcard* vCard = belle_sip_object_new(LinphoneVcard);
105 vCard->belCard = belcard;
106 return vCard;
107 }
108
linphone_vcard_free(LinphoneVcard * vCard)109 void linphone_vcard_free(LinphoneVcard *vCard) {
110 belle_sip_object_unref((belle_sip_object_t *)vCard);
111 }
112
linphone_vcard_ref(LinphoneVcard * vCard)113 LinphoneVcard *linphone_vcard_ref(LinphoneVcard *vCard) {
114 return (LinphoneVcard *)belle_sip_object_ref((belle_sip_object_t *)vCard);
115 }
116
linphone_vcard_unref(LinphoneVcard * vCard)117 void linphone_vcard_unref(LinphoneVcard *vCard) {
118 belle_sip_object_unref((belle_sip_object_t *)vCard);
119 }
120
linphone_vcard_clone(const LinphoneVcard * vCard)121 LinphoneVcard *linphone_vcard_clone(const LinphoneVcard *vCard) {
122 LinphoneVcard *copy = belle_sip_object_new(LinphoneVcard);
123
124 copy->belCard = belcard::BelCardParser::getInstance()->parseOne(vCard->belCard->toFoldedString());
125
126 if (vCard->url) copy->url = ms_strdup(vCard->url);
127 if (vCard->etag) copy->etag = ms_strdup(vCard->etag);
128
129 memcpy(copy->md5, vCard->md5, sizeof *vCard->md5);
130
131 return copy;
132 }
133
linphone_vcard_context_get_vcard_list_from_file(LinphoneVcardContext * context,const char * filename)134 bctbx_list_t* linphone_vcard_context_get_vcard_list_from_file(LinphoneVcardContext *context, const char *filename) {
135 bctbx_list_t *result = NULL;
136 if (context && filename) {
137 if (!context->parser) {
138 context->parser = belcard::BelCardParser::getInstance();
139 }
140 shared_ptr<belcard::BelCardList> belCards = context->parser->parseFile(filename);
141 if (belCards) {
142 for (auto it = belCards->getCards().begin(); it != belCards->getCards().end(); ++it) {
143 shared_ptr<belcard::BelCard> belCard = (*it);
144 LinphoneVcard *vCard = linphone_vcard_new_from_belcard(belCard);
145 result = bctbx_list_append(result, vCard);
146 }
147 }
148 }
149 return result;
150 }
151
linphone_vcard_context_get_vcard_list_from_buffer(LinphoneVcardContext * context,const char * buffer)152 bctbx_list_t* linphone_vcard_context_get_vcard_list_from_buffer(LinphoneVcardContext *context, const char *buffer) {
153 bctbx_list_t *result = NULL;
154 if (context && buffer) {
155 if (!context->parser) {
156 context->parser = belcard::BelCardParser::getInstance();
157 }
158 shared_ptr<belcard::BelCardList> belCards = context->parser->parse(buffer);
159 if (belCards) {
160 for (auto it = belCards->getCards().begin(); it != belCards->getCards().end(); ++it) {
161 shared_ptr<belcard::BelCard> belCard = (*it);
162 LinphoneVcard *vCard = linphone_vcard_new_from_belcard(belCard);
163 result = bctbx_list_append(result, vCard);
164 }
165 }
166 }
167 return result;
168 }
169
linphone_vcard_context_get_vcard_from_buffer(LinphoneVcardContext * context,const char * buffer)170 LinphoneVcard* linphone_vcard_context_get_vcard_from_buffer(LinphoneVcardContext *context, const char *buffer) {
171 LinphoneVcard *vCard = NULL;
172 if (context && buffer) {
173 if (!context->parser) {
174 context->parser = belcard::BelCardParser::getInstance();
175 }
176 shared_ptr<belcard::BelCard> belCard = context->parser->parseOne(buffer);
177 if (belCard) {
178 vCard = linphone_vcard_new_from_belcard(belCard);
179 } else {
180 ms_error("Couldn't parse buffer %s", buffer);
181 }
182 }
183 return vCard;
184 }
185
linphone_vcard_as_vcard4_string(LinphoneVcard * vCard)186 const char * linphone_vcard_as_vcard4_string(LinphoneVcard *vCard) {
187 if (!vCard) return NULL;
188
189 return vCard->belCard->toFoldedString().c_str();
190 }
191
linphone_vcard_get_belcard(LinphoneVcard * vcard)192 void *linphone_vcard_get_belcard(LinphoneVcard *vcard) {
193 return &vcard->belCard;
194 }
195
linphone_vcard_set_full_name(LinphoneVcard * vCard,const char * name)196 void linphone_vcard_set_full_name(LinphoneVcard *vCard, const char *name) {
197 if (!vCard || !name) return;
198
199 if (vCard->belCard->getFullName()) {
200 vCard->belCard->getFullName()->setValue(name);
201 } else {
202 shared_ptr<belcard::BelCardFullName> fn = belcard::BelCardGeneric::create<belcard::BelCardFullName>();
203 fn->setValue(name);
204 vCard->belCard->setFullName(fn);
205 }
206 }
207
linphone_vcard_get_full_name(const LinphoneVcard * vCard)208 const char* linphone_vcard_get_full_name(const LinphoneVcard *vCard) {
209 if (!vCard) return NULL;
210
211 const char *result = vCard->belCard->getFullName() ? vCard->belCard->getFullName()->getValue().c_str() : NULL;
212 return result;
213 }
214
linphone_vcard_set_skip_validation(LinphoneVcard * vCard,bool_t skip)215 void linphone_vcard_set_skip_validation(LinphoneVcard *vCard, bool_t skip) {
216 if (!vCard || !vCard->belCard) return;
217
218 vCard->belCard->setSkipFieldValidation((skip == TRUE) ? true : false);
219 }
220
linphone_vcard_get_skip_validation(const LinphoneVcard * vCard)221 bool_t linphone_vcard_get_skip_validation(const LinphoneVcard *vCard) {
222 if (!vCard) return FALSE;
223
224 bool_t result = vCard->belCard->getSkipFieldValidation();
225 return result;
226 }
227
linphone_vcard_set_family_name(LinphoneVcard * vCard,const char * name)228 void linphone_vcard_set_family_name(LinphoneVcard *vCard, const char *name) {
229 if (!vCard || !name) return;
230
231 if (vCard->belCard->getName()) {
232 vCard->belCard->getName()->setFamilyName(name);
233 } else {
234 shared_ptr<belcard::BelCardName> n = belcard::BelCardGeneric::create<belcard::BelCardName>();
235 n->setFamilyName(name);
236 vCard->belCard->setName(n);
237 }
238 }
239
linphone_vcard_get_family_name(const LinphoneVcard * vCard)240 const char* linphone_vcard_get_family_name(const LinphoneVcard *vCard) {
241 if (!vCard) return NULL;
242
243 const char *result = vCard->belCard->getName() ? vCard->belCard->getName()->getFamilyName().c_str() : NULL;
244 return result;
245 }
246
linphone_vcard_set_given_name(LinphoneVcard * vCard,const char * name)247 void linphone_vcard_set_given_name(LinphoneVcard *vCard, const char *name) {
248 if (!vCard || !name) return;
249
250 if (vCard->belCard->getName()) {
251 vCard->belCard->getName()->setGivenName(name);
252 } else {
253 shared_ptr<belcard::BelCardName> n = belcard::BelCardGeneric::create<belcard::BelCardName>();
254 n->setGivenName(name);
255 vCard->belCard->setName(n);
256 }
257 }
258
linphone_vcard_get_given_name(const LinphoneVcard * vCard)259 const char* linphone_vcard_get_given_name(const LinphoneVcard *vCard) {
260 if (!vCard) return NULL;
261
262 const char *result = vCard->belCard->getName() ? vCard->belCard->getName()->getGivenName().c_str() : NULL;
263 return result;
264 }
265
linphone_vcard_add_sip_address(LinphoneVcard * vCard,const char * sip_address)266 void linphone_vcard_add_sip_address(LinphoneVcard *vCard, const char *sip_address) {
267 if (!vCard || !sip_address) return;
268
269 shared_ptr<belcard::BelCardImpp> impp = belcard::BelCardGeneric::create<belcard::BelCardImpp>();
270 impp->setValue(sip_address);
271 vCard->belCard->addImpp(impp);
272 }
273
linphone_vcard_remove_sip_address(LinphoneVcard * vCard,const char * sip_address)274 void linphone_vcard_remove_sip_address(LinphoneVcard *vCard, const char *sip_address) {
275 if (!vCard) return;
276
277 shared_ptr<belcard::BelCardImpp> impp;
278 for (auto it = vCard->belCard->getImpp().begin(); it != vCard->belCard->getImpp().end(); ++it) {
279 const char *value = (*it)->getValue().c_str();
280 if (strcmp(value, sip_address) == 0) {
281 impp = *it;
282 break;
283 }
284 }
285 if (impp) {
286 vCard->belCard->removeImpp(impp);
287 }
288 }
289
linphone_vcard_edit_main_sip_address(LinphoneVcard * vCard,const char * sip_address)290 void linphone_vcard_edit_main_sip_address(LinphoneVcard *vCard, const char *sip_address) {
291 if (!vCard || !sip_address) return;
292
293 if (vCard->belCard->getImpp().size() > 0) {
294 const shared_ptr<belcard::BelCardImpp> impp = vCard->belCard->getImpp().front();
295 impp->setValue(sip_address);
296 } else {
297 shared_ptr<belcard::BelCardImpp> impp = belcard::BelCardGeneric::create<belcard::BelCardImpp>();
298 impp->setValue(sip_address);
299 vCard->belCard->addImpp(impp);
300 }
301 }
302
linphone_vcard_get_sip_addresses(LinphoneVcard * vCard)303 const bctbx_list_t* linphone_vcard_get_sip_addresses(LinphoneVcard *vCard) {
304 if (!vCard) return NULL;
305 if (!vCard->sip_addresses_cache) {
306 for (auto it = vCard->belCard->getImpp().begin(); it != vCard->belCard->getImpp().end(); ++it) {
307 LinphoneAddress* addr = linphone_address_new((*it)->getValue().c_str());
308 if (addr) {
309 vCard->sip_addresses_cache = bctbx_list_append(vCard->sip_addresses_cache, addr);
310 }
311 }
312 }
313 return vCard->sip_addresses_cache;
314 }
315
linphone_vcard_add_phone_number(LinphoneVcard * vCard,const char * phone)316 void linphone_vcard_add_phone_number(LinphoneVcard *vCard, const char *phone) {
317 if (!vCard || !phone) return;
318
319 shared_ptr<belcard::BelCardPhoneNumber> phone_number = belcard::BelCardGeneric::create<belcard::BelCardPhoneNumber>();
320 phone_number->setValue(phone);
321 vCard->belCard->addPhoneNumber(phone_number);
322 }
323
linphone_vcard_remove_phone_number(LinphoneVcard * vCard,const char * phone)324 void linphone_vcard_remove_phone_number(LinphoneVcard *vCard, const char *phone) {
325 if (!vCard) return;
326
327 shared_ptr<belcard::BelCardPhoneNumber> tel;
328 for (auto it = vCard->belCard->getPhoneNumbers().begin(); it != vCard->belCard->getPhoneNumbers().end(); ++it) {
329 const char *value = (*it)->getValue().c_str();
330 if (strcmp(value, phone) == 0) {
331 tel = *it;
332 break;
333 }
334 }
335 if (tel) {
336 vCard->belCard->removePhoneNumber(tel);
337 }
338 }
339
linphone_vcard_get_phone_numbers(const LinphoneVcard * vCard)340 bctbx_list_t* linphone_vcard_get_phone_numbers(const LinphoneVcard *vCard) {
341 bctbx_list_t *result = NULL;
342 if (!vCard) return NULL;
343
344 for (auto it = vCard->belCard->getPhoneNumbers().begin(); it != vCard->belCard->getPhoneNumbers().end(); ++it) {
345 const char *value = (*it)->getValue().c_str();
346 result = bctbx_list_append(result, (char *)value);
347 }
348 return result;
349 }
350
linphone_vcard_set_organization(LinphoneVcard * vCard,const char * organization)351 void linphone_vcard_set_organization(LinphoneVcard *vCard, const char *organization) {
352 if (!vCard) return;
353
354 if (vCard->belCard->getOrganizations().size() > 0) {
355 const shared_ptr<belcard::BelCardOrganization> org = vCard->belCard->getOrganizations().front();
356 org->setValue(organization);
357 } else {
358 shared_ptr<belcard::BelCardOrganization> org = belcard::BelCardGeneric::create<belcard::BelCardOrganization>();
359 org->setValue(organization);
360 vCard->belCard->addOrganization(org);
361 }
362 }
363
linphone_vcard_get_organization(const LinphoneVcard * vCard)364 const char* linphone_vcard_get_organization(const LinphoneVcard *vCard) {
365 if (vCard && vCard->belCard->getOrganizations().size() > 0) {
366 const shared_ptr<belcard::BelCardOrganization> org = vCard->belCard->getOrganizations().front();
367 return org->getValue().c_str();
368 }
369
370 return NULL;
371 }
372
linphone_vcard_generate_unique_id(LinphoneVcard * vCard)373 bool_t linphone_vcard_generate_unique_id(LinphoneVcard *vCard) {
374 char uuid[64];
375
376 if (vCard) {
377 if (linphone_vcard_get_uid(vCard)) {
378 return FALSE;
379 }
380 if (sal_generate_uuid(uuid, sizeof(uuid)) == 0) {
381 char vcard_uuid[sizeof(uuid)+4];
382 snprintf(vcard_uuid, sizeof(vcard_uuid), "urn:%s", uuid);
383 linphone_vcard_set_uid(vCard, vcard_uuid);
384 return TRUE;
385 }
386 }
387 return FALSE;
388 }
389
linphone_vcard_set_uid(LinphoneVcard * vCard,const char * uid)390 void linphone_vcard_set_uid(LinphoneVcard *vCard, const char *uid) {
391 if (!vCard || !uid) return;
392
393 shared_ptr<belcard::BelCardUniqueId> uniqueId = belcard::BelCardGeneric::create<belcard::BelCardUniqueId>();
394 uniqueId->setValue(uid);
395 vCard->belCard->setUniqueId(uniqueId);
396 }
397
linphone_vcard_get_uid(const LinphoneVcard * vCard)398 const char* linphone_vcard_get_uid(const LinphoneVcard *vCard) {
399 if (vCard && vCard->belCard->getUniqueId()) {
400 return vCard->belCard->getUniqueId()->getValue().c_str();
401 }
402 return NULL;
403 }
404
linphone_vcard_set_etag(LinphoneVcard * vCard,const char * etag)405 void linphone_vcard_set_etag(LinphoneVcard *vCard, const char * etag) {
406 if (!vCard) {
407 return;
408 }
409 if (vCard->etag) {
410 ms_free(vCard->etag);
411 vCard->etag = NULL;
412 }
413 vCard->etag = ms_strdup(etag);
414 }
415
linphone_vcard_get_etag(const LinphoneVcard * vCard)416 const char* linphone_vcard_get_etag(const LinphoneVcard *vCard) {
417 if (!vCard) return NULL;
418 return vCard->etag;
419 }
420
linphone_vcard_set_url(LinphoneVcard * vCard,const char * url)421 void linphone_vcard_set_url(LinphoneVcard *vCard, const char * url) {
422 if (!vCard) {
423 return;
424 }
425 if (vCard->url) {
426 ms_free(vCard->url);
427 vCard->url = NULL;
428 }
429 vCard->url = ms_strdup(url);
430 }
431
linphone_vcard_get_url(const LinphoneVcard * vCard)432 const char* linphone_vcard_get_url(const LinphoneVcard *vCard) {
433 if (!vCard) return NULL;
434 return vCard->url;
435 }
436
linphone_vcard_compute_md5_hash(LinphoneVcard * vCard)437 void linphone_vcard_compute_md5_hash(LinphoneVcard *vCard) {
438 const char *text = NULL;
439 if (!vCard) return;
440 text = linphone_vcard_as_vcard4_string(vCard);
441 bctbx_md5((unsigned char *)text, strlen(text), vCard->md5);
442 }
443
linphone_vcard_compare_md5_hash(LinphoneVcard * vCard)444 bool_t linphone_vcard_compare_md5_hash(LinphoneVcard *vCard) {
445 unsigned char previous_md5[VCARD_MD5_HASH_SIZE];
446 memcpy(previous_md5, vCard->md5, VCARD_MD5_HASH_SIZE);
447 linphone_vcard_compute_md5_hash(vCard);
448 return memcmp(vCard->md5, previous_md5, VCARD_MD5_HASH_SIZE);
449 }
450
linphone_core_vcard_supported(void)451 bool_t linphone_core_vcard_supported(void) {
452 return TRUE;
453 }
454
linphone_vcard_clean_cache(LinphoneVcard * vCard)455 void linphone_vcard_clean_cache(LinphoneVcard *vCard) {
456 if (vCard->sip_addresses_cache) bctbx_list_free_with_data(vCard->sip_addresses_cache, (void (*)(void*))linphone_address_unref);
457 vCard->sip_addresses_cache = NULL;
458 }
459
460 } // extern "C"
461