jabberd2  2.6.1
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  if (!strcmp(dkey, "tel")) {
194  nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), "VOICE", pkt->nad->elems[elem].depth + 1);
195  }
196  nad_append_elem(pkt->nad, NAD_ENS(pkt->nad, 2), vskey, pkt->nad->elems[elem].depth + 1);
197  nad_append_cdata(pkt->nad, dval, strlen(dval), pkt->nad->elems[elem].depth + 2);
198  }
199 
200  return pkt;
201 }
202 
204  os_t os;
205  st_ret_t ret;
206  pkt_t result;
207 
208  /* only handle vcard sets and gets that aren't to anyone */
209  if(pkt->to != NULL || (pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD)
210  return mod_PASS;
211 
212  /* get */
213  if(pkt->type == pkt_IQ) {
214  if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->jid)))
216 
217  ret = storage_get(sess->user->sm->st, "vcard", jid_user(sess->jid), NULL, &os);
218  switch(ret) {
219  case st_FAILED:
221 
222  case st_NOTIMPL:
224 
225  case st_NOTFOUND:
226  nad_set_attr(pkt->nad, 1, -1, "type", "result", 6);
227  nad_set_attr(pkt->nad, 1, -1, "to", NULL, 0);
228  nad_set_attr(pkt->nad, 1, -1, "from", NULL, 0);
229 
230  pkt_sess(pkt, sess);
231 
232  return mod_HANDLED;
233 
234  case st_SUCCESS:
235  result = _iq_vcard_to_pkt(sess->user->sm, os);
236  os_free(os);
237 
238  nad_set_attr(result->nad, 1, -1, "type", "result", 6);
239  pkt_id(pkt, result);
240 
241  pkt_sess(result, sess);
242 
243  pkt_free(pkt);
244 
245  return mod_HANDLED;
246  }
247 
248  /* we never get here */
249  pkt_free(pkt);
250  return mod_HANDLED;
251  }
252 
253  os = _iq_vcard_to_object(mi, pkt);
254 
255  if (sm_storage_rate_limit(sess->user->sm, jid_user(sess->jid)))
257 
258  ret = storage_replace(sess->user->sm->st, "vcard", jid_user(sess->jid), NULL, os);
259  os_free(os);
260 
261  switch(ret) {
262  case st_FAILED:
264 
265  case st_NOTIMPL:
267 
268  default:
269  result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL);
270 
271  pkt_id(pkt, result);
272 
273  pkt_sess(result, sess);
274 
275  pkt_free(pkt);
276 
277  return mod_HANDLED;
278  }
279 
280  /* we never get here */
281  pkt_free(pkt);
282  return mod_HANDLED;
283 }
284 
285 /* for the special JID of your jabber server bare domain.
286  * You can have one for every virtual host
287  * you can populate it using your DBMS frontend
288  */
290  os_t os;
291  st_ret_t ret;
292  pkt_t result;
293 
294  /* only handle vcard sets and gets */
295  if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD)
296  return mod_PASS;
297 
298  /* error them if they're trying to do a set */
299  if(pkt->type == pkt_IQ_SET)
300  return -stanza_err_FORBIDDEN;
301 
302  /* a vcard for the server */
303  ret = storage_get(mi->sm->st, "vcard", pkt->to->domain, NULL, &os);
304  switch(ret) {
305  case st_FAILED:
307 
308  case st_NOTIMPL:
310 
311  case st_NOTFOUND:
313 
314  case st_SUCCESS:
315  result = _iq_vcard_to_pkt(mi->sm, os);
316  os_free(os);
317 
318  result->to = jid_dup(pkt->from);
319  result->from = jid_dup(pkt->to);
320 
321  nad_set_attr(result->nad, 1, -1, "to", jid_full(result->to), 0);
322  nad_set_attr(result->nad, 1, -1, "from", jid_full(result->from), 0);
323 
324  pkt_id(pkt, result);
325 
326  pkt_router(result);
327 
328  pkt_free(pkt);
329 
330  return mod_HANDLED;
331  }
332 
333  /* we never get here */
334  pkt_free(pkt);
335  return mod_HANDLED;
336 }
337 
339  os_t os;
340  st_ret_t ret;
341  pkt_t result;
342 
343  /* only handle vcard sets and gets, without resource */
344  if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VCARD || pkt->to->resource[0] !='\0')
345  return mod_PASS;
346 
347  /* error them if they're trying to do a set */
348  if(pkt->type == pkt_IQ_SET)
349  return -stanza_err_FORBIDDEN;
350 
351  if (sm_storage_rate_limit(user->sm, jid_user(pkt->from)))
353 
354  ret = storage_get(user->sm->st, "vcard", jid_user(user->jid), NULL, &os);
355  switch(ret) {
356  case st_FAILED:
358 
359  case st_NOTIMPL:
361 
362  case st_NOTFOUND:
364 
365  case st_SUCCESS:
366  result = _iq_vcard_to_pkt(user->sm, os);
367  os_free(os);
368 
369  result->to = jid_dup(pkt->from);
370  result->from = jid_dup(pkt->to);
371 
372  nad_set_attr(result->nad, 1, -1, "to", jid_full(result->to), 0);
373  nad_set_attr(result->nad, 1, -1, "from", jid_full(result->from), 0);
374 
375  pkt_id(pkt, result);
376 
377  pkt_router(result);
378 
379  pkt_free(pkt);
380 
381  return mod_HANDLED;
382  }
383 
384  /* we never get here */
385  pkt_free(pkt);
386  return mod_HANDLED;
387 }
388 
390  log_debug(ZONE, "deleting vcard for %s", jid_user(jid));
391 
392  storage_delete(mi->sm->st, "vcard", jid_user(jid), NULL);
393 }
394 
395 static void _iq_vcard_free(module_t mod) {
398  free(mod->private);
399 }
400 
401 DLLEXPORT int module_init(mod_instance_t mi, const char *arg) {
402  module_t mod = mi->mod;
403  mod_iq_vcard_t iq_vcard;
404 
405  if(mod->init) return 0;
406 
407  mod->pkt_sm = _iq_vcard_pkt_sm;
408  mod->in_sess = _iq_vcard_in_sess;
411  mod->free = _iq_vcard_free;
412 
415 
416  iq_vcard = (mod_iq_vcard_t) calloc(1, sizeof(struct _mod_iq_vcard_st));
417  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);
418  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);
419  mod->private = iq_vcard;
420 
421  return 0;
422 }
user_t user
user this session belongs to
Definition: sm.h:256
pkt_type_t type
packet type
Definition: sm.h:138
int sm_register_ns(sm_t sm, const char *uri)
register a new global ns
Definition: sm.c:324
jid_t jid
session jid (user@host/res)
Definition: sm.h:258
struct nad_elem_st * elems
Definition: nad.h:95
static sm_t sm
Definition: main.c:33
data structures and prototypes for the session manager
#define NAD_CDATA_L(N, E)
Definition: nad.h:186
void sm_unregister_ns(sm_t sm, const char *uri)
unregister a global ns
Definition: sm.c:338
const char * jid_user(jid_t jid)
expand and return the user
Definition: jid.c:338
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:346
single instance of a module in a chain
Definition: sm.h:446
static pkt_t _iq_vcard_to_pkt(sm_t sm, os_t os)
Definition: mod_iq_vcard.c:154
void nad_set_attr(nad_t nad, unsigned int elem, int ns, const char *name, const char *val, int vallen)
create, update, or zap any matching attr on this elem
Definition: nad.c:407
void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
append new cdata to the last elem
Definition: nad.c:753
config_t config
config context
Definition: sm.h:198
int init
number of times the module intialiser has been called
Definition: sm.h:416
info/query (set)
Definition: sm.h:107
#define stanza_err_FEATURE_NOT_IMPLEMENTED
Definition: util.h:369
int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
bring a new namespace into scope
Definition: nad.c:778
sm_t sm
sm context
Definition: sm.h:237
#define stanza_err_FORBIDDEN
Definition: util.h:370
int j_atoi(const char *a, int def)
Definition: str.c:87
char * resource
Definition: jid.h:46
int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
create a new elem on the list
Definition: nad.c:711
mm_t mm
module manager
Definition: sm.h:404
size_t vcard_max_field_size_default
Definition: mod_iq_vcard.c:36
#define DLLEXPORT
Definition: c2s.h:47
static mod_ret_t _iq_vcard_pkt_sm(mod_instance_t mi, pkt_t pkt)
Definition: mod_iq_vcard.c:289
sm_t sm
sm context
Definition: sm.h:366
mod_ret_t(* in_sess)(mod_instance_t mi, sess_t sess, pkt_t pkt)
in-sess handler
Definition: sm.h:423
unsigned int depth
Definition: nad.h:77
static int ns_VCARD
Definition: mod_iq_vcard.c:31
module_t mod
module that this is an instance of
Definition: sm.h:449
jid_t from
packet addressing (not used for routing)
Definition: sm.h:140
void feature_unregister(sm_t sm, const char *feature)
unregister feature
Definition: feature.c:45
void * private
module private data
Definition: sm.h:418
packet summary data wrapper
Definition: sm.h:129
storage_t st
storage subsystem
Definition: sm.h:211
size_t vcard_max_field_size_avatar
Definition: mod_iq_vcard.c:37
nad_t nad
nad of the entire packet
Definition: sm.h:146
session manager global context
Definition: sm.h:167
#define stanza_err_RESOURCE_CONSTRAINT
Definition: util.h:383
char * domain
Definition: jid.h:45
Definition: jid.h:42
struct _mod_iq_vcard_st * mod_iq_vcard_t
static const char * _iq_vcard_map[]
these are the vcard attributes that gabber supports.
Definition: mod_iq_vcard.c:50
void pkt_id(pkt_t src, pkt_t dest)
convenience - copy the packet id from src to dest
Definition: pkt.c:353
mod_ret_t(* pkt_user)(mod_instance_t mi, user_t user, pkt_t pkt)
pkt-user handler
Definition: sm.h:430
void pkt_router(pkt_t pkt)
Definition: pkt.c:379
void pkt_free(pkt_t pkt)
Definition: pkt.c:315
#define log_debug(...)
Definition: log.h:65
void feature_register(sm_t sm, const char *feature)
register a feature
Definition: feature.c:37
info/query (get)
Definition: sm.h:106
packet was unhandled, should be passed to the next module
Definition: sm.h:340
int ns
iq sub-namespace
Definition: sm.h:142
static void _iq_vcard_user_delete(mod_instance_t mi, jid_t jid)
Definition: mod_iq_vcard.c:389
#define stanza_err_ITEM_NOT_FOUND
Definition: util.h:373
packet was handled (and freed)
Definition: sm.h:339
static mod_ret_t _iq_vcard_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt)
Definition: mod_iq_vcard.c:338
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
static void _iq_vcard_free(module_t mod)
Definition: mod_iq_vcard.c:395
int nad_find_elem(nad_t nad, unsigned int elem, int ns, const char *name, int depth)
locate the next elem at a given depth with an optional matching name
Definition: nad.c:206
void(* user_delete)(mod_instance_t mi, jid_t jid)
user-delete handler
Definition: sm.h:438
mod_ret_t(* pkt_sm)(mod_instance_t mi, pkt_t pkt)
pkt-sm handler
Definition: sm.h:429
static mod_ret_t _iq_vcard_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt)
Definition: mod_iq_vcard.c:203
jid_t to
Definition: sm.h:140
#define NAD_CDATA(N, E)
Definition: nad.h:185
jid_t jid_dup(jid_t jid)
duplicate a jid
Definition: jid.c:372
jid_t jid
user jid (user@host)
Definition: sm.h:239
#define ZONE
Definition: mio_impl.h:76
const char * config_get_one(config_t c, const char *key, int num)
get config value n for this key
Definition: config.c:278
void(* free)(module_t mod)
called when module is freed
Definition: sm.h:442
data for a single module
Definition: sm.h:403
static os_t _iq_vcard_to_object(mod_instance_t mi, pkt_t pkt)
Definition: mod_iq_vcard.c:98
#define uri_VCARD
Definition: mod_iq_vcard.c:30
pkt_t pkt_create(sm_t sm, const char *elem, const char *type, const char *to, const char *from)
Definition: pkt.c:328
mod_ret_t
module return values
Definition: sm.h:338
#define stanza_err_SERVICE_UNAVAILABLE
Definition: util.h:384
sm_t sm
sm context
Definition: sm.h:447
#define stanza_err_INTERNAL_SERVER_ERROR
Definition: util.h:372
void pkt_sess(pkt_t pkt, sess_t sess)
Definition: pkt.c:459
int sm_storage_rate_limit(sm_t sm, const char *owner)
Definition: sm.c:355
#define VCARD_MAX_FIELD_SIZE
Definition: mod_iq_vcard.c:33
#define NAD_ENS(N, E)
Definition: nad.h:196
data for a single user
Definition: sm.h:234
DLLEXPORT int module_init(mod_instance_t mi, const char *arg)
Definition: mod_iq_vcard.c:401