vcard.cc 10.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
vcard.cc
Copyright (C) 2015  Belledonne Communications SARL

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

20 21
#include "vcard.h"
#include "belcard/belcard.hpp"
22
#include "belcard/belcard_parser.hpp"
23
#include "sal/sal.h"
24
#include <bctoolbox/crypto.h>
25

26 27 28 29 30
struct _LinphoneVcardContext {
	belcard::BelCardParser *parser;
	void *user_data;
};

31
struct _LinphoneVcard {
32
	shared_ptr<belcard::BelCard> belCard;
33 34
	char *etag;
	char *url;
35
	unsigned char *md5;
36 37
};

38 39 40 41
#ifdef __cplusplus
extern "C" {
#endif

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
LinphoneVcardContext* linphone_vcard_context_new(void) {
	LinphoneVcardContext* context = ms_new0(LinphoneVcardContext, 1);
	context->parser = new belcard::BelCardParser();
	context->user_data = NULL;
	return context;
}

void linphone_vcard_context_destroy(LinphoneVcardContext *context) {
	if (context) {
		if (context->parser) delete context->parser;
		ms_free(context);
	}
}

void* linphone_vcard_context_get_user_data(LinphoneVcardContext *context) {
	return context ? context->user_data : NULL;
}


void linphone_vcard_context_set_user_data(LinphoneVcardContext *context, void *data) {
	if (context) context->user_data = data;
}

65 66
LinphoneVcard* linphone_vcard_new(void) {
	LinphoneVcard* vCard = (LinphoneVcard*) ms_new0(LinphoneVcard, 1);
67 68
	vCard->belCard = belcard::BelCardGeneric::create<belcard::BelCard>();
	return vCard;
69 70
}

71 72 73 74 75 76
static LinphoneVcard* linphone_vcard_new_from_belcard(shared_ptr<belcard::BelCard> belcard) {
	LinphoneVcard* vCard = (LinphoneVcard*) ms_new0(LinphoneVcard, 1);
	vCard->belCard = belcard;
	return vCard;
}

77
void linphone_vcard_free(LinphoneVcard *vCard) {
78
	if (!vCard) return;
Sylvain Berfini's avatar
Sylvain Berfini committed
79 80
	if (vCard->etag) ms_free(vCard->etag);
	if (vCard->url) ms_free(vCard->url);
81 82
	vCard->belCard.reset();
	ms_free(vCard);
83 84
}

85
bctbx_list_t* linphone_vcard_list_from_vcard4_file(LinphoneVcardContext *context, const char *filename) {
86
	bctbx_list_t *result = NULL;
87 88
	if (context && filename) {
		belcard::BelCardParser *parser = context->parser;
89
		shared_ptr<belcard::BelCardList> belCards = parser->parseFile(filename);
90
		if (belCards) {
91
			for (auto it = belCards->getCards().begin(); it != belCards->getCards().end(); ++it) {
92 93
				shared_ptr<belcard::BelCard> belCard = (*it);
				LinphoneVcard *vCard = linphone_vcard_new_from_belcard(belCard);
94
				result = bctbx_list_append(result, vCard);
95 96 97 98 99 100
			}
		}
	}
	return result;
}

101
bctbx_list_t* linphone_vcard_list_from_vcard4_buffer(LinphoneVcardContext *context, const char *buffer) {
102
	bctbx_list_t *result = NULL;
103 104
	if (context && buffer) {
		belcard::BelCardParser *parser = context->parser;
105
		shared_ptr<belcard::BelCardList> belCards = parser->parse(buffer);
106 107 108
		if (belCards) {
			for (auto it = belCards->getCards().begin(); it != belCards->getCards().end(); ++it) {
				shared_ptr<belcard::BelCard> belCard = (*it);
109
				LinphoneVcard *vCard = linphone_vcard_new_from_belcard(belCard);
110
				result = bctbx_list_append(result, vCard);
111 112 113 114 115 116
			}
		}
	}
	return result;
}

117
LinphoneVcard* linphone_vcard_new_from_vcard4_buffer(LinphoneVcardContext *context, const char *buffer) {
118
	LinphoneVcard *vCard = NULL;
119 120
	if (context && buffer) {
		belcard::BelCardParser *parser = context->parser;
121
		shared_ptr<belcard::BelCard> belCard = parser->parseOne(buffer);
122
		if (belCard) {
123
			vCard = linphone_vcard_new_from_belcard(belCard);
Sylvain Berfini's avatar
Sylvain Berfini committed
124 125
		} else {
			ms_error("Couldn't parse buffer %s", buffer);
126 127 128 129 130
		}
	}
	return vCard;
}

131
const char * linphone_vcard_as_vcard4_string(LinphoneVcard *vCard) {
132 133
	if (!vCard) return NULL;
	
134
	return vCard->belCard->toFoldedString().c_str();
135 136
}

137
void linphone_vcard_set_full_name(LinphoneVcard *vCard, const char *name) {
138 139
	if (!vCard || !name) return;
	
140 141
	shared_ptr<belcard::BelCardFullName> fn = belcard::BelCardGeneric::create<belcard::BelCardFullName>();
	fn->setValue(name);
142
	vCard->belCard->setFullName(fn);
143 144
}

145
const char* linphone_vcard_get_full_name(const LinphoneVcard *vCard) {
146 147
	if (!vCard) return NULL;
	
148
	const char *result = vCard->belCard->getFullName() ? vCard->belCard->getFullName()->getValue().c_str() : NULL;
149
	return result;
150 151
}

152
void linphone_vcard_add_sip_address(LinphoneVcard *vCard, const char *sip_address) {
153 154
	if (!vCard || !sip_address) return;
	
155 156 157 158 159
	shared_ptr<belcard::BelCardImpp> impp = belcard::BelCardGeneric::create<belcard::BelCardImpp>();
	impp->setValue(sip_address);
	vCard->belCard->addImpp(impp);
}

160
void linphone_vcard_remove_sip_address(LinphoneVcard *vCard, const char *sip_address) {
161 162
	if (!vCard) return;
	
163
	shared_ptr<belcard::BelCardImpp> impp;
164 165 166
	for (auto it = vCard->belCard->getImpp().begin(); it != vCard->belCard->getImpp().end(); ++it) {
		const char *value = (*it)->getValue().c_str();
		if (strcmp(value, sip_address) == 0) {
167
			impp = *it;
168 169 170
			break;
		}
	}
171 172 173
	if (impp) {
		vCard->belCard->removeImpp(impp);
	}
174 175
}

176
void linphone_vcard_edit_main_sip_address(LinphoneVcard *vCard, const char *sip_address) {
177 178 179 180 181 182 183 184 185 186 187 188
	if (!vCard || !sip_address) return;
	
	if (vCard->belCard->getImpp().size() > 0) {
		const shared_ptr<belcard::BelCardImpp> impp = vCard->belCard->getImpp().front();
		impp->setValue(sip_address);
	} else {
		shared_ptr<belcard::BelCardImpp> impp = belcard::BelCardGeneric::create<belcard::BelCardImpp>();
		impp->setValue(sip_address);
		vCard->belCard->addImpp(impp);
	}
}

189 190
bctbx_list_t* linphone_vcard_get_sip_addresses(const LinphoneVcard *vCard) {
	bctbx_list_t *result = NULL;
191 192
	if (!vCard) return NULL;
	
193
	for (auto it = vCard->belCard->getImpp().begin(); it != vCard->belCard->getImpp().end(); ++it) {
194 195
		const char *value = (*it)->getValue().c_str();
		if (strncmp(value, "sip:", 4) == 0) {
196
			result = bctbx_list_append(result, (char *)value);
197 198 199
		}
	}
	return result;
200 201
}

202 203 204 205 206 207 208 209 210 211 212
void linphone_vcard_add_phone_number(LinphoneVcard *vCard, const char *phone) {
	if (!vCard || !phone) return;
	
	shared_ptr<belcard::BelCardPhoneNumber> phone_number = belcard::BelCardGeneric::create<belcard::BelCardPhoneNumber>();
	phone_number->setValue(phone);
	vCard->belCard->addPhoneNumber(phone_number);
}

void linphone_vcard_remove_phone_number(LinphoneVcard *vCard, const char *phone) {
	if (!vCard) return;
	
213
	shared_ptr<belcard::BelCardPhoneNumber> tel;
214 215 216
	for (auto it = vCard->belCard->getPhoneNumbers().begin(); it != vCard->belCard->getPhoneNumbers().end(); ++it) {
		const char *value = (*it)->getValue().c_str();
		if (strcmp(value, phone) == 0) {
217
			tel = *it;
218 219 220
			break;
		}
	}
221 222 223
	if (tel) {
		vCard->belCard->removePhoneNumber(tel);
	}
224 225
}

226 227
bctbx_list_t* linphone_vcard_get_phone_numbers(const LinphoneVcard *vCard) {
	bctbx_list_t *result = NULL;
228 229 230 231
	if (!vCard) return NULL;
	
	for (auto it = vCard->belCard->getPhoneNumbers().begin(); it != vCard->belCard->getPhoneNumbers().end(); ++it) {
		const char *value = (*it)->getValue().c_str();
232
		result = bctbx_list_append(result, (char *)value);
233 234 235 236
	}
	return result;
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
void linphone_vcard_set_organization(LinphoneVcard *vCard, const char *organization) {
	if (!vCard) return;
	
	if (vCard->belCard->getOrganizations().size() > 0) {
		const shared_ptr<belcard::BelCardOrganization> org = vCard->belCard->getOrganizations().front();
		org->setValue(organization);
	} else {
		shared_ptr<belcard::BelCardOrganization> org = belcard::BelCardGeneric::create<belcard::BelCardOrganization>();
		org->setValue(organization);
		vCard->belCard->addOrganization(org);
	}
}

const char* linphone_vcard_get_organization(const LinphoneVcard *vCard) {
	if (vCard && vCard->belCard->getOrganizations().size() > 0) {
		const shared_ptr<belcard::BelCardOrganization> org = vCard->belCard->getOrganizations().front();
		return org->getValue().c_str();
	}
	
	return NULL;
}

259
bool_t linphone_vcard_generate_unique_id(LinphoneVcard *vCard) {
260 261 262 263 264 265 266 267 268
	char uuid[64];
	
	if (vCard) {
		if (linphone_vcard_get_uid(vCard)) {
			return FALSE;
		}
		if (sal_generate_uuid(uuid, sizeof(uuid)) == 0) {
			char vcard_uuid[sizeof(uuid)+4];
			snprintf(vcard_uuid, sizeof(vcard_uuid), "urn:%s", uuid);
Sylvain Berfini's avatar
Sylvain Berfini committed
269
			linphone_vcard_set_uid(vCard, vcard_uuid);
270 271 272 273 274 275
			return TRUE;
		}
	}
	return FALSE;
}

276
void linphone_vcard_set_uid(LinphoneVcard *vCard, const char *uid) {
277 278 279 280 281 282 283
	if (!vCard || !uid) return;
	
	shared_ptr<belcard::BelCardUniqueId> uniqueId = belcard::BelCardGeneric::create<belcard::BelCardUniqueId>();
	uniqueId->setValue(uid);
	vCard->belCard->setUniqueId(uniqueId);
}

284
const char* linphone_vcard_get_uid(const LinphoneVcard *vCard) {
Sylvain Berfini's avatar
Sylvain Berfini committed
285
	if (vCard && vCard->belCard->getUniqueId()) {
286 287 288 289 290
		return vCard->belCard->getUniqueId()->getValue().c_str();
	}
	return NULL;
}

291
void linphone_vcard_set_etag(LinphoneVcard *vCard, const char * etag) {
292 293 294 295 296
	if (!vCard) {
		return;
	}
	if (vCard->etag) {
		ms_free(vCard->etag);
Sylvain Berfini's avatar
Sylvain Berfini committed
297
		vCard->etag = NULL;
298
	}
299 300 301
	vCard->etag = ms_strdup(etag);
}

302
const char* linphone_vcard_get_etag(const LinphoneVcard *vCard) {
Sylvain Berfini's avatar
Sylvain Berfini committed
303
	if (!vCard) return NULL;
304 305 306
	return vCard->etag;
}

307
void linphone_vcard_set_url(LinphoneVcard *vCard, const char * url) {
308 309 310 311 312
	if (!vCard) {
		return;
	}
	if (vCard->url) {
		ms_free(vCard->url);
Sylvain Berfini's avatar
Sylvain Berfini committed
313
		vCard->url = NULL;
314
	}
315 316 317
	vCard->url = ms_strdup(url);
}

318
const char* linphone_vcard_get_url(const LinphoneVcard *vCard) {
Sylvain Berfini's avatar
Sylvain Berfini committed
319
	if (!vCard) return NULL;
320
	return vCard->url;
321 322
}

323 324
#define VCARD_MD5_HASH_SIZE 16

325
void linphone_vcard_compute_md5_hash(LinphoneVcard *vCard) {
326
	unsigned char digest[VCARD_MD5_HASH_SIZE];
327
	const char *text = NULL;
328 329 330
	if (!vCard) {
		return;
	}
331
	text = linphone_vcard_as_vcard4_string(vCard);
jehan's avatar
jehan committed
332
	bctbx_md5((unsigned char *)text, strlen(text), digest);
333 334
	vCard->md5 = (unsigned char *)ms_malloc(sizeof(digest));
	memcpy(vCard->md5, digest, sizeof(digest));
335 336
}

337
bool_t linphone_vcard_compare_md5_hash(LinphoneVcard *vCard) {
338 339 340 341 342 343
	unsigned char *previous_md5 = vCard->md5;
	unsigned char *new_md5 = NULL;
	int result = -1;
	
	if (!previous_md5) {
		return result;
344
	}
345 346 347
	
	linphone_vcard_compute_md5_hash(vCard);
	new_md5 = vCard->md5;
348
	result = memcmp(new_md5, previous_md5, VCARD_MD5_HASH_SIZE);
349 350 351 352
	
	ms_free(previous_md5);
	ms_free(new_md5);
	return result;
353 354
}

355 356 357
#ifdef __cplusplus
}
#endif