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