/** fetch user data */ user_t user_load(sm_t sm, jid_t jid) { user_t user; /* already loaded */ user = xhash_get(sm->users, jid_user(jid)); if(user != NULL) { log_debug(ZONE, "returning previously-created user data for %s", jid_user(jid)); return user; } /* make a new one */ user = _user_alloc(sm, jid); /* get modules to setup */ if(mm_user_load(sm->mm, user) != 0) { log_debug(ZONE, "modules failed user load for %s", jid_user(jid)); pool_free(user->p); return NULL; } /* save them for later */ xhash_put(sm->users, jid_user(user->jid), (void *) user); log_debug(ZONE, "loaded user data for %s", jid_user(jid)); return user; }
/** trash a user */ void user_delete(sm_t sm, jid_t jid) { user_t user; sess_t scan, next; log_debug(ZONE, "delete user request for %s", jid_user(jid)); user = user_load(sm, jid); if(user == NULL) { log_debug(ZONE, "user doesn't exist, can't delete"); return; } /* close their sessions first (this will free user, after the last session ends) */ scan = user->sessions; while(scan != NULL) { next = scan->next; sm_c2s_action(scan, "ended", NULL); sess_end(scan); scan = next; } mm_user_delete(sm->mm, jid); log_write(sm->log, LOG_NOTICE, "deleted user: jid=%s", jid_user(jid)); }
/** initialise a user */ int user_create(sm_t sm, jid_t jid) { user_t user; log_debug(ZONE, "create user request for %s", jid_user(jid)); /* check whether it is to serviced domain */ if(xhash_get(sm->hosts, jid->domain) == NULL) { log_write(sm->log, LOG_ERR, "request to create user for non-serviced domain: jid=%s", jid_user(jid)); log_debug(ZONE, "no such domain, not creating"); return 1; } user = user_load(sm, jid); if(user != NULL) { log_write(sm->log, LOG_ERR, "request to create already-active user: jid=%s", jid_user(jid)); log_debug(ZONE, "user already active, not creating"); return 1; } /* modules create */ if(mm_user_create(sm->mm, jid) != 0) { log_write(sm->log, LOG_ERR, "user creation failed: jid=%s", jid_user(jid)); log_debug(ZONE, "user create failed, forcing deletion for cleanup"); mm_user_delete(sm->mm, jid); return 1; } log_write(sm->log, LOG_NOTICE, "created user: jid=%s", jid_user(jid)); return 0; }
/* drop incoming presence if the user isn't around, * so we don't have to load them during broadcasts */ mod_ret_t _presence_in_router(mod_instance_t mi, pkt_t pkt) { user_t user; sess_t sess; /* only check presence to users, pass presence to sm and probes */ if(!(pkt->type & pkt_PRESENCE) || pkt->to->node[0] == '\0' || pkt->type == pkt_PRESENCE_PROBE) return mod_PASS; /* get the user _without_ doing a load */ user = xhash_get(mi->mod->mm->sm->users, jid_user(pkt->to)); /* no user, or no sessions, bail */ if(user == NULL || user->sessions == NULL) { pkt_free(pkt); return mod_HANDLED; } /* only pass if there's at least one available session */ for(sess = user->sessions; sess != NULL; sess = sess->next) if(sess->available) return mod_PASS; /* no available sessions, drop */ pkt_free(pkt); return mod_HANDLED; }
static int _vacation_user_load(mod_instance_t mi, user_t user) { module_t mod = mi->mod; vacation_t v; os_t os; os_object_t o; v = (vacation_t) calloc(1, sizeof(struct _vacation_st)); user->module_data[mod->index] = v; if(storage_get(mod->mm->sm->st, "vacation-settings", jid_user(user->jid), NULL, &os) == st_SUCCESS) { if(os_iter_first(os)) { o = os_iter_object(os); if(os_object_get_time(os, o, "start", &v->start) && os_object_get_time(os, o, "end", &v->end) && os_object_get_str(os, o, "message", &v->msg)) v->msg = strdup(v->msg); else { v->start = 0; v->end = 0; v->msg = NULL; } } os_free(os); } pool_cleanup(user->p, (void (*))(void *) _vacation_user_free, v); return 0; }
static void _roster_publish_save_item(user_t user, item_t item) { os_t os; os_object_t o; char filter[4096]; int i; log_debug(ZONE, "saving roster item %s for %s", jid_full(item->jid), jid_user(user->jid)); os = os_new(); o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); if(item->name != NULL) os_object_put(o, "name", item->name, os_type_STRING); os_object_put(o, "to", &item->to, os_type_BOOLEAN); os_object_put(o, "from", &item->from, os_type_BOOLEAN); os_object_put(o, "ask", &item->ask, os_type_INTEGER); snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid)); storage_replace(user->sm->st, "roster-items", jid_user(user->jid), filter, os); os_free(os); snprintf(filter, 4096, "(jid=%s)", jid_full(item->jid)); if(item->ngroups == 0) { storage_delete(user->sm->st, "roster-groups", jid_user(user->jid), filter); return; } os = os_new(); for(i = 0; i < item->ngroups; i++) { o = os_object_new(os); os_object_put(o, "jid", jid_full(item->jid), os_type_STRING); os_object_put(o, "group", item->groups[i], os_type_STRING); } storage_replace(user->sm->st, "roster-groups", jid_user(user->jid), filter, os); os_free(os); }
static int _active_user_create(mod_instance_t mi, jid_t jid) { time_t t; os_t os; os_object_t o; log_debug(ZONE, "activating user %s", jid_user(jid)); t = time(NULL); os = os_new(); o = os_object_new(os); os_object_put_time(o, "time", &t); storage_put(mi->sm->st, "active", jid_user(jid), os); os_free(os); return 0; }
/* presence packets to the sm */ static mod_ret_t _presence_pkt_sm(mod_instance_t mi, pkt_t pkt) { module_t mod = mi->mod; jid_t smjid; /* only check presence/subs to server JID */ if(!(pkt->type & pkt_PRESENCE || pkt->type & pkt_S10N)) return mod_PASS; smjid = jid_new(jid_user(pkt->to), -1); /* handle subscription requests */ if(pkt->type == pkt_S10N) { log_debug(ZONE, "accepting subscription request from %s", jid_full(pkt->from)); /* accept request */ pkt_router(pkt_create(mod->mm->sm, "presence", "subscribed", jid_user(pkt->from), jid_user(smjid))); /* and subscribe back to theirs */ pkt_router(pkt_create(mod->mm->sm, "presence", "subscribe", jid_user(pkt->from), jid_user(smjid))); pkt_free(pkt); jid_free(smjid); return mod_HANDLED; } /* handle unsubscribe requests */ if(pkt->type == pkt_S10N_UN) { log_debug(ZONE, "accepting unsubscribe request from %s", jid_full(pkt->from)); /* ack the request */ pkt_router(pkt_create(mod->mm->sm, "presence", "unsubscribed", jid_user(pkt->from), jid_user(smjid))); pkt_free(pkt); jid_free(smjid); return mod_HANDLED; } /* drop the rest */ log_debug(ZONE, "dropping presence from %s", jid_full(pkt->from)); pkt_free(pkt); jid_free(smjid); return mod_HANDLED; }
mreturn mod_roster_auto_in_s10n(mapi m, void *arg) { xmlnode reply, x; log_debug("AUTO ROSTER"); //in not s10n if (m->packet->type != JPACKET_S10N) return M_IGNORE; //if no to if (m->packet->to == NULL) return M_PASS; //if from me if (jid_cmpx(m->s->uid, m->packet->from, JID_USER | JID_SERVER) == 0) return M_PASS; log_debug("handling incoming s10n"); switch (jpacket_subtype(m->packet)) { case JPACKET__SUBSCRIBE: log_debug("SUBSCRIBE"); reply = jutil_presnew(JPACKET__SUBSCRIBED, jid_full(m->packet->from), NULL); js_session_from(m->s, jpacket_new(reply)); reply = jutil_presnew(JPACKET__SUBSCRIBE, jid_full(m->packet->from), NULL); js_session_from(m->s, jpacket_new(reply)); break; case JPACKET__SUBSCRIBED: break; case JPACKET__UNSUBSCRIBE: log_debug("UNSUBSCRIBE"); //reply = jutil_presnew(JPACKET__UNSUBSCRIBED, jid_full(m->packet->from),NULL); //js_session_from(m->s, jpacket_new(reply)); //remove account. reply = jutil_iqnew(JPACKET__SET, NS_ROSTER); x = xmlnode_get_tag(reply, "query"); x = xmlnode_insert_tag(x, "item"); xmlnode_put_attrib(x, "jid", jid_full(jid_user(m->packet->from))); xmlnode_put_attrib(x, "subscription", "remove"); js_session_from(m->s, jpacket_new(reply)); // reply = jutil_iqnewpresnew(JPACKET__UNSUBSCRIBE, jid_full(m->packet->from),NULL); // js_session_from(m->s, jpacket_new(reply)); break; case JPACKET__UNSUBSCRIBED: break; } xmlnode_free(m->packet->x); return M_HANDLED; }
/** see if a jid is in an acl */ int aci_check(xht acls, char *type, jid_t jid) { jid_t list, dup; dup = jid_dup(jid); if (dup->resource[0]) { /* resourceless version */ dup->resource[0] = '\0'; dup->dirty = 1; } log_debug(ZONE, "checking for '%s' in acl 'all'", jid_full(jid)); list = (jid_t) xhash_get(acls, "all"); if(jid_search(list, jid)) { jid_free(dup); return 1; } log_debug(ZONE, "checking for '%s' in acl 'all'", jid_user(dup)); if(jid_search(list, dup)) { jid_free(dup); return 1; } if(type != NULL) { log_debug(ZONE, "checking for '%s' in acl '%s'", jid_full(jid), type); list = (jid_t) xhash_get(acls, type); if(jid_search(list, jid)) { jid_free(dup); return 1; } log_debug(ZONE, "checking for '%s' in acl '%s'", jid_user(dup), type); if(jid_search(list, dup)) { jid_free(dup); return 1; } } jid_free(dup); return 0; }
xht aci_load(sm_t sm) { xht acls; int aelem, jelem, attr; char type[33]; jid_t list, jid; log_debug(ZONE, "loading aci"); acls = xhash_new(51); if((aelem = nad_find_elem(sm->config->nad, 0, -1, "aci", 1)) < 0) return acls; aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 1); while(aelem >= 0) { list = NULL; if((attr = nad_find_attr(sm->config->nad, aelem, -1, "type", NULL)) < 0) { aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 0); continue; } snprintf(type, 33, "%.*s", NAD_AVAL_L(sm->config->nad, attr), NAD_AVAL(sm->config->nad, attr)); log_debug(ZONE, "building list for '%s'", type); jelem = nad_find_elem(sm->config->nad, aelem, -1, "jid", 1); while(jelem >= 0) { if(NAD_CDATA_L(sm->config->nad, jelem) > 0) { jid = jid_new(NAD_CDATA(sm->config->nad, jelem), NAD_CDATA_L(sm->config->nad, jelem)); list = jid_append(list, jid); log_debug(ZONE, "added '%s'", jid_user(jid)); jid_free(jid); } jelem = nad_find_elem(sm->config->nad, jelem, -1, "jid", 0); } if(list != NULL) { xhash_put(acls, pstrdup(xhash_pool(acls), type), (void *) list); } aelem = nad_find_elem(sm->config->nad, aelem, -1, "acl", 0); } return acls; }
/** free the roster */ static void _roster_free(user_t user) { if(user->roster == NULL) return; log_debug(ZONE, "freeing roster for %s", jid_user(user->jid)); xhash_walk(user->roster, _roster_free_walker, NULL); xhash_free(user->roster); user->roster = NULL; }
static int _active_user_load(mod_instance_t mi, user_t user) { os_t os; os_object_t o; /* get their active status */ if(storage_get(user->sm->st, "active", jid_user(user->jid), NULL, &os) == st_SUCCESS && os_iter_first(os)) { o = os_iter_object(os); os_object_get_time(os, o, "time", &user->active); os_free(os); } else /* can't load them if they're inactive */ return 1; return 0; }
void sess_end(sess_t sess) { log_debug(ZONE, "shutting down session %s", jid_full(sess->jid)); _sess_end_guts(sess); log_write(sess->user->sm->log, LOG_NOTICE, "session ended: jid=%s", jid_full(sess->jid)); /* if it was the last session, free the user */ if(sess->user->sessions == NULL) { mm_user_unload(sess->user->sm->mm, sess->user); log_write(sess->user->sm->log, LOG_NOTICE, "user unloaded jid=%s", jid_user(sess->jid)); user_free(sess->user); } /* free the session */ pool_free(sess->p); }
mreturn mod_browse_server(mapi m, void *arg) { xmlnode browse, query, x; if (m->packet->type != JPACKET_IQ) return M_IGNORE; if (jpacket_subtype(m->packet) != JPACKET__GET || !NSCHECK(m->packet->iq, NS_BROWSE) || m->packet->to->resource != NULL) return M_PASS; /* get data from the config file */ if ((browse = js_config(m->si, "browse")) == NULL) return M_PASS; log_debug("handling browse query"); /* build the result IQ */ query = xmlnode_insert_tag(jutil_iqresult(m->packet->x), "service"); xmlnode_put_attrib(query, "xmlns", NS_BROWSE); xmlnode_put_attrib(query, "type", "jabber"); xmlnode_put_attrib(query, "jid", m->packet->to->server); xmlnode_put_attrib(query, "name", xmlnode_get_data(js_config(m->si, "vCard/FN"))); /* pull name from the server vCard */ /* copy in the configured services */ xmlnode_insert_node(query, xmlnode_get_firstchild(browse)); /* list the admin stuff */ if (js_admin_jid(m->si, jid_user(m->packet->from), ADMIN_READ)) { x = xmlnode_insert_tag(query, "item"); xmlnode_put_attrib(x, "jid", spools(xmlnode_pool(x), m->packet->to->server, "/admin", xmlnode_pool(x))); xmlnode_put_attrib(x, "name", "Online Users"); xmlnode_insert_cdata(xmlnode_insert_tag(query, "ns"), NS_ADMIN, -1); } jpacket_reset(m->packet); js_deliver(m->si, m->packet); return M_HANDLED; }
/* returns a valid nick from the list, x is the first <nick>foo</nick> xmlnode, checks siblings */ char *con_room_nick(cnr room, cnu user, xmlnode x) { char *nick = NULL; xmlnode cur; int count = 1; if(room == NULL || user == NULL) { log_warn(NAME, "[%s] Aborting - NULL attribute found", FZONE); return NULL; } log_debug(NAME, "[%s] looking for valid nick in room %s from starter %s", FZONE, jid_full(room->id), xmlnode2str(x)); /* make-up-a-nick phase */ if(x == NULL) { nick = pmalloco(user->p, j_strlen(user->realid->user) + 10); log_debug(NAME, "[%s] Malloc: Nick = %d", FZONE, j_strlen(user->realid->user) + 10); sprintf(nick, "%s", user->realid->user); while(g_hash_table_lookup(room->local, nick) != NULL) sprintf(nick, "%s%d", user->realid->user,count++); return nick; } /* scan the list */ for(cur = x; cur != NULL; cur = xmlnode_get_nextsibling(cur)) { if(j_strcmp(xmlnode_get_name(cur),"nick") == 0 && (nick = xmlnode_get_data(cur)) != NULL) if(g_hash_table_lookup(room->local, nick) == NULL) break; } if(is_registered(room->master, jid_full(jid_user(user->realid)), nick) == -1) nick = NULL; return nick; }
static void _iq_private_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting private xml storage for %s", jid_user(jid)); storage_delete(mi->sm->st, "private", jid_user(jid), NULL); }
static mod_ret_t _offline_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { st_ret_t ret; os_t os; os_object_t o; nad_t nad; pkt_t queued; int ns, elem, attr; char cttl[15], cstamp[18]; time_t ttl, stamp; /* if they're becoming available for the first time */ if(pkt->type == pkt_PRESENCE && pkt->to == NULL && sess->user->top == NULL) { ret = storage_get(pkt->sm->st, "queue", jid_user(sess->jid), NULL, &os); if(ret != st_SUCCESS) { log_debug(ZONE, "storage_get returned %d", ret); return mod_PASS; } if(os_iter_first(os)) do { o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { queued = pkt_new(pkt->sm, nad_copy(nad)); if(queued == NULL) { log_debug(ZONE, "invalid queued packet, not delivering"); } else { /* check expiry as necessary */ if((ns = nad_find_scoped_namespace(queued->nad, uri_EXPIRE, NULL)) >= 0 && (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 && (attr = nad_find_attr(queued->nad, elem, -1, "seconds", NULL)) >= 0) { snprintf(cttl, 15, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr)); ttl = atoi(cttl); /* it should have a x:delay stamp, because we stamp everything we store */ if((ns = nad_find_scoped_namespace(queued->nad, uri_DELAY, NULL)) >= 0 && (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 && (attr = nad_find_attr(queued->nad, elem, -1, "stamp", NULL)) >= 0) { snprintf(cstamp, 18, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr)); stamp = datetime_in(cstamp); if(stamp + ttl <= time(NULL)) { log_debug(ZONE, "queued packet has expired, dropping"); pkt_free(queued); continue; } } } log_debug(ZONE, "delivering queued packet to %s", jid_full(sess->jid)); pkt_sess(queued, sess); } } } while(os_iter_next(os)); os_free(os); /* drop the spool */ storage_delete(pkt->sm->st, "queue", jid_user(sess->jid), NULL); } /* pass it so that other modules and mod_presence can get it */ return mod_PASS; }
void user_free(user_t user) { log_debug(ZONE, "freeing user %s", jid_user(user->jid)); xhash_zap(user->sm->users, jid_user(user->jid)); pool_free(user->p); }
/** register set handler */ static void _authreg_register_set(c2s_t c2s, sess_t sess, nad_t nad) { int ns = 0, elem, attr; char username[1024], password[1024]; /* if we're not configured for registration (or pw changes), or we can't set passwords, fail outright */ if(!(sess->host->ar_register_enable || sess->host->ar_register_password) || c2s->ar->set_password == NULL) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } ns = nad_find_scoped_namespace(nad, uri_REGISTER, NULL); /* removals */ if(sess->active && nad_find_elem(nad, 1, ns, "remove", 1) >= 0) { /* only if full reg is enabled */ if(!sess->host->ar_register_enable) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } log_debug(ZONE, "user remove requested"); /* make sure we can delete them */ if(c2s->ar->delete_user == NULL) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* otherwise, delete them */ if((c2s->ar->delete_user)(c2s->ar, sess->resources->jid->node, sess->host->realm) != 0) { log_debug(ZONE, "user delete failed"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } log_write(c2s->log, LOG_NOTICE, "[%d] deleted user: user=%s; realm=%s", sess->s->tag, sess->resources->jid->node, sess->host->realm); log_write(c2s->log, LOG_NOTICE, "[%d] registration remove succeeded, requesting user deletion: jid=%s", sess->s->tag, jid_user(sess->resources->jid)); /* make a result nad */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); nad_free(nad); sx_nad_write(sess->s, sess->result); sess->result = NULL; /* get the sm to delete them (it will force their sessions to end) */ sm_delete(sess, sess->resources); return; } /* username is required */ elem = nad_find_elem(nad, 1, ns, "username", 1); if(elem < 0) { log_debug(ZONE, "register set with no username, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } snprintf(username, 1024, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); if(stringprep_xmpp_nodeprep(username, 1024) != 0) { log_debug(ZONE, "register set username failed nodeprep, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_JID_MALFORMED), 0)); return; } elem = nad_find_elem(nad, 1, ns, "password", 1); if(elem < 0) { log_debug(ZONE, "register set with no password, bouncing it"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_BAD_REQUEST), 0)); return; } /* if they're already auth'd, its a password change */ if(sess->active) { /* confirm that the username matches their auth id */ if(strcmp(username, sess->resources->jid->node) != 0) { log_debug(ZONE, "%s is trying to change password for %s, bouncing it", jid_full(sess->resources->jid), username); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_OLD_UNAUTH), 0)); return; } } /* can't go on if we're not doing full reg */ else if(!sess->host->ar_register_enable) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* if they exist, bounce */ else if((c2s->ar->user_exists)(c2s->ar, username, sess->host->realm)) { log_debug(ZONE, "attempt to register %s, but they already exist", username); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_CONFLICT), 0)); return; } /* make sure we can create them */ else if(c2s->ar->create_user == NULL) { sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_NOT_ALLOWED), 0)); return; } /* otherwise, create them */ else if((c2s->ar->create_user)(c2s->ar, username, sess->host->realm) != 0) { log_debug(ZONE, "user create failed"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } else log_write(c2s->log, LOG_NOTICE, "[%d] created user: user=%s; realm=%s", sess->s->tag, username, sess->host->realm); /* extract the password */ snprintf(password, 257, "%.*s", NAD_CDATA_L(nad, elem), NAD_CDATA(nad, elem)); /* change it */ if((c2s->ar->set_password)(c2s->ar, username, sess->host->realm, password) != 0) { log_debug(ZONE, "password store failed"); sx_nad_write(sess->s, stanza_tofrom(stanza_error(nad, 0, stanza_err_INTERNAL_SERVER_ERROR), 0)); return; } log_debug(ZONE, "updated auth creds for %s", username); /* make a result nad */ sess->result = nad_new(); ns = nad_add_namespace(sess->result, uri_CLIENT, NULL); nad_append_elem(sess->result, ns, "iq", 0); nad_set_attr(sess->result, 0, -1, "type", "result", 6); /* extract the id */ attr = nad_find_attr(nad, 0, -1, "id", NULL); if(attr >= 0) nad_set_attr(sess->result, 0, -1, "id", NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr)); /* if they're active, then this was just a password change, and we're done */ if(sess->active) { log_write(c2s->log, LOG_NOTICE, "[%d] password changed: jid=%s", sess->s->tag, jid_user(sess->resources->jid)); sx_nad_write(sess->s, sess->result); sess->result = NULL; return; } /* create new bound jid holder */ if(sess->resources == NULL) { sess->resources = (bres_t) calloc(1, sizeof(struct bres_st)); } /* our local id */ sprintf(sess->resources->c2s_id, "%d", sess->s->tag); /* the user jid for this transaction */ sess->resources->jid = jid_new(sess->s->req_to, -1); jid_reset_components(sess->resources->jid, username, sess->resources->jid->domain, sess->resources->jid->resource); log_write(c2s->log, LOG_NOTICE, "[%d] registration succeeded, requesting user creation: jid=%s", sess->s->tag, jid_user(sess->resources->jid)); /* get the sm to create them */ sm_create(sess, sess->resources); nad_free(nad); return; }
/** * process commandline * @return: 0 to indicate that output needs to be written */ int _pbx_process_command(c2s_t c2s, char *cmd) { jid_t jid; int action = 0, len; sess_t sess; unsigned char hashbuf[44] = "PBX"; unsigned char *sesshash; sesshash = hashbuf+3; /* get command */ if(!strncasecmp("START ", cmd, 6)) { cmd += 6; action = 1; } if(!strncasecmp("STOP ", cmd, 5)) { cmd += 5; action = 2; } if(action != 0) { len = _pbx_command_part_len(cmd); if(len > 0) { jid = jid_new(cmd, len); if(jid) { cmd += len; if(*cmd != '\0') cmd++; shahash_r(jid_full(jid), sesshash); sess = xhash_get(c2s->sessions, hashbuf); switch(action) { case 1: log_debug(ZONE, "STARTing session for %s/%s (%s) with commandline: %s", jid_user(jid), jid->resource, hashbuf, cmd); if(sess == NULL) { /* create new session */ sess = (sess_t) calloc(1, sizeof(struct sess_st)); sess->c2s = c2s; sess->last_activity = time(NULL); /* put into sessions hash */ snprintf(sess->skey, sizeof(sess->skey), "%s", hashbuf); xhash_put(c2s->sessions, sess->skey, (void *) sess); /* generate bound resource */ sess->resources = (bres_t) calloc(1, sizeof(struct bres_st)); snprintf(sess->resources->c2s_id, sizeof(sess->resources->c2s_id), "%s", hashbuf); sess->resources->jid = jid; /* open SM session */ log_write(sess->c2s->log, LOG_NOTICE, "[PBX] requesting session: jid=%s", jid_full(jid)); sm_start(sess, sess->resources); /* generate presence packet to get session online */ /* a bit hacky, but we need to emulate _some_ of the client behavior */ sess->result = _pbx_presence_nad(1, cmd); } else { /* just send the presence */ sm_packet(sess, sess->resources, _pbx_presence_nad(1, cmd)); } break; case 2: log_debug(ZONE, "STOPping session for %s/%s with commandline: %s", jid_user(jid), jid->resource, cmd); if(sess != NULL) { /* send unavailable presence */ sm_packet(sess, sess->resources, _pbx_presence_nad(0, cmd)); /* end the session */ sm_end(sess, sess->resources); xhash_zap(c2s->sessions, sess->skey); jqueue_push(c2s->dead_sess, (void *) sess, 0); } break; } /* TODO: respond with "OK", return 0 */ return -1; } } /* TODO: generate "ERR" response, return 0 */ return -1; } if(!strncasecmp("STATUS", cmd, 6)) { log_write(c2s->log, LOG_INFO, "STATUS PBX command not implemented yet"); return -1; } return -1; }
static void _router_process_route(component_t comp, nad_t nad) { int atype, ato, afrom; unsigned int dest; struct jid_st sto, sfrom; jid_static_buf sto_buf, sfrom_buf; jid_t to = NULL, from = NULL; routes_t targets; component_t target; union xhashv xhv; /* init static jid */ jid_static(&sto,&sto_buf); jid_static(&sfrom,&sfrom_buf); if(nad_find_attr(nad, 0, -1, "error", NULL) >= 0) { log_debug(ZONE, "dropping error packet, trying to avoid loops"); nad_free(nad); return; } atype = nad_find_attr(nad, 0, -1, "type", NULL); ato = nad_find_attr(nad, 0, -1, "to", NULL); afrom = nad_find_attr(nad, 0, -1, "from", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); if(afrom >= 0) from = jid_reset(&sfrom, NAD_AVAL(nad, afrom), NAD_AVAL_L(nad, afrom)); /* unicast */ if(atype < 0) { if(to == NULL || from == NULL) { log_debug(ZONE, "unicast route with missing or invalid to or from, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); _router_comp_write(comp, nad); return; } log_debug(ZONE, "unicast route from %s to %s", from->domain, to->domain); /* check the from */ if(xhash_get(comp->routes, from->domain) == NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to send a packet from '%s', but that name is not bound to this component", comp->ip, comp->port, from->domain); nad_set_attr(nad, 0, -1, "error", "401", 3); _router_comp_write(comp, nad); return; } /* filter it */ if(comp->r->filter != NULL) { int ret = filter_packet(comp->r, nad); if(ret == stanza_err_REDIRECT) { ato = nad_find_attr(nad, 0, -1, "to", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); } else if(ret > 0) { log_debug(ZONE, "packet filtered out: %s (%s)", _stanza_errors[ret - stanza_err_BAD_REQUEST].name, _stanza_errors[ret - stanza_err_BAD_REQUEST].code); nad_set_attr(nad, 0, -1, "error", _stanza_errors[ret - stanza_err_BAD_REQUEST].code, 3); _router_comp_write(comp, nad); return; } } /* find a target */ targets = xhash_get(comp->r->routes, to->domain); if(targets == NULL) { if(comp->r->default_route != NULL && strcmp(from->domain, comp->r->default_route) == 0) { log_debug(ZONE, "%s is unbound, bouncing", from->domain); nad_set_attr(nad, 0, -1, "error", "404", 3); _router_comp_write(comp, nad); return; } targets = xhash_get(comp->r->routes, comp->r->default_route); } if(targets == NULL) { log_debug(ZONE, "%s is unbound, and no default route, bouncing", to->domain); nad_set_attr(nad, 0, -1, "error", "404", 3); _router_comp_write(comp, nad); return; } /* copy to any log sinks */ if(xhash_count(comp->r->log_sinks) > 0) xhash_walk(comp->r->log_sinks, _router_route_log_sink, (void *) nad); /* get route candidate */ if(targets->ncomp == 1) { dest = 0; } else { switch(targets->rtype) { case route_MULTI_TO: ato = nad_find_attr(nad, 1, -1, "to", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); else { ato = nad_find_attr(nad, 1, -1, "target", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); else { const char *out; int len; nad_print(nad, 0, &out, &len); log_write(comp->r->log, LOG_ERR, "Cannot get destination for multiple route: %.*s", len, out); } } break; case route_MULTI_FROM: ato = nad_find_attr(nad, 1, -1, "from", NULL); if(ato >= 0) to = jid_reset(&sto, NAD_AVAL(nad, ato), NAD_AVAL_L(nad, ato)); else { const char *out; int len; nad_print(nad, 0, &out, &len); log_write(comp->r->log, LOG_ERR, "Cannot get source for multiple route: %.*s", len, out); } break; default: log_write(comp->r->log, LOG_ERR, "Multiple components bound to single component route '%s'", targets->name); /* simulate no 'to' info in this case */ } if(to->node == NULL || strlen(to->node) == 0) { /* no node in destination JID - going random */ dest = rand(); log_debug(ZONE, "randomized to %u %% %d = %d", dest, targets->ncomp, dest % targets->ncomp); } else { /* use JID hash */ unsigned char hashval[20]; unsigned int *val; int i; shahash_raw(jid_user(to), hashval); val = (unsigned int *) hashval; dest = *val; for(i=1; i < 20 / (sizeof(unsigned int)/sizeof(unsigned char)); i++, val++) { dest ^= *val; } dest >>= 2; log_debug(ZONE, "JID %s hashed to %u %% %d = %d", jid_user(to), dest, targets->ncomp, dest % targets->ncomp); /* jid_user() calls jid_expand() which may allocate some memory in _user and _full */ if (to->_user != NULL ) free(to->_user); if (to->_full != NULL ) free(to->_full); } dest = dest % targets->ncomp; } target = targets->comp[dest]; /* push it out */ log_debug(ZONE, "writing route for '%s'*%u to %s, port %d", to->domain, dest+1, target->ip, target->port); /* if logging enabled, log messages that match our criteria */ if (comp->r->message_logging_enabled && comp->r->message_logging_file != NULL) { int attr_msg_to; int attr_msg_from; int attr_route_to; int attr_route_from; jid_t jid_msg_from = NULL; jid_t jid_msg_to = NULL; jid_t jid_route_from = NULL; jid_t jid_route_to = NULL; if ((NAD_ENAME_L(nad, 1) == 7 && strncmp("message", NAD_ENAME(nad, 1), 7) == 0) && // has a "message" element ((attr_route_from = nad_find_attr(nad, 0, -1, "from", NULL)) >= 0) && ((attr_route_to = nad_find_attr(nad, 0, -1, "to", NULL)) >= 0) && ((strncmp(NAD_AVAL(nad, attr_route_to), "c2s", 3)) != 0) && // ignore messages to "c2s" or we'd have dups ((jid_route_from = jid_new(NAD_AVAL(nad, attr_route_from), NAD_AVAL_L(nad, attr_route_from))) != NULL) && // has valid JID source in route ((jid_route_to = jid_new(NAD_AVAL(nad, attr_route_to), NAD_AVAL_L(nad, attr_route_to))) != NULL) && // has valid JID destination in route ((attr_msg_from = nad_find_attr(nad, 1, -1, "from", NULL)) >= 0) && ((attr_msg_to = nad_find_attr(nad, 1, -1, "to", NULL)) >= 0) && ((jid_msg_from = jid_new(NAD_AVAL(nad, attr_msg_from), NAD_AVAL_L(nad, attr_msg_from))) != NULL) && // has valid JID source in message ((jid_msg_to = jid_new(NAD_AVAL(nad, attr_msg_to), NAD_AVAL_L(nad, attr_msg_to))) != NULL)) // has valid JID dest in message { message_log(nad, comp->r, jid_full(jid_msg_from), jid_full(jid_msg_to)); } if (jid_msg_from != NULL) jid_free(jid_msg_from); if (jid_msg_to != NULL) jid_free(jid_msg_to); if (jid_route_from != NULL) jid_free(jid_route_from); if (jid_route_to != NULL) jid_free(jid_route_to); } _router_comp_write(target, nad); return; } /* broadcast */ if(NAD_AVAL_L(nad, atype) == 9 && strncmp("broadcast", NAD_AVAL(nad, atype), 9) == 0) { if(from == NULL) { log_debug(ZONE, "broadcast route with missing or invalid from, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); _router_comp_write(comp, nad); return; } log_debug(ZONE, "broadcast route from %s", from->domain); /* check the from */ if(xhash_get(comp->routes, from->domain) == NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to send a packet from '%s', but that name is not bound to this component", comp->ip, comp->port, from->domain); nad_set_attr(nad, 0, -1, "error", "401", 3); _router_comp_write(comp, nad); return; } /* loop the components and distribute */ if(xhash_iter_first(comp->r->components)) do { xhv.comp_val = ⌖ xhash_iter_get(comp->r->components, NULL, NULL, xhv.val); if(target != comp) { log_debug(ZONE, "writing broadcast to %s, port %d", target->ip, target->port); _router_comp_write(target, nad_copy(nad)); } } while(xhash_iter_next(comp->r->components)); nad_free(nad); return; } log_debug(ZONE, "unknown route type '%.*s', dropping", NAD_AVAL_L(nad, atype), NAD_AVAL(nad, atype)); nad_free(nad); }
/** Callback processing incoming Jabber packets. */ result it_receive(instance i, dpacket d, void *arg) { iti ti = (iti) arg; jpacket jp; session s; session_ref alt_s; unsigned char *user; log_debug(ti->i->id,"Packet received: %s\n",xmlnode2str(d->x)); switch(d->type) { case p_ROUTE: { /* ignore */ return r_PASS; } case p_NONE: case p_NORM: jp = jpacket_new(d->x); break; default: return r_ERR; } if (!jp->from ||/* !jp->from->user ||*/ jp->type == JPACKET_UNKNOWN /* || jpacket_subtype(jp) == JPACKET__ERROR */) { /* ignore invalid packets */ xmlnode_free(jp->x); return r_DONE; } /* JID user part should be case insensitive */ /* convert user part of from JID to lower case */ if(jp->from->user != NULL) for(user = jp->from->user; *user != '\0'; user++) if(*user < 128) *user = tolower(*user); /* Mangle "from" JID, save original attribute for XDB conversion */ xmlnode_put_attrib(jp->x, "origfrom", xmlnode_get_attrib(jp->x, "from")); xmlnode_put_attrib(jp->x, "from", jid_full(jp->from)); SEM_LOCK(ti->sessions_sem); s = (session) wpxhash_get(ti->sessions,jid_full(jid_user(jp->from))); alt_s = (session_ref) wpxhash_get(ti->sessions_alt,jp->to->user); if (s != NULL) { if (s->exit_flag) { SEM_UNLOCK(ti->sessions_sem); log_alert("exit flag","message to exiting session"); if (jp->type != JPACKET_PRESENCE){ jutil_error(jp->x,TERROR_NOTFOUND); it_deliver(ti,jp->x); } else xmlnode_free(jp->x); } else if ((alt_s != NULL) && ( (jp->type == JPACKET_MESSAGE) // all messages || ((jp->type == JPACKET_IQ) && (j_strcmp(xmlnode_get_attrib(jp->iq,"xmlns"),NS_VCARD) == -1)) // all IQs except of vCard || (jp->type == JPACKET_PRESENCE) )) { // all presences _targeted_to_specific_user_ // rewriting "to" and "from" and putting packet back on the wire xmlnode_put_attrib(jp->x, "from", jid_full(it_uin2jid(jp->p,s->uin,jp->to->server))); xmlnode_put_attrib(jp->x, "to", jid_full(alt_s->s->orgid)); SEM_UNLOCK(ti->sessions_sem); it_deliver(ti,jp->x); } else { jp->aux1 = (void *) s; mtq_send(s->q,jp->p,it_session_jpacket,(void *) jp); SEM_UNLOCK(ti->sessions_sem); } } else { SEM_UNLOCK(ti->sessions_sem); if(jpacket_subtype(jp)!=JPACKET__ERROR) it_unknown(ti,jp); else xmlnode_free(jp->x); } return r_DONE; }
static mod_ret_t _amp_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { /* only handle messages */ if (! pkt->type & pkt_MESSAGE) return mod_PASS; /* we're only interested in no to, to our host, or to us */ if (pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0) return mod_PASS; /* TODO: implementation */ return mod_PASS; }
void sm_delete(sess_t sess, bres_t res) { sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "delete", jid_user(res->jid), NULL)); }
void sm_create(sess_t sess, bres_t res) { _sm_generate_id(sess, res, "create"); sx_nad_write(sess->c2s->router, _sm_build_route(sess, res, "create", jid_user(res->jid), res->sm_request)); }
static mod_ret_t _vacation_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; vacation_t v = sess->user->module_data[mod->index]; int ns, start, end, msg; char dt[30]; pkt_t res; os_t os; os_object_t o; /* we only want to play with vacation iq packets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_VACATION) return mod_PASS; /* if it has a to, throw it out */ if(pkt->to != NULL) return -stanza_err_BAD_REQUEST; /* get */ if(pkt->type == pkt_IQ) { if(v->msg == NULL) { res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); pkt_id(pkt, res); pkt_free(pkt); pkt_sess(res, sess); return mod_HANDLED; } ns = nad_find_scoped_namespace(pkt->nad, uri_VACATION, NULL); if(v->start != 0) { datetime_out(v->start, dt_DATETIME, dt, 30); nad_insert_elem(pkt->nad, 2, ns, "start", dt); } else nad_insert_elem(pkt->nad, 2, ns, "start", NULL); if(v->end != 0) { datetime_out(v->end, dt_DATETIME, dt, 30); nad_insert_elem(pkt->nad, 2, ns, "end", dt); } else nad_insert_elem(pkt->nad, 2, ns, "end", NULL); nad_insert_elem(pkt->nad, 2, ns, "message", v->msg); pkt_tofrom(pkt); nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_sess(pkt, sess); return mod_HANDLED; } /* set */ ns = nad_find_scoped_namespace(pkt->nad, uri_VACATION, NULL); start = nad_find_elem(pkt->nad, 2, ns, "start", 1); end = nad_find_elem(pkt->nad, 2, ns, "end", 1); msg = nad_find_elem(pkt->nad, 2, ns, "message", 1); if(start < 0 || end < 0 || msg < 0) { /* forget */ if(v->msg != NULL) { free(v->msg); v->msg = NULL; } v->start = 0; v->end = 0; storage_delete(mi->sm->st, "vacation-settings", jid_user(sess->jid), NULL); res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); pkt_id(pkt, res); pkt_free(pkt); pkt_sess(res, sess); return mod_HANDLED; } if(NAD_CDATA_L(pkt->nad, start) > 0) { strncpy(dt, NAD_CDATA(pkt->nad, start), (30 < NAD_CDATA_L(pkt->nad, start) ? 30 : NAD_CDATA_L(pkt->nad, start))); v->start = datetime_in(dt); } else v->start = 0; if(NAD_CDATA_L(pkt->nad, end) > 0) { strncpy(dt, NAD_CDATA(pkt->nad, end), (30 < NAD_CDATA_L(pkt->nad, end) ? 30 : NAD_CDATA_L(pkt->nad, end))); v->end = datetime_in(dt); } else v->end = 0; v->msg = (char *) malloc(sizeof(char) * (NAD_CDATA_L(pkt->nad, msg) + 1)); strncpy(v->msg, NAD_CDATA(pkt->nad, msg), NAD_CDATA_L(pkt->nad, msg)); v->msg[NAD_CDATA_L(pkt->nad, msg)] = '\0'; os = os_new(); o = os_object_new(os); os_object_put(o, "start", &v->start, os_type_INTEGER); os_object_put(o, "end", &v->end, os_type_INTEGER); os_object_put(o, "message", v->msg, os_type_STRING); if(storage_replace(mod->mm->sm->st, "vacation-settings", jid_user(sess->user->jid), NULL, os) != st_SUCCESS) { free(v->msg); v->msg = NULL; v->start = 0; v->end = 0; return -stanza_err_INTERNAL_SERVER_ERROR; } res = pkt_create(mod->mm->sm, "iq", "result", NULL, NULL); pkt_id(pkt, res); pkt_free(pkt); pkt_sess(res, sess); return mod_HANDLED; }
static mod_ret_t _iq_private_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { module_t mod = mi->mod; int ns, elem, target, targetns; st_ret_t ret; char filter[4096]; os_t os; os_object_t o; nad_t nad; pkt_t result; sess_t sscan; /* only handle private sets and gets */ if((pkt->type != pkt_IQ && pkt->type != pkt_IQ_SET) || pkt->ns != ns_PRIVATE) return mod_PASS; /* we're only interested in no to, to our host, or to us */ if(pkt->to != NULL && jid_compare_user(sess->jid, pkt->to) != 0 && strcmp(sess->jid->domain, jid_user(pkt->to)) != 0) return mod_PASS; ns = nad_find_scoped_namespace(pkt->nad, uri_PRIVATE, NULL); elem = nad_find_elem(pkt->nad, 1, ns, "query", 1); /* find the first child */ target = elem + 1; while(target < pkt->nad->ecur) { if(pkt->nad->elems[target].depth > pkt->nad->elems[elem].depth) break; target++; } /* not found, so we're done */ if(target == pkt->nad->ecur) return -stanza_err_BAD_REQUEST; /* find the target namespace */ targetns = NAD_ENS(pkt->nad, target); /* gotta have a namespace */ if(targetns < 0) { log_debug(ZONE, "no namespace specified"); return -stanza_err_BAD_REQUEST; } log_debug(ZONE, "processing private request for %.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); /* get */ if(pkt->type == pkt_IQ) { #ifdef ENABLE_EXPERIMENTAL /* remember that this resource requested the namespace */ if(sess->module_data[mod->index] == NULL) { /* create new hash if necesary */ sess->module_data[mod->index] = xhash_new(101); pool_cleanup(sess->p, (void (*))(void *) xhash_free, sess->module_data[mod->index]); } xhash_put(sess->module_data[mod->index], pstrdupx(sess->p, NAD_NURI(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns)), (void *) 1); #endif snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_get(sess->user->sm->st, "private", jid_user(sess->jid), filter, &os); switch(ret) { case st_SUCCESS: if(os_iter_first(os)) { o = os_iter_object(os); if(os_object_get_nad(os, o, "xml", &nad)) { result = pkt_new(sess->user->sm, nad_copy(nad)); if(result != NULL) { nad_set_attr(result->nad, 1, -1, "type", "result", 6); pkt_id(pkt, result); pkt_sess(result, sess); pkt_free(pkt); os_free(os); return mod_HANDLED; } } } os_free(os); /* drop through */ log_debug(ZONE, "storage_get succeeded, but couldn't make packet, faking st_NOTFOUND"); case st_NOTFOUND: log_debug(ZONE, "namespace not found, returning"); /* * !!! really, we should just return a 404. 1.4 just slaps a * result on the packet and sends it back. hurrah for * legacy namespaces. */ nad_set_attr(pkt->nad, 1, -1, "type", "result", 6); pkt_sess(pkt_tofrom(pkt), sess); return mod_HANDLED; case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; } } os = os_new(); o = os_object_new(os); snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); os_object_put(o, "ns", filter, os_type_STRING); os_object_put(o, "xml", pkt->nad, os_type_NAD); snprintf(filter, 4096, "(ns=%i:%.*s)", NAD_NURI_L(pkt->nad, targetns), NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); ret = storage_replace(sess->user->sm->st, "private", jid_user(sess->jid), filter, os); os_free(os); switch(ret) { case st_FAILED: return -stanza_err_INTERNAL_SERVER_ERROR; case st_NOTIMPL: return -stanza_err_FEATURE_NOT_IMPLEMENTED; default: /* create result packet */ result = pkt_create(sess->user->sm, "iq", "result", NULL, NULL); pkt_id(pkt, result); /* and flush it to the session */ pkt_sess(result, sess); #ifdef ENABLE_EXPERIMENTAL /* push it to all resources that read this xmlns item */ snprintf(filter, 4096, "%.*s", NAD_NURI_L(pkt->nad, targetns), NAD_NURI(pkt->nad, targetns)); for(sscan = sess->user->sessions; sscan != NULL; sscan = sscan->next) { /* skip our resource and those that didn't read any private-storage */ if(sscan == sess || sscan->module_data[mod->index] == NULL) continue; /* check whether namespace was read */ if(xhash_get(sscan->module_data[mod->index], filter)) { result = pkt_dup(pkt, jid_full(sscan->jid), NULL); if(result->from != NULL) { jid_free(result->from); nad_set_attr(result->nad, 1, -1, "from", NULL, 0); } pkt_id_new(result); pkt_sess(result, sscan); } } #endif /* finally free the packet */ pkt_free(pkt); return mod_HANDLED; } /* we never get here */ return 0; }
/* * js_session_new -- creates a new session, registers the resource for it * * Sets up all the data associated with the new session, then send it a * start spacket, which basically notifies all modules about the new session * * returns * a pointer to the new session */ session js_session_new(jsmi si, dpacket dp) { pool p; session s, cur; udata u; int i; char routeres[10]; /* screen out illegal calls */ if (dp == NULL || dp->id->user == NULL || dp->id->resource == NULL || xmlnode_get_attrib(dp->x, "from") == NULL) return NULL; if ((u = js_user(si, dp->id, 0)) == NULL) return NULL; if (u->scount >= MAX_USER_SESSIONS) { THREAD_DEC(u->ref); return NULL; } log_debug("session_create %s", jid_full(dp->id)); /* create session */ p = pool_heap(1024); s = pmalloco(p, sizeof(struct session_struct)); s->p = p; s->si = si; /* save authorative remote session id */ s->sid = jid_new(p, xmlnode_get_attrib(dp->x, "from")); /* session identity */ s->id = jid_new(p, jid_full(dp->id)); /* id bez resource */ s->uid = jid_user(s->id); s->route = jid_new(p, jid_full(dp->id)); snprintf(routeres, 9, "%X", s); jid_set(s->route, routeres, JID_RESOURCE); s->res = pstrdup(p, dp->id->resource); s->u = u; jid_full(s->sid); jid_full(s->uid); jid_full(s->id); jid_full(s->route); { register char *text; text = xmlnode_get_attrib(dp->x, "ip"); if (text) { s->ip = pstrdup(s->p, xmlnode_get_attrib(dp->x, "ip")); xmlnode_hide_attrib(dp->x, "ip"); } else s->ip = "none"; } /* default settings */ s->exit_flag = 0; s->roster = 0; s->priority = -129; s->presence = jutil_presnew(JPACKET__UNAVAILABLE, NULL, NULL); xmlnode_put_attrib(s->presence, "from", jid_full(s->id)); s->c_in = s->c_out = 0; for (i = 0; i < es_LAST; i++) s->events[i] = NULL; SEM_LOCK(u->sem); if (u->sessions != NULL) { s->q = get_mtq_queue(si, u->sessions->q); for (cur = u->sessions; cur != NULL; cur = cur->next) if (j_strcmp(dp->id->resource, cur->res) == 0) js_session_end_nosem(cur, "Replaced by new connection"); } else { s->q = get_mtq_queue(si, NULL); } /* make sure we're linked with the user */ s->next = s->u->sessions; s->u->sessions = s; s->u->scount++; SEM_UNLOCK(u->sem); /* session start */ { packet_thread_p pt; pt = malloc(sizeof(packet_thread_t)); pt->s = s; pt->type = 0; fast_mtq_send(s->q->mtq, pt); } THREAD_DEC(u->ref); return s; }
static void _vacation_user_delete(mod_instance_t mi, jid_t jid) { log_debug(ZONE, "deleting vacations settings for %s", jid_user(jid)); storage_delete(mi->sm->st, "vacation-settings", jid_user(jid), NULL); }