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