Added.
[silc.git] / lib / silcutil / silcvcard.c
1 /*
2
3   silcvcard.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* Implementation of the VCard (RFC 2426) */
20
21 #include "silcincludes.h"
22
23 #define VCARD_HEADER "BEGIN:VCARD\n"
24 #define VCARD_VERSION "VERSION:3.0\n"
25 #define VCARD_FOOTER "END:VCARD"
26
27 /* Free all data inside the card structure */
28
29 static void silc_vcard_free_internal(SilcVCard vcard)
30 {
31   int i;
32
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);
58   }
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);
63   }
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);
68   }
69   silc_free(vcard->emails);
70   silc_free(vcard->note);
71   silc_free(vcard->rev);
72 }
73
74 /* Encode VCard */
75
76 char *silc_vcard_encode(SilcVCard vcard, SilcUInt32 *vcard_len)
77 {
78   SilcBufferStruct buffer;
79   int i;
80
81   if (!vcard->full_name || !vcard->family_name || !vcard->first_name)
82     return NULL;
83
84   memset(&buffer, 0, sizeof(buffer));
85   silc_buffer_strformat(
86        &buffer,
87        VCARD_HEADER,
88        VCARD_VERSION,
89        "FN:", vcard->full_name, "\n",
90        "N:", vcard->family_name, ";", vcard->first_name, ";",
91        vcard->middle_names, ";", vcard->prefix, ";", vcard->suffix, "\n",
92        SILC_STR_END);
93
94   if (vcard->nickname)
95     silc_buffer_strformat(&buffer,
96                           "NICKNAME:", vcard->nickname, "\n",
97                           SILC_STR_END);
98   if (vcard->bday)
99     silc_buffer_strformat(&buffer,
100                           "BDAY:", vcard->bday, "\n",
101                           SILC_STR_END);
102   if (vcard->title)
103     silc_buffer_strformat(&buffer,
104                           "TITLE:", vcard->title, "\n",
105                           SILC_STR_END);
106   if (vcard->role)
107     silc_buffer_strformat(&buffer,
108                           "ROLE:", vcard->role, "\n",
109                           SILC_STR_END);
110   if (vcard->org_name)
111     silc_buffer_strformat(&buffer,
112                           "ORG:", vcard->org_name, ";", vcard->org_unit, "\n",
113                           SILC_STR_END);
114   if (vcard->categories)
115     silc_buffer_strformat(&buffer,
116                           "CATEGORIES:", vcard->categories, "\n",
117                           SILC_STR_END);
118   if (vcard->class)
119     silc_buffer_strformat(&buffer,
120                           "CLASS:", vcard->class, "\n",
121                           SILC_STR_END);
122   if (vcard->url)
123     silc_buffer_strformat(&buffer,
124                           "URL:", vcard->url, "\n",
125                           SILC_STR_END);
126   if (vcard->label)
127     silc_buffer_strformat(&buffer,
128                           "LABEL;", vcard->url, "\n",
129                           SILC_STR_END);
130   for (i = 0; i < vcard->num_addrs; i++) {
131     silc_buffer_strformat(&buffer,
132                           "ADR;TYPE=",
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",
141                           SILC_STR_END);
142   }
143   for (i = 0; i < vcard->num_tels; i++) {
144     silc_buffer_strformat(&buffer,
145                           "TEL;TYPE=",
146                           vcard->tels[i].type, ":",
147                           vcard->tels[i].tel, "\n",
148                           SILC_STR_END);
149   }
150   for (i = 0; i < vcard->num_emails; i++) {
151     silc_buffer_strformat(&buffer,
152                           "EMAIL;TYPE=",
153                           vcard->emails[i].type, ":",
154                           vcard->emails[i].address, "\n",
155                           SILC_STR_END);
156   }
157   if (vcard->note)
158     silc_buffer_strformat(&buffer,
159                           "NOTE:", vcard->note, "\n",
160                           SILC_STR_END);
161   if (vcard->rev)
162     silc_buffer_strformat(&buffer,
163                           "REV:", vcard->rev, "\n",
164                           SILC_STR_END);
165
166   silc_buffer_strformat(&buffer, VCARD_FOOTER, SILC_STR_END);
167
168   if (vcard_len)
169     *vcard_len = buffer.truelen;
170
171   return buffer.head;
172 }
173
174 #define VCARD_TOKEN(x)                          \
175   if (!(x)) {                                   \
176     (x) = silc_memdup(val + off, i - off);      \
177     off = i + 1;                                \
178     continue;                                   \
179   }
180
181 #define VCARD_TYPETOKEN(x)                              \
182   if (!(x)) {                                           \
183     int tmpi;                                           \
184     (x) = silc_memdup(val + off + 5, i - off - 5 - 1);  \
185     tmpi = off + 5 + strlen((x)) + 1;                   \
186     off = i;                                            \
187     i = tmpi;                                           \
188   }
189
190 #define VCARD_LASTTOKEN(x)                      \
191   if (!(x)) {                                   \
192     if (off < len)                              \
193       (x) = silc_memdup(val + off, len - off);  \
194   }                                             \
195
196 /* Decode VCard */
197
198 bool silc_vcard_decode(const unsigned char *data, SilcUInt32 data_len,
199                        SilcVCard vcard)
200 {
201   unsigned char *val;
202   bool has_begin = FALSE, has_end = FALSE;
203   int len, i, off = 0;
204   
205   val = (unsigned char *)data;
206   while (val) {
207     if (!strchr(val, '\n'))
208       break;
209     len = strchr(val, '\n') - (char *)val;
210     if (len > data_len - (val - data))
211       break;
212
213     if (!strncasecmp(val, VCARD_HEADER, strlen(VCARD_HEADER))) {
214       has_begin = TRUE;
215     } else if (!strncasecmp(val, "FN:", 3)) {
216       if (vcard->full_name)
217         break;
218       if (len - 3)
219         vcard->full_name = silc_memdup(val + 3, len - 3);
220     } else if (!strncasecmp(val, "N:", 2)) {
221       if (vcard->family_name)
222         break;
223       if (len - 2) {
224         off = 2;
225         for (i = off; i < len; i++)
226           if (val[i] == ';') {
227             VCARD_TOKEN(vcard->family_name);
228             VCARD_TOKEN(vcard->first_name);
229             VCARD_TOKEN(vcard->middle_names);
230             VCARD_TOKEN(vcard->prefix);
231           }
232         VCARD_LASTTOKEN(vcard->suffix);
233       }
234     } else if (!strncasecmp(val, "NICKNAME:", 9)) {
235       if (vcard->nickname)
236         continue;
237       if (len - 9)
238         vcard->nickname = silc_memdup(val + 9, len - 9);
239     } else if (!strncasecmp(val, "BDAY:", 5)) {
240       if (vcard->bday)
241         continue;
242       if (len - 5)
243         vcard->bday = silc_memdup(val + 5, len - 5);
244     } else if (!strncasecmp(val, "TITLE:", 6)) {
245       if (vcard->title)
246         continue;
247       if (len - 6)
248         vcard->title = silc_memdup(val + 6, len - 6);
249     } else if (!strncasecmp(val, "ROLE:", 5)) {
250       if (vcard->role)
251         continue;
252       if (len - 5)
253         vcard->role = silc_memdup(val + 5, len - 5);
254     } else if (!strncasecmp(val, "ORG:", 4)) {
255       if (vcard->org_name)
256         continue;
257       if (len - 4) {
258         off = 4;
259         for (i = off; i < len; i++) {
260           if (val[i] == ';') {
261             VCARD_TOKEN(vcard->org_name);
262             break;
263           }
264         }
265         if (!vcard->org_name) {
266           VCARD_LASTTOKEN(vcard->org_name);
267         } else {
268           VCARD_LASTTOKEN(vcard->org_unit);
269         }
270       }
271     } else if (!strncasecmp(val, "CATEGORIES:", 11)) {
272       if (vcard->categories)
273         continue;
274       if (len - 11)
275         vcard->categories = silc_memdup(val + 11, len - 11);
276     } else if (!strncasecmp(val, "CLASS:", 6)) {
277       if (vcard->class)
278         continue;
279       if (len - 6)
280         vcard->class = silc_memdup(val + 6, len - 6);
281     } else if (!strncasecmp(val, "URL:", 4)) {
282       if (vcard->url)
283         continue;
284       if (len - 4)
285         vcard->url = silc_memdup(val + 4, len - 4);
286     } else if (!strncasecmp(val, "LABEL;", 6)) {
287       if (vcard->label)
288         continue;
289       if (len - 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));
294       if (len - 4) {
295         off = 4;
296         for (i = off; i < len; i++)
297           if (val[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);
305           }
306         VCARD_LASTTOKEN(vcard->addrs[vcard->num_addrs].country);
307       }
308       vcard->num_addrs++;
309     } else if (!strncasecmp(val, "TEL;", 4)) {
310       vcard->tels = silc_realloc(vcard->tels, sizeof(*vcard->tels) *
311                                  (vcard->num_tels + 1));
312       if (len - 4) {
313         off = 4;
314         for (i = off; i < len; i++)
315           if (val[i] == ':') {
316             i++;
317             VCARD_TYPETOKEN(vcard->tels[vcard->num_tels].type);
318             break;
319           }
320         VCARD_LASTTOKEN(vcard->tels[vcard->num_tels].tel);
321       }
322       vcard->num_tels++;
323     } else if (!strncasecmp(val, "EMAIL;", 6)) {
324       vcard->emails = silc_realloc(vcard->emails, sizeof(*vcard->emails) *
325                                    (vcard->num_emails + 1));
326       if (len - 6) {
327         off = 6;
328         for (i = off; i < len; i++)
329           if (val[i] == ':') {
330             i++;
331             VCARD_TYPETOKEN(vcard->emails[vcard->num_emails].type);
332             break;
333           }
334         VCARD_LASTTOKEN(vcard->emails[vcard->num_emails].address);
335       }
336       vcard->num_emails++;
337     } else if (!strncasecmp(val, "NOTE:", 5)) {
338       if (vcard->note)
339         continue;
340       if (len - 5)
341         vcard->note = silc_memdup(val + 5, len - 5);
342     } else if (!strncasecmp(val, "REV:", 4)) {
343       if (vcard->rev)
344         continue;
345       if (len - 4)
346         vcard->rev = silc_memdup(val + 4, len - 4);
347     } else if (!strncasecmp(val, VCARD_FOOTER, strlen(VCARD_FOOTER))) {
348       has_end = TRUE;
349       break;
350     }
351
352     val = strchr(val, '\n');
353     if (!val || !(*val))
354       break;
355     val++;
356     if (!val || !(*val))
357       break;
358   }
359
360   if (!has_begin || !has_end) {
361     silc_vcard_free_internal(vcard);
362     return FALSE;
363   }
364
365   return TRUE;
366 }
367
368 /* Free the vcard structure */
369
370 void silc_vcard_free(SilcVCard vcard)
371 {
372   silc_vcard_free_internal(vcard);
373   memset(vcard, 'F', sizeof(*vcard));
374   silc_free(vcard);
375 }
376
377 /* Print card to file stream */
378
379 void silc_vcard_fprintf(SilcVCard vcard, FILE *stream)
380 {
381   int i;
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",
388             vcard->family_name,
389             vcard->first_name ? vcard->first_name : "",
390             vcard->middle_names ? vcard->middle_names : "",
391             vcard->prefix ? vcard->prefix : "",
392             vcard->suffix ? vcard->suffix : "");
393   if (vcard->nickname)
394     fprintf(stream, "NICKNAME:%s\n", vcard->nickname);
395   if (vcard->bday)
396     fprintf(stream, "BDAY:%s\n", vcard->bday);
397   if (vcard->title)
398     fprintf(stream, "TITLE:%s\n", vcard->title);
399   if (vcard->role)
400     fprintf(stream, "ROLE:%s\n", vcard->role);
401   if (vcard->org_name)
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);
406   if (vcard->class)
407     fprintf(stream, "CLASS:%s\n", vcard->class);
408   if (vcard->url)
409     fprintf(stream, "URL:%s\n", vcard->url);
410   if (vcard->label)
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 : "");
422   }
423   for (i = 0; i < vcard->num_tels; i++) {
424     fprintf(stream, "TEL;TYPE=%s:%s\n",
425             vcard->tels[i].type,
426             vcard->tels[i].tel ? vcard->tels[i].tel : "");
427   }
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 : "");
432   }
433   if (vcard->note)
434     fprintf(stream, "NOTE:%s\n", vcard->note);
435   if (vcard->rev)
436     fprintf(stream, "REV:%s\n", vcard->rev);
437   fprintf(stream, "%s", VCARD_FOOTER);
438   fflush(stream);
439 }