4c2bcab012f47954e2255b590af426d22c518791
[citadel.git] / citadel / vcard.c
1 /*
2  * $Id$
3  *
4  * vCard implementation for Citadel/UX
5  *
6  * Copyright (C) 1999 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
34 #include "citadel.h"
35 #include "server.h"
36 #include "support.h"
37 #include "vcard.h"
38
39 /* 
40  * Constructor (empty vCard)
41  */
42 struct vCard *vcard_new() {
43         struct vCard *v;
44
45         v = (struct vCard *) malloc(sizeof(struct vCard));
46         if (v == NULL) return v;
47
48         v->magic = CTDL_VCARD_MAGIC;
49         v->numprops = 0;
50         v->prop = NULL;
51
52         return v;
53 }
54
55
56 /*
57  * Add a property to a vCard
58  */
59 void vcard_add_prop(struct vCard *v, char *propname, char *propvalue) {
60         ++v->numprops;
61         v->prop = realloc(v->prop,
62                 (v->numprops * sizeof(char *) * 2) );
63         v->prop[v->numprops-1].name = strdup(propname);
64         v->prop[v->numprops-1].value = strdup(propvalue);
65 }
66
67
68
69 /*
70  * Constructor (supply serialized vCard)
71  */
72 struct vCard *vcard_load(char *vtext) {
73         struct vCard *v;
74         int valid = 0;
75         char *mycopy, *ptr;
76         char *namebuf, *valuebuf;
77         int i;
78         int colonpos, nlpos;
79
80         mycopy = strdup(vtext);
81         if (mycopy == NULL) return NULL;
82
83         /* First, fix this big pile o' vCard to make it more parseable.
84          * To make it easier to parse, we convert CRLF to LF, and unfold any
85          * multi-line fields into single lines.
86          */
87         for (i=0; i<strlen(mycopy); ++i) {
88                 if (!strncmp(&mycopy[i], "\r\n", 2)) {
89                         strcpy(&mycopy[i], &mycopy[i+1]);
90                 }
91                 if ( (mycopy[i]=='\n') && (isspace(mycopy[i+1])) ) {
92                         strcpy(&mycopy[i], &mycopy[i+1]);
93                 }
94         }
95
96         v = vcard_new();
97         if (v == NULL) return v;
98
99         ptr = mycopy;
100         while (strlen(ptr)>0) {
101                 colonpos = (-1);
102                 nlpos = (-1);
103                 colonpos = pattern2(ptr, ":");
104                 nlpos = pattern2(ptr, "\n");
105
106                 if ((nlpos > colonpos) && (colonpos > 0)) {
107                         namebuf = malloc(colonpos + 1);
108                         valuebuf = malloc(nlpos - colonpos + 1);
109                         strncpy(namebuf, ptr, colonpos);
110                         namebuf[colonpos] = 0;
111                         strncpy(valuebuf, &ptr[colonpos+1], nlpos-colonpos-1);
112                         valuebuf[nlpos-colonpos-1] = 0;
113
114                         if ( (!strcasecmp(namebuf, "end"))
115                            && (!strcasecmp(valuebuf, "vcard")) )  valid = 0;
116                         if ( (!strcasecmp(namebuf, "begin"))
117                            && (!strcasecmp(valuebuf, "vcard")) )  valid = 1;
118
119                         if ( (valid) && (strcasecmp(namebuf, "begin")) ) {
120                                 ++v->numprops;
121                                 v->prop = realloc(v->prop,
122                                         (v->numprops * sizeof(char *) * 2) );
123                                 v->prop[v->numprops-1].name = namebuf;
124                                 v->prop[v->numprops-1].value = valuebuf;
125                         } 
126                         else {
127                                 free(namebuf);
128                                 free(valuebuf);
129                         }
130
131                 }
132
133                 while ( (*ptr != '\n') && (strlen(ptr)>0) ) {
134                         ++ptr;
135                 }
136                 if (*ptr == '\n') ++ptr;
137         }
138
139         free(mycopy);
140         return v;
141 }
142
143
144 /*
145  * Fetch the value of a particular key.
146  * If is_partial is set to 1, a partial match is ok (for example,
147  * a key of "tel;home" will satisfy a search for "tel").
148  * Set "instance" to a value higher than 0 to return subsequent instances
149  * of the same key.
150  * Set "get_propname" to nonzero to fetch the property name instead of value.
151  */
152 char *vcard_get_prop(struct vCard *v, char *propname,
153                         int is_partial, int instance, int get_propname) {
154         int i;
155         int found_instance = 0;
156
157         if (v->numprops) for (i=0; i<(v->numprops); ++i) {
158                 if ( (!strcasecmp(v->prop[i].name, propname))
159                    || (propname[0] == 0)
160                    || (  (!strncasecmp(v->prop[i].name,
161                                         propname, strlen(propname)))
162                          && (v->prop[i].name[strlen(propname)] == ';')
163                          && (is_partial) ) ) {
164                         if (instance == found_instance++) {
165                                 if (get_propname) {
166                                         return(v->prop[i].name);
167                                 }
168                                 else {
169                                         return(v->prop[i].value);
170                                 }
171                         }
172                 }
173         }
174
175         return NULL;
176 }
177
178
179 /*
180  * Destructor
181  */
182 void vcard_free(struct vCard *v) {
183         int i;
184         
185         if (v->magic != CTDL_VCARD_MAGIC) return;       /* Self-check */
186         
187         if (v->numprops) for (i=0; i<(v->numprops); ++i) {
188                 free(v->prop[i].name);
189                 free(v->prop[i].value);
190         }
191
192         if (v->prop != NULL) free(v->prop);
193         
194         memset(v, 0, sizeof(struct vCard));
195         free(v);
196 }
197
198
199
200
201 /*
202  * Set a name/value pair in the card
203  */
204 void vcard_set_prop(struct vCard *v, char *name, char *value, int append) {
205         int i;
206
207         if (v->magic != CTDL_VCARD_MAGIC) return;       /* Self-check */
208
209         /* If this key is already present, replace it */
210         if (!append) if (v->numprops) for (i=0; i<(v->numprops); ++i) {
211                 if (!strcasecmp(v->prop[i].name, name)) {
212                         free(v->prop[i].name);
213                         free(v->prop[i].value);
214                         v->prop[i].name = strdup(name);
215                         v->prop[i].value = strdup(value);
216                         return;
217                 }
218         }
219
220         /* Otherwise, append it */
221         ++v->numprops;
222         v->prop = realloc(v->prop,
223                 (v->numprops * sizeof(char *) * 2) );
224         v->prop[v->numprops-1].name = strdup(name);
225         v->prop[v->numprops-1].value = strdup(value);
226 }
227
228
229
230
231 /*
232  * Serialize a struct vcard into a standard text/x-vcard MIME type.
233  *
234  */
235 char *vcard_serialize(struct vCard *v)
236 {
237         char *ser;
238         int i;
239         size_t len;
240
241         if (v->magic != CTDL_VCARD_MAGIC) return NULL;  /* self check */
242
243         /* Figure out how big a buffer we need to allocate */
244         len = 64;       /* for begin, end, and a little padding for safety */
245         if (v->numprops) for (i=0; i<(v->numprops); ++i) {
246                 len = len +
247                         strlen(v->prop[i].name) +
248                         strlen(v->prop[i].value) + 4;
249         }
250
251         ser = malloc(len);
252         if (ser == NULL) return NULL;
253
254         strcpy(ser, "begin:vcard\r\n");
255         if (v->numprops) for (i=0; i<(v->numprops); ++i) {
256                 strcat(ser, v->prop[i].name);
257                 strcat(ser, ":");
258                 strcat(ser, v->prop[i].value);
259                 strcat(ser, "\r\n");
260         }
261         strcat(ser, "end:vcard\r\n");
262
263         return ser;
264 }