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