4 * vCard data type implementation for Citadel/UX
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.
21 #include <sys/types.h>
23 #include <sys/socket.h>
24 #ifdef HAVE_SYS_TIME_H
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
40 #include "webserver.h"
44 * Constructor (empty vCard)
46 struct vCard *vcard_new() {
49 v = (struct vCard *) malloc(sizeof(struct vCard));
50 if (v == NULL) return v;
52 v->magic = CTDL_VCARD_MAGIC;
61 * Constructor (supply serialized vCard)
63 struct vCard *vcard_load(char *vtext) {
67 char *namebuf, *valuebuf;
71 if (vtext == NULL) return vcard_new();
72 mycopy = strdup(vtext);
73 if (mycopy == NULL) return NULL;
75 /* First, fix this big pile o' vCard to make it more parseable.
76 * To make it easier to parse, we convert CRLF to LF, and unfold any
77 * multi-line fields into single lines.
79 for (i=0; i<strlen(mycopy); ++i) {
80 if (!strncmp(&mycopy[i], "\r\n", 2)) {
81 strcpy(&mycopy[i], &mycopy[i+1]);
83 if ( (mycopy[i]=='\n') && (isspace(mycopy[i+1])) ) {
84 strcpy(&mycopy[i], &mycopy[i+1]);
89 if (v == NULL) return v;
92 while (strlen(ptr)>0) {
95 colonpos = pattern2(ptr, ":");
96 nlpos = pattern2(ptr, "\n");
98 if ((nlpos > colonpos) && (colonpos > 0)) {
99 namebuf = malloc(colonpos + 1);
100 valuebuf = malloc(nlpos - colonpos + 1);
101 strncpy(namebuf, ptr, colonpos);
102 namebuf[colonpos] = 0;
103 strncpy(valuebuf, &ptr[colonpos+1], nlpos-colonpos-1);
104 valuebuf[nlpos-colonpos-1] = 0;
106 if (!strcasecmp(namebuf, "end")) {
109 if ( (!strcasecmp(namebuf, "begin"))
110 && (!strcasecmp(valuebuf, "vcard"))
115 if ( (valid) && (strcasecmp(namebuf, "begin")) ) {
117 v->prop = realloc(v->prop,
118 (v->numprops * sizeof(struct vCardProp))
120 v->prop[v->numprops-1].name = namebuf;
121 v->prop[v->numprops-1].value = valuebuf;
130 while ( (*ptr != '\n') && (strlen(ptr)>0) ) {
133 if (*ptr == '\n') ++ptr;
142 * Fetch the value of a particular key.
143 * If is_partial is set to 1, a partial match is ok (for example,
144 * a key of "tel;home" will satisfy a search for "tel").
145 * Set "instance" to a value higher than 0 to return subsequent instances
147 * Set "get_propname" to nonzero to fetch the property name instead of value.
149 char *vcard_get_prop(struct vCard *v, char *propname,
150 int is_partial, int instance, int get_propname) {
152 int found_instance = 0;
154 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
155 if ( (!strcasecmp(v->prop[i].name, propname))
156 || (propname[0] == 0)
157 || ( (!strncasecmp(v->prop[i].name,
158 propname, strlen(propname)))
159 && (v->prop[i].name[strlen(propname)] == ';')
160 && (is_partial) ) ) {
161 if (instance == found_instance++) {
163 return(v->prop[i].name);
166 return(v->prop[i].value);
181 void vcard_free(struct vCard *v) {
184 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
186 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
187 free(v->prop[i].name);
188 free(v->prop[i].value);
191 if (v->prop != NULL) free(v->prop);
193 memset(v, 0, sizeof(struct vCard));
201 * Set a name/value pair in the card
203 void vcard_set_prop(struct vCard *v, char *name, char *value, int append) {
206 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
208 /* If this key is already present, replace it */
209 if (!append) if (v->numprops) for (i=0; i<(v->numprops); ++i) {
210 if (!strcasecmp(v->prop[i].name, name)) {
211 free(v->prop[i].name);
212 free(v->prop[i].value);
213 v->prop[i].name = strdup(name);
214 v->prop[i].value = strdup(value);
219 /* Otherwise, append it */
221 v->prop = realloc(v->prop,
222 (v->numprops * sizeof(struct vCardProp)) );
223 v->prop[v->numprops-1].name = strdup(name);
224 v->prop[v->numprops-1].value = strdup(value);
231 * Serialize a struct vcard into a standard text/x-vcard MIME type.
234 char *vcard_serialize(struct vCard *v)
240 if (v->magic != CTDL_VCARD_MAGIC) return NULL; /* self check */
242 /* Figure out how big a buffer we need to allocate */
243 len = 64; /* for begin, end, and a little padding for safety */
244 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
246 strlen(v->prop[i].name) +
247 strlen(v->prop[i].value) + 4;
251 if (ser == NULL) return NULL;
253 safestrncpy(ser, "begin:vcard\r\n", len);
254 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
255 strcat(ser, v->prop[i].name);
257 strcat(ser, v->prop[i].value);
260 strcat(ser, "end:vcard\r\n");