4 * vCard implementation for Citadel/UX
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.
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
23 # include <sys/time.h>
41 * Constructor (empty vCard)
43 struct vCard *vcard_new() {
46 v = (struct vCard *) mallok(sizeof(struct vCard));
47 if (v == NULL) return v;
49 v->magic = CTDL_VCARD_MAGIC;
58 * Constructor (supply serialized vCard)
60 struct vCard *vcard_load(char *vtext) {
64 char *namebuf, *valuebuf;
68 mycopy = strdoop(vtext);
69 if (mycopy == NULL) return NULL;
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.
75 for (i=0; i<strlen(mycopy); ++i) {
76 if (!strncmp(&mycopy[i], "\r\n", 2)) {
77 strcpy(&mycopy[i], &mycopy[i+1]);
79 if ( (mycopy[i]=='\n') && (isspace(mycopy[i+1])) ) {
80 strcpy(&mycopy[i], &mycopy[i+1]);
85 if (v == NULL) return v;
88 while (strlen(ptr)>0) {
91 colonpos = pattern2(ptr, ":");
92 nlpos = pattern2(ptr, "\n");
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;
102 if ( (!strcasecmp(namebuf, "end"))
103 && (!strcasecmp(valuebuf, "vcard")) ) valid = 0;
104 if ( (!strcasecmp(namebuf, "begin"))
105 && (!strcasecmp(valuebuf, "vcard")) ) valid = 1;
107 if ( (valid) && (strcasecmp(namebuf, "begin")) ) {
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;
121 while ( (*ptr != '\n') && (strlen(ptr)>0) ) {
124 if (*ptr == '\n') ++ptr;
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
138 * Set "get_propname" to nonzero to fetch the property name instead of value.
140 char *vcard_get_prop(struct vCard *v, char *propname,
141 int is_partial, int instance, int get_propname) {
143 int found_instance = 0;
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++) {
154 return(v->prop[i].name);
157 return(v->prop[i].value);
172 void vcard_free(struct vCard *v) {
175 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
177 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
178 phree(v->prop[i].name);
179 phree(v->prop[i].value);
182 if (v->prop != NULL) phree(v->prop);
184 memset(v, 0, sizeof(struct vCard));
192 * Set a name/value pair in the card
194 void vcard_set_prop(struct vCard *v, char *name, char *value, int append) {
197 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
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);
210 /* Otherwise, append it */
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);
222 * Serialize a struct vcard into a standard text/x-vcard MIME type.
225 char *vcard_serialize(struct vCard *v)
231 if (v->magic != CTDL_VCARD_MAGIC) return NULL; /* self check */
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) {
237 strlen(v->prop[i].name) +
238 strlen(v->prop[i].value) + 4;
242 if (ser == NULL) return NULL;
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);
248 strcat(ser, v->prop[i].value);
251 strcat(ser, "end:vcard\r\n");