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