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>
39 * Constructor (empty vCard)
41 struct vCard *vcard_new() {
44 v = (struct vCard *) malloc(sizeof(struct vCard));
45 if (v == NULL) return v;
47 v->magic = CTDL_VCARD_MAGIC;
56 * Constructor (supply serialized vCard)
58 struct vCard *vcard_load(char *vtext) {
62 char *namebuf, *valuebuf;
66 mycopy = strdup(vtext);
67 if (mycopy == NULL) return NULL;
69 /* First, fix this big pile o' vCard to make it more parseable.
70 * To make it easier to parse, we convert CRLF to LF, and unfold any
71 * multi-line fields into single lines.
73 for (i=0; i<strlen(mycopy); ++i) {
74 if (!strncmp(&mycopy[i], "\r\n", 2)) {
75 strcpy(&mycopy[i], &mycopy[i+1]);
77 if ( (mycopy[i]=='\n') && (isspace(mycopy[i+1])) ) {
78 strcpy(&mycopy[i], &mycopy[i+1]);
83 if (v == NULL) return v;
86 while (strlen(ptr)>0) {
89 colonpos = pattern2(ptr, ":");
90 nlpos = pattern2(ptr, "\n");
92 if ((nlpos > colonpos) && (colonpos > 0)) {
93 namebuf = malloc(colonpos + 1);
94 valuebuf = malloc(nlpos - colonpos + 1);
95 strncpy(namebuf, ptr, colonpos);
96 namebuf[colonpos] = 0;
97 strncpy(valuebuf, &ptr[colonpos+1], nlpos-colonpos-1);
98 valuebuf[nlpos-colonpos-1] = 0;
100 if ( (!strcasecmp(namebuf, "end"))
101 && (!strcasecmp(valuebuf, "vcard")) ) valid = 0;
102 if ( (!strcasecmp(namebuf, "begin"))
103 && (!strcasecmp(valuebuf, "vcard")) ) valid = 1;
105 if ( (valid) && (strcasecmp(namebuf, "begin")) ) {
107 v->prop = realloc(v->prop,
108 (v->numprops * sizeof(char *) * 2) );
109 v->prop[v->numprops-1].name = namebuf;
110 v->prop[v->numprops-1].value = valuebuf;
119 while ( (*ptr != '\n') && (strlen(ptr)>0) ) {
122 if (*ptr == '\n') ++ptr;
131 * Fetch the value of a particular key.
132 * If is_partial is set to 1, a partial match is ok (for example,
133 * a key of "tel;home" will satisfy a search for "tel").
134 * Set "instance" to a value higher than 0 to return subsequent instances
136 * Set "get_propname" to nonzero to fetch the property name instead of value.
138 char *vcard_get_prop(struct vCard *v, char *propname,
139 int is_partial, int instance, int get_propname) {
141 int found_instance = 0;
143 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
144 if ( (!strcasecmp(v->prop[i].name, propname))
145 || (propname[0] == 0)
146 || ( (!strncasecmp(v->prop[i].name,
147 propname, strlen(propname)))
148 && (v->prop[i].name[strlen(propname)] == ';')
149 && (is_partial) ) ) {
150 if (instance == found_instance++) {
152 return(v->prop[i].name);
155 return(v->prop[i].value);
170 void vcard_free(struct vCard *v) {
173 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
175 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
176 free(v->prop[i].name);
177 free(v->prop[i].value);
180 if (v->prop != NULL) free(v->prop);
182 memset(v, 0, sizeof(struct vCard));
190 * Set a name/value pair in the card
192 void vcard_set_prop(struct vCard *v, char *name, char *value, int append) {
195 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
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);
208 /* Otherwise, append it */
210 v->prop = realloc(v->prop,
211 (v->numprops * sizeof(char *) * 2) );
212 v->prop[v->numprops-1].name = strdup(name);
213 v->prop[v->numprops-1].value = strdup(value);
220 * Serialize a struct vcard into a standard text/x-vcard MIME type.
223 char *vcard_serialize(struct vCard *v)
229 if (v->magic != CTDL_VCARD_MAGIC) return NULL; /* self check */
231 /* Figure out how big a buffer we need to allocate */
232 len = 64; /* for begin, end, and a little padding for safety */
233 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
235 strlen(v->prop[i].name) +
236 strlen(v->prop[i].value) + 4;
240 if (ser == NULL) return NULL;
242 strcpy(ser, "begin:vcard\r\n");
243 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
244 strcat(ser, v->prop[i].name);
246 strcat(ser, v->prop[i].value);
249 strcat(ser, "end:vcard\r\n");