2 * $Id: vcard.c 5754 2007-11-16 05:52:26Z ajc $
4 * vCard implementation for Citadel
6 * Copyright (C) 1999-2008 by the citadel.org development team.
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>
34 #include <libcitadel.h>
38 * Constructor (empty vCard)
39 * Returns an 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
;
55 * Remove the "charset=" attribute from a vCard property name
58 void remove_charset_attribute(char *strbuf
)
63 t
= num_tokens(strbuf
, ';');
65 extract_token(compare
, strbuf
, i
, ';', sizeof compare
);
67 if (!strncasecmp(compare
, "charset=", 8)) {
68 remove_token(strbuf
, i
, ';');
71 if (!IsEmptyStr(strbuf
)) {
72 if (strbuf
[strlen(strbuf
)-1] == ';') {
73 strbuf
[strlen(strbuf
)-1] = 0;
80 * Add a property to a vCard
82 * v vCard structure to which we are adding
83 * propname name of new property
84 * propvalue value of new property
86 void vcard_add_prop(struct vCard
*v
, char *propname
, char *propvalue
) {
88 v
->prop
= realloc(v
->prop
,
89 (v
->numprops
* sizeof(struct vCardProp
)) );
90 v
->prop
[v
->numprops
-1].name
= strdup(propname
);
91 v
->prop
[v
->numprops
-1].value
= strdup(propvalue
);
97 * Constructor - returns a new struct vcard given a serialized vcard
99 struct vCard
*vcard_load(char *vtext
) {
103 char *namebuf
, *valuebuf
;
107 if (vtext
== NULL
) return vcard_new();
108 mycopy
= strdup(vtext
);
109 if (mycopy
== NULL
) return NULL
;
112 * First, fix this big pile o' vCard to make it more parseable.
113 * To make it easier to parse, we convert CRLF to LF, and unfold any
114 * multi-line fields into single lines.
116 for (i
=0; !IsEmptyStr(&mycopy
[i
]); ++i
) {
117 if (!strncmp(&mycopy
[i
], "\r\n", 2)) {
118 strcpy(&mycopy
[i
], &mycopy
[i
+1]);
120 if ( (mycopy
[i
]=='\n') && (isspace(mycopy
[i
+1])) ) {
121 strcpy(&mycopy
[i
], &mycopy
[i
+1]);
126 if (v
== NULL
) return v
;
129 while (!IsEmptyStr(ptr
)) {
132 colonpos
= pattern2(ptr
, ":");
133 nlpos
= pattern2(ptr
, "\n");
135 if ((nlpos
> colonpos
) && (colonpos
> 0)) {
136 namebuf
= malloc(colonpos
+ 1);
137 valuebuf
= malloc(nlpos
- colonpos
+ 1);
138 memcpy(namebuf
, ptr
, colonpos
);
139 namebuf
[colonpos
] = '\0';
140 memcpy(valuebuf
, &ptr
[colonpos
+1], nlpos
-colonpos
-1);
141 valuebuf
[nlpos
-colonpos
-1] = '\0';
143 if (!strcasecmp(namebuf
, "end")) {
146 if ( (!strcasecmp(namebuf
, "begin"))
147 && (!strcasecmp(valuebuf
, "vcard"))
152 if ( (valid
) && (strcasecmp(namebuf
, "begin")) ) {
153 remove_charset_attribute(namebuf
);
155 v
->prop
= realloc(v
->prop
,
156 (v
->numprops
* sizeof(struct vCardProp
))
158 v
->prop
[v
->numprops
-1].name
= namebuf
;
159 v
->prop
[v
->numprops
-1].value
= valuebuf
;
168 while ( (*ptr
!= '\n') && (!IsEmptyStr(ptr
)) ) {
171 if (*ptr
== '\n') ++ptr
;
180 * Fetch the value of a particular key.
181 * If is_partial is set to 1, a partial match is ok (for example,
182 * a key of "tel;home" will satisfy a search for "tel").
183 * Set "instance" to a value higher than 0 to return subsequent instances
186 * Set "get_propname" to nonzero to fetch the property name instead of value.
187 * v vCard to get keyvalue from
188 * propname key to retrieve
190 * instance if nonzero return a later token of the value
191 * get_propname if nonzero get the real property name???
193 * returns the requested value / token / propertyname
195 char *vcard_get_prop(struct vCard
*v
, char *propname
,
196 int is_partial
, int instance
, int get_propname
) {
198 int found_instance
= 0;
200 if (v
->numprops
) for (i
=0; i
<(v
->numprops
); ++i
) {
201 if ( (!strcasecmp(v
->prop
[i
].name
, propname
))
202 || (propname
[0] == 0)
203 || ( (!strncasecmp(v
->prop
[i
].name
,
204 propname
, strlen(propname
)))
205 && (v
->prop
[i
].name
[strlen(propname
)] == ';')
206 && (is_partial
) ) ) {
207 if (instance
== found_instance
++) {
209 return(v
->prop
[i
].name
);
212 return(v
->prop
[i
].value
);
227 void vcard_free(struct vCard
*v
) {
230 if (v
->magic
!= CTDL_VCARD_MAGIC
) return; /* Self-check */
232 if (v
->numprops
) for (i
=0; i
<(v
->numprops
); ++i
) {
233 free(v
->prop
[i
].name
);
234 free(v
->prop
[i
].value
);
237 if (v
->prop
!= NULL
) free(v
->prop
);
239 memset(v
, 0, sizeof(struct vCard
));
247 * Set a name/value pair in the card
248 * v vCard to manipulate
250 * value the value to assign to key
251 * append if nonzero, append rather than replace if this key already exists.
253 void vcard_set_prop(struct vCard
*v
, char *name
, char *value
, int append
) {
256 if (v
->magic
!= CTDL_VCARD_MAGIC
) return; /* Self-check */
258 /* If this key is already present, replace it */
259 if (!append
) if (v
->numprops
) for (i
=0; i
<(v
->numprops
); ++i
) {
260 if (!strcasecmp(v
->prop
[i
].name
, name
)) {
261 free(v
->prop
[i
].name
);
262 free(v
->prop
[i
].value
);
263 v
->prop
[i
].name
= strdup(name
);
264 v
->prop
[i
].value
= strdup(value
);
269 /* Otherwise, append it */
271 v
->prop
= realloc(v
->prop
,
272 (v
->numprops
* sizeof(struct vCardProp
)) );
273 v
->prop
[v
->numprops
-1].name
= strdup(name
);
274 v
->prop
[v
->numprops
-1].value
= strdup(value
);
281 * Serialize a 'struct vcard' into an actual vcard.
283 char *vcard_serialize(struct vCard
*v
)
290 if (v
== NULL
) return NULL
; /* self check */
291 if (v
->magic
!= CTDL_VCARD_MAGIC
) return NULL
; /* self check */
293 /* Set the vCard version number to 2.1 at this time. */
294 vcard_set_prop(v
, "VERSION", "2.1", 0);
296 /* Figure out how big a buffer we need to allocate */
297 len
= 64; /* for begin, end, and a little padding for safety */
298 if (v
->numprops
) for (i
=0; i
<(v
->numprops
); ++i
) {
300 strlen(v
->prop
[i
].name
) +
301 strlen(v
->prop
[i
].value
) + 16;
305 if (ser
== NULL
) return NULL
;
307 safestrncpy(ser
, "begin:vcard\r\n", len
);
308 if (v
->numprops
) for (i
=0; i
<(v
->numprops
); ++i
) {
309 if ( (strcasecmp(v
->prop
[i
].name
, "end")) && (v
->prop
[i
].value
!= NULL
) ) {
311 for (j
=0; !IsEmptyStr(&v
->prop
[i
].value
[j
]); ++j
) {
312 if ( (v
->prop
[i
].value
[j
] < 32) || (v
->prop
[i
].value
[j
] > 126) ) {
316 strcat(ser
, v
->prop
[i
].name
);
318 strcat(ser
, ";charset=UTF-8");
321 strcat(ser
, v
->prop
[i
].value
);
325 strcat(ser
, "end:vcard\r\n");
333 * Convert FN (Friendly Name) into N (Name)
335 * vname Supplied friendly-name
336 * n Target buffer to store Name
337 * vname_size Size of buffer
339 void vcard_fn_to_n(char *vname
, char *n
, size_t vname_size
) {
342 char middlename
[256];
343 char honorific_prefixes
[256];
344 char honorific_suffixes
[256];
347 safestrncpy(buf
, n
, sizeof buf
);
349 /* Try to intelligently convert the screen name to a
350 * fully expanded vCard name based on the number of
353 safestrncpy(lastname
, "", sizeof lastname
);
354 safestrncpy(firstname
, "", sizeof firstname
);
355 safestrncpy(middlename
, "", sizeof middlename
);
356 safestrncpy(honorific_prefixes
, "", sizeof honorific_prefixes
);
357 safestrncpy(honorific_suffixes
, "", sizeof honorific_suffixes
);
359 /* Honorific suffixes */
360 if (num_tokens(buf
, ',') > 1) {
361 extract_token(honorific_suffixes
, buf
, (num_tokens(buf
, ' ') - 1), ',',
362 sizeof honorific_suffixes
);
363 remove_token(buf
, (num_tokens(buf
, ',') - 1), ',');
366 /* Find a last name */
367 extract_token(lastname
, buf
, (num_tokens(buf
, ' ') - 1), ' ', sizeof lastname
);
368 remove_token(buf
, (num_tokens(buf
, ' ') - 1), ' ');
370 /* Find honorific prefixes */
371 if (num_tokens(buf
, ' ') > 2) {
372 extract_token(honorific_prefixes
, buf
, 0, ' ', sizeof honorific_prefixes
);
373 remove_token(buf
, 0, ' ');
376 /* Find a middle name */
377 if (num_tokens(buf
, ' ') > 1) {
378 extract_token(middlename
, buf
, (num_tokens(buf
, ' ') - 1), ' ', sizeof middlename
);
379 remove_token(buf
, (num_tokens(buf
, ' ') - 1), ' ');
382 /* Anything left is probably the first name */
383 safestrncpy(firstname
, buf
, sizeof firstname
);
386 /* Compose the structured name */
387 snprintf(vname
, vname_size
, "%s;%s;%s;%s;%s", lastname
, firstname
, middlename
,
388 honorific_prefixes
, honorific_suffixes
);