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