4 * vCard implementation for Citadel
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.
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
23 # include <sys/time.h>
42 * Constructor (empty vCard)
44 struct vCard *vcard_new() {
47 v = (struct vCard *) malloc(sizeof(struct vCard));
48 if (v == NULL) return v;
50 v->magic = CTDL_VCARD_MAGIC;
59 * Add a property to a vCard
61 void vcard_add_prop(struct vCard *v, char *propname, char *propvalue) {
63 v->prop = realloc(v->prop,
64 (v->numprops * sizeof(struct vCardProp)) );
65 v->prop[v->numprops-1].name = strdup(propname);
66 v->prop[v->numprops-1].value = strdup(propvalue);
72 * Constructor (supply serialized vCard)
74 struct vCard *vcard_load(char *vtext) {
78 char *namebuf, *valuebuf;
82 mycopy = strdup(vtext);
83 if (mycopy == NULL) return NULL;
85 /* First, fix this big pile o' vCard to make it more parseable.
86 * To make it easier to parse, we convert CRLF to LF, and unfold any
87 * multi-line fields into single lines.
89 for (i=0; i<strlen(mycopy); ++i) {
90 if (!strncmp(&mycopy[i], "\r\n", 2)) {
91 strcpy(&mycopy[i], &mycopy[i+1]);
93 if ( (mycopy[i]=='\n') && (isspace(mycopy[i+1])) ) {
94 strcpy(&mycopy[i], &mycopy[i+1]);
99 if (v == NULL) return v;
102 while (strlen(ptr)>0) {
105 colonpos = pattern2(ptr, ":");
106 nlpos = pattern2(ptr, "\n");
108 if ((nlpos > colonpos) && (colonpos > 0)) {
109 namebuf = malloc(colonpos + 1);
110 valuebuf = malloc(nlpos - colonpos + 1);
111 strncpy(namebuf, ptr, colonpos);
112 namebuf[colonpos] = 0;
113 strncpy(valuebuf, &ptr[colonpos+1], nlpos-colonpos-1);
114 valuebuf[nlpos-colonpos-1] = 0;
116 if ( (!strcasecmp(namebuf, "end"))
117 && (!strcasecmp(valuebuf, "vcard")) ) valid = 0;
118 if ( (!strcasecmp(namebuf, "begin"))
119 && (!strcasecmp(valuebuf, "vcard")) ) valid = 1;
121 if ( (valid) && (strcasecmp(namebuf, "begin")) ) {
123 v->prop = realloc(v->prop,
124 (v->numprops * sizeof(struct vCardProp)) );
125 v->prop[v->numprops-1].name = namebuf;
126 v->prop[v->numprops-1].value = valuebuf;
135 while ( (*ptr != '\n') && (strlen(ptr)>0) ) {
138 if (*ptr == '\n') ++ptr;
147 * Fetch the value of a particular key.
148 * If is_partial is set to 1, a partial match is ok (for example,
149 * a key of "tel;home" will satisfy a search for "tel").
150 * Set "instance" to a value higher than 0 to return subsequent instances
152 * Set "get_propname" to nonzero to fetch the property name instead of value.
154 char *vcard_get_prop(struct vCard *v, char *propname,
155 int is_partial, int instance, int get_propname) {
157 int found_instance = 0;
159 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
160 if ( (!strcasecmp(v->prop[i].name, propname))
161 || (propname[0] == 0)
162 || ( (!strncasecmp(v->prop[i].name,
163 propname, strlen(propname)))
164 && (v->prop[i].name[strlen(propname)] == ';')
165 && (is_partial) ) ) {
166 if (instance == found_instance++) {
168 return(v->prop[i].name);
171 return(v->prop[i].value);
184 void vcard_free(struct vCard *v) {
187 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
189 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
190 free(v->prop[i].name);
191 free(v->prop[i].value);
194 if (v->prop != NULL) free(v->prop);
196 memset(v, 0, sizeof(struct vCard));
204 * Set a name/value pair in the card
206 void vcard_set_prop(struct vCard *v, char *name, char *value, int append) {
209 if (v->magic != CTDL_VCARD_MAGIC) return; /* Self-check */
211 /* If this key is already present, replace it */
212 if (!append) if (v->numprops) for (i=0; i<(v->numprops); ++i) {
213 if (!strcasecmp(v->prop[i].name, name)) {
214 free(v->prop[i].name);
215 free(v->prop[i].value);
216 v->prop[i].name = strdup(name);
217 v->prop[i].value = strdup(value);
222 /* Otherwise, append it */
224 v->prop = realloc(v->prop,
225 (v->numprops * sizeof(struct vCardProp)) );
226 v->prop[v->numprops-1].name = strdup(name);
227 v->prop[v->numprops-1].value = strdup(value);
234 * Serialize a struct vcard into a standard text/x-vcard MIME type.
237 char *vcard_serialize(struct vCard *v)
243 if (v->magic != CTDL_VCARD_MAGIC) return NULL; /* self check */
245 /* Figure out how big a buffer we need to allocate */
246 len = 64; /* for begin, end, and a little padding for safety */
247 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
249 strlen(v->prop[i].name) +
250 strlen(v->prop[i].value) + 4;
254 if (ser == NULL) return NULL;
256 strcpy(ser, "begin:vcard\r\n");
257 if (v->numprops) for (i=0; i<(v->numprops); ++i) {
258 strcat(ser, v->prop[i].name);
260 strcat(ser, v->prop[i].value);
263 strcat(ser, "end:vcard\r\n");
271 * Convert FN (Friendly Name) into N (Name)
273 void vcard_fn_to_n(char *vname, char *n, size_t vname_size) {
276 char middlename[256];
277 char honorific_prefixes[256];
278 char honorific_suffixes[256];
281 safestrncpy(buf, n, sizeof buf);
283 /* Try to intelligently convert the screen name to a
284 * fully expanded vCard name based on the number of
287 safestrncpy(lastname, "", sizeof lastname);
288 safestrncpy(firstname, "", sizeof firstname);
289 safestrncpy(middlename, "", sizeof middlename);
290 safestrncpy(honorific_prefixes, "", sizeof honorific_prefixes);
291 safestrncpy(honorific_suffixes, "", sizeof honorific_suffixes);
293 /* Honorific suffixes */
294 if (num_tokens(buf, ',') > 1) {
295 extract_token(honorific_suffixes, buf, (num_tokens(buf, ' ') - 1), ',',
296 sizeof honorific_suffixes);
297 remove_token(buf, (num_tokens(buf, ',') - 1), ',');
300 /* Find a last name */
301 extract_token(lastname, buf, (num_tokens(buf, ' ') - 1), ' ', sizeof lastname);
302 remove_token(buf, (num_tokens(buf, ' ') - 1), ' ');
304 /* Find honorific prefixes */
305 if (num_tokens(buf, ' ') > 2) {
306 extract_token(honorific_prefixes, buf, 0, ' ', sizeof honorific_prefixes);
307 remove_token(buf, 0, ' ');
310 /* Find a middle name */
311 if (num_tokens(buf, ' ') > 1) {
312 extract_token(middlename, buf, (num_tokens(buf, ' ') - 1), ' ', sizeof middlename);
313 remove_token(buf, (num_tokens(buf, ' ') - 1), ' ');
316 /* Anything left is probably the first name */
317 safestrncpy(firstname, buf, sizeof firstname);
320 /* Compose the structured name */
321 snprintf(vname, vname_size, "%s;%s;%s;%s;%s", lastname, firstname, middlename,
322 honorific_prefixes, honorific_suffixes);