5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 /* Implementation of the VCard (RFC 2426) */
22 #include "silcincludes.h"
24 #define VCARD_HEADER "BEGIN:VCARD\n"
25 #define VCARD_VERSION "VERSION:3.0\n"
26 #define VCARD_FOOTER "END:VCARD"
28 /* Free all data inside the card structure */
30 static void silc_vcard_free_internal(SilcVCard vcard)
34 silc_free(vcard->full_name);
35 silc_free(vcard->family_name);
36 silc_free(vcard->first_name);
37 silc_free(vcard->middle_names);
38 silc_free(vcard->prefix);
39 silc_free(vcard->suffix);
40 silc_free(vcard->nickname);
41 silc_free(vcard->bday);
42 silc_free(vcard->title);
43 silc_free(vcard->role);
44 silc_free(vcard->org_name);
45 silc_free(vcard->org_unit);
46 silc_free(vcard->categories);
47 silc_free(vcard->class);
48 silc_free(vcard->url);
49 silc_free(vcard->label);
50 for (i = 0; i < vcard->num_addrs; i++) {
51 silc_free(vcard->addrs[i].type);
52 silc_free(vcard->addrs[i].pbox);
53 silc_free(vcard->addrs[i].ext_addr);
54 silc_free(vcard->addrs[i].street_addr);
55 silc_free(vcard->addrs[i].city);
56 silc_free(vcard->addrs[i].state);
57 silc_free(vcard->addrs[i].code);
58 silc_free(vcard->addrs[i].country);
60 silc_free(vcard->addrs);
61 for (i = 0; i < vcard->num_tels; i++) {
62 silc_free(vcard->tels[i].type);
63 silc_free(vcard->tels[i].tel);
65 silc_free(vcard->tels);
66 for (i = 0; i < vcard->num_emails; i++) {
67 silc_free(vcard->emails[i].type);
68 silc_free(vcard->emails[i].address);
70 silc_free(vcard->emails);
71 silc_free(vcard->note);
72 silc_free(vcard->rev);
77 unsigned char *silc_vcard_encode(SilcVCard vcard, SilcUInt32 *vcard_len)
79 SilcBufferStruct buffer;
82 if (!vcard->full_name || !vcard->family_name || !vcard->first_name)
85 memset(&buffer, 0, sizeof(buffer));
86 silc_buffer_strformat(
90 "FN:", vcard->full_name, "\n",
91 "N:", vcard->family_name, ";", vcard->first_name, ";",
92 vcard->middle_names, ";", vcard->prefix, ";", vcard->suffix, "\n",
96 silc_buffer_strformat(&buffer,
97 "NICKNAME:", vcard->nickname, "\n",
100 silc_buffer_strformat(&buffer,
101 "BDAY:", vcard->bday, "\n",
104 silc_buffer_strformat(&buffer,
105 "TITLE:", vcard->title, "\n",
108 silc_buffer_strformat(&buffer,
109 "ROLE:", vcard->role, "\n",
112 silc_buffer_strformat(&buffer,
113 "ORG:", vcard->org_name, ";", vcard->org_unit, "\n",
115 if (vcard->categories)
116 silc_buffer_strformat(&buffer,
117 "CATEGORIES:", vcard->categories, "\n",
120 silc_buffer_strformat(&buffer,
121 "CLASS:", vcard->class, "\n",
124 silc_buffer_strformat(&buffer,
125 "URL:", vcard->url, "\n",
128 silc_buffer_strformat(&buffer,
129 "LABEL;", vcard->url, "\n",
131 for (i = 0; i < vcard->num_addrs; i++) {
132 silc_buffer_strformat(&buffer,
134 vcard->addrs[i].type, ":",
135 vcard->addrs[i].pbox, ";",
136 vcard->addrs[i].ext_addr, ";",
137 vcard->addrs[i].street_addr, ";",
138 vcard->addrs[i].city, ";",
139 vcard->addrs[i].state, ";",
140 vcard->addrs[i].code, ";",
141 vcard->addrs[i].country, "\n",
144 for (i = 0; i < vcard->num_tels; i++) {
145 silc_buffer_strformat(&buffer,
147 vcard->tels[i].type, ":",
148 vcard->tels[i].tel, "\n",
151 for (i = 0; i < vcard->num_emails; i++) {
152 silc_buffer_strformat(&buffer,
154 vcard->emails[i].type, ":",
155 vcard->emails[i].address, "\n",
159 silc_buffer_strformat(&buffer,
160 "NOTE:", vcard->note, "\n",
163 silc_buffer_strformat(&buffer,
164 "REV:", vcard->rev, "\n",
167 silc_buffer_strformat(&buffer, VCARD_FOOTER, SILC_STR_END);
170 *vcard_len = buffer.truelen;
176 #define VCARD_TOKEN(x) \
178 (x) = silc_memdup(val + off, i - off); \
183 /* Take on TYPE= token and prepare for next token */
184 #define VCARD_TYPETOKEN(x) \
187 (x) = silc_memdup(val + off + 5, i - off - 5 - 1); \
188 tmpi = off + 5 + strlen((x)) + 1; \
193 /* Take last token */
194 #define VCARD_LASTTOKEN(x) \
197 (x) = silc_memdup(val + off, len - off); \
202 bool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
206 bool has_begin = FALSE, has_end = FALSE;
209 val = (unsigned char *)data;
211 if (!strchr(val, '\n'))
213 len = strchr(val, '\n') - (char *)val;
214 if (len > data_len - (val - data))
217 if (!strncasecmp(val, VCARD_HEADER, strlen(VCARD_HEADER))) {
219 } else if (!strncasecmp(val, "FN:", 3)) {
220 if (vcard->full_name)
223 vcard->full_name = silc_memdup(val + 3, len - 3);
224 } else if (!strncasecmp(val, "N:", 2)) {
225 if (vcard->family_name)
229 for (i = off; i < len; i++)
231 VCARD_TOKEN(vcard->family_name);
232 VCARD_TOKEN(vcard->first_name);
233 VCARD_TOKEN(vcard->middle_names);
234 VCARD_TOKEN(vcard->prefix);
236 VCARD_LASTTOKEN(vcard->suffix);
238 } else if (!strncasecmp(val, "NICKNAME:", 9)) {
242 vcard->nickname = silc_memdup(val + 9, len - 9);
243 } else if (!strncasecmp(val, "BDAY:", 5)) {
247 vcard->bday = silc_memdup(val + 5, len - 5);
248 } else if (!strncasecmp(val, "TITLE:", 6)) {
252 vcard->title = silc_memdup(val + 6, len - 6);
253 } else if (!strncasecmp(val, "ROLE:", 5)) {
257 vcard->role = silc_memdup(val + 5, len - 5);
258 } else if (!strncasecmp(val, "ORG:", 4)) {
263 for (i = off; i < len; i++) {
265 VCARD_TOKEN(vcard->org_name);
269 /* It's possible to have ORG without last ';', so check for it */
270 if (!vcard->org_name) {
271 VCARD_LASTTOKEN(vcard->org_name);
273 VCARD_LASTTOKEN(vcard->org_unit);
276 } else if (!strncasecmp(val, "CATEGORIES:", 11)) {
277 if (vcard->categories)
280 vcard->categories = silc_memdup(val + 11, len - 11);
281 } else if (!strncasecmp(val, "CLASS:", 6)) {
285 vcard->class = silc_memdup(val + 6, len - 6);
286 } else if (!strncasecmp(val, "URL:", 4)) {
290 vcard->url = silc_memdup(val + 4, len - 4);
291 } else if (!strncasecmp(val, "LABEL;", 6)) {
295 vcard->label = silc_memdup(val + 6, len - 6);
296 } else if (!strncasecmp(val, "ADR;", 4)) {
297 vcard->addrs = silc_realloc(vcard->addrs, sizeof(*vcard->addrs) *
298 (vcard->num_addrs + 1));
301 for (i = off; i < len; i++)
303 VCARD_TYPETOKEN(vcard->addrs[vcard->num_addrs].type);
304 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].pbox);
305 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].ext_addr);
306 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].street_addr);
307 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].city);
308 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].state);
309 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].code);
311 VCARD_LASTTOKEN(vcard->addrs[vcard->num_addrs].country);
314 } else if (!strncasecmp(val, "TEL;", 4)) {
315 vcard->tels = silc_realloc(vcard->tels, sizeof(*vcard->tels) *
316 (vcard->num_tels + 1));
319 for (i = off; i < len; i++)
322 VCARD_TYPETOKEN(vcard->tels[vcard->num_tels].type);
325 VCARD_LASTTOKEN(vcard->tels[vcard->num_tels].tel);
328 } else if (!strncasecmp(val, "EMAIL;", 6)) {
329 vcard->emails = silc_realloc(vcard->emails, sizeof(*vcard->emails) *
330 (vcard->num_emails + 1));
333 for (i = off; i < len; i++)
336 VCARD_TYPETOKEN(vcard->emails[vcard->num_emails].type);
339 VCARD_LASTTOKEN(vcard->emails[vcard->num_emails].address);
342 } else if (!strncasecmp(val, "NOTE:", 5)) {
346 vcard->note = silc_memdup(val + 5, len - 5);
347 } else if (!strncasecmp(val, "REV:", 4)) {
351 vcard->rev = silc_memdup(val + 4, len - 4);
352 } else if (!strncasecmp(val, VCARD_FOOTER, strlen(VCARD_FOOTER))) {
357 val = strchr(val, '\n');
365 if (!has_begin || !has_end) {
366 silc_vcard_free_internal(vcard);
373 /* Free the vcard structure */
375 void silc_vcard_free(SilcVCard vcard)
377 silc_vcard_free_internal(vcard);
378 memset(vcard, 'F', sizeof(*vcard));
382 /* Print card to file stream */
384 void silc_vcard_fprintf(SilcVCard vcard, FILE *stream)
387 fprintf(stream, "%s", VCARD_HEADER);
388 fprintf(stream, "%s", VCARD_VERSION);
389 if (vcard->full_name)
390 fprintf(stream, "FN:%s\n", vcard->full_name);
391 if (vcard->family_name)
392 fprintf(stream, "N:%s;%s;%s;%s;%s\n",
394 vcard->first_name ? vcard->first_name : "",
395 vcard->middle_names ? vcard->middle_names : "",
396 vcard->prefix ? vcard->prefix : "",
397 vcard->suffix ? vcard->suffix : "");
399 fprintf(stream, "NICKNAME:%s\n", vcard->nickname);
401 fprintf(stream, "BDAY:%s\n", vcard->bday);
403 fprintf(stream, "TITLE:%s\n", vcard->title);
405 fprintf(stream, "ROLE:%s\n", vcard->role);
407 fprintf(stream, "ORG:%s;%s\n", vcard->org_name,
408 vcard->org_unit ? vcard->org_unit : "");
409 if (vcard->categories)
410 fprintf(stream, "CATEGORIES:%s\n", vcard->categories);
412 fprintf(stream, "CLASS:%s\n", vcard->class);
414 fprintf(stream, "URL:%s\n", vcard->url);
416 fprintf(stream, "LABEL;%s\n", vcard->label);
417 for (i = 0; i < vcard->num_addrs; i++) {
418 fprintf(stream, "ADR;TYPE=%s:%s;%s;%s;%s;%s;%s;%s\n",
419 vcard->addrs[i].type,
420 vcard->addrs[i].pbox ? vcard->addrs[i].pbox : "",
421 vcard->addrs[i].ext_addr ? vcard->addrs[i].ext_addr : "",
422 vcard->addrs[i].street_addr ? vcard->addrs[i].street_addr : "",
423 vcard->addrs[i].city ? vcard->addrs[i].city : "",
424 vcard->addrs[i].state ? vcard->addrs[i].state : "",
425 vcard->addrs[i].code ? vcard->addrs[i].code : "",
426 vcard->addrs[i].country ? vcard->addrs[i].country : "");
428 for (i = 0; i < vcard->num_tels; i++) {
429 fprintf(stream, "TEL;TYPE=%s:%s\n",
431 vcard->tels[i].tel ? vcard->tels[i].tel : "");
433 for (i = 0; i < vcard->num_emails; i++) {
434 fprintf(stream, "EMAIL;TYPE=%s:%s\n",
435 vcard->emails[i].type,
436 vcard->emails[i].address ? vcard->emails[i].address : "");
439 fprintf(stream, "NOTE:%s\n", vcard->note);
441 fprintf(stream, "REV:%s\n", vcard->rev);
442 fprintf(stream, "%s", VCARD_FOOTER);