Better XML vCard compliance. (Almost) Complete Jabberd2 support. A lot of
[vcard2ldap.git] / src / v2l_vcard.c
blob4b6fafe64f51f3cd5dcfb43675260b5d9db9b8b6
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #include <stdlib.h>
18 #include <stdio.h>
19 #ifndef _V2L_JABBER2
20 #include <jabberd.h>
21 #else
22 #include "../util/util.h"
23 #include <xmlnode.h>
25 #define log_warn log_debug
26 #define log_error log_debug
28 #endif
29 #include <v2l_conn.h>
30 #include <v2l_config.h>
31 #include <v2l_vcard.h>
33 #define LOG_ERROR_MEM log_error(ZONE, "Unable to allocate memory")
35 /* create the <FN> tag */
36 static int _v2l_create_fn (xmlnode vcard);
38 /* mapping functions from LDAP to XML vCard */
39 static xmlnode _v2l_ldap2vcard_generic (char *attr, char **vals, xmlnode res,
40 const char *tag);
41 static xmlnode _v2l_ldap2vcard_generic_group (char *attr, char **vals,
42 xmlnode res, const char *gtag, const char **tags);
44 static xmlnode _v2l_ldap2vcard_n (char *attr, char **vals, xmlnode res);
45 static xmlnode _v2l_ldap2vcard_nickname (char *attr, char **vals, xmlnode res);
46 static xmlnode _v2l_ldap2vcard_url (char *attr, char **vals, xmlnode res);
47 static xmlnode _v2l_ldap2vcard_org (char *attr, char **vals, xmlnode res);
48 static xmlnode _v2l_ldap2vcard_title (char *attr, char **vals, xmlnode res);
49 static xmlnode _v2l_ldap2vcard_tel (char *attr, char **vals, xmlnode res);
50 static xmlnode _v2l_ldap2vcard_adr (char *attr, char **vals, xmlnode res);
51 static xmlnode _v2l_ldap2vcard_email (char *attr, char **vals, xmlnode res);
53 /* mapping functions from XML Vcard to LDAP */
54 static v2l_LdapRequest *_v2l_vcard2ldap_generic (v2l_LdapRequest *req,
55 xmlnode data, const char **tags);
57 static v2l_LdapRequest *_v2l_vcard2ldap_n (v2l_LdapRequest *req, xmlnode data);
58 static v2l_LdapRequest *_v2l_vcard2ldap_nickname (v2l_LdapRequest *req,
59 xmlnode data);
60 static v2l_LdapRequest *_v2l_vcard2ldap_url (v2l_LdapRequest *req,
61 xmlnode data);
62 static v2l_LdapRequest *_v2l_vcard2ldap_org (v2l_LdapRequest *req,
63 xmlnode data);
64 static v2l_LdapRequest *_v2l_vcard2ldap_title (v2l_LdapRequest *req,
65 xmlnode data);
66 static v2l_LdapRequest *_v2l_vcard2ldap_tel (v2l_LdapRequest *req,
67 xmlnode data);
68 static v2l_LdapRequest *_v2l_vcard2ldap_adr (v2l_LdapRequest *req,
69 xmlnode data);
70 static v2l_LdapRequest *_v2l_vcard2ldap_email (v2l_LdapRequest *req,
71 xmlnode data);
73 /******* Translation maps */
74 static const char const *V2L_N_TAGS[2][5] = {
75 {"N"},
76 {"FAMILY", "sn", "GIVEN", "givenName", NULL}
78 static const char *V2L_NICKNAME_TAGS[2][3] = {
79 {"NICKNAME"},
80 {"NICKNAME", "displayName", NULL}
82 static const char *V2L_URL_TAGS[2][3] = {
83 {"URL"},
84 {"URL", "labeledURI", NULL}
86 static const char *V2L_ORG_TAGS[2][5] = {
87 {"ORG"},
88 {"ORGNAME", "o", "ORGUNIT", "ou", NULL}
90 static const char *V2L_TITLE_TAGS[2][5] = {
91 {"TITLE"},
92 {"TITLE", "irisPersonalTitle", "TITLE", "title", NULL}
94 static const char *V2L_TEL_TAGS[2][5] = {
95 {"TEL"},
96 {"NUMBER", "telephoneNumber", NULL}
98 static const char *V2L_ADR_TAGS[2][11] = {
99 {"ADR"},
100 {"STREET", "street", "LOCALITY", "l", "REGION", "st", "PCODE", "postalCode",
101 /* "COUNTRY", "c", */ NULL}
103 static const char *V2L_EMAIL_TAGS[2][9] = {
104 {"EMAIL"},
105 {"USERID", "irisMailMainAddress", "USERID", "mail", NULL}
109 static v2l_Ldap2Vcard static_map_ldap[] = {
110 {"givenName", _v2l_ldap2vcard_n},
111 {"sn", _v2l_ldap2vcard_n},
112 {"displayName", _v2l_ldap2vcard_nickname},
113 {"labeledURI", _v2l_ldap2vcard_url},
114 {"o", _v2l_ldap2vcard_org},
115 {"ou", _v2l_ldap2vcard_org},
116 {"title", _v2l_ldap2vcard_title},
117 {"telephoneNumber", _v2l_ldap2vcard_tel},
118 {"street", _v2l_ldap2vcard_adr},
119 {"l", _v2l_ldap2vcard_adr},
120 {"st", _v2l_ldap2vcard_adr},
121 {"postalCode", _v2l_ldap2vcard_adr},
122 /* {"c", _v2l_ldap2vcard_adr}, */
123 {"mail", _v2l_ldap2vcard_email},
124 {NULL, NULL}
127 /* <FN> is not handled but created in v2l_create_fn() */
128 static v2l_Vcard2Ldap static_map_vcard[] = {
129 {"N", _v2l_vcard2ldap_n},
130 {"NICKNAME", _v2l_vcard2ldap_nickname},
131 {"URL", _v2l_vcard2ldap_url},
132 {"ORG", _v2l_vcard2ldap_org},
133 {"TITLE", _v2l_vcard2ldap_title},
134 {"TEL", _v2l_vcard2ldap_tel},
135 {"ADR", _v2l_vcard2ldap_adr},
136 {"EMAIL", _v2l_vcard2ldap_email},
137 {NULL, NULL}
140 /* public api */
141 xmlnode
142 v2l_vcard_get (v2l_Config *self, v2l_LdapConn *curr_conn)
144 LDAPMessage *current_result;
145 BerElement *ber;
146 v2l_Ldap2Vcard *handled;
147 xmlnode vcard;
148 char *current_attr;
149 int rc;
151 /* LDAP request is asynchronous */
152 v2l_LdapEvt *evt_res;
154 evt_res = (v2l_LdapEvt *) malloc (sizeof (v2l_LdapEvt));
156 if (evt_res == NULL)
158 LOG_ERROR_MEM;
159 return NULL;
162 evt_res->ld = curr_conn->ld;
164 /* get user info from LDAP */
165 rc = v2l_ldap_search (curr_conn->entry, self->suffix, NULL, 1, evt_res);
167 if (rc != LDAP_SUCCESS)
169 log_error(ZONE, "LDAP error attempting to retrieve user info: %s",
170 ldap_err2string (rc));
171 free (evt_res);
172 return NULL;
175 v2l_ldap_sync(evt_res);
177 if (ldap_count_entries (evt_res->ld, evt_res->result) != 1)
179 log_warn (ZONE,
180 "Multiple users with the same dn?, vCard is not retrieved");
181 free (evt_res);
182 return NULL;
185 /* prepare the XML result */
186 vcard = xmlnode_new_tag ("vCard");
187 xmlnode_put_attrib (vcard, "xmlns", "vcard-temp");
189 current_result = ldap_first_entry (evt_res->ld, evt_res->result);
190 /* step through each attribute in objectclass */
192 for (current_attr =
193 ldap_first_attribute (evt_res->ld, current_result, &ber);
194 current_attr != NULL;
195 current_attr = ldap_next_attribute (evt_res->ld, current_result, ber))
197 /* and look for its associated callback */
198 for (handled = static_map_ldap; handled->attrname != NULL; handled++)
200 if (strcmp (handled->attrname, current_attr) == 0)
202 char **vals = ldap_get_values (evt_res->ld, current_result,
203 current_attr);
205 vcard = (handled->set) (current_attr, vals, vcard);
206 ldap_value_free (vals);
207 break;
211 ldap_memfree (current_attr);
214 if (ber != NULL)
216 ber_free (ber, 0);
219 /* don't forget to free the next attribute */
220 ldap_memfree (current_attr);
221 ldap_msgfree (evt_res->result);
222 free (evt_res);
224 _v2l_create_fn (vcard);
225 log_debug (ZONE, "vCard read from LDAP: %s", xmlnode2str (vcard));
227 return vcard;
231 v2l_vcard_set (v2l_Config *self, v2l_LdapConn *curr_conn, xmlnode data)
233 xmlnode node;
234 v2l_LdapRequest *ldap_req = NULL;
235 v2l_Vcard2Ldap *handled;
237 if (data == NULL)
239 log_warn (ZONE, "vCard data is NULL?");
240 return 0;
243 for (handled = static_map_vcard; handled->tagname != NULL; handled++)
245 node = xmlnode_get_tag (data, handled->tagname);
247 if (node != NULL)
249 ldap_req = (handled->set) (ldap_req, node);
253 return v2l_request_record (self, curr_conn, ldap_req);
256 /* public api ends here */
258 static int
259 _v2l_create_fn (xmlnode vcard)
261 xmlnode n, fn;
262 char *family, *given, *fn_str;
264 fn = xmlnode_new_tag ("FN");
265 n = xmlnode_get_tag (vcard, V2L_N_TAGS[0][0]);
266 family = xmlnode_get_tag_data (n, V2L_N_TAGS[1][0]);
267 given = xmlnode_get_tag_data (n, V2L_N_TAGS[1][2]);
269 if ((family == NULL) && (given == NULL))
271 log_debug (ZONE, "<fn><n>...</n></fn> is empty, returning");
272 xmlnode_insert_tag_node (vcard, fn);
273 return 1;
276 if (family != NULL)
278 fn_str = (char *) malloc (sizeof (char) * (strlen (family) + 2));
279 sprintf (fn_str, "%s ", family);
281 if (given != NULL)
283 fn_str = (char *) realloc (fn_str,
284 sizeof (char) * (strlen (family) +
285 2 + strlen (given)));
286 strcat (fn_str, given);
289 xmlnode_insert_cdata (fn, fn_str, strlen (fn_str));
290 xmlnode_insert_tag_node (vcard, fn);
291 free (fn_str);
293 return 1;
296 /* LDAP -> vCard */
298 static xmlnode
299 _v2l_ldap2vcard_generic (char *attr, char **vals, xmlnode res, const char *tag)
301 xmlnode node;
303 node = xmlnode_new_tag (tag);
304 xmlnode_insert_cdata (node, vals[0], strlen (vals[0]));
306 if (res != NULL)
308 xmlnode_insert_tag_node (res, node);
309 return res;
311 else
313 return node;
317 static xmlnode
318 _v2l_ldap2vcard_generic_group (char *attr, char **vals, xmlnode res,
319 const char *gtag, const char **tags)
321 xmlnode node;
322 int first;
323 const char **handled, **pvals;
325 first = 0;
327 node = xmlnode_get_tag (res, gtag);
329 if (node == NULL)
331 node = xmlnode_new_tag (gtag);
332 first = 1;
335 for (handled = tags, pvals = (const char **) vals;
336 *handled != NULL && *pvals != NULL; handled += 2)
339 if (strcmp (attr, *(handled + 1)) == 0)
341 xmlnode tmp = xmlnode_new_tag (*handled);
342 xmlnode_insert_cdata (tmp, *pvals, strlen (*pvals));
343 xmlnode_insert_tag_node (node, tmp);
344 pvals++;
348 if (first)
350 xmlnode_insert_tag_node (res, node);
353 return res;
356 static xmlnode
357 _v2l_ldap2vcard_n (char *attr, char **vals, xmlnode res)
359 return _v2l_ldap2vcard_generic_group (attr, vals, res, V2L_N_TAGS[0][0],
360 V2L_N_TAGS[1]);
363 static xmlnode
364 _v2l_ldap2vcard_nickname (char *attr, char **vals, xmlnode res)
366 return _v2l_ldap2vcard_generic (attr, vals, res, V2L_NICKNAME_TAGS[0][0]);
369 static xmlnode
370 _v2l_ldap2vcard_url (char *attr, char **vals, xmlnode res)
372 return _v2l_ldap2vcard_generic (attr, vals, res, V2L_URL_TAGS[0][0]);
375 static xmlnode
376 _v2l_ldap2vcard_org (char *attr, char **vals, xmlnode res)
378 return _v2l_ldap2vcard_generic_group (attr, vals, res,
379 V2L_ORG_TAGS[0][0], V2L_ORG_TAGS[1]);
382 static xmlnode
383 _v2l_ldap2vcard_title (char *attr, char **vals, xmlnode res)
385 return _v2l_ldap2vcard_generic (attr, vals, res, V2L_TITLE_TAGS[0][0]);
388 static xmlnode
389 _v2l_ldap2vcard_tel (char *attr, char **vals, xmlnode res)
391 return _v2l_ldap2vcard_generic_group (attr, vals, res,
392 V2L_TEL_TAGS[0][0], V2L_TEL_TAGS[1]);
395 static xmlnode
396 _v2l_ldap2vcard_adr (char *attr, char **vals, xmlnode res)
398 return _v2l_ldap2vcard_generic_group (attr, vals, res,
399 V2L_ADR_TAGS[0][0], V2L_ADR_TAGS[1]);
402 static xmlnode
403 _v2l_ldap2vcard_email (char *attr, char **vals, xmlnode res)
405 return _v2l_ldap2vcard_generic_group (attr, vals, res,
406 V2L_EMAIL_TAGS[0][0], V2L_EMAIL_TAGS[1]);
409 /* vCard -> LDAP */
411 static v2l_LdapRequest *
412 _v2l_vcard2ldap_generic (v2l_LdapRequest *req, xmlnode data, const char **tags)
414 xmlnode node;
415 const char **handled, *str;
417 for (handled = tags; *handled != NULL; handled += 2)
419 node = xmlnode_get_tag (data, *handled);
420 str = xmlnode_get_data(node);
422 if (node == NULL || str == NULL)
424 for (node = xmlnode_get_firstchild (data); node != NULL;
425 node = xmlnode_get_nextsibling (node))
427 str = xmlnode_get_data (node);
429 if (str != NULL && str[0] != '\n')
431 break;
435 if (node == NULL)
437 continue;
441 req = v2l_add_attr_str (req, *(char **) (handled + 1), str);
444 return req;
447 static v2l_LdapRequest *
448 _v2l_vcard2ldap_n (v2l_LdapRequest * req, xmlnode data)
450 req = _v2l_vcard2ldap_generic (req, data, V2L_N_TAGS[1]);
452 if (req != NULL)
454 v2l_LdapRequest *ptr;
455 char *sn;
457 for (ptr = req, sn = NULL; ptr != NULL; ptr = ptr->next)
459 if (strcmp (ptr->attr->mod_type, "sn") == 0)
461 sn = ptr->attr->mod_values[0];
462 break;
466 if (sn != NULL)
468 char *sit, *sn1, *sn2;
470 for (sit = sn; *sit != ' ' && *sit != 0; sit++);
472 sn1 = (char *) malloc (sizeof (char) * (sit - sn + 1));
474 if (sn1 == NULL)
476 return req;
479 strncpy (sn1, sn, sizeof (char) * (sit - sn));
480 sn1[sit - sn] = 0;
481 ptr = v2l_add_attr_str (req, "sn1", sn1);
482 free (sn1);
484 if (ptr == NULL)
486 return req;
489 req = ptr;
491 if (sit - sn != strlen (sn))
493 sn2 = (char *) malloc (sizeof (char) * (strlen (sit) + 1));
495 if (sn2 == NULL)
497 LOG_ERROR_MEM;
498 return req;
501 strcpy (sn2, sit);
502 ptr = v2l_add_attr_str (req, "sn2", sn2);
503 free (sn2);
505 if (ptr == NULL)
507 return req;
510 req = ptr;
512 } /* sn != NULL */
513 } /* req != NULL */
515 return req;
518 static v2l_LdapRequest *
519 _v2l_vcard2ldap_nickname (v2l_LdapRequest * req, xmlnode data)
521 return _v2l_vcard2ldap_generic (req, data, V2L_NICKNAME_TAGS[1]);
524 static v2l_LdapRequest *
525 _v2l_vcard2ldap_url (v2l_LdapRequest * req, xmlnode data)
527 return _v2l_vcard2ldap_generic (req, data, V2L_URL_TAGS[1]);
530 static v2l_LdapRequest *
531 _v2l_vcard2ldap_org (v2l_LdapRequest * req, xmlnode data)
533 return _v2l_vcard2ldap_generic (req, data, V2L_ORG_TAGS[1]);
536 static v2l_LdapRequest *
537 _v2l_vcard2ldap_title (v2l_LdapRequest * req, xmlnode data)
539 return _v2l_vcard2ldap_generic (req, data, V2L_TITLE_TAGS[1]);
542 static v2l_LdapRequest *
543 _v2l_vcard2ldap_tel (v2l_LdapRequest * req, xmlnode data)
545 return _v2l_vcard2ldap_generic (req, data, V2L_TEL_TAGS[1]);
548 static v2l_LdapRequest *
549 _v2l_vcard2ldap_adr (v2l_LdapRequest * req, xmlnode data)
551 return _v2l_vcard2ldap_generic (req, data, V2L_ADR_TAGS[1]);
554 static v2l_LdapRequest *
555 _v2l_vcard2ldap_email (v2l_LdapRequest * req, xmlnode data)
557 return _v2l_vcard2ldap_generic (req, data, V2L_EMAIL_TAGS[1]);