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