jabberd2  2.2.16
sm/mod_disco.c
Go to the documentation of this file.
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 }