📄 mod_disco.c
字号:
}/** build a disco items result, active sessions */static void _disco_sessions_result(module_t mod, disco_t d, pkt_t pkt) { int ns; sess_t sess; ns = nad_add_namespace(pkt->nad, uri_DISCO_ITEMS, NULL); nad_append_elem(pkt->nad, ns, "query", 2); nad_append_attr(pkt->nad, -1, "node", "sessions"); if(xhash_iter_first(mod->mm->sm->sessions)) do { xhash_iter_get(mod->mm->sm->sessions, NULL, (void **) &sess); nad_append_elem(pkt->nad, ns, "item", 3); nad_append_attr(pkt->nad, -1, "jid", jid_full(sess->jid)); nad_append_attr(pkt->nad, -1, "name", "Active session"); } while(xhash_iter_next(mod->mm->sm->sessions));}/** catch responses and populate the table; respond to requests */static mod_ret_t _disco_pkt_sm(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; disco_t d = (disco_t) mod->private; pkt_t result; int node; /* disco info results go to a seperate function */ if(pkt->type == pkt_IQ_RESULT && pkt->ns == ns_DISCO_INFO) return _disco_pkt_sm_populate(mi, pkt); /* we want disco, browse or agents gets */ if(pkt->type != pkt_IQ || !(pkt->ns == ns_DISCO_INFO || pkt->ns == ns_DISCO_ITEMS || pkt->ns == ns_BROWSE || pkt->ns == ns_AGENTS)) return mod_PASS; /* generate the caches if we haven't yet */ if(d->disco_info_result == NULL) _disco_generate_packets(mod, d); /* they want to know about us */ if(pkt->ns == ns_DISCO_INFO) { result = pkt_dup(d->disco_info_result, jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, result); pkt_free(pkt); /* off it goes */ pkt_router(result); return mod_HANDLED; } /* handle agents */ if(pkt->ns == ns_AGENTS) { /* make sure we're supporting compat */ if(!d->agents) return -stanza_err_NOT_ALLOWED; result = pkt_dup(d->agents_result, jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, result); pkt_free(pkt); /* off it goes */ pkt_router(result); return mod_HANDLED; } /* handle browse */ if(pkt->ns == ns_BROWSE) { /* make sure we're supporting compat */ if(!d->browse) return -stanza_err_NOT_ALLOWED; result = pkt_dup(d->browse_result, jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, result); pkt_free(pkt); /* off it goes */ pkt_router(result); return mod_HANDLED; } /* they want to know who we know about */ node = nad_find_attr(pkt->nad, 2, -1, "node", NULL); if(node < 0) { /* no node, so toplevel services */ result = pkt_dup(d->disco_items_result, jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, result); pkt_free(pkt); /* if they have privs, them show them any administrative things they can disco to */ if(aci_check(mod->mm->sm->acls, "disco", result->to)) { nad_append_elem(result->nad, NAD_ENS(result->nad, 2), "item", 3); nad_append_attr(result->nad, -1, "jid", mod->mm->sm->id); nad_append_attr(result->nad, -1, "node", "sessions"); nad_append_attr(result->nad, -1, "name", "Active sessions"); } pkt_router(result); return mod_HANDLED; } /* active sessions */ if(NAD_AVAL_L(pkt->nad, node) == 8 && strncmp("sessions", NAD_AVAL(pkt->nad, node), 8) == 0) { /* priviliged op, make sure they're allowed */ if(!aci_check(mod->mm->sm->acls, "disco", pkt->from)) return -stanza_err_ITEM_NOT_FOUND; /* we never advertised it, so we can pretend its not here */ result = pkt_create(mod->mm->sm, "iq", "result", jid_full(pkt->from), jid_full(pkt->to)); pkt_id(pkt, result); pkt_free(pkt); _disco_sessions_result(mod, d, result); /* off it goes */ pkt_router(result); return mod_HANDLED; } /* I dunno what they're asking for */ return -stanza_err_ITEM_NOT_FOUND;}/** legacy support for agents requests from sessions */static mod_ret_t _disco_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; disco_t d = (disco_t) mod->private; pkt_t result; /* we want agents gets */ if(pkt->type != pkt_IQ || pkt->ns != ns_AGENTS || pkt->to != NULL) return mod_PASS; /* fail if its not enabled */ if(!d->agents) return -stanza_err_NOT_ALLOWED; /* generate the caches if we haven't yet */ if(d->disco_info_result == NULL) _disco_generate_packets(mod, d); /* pre-canned response */ result = pkt_dup(d->agents_result, NULL, NULL); pkt_id(pkt, result); pkt_free(pkt); /* off it goes */ pkt_sess(result, sess); return mod_HANDLED;}/** update the table for component changes */static mod_ret_t _disco_pkt_router(mod_instance_t mi, pkt_t pkt){ module_t mod = mi->mod; disco_t d = (disco_t) mod->private; service_t svc; pkt_t request; int ns; /* we want advertisements with a from address */ if(pkt->from == NULL || !(pkt->rtype & route_ADV)) return mod_PASS; /* component online */ if(pkt->rtype == route_ADV) { log_debug(ZONE, "presence from component %s, issuing discovery request", jid_full(pkt->from)); /* new disco get packet */ request = pkt_create(mod->mm->sm, "iq", "get", jid_full(pkt->from), mod->mm->sm->id); ns = nad_add_namespace(request->nad, uri_DISCO_INFO, NULL); nad_append_elem(request->nad, ns, "query", 2); pkt_router(request); /* done with this */ pkt_free(pkt); return mod_HANDLED; } /* it went away. find it and remove it */ svc = xhash_get(d->dyn, jid_full(pkt->from)); if(svc != NULL) { log_debug(ZONE, "dropping entry for %s", jid_full(pkt->from)); xhash_zap(d->dyn, jid_full(pkt->from)); jid_free(svc->jid); xhash_free(svc->features); free(svc); /* unify */ _disco_unify_lists(d); _disco_generate_packets(mod, d); } /* done */ pkt_free(pkt); return mod_HANDLED;}static void _disco_free_walker(xht h, const char *key, void *val, void *arg) { service_t svc = (service_t) val; jid_free(svc->jid); xhash_free(svc->features); free(svc);}static void _disco_free(module_t mod) { disco_t d = (disco_t) mod->private; xhash_walk(d->stat, _disco_free_walker, NULL); xhash_walk(d->dyn, _disco_free_walker, NULL); xhash_free(d->stat); xhash_free(d->dyn); xhash_free(d->un); if(d->disco_info_result != NULL) pkt_free(d->disco_info_result); if(d->disco_items_result != NULL) pkt_free(d->disco_items_result); if(d->agents_result != NULL) pkt_free(d->agents_result); if(d->browse_result != NULL) pkt_free(d->browse_result); free(d);}int disco_init(mod_instance_t mi, char *arg){ module_t mod = mi->mod; disco_t d; nad_t nad; int items, item, jid, name, category, type, ns; service_t svc; if(mod->init) return 0; log_debug(ZONE, "disco module init"); d = (disco_t) malloc(sizeof(struct disco_st)); memset(d, 0, sizeof(struct disco_st)); /* new hashes to store the lists in */ d->dyn = xhash_new(51); d->stat = xhash_new(51); /* identity */ d->category = config_get_one(mod->mm->sm->config, "discovery.identity.category", 0); if(d->category == NULL) d->category = "server"; d->type = config_get_one(mod->mm->sm->config, "discovery.identity.type", 0); if(d->type == NULL) d->type = "im"; d->name = config_get_one(mod->mm->sm->config, "discovery.identity.name", 0); if(d->name == NULL) d->name = "Jabber IM server"; /* agents compatibility */ d->agents = (int) config_get(mod->mm->sm->config, "discovery.agents"); /* browse compatibility */ /* CODE READERS, NOTE WELL: Browse is very deprecated. Don't use this :) */ d->browse = (int) config_get(mod->mm->sm->config, "discovery.browse"); if(d->agents) log_debug(ZONE, "agents compat enabled"); if(d->browse) log_debug(ZONE, "browse compat enabled"); /* our data */ mod->private = (void *) d; /* our handlers */ mod->pkt_sm = _disco_pkt_sm; mod->in_sess = _disco_in_sess; mod->pkt_router = _disco_pkt_router; mod->free = _disco_free; nad = mod->mm->sm->config->nad; /* we support a number of things */ feature_register(mod->mm->sm, uri_DISCO); if(d->agents) feature_register(mod->mm->sm, uri_AGENTS); if(d->browse) feature_register(mod->mm->sm, uri_BROWSE); /* populate the static list from the config file */ if((items = nad_find_elem(nad, 0, -1, "discovery", 1)) < 0 || (items = nad_find_elem(nad, items, -1, "items", 1)) < 0) return 0; item = nad_find_elem(nad, items, -1, "item", 1); while(item >= 0) { /* jid is required */ jid = nad_find_attr(nad, item, -1, "jid", NULL); if(jid < 0) { item = nad_find_elem(nad, item, -1, "item", 0); continue; } /* new service */ svc = (service_t) malloc(sizeof(struct service_st)); memset(svc, 0, sizeof(struct service_st)); svc->features = xhash_new(13); svc->jid = jid_new(mod->mm->sm->pc, NAD_AVAL(nad, jid), NAD_AVAL_L(nad, jid)); /* link it in */ xhash_put(d->stat, jid_full(svc->jid), (void *) svc); /* copy the name */ name = nad_find_attr(nad, item, -1, "name", NULL); if(name >= 0) snprintf(svc->name, 257, "%.*s", NAD_AVAL_L(nad, name), NAD_AVAL(nad, name)); /* category and type */ category = nad_find_attr(nad, item, -1, "category", NULL); if(category >= 0) snprintf(svc->category, 257, "%.*s", NAD_AVAL_L(nad, category), NAD_AVAL(nad, category)); else strcpy(svc->category, "unknown"); type = nad_find_attr(nad, item, -1, "type", NULL); if(type >= 0) snprintf(svc->type, 257, "%.*s", NAD_AVAL_L(nad, type), NAD_AVAL(nad, type)); else strcpy(svc->type, "unknown"); /* namespaces */ ns = nad_find_elem(nad, item, -1, "ns", 1); while(ns >= 0) { if(NAD_CDATA_L(nad, ns) > 0) xhash_put(svc->features, pstrdupx(xhash_pool(svc->features), NAD_CDATA(nad, ns), NAD_CDATA_L(nad, ns)), (void *) 1); ns = nad_find_elem(nad, ns, -1, "ns", 0); } item = nad_find_elem(nad, item, -1, "item", 0); log_debug(ZONE, "added %s to static list", jid_full(svc->jid)); } /* generate the initial union list */ _disco_unify_lists(d); /* we don't generate the packets here, because the router conn isn't up yet, and so we don't have a nad cache */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -