jabberd2  2.2.17
mod_iq_vcard.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sm.h"
22 
30 #define uri_VCARD "vcard-temp"
31 static int ns_VCARD = 0;
32 
33 #define VCARD_MAX_FIELD_SIZE (16384)
34 
35 typedef struct _mod_iq_vcard_st {
39 
50 static const char *_iq_vcard_map[] = {
51  "FN", "fn",
52  "N/FAMILY", "n-family",
53  "N/GIVEN", "n-given",
54  "N/MIDDLE", "n-middle",
55  "N/PREFIX", "n-prefix",
56  "N/SUFFIX", "n-suffix",
57  "NICKNAME", "nickname",
58  "PHOTO/TYPE", "photo-type",
59  "PHOTO/BINVAL", "photo-binval",
60  "PHOTO/EXTVAL", "photo-extval",
61  "BDAY", "bday",
62  "ADR/POBOX", "adr-pobox",
63  "ADR/EXTADD", "adr-extadd",
64  "ADR/STREET", "adr-street",
65  "ADR/LOCALITY", "adr-locality",
66  "ADR/REGION", "adr-region",
67  "ADR/PCODE", "adr-pcode",
68  "ADR/CTRY", "adr-country",
69  "TEL/NUMBER", "tel",
70  "EMAIL/USERID", "email",
71  "JABBERID", "jabberid",
72  "MAILER", "mailer",
73  "TZ", "tz",
74  "GEO/LAT", "geo-lat",
75  "GEO/LON", "geo-lon",
76  "TITLE", "title",
77  "ROLE", "role",
78  "LOGO/TYPE", "logo-type",
79  "LOGO/BINVAL", "logo-binval",
80  "LOGO/EXTVAL", "logo-extval",
81  "AGENT/EXTVAL", "agent-extval",
82  "ORG/ORGNAME", "org-orgname",
83  "ORG/ORGUNIT", "org-orgunit",
84  "NOTE", "note",
85  "REV", "rev",
86  "SORT-STRING", "sort-string",
87  "SOUND/PHONETIC","sound-phonetic",
88  "SOUND/BINVAL", "sound-binval",
89  "SOUND/EXTVAL", "sound-extval",
90  "UID", "uid",
91  "URL", "url",
92  "DESC", "desc",
93  "KEY/TYPE", "key-type",
94  "KEY/CRED", "key-cred",
95  NULL, NULL
96 };
97 
99  os_t os;
100  os_object_t o;
101  int i = 0, elem;
102  char ekey[10], *cdata;
103  const char *vkey, *dkey, *vskey;
104  size_t fieldsize;
105  mod_iq_vcard_t iq_vcard = (mod_iq_vcard_t) mi->mod->private;
106 
107  log_debug(ZONE, "building object from packet");
108 
109  os = os_new();
110  o = os_object_new(os);
111 
112  while(_iq_vcard_map[i] != NULL) {
113  vkey = _iq_vcard_map[i];
114  dkey = _iq_vcard_map[i + 1];
115 
116  i += 2;
117 
118  if( !strcmp(vkey, "PHOTO/BINVAL") ) {
119  fieldsize = iq_vcard->vcard_max_field_size_avatar;
120  } else {
121  fieldsize = iq_vcard->vcard_max_field_size_default;
122  }
123 
124  vskey = strchr(vkey, '/');
125  if(vskey == NULL) {
126  vskey = vkey;
127  elem = 2;
128  } else {
129  sprintf(ekey, "%.*s", (int) (vskey - vkey), vkey);
130  elem = nad_find_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 2), ekey, 1);
131  if(elem < 0)
132  continue;
133  vskey++;
134  }
135 
136  elem = nad_find_elem(pkt->nad, elem, NAD_ENS(pkt->nad, 2), vskey, 1);
137  if(elem < 0 || NAD_CDATA_L(pkt->nad, elem) == 0)
138  continue;
139 
140  log_debug(ZONE, "extracted vcard key %s val '%.*s' for db key %s", vkey, NAD_CDATA_L(pkt->nad, elem), NAD_CDATA(pkt->nad, elem), dkey);
141 
142  cdata = malloc(fieldsize);
143  if(cdata) {
144  snprintf(cdata, fieldsize, "%.*s", NAD_CDATA_L(pkt->nad, elem), NAD_CDATA(pkt->nad, elem));
145  cdata[fieldsize-1] = '\0';
146  os_object_put(o, dkey, cdata, os_type_STRING);
147  free(cdata);
148  }
149  }
150 
151  return os;
152 }
153 
154 static pkt_t _iq_vcard_to_pkt(sm_t sm, os_t os) {
155  pkt_t pkt;
156  os_object_t o;
157  int i = 0, elem;
158  char ekey[10], *dval;
159  const char *vkey, *dkey, *vskey;
160 
161  log_debug(ZONE, "building packet from object");
162 
163  pkt = pkt_create(sm, "iq", "result", NULL, NULL);
164  nad_append_elem(pkt->nad, nad_add_namespace(pkt->nad, uri_VCARD, NULL), "vCard", 2);
165 
166  if(!os_iter_first(os))
167  return pkt;
168  o = os_iter_object(os);
169 
170  while(_iq_vcard_map[i] != NULL) {
171  vkey = _iq_vcard_map[i];
172  dkey = _iq_vcard_map[i + 1];
173 
174  i += 2;
175 
176  if(!os_object_get_str(os, o, dkey, &dval))
177  continue;
178 
179  vskey = strchr(vkey, '/');
180  if(vskey == NULL) {
181  vskey = vkey;
182  elem = 2;
183  } else {
184  sprintf(ekey, "%.*s", (int) (vskey - vkey), vkey);
185  elem = nad_find_elem(pkt->nad, 2, NAD_ENS(pkt->nad, 2), ekey, 1);
186  if(elem < 0)
187  elem = nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), ekey, 3);
188  vskey++;
189  }
190 
191  log_debug(ZONE, "extracted dbkey %s val '%s' for vcard key %s", dkey, dval, vkey);
192 
193  nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), vskey, pkt->nad->elems[elem].depth + 1);
194  nad_append_cdata(pkt->nad, dval, strlen(dval), pkt->nad->elems[elem].depth + 2);
195  }
196 
197  return pkt;
198 }
199 
201  os_t os;
202  st_ret_t ret;
203  pkt_t result;
204 
205  /* only handle vcard sets and gets that aren't to anyone */
206  if(pkt->to != NULL || (pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD)
207  return mod_PASS;
208 
209  /* get */
210  if(pkt->type == pkt_IQ) {
211  if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->jid)))
213 
214  ret = storage_get(sess->user->sm->st, "vcard", jid_user(sess->jid), NULL, &os);
215  switch(ret) {
216  case st_FAILED:
218 
219  case st_NOTIMPL:
221 
222  case st_NOTFOUND:
223  nad_set_attr(pkt->nad, 1, -1, "type", "result", 6);
224  nad_set_attr(pkt->nad, 1, -1, "to", NULL, 0);
225  nad_set_attr(pkt->nad, 1, -1, "from", NULL, 0);
226 
227  pkt_sess(pkt, sess);
228 
229  return mod_HANDLED;
230 
231  case st_SUCCESS:
232  result = _iq_vcard_to_pkt(sess->user->sm, os);
233  os_free(os);
234 
235  nad_set_attr(result->nad, 1, -1, "type", "result", 6);
236  pkt_id(pkt, result);
237 
238  pkt_sess(result, sess);
239 
240  pkt_free(pkt);
241 
242  return mod_HANDLED;
243  }
244 
245  /* we never get here */
246  pkt_free(pkt);
247  return mod_HANDLED;
248  }
249 
250  os = _iq_vcard_to_object(mi, pkt);
251 
252  if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->jid)))
254 
255  ret = storage_replace(sess->user->sm->st, "vcard", jid_user(sess->jid), NULL, os);
256  os_free(os);
257 
258  switch(ret) {
259  case st_FAILED:
261 
262  case st_NOTIMPL:
264 
265  default:
266  result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL);
267 
268  pkt_id(pkt, result);
269 
270  pkt_sess(result, sess);
271 
272  pkt_free(pkt);
273 
274  return mod_HANDLED;
275  }
276 
277  /* we never get here */
278  pkt_free(pkt);
279  return mod_HANDLED;
280 }
281 
282 /* for the special JID of your jabber server bare domain.
283  * You can have one for every virtual host
284  * you can populate it using your DBMS frontend
285  */
287  os_t os;
288  st_ret_t ret;
289  pkt_t result;
290 
291  /* only handle vcard sets and gets */
292  if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD)
293  return mod_PASS;
294 
295  /* error them if they're trying to do a set */
296  if(pkt->type == pkt_IQ_SET)
297  return -stanza_err_FORBIDDEN;
298 
299  /* a vcard for the server */
300  ret = storage_get(mi->sm->st, "vcard", pkt->to->domain, NULL, &os);
301  switch(ret) {
302  case st_FAILED:
304 
305  case st_NOTIMPL:
307 
308  case st_NOTFOUND:
310 
311  case st_SUCCESS:
312  result = _iq_vcard_to_pkt(mi->sm, os);
313  os_free(os);
314 
315  result->to = jid_dup(pkt->from);
316  result->from = jid_dup(pkt->to);
317 
318  nad_set_attr(result->nad, 1, -1, "to", jid_full(result->to), 0);
319  nad_set_attr(result->nad, 1, -1, "from", jid_full(result->from), 0);
320 
321  pkt_id(pkt, result);
322 
323  pkt_router(result);
324 
325  pkt_free(pkt);
326 
327  return mod_HANDLED;
328  }
329 
330  /* we never get here */
331  pkt_free(pkt);
332  return mod_HANDLED;
333 }
334 
336  os_t os;
337  st_ret_t ret;
338  pkt_t result;
339 
340  /* only handle vcard sets and gets, without resource */
341  if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD || pkt->to->resource[0] !='\0')
342  return mod_PASS;
343 
344  /* error them if they're trying to do a set */
345  if(pkt->type == pkt_IQ_SET)
346  return -stanza_err_FORBIDDEN;
347 
348  if (sm_storage_rate_limit(user->sm, pkt->from))
350 
351  ret = storage_get(user->sm->st, "vcard", jid_user(user->jid), NULL, &os);
352  switch(ret) {
353  case st_FAILED:
355 
356  case st_NOTIMPL:
358 
359  case st_NOTFOUND:
361 
362  case st_SUCCESS:
363  result = _iq_vcard_to_pkt(user->sm, os);
364  os_free(os);
365 
366  result->to = jid_dup(pkt->from);
367  result->from = jid_dup(pkt->to);
368 
369  nad_set_attr(result->nad, 1, -1, "to", jid_full(result->to), 0);
370  nad_set_attr(result->nad, 1, -1, "from", jid_full(result->from), 0);
371 
372  pkt_id(pkt, result);
373 
374  pkt_router(result);
375 
376  pkt_free(pkt);
377 
378  return mod_HANDLED;
379  }
380 
381  /* we never get here */
382  pkt_free(pkt);
383  return mod_HANDLED;
384 }
385 
387  log_debug(ZONE, "deleting vcard for %s", jid_user(jid));
388 
389  storage_delete(mi->sm->st, "vcard", jid_user(jid), NULL);
390 }
391 
392 static void _iq_vcard_free(module_t mod) {
395  free(mod->private);
396 }
397 
399  module_t mod = mi->mod;
400  mod_iq_vcard_t iq_vcard;
401 
402  if(mod->init) return 0;
403 
404  mod->pkt_sm = _iq_vcard_pkt_sm;
405  mod->in_sess = _iq_vcard_in_sess;
408  mod->free = _iq_vcard_free;
409 
412 
413  iq_vcard = (mod_iq_vcard_t) calloc(1, sizeof(struct _mod_iq_vcard_st));
414  iq_vcard->vcard_max_field_size_default = j_atoi(config_get_one(mod->mm->sm->config, "user.vcard.max-field-size.default", 0), VCARD_MAX_FIELD_SIZE);
415  iq_vcard->vcard_max_field_size_avatar = j_atoi(config_get_one(mod->mm->sm->config, "user.vcard.max-field-size.avatar", 0), VCARD_MAX_FIELD_SIZE);
416  mod->private = iq_vcard;
417 
418  return 0;
419 }