]> code.citadel.org Git - citadel.git/blob - citadel/vcard.c
26bb455c408ef776ba017aedefefe850afa0c79a
[citadel.git] / citadel / vcard.c
1 /*
2  * $Id$
3  *
4  * vCard implementation for Citadel
5  *
6  * Copyright (C) 1999-2005 by Art Cancro
7  * This code is freely redistributable under the terms of the GNU General
8  * Public License.  All other rights reserved.
9  */
10
11
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <fcntl.h>
16 #include <signal.h>
17
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
20 # include <time.h>
21 #else
22 # if HAVE_SYS_TIME_H
23 #  include <sys/time.h>
24 # else
25 #  include <time.h>
26 # endif
27 #endif
28
29 #include <ctype.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <limits.h>
33 #include <string.h>
34
35 #include "citadel.h"
36 #include "server.h"
37 #include "support.h"
38 #include "vcard.h"
39 #include "tools.h"
40
41 /* 
42  * Constructor (empty vCard)
43  */
44 struct vCard *vcard_new() {
45         struct vCard *v;
46
47         v = (struct vCard *) malloc(sizeof(struct vCard));
48         if (v == NULL) return v;
49
50         v->magic = CTDL_VCARD_MAGIC;
51         v->numprops = 0;
52         v->prop = NULL;
53
54         return v;
55 }
56
57
58 /*
59  * Add a property to a vCard
60  */
61 void vcard_add_prop(struct vCard *v, char *propname, char *propvalue) {
62         ++v->numprops;
63         v->prop = realloc(v->prop,
64                 (v->numprops * sizeof(struct vCardProp)) );
65         v->prop[v->numprops-1].name = strdup(propname);
66         v->prop[v->numprops-1].value = strdup(propvalue);
67 }
68
69
70
71 /*
72  * Constructor (supply serialized vCard)
73  */
74 struct vCard *vcard_load(char *vtext) {
75         struct vCard *v;
76         int valid = 0;
77         char *mycopy, *ptr;
78         char *namebuf, *valuebuf;
79         int i;
80         int colonpos, nlpos;
81
82         mycopy = strdup(vtext);
83         if (mycopy == NULL) return NULL;
84
85         /* First, fix this big pile o' vCard to make it more parseable.
86          * To make it easier to parse, we convert CRLF to LF, and unfold any
87          * multi-line fields into single lines.
88          */
89         for (i=0; i<strlen(mycopy); ++i) {
90                 if (!strncmp(&mycopy[i], "\r\n", 2)) {
91                         strcpy(&mycopy[i], &mycopy[i+1]);
92                 }
93                 if ( (mycopy[i]=='\n') && (isspace(mycopy[i+1])) ) {
94                         strcpy(&mycopy[i], &mycopy[i+1]);
95                 }
96         }
97
98         v = vcard_new();
99         if (v == NULL) return v;
100
101         ptr = mycopy;
102         while (strlen(ptr)>0) {
103                 colonpos = (-1);
104                 nlpos = (-1);
105                 colonpos = pattern2(ptr, ":");
106                 nlpos = pattern2(ptr, "\n");
107
108                 if ((nlpos > colonpos) && (colonpos > 0)) {
109                         namebuf = malloc(colonpos + 1);
110                         valuebuf = malloc(nlpos - colonpos + 1);
111                         strncpy(namebuf, ptr, colonpos);
112                         namebuf[colonpos] = 0;
113                         strncpy(valuebuf, &ptr[colonpos+1], nlpos-colonpos-1);
114                         valuebuf[nlpos-colonpos-1] = 0;
115
116                         if ( (!strcasecmp(namebuf, "end"))
117                            && (!strcasecmp(valuebuf, "vcard")) )  valid = 0;
118                         if ( (!strcasecmp(namebuf, "begin"))
119                            && (!strcasecmp(valuebuf, "vcard")) )  valid = 1;
120
121                         if ( (valid) && (strcasecmp(namebuf, "begin")) ) {
122                                 ++v->numprops;
123                                 v->prop = realloc(v->prop,
124                                         (v->numprops * sizeof(struct vCardProp)) );
125                                 v->prop[v->numprops-1].name = namebuf;
126                                 v->prop[v->numprops-1].value = valuebuf;
127                         } 
128                         else {
129                                 free(namebuf);
130                                 free(valuebuf);
131                         }
132
133                 }
134
135                 while ( (*ptr != '\n') && (strlen(ptr)>0) ) {
136                         ++ptr;
137                 }
138                 if (*ptr == '\n') ++ptr;
139         }
140
141         free(mycopy);
142         return v;
143 }
144
145
146 /*
147  * Fetch the value of a particular key.
148  * If is_partial is set to 1, a partial match is ok (for example,
149  * a key of "tel;home" will satisfy a search for "tel").
150  * Set "instance" to a value higher than 0 to return subsequent instances
151  * of the same key.
152  * Set "get_propname" to nonzero to fetch the property name instead of value.
153  */
154 char *vcard_get_prop(struct vCard *v, char *propname,
155                         int is_partial, int instance, int get_propname) {
156         int i;
157         int found_instance = 0;
158
159         if (v->numprops) for (i=0; i<(v->numprops); ++i) {
160                 if ( (!strcasecmp(v->prop[i].name, propname))
161                    || (propname[0] == 0)
162                    || (  (!strncasecmp(v->prop[i].name,
163                                         propname, strlen(propname)))
164                          && (v->prop[i].name[strlen(propname)] == ';')
165                          && (is_partial) ) ) {
166                         if (instance == found_instance++) {
167                                 if (get_propname) {
168                                         return(v->prop[i].name);
169                                 }
170                                 else {
171                                         return(v->prop[i].value);
172                                 }
173                         }
174                 }
175         }
176
177         return NULL;
178 }
179
180
181 /*
182  * Destructor
183  */
184 void vcard_free(struct vCard *v) {
185         int i;
186         
187         if (v->magic != CTDL_VCARD_MAGIC) return;       /* Self-check */
188         
189         if (v->numprops) for (i=0; i<(v->numprops); ++i) {
190                 free(v->prop[i].name);
191                 free(v->prop[i].value);
192         }
193
194         if (v->prop != NULL) free(v->prop);
195         
196         memset(v, 0, sizeof(struct vCard));
197         free(v);
198 }
199
200
201
202
203 /*
204  * Set a name/value pair in the card
205  */
206 void vcard_set_prop(struct vCard *v, char *name, char *value, int append) {
207         int i;
208
209         if (v->magic != CTDL_VCARD_MAGIC) return;       /* Self-check */
210
211         /* If this key is already present, replace it */
212         if (!append) if (v->numprops) for (i=0; i<(v->numprops); ++i) {
213                 if (!strcasecmp(v->prop[i].name, name)) {
214                         free(v->prop[i].name);
215                         free(v->prop[i].value);
216                         v->prop[i].name = strdup(name);
217                         v->prop[i].value = strdup(value);
218                         return;
219                 }
220         }
221
222         /* Otherwise, append it */
223         ++v->numprops;
224         v->prop = realloc(v->prop,
225                 (v->numprops * sizeof(struct vCardProp)) );
226         v->prop[v->numprops-1].name = strdup(name);
227         v->prop[v->numprops-1].value = strdup(value);
228 }
229
230
231
232
233 /*
234  * Serialize a struct vcard into a standard text/x-vcard MIME type.
235  *
236  */
237 char *vcard_serialize(struct vCard *v)
238 {
239         char *ser;
240         int i;
241         size_t len;
242
243         if (v->magic != CTDL_VCARD_MAGIC) return NULL;  /* self check */
244
245         /* Figure out how big a buffer we need to allocate */
246         len = 64;       /* for begin, end, and a little padding for safety */
247         if (v->numprops) for (i=0; i<(v->numprops); ++i) {
248                 len = len +
249                         strlen(v->prop[i].name) +
250                         strlen(v->prop[i].value) + 4;
251         }
252
253         ser = malloc(len);
254         if (ser == NULL) return NULL;
255
256         strcpy(ser, "begin:vcard\r\n");
257         if (v->numprops) for (i=0; i<(v->numprops); ++i) {
258                 strcat(ser, v->prop[i].name);
259                 strcat(ser, ":");
260                 strcat(ser, v->prop[i].value);
261                 strcat(ser, "\r\n");
262         }
263         strcat(ser, "end:vcard\r\n");
264
265         return ser;
266 }
267
268
269
270 /*
271  * Convert FN (Friendly Name) into N (Name)
272  */
273 void vcard_fn_to_n(char *vname, char *n, size_t vname_size) {
274         char lastname[256];
275         char firstname[256];
276         char middlename[256];
277         char honorific_prefixes[256];
278         char honorific_suffixes[256];
279         char buf[256];
280
281         safestrncpy(buf, n, sizeof buf);
282
283         /* Try to intelligently convert the screen name to a
284          * fully expanded vCard name based on the number of
285          * words in the name
286          */
287         safestrncpy(lastname, "", sizeof lastname);
288         safestrncpy(firstname, "", sizeof firstname);
289         safestrncpy(middlename, "", sizeof middlename);
290         safestrncpy(honorific_prefixes, "", sizeof honorific_prefixes);
291         safestrncpy(honorific_suffixes, "", sizeof honorific_suffixes);
292
293         /* Honorific suffixes */
294         if (num_tokens(buf, ',') > 1) {
295                 extract_token(honorific_suffixes, buf, (num_tokens(buf, ' ') - 1), ',',
296                         sizeof honorific_suffixes);
297                 remove_token(buf, (num_tokens(buf, ',') - 1), ',');
298         }
299
300         /* Find a last name */
301         extract_token(lastname, buf, (num_tokens(buf, ' ') - 1), ' ', sizeof lastname);
302         remove_token(buf, (num_tokens(buf, ' ') - 1), ' ');
303
304         /* Find honorific prefixes */
305         if (num_tokens(buf, ' ') > 2) {
306                 extract_token(honorific_prefixes, buf, 0, ' ', sizeof honorific_prefixes);
307                 remove_token(buf, 0, ' ');
308         }
309
310         /* Find a middle name */
311         if (num_tokens(buf, ' ') > 1) {
312                 extract_token(middlename, buf, (num_tokens(buf, ' ') - 1), ' ', sizeof middlename);
313                 remove_token(buf, (num_tokens(buf, ' ') - 1), ' ');
314         }
315
316         /* Anything left is probably the first name */
317         safestrncpy(firstname, buf, sizeof firstname);
318         striplt(firstname);
319
320         /* Compose the structured name */
321         snprintf(vname, vname_size, "%s;%s;%s;%s;%s", lastname, firstname, middlename,
322                 honorific_prefixes, honorific_suffixes);
323 }
324
325
326
327