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