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.
19 /* Implementation of the VCard (RFC 2426) */
21 #include "silcincludes.h"
23 #define VCARD_HEADER "BEGIN:VCARD\n"
24 #define VCARD_VERSION "VERSION:3.0\n"
25 #define VCARD_FOOTER "END:VCARD"
27 /* Free all data inside the card structure */
29 static void silc_vcard_free_internal(SilcVCard vcard)
33 silc_free(vcard->full_name);
34 silc_free(vcard->family_name);
35 silc_free(vcard->first_name);
36 silc_free(vcard->middle_names);
37 silc_free(vcard->prefix);
38 silc_free(vcard->suffix);
39 silc_free(vcard->nickname);
40 silc_free(vcard->bday);
41 silc_free(vcard->title);
42 silc_free(vcard->role);
43 silc_free(vcard->org_name);
44 silc_free(vcard->org_unit);
45 silc_free(vcard->categories);
46 silc_free(vcard->class);
47 silc_free(vcard->url);
48 silc_free(vcard->label);
49 for (i = 0; i < vcard->num_addrs; i++) {
50 silc_free(vcard->addrs[i].type);
51 silc_free(vcard->addrs[i].pbox);
52 silc_free(vcard->addrs[i].ext_addr);
53 silc_free(vcard->addrs[i].street_addr);
54 silc_free(vcard->addrs[i].city);
55 silc_free(vcard->addrs[i].state);
56 silc_free(vcard->addrs[i].code);
57 silc_free(vcard->addrs[i].country);
59 silc_free(vcard->addrs);
60 for (i = 0; i < vcard->num_tels; i++) {
61 silc_free(vcard->tels[i].type);
62 silc_free(vcard->tels[i].tel);
64 silc_free(vcard->tels);
65 for (i = 0; i < vcard->num_emails; i++) {
66 silc_free(vcard->emails[i].type);
67 silc_free(vcard->emails[i].address);
69 silc_free(vcard->emails);
70 silc_free(vcard->note);
71 silc_free(vcard->rev);
76 char *silc_vcard_encode(SilcVCard vcard, SilcUInt32 *vcard_len)
78 SilcBufferStruct buffer;
81 if (!vcard->full_name || !vcard->family_name || !vcard->first_name)
84 memset(&buffer, 0, sizeof(buffer));
85 silc_buffer_strformat(
89 "FN:", vcard->full_name, "\n",
90 "N:", vcard->family_name, ";", vcard->first_name, ";",
91 vcard->middle_names, ";", vcard->prefix, ";", vcard->suffix, "\n",
95 silc_buffer_strformat(&buffer,
96 "NICKNAME:", vcard->nickname, "\n",
99 silc_buffer_strformat(&buffer,
100 "BDAY:", vcard->bday, "\n",
103 silc_buffer_strformat(&buffer,
104 "TITLE:", vcard->title, "\n",
107 silc_buffer_strformat(&buffer,
108 "ROLE:", vcard->role, "\n",
111 silc_buffer_strformat(&buffer,
112 "ORG:", vcard->org_name, ";", vcard->org_unit, "\n",
114 if (vcard->categories)
115 silc_buffer_strformat(&buffer,
116 "CATEGORIES:", vcard->categories, "\n",
119 silc_buffer_strformat(&buffer,
120 "CLASS:", vcard->class, "\n",
123 silc_buffer_strformat(&buffer,
124 "URL:", vcard->url, "\n",
127 silc_buffer_strformat(&buffer,
128 "LABEL;", vcard->url, "\n",
130 for (i = 0; i < vcard->num_addrs; i++) {
131 silc_buffer_strformat(&buffer,
133 vcard->addrs[i].type, ":",
134 vcard->addrs[i].pbox, ";",
135 vcard->addrs[i].ext_addr, ";",
136 vcard->addrs[i].street_addr, ";",
137 vcard->addrs[i].city, ";",
138 vcard->addrs[i].state, ";",
139 vcard->addrs[i].code, ";",
140 vcard->addrs[i].country, "\n",
143 for (i = 0; i < vcard->num_tels; i++) {
144 silc_buffer_strformat(&buffer,
146 vcard->tels[i].type, ":",
147 vcard->tels[i].tel, "\n",
150 for (i = 0; i < vcard->num_emails; i++) {
151 silc_buffer_strformat(&buffer,
153 vcard->emails[i].type, ":",
154 vcard->emails[i].address, "\n",
158 silc_buffer_strformat(&buffer,
159 "NOTE:", vcard->note, "\n",
162 silc_buffer_strformat(&buffer,
163 "REV:", vcard->rev, "\n",
166 silc_buffer_strformat(&buffer, VCARD_FOOTER, SILC_STR_END);
169 *vcard_len = buffer.truelen;
174 #define VCARD_TOKEN(x) \
176 (x) = silc_memdup(val + off, i - off); \
181 #define VCARD_TYPETOKEN(x) \
184 (x) = silc_memdup(val + off + 5, i - off - 5 - 1); \
185 tmpi = off + 5 + strlen((x)) + 1; \
190 #define VCARD_LASTTOKEN(x) \
193 (x) = silc_memdup(val + off, len - off); \
198 bool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
202 bool has_begin = FALSE, has_end = FALSE;
205 val = (unsigned char *)data;
207 if (!strchr(val, '\n'))
209 len = strchr(val, '\n') - (char *)val;
210 if (len > data_len - (val - data))
213 if (!strncasecmp(val, VCARD_HEADER, strlen(VCARD_HEADER))) {
215 } else if (!strncasecmp(val, "FN:", 3)) {
216 if (vcard->full_name)
219 vcard->full_name = silc_memdup(val + 3, len - 3);
220 } else if (!strncasecmp(val, "N:", 2)) {
221 if (vcard->family_name)
225 for (i = off; i < len; i++)
227 VCARD_TOKEN(vcard->family_name);
228 VCARD_TOKEN(vcard->first_name);
229 VCARD_TOKEN(vcard->middle_names);
230 VCARD_TOKEN(vcard->prefix);
232 VCARD_LASTTOKEN(vcard->suffix);
234 } else if (!strncasecmp(val, "NICKNAME:", 9)) {
238 vcard->nickname = silc_memdup(val + 9, len - 9);
239 } else if (!strncasecmp(val, "BDAY:", 5)) {
243 vcard->bday = silc_memdup(val + 5, len - 5);
244 } else if (!strncasecmp(val, "TITLE:", 6)) {
248 vcard->title = silc_memdup(val + 6, len - 6);
249 } else if (!strncasecmp(val, "ROLE:", 5)) {
253 vcard->role = silc_memdup(val + 5, len - 5);
254 } else if (!strncasecmp(val, "ORG:", 4)) {
259 for (i = off; i < len; i++) {
261 VCARD_TOKEN(vcard->org_name);
265 if (!vcard->org_name) {
266 VCARD_LASTTOKEN(vcard->org_name);
268 VCARD_LASTTOKEN(vcard->org_unit);
271 } else if (!strncasecmp(val, "CATEGORIES:", 11)) {
272 if (vcard->categories)
275 vcard->categories = silc_memdup(val + 11, len - 11);
276 } else if (!strncasecmp(val, "CLASS:", 6)) {
280 vcard->class = silc_memdup(val + 6, len - 6);
281 } else if (!strncasecmp(val, "URL:", 4)) {
285 vcard->url = silc_memdup(val + 4, len - 4);
286 } else if (!strncasecmp(val, "LABEL;", 6)) {
290 vcard->label = silc_memdup(val + 6, len - 6);
291 } else if (!strncasecmp(val, "ADR;", 4)) {
292 vcard->addrs = silc_realloc(vcard->addrs, sizeof(*vcard->addrs) *
293 (vcard->num_addrs + 1));
296 for (i = off; i < len; i++)
298 VCARD_TYPETOKEN(vcard->addrs[vcard->num_addrs].type);
299 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].pbox);
300 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].ext_addr);
301 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].street_addr);
302 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].city);
303 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].state);
304 VCARD_TOKEN(vcard->addrs[vcard->num_addrs].code);
306 VCARD_LASTTOKEN(vcard->addrs[vcard->num_addrs].country);
309 } else if (!strncasecmp(val, "TEL;", 4)) {
310 vcard->tels = silc_realloc(vcard->tels, sizeof(*vcard->tels) *
311 (vcard->num_tels + 1));
314 for (i = off; i < len; i++)
317 VCARD_TYPETOKEN(vcard->tels[vcard->num_tels].type);
320 VCARD_LASTTOKEN(vcard->tels[vcard->num_tels].tel);
323 } else if (!strncasecmp(val, "EMAIL;", 6)) {
324 vcard->emails = silc_realloc(vcard->emails, sizeof(*vcard->emails) *
325 (vcard->num_emails + 1));
328 for (i = off; i < len; i++)
331 VCARD_TYPETOKEN(vcard->emails[vcard->num_emails].type);
334 VCARD_LASTTOKEN(vcard->emails[vcard->num_emails].address);
337 } else if (!strncasecmp(val, "NOTE:", 5)) {
341 vcard->note = silc_memdup(val + 5, len - 5);
342 } else if (!strncasecmp(val, "REV:", 4)) {
346 vcard->rev = silc_memdup(val + 4, len - 4);
347 } else if (!strncasecmp(val, VCARD_FOOTER, strlen(VCARD_FOOTER))) {
352 val = strchr(val, '\n');
360 if (!has_begin || !has_end) {
361 silc_vcard_free_internal(vcard);
368 /* Free the vcard structure */
370 void silc_vcard_free(SilcVCard vcard)
372 silc_vcard_free_internal(vcard);
373 memset(vcard, 'F', sizeof(*vcard));
377 /* Print card to file stream */
379 void silc_vcard_fprintf(SilcVCard vcard, FILE *stream)
382 fprintf(stream, "%s", VCARD_HEADER);
383 fprintf(stream, "%s", VCARD_VERSION);
384 if (vcard->full_name)
385 fprintf(stream, "FN:%s\n", vcard->full_name);
386 if (vcard->family_name)
387 fprintf(stream, "N:%s;%s;%s;%s;%s\n",
389 vcard->first_name ? vcard->first_name : "",
390 vcard->middle_names ? vcard->middle_names : "",
391 vcard->prefix ? vcard->prefix : "",
392 vcard->suffix ? vcard->suffix : "");
394 fprintf(stream, "NICKNAME:%s\n", vcard->nickname);
396 fprintf(stream, "BDAY:%s\n", vcard->bday);
398 fprintf(stream, "TITLE:%s\n", vcard->title);
400 fprintf(stream, "ROLE:%s\n", vcard->role);
402 fprintf(stream, "ORG:%s;%s\n", vcard->org_name,
403 vcard->org_unit ? vcard->org_unit : "");
404 if (vcard->categories)
405 fprintf(stream, "CATEGORIES:%s\n", vcard->categories);
407 fprintf(stream, "CLASS:%s\n", vcard->class);
409 fprintf(stream, "URL:%s\n", vcard->url);
411 fprintf(stream, "LABEL;%s\n", vcard->label);
412 for (i = 0; i < vcard->num_addrs; i++) {
413 fprintf(stream, "ADR;TYPE=%s:%s;%s;%s;%s;%s;%s;%s\n",
414 vcard->addrs[i].type,
415 vcard->addrs[i].pbox ? vcard->addrs[i].pbox : "",
416 vcard->addrs[i].ext_addr ? vcard->addrs[i].ext_addr : "",
417 vcard->addrs[i].street_addr ? vcard->addrs[i].street_addr : "",
418 vcard->addrs[i].city ? vcard->addrs[i].city : "",
419 vcard->addrs[i].state ? vcard->addrs[i].state : "",
420 vcard->addrs[i].code ? vcard->addrs[i].code : "",
421 vcard->addrs[i].country ? vcard->addrs[i].country : "");
423 for (i = 0; i < vcard->num_tels; i++) {
424 fprintf(stream, "TEL;TYPE=%s:%s\n",
426 vcard->tels[i].tel ? vcard->tels[i].tel : "");
428 for (i = 0; i < vcard->num_emails; i++) {
429 fprintf(stream, "EMAIL;TYPE=%s:%s\n",
430 vcard->emails[i].type,
431 vcard->emails[i].address ? vcard->emails[i].address : "");
434 fprintf(stream, "NOTE:%s\n", vcard->note);
436 fprintf(stream, "REV:%s\n", vcard->rev);
437 fprintf(stream, "%s", VCARD_FOOTER);