jabberd2  2.6.1
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;
74  sess_t *sess_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, query, 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  query = nad_find_elem(pkt->nad, 1, ns, "query", 1);
248  if(query < 0)
249  return -stanza_err_BAD_REQUEST;
250 
251  elem = nad_find_elem(pkt->nad, query, ns, "identity", 1);
252  if(elem < 0)
253  return -stanza_err_BAD_REQUEST;
254 
255  /* we don't want to list other im servers on the router */
256  if(nad_find_attr(pkt->nad, elem, -1, "category", "server") >= 0
257  && nad_find_attr(pkt->nad, elem, -1, "type", "im") >= 0) {
258  pkt_free(pkt);
259  return mod_HANDLED;
260  }
261 
262  /* see if we already have this service */
263  svc = xhash_get(d->dyn, jid_full(pkt->from));
264  if(svc == NULL)
265  {
266  /* make a new one */
267  svc = (service_t) calloc(1, sizeof(struct service_st));
268 
269  svc->jid = jid_dup(pkt->from);
270 
271  svc->features = xhash_new(11);
272 
273  /* link it in */
274  xhash_put(d->dyn, jid_full(svc->jid), (void *) svc);
275 
276  /* unify */
278  }
279 
280  /* fill in the name */
281  attr = nad_find_attr(pkt->nad, elem, -1, "name", NULL);
282  if(attr < 0)
283  svc->name[0] = '\0';
284  else
285  snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
286 
287  /* category and type */
288  attr = nad_find_attr(pkt->nad, elem, -1, "category", NULL);
289  if(attr >= 0)
290  snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
291  else
292  strcpy(svc->category, "unknown");
293 
294  attr = nad_find_attr(pkt->nad, elem, -1, "type", NULL);
295  if(attr >= 0)
296  snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
297  else
298  strcpy(svc->type, "unknown");
299 
300  /* features */
301  elem = nad_find_elem(pkt->nad, query, -1, "feature", 1);
302  while(elem >= 0)
303  {
304  attr = nad_find_attr(pkt->nad, elem, -1, "var", NULL);
305  if(attr < 0)
306  {
307  elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0);
308  continue;
309  }
310 
311  xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)), (void *) 1);
312 
313  elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0);
314  }
315 
316  /* regenerate packets */
317  _disco_generate_packets(mod, d);
318 
319  pkt_free(pkt);
320 
321  return mod_HANDLED;
322 }
323 
325 static void _disco_sessions_result(module_t mod, disco_t d, pkt_t pkt) {
326  int ns;
327  sess_t sess;
328  union xhashv xhv;
329 
330  ns = nad_add_namespace(pkt->nad, uri_DISCO_ITEMS, NULL);
331  nad_append_elem(pkt->nad, ns, "query", 2);
332  nad_append_attr(pkt->nad, -1, "node", "sessions");
333 
334  if(xhash_iter_first(mod->mm->sm->sessions))
335  do {
336  xhv.sess_val = &sess;
337  xhash_iter_get(mod->mm->sm->sessions, NULL, NULL, xhv.val);
338 
339  nad_append_elem(pkt->nad, ns, "item", 3);
340  nad_append_attr(pkt->nad, -1, "jid", jid_full(sess->jid));
341  nad_append_attr(pkt->nad, -1, "name", "Active session");
342  } while(xhash_iter_next(mod->mm->sm->sessions));
343 }
344 
347  module_t mod = mi->mod;
348  disco_t d = (disco_t) mod->private;
349  pkt_t result;
350  int node, ns;
351 
352  /* disco info results go to a seperate function */
353  if(pkt->type == pkt_IQ_RESULT && pkt->ns == ns_DISCO_INFO)
354  return _disco_pkt_sm_populate(mi, pkt);
355 
356  /* check whether the requested domain is serviced here */
357  if(xhash_get(mod->mm->sm->hosts, pkt->to->domain) == NULL)
359 
360  /* we want disco or agents gets */
361  if(pkt->type != pkt_IQ || !(pkt->ns == ns_DISCO_INFO || pkt->ns == ns_DISCO_ITEMS || pkt->ns == ns_AGENTS))
362  return mod_PASS;
363 
364  /* generate the caches if we haven't yet */
365  if(d->disco_info_result == NULL)
366  _disco_generate_packets(mod, d);
367 
368  node = nad_find_attr(pkt->nad, 2, -1, "node", NULL);
369 
370  /* they want to know about us */
371  if(pkt->ns == ns_DISCO_INFO) {
372  /* respond with cached disco info packet if no node given */
373  if(node < 0) {
374  result = pkt_dup(d->disco_info_result, jid_full(pkt->from), jid_full(pkt->to));
375 
376  node = nad_find_attr(pkt->nad, 2, -1, "node", NULL);
377  if(node >= 0) {
378  nad_set_attr(result->nad, 2, -1, "node", NAD_AVAL(pkt->nad, node), NAD_AVAL_L(pkt->nad, node));
379  }
380 
381  pkt_id(pkt, result);
382  pkt_free(pkt);
383 
384  /* off it goes */
385  pkt_router(result);
386 
387  return mod_HANDLED;
388  }
389  else if(NAD_AVAL_L(pkt->nad, node) == 8 && strncmp("sessions", NAD_AVAL(pkt->nad, node), 8) == 0) {
390  /* priviliged op, make sure they're allowed */
391  if(!aci_check(mod->mm->sm->acls, "disco", pkt->from))
392  return -stanza_err_ITEM_NOT_FOUND; /* we never advertised it, so we can pretend its not here */
393 
394  result = pkt_create(mod->mm->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to));
395  pkt_id(pkt, result);
396  pkt_free(pkt);
397 
398  ns = nad_add_namespace(result->nad, uri_DISCO_INFO, NULL);
399  nad_append_elem(result->nad, ns, "query", 2);
400  nad_append_elem(result->nad, ns, "identity", 3);
401  nad_append_attr(result->nad, -1, "category", "hierarchy");
402  nad_append_attr(result->nad, -1, "type", "branch");
403  nad_append_attr(result->nad, -1, "name", ACTIVE_SESSIONS_NAME);
404  nad_append_elem(result->nad, -1, "feature", 3);
405  nad_append_attr(result->nad, -1, "var", uri_DISCO_INFO);
406  nad_append_elem(result->nad, -1, "feature", 3);
407  nad_append_attr(result->nad, -1, "var", uri_DISCO_ITEMS);
408 
409  /* off it goes */
410  pkt_router(result);
411 
412  return mod_HANDLED;
413  }
414  else
416  }
417 
418  /* handle agents */
419  if(pkt->ns == ns_AGENTS) {
420  /* make sure we're supporting compat */
421  if(!d->agents)
422  return -stanza_err_NOT_ALLOWED;
423 
424  result = pkt_dup(d->agents_result, jid_full(pkt->from), jid_full(pkt->to));
425  pkt_id(pkt, result);
426  pkt_free(pkt);
427 
428  /* off it goes */
429  pkt_router(result);
430 
431  return mod_HANDLED;
432  }
433 
434  /* they want to know who we know about */
435  if(node < 0) {
436  /* no node, so toplevel services */
437  result = pkt_dup(d->disco_items_result, jid_full(pkt->from), jid_full(pkt->to));
438  pkt_id(pkt, result);
439  pkt_free(pkt);
440 
441  /* if they have privs, then show them any administrative things they can disco to */
442  if(aci_check(mod->mm->sm->acls, "disco", result->to)) {
443  nad_append_elem(result->nad, NAD_ENS(result->nad, 2), "item", 3);
444  nad_append_attr(result->nad, -1, "jid", jid_full(result->from));
445  nad_append_attr(result->nad, -1, "node", "sessions");
446  nad_append_attr(result->nad, -1, "name", ACTIVE_SESSIONS_NAME);
447  }
448 
449  pkt_router(result);
450 
451  return mod_HANDLED;
452  }
453 
454  /* active sessions */
455  if(NAD_AVAL_L(pkt->nad, node) == 8 && strncmp("sessions", NAD_AVAL(pkt->nad, node), 8) == 0) {
456  /* priviliged op, make sure they're allowed */
457  if(!aci_check(mod->mm->sm->acls, "disco", pkt->from))
458  return -stanza_err_ITEM_NOT_FOUND; /* we never advertised it, so we can pretend its not here */
459 
460  result = pkt_create(mod->mm->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to));
461  pkt_id(pkt, result);
462  pkt_free(pkt);
463 
464  _disco_sessions_result(mod, d, result);
465 
466  /* off it goes */
467  pkt_router(result);
468 
469  return mod_HANDLED;
470  }
471 
472  /* I dunno what they're asking for */
474 }
475 
477 static void _disco_user_result(pkt_t pkt, user_t user)
478 {
479  /* identity */
480  nad_append_elem(pkt->nad, -1, "identity", 3);
481  nad_append_attr(pkt->nad, -1, "category", "account");
482  /* if user is logged in (has session) yet never logged in (no active time)
483  it is certainly an anonymous user */
484  log_debug(ZONE, "%s: top %p active %d", jid_full(user->jid), user->sessions, user->active);
485  nad_append_attr(pkt->nad, -1, "type", (user->sessions && !user->active) ? "anonymous" : "registered");
486 
487  /* tell them */
488  nad_set_attr(pkt->nad, 1, -1, "type", "result", 6);
489 }
490 
493  module_t mod = mi->mod;
494  disco_t d = (disco_t) mod->private;
495  pkt_t result;
496 
497  /* disco info requests */
498  if(pkt->type == pkt_IQ && pkt->ns == ns_DISCO_INFO)
499  {
500  /* it has to have no to address or self bare jid */
501  if(pkt->to != NULL && strcmp(jid_user(sess->jid), jid_full(pkt->to)))
502  {
503  return mod_PASS;
504  }
505 
506  _disco_user_result(pkt, sess->user);
507  pkt_sess(pkt_tofrom(pkt), sess);
508  return mod_HANDLED;
509  }
510 
511  /* we want agents gets */
512  if(pkt->type != pkt_IQ || pkt->ns != ns_AGENTS || pkt->to != NULL)
513  return mod_PASS;
514 
515  /* fail if its not enabled */
516  if(!d->agents)
517  return -stanza_err_NOT_ALLOWED;
518 
519  /* generate the caches if we haven't yet */
520  if(d->disco_info_result == NULL)
521  _disco_generate_packets(mod, d);
522 
523  /* pre-canned response */
524  result = pkt_dup(d->agents_result, NULL, NULL);
525  pkt_id(pkt, result);
526  pkt_free(pkt);
527 
528  /* off it goes */
529  pkt_sess(result, sess);
530 
531  return mod_HANDLED;
532 }
533 
535  /* disco info requests */
536  if(pkt->type == pkt_IQ && pkt->ns == ns_DISCO_INFO)
537  {
538  _disco_user_result(pkt, user);
539  pkt_router(pkt_tofrom(pkt));
540  return mod_HANDLED;
541  }
542 
543  /* pass everything else */
544  return mod_PASS;
545 }
546 
549 {
550  module_t mod = mi->mod;
551  disco_t d = (disco_t) mod->private;
552  service_t svc;
553  pkt_t request;
554  int ns;
555 
556  /* we want advertisements with a from address */
557  if(pkt->from == NULL || !(pkt->rtype & route_ADV))
558  return mod_PASS;
559 
560  /* component online */
561  if(pkt->rtype == route_ADV)
562  {
563  log_debug(ZONE, "presence from component %s, issuing discovery request", jid_full(pkt->from));
564 
565  /* new disco get packet */
566  request = pkt_create(mod->mm->sm, "iq", "get", jid_full(pkt->from), mod->mm->sm->id);
567  pkt_id_new(request);
568  ns = nad_add_namespace(request->nad, uri_DISCO_INFO, NULL);
569  nad_append_elem(request->nad, ns, "query", 2);
570 
571  pkt_router(request);
572 
573  /* done with this */
574  pkt_free(pkt);
575 
576  return mod_HANDLED;
577  }
578 
579  /* it went away. find it and remove it */
580  svc = xhash_get(d->dyn, jid_full(pkt->from));
581  if(svc != NULL)
582  {
583  log_debug(ZONE, "dropping entry for %s", jid_full(pkt->from));
584 
585  xhash_zap(d->dyn, jid_full(pkt->from));
586 
587  jid_free(svc->jid);
588  xhash_free(svc->features);
589  free(svc);
590 
591  /* unify */
593  _disco_generate_packets(mod, d);
594  }
595 
596  /* done */
597  pkt_free(pkt);
598 
599  return mod_HANDLED;
600 }
601 
602 static void _disco_free_walker(const char *key, int keylen, void *val, void *arg) {
603  service_t svc = (service_t) val;
604 
605  jid_free(svc->jid);
606  xhash_free(svc->features);
607  free(svc);
608 }
609 
610 static void _disco_free(module_t mod) {
611  disco_t d = (disco_t) mod->private;
612 
614  xhash_walk(d->dyn, _disco_free_walker, NULL);
615 
616  xhash_free(d->stat);
617  xhash_free(d->dyn);
618  xhash_free(d->un);
619 
620  if(d->disco_info_result != NULL) pkt_free(d->disco_info_result);
622  if(d->agents_result != NULL) pkt_free(d->agents_result);
623 
624  free(d);
625 }
626 
627 DLLEXPORT int module_init(mod_instance_t mi, const char *arg)
628 {
629  module_t mod = mi->mod;
630  disco_t d;
631  nad_t nad;
632  int items, item, jid, name, category, type, ns;
633  service_t svc;
634 
635  if(mod->init) return 0;
636 
637  log_debug(ZONE, "disco module init");
638 
639  d = (disco_t) calloc(1, sizeof(struct disco_st));
640 
641  /* new hashes to store the lists in */
642  d->dyn = xhash_new(51);
643  d->stat = xhash_new(51);
644 
645  /* identity */
646  d->category = config_get_one(mod->mm->sm->config, "discovery.identity.category", 0);
647  if(d->category == NULL) d->category = "server";
648  d->type = config_get_one(mod->mm->sm->config, "discovery.identity.type", 0);
649  if(d->type == NULL) d->type = "im";
650  d->name = config_get_one(mod->mm->sm->config, "discovery.identity.name", 0);
651  if(d->name == NULL) d->name = "Jabber IM server";
652 
653  /* agents compatibility */
654  d->agents = config_get(mod->mm->sm->config, "discovery.agents") != NULL;
655 
656  if(d->agents)
657  log_debug(ZONE, "agents compat enabled");
658 
659  /* our data */
660  mod->private = (void *) d;
661 
662  /* our handlers */
663  mod->pkt_sm = _disco_pkt_sm;
664  mod->in_sess = _disco_in_sess;
665  mod->pkt_user = _disco_pkt_user;
667  mod->free = _disco_free;
668 
669  nad = mod->mm->sm->config->nad;
670 
671  /* we support a number of things */
674  if(d->agents)
676 
677  /* populate the static list from the config file */
678  if((items = nad_find_elem(nad, 0, -1, "discovery", 1)) < 0 || (items = nad_find_elem(nad, items, -1, "items", 1)) < 0)
679  return 0;
680 
681  item = nad_find_elem(nad, items, -1, "item", 1);
682  while(item >= 0)
683  {
684  /* jid is required */
685  jid = nad_find_attr(nad, item, -1, "jid", NULL);
686  if(jid < 0)
687  {
688  item = nad_find_elem(nad, item, -1, "item", 0);
689  continue;
690  }
691 
692  /* new service */
693  svc = (service_t) calloc(1, sizeof(struct service_st));
694 
695  svc->features = xhash_new(13);
696 
697  svc->jid = jid_new(NAD_AVAL(nad, jid), NAD_AVAL_L(nad, jid));
698 
699  /* link it in */
700  xhash_put(d->stat, jid_full(svc->jid), (void *) svc);
701 
702  /* copy the name */
703  name = nad_find_attr(nad, item, -1, "name", NULL);
704  if(name >= 0)
705  snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(nad, name), NAD_AVAL(nad, name));
706 
707  /* category and type */
708  category = nad_find_attr(nad, item, -1, "category", NULL);
709  if(category >= 0)
710  snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(nad, category), NAD_AVAL(nad, category));
711  else
712  strcpy(svc->category, "unknown");
713 
714  type = nad_find_attr(nad, item, -1, "type", NULL);
715  if(type >= 0)
716  snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(nad, type), NAD_AVAL(nad, type));
717  else
718  strcpy(svc->type, "unknown");
719 
720  /* namespaces */
721  ns = nad_find_elem(nad, item, -1, "ns", 1);
722  while(ns >= 0)
723  {
724  if(NAD_CDATA_L(nad, ns) > 0)
725  xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_CDATA(nad, ns), NAD_CDATA_L(nad, ns)), (void *) 1);
726 
727  ns = nad_find_elem(nad, ns, -1, "ns", 0);
728  }
729 
730  item = nad_find_elem(nad, item, -1, "item", 0);
731 
732  log_debug(ZONE, "added %s to static list", jid_full(svc->jid));
733  }
734 
735  /* generate the initial union list */
737 
738  /* we don't generate the packets here, because the router conn isn't up yet, and so we don't have a nad cache */
739 
740  return 0;
741 }
#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:745
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:534
#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:325
#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:338
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:346
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&#39;s to and from attributes
Definition: pkt.c:57
int nad_find_attr(nad_t nad, unsigned 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:237
single instance of a module in a chain
Definition: sm.h:446
static void _disco_user_result(pkt_t pkt, user_t user)
response to quering user JID
Definition: mod_disco.c:477
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
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:778
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:781
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:346
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
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:492
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:602
const char * name
Definition: mod_disco.c:51
#define DLLEXPORT
Definition: c2s.h:47
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:404
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:406
#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:272
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:548
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
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
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
jid_t to
Definition: sm.h:140
static void _disco_free(module_t mod)
Definition: mod_disco.c:610
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:372
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:402
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:278
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
#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:627
#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:292
route_type_t rtype
type of enclosing route
Definition: sm.h:136
xht features
feature index (key is feature string
Definition: sm.h:196