jabberd2
2.2.16
|
00001 /* 00002 * jabberd - Jabber Open Source Server 00003 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney, 00004 * Ryan Eatmon, Robert Norris 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00019 */ 00020 00021 #include "sm.h" 00022 00030 #define ACTIVE_SESSIONS_NAME "Active sessions" 00031 00033 typedef struct service_st *service_t; 00034 struct service_st { 00035 jid_t jid; 00036 00037 char name[257]; 00038 00039 char category[257]; 00040 char type[257]; 00041 00042 xht features; 00043 }; 00044 00046 typedef struct disco_st *disco_t; 00047 struct disco_st { 00049 char *category; 00050 char *type; 00051 char *name; 00052 00054 int agents; 00055 00057 xht dyn; 00058 xht stat; 00059 00061 xht un; 00062 00064 pkt_t disco_info_result; 00065 pkt_t disco_items_result; 00066 pkt_t agents_result; 00067 }; 00068 00069 /* union for xhash_iter_get to comply with strict-alias rules for gcc3 */ 00070 union xhashv 00071 { 00072 void **val; 00073 service_t *svc_val; 00074 sess_t *sess_val; 00075 const char **char_val; 00076 }; 00077 00079 static void _disco_unify_walker(const char *key, int keylen, void *val, void *arg) { 00080 service_t svc = (service_t) val; 00081 xht dest = (xht) arg; 00082 00083 /* if its already there, skip this one */ 00084 if(xhash_get(dest, jid_full(svc->jid)) != NULL) 00085 return; 00086 00087 log_debug(ZONE, "unify: %s", jid_full(svc->jid)); 00088 00089 xhash_put(dest, jid_full(svc->jid), (void *) svc); 00090 } 00091 00093 static void _disco_unify_lists(disco_t d) { 00094 log_debug(ZONE, "unifying lists"); 00095 00096 if(d->un != NULL) 00097 xhash_free(d->un); 00098 00099 d->un = xhash_new(101); 00100 00101 /* dynamic overrieds static */ 00102 xhash_walk(d->dyn, _disco_unify_walker, (void *) d->un); 00103 xhash_walk(d->stat, _disco_unify_walker, (void *) d->un); 00104 } 00105 00107 static pkt_t _disco_items_result(module_t mod, disco_t d) { 00108 pkt_t pkt; 00109 int ns; 00110 service_t svc; 00111 union xhashv xhv; 00112 00113 pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); 00114 ns = nad_add_namespace(pkt->nad, uri_DISCO_ITEMS, NULL); 00115 nad_append_elem(pkt->nad, ns, "query", 2); 00116 00117 if(xhash_iter_first(d->un)) 00118 do { 00119 xhv.svc_val = &svc; 00120 xhash_iter_get(d->un, NULL, NULL, xhv.val); 00121 00122 nad_append_elem(pkt->nad, ns, "item", 3); 00123 nad_append_attr(pkt->nad, -1, "jid", jid_full(svc->jid)); 00124 00125 if(svc->name[0] != '\0') 00126 nad_append_attr(pkt->nad, -1, "name", svc->name); 00127 } while(xhash_iter_next(d->un)); 00128 00129 return pkt; 00130 } 00131 00133 static pkt_t _disco_info_result(module_t mod, disco_t d) { 00134 pkt_t pkt; 00135 int el, ns; 00136 const char *key; 00137 int keylen; 00138 00139 pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); 00140 ns = nad_add_namespace(pkt->nad, uri_DISCO_INFO, NULL); 00141 nad_append_elem(pkt->nad, ns, "query", 2); 00142 00143 /* identity */ 00144 nad_append_elem(pkt->nad, ns, "identity", 3); 00145 nad_append_attr(pkt->nad, -1, "category", d->category); 00146 nad_append_attr(pkt->nad, -1, "type", d->type); 00147 nad_append_attr(pkt->nad, -1, "name", d->name); 00148 00149 /* fill in our features */ 00150 if(xhash_iter_first(mod->mm->sm->features)) 00151 do { 00152 xhash_iter_get(mod->mm->sm->features, &key, &keylen, NULL); 00153 00154 el = nad_append_elem(pkt->nad, ns, "feature", 3); 00155 nad_set_attr(pkt->nad, el, -1, "var", (char *) key, keylen); 00156 } while(xhash_iter_next(mod->mm->sm->features)); 00157 00158 /* put it throuhg disco_extend chain to add 00159 * XEP-0128 Service Discovery Extensions */ 00160 mm_disco_extend(mod->mm, pkt); 00161 00162 return pkt; 00163 } 00164 00166 static pkt_t _disco_agents_result(module_t mod, disco_t d) { 00167 pkt_t pkt; 00168 int ns; 00169 const char *key; 00170 int keylen; 00171 service_t svc; 00172 union xhashv xhv; 00173 00174 pkt = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); 00175 ns = nad_add_namespace(pkt->nad, uri_AGENTS, NULL); 00176 nad_append_elem(pkt->nad, ns, "query", 2); 00177 00178 /* fill in the items */ 00179 if(xhash_iter_first(d->un)) 00180 do { 00181 xhv.svc_val = &svc; 00182 xhash_iter_get(d->un, &key, &keylen, xhv.val); 00183 00184 nad_append_elem(pkt->nad, ns, "agent", 3); 00185 nad_append_attr(pkt->nad, -1, "jid", jid_full(svc->jid)); 00186 00187 if(svc->name[0] != '\0') { 00188 nad_append_elem(pkt->nad, ns, "name", 4); 00189 nad_append_cdata(pkt->nad, svc->name, strlen(svc->name), 5); 00190 } 00191 00192 nad_append_elem(pkt->nad, ns, "service", 4); 00193 nad_append_cdata(pkt->nad, svc->type, strlen(svc->type), 5); 00194 00195 /* map features to the old agent flags */ 00196 if(xhash_get(svc->features, uri_REGISTER) != NULL) 00197 nad_append_elem(pkt->nad, ns, "register", 4); 00198 if(xhash_get(svc->features, uri_SEARCH) != NULL) 00199 nad_append_elem(pkt->nad, ns, "search", 4); 00200 if(xhash_get(svc->features, uri_GATEWAY) != NULL) 00201 nad_append_elem(pkt->nad, ns, "transport", 4); 00202 00203 /* conference gets special treatment */ 00204 if(strcmp(svc->category, "conference") == 0) 00205 nad_append_elem(pkt->nad, ns, "groupchat", 4); 00206 } while(xhash_iter_next(d->un)); 00207 00208 return pkt; 00209 } 00210 00212 static void _disco_generate_packets(module_t mod, disco_t d) { 00213 log_debug(ZONE, "regenerating packets"); 00214 00215 if(d->disco_items_result != NULL) 00216 pkt_free(d->disco_items_result); 00217 d->disco_items_result = _disco_items_result(mod, d); 00218 00219 if(d->disco_info_result != NULL) 00220 pkt_free(d->disco_info_result); 00221 d->disco_info_result = _disco_info_result(mod, d); 00222 00223 if(d->agents) { 00224 if(d->agents_result != NULL) 00225 pkt_free(d->agents_result); 00226 d->agents_result = _disco_agents_result(mod, d); 00227 } 00228 00229 } 00230 00232 static mod_ret_t _disco_pkt_sm_populate(mod_instance_t mi, pkt_t pkt) 00233 { 00234 module_t mod = mi->mod; 00235 disco_t d = (disco_t) mod->private; 00236 int ns, qelem, elem, attr; 00237 service_t svc; 00238 00239 /* it has to come from the service itself - don't want any old user messing with the table */ 00240 if(pkt->from->node[0] != '\0' || pkt->from->resource[0] != '\0') 00241 { 00242 log_debug(ZONE, "disco response from %s, not allowed", jid_full(pkt->from)); 00243 return -stanza_err_NOT_ALLOWED; 00244 } 00245 00246 ns = nad_find_scoped_namespace(pkt->nad, uri_DISCO_INFO, NULL); 00247 qelem = nad_find_elem(pkt->nad, 1, ns, "query", 1); 00248 00249 elem = nad_find_elem(pkt->nad, qelem, ns, "identity", 1); 00250 if(elem < 0) 00251 return -stanza_err_BAD_REQUEST; 00252 00253 /* we don't want to list other im servers on the router */ 00254 if(nad_find_attr(pkt->nad, elem, -1, "category", "server") >= 0 00255 && nad_find_attr(pkt->nad, elem, -1, "type", "im") >= 0) { 00256 pkt_free(pkt); 00257 return mod_HANDLED; 00258 } 00259 00260 /* see if we already have this service */ 00261 svc = xhash_get(d->dyn, jid_full(pkt->from)); 00262 if(svc == NULL) 00263 { 00264 /* make a new one */ 00265 svc = (service_t) calloc(1, sizeof(struct service_st)); 00266 00267 svc->jid = jid_dup(pkt->from); 00268 00269 svc->features = xhash_new(11); 00270 00271 /* link it in */ 00272 xhash_put(d->dyn, jid_full(svc->jid), (void *) svc); 00273 00274 /* unify */ 00275 _disco_unify_lists(d); 00276 } 00277 00278 /* fill in the name */ 00279 attr = nad_find_attr(pkt->nad, elem, -1, "name", NULL); 00280 if(attr < 0) 00281 svc->name[0] = '\0'; 00282 else 00283 snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); 00284 00285 /* category and type */ 00286 attr = nad_find_attr(pkt->nad, elem, -1, "category", NULL); 00287 if(attr >= 0) 00288 snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); 00289 else 00290 strcpy(svc->category, "unknown"); 00291 00292 attr = nad_find_attr(pkt->nad, elem, -1, "type", NULL); 00293 if(attr >= 0) 00294 snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr)); 00295 else 00296 strcpy(svc->type, "unknown"); 00297 00298 /* features */ 00299 elem = nad_find_elem(pkt->nad, qelem, -1, "feature", 1); 00300 while(elem >= 0) 00301 { 00302 attr = nad_find_attr(pkt->nad, elem, -1, "var", NULL); 00303 if(attr < 0) 00304 { 00305 elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0); 00306 continue; 00307 } 00308 00309 xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)), (void *) 1); 00310 00311 elem = nad_find_elem(pkt->nad, elem, -1, "feature", 0); 00312 } 00313 00314 /* regenerate packets */ 00315 _disco_generate_packets(mod, d); 00316 00317 pkt_free(pkt); 00318 00319 return mod_HANDLED; 00320 } 00321 00323 static mod_ret_t _disco_in_sess_result(mod_instance_t mi, sess_t sess, pkt_t pkt) 00324 { 00325 /* it has to have no to address or self bare jid */ 00326 if(pkt->to != NULL && strcmp(jid_user(sess->jid), jid_full(pkt->to))) 00327 { 00328 return mod_PASS; 00329 } 00330 00331 /* identity */ 00332 nad_append_elem(pkt->nad, -1, "identity", 3); 00333 nad_append_attr(pkt->nad, -1, "category", "account"); 00334 nad_append_attr(pkt->nad, -1, "type", "registered"); 00335 00336 /* tell them */ 00337 nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); 00338 pkt_sess(pkt_tofrom(pkt), sess); 00339 00340 return mod_HANDLED; 00341 } 00342 00344 static void _disco_sessions_result(module_t mod, disco_t d, pkt_t pkt) { 00345 int ns; 00346 sess_t sess; 00347 union xhashv xhv; 00348 00349 ns = nad_add_namespace(pkt->nad, uri_DISCO_ITEMS, NULL); 00350 nad_append_elem(pkt->nad, ns, "query", 2); 00351 nad_append_attr(pkt->nad, -1, "node", "sessions"); 00352 00353 if(xhash_iter_first(mod->mm->sm->sessions)) 00354 do { 00355 xhv.sess_val = &sess; 00356 xhash_iter_get(mod->mm->sm->sessions, NULL, NULL, xhv.val); 00357 00358 nad_append_elem(pkt->nad, ns, "item", 3); 00359 nad_append_attr(pkt->nad, -1, "jid", jid_full(sess->jid)); 00360 nad_append_attr(pkt->nad, -1, "name", "Active session"); 00361 } while(xhash_iter_next(mod->mm->sm->sessions)); 00362 } 00363 00365 static mod_ret_t _disco_pkt_sm(mod_instance_t mi, pkt_t pkt) { 00366 module_t mod = mi->mod; 00367 disco_t d = (disco_t) mod->private; 00368 pkt_t result; 00369 int node, ns; 00370 00371 /* disco info results go to a seperate function */ 00372 if(pkt->type == pkt_IQ_RESULT && pkt->ns == ns_DISCO_INFO) 00373 return _disco_pkt_sm_populate(mi, pkt); 00374 00375 /* check whether the requested domain is serviced here */ 00376 if(xhash_get(mod->mm->sm->hosts, pkt->to->domain) == NULL) 00377 return -stanza_err_ITEM_NOT_FOUND; 00378 00379 /* we want disco or agents gets */ 00380 if(pkt->type != pkt_IQ || !(pkt->ns == ns_DISCO_INFO || pkt->ns == ns_DISCO_ITEMS || pkt->ns == ns_AGENTS)) 00381 return mod_PASS; 00382 00383 /* generate the caches if we haven't yet */ 00384 if(d->disco_info_result == NULL) 00385 _disco_generate_packets(mod, d); 00386 00387 node = nad_find_attr(pkt->nad, 2, -1, "node", NULL); 00388 00389 /* they want to know about us */ 00390 if(pkt->ns == ns_DISCO_INFO) { 00391 /* respond with cached disco info packet if no node given */ 00392 if(node < 0) { 00393 result = pkt_dup(d->disco_info_result, jid_full(pkt->from), jid_full(pkt->to)); 00394 00395 node = nad_find_attr(pkt->nad, 2, -1, "node", NULL); 00396 if(node >= 0) { 00397 nad_set_attr(result->nad, 2, -1, "node", NAD_AVAL(pkt->nad, node), NAD_AVAL_L(pkt->nad, node)); 00398 } 00399 00400 pkt_id(pkt, result); 00401 pkt_free(pkt); 00402 00403 /* off it goes */ 00404 pkt_router(result); 00405 00406 return mod_HANDLED; 00407 } 00408 else if(NAD_AVAL_L(pkt->nad, node) == 8 && strncmp("sessions", NAD_AVAL(pkt->nad, node), 8) == 0) { 00409 /* priviliged op, make sure they're allowed */ 00410 if(!aci_check(mod->mm->sm->acls, "disco", pkt->from)) 00411 return -stanza_err_ITEM_NOT_FOUND; /* we never advertised it, so we can pretend its not here */ 00412 00413 result = pkt_create(mod->mm->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to)); 00414 pkt_id(pkt, result); 00415 pkt_free(pkt); 00416 00417 ns = nad_add_namespace(result->nad, uri_DISCO_INFO, NULL); 00418 nad_append_elem(result->nad, ns, "query", 2); 00419 nad_append_elem(result->nad, ns, "identity", 3); 00420 nad_append_attr(result->nad, -1, "category", "hierarchy"); 00421 nad_append_attr(result->nad, -1, "type", "branch"); 00422 nad_append_attr(result->nad, -1, "name", ACTIVE_SESSIONS_NAME); 00423 nad_append_elem(result->nad, -1, "feature", 3); 00424 nad_append_attr(result->nad, -1, "var", uri_DISCO_INFO); 00425 nad_append_elem(result->nad, -1, "feature", 3); 00426 nad_append_attr(result->nad, -1, "var", uri_DISCO_ITEMS); 00427 00428 /* off it goes */ 00429 pkt_router(result); 00430 00431 return mod_HANDLED; 00432 } 00433 else 00434 return -stanza_err_ITEM_NOT_FOUND; 00435 } 00436 00437 /* handle agents */ 00438 if(pkt->ns == ns_AGENTS) { 00439 /* make sure we're supporting compat */ 00440 if(!d->agents) 00441 return -stanza_err_NOT_ALLOWED; 00442 00443 result = pkt_dup(d->agents_result, jid_full(pkt->from), jid_full(pkt->to)); 00444 pkt_id(pkt, result); 00445 pkt_free(pkt); 00446 00447 /* off it goes */ 00448 pkt_router(result); 00449 00450 return mod_HANDLED; 00451 } 00452 00453 /* they want to know who we know about */ 00454 if(node < 0) { 00455 /* no node, so toplevel services */ 00456 result = pkt_dup(d->disco_items_result, jid_full(pkt->from), jid_full(pkt->to)); 00457 pkt_id(pkt, result); 00458 pkt_free(pkt); 00459 00460 /* if they have privs, then show them any administrative things they can disco to */ 00461 if(aci_check(mod->mm->sm->acls, "disco", result->to)) { 00462 nad_append_elem(result->nad, NAD_ENS(result->nad, 2), "item", 3); 00463 nad_append_attr(result->nad, -1, "jid", jid_full(result->from)); 00464 nad_append_attr(result->nad, -1, "node", "sessions"); 00465 nad_append_attr(result->nad, -1, "name", ACTIVE_SESSIONS_NAME); 00466 } 00467 00468 pkt_router(result); 00469 00470 return mod_HANDLED; 00471 } 00472 00473 /* active sessions */ 00474 if(NAD_AVAL_L(pkt->nad, node) == 8 && strncmp("sessions", NAD_AVAL(pkt->nad, node), 8) == 0) { 00475 /* priviliged op, make sure they're allowed */ 00476 if(!aci_check(mod->mm->sm->acls, "disco", pkt->from)) 00477 return -stanza_err_ITEM_NOT_FOUND; /* we never advertised it, so we can pretend its not here */ 00478 00479 result = pkt_create(mod->mm->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to)); 00480 pkt_id(pkt, result); 00481 pkt_free(pkt); 00482 00483 _disco_sessions_result(mod, d, result); 00484 00485 /* off it goes */ 00486 pkt_router(result); 00487 00488 return mod_HANDLED; 00489 } 00490 00491 /* I dunno what they're asking for */ 00492 return -stanza_err_ITEM_NOT_FOUND; 00493 } 00494 00496 static mod_ret_t _disco_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { 00497 module_t mod = mi->mod; 00498 disco_t d = (disco_t) mod->private; 00499 pkt_t result; 00500 00501 /* disco info requests go to a seperate function */ 00502 if(pkt->type == pkt_IQ && pkt->ns == ns_DISCO_INFO) 00503 return _disco_in_sess_result(mi, sess, pkt); 00504 00505 /* we want agents gets */ 00506 if(pkt->type != pkt_IQ || pkt->ns != ns_AGENTS || pkt->to != NULL) 00507 return mod_PASS; 00508 00509 /* fail if its not enabled */ 00510 if(!d->agents) 00511 return -stanza_err_NOT_ALLOWED; 00512 00513 /* generate the caches if we haven't yet */ 00514 if(d->disco_info_result == NULL) 00515 _disco_generate_packets(mod, d); 00516 00517 /* pre-canned response */ 00518 result = pkt_dup(d->agents_result, NULL, NULL); 00519 pkt_id(pkt, result); 00520 pkt_free(pkt); 00521 00522 /* off it goes */ 00523 pkt_sess(result, sess); 00524 00525 return mod_HANDLED; 00526 } 00527 00529 static mod_ret_t _disco_pkt_router(mod_instance_t mi, pkt_t pkt) 00530 { 00531 module_t mod = mi->mod; 00532 disco_t d = (disco_t) mod->private; 00533 service_t svc; 00534 pkt_t request; 00535 int ns; 00536 00537 /* we want advertisements with a from address */ 00538 if(pkt->from == NULL || !(pkt->rtype & route_ADV)) 00539 return mod_PASS; 00540 00541 /* component online */ 00542 if(pkt->rtype == route_ADV) 00543 { 00544 log_debug(ZONE, "presence from component %s, issuing discovery request", jid_full(pkt->from)); 00545 00546 /* new disco get packet */ 00547 request = pkt_create(mod->mm->sm, "iq", "get", jid_full(pkt->from), mod->mm->sm->id); 00548 pkt_id_new(request); 00549 ns = nad_add_namespace(request->nad, uri_DISCO_INFO, NULL); 00550 nad_append_elem(request->nad, ns, "query", 2); 00551 00552 pkt_router(request); 00553 00554 /* done with this */ 00555 pkt_free(pkt); 00556 00557 return mod_HANDLED; 00558 } 00559 00560 /* it went away. find it and remove it */ 00561 svc = xhash_get(d->dyn, jid_full(pkt->from)); 00562 if(svc != NULL) 00563 { 00564 log_debug(ZONE, "dropping entry for %s", jid_full(pkt->from)); 00565 00566 xhash_zap(d->dyn, jid_full(pkt->from)); 00567 00568 jid_free(svc->jid); 00569 xhash_free(svc->features); 00570 free(svc); 00571 00572 /* unify */ 00573 _disco_unify_lists(d); 00574 _disco_generate_packets(mod, d); 00575 } 00576 00577 /* done */ 00578 pkt_free(pkt); 00579 00580 return mod_HANDLED; 00581 } 00582 00583 static void _disco_free_walker(const char *key, int keylen, void *val, void *arg) { 00584 service_t svc = (service_t) val; 00585 00586 jid_free(svc->jid); 00587 xhash_free(svc->features); 00588 free(svc); 00589 } 00590 00591 static void _disco_free(module_t mod) { 00592 disco_t d = (disco_t) mod->private; 00593 00594 xhash_walk(d->stat, _disco_free_walker, NULL); 00595 xhash_walk(d->dyn, _disco_free_walker, NULL); 00596 00597 xhash_free(d->stat); 00598 xhash_free(d->dyn); 00599 xhash_free(d->un); 00600 00601 if(d->disco_info_result != NULL) pkt_free(d->disco_info_result); 00602 if(d->disco_items_result != NULL) pkt_free(d->disco_items_result); 00603 if(d->agents_result != NULL) pkt_free(d->agents_result); 00604 00605 free(d); 00606 } 00607 00608 DLLEXPORT int module_init(mod_instance_t mi, char *arg) 00609 { 00610 module_t mod = mi->mod; 00611 disco_t d; 00612 nad_t nad; 00613 int items, item, jid, name, category, type, ns; 00614 service_t svc; 00615 00616 if(mod->init) return 0; 00617 00618 log_debug(ZONE, "disco module init"); 00619 00620 d = (disco_t) calloc(1, sizeof(struct disco_st)); 00621 00622 /* new hashes to store the lists in */ 00623 d->dyn = xhash_new(51); 00624 d->stat = xhash_new(51); 00625 00626 /* identity */ 00627 d->category = config_get_one(mod->mm->sm->config, "discovery.identity.category", 0); 00628 if(d->category == NULL) d->category = "server"; 00629 d->type = config_get_one(mod->mm->sm->config, "discovery.identity.type", 0); 00630 if(d->type == NULL) d->type = "im"; 00631 d->name = config_get_one(mod->mm->sm->config, "discovery.identity.name", 0); 00632 if(d->name == NULL) d->name = "Jabber IM server"; 00633 00634 /* agents compatibility */ 00635 d->agents = config_get(mod->mm->sm->config, "discovery.agents") != NULL; 00636 00637 if(d->agents) 00638 log_debug(ZONE, "agents compat enabled"); 00639 00640 /* our data */ 00641 mod->private = (void *) d; 00642 00643 /* our handlers */ 00644 mod->pkt_sm = _disco_pkt_sm; 00645 mod->in_sess = _disco_in_sess; 00646 mod->pkt_router = _disco_pkt_router; 00647 mod->free = _disco_free; 00648 00649 nad = mod->mm->sm->config->nad; 00650 00651 /* we support a number of things */ 00652 feature_register(mod->mm->sm, uri_DISCO_INFO); 00653 feature_register(mod->mm->sm, uri_DISCO_ITEMS); 00654 if(d->agents) 00655 feature_register(mod->mm->sm, uri_AGENTS); 00656 00657 /* populate the static list from the config file */ 00658 if((items = nad_find_elem(nad, 0, -1, "discovery", 1)) < 0 || (items = nad_find_elem(nad, items, -1, "items", 1)) < 0) 00659 return 0; 00660 00661 item = nad_find_elem(nad, items, -1, "item", 1); 00662 while(item >= 0) 00663 { 00664 /* jid is required */ 00665 jid = nad_find_attr(nad, item, -1, "jid", NULL); 00666 if(jid < 0) 00667 { 00668 item = nad_find_elem(nad, item, -1, "item", 0); 00669 continue; 00670 } 00671 00672 /* new service */ 00673 svc = (service_t) calloc(1, sizeof(struct service_st)); 00674 00675 svc->features = xhash_new(13); 00676 00677 svc->jid = jid_new(NAD_AVAL(nad, jid), NAD_AVAL_L(nad, jid)); 00678 00679 /* link it in */ 00680 xhash_put(d->stat, jid_full(svc->jid), (void *) svc); 00681 00682 /* copy the name */ 00683 name = nad_find_attr(nad, item, -1, "name", NULL); 00684 if(name >= 0) 00685 snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(nad, name), NAD_AVAL(nad, name)); 00686 00687 /* category and type */ 00688 category = nad_find_attr(nad, item, -1, "category", NULL); 00689 if(category >= 0) 00690 snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(nad, category), NAD_AVAL(nad, category)); 00691 else 00692 strcpy(svc->category, "unknown"); 00693 00694 type = nad_find_attr(nad, item, -1, "type", NULL); 00695 if(type >= 0) 00696 snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(nad, type), NAD_AVAL(nad, type)); 00697 else 00698 strcpy(svc->type, "unknown"); 00699 00700 /* namespaces */ 00701 ns = nad_find_elem(nad, item, -1, "ns", 1); 00702 while(ns >= 0) 00703 { 00704 if(NAD_CDATA_L(nad, ns) > 0) 00705 xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_CDATA(nad, ns), NAD_CDATA_L(nad, ns)), (void *) 1); 00706 00707 ns = nad_find_elem(nad, ns, -1, "ns", 0); 00708 } 00709 00710 item = nad_find_elem(nad, item, -1, "item", 0); 00711 00712 log_debug(ZONE, "added %s to static list", jid_full(svc->jid)); 00713 } 00714 00715 /* generate the initial union list */ 00716 _disco_unify_lists(d); 00717 00718 /* we don't generate the packets here, because the router conn isn't up yet, and so we don't have a nad cache */ 00719 00720 return 0; 00721 }