jabberd2  2.3.6
mod_disco.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 ACTIVE_SESSIONS_NAME "Active sessions"
31 
33 typedef struct service_st *service_t;
34 struct service_st {
36 
37  char name[257];
38 
39  char category[257];
40  char type[257];
41 
43 };
44 
46 typedef struct disco_st *disco_t;
47 struct disco_st {
49  const char *category;
50  const char *type;
51  const char *name;
52 
54  int agents;
55 
59 
62 
67 };
68 
69 /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */
70 union xhashv
71 {
72  void **val;
73  service_t *svc_val;
75  const char **char_val;
76 };
77 
79 static void _disco_unify_walker(const char *key, int keylen, void *val, void *arg) {
80  service_t svc = (service_t) val;
81  xht dest = (xht) arg;
82 
83  /* if its already there, skip this one */
84  if(xhash_get(dest, jid_full(svc->jid)) != NULL)
85  return;
86 
87  log_debug(ZONE, "unify: %s", jid_full(svc->jid));
88 
89  xhash_put(dest, jid_full(svc->jid), (void *) svc);
90 }
91 
93 static void _disco_unify_lists(disco_t d) {
94  log_debug(ZONE, "unifying lists");
95 
96  if(d->un != NULL)
97  xhash_free(d->un);
98 
99  d->un = xhash_new(101);
100 
101  /* dynamic overrieds static */
102  xhash_walk(d->dyn, _disco_unify_walker, (void *) d->un);
103  xhash_walk(d->stat, _disco_unify_walker, (void *) d->un);
104 }
105 
107 static pkt_t _disco_items_result(module_t mod, disco_t d) {
108  pkt_t pkt;
109  int ns;
110  service_t svc;
111  union xhashv xhv;
112 
113  pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL);
114  ns = nad_add_namespace(pkt->nad, uri_DISCO_ITEMS, NULL);
115  nad_append_elem(pkt->nad, ns, "query", 2);
116 
117  if(xhash_iter_first(d->un))
118  do {
119  xhv.svc_val = &svc;
120  xhash_iter_get(d->un, NULL, NULL, xhv.val);
121 
122  nad_append_elem(pkt->nad, ns, "item", 3);
123  nad_append_attr(pkt->nad, -1, "jid", jid_full(svc->jid));
124 
125  if(svc->name[0] != '\0')
126  nad_append_attr(pkt->nad, -1, "name", svc->name);
127  } while(xhash_iter_next(d->un));
128 
129  return pkt;
130 }
131 
133 static pkt_t _disco_info_result(module_t mod, disco_t d) {
134  pkt_t pkt;
135  int el, ns;
136  const char *key;
137  int keylen;
138 
139  pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL);
140  ns = nad_add_namespace(pkt->nad, uri_DISCO_INFO, NULL);
141  nad_append_elem(pkt->nad, ns, "query", 2);
142 
143  /* identity */
144  nad_append_elem(pkt->nad, ns, "identity", 3);
145  nad_append_attr(pkt->nad, -1, "category", d->category);
146  nad_append_attr(pkt->nad, -1, "type", d->type);
147  nad_append_attr(pkt->nad, -1, "name", d->name);
148 
149  /* fill in our features */
150  if(xhash_iter_first(mod->mm->sm->features))
151  do {
152  xhash_iter_get(mod->mm->sm->features, &key, &keylen, NULL);
153 
154  el = nad_append_elem(pkt->nad, ns, "feature", 3);
155  nad_set_attr(pkt->nad, el, -1, "var", (char *) key, keylen);
156  } while(xhash_iter_next(mod->mm->sm->features));
157 
158  /* put it throuhg disco_extend chain to add
159  * XEP-0128 Service Discovery Extensions */
160  mm_disco_extend(mod->mm, pkt);
161 
162  return pkt;
163 }
164 
166 static pkt_t _disco_agents_result(module_t mod, disco_t d) {
167  pkt_t pkt;
168  int ns;
169  const char *key;
170  int keylen;
171  service_t svc;
172  union xhashv xhv;
173 
174  pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL);
175  ns = nad_add_namespace(pkt->nad, uri_AGENTS, NULL);
176  nad_append_elem(pkt->nad, ns, "query", 2);
177 
178  /* fill in the items */
179  if(xhash_iter_first(d->un))
180  do {
181  xhv.svc_val = &svc;
182  xhash_iter_get(d->un, &key, &keylen, xhv.val);
183 
184  nad_append_elem(pkt->nad, ns, "agent", 3);
185  nad_append_attr(pkt->nad, -1, "jid", jid_full(svc->jid));
186 
187  if(svc->name[0] != '\0') {
188  nad_append_elem(pkt->nad, ns, "name", 4);
189  nad_append_cdata(pkt->nad, svc->name, strlen(svc->name), 5);
190  }
191 
192  nad_append_elem(pkt->nad, ns, "service", 4);
193  nad_append_cdata(pkt->nad, svc->type, strlen(svc->type), 5);
194 
195  /* map features to the old agent flags */
196  if(xhash_get(svc->features, uri_REGISTER) != NULL)
197  nad_append_elem(pkt->nad, ns, "register", 4);
198  if(xhash_get(svc->features, uri_SEARCH) != NULL)
199  nad_append_elem(pkt->nad, ns, "search", 4);
200  if(xhash_get(svc->features, uri_GATEWAY) != NULL)
201  nad_append_elem(pkt->nad, ns, "transport", 4);
202 
203  /* conference gets special treatment */
204  if(strcmp(svc->category, "conference") == 0)
205  nad_append_elem(pkt->nad, ns, "groupchat", 4);
206  } while(xhash_iter_next(d->un));
207 
208  return pkt;
209 }
210 
212 static void _disco_generate_packets(module_t mod, disco_t d) {
213  log_debug(ZONE, "regenerating packets");
214 
215  if(d->disco_items_result != NULL)
218 
219  if(d->disco_info_result != NULL)
222 
223  if(d->agents) {
224  if(d->agents_result != NULL)
226  d->agents_result = _disco_agents_result(mod, d);
227  }
228 
229 }
230 
233 {
234  module_t mod = mi->mod;
235  disco_t d = (disco_t) mod->private;
236  int ns, qelem, elem, attr;
237  service_t svc;
238 
239  /* it has to come from the service itself - don't want any old user messing with the table */
240  if(pkt->from->node[0] != '\0' || pkt->from->resource[0] != '\0')
241  {
242  log_debug(ZONE, "disco response from %s, not allowed", jid_full(pkt->from));
243  return -stanza_err_NOT_ALLOWED;
244  }
245 
246  ns = nad_find_scoped_namespace(pkt->nad, uri_DISCO_INFO, NULL);
247  qelem = nad_find_elem(pkt->nad, 1, ns, "query", 1);
248 
249  elem = nad_find_elem(pkt->nad, qelem, ns, "identity", 1);
250  if(elem < 0)
251  return -stanza_err_BAD_REQUEST;
252 
253  /* we don't want to list other im servers on the router */
254  if(nad_find_attr(pkt->nad, elem, -1, "category", "server") >= 0
255  && nad_find_attr(pkt->nad, elem, -1, "type", "im") >= 0) {
256  pkt_free(pkt);
257  return mod_HANDLED;
258  }
259 
260  /* see if we already have this service */
261  svc = xhash_get(d->dyn, jid_full(pkt->from));
262  if(svc == NULL)
263  {
264  /* make a new one */
265  svc = (service_t) calloc(1, sizeof(struct service_st));
266 
267  svc->jid = jid_dup(pkt->from);
268 
269  svc->features = xhash_new(11);
270 
271  /* link it in */
272  xhash_put(d->dyn, jid_full(svc->jid), (void *) svc);
273 
274  /* unify */
276  }
277 
278  /* fill in the name */
279  attr = nad_find_attr(pkt->nad, elem, -1, "name", NULL);
280  if(attr < 0)
281  svc->name[0] = '\0';
282  else
283  snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
284 
285  /* category and type */
286  attr = nad_find_attr(pkt->nad, elem, -1, "category", NULL);
287  if(attr >= 0)
288  snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
289  else
290  strcpy(svc->category, "unknown");
291 
292  attr = nad_find_attr(pkt->nad, elem, -1, "type", NULL);
293  if(attr >= 0)
294  snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
295  else
296  strcpy(svc->type, "unknown");
297 
298  /* features */
299  elem = nad_find_elem(pkt->nad, qelem, -1, "feature", 1);
300  while(elem >= 0)
301  {
302  attr = nad_find_attr(pkt->nad, elem, -1, "var", NULL);
303  if(attr < 0)
304  {
305  elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0);
306  continue;
307  }
308 
309  xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)), (void *) 1);
310 
311  elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0);
312  }
313 
314  /* regenerate packets */
315  _disco_generate_packets(mod, d);
316 
317  pkt_free(pkt);
318 
319  return mod_HANDLED;
320 }
321 
323 static void _disco_sessions_result(module_t mod, disco_t d, pkt_t pkt) {
324  int ns;
325  sess_t sess;
326  union xhashv xhv;
327 
328  ns = nad_add_namespace(pkt->nad, uri_DISCO_ITEMS, NULL);
329  nad_append_elem(pkt->nad, ns, "query", 2);
330  nad_append_attr(pkt->nad, -1, "node", "sessions");
331 
332  if(xhash_iter_first(mod->mm->sm->sessions))
333  do {
334  xhv.sess_val = &sess;
335  xhash_iter_get(mod->mm->sm->sessions, NULL, NULL, xhv.val);
336 
337  nad_append_elem(pkt->nad, ns, "item", 3);
338  nad_append_attr(pkt->nad, -1, "jid", jid_full(sess->jid));
339  nad_append_attr(pkt->nad, -1, "name", "Active session");
340  } while(xhash_iter_next(mod->mm->sm->sessions));
341 }
342 
345  module_t mod = mi->mod;
346  disco_t d = (disco_t) mod->private;
347  pkt_t result;
348  int node, ns;
349 
350  /* disco info results go to a seperate function */
351  if(pkt->type == pkt_IQ_RESULT && pkt->ns == ns_DISCO_INFO)
352  return _disco_pkt_sm_populate(mi, pkt);
353 
354  /* check whether the requested domain is serviced here */
355  if(xhash_get(mod->mm->sm->hosts, pkt->to->domain) == NULL)
357 
358  /* we want disco or agents gets */
359  if(pkt->type != pkt_IQ || !(pkt->ns == ns_DISCO_INFO || pkt->ns == ns_DISCO_ITEMS || pkt->ns == ns_AGENTS))
360  return mod_PASS;
361 
362  /* generate the caches if we haven't yet */
363  if(d->disco_info_result == NULL)
364  _disco_generate_packets(mod, d);
365 
366  node = nad_find_attr(pkt->nad, 2, -1, "node", NULL);
367 
368  /* they want to know about us */
369  if(pkt->ns == ns_DISCO_INFO) {
370  /* respond with cached disco info packet if no node given */
371  if(node < 0) {
372  result = pkt_dup(d->disco_info_result, jid_full(pkt->from), jid_full(pkt->to));
373 
374  node = nad_find_attr(pkt->nad, 2, -1, "node", NULL);
375  if(node >= 0) {
376  nad_set_attr(result->nad, 2, -1, "node", NAD_AVAL(pkt->nad, node), NAD_AVAL_L(pkt->nad, node));
377  }
378 
379  pkt_id(pkt, result);
380  pkt_free(pkt);
381 
382  /* off it goes */
383  pkt_router(result);
384 
385  return mod_HANDLED;
386  }
387  else if(NAD_AVAL_L(pkt->nad, node) == 8 && strncmp("sessions", NAD_AVAL(pkt->nad, node), 8) == 0) {
388  /* priviliged op, make sure they're allowed */
389  if(!aci_check(mod->mm->sm->acls, "disco", pkt->from))
390  return -stanza_err_ITEM_NOT_FOUND; /* we never advertised it, so we can pretend its not here */
391 
392  result = pkt_create(mod->mm->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to));
393  pkt_id(pkt, result);
394  pkt_free(pkt);
395 
396  ns = nad_add_namespace(result->nad, uri_DISCO_INFO, NULL);
397  nad_append_elem(result->nad, ns, "query", 2);
398  nad_append_elem(result->nad, ns, "identity", 3);
399  nad_append_attr(result->nad, -1, "category", "hierarchy");
400  nad_append_attr(result->nad, -1, "type", "branch");
401  nad_append_attr(result->nad, -1, "name", ACTIVE_SESSIONS_NAME);
402  nad_append_elem(result->nad, -1, "feature", 3);
403  nad_append_attr(result->nad, -1, "var", uri_DISCO_INFO);
404  nad_append_elem(result->nad, -1, "feature", 3);
405  nad_append_attr(result->nad, -1, "var", uri_DISCO_ITEMS);
406 
407  /* off it goes */
408  pkt_router(result);
409 
410  return mod_HANDLED;
411  }
412  else
414  }
415 
416  /* handle agents */
417  if(pkt->ns == ns_AGENTS) {
418  /* make sure we're supporting compat */
419  if(!d->agents)
420  return -stanza_err_NOT_ALLOWED;
421 
422  result = pkt_dup(d->agents_result, jid_full(pkt->from), jid_full(pkt->to));
423  pkt_id(pkt, result);
424  pkt_free(pkt);
425 
426  /* off it goes */
427  pkt_router(result);
428 
429  return mod_HANDLED;
430  }
431 
432  /* they want to know who we know about */
433  if(node < 0) {
434  /* no node, so toplevel services */
435  result = pkt_dup(d->disco_items_result, jid_full(pkt->from), jid_full(pkt->to));
436  pkt_id(pkt, result);
437  pkt_free(pkt);
438 
439  /* if they have privs, then show them any administrative things they can disco to */
440  if(aci_check(mod->mm->sm->acls, "disco", result->to)) {
441  nad_append_elem(result->nad, NAD_ENS(result->nad, 2), "item", 3);
442  nad_append_attr(result->nad, -1, "jid", jid_full(result->from));
443  nad_append_attr(result->nad, -1, "node", "sessions");
444  nad_append_attr(result->nad, -1, "name", ACTIVE_SESSIONS_NAME);
445  }
446 
447  pkt_router(result);
448 
449  return mod_HANDLED;
450  }
451 
452  /* active sessions */
453  if(NAD_AVAL_L(pkt->nad, node) == 8 && strncmp("sessions", NAD_AVAL(pkt->nad, node), 8) == 0) {
454  /* priviliged op, make sure they're allowed */
455  if(!aci_check(mod->mm->sm->acls, "disco", pkt->from))
456  return -stanza_err_ITEM_NOT_FOUND; /* we never advertised it, so we can pretend its not here */
457 
458  result = pkt_create(mod->mm->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to));
459  pkt_id(pkt, result);
460  pkt_free(pkt);
461 
462  _disco_sessions_result(mod, d, result);
463 
464  /* off it goes */
465  pkt_router(result);
466 
467  return mod_HANDLED;
468  }
469 
470  /* I dunno what they're asking for */
472 }
473 
475 static void _disco_user_result(pkt_t pkt, user_t user)
476 {
477  /* identity */
478  nad_append_elem(pkt->nad, -1, "identity", 3);
479  nad_append_attr(pkt->nad, -1, "category", "account");
480  /* if user is logged in (has session) yet never logged in (no active time)
481  it is certainly an anonymous user */
482  log_debug(ZONE, "%s: top %p active %d", jid_full(user->jid), user->sessions, user->active);
483  nad_append_attr(pkt->nad, -1, "type", (user->sessions && !user->active) ? "anonymous" : "registered");
484 
485  /* tell them */
486  nad_set_attr(pkt->nad, 1, -1, "type", "result", 6);
487 }
488 
491  module_t mod = mi->mod;
492  disco_t d = (disco_t) mod->private;
493  pkt_t result;
494 
495  /* disco info requests */
496  if(pkt->type == pkt_IQ && pkt->ns == ns_DISCO_INFO)
497  {
498  /* it has to have no to address or self bare jid */
499  if(pkt->to != NULL && strcmp(jid_user(sess->jid), jid_full(pkt->to)))
500  {
501  return mod_PASS;
502  }
503 
504  _disco_user_result(pkt, sess->user);
505  pkt_sess(pkt_tofrom(pkt), sess);
506  return mod_HANDLED;
507  }
508 
509  /* we want agents gets */
510  if(pkt->type != pkt_IQ || pkt->ns != ns_AGENTS || pkt->to != NULL)
511  return mod_PASS;
512 
513  /* fail if its not enabled */
514  if(!d->agents)
515  return -stanza_err_NOT_ALLOWED;
516 
517  /* generate the caches if we haven't yet */
518  if(d->disco_info_result == NULL)
519  _disco_generate_packets(mod, d);
520 
521  /* pre-canned response */
522  result = pkt_dup(d->agents_result, NULL, NULL);
523  pkt_id(pkt, result);
524  pkt_free(pkt);
525 
526  /* off it goes */
527  pkt_sess(result, sess);
528 
529  return mod_HANDLED;
530 }
531 
533  /* disco info requests */
534  if(pkt->type == pkt_IQ && pkt->ns == ns_DISCO_INFO)
535  {
536  _disco_user_result(pkt, user);
537  pkt_router(pkt_tofrom(pkt));
538  return mod_HANDLED;
539  }
540 
541  /* pass everything else */
542  return mod_PASS;
543 }
544 
547 {
548  module_t mod = mi->mod;
549  disco_t d = (disco_t) mod->private;
550  service_t svc;
551  pkt_t request;
552  int ns;
553 
554  /* we want advertisements with a from address */
555  if(pkt->from == NULL || !(pkt->rtype & route_ADV))
556  return mod_PASS;
557 
558  /* component online */
559  if(pkt->rtype == route_ADV)
560  {
561  log_debug(ZONE, "presence from component %s, issuing discovery request", jid_full(pkt->from));
562 
563  /* new disco get packet */
564  request = pkt_create(mod->mm->sm, "iq", "get", jid_full(pkt->from), mod->mm->sm->id);
565  pkt_id_new(request);
566  ns = nad_add_namespace(request->nad, uri_DISCO_INFO, NULL);
567  nad_append_elem(request->nad, ns, "query", 2);
568 
569  pkt_router(request);
570 
571  /* done with this */
572  pkt_free(pkt);
573 
574  return mod_HANDLED;
575  }
576 
577  /* it went away. find it and remove it */
578  svc = xhash_get(d->dyn, jid_full(pkt->from));
579  if(svc != NULL)
580  {
581  log_debug(ZONE, "dropping entry for %s", jid_full(pkt->from));
582 
583  xhash_zap(d->dyn, jid_full(pkt->from));
584 
585  jid_free(svc->jid);
586  xhash_free(svc->features);
587  free(svc);
588 
589  /* unify */
591  _disco_generate_packets(mod, d);
592  }
593 
594  /* done */
595  pkt_free(pkt);
596 
597  return mod_HANDLED;
598 }
599 
600 static void _disco_free_walker(const char *key, int keylen, void *val, void *arg) {
601  service_t svc = (service_t) val;
602 
603  jid_free(svc->jid);
604  xhash_free(svc->features);
605  free(svc);
606 }
607 
608 static void _disco_free(module_t mod) {
609  disco_t d = (disco_t) mod->private;
610 
612  xhash_walk(d->dyn, _disco_free_walker, NULL);
613 
614  xhash_free(d->stat);
615  xhash_free(d->dyn);
616  xhash_free(d->un);
617 
618  if(d->disco_info_result != NULL) pkt_free(d->disco_info_result);
620  if(d->agents_result != NULL) pkt_free(d->agents_result);
621 
622  free(d);
623 }
624 
625 DLLEXPORT int module_init(mod_instance_t mi, const char *arg)
626 {
627  module_t mod = mi->mod;
628  disco_t d;
629  nad_t nad;
630  int items, item, jid, name, category, type, ns;
631  service_t svc;
632 
633  if(mod->init) return 0;
634 
635  log_debug(ZONE, "disco module init");
636 
637  d = (disco_t) calloc(1, sizeof(struct disco_st));
638 
639  /* new hashes to store the lists in */
640  d->dyn = xhash_new(51);
641  d->stat = xhash_new(51);
642 
643  /* identity */
644  d->category = config_get_one(mod->mm->sm->config, "discovery.identity.category", 0);
645  if(d->category == NULL) d->category = "server";
646  d->type = config_get_one(mod->mm->sm->config, "discovery.identity.type", 0);
647  if(d->type == NULL) d->type = "im";
648  d->name = config_get_one(mod->mm->sm->config, "discovery.identity.name", 0);
649  if(d->name == NULL) d->name = "Jabber IM server";
650 
651  /* agents compatibility */
652  d->agents = config_get(mod->mm->sm->config, "discovery.agents") != NULL;
653 
654  if(d->agents)
655  log_debug(ZONE, "agents compat enabled");
656 
657  /* our data */
658  mod->private = (void *) d;
659 
660  /* our handlers */
661  mod->pkt_sm = _disco_pkt_sm;
662  mod->in_sess = _disco_in_sess;
663  mod->pkt_user = _disco_pkt_user;
665  mod->free = _disco_free;
666 
667  nad = mod->mm->sm->config->nad;
668 
669  /* we support a number of things */
672  if(d->agents)
674 
675  /* populate the static list from the config file */
676  if((items = nad_find_elem(nad, 0, -1, "discovery", 1)) < 0 || (items = nad_find_elem(nad, items, -1, "items", 1)) < 0)
677  return 0;
678 
679  item = nad_find_elem(nad, items, -1, "item", 1);
680  while(item >= 0)
681  {
682  /* jid is required */
683  jid = nad_find_attr(nad, item, -1, "jid", NULL);
684  if(jid < 0)
685  {
686  item = nad_find_elem(nad, item, -1, "item", 0);
687  continue;
688  }
689 
690  /* new service */
691  svc = (service_t) calloc(1, sizeof(struct service_st));
692 
693  svc->features = xhash_new(13);
694 
695  svc->jid = jid_new(NAD_AVAL(nad, jid), NAD_AVAL_L(nad, jid));
696 
697  /* link it in */
698  xhash_put(d->stat, jid_full(svc->jid), (void *) svc);
699 
700  /* copy the name */
701  name = nad_find_attr(nad, item, -1, "name", NULL);
702  if(name >= 0)
703  snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(nad, name), NAD_AVAL(nad, name));
704 
705  /* category and type */
706  category = nad_find_attr(nad, item, -1, "category", NULL);
707  if(category >= 0)
708  snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(nad, category), NAD_AVAL(nad, category));
709  else
710  strcpy(svc->category, "unknown");
711 
712  type = nad_find_attr(nad, item, -1, "type", NULL);
713  if(type >= 0)
714  snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(nad, type), NAD_AVAL(nad, type));
715  else
716  strcpy(svc->type, "unknown");
717 
718  /* namespaces */
719  ns = nad_find_elem(nad, item, -1, "ns", 1);
720  while(ns >= 0)
721  {
722  if(NAD_CDATA_L(nad, ns) > 0)
723  xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_CDATA(nad, ns), NAD_CDATA_L(nad, ns)), (void *) 1);
724 
725  ns = nad_find_elem(nad, ns, -1, "ns", 0);
726  }
727 
728  item = nad_find_elem(nad, item, -1, "item", 0);
729 
730  log_debug(ZONE, "added %s to static list", jid_full(svc->jid));
731  }
732 
733  /* generate the initial union list */
735 
736  /* we don't generate the packets here, because the router conn isn't up yet, and so we don't have a nad cache */
737 
738  return 0;
739 }
#define ACTIVE_SESSIONS_NAME
Definition: mod_disco.c:30
user_t user
user this session belongs to
Definition: sm.h:256
struct xht_struct * xht
pkt_type_t type
packet type
Definition: sm.h:138
jid_t jid
session jid (user@host/res)
Definition: sm.h:258
Definition: nad.h:93
int nad_append_attr(nad_t nad, int ns, const char *name, const char *val)
attach new attr to the last elem
Definition: nad.c:729
data structures and prototypes for the session manager
static mod_ret_t _disco_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt)
Definition: mod_disco.c:532
#define ns_DISCO_INFO
Definition: sm.h:81
xht stat
Definition: mod_disco.c:58
static void _disco_sessions_result(module_t mod, disco_t d, pkt_t pkt)
build a disco items result, active sessions
Definition: mod_disco.c:323
#define NAD_CDATA_L(N, E)
Definition: nad.h:186
const char * id
component id
Definition: sm.h:168
#define ns_DISCO_ITEMS
Definition: sm.h:80
void xhash_free(xht h)
Definition: xhash.c:241
const char * jid_user(jid_t jid)
expand and return the user
Definition: jid.c:339
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:347
service_t * svc_val
Definition: mod_disco.c:73
pkt_t agents_result
Definition: mod_disco.c:66
jid_t jid_new(const char *id, int len)
make a new jid
Definition: jid.c:81
pkt_t pkt_tofrom(pkt_t pkt)
swap a packet's to and from attributes
Definition: pkt.c:57
single instance of a module in a chain
Definition: sm.h:446
int nad_find_elem(nad_t nad, 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:204
static void _disco_user_result(pkt_t pkt, user_t user)
response to quering user JID
Definition: mod_disco.c:475
void nad_append_cdata(nad_t nad, const char *cdata, int len, int depth)
append new cdata to the last elem
Definition: nad.c:737
config_t config
config context
Definition: sm.h:198
int init
number of times the module intialiser has been called
Definition: sm.h:416
xht hosts
vHosts map
Definition: sm.h:224
int nad_add_namespace(nad_t nad, const char *uri, const char *prefix)
bring a new namespace into scope
Definition: nad.c:762
pkt_t pkt_dup(pkt_t pkt, const char *to, const char *from)
duplicate pkt, replacing addresses
Definition: pkt.c:84
info/query (result)
Definition: sm.h:108
const char * category
identity
Definition: mod_disco.c:49
void pkt_id_new(pkt_t pkt)
create an id value for new iq packets
Definition: pkt.c:364
void mm_disco_extend(mm_t mm, pkt_t pkt)
disco extend
Definition: mm.c:778
int agents
compatibility
Definition: mod_disco.c:54
char * resource
Definition: jid.h:46
static mod_ret_t _disco_pkt_sm(mod_instance_t mi, pkt_t pkt)
catch responses and populate the table; respond to requests
Definition: mod_disco.c:344
int nad_append_elem(nad_t nad, int ns, const char *name, int depth)
create a new elem on the list
Definition: nad.c:695
int xhash_iter_next(xht h)
Definition: xhash.c:320
static mod_ret_t _disco_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt)
legacy support for agents requests from sessions
Definition: mod_disco.c:490
xht sessions
pointers to all connected sessions (key is random sm id)
Definition: sm.h:191
mm_t mm
module manager
Definition: sm.h:404
static pkt_t _disco_items_result(module_t mod, disco_t d)
build a disco items result, known services
Definition: mod_disco.c:107
static void _disco_free_walker(const char *key, int keylen, void *val, void *arg)
Definition: mod_disco.c:600
const char * name
Definition: mod_disco.c:51
#define DLLEXPORT
Definition: c2s.h:47
void nad_set_attr(nad_t nad, 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:403
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
struct disco_st * disco_t
all the current disco data
Definition: mod_disco.c:46
mod_ret_t(* pkt_router)(mod_instance_t mi, pkt_t pkt)
pkt-router handler
Definition: sm.h:432
sess_t sessions
list of action sessions
Definition: sm.h:243
nad_t nad
Definition: util.h:203
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 * private
module private data
Definition: sm.h:418
void ** val
Definition: c2s.h:401
packet summary data wrapper
Definition: sm.h:129
char * pstrdupx(pool_t p, const char *src, int len)
use given size
Definition: pool.c:205
nad_t nad
nad of the entire packet
Definition: sm.h:146
void jid_free(jid_t jid)
free a jid
Definition: jid.c:286
int aci_check(xht aci, const char *type, const char *name)
see if a username is in an acl
Definition: aci.c:93
advertisement (available)
Definition: sm.h:123
static mod_ret_t _disco_pkt_sm_populate(mod_instance_t mi, pkt_t pkt)
catch responses and populate the table
Definition: mod_disco.c:232
void xhash_put(xht h, const char *key, void *val)
Definition: xhash.c:163
sess_t * sess_val
Definition: c2s.h:403
#define uri_AGENTS
Definition: uri.h:64
#define stanza_err_BAD_REQUEST
Definition: util.h:367
char * domain
Definition: jid.h:45
xht features
Definition: mod_disco.c:42
jid_t jid
Definition: mod_disco.c:35
Definition: jid.h:42
int xhash_iter_get(xht h, const char **key, int *keylen, void **val)
Definition: xhash.c:374
#define uri_REGISTER
Definition: uri.h:62
#define NAD_AVAL_L(N, A)
Definition: nad.h:190
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 xhash_zap(xht h, const char *key)
Definition: xhash.c:235
void pkt_free(pkt_t pkt)
Definition: pkt.c:315
#define log_debug(...)
Definition: log.h:65
pkt_t disco_items_result
Definition: mod_disco.c:65
#define stanza_err_NOT_ALLOWED
Definition: util.h:376
void feature_register(sm_t sm, const char *feature)
register a feature
Definition: feature.c:37
info/query (get)
Definition: sm.h:106
#define NAD_AVAL(N, A)
Definition: nad.h:189
#define uri_SEARCH
Definition: uri.h:77
xht dyn
the lists
Definition: mod_disco.c:57
#define uri_GATEWAY
Definition: uri.h:72
packet was unhandled, should be passed to the next module
Definition: sm.h:340
int ns
iq sub-namespace
Definition: sm.h:142
#define stanza_err_ITEM_NOT_FOUND
Definition: util.h:373
config_elem_t config_get(config_t c, const char *key)
get the config element for this key
Definition: config.c:271
packet was handled (and freed)
Definition: sm.h:339
static mod_ret_t _disco_pkt_router(mod_instance_t mi, pkt_t pkt)
update the table for component changes
Definition: mod_disco.c:546
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
static void _disco_unify_walker(const char *key, int keylen, void *val, void *arg)
put val into arg
Definition: mod_disco.c:79
int xhash_iter_first(xht h)
iteration
Definition: xhash.c:311
struct service_st * service_t
holder for a single service
Definition: mod_disco.c:33
void xhash_walk(xht h, xhash_walker w, void *arg)
Definition: xhash.c:268
static void _disco_generate_packets(module_t mod, disco_t d)
generate cached result packets
Definition: mod_disco.c:212
static pkt_t _disco_info_result(module_t mod, disco_t d)
build a disco info result
Definition: mod_disco.c:133
mod_ret_t(* pkt_sm)(mod_instance_t mi, pkt_t pkt)
pkt-sm handler
Definition: sm.h:429
pkt_t disco_info_result
cached result packets
Definition: mod_disco.c:64
const char ** char_val
Definition: c2s.h:402
jid_t to
Definition: sm.h:140
static void _disco_free(module_t mod)
Definition: mod_disco.c:608
pool_t xhash_pool(xht h)
get our pool
Definition: xhash.c:305
#define NAD_CDATA(N, E)
Definition: nad.h:185
jid_t jid_dup(jid_t jid)
duplicate a jid
Definition: jid.c:373
jid_t jid
user jid (user@host)
Definition: sm.h:239
char category[257]
Definition: mod_disco.c:39
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
xht acls
access control lists (key is list name, value is jid_t list)
Definition: sm.h:215
#define ZONE
Definition: mio_impl.h:76
session packet handling
Definition: c2s.h:399
xht un
unified list
Definition: mod_disco.c:61
static pkt_t _disco_agents_result(module_t mod, disco_t d)
build an agents result
Definition: mod_disco.c:166
const char * config_get_one(config_t c, const char *key, int num)
get config value n for this key
Definition: config.c:277
char name[257]
Definition: mod_disco.c:37
void(* free)(module_t mod)
called when module is freed
Definition: sm.h:442
xht xhash_new(int prime)
Definition: xhash.c:96
data for a single module
Definition: sm.h:403
#define uri_DISCO_INFO
Definition: uri.h:81
int nad_find_attr(nad_t nad, int elem, int ns, const char *name, const char *val)
get a matching attr on this elem, both name and optional val
Definition: nad.c:235
#define uri_DISCO_ITEMS
Definition: uri.h:80
static void _disco_unify_lists(disco_t d)
unify the contents of dyn and stat
Definition: mod_disco.c:93
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
const char * type
Definition: mod_disco.c:50
#define ns_AGENTS
Definition: sm.h:72
void pkt_sess(pkt_t pkt, sess_t sess)
Definition: pkt.c:459
char type[257]
Definition: mod_disco.c:40
char * node
Definition: jid.h:44
time_t active
time that user first logged in (ever)
Definition: sm.h:247
DLLEXPORT int module_init(mod_instance_t mi, const char *arg)
Definition: mod_disco.c:625
#define NAD_ENS(N, E)
Definition: nad.h:196
data for a single user
Definition: sm.h:234
int nad_find_scoped_namespace(nad_t nad, const char *uri, const char *prefix)
find a namespace in scope
Definition: nad.c:290
route_type_t rtype
type of enclosing route
Definition: sm.h:136
xht features
feature index (key is feature string
Definition: sm.h:196