More sophisticated selection of the user jid in Vcard2Ldap. Minor fixes.
[vcard2ldap.git] / src / v2l_vcard.c
blobca9eef5efc50c0488b4250166d74c04f84bc2619
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 /*! \file v2l_vcard.c
18 \brief XML vCard's to/from LDAP objects translation functions.
19 Implementation
22 #include <stdlib.h>
24 #ifndef _V2L_JABBER2
25 #include <jabberd.h>
26 #else
27 #include "../util/util.h"
28 #include <xmlnode.h>
30 #define log_warn log_debug
31 #define log_error log_debug
33 #endif
34 #include <v2l_vcard.h>
36 #define LOG_ERROR_MEM log_error (ZONE, "Unable to allocate memory")
38 /*! \brief vCard template item.
39 SLL. All of relations tag<->LDAP attr read from template
41 typedef struct v2l_vCardItem
43 char *vcard; /*!< tag name */
44 char *ldap; /*!< LDAP attribute */
45 char *group; /*!< XML parent of the tag */
46 struct v2l_vCardItem *next;
47 } v2l_vCardItem;
49 /*! \brief Gets the translation map.
50 If it is not initilized yet, the function reads the template from disk
51 and sets the map.
52 \param self Module config, if map is initialized can be NULL.
53 \return The map, NULL if error.
55 static v2l_vCardItem *_v2l_vcard_map (v2l_Config *self);
57 /*! \brief Creates the FN tag
58 Creates FN tag from GIVEN and FAMILY tags.
59 \param vcard The vCard.
60 \return 1 if no error, otherwise 0.
62 static int _v2l_create_fn (xmlnode vcard);
64 /*! \brief Sets sn1 and sn2 from sn
65 Hack. IrisPerson has two surnames: first surname and mother's maiden name.
66 This function splits sn in two. Should be called when the list of request
67 are complete and before program excutes them.
68 \param req The SLL of LDAP requests.
70 static v2l_LdapRequest *_v2l_set_sn12 (v2l_LdapRequest *req);
72 /*! \brief Map function from LDAP to XML vCard
73 \param item Info about the tag (name, parent group and attribute associated)
74 \param vals array of values for the attribe.
75 \param[in,out] res The vCard, output is appended here.
76 \return res + new tag or res if error.
78 static xmlnode _v2l_ldap2vcard_generic (v2l_vCardItem *item, const char **vals,
79 xmlnode res);
81 /*! \brief Function for maps PHOTO tag.
82 Hack. InetOrgPerson has a jpegphoto attribute so PHOTO/MIMETYPE tag can be
83 only "image/jpeg"
84 \warning The module doesn't support storing avatars in another format (png)
86 static xmlnode _v2l_ldap2vcard_photo (v2l_vCardItem *item, const char **vals,
87 xmlnode res);
89 /*! \brief Map function from XML Vcard to LDAP
90 \param item Info about the tag (name, parent group and attribute associated)
91 \param data Thhe vCard.
92 \param[in,out] req List of requests, the new request is appended here.
93 \return req + new request or req if error.
95 static v2l_LdapRequest *_v2l_vcard2ldap_generic (v2l_vCardItem *item,
96 xmlnode data, v2l_LdapRequest *req);
98 /*! \brief Finds tag linked to attr
99 Parses the translation map since 'item' node.
100 \param item Where the search starts.
101 \param attr The attribute;
102 \return node with tag<->attr association or NULL if error or not found.
104 static v2l_vCardItem *_v2l_vcard_find_attr (v2l_vCardItem *item,
105 const char *attr);
107 /*! \brief Is LDAP object attribute linked to any tag?
108 Utility function.
109 \param attr The attribute.
110 \param[out] shrdata Contents the address of any map's node. NULL if no match
111 \return true if attr is linked to any tag, otherwise false
113 static int _v2l_vcard_attr_match (const char *attr, void **shrdata);
115 /*! \brief Function applied to all attrs.
116 Utility function, walker function.
117 \param attr The attribute.
118 \param vals Values of attribute.
119 \param pointer Deferenced pointer to vCard.
120 \param shrdata Data shared with the match function.
122 static void _v2l_vcard_attr_value (const char *attr, const char **vals,
123 void *pointer, void *shrdata);
125 #if 0
126 static v2l_vCardItem *
127 _v2l_vcard_find_tag (v2l_vCardItem *item, char *tag);
128 #endif
130 /*! List of all XML vCard tags supported */
131 static const char *_V2L_MAP_VCARD [] = {
132 "FN",
133 "NICKNAME",
134 "URL",
135 "TEL/NUMBER",
136 "EMAIL/USERID",
137 "TITLE",
138 "ROLE",
139 "BDAY",
140 "DESC",
141 "N/FAMILY",
142 "N/GIVEN",
143 "N/MIDDLE",
144 "N/PREFIX",
145 "N/SUFFIX",
146 "ADR/STREET",
147 "ADR/POBOX",
148 "ADR/EXTADD",
149 "ADR/LOCALITY",
150 "ADR/REGION",
151 "ADR/PCODE",
152 "ADR/CTRY",
153 "ORG/ORGNAME",
154 "ORG/ORGUNIT",
156 "TZ",
157 "GEO/LAT",
158 "GEO/LON",
159 "AGENT/EXTVAL",
160 "NOTE",
161 "REV",
162 "SORT-STRING",
164 "KEY/TYPE",
165 "KEY/CRED",
167 "PHOTO/TYPE",
168 "PHOTO/BINVAL",
169 "PHOTO/EXTVAL",
171 "LOGO/TYPE",
172 "LOGO/BINVAL",
173 "LOGO/EXTVAL",
175 "SOUND/PHONETIC",
176 "SOUND/BINVAL",
177 "SOUND/EXTVAL",
179 NULL
182 /* public api */
184 xmlnode
185 v2l_vcard_get (v2l_Config *self, v2l_LdapConn *curr_conn)
187 xmlnode vcard;
188 v2l_LdapEvt *evt_res;
190 if (_v2l_vcard_map (self) == NULL)
192 log_error (ZONE, "Unreadable/malformed vCard template!");
193 return NULL;
196 /* get user info from LDAP */
197 evt_res = v2l_ldap_get_entry (self, curr_conn);
199 if (evt_res == NULL)
201 return NULL;
204 /* prepare the XML result */
205 vcard = xmlnode_new_tag ("vCard");
206 xmlnode_put_attrib (vcard, "xmlns", "vcard-temp");
208 v2l_ldap_for_all_attrs (_v2l_vcard_attr_value, _v2l_vcard_attr_match, vcard,
209 evt_res);
211 free (evt_res);
212 _v2l_create_fn (vcard);
214 return vcard;
218 v2l_vcard_set (v2l_Config *self, v2l_LdapConn *curr_conn, xmlnode data)
220 xmlnode node;
221 v2l_LdapRequest *ldap_req = NULL;
222 v2l_vCardItem *item;
224 if (data == NULL)
226 log_warn (ZONE, "vCard data is NULL?");
227 return 0;
230 item = _v2l_vcard_map (self);
232 if (item == NULL)
234 log_error (ZONE, "Unreadable/Malformed vCard template!");
235 return 0;
240 if (strcmp (item->vcard, "FN") == 0) /* FIXME: ugly */
242 goto is_fn;
245 if (item->group != NULL)
247 char tag[30];
249 sprintf (tag, "%s/%s", item->group, item->vcard);
250 node = xmlnode_get_tag (data, tag);
252 else
254 node = xmlnode_get_tag (data, item->vcard);
257 if (node != NULL)
259 ldap_req = _v2l_vcard2ldap_generic (item, node, ldap_req);
261 is_fn:
262 item = item->next;
263 } while (item != NULL);
265 ldap_req = _v2l_set_sn12 (ldap_req);
267 return v2l_request_record (self, curr_conn, ldap_req);
270 /* public api ends here */
272 static v2l_vCardItem *
273 _v2l_vcard_map (v2l_Config *self)
275 static v2l_vCardItem *_V2L_TPL = NULL;
276 xmlnode tpl, tag;
277 char **stag, *tmp, group[10];
278 v2l_vCardItem *item;
280 if (_V2L_TPL == NULL && self != NULL && self->confpath != NULL)
282 tpl = xmlnode_file (self->confpath);
284 if (tpl == NULL)
286 return NULL;
289 for (stag = (char **) _V2L_MAP_VCARD; *stag != NULL; stag++)
291 tmp = strchr (*stag, '/');
293 if (tmp == NULL)
295 group[0] = 0;
296 tmp = *stag;
298 else
300 sprintf (group, "%.*s", tmp - *stag, *stag);
301 tmp++;
304 tag = xmlnode_get_tag (tpl, *stag);
306 if (xmlnode_get_data (tag) != NULL)
308 int ntags = 0;
309 char find_attr[30];
313 v2l_vCardItem *ptr;
315 ptr = (v2l_vCardItem *) pmalloc (self->poolref,
316 sizeof (v2l_vCardItem));
318 ptr->vcard = tmp;
319 ptr->ldap = pstrdup (self->poolref, xmlnode_get_data (tag));
320 ptr->next = NULL;
321 ptr->group = group[0] == 0 ? NULL :
322 pstrdup (self->poolref, group);
324 if (_V2L_TPL == NULL)
326 _V2L_TPL = ptr;
327 item = ptr;
329 else
331 item->next = ptr;
332 item = item->next;
335 sprintf (find_attr, "%s?v2ln=%d", *stag, ++ntags);
336 tag = xmlnode_get_tag (tpl, find_attr);
337 } while (tag && xmlnode_get_data (tag) != NULL && ntags < 10);
338 }/* xmlnode_get_data (tag) != NULL */
339 } /* for loop, all tags in template */
341 xmlnode_free (tpl);
344 return _V2L_TPL;
347 #if 0
348 static v2l_vCardItem *
349 _v2l_vcard_find_tag (v2l_vCardItem *item, char *tag)
351 v2l_vCardItem *res = NULL;
353 while (item != NULL)
355 if (strcmp (item->vcard, tag) == 0)
357 res = item;
358 break;
361 item = item->next;
364 return res;
366 #endif
368 static v2l_vCardItem *
369 _v2l_vcard_find_attr (v2l_vCardItem *item, const char *attr)
371 v2l_vCardItem *res = NULL;
373 while (item != NULL)
375 if (strcmp (item->ldap, attr) == 0)
377 res = item;
378 break;
381 item = item->next;
384 return res;
387 static int
388 _v2l_vcard_attr_match (const char *attr, void **shrdata)
390 *shrdata = _v2l_vcard_find_attr (_v2l_vcard_map (NULL), attr);
392 return *shrdata != NULL;
395 static void
396 _v2l_vcard_attr_value (const char *attr, const char **vals, void *pointer,
397 void *shrdata)
399 xmlnode vcard;
400 v2l_vCardItem *match;
402 vcard = (xmlnode) pointer;
403 match = (v2l_vCardItem *) shrdata;
405 if (vals != NULL)
407 /* FIXME: ugly */
408 if (match->group != NULL && (strcmp (match->group, "PHOTO") == 0))
410 _v2l_ldap2vcard_photo (match, vals, vcard);
412 else
414 _v2l_ldap2vcard_generic (match, vals, vcard);
419 static int
420 _v2l_create_fn (xmlnode vcard)
422 xmlnode n, fn;
423 char *family, *given, *fn_str;
424 int len;
426 fn = xmlnode_insert_tag (vcard, "FN");
427 n = xmlnode_get_tag (vcard, "N");
428 family = xmlnode_get_tag_data (n, "FAMILY");
429 given = xmlnode_get_tag_data (n, "GIVEN");
431 len = 0;
432 len += (family != NULL) ? strlen (family) : 0;
433 len += (given != NULL) ? strlen (given) : 0;
435 if (len == 0)
437 log_debug (ZONE, "<fn><n>...</n></fn> is empty, returning");
438 return 1;
441 fn_str = (char *) malloc (sizeof (char) * (len + 2));
443 if (fn_str == NULL)
445 LOG_ERROR_MEM;
446 return 0;
449 fn_str[0] = 0;
451 if (family != NULL)
453 sprintf (fn_str, "%s ", family);
456 if (given != NULL)
458 strcat (fn_str, given);
461 xmlnode_insert_cdata (fn, fn_str, len + 1);
462 free (fn_str);
464 return 1;
467 /* LDAP -> vCard */
469 static xmlnode
470 _v2l_ldap2vcard_generic (v2l_vCardItem *item, const char **vals, xmlnode res)
472 xmlnode node;
474 if (item->group != NULL)
476 node = xmlnode_get_tag (res, item->group);
478 if (node == NULL)
480 node = xmlnode_insert_tag (res, item->group);
483 else
485 node = res;
488 node = xmlnode_insert_tag (node, item->vcard);
489 xmlnode_insert_cdata (node, vals[0], strlen (vals[0]));
491 return res;
494 static xmlnode
495 _v2l_ldap2vcard_photo (v2l_vCardItem *item, const char **vals, xmlnode res)
497 xmlnode mimetype, photo;
499 res = _v2l_ldap2vcard_generic (item, vals, res);
501 /* FIXME: mimetype is hardcoded */
502 photo = xmlnode_get_tag (res, "PHOTO");
503 mimetype = xmlnode_insert_tag (photo, "TYPE");
504 xmlnode_insert_cdata (mimetype, "image/jpeg", sizeof ("image/jpeg"));
506 return res;
509 /* vCard -> LDAP */
511 static v2l_LdapRequest *
512 _v2l_vcard2ldap_generic (v2l_vCardItem *item, xmlnode data,
513 v2l_LdapRequest *req)
515 const char *str;
517 str = xmlnode_get_data (data);
519 return str == NULL ? req : v2l_add_attr_str (req, item->ldap, str);
522 static v2l_LdapRequest *
523 _v2l_set_sn12 (v2l_LdapRequest *req)
525 if (req != NULL)
527 v2l_LdapRequest *ptr;
528 char *sn;
530 for (ptr = req, sn = NULL; ptr != NULL; ptr = ptr->next)
532 if (strcmp (ptr->attr->mod_type, "sn") == 0)
534 sn = ptr->attr->mod_values[0];
535 break;
539 if (sn != NULL)
541 char *sit, *sn1, *sn2;
543 for (sit = sn; *sit != ' ' && *sit != 0; sit++);
545 sn1 = (char *) malloc (sizeof (char) * (sit - sn + 1));
547 if (sn1 == NULL)
549 return req;
552 strncpy (sn1, sn, sizeof (char) * (sit - sn));
553 sn1[sit - sn] = 0;
554 ptr = v2l_add_attr_str (req, "sn1", sn1);
555 free (sn1);
557 if (ptr == NULL)
559 return req;
562 req = ptr;
564 if (sit - sn != strlen (sn))
566 sn2 = (char *) malloc (strlen (sit) + 1);
568 if (sn2 == NULL)
570 LOG_ERROR_MEM;
571 return req;
574 strcpy (sn2, sit);
575 ptr = v2l_add_attr_str (req, "sn2", sn2);
576 free (sn2);
578 if (ptr == NULL)
580 return req;
583 req = ptr;
585 } /* sn != NULL */
586 } /* req != NULL */
588 return req;