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>
40 * Constructor (empty vCard)
42 struct vCard *vcard_new() {
45 v = (struct vCard *) mallok(sizeof(struct vCard));
46 if (v == NULL) return v;
48 v->magic = CTDL_VCARD_MAGIC;
57 * Constructor (supply serialized vCard)
59 struct vCard *vcard_load(char *vtext) {
63 char *namebuf, *valuebuf;
67 mycopy = strdoop(vtext);
68 if (mycopy == NULL) return NULL;
70 /* First, fix this big pile o' vCard to make it more parseable.
71 * To make it easier to parse, we convert CRLF to LF, and unfold any
72 * multi-line fields into single lines.
74 for (i=0; i<strlen(mycopy); ++i) {
75 if (!strncmp(&mycopy[i], "\r\n", 2)) {
76 strcpy(&mycopy[i], &mycopy[i+1]);
78 if ( (mycopy[i]=='\n') && (isspace(mycopy[i+1])) ) {
79 strcpy(&mycopy[i], &mycopy[i+1]);
84 if (v == NULL) return v;
87 while (strlen(ptr)>0) {
90 colonpos = pattern2(ptr, ":");
91 nlpos = pattern2(ptr, "\n");
93 if ((nlpos > colonpos) && (colonpos > 0)) {
94 namebuf = mallok(colonpos + 1);
95 valuebuf = mallok(nlpos - colonpos + 1);
96 strncpy(namebuf, ptr, colonpos);
97 namebuf[colonpos] = 0;
98 strncpy(valuebuf, &ptr[colonpos+1], nlpos-colonpos-1);
99 valuebuf[nlpos-colonpos-1] = 0;
101 if ( (!strcasecmp(namebuf, "end"))
102 && (!strcasecmp(valuebuf, "vcard")) ) valid = 0;
103 if ( (!strcasecmp(namebuf, "begin"))
104 && (!strcasecmp(valuebuf, "vcard")) ) valid = 1;
106 if ( (valid) && (strcasecmp(namebuf, "begin")) ) {
108 v->prop = reallok(v->prop,
109 (v->numprops * sizeof(char *) * 2) );
110 v->prop[v->numprops-1].name = namebuf;
111 v->prop[v->numprops-1].value = valuebuf;
120 while ( (*ptr != '\n') && (strlen(ptr)>0) ) {
123 if (*ptr == '\n') ++ptr;
132 * Fetch the value of a particular key.
133 * If is_partial is set to 1, a partial match is ok (for example,
134 * a key of "tel;home" will satisfy a search for "tel").
135 * Set "instance" to a value higher than 0 to return subsequent instances
137 * Set "get_propname" to nonzero to fetch the property name instead of value.
139 char *vcard_get_prop(struct vCard *v, char *propname,
140 int is_partial, int instance, int get_propname) {
142 int found_instance = 0;
144 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
145 if ( (!strcasecmp(v->prop[i].name, propname))
146 || (propname[0] == 0)
147 || ( (!strncasecmp(v->prop[i].name,
148 propname, strlen(propname)))
149 && (v->prop[i].name[strlen(propname)] == ';')
150 && (is_partial) ) ) {
151 if (instance == found_instance++) {
153 return(v->prop[i].name);
156 return(v->prop[i].value);
171 void vcard_free(struct vCard *v) {
174 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
176 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
177 phree(v->prop[i].name);
178 phree(v->prop[i].value);
181 if (v->prop != NULL) phree(v->prop);
183 memset(v, 0, sizeof(struct vCard));
191 * Set a name/value pair in the card
193 void vcard_set_prop(struct vCard *v, char *name, char *value, int append) {
196 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
198 /* If this key is already present, replace it */
199 if (!append) if (v->numprops) for (i=0; i<(v->numprops); ++i) {
200 if (!strcasecmp(v->prop[i].name, name)) {
201 phree(v->prop[i].name);
202 phree(v->prop[i].value);
203 v->prop[i].name = strdoop(name);
204 v->prop[i].value = strdoop(value);
209 /* Otherwise, append it */
211 v->prop = reallok(v->prop,
212 (v->numprops * sizeof(char *) * 2) );
213 v->prop[v->numprops-1].name = strdoop(name);
214 v->prop[v->numprops-1].value = strdoop(value);
221 * Serialize a struct vcard into a standard text/x-vcard MIME type.
224 char *vcard_serialize(struct vCard *v)
230 if (v->magic != CTDL_VCARD_MAGIC) return NULL; /* self check */
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) {
236 strlen(v->prop[i].name) +
237 strlen(v->prop[i].value) + 4;
241 if (ser == NULL) return NULL;
243 strcpy(ser, "begin:vcard\r\n");
244 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
245 strcat(ser, v->prop[i].name);
247 strcat(ser, v->prop[i].value);
250 strcat(ser, "end:vcard\r\n");