📄 mod_presence.c
字号:
* * @param m the mapi structure * @param arg pointer to the modpres structure containing the module's data for this session * @return M_IGNORE if the stanza is no presence, M_PASS if the presence has a to attribute, is a probe, or is an error presence, M_HANDLED else */mreturn mod_presence_out(mapi m, void *arg){ xmlnode pnew, delay; modpres mp = (modpres)arg; session cur = NULL; int oldpri, newpri; char *priority; if(m->packet->type != JPACKET_PRESENCE) return M_IGNORE; if(m->packet->to != NULL || jpacket_subtype(m->packet) == JPACKET__PROBE || jpacket_subtype(m->packet) == JPACKET__ERROR) return M_PASS; log_debug2(ZONE, LOGT_DELIVER, "new presence from %s of %s",jid_full(m->s->id),xmlnode2str(m->packet->x)); /* pre-existing conditions (no, we are not an insurance company) */ oldpri = m->s->priority; /* check that the priority is in the valid range */ priority = xmlnode_get_tag_data(m->packet->x, "priority"); if (priority == NULL) { newpri = 0; } else { newpri = j_atoi(priority, 0); if (newpri < -128 || newpri > 127) { log_notice("mod_presence", "got presence with invalid priority value from %s", jid_full(m->s->id)); xmlnode_free(m->packet->x); return M_HANDLED; } } /* invisible mode is special, don't you wish you were special too? */ if(jpacket_subtype(m->packet) == JPACKET__INVISIBLE) { log_debug2(ZONE, LOGT_DELIVER, "handling invisible mode request"); /* if we get this and we're available, it means go unavail first then reprocess this packet, nifty trick :) */ if(oldpri >= -128) { js_session_from(m->s, jpacket_new(jutil_presnew(JPACKET__UNAVAILABLE,NULL,NULL))); js_session_from(m->s, m->packet); return M_HANDLED; } /* now, pretend we come online :) */ /* (this is the handling of the reinjected invisible presence * or an initial invisible presence) */ mp->invisible = 1; mod_presence_roster(m, NULL); /* send out probes to users we are subscribed to */ m->s->priority = newpri; /* store presence in xdb? */ if (mp->conf->pres_to_xdb > 0) mod_presence_store(m); xmlnode_free(m->packet->x); /* we do not broadcast invisible presences without a to attribute */ return M_HANDLED; } /* our new presence, keep it */ xmlnode_free(m->s->presence); m->s->presence = xmlnode_dup(m->packet->x); m->s->priority = jutil_priority(m->packet->x); /* store presence in xdb? */ if (mp->conf->pres_to_xdb > 0) mod_presence_store(m); /* stamp the sessions presence */ delay = xmlnode_insert_tag(m->s->presence,"x"); xmlnode_put_attrib(delay,"xmlns",NS_DELAY); xmlnode_put_attrib(delay,"from",jid_full(m->s->id)); xmlnode_put_attrib(delay,"stamp",jutil_timestamp()); log_debug2(ZONE, LOGT_DELIVER, "presence oldp %d newp %d",oldpri,m->s->priority); /* if we're going offline now, let everyone know */ if(m->s->priority < -128) { /* jutil_priority returns -129 in case the "type" attribute is missing */ if(!mp->invisible) /* bcc's don't get told if we were invisible */ _mod_presence_broadcast(m->s,mp->conf->bcc,m->packet->x,NULL); _mod_presence_broadcast(m->s,mp->A,m->packet->x,NULL); _mod_presence_broadcast(m->s,mp->I,m->packet->x,NULL); /* reset vars */ mp->invisible = 0; if(mp->A != NULL) mp->A->next = NULL; mp->I = NULL; xmlnode_free(m->packet->x); return M_HANDLED; } /* available presence updates, intersection of A and T */ if(oldpri >= -128 && !mp->invisible) { _mod_presence_broadcast(m->s,mp->A,m->packet->x,js_trustees(m->user)); xmlnode_free(m->packet->x); return M_HANDLED; } /* at this point we're coming out of the closet */ mp->invisible = 0; /* make sure we get notified for any presence about ourselves */ /* XXX: the following is the original code: it caused existing presences * to be stamped several times and the presence to be sent out twice. pnew = jutil_presnew(JPACKET__PROBE,jid_full(jid_user(m->s->id)),NULL); xmlnode_put_attrib(pnew,"from",jid_full(jid_user(m->s->id))); js_session_from(m->s, jpacket_new(pnew)); */ /* XXX: I think this should be okay as well: */ /* send us all presences of our other resources */ for (cur = m->user->sessions; cur != NULL; cur=cur->next) { pool pool_for_existing_presence = NULL; xmlnode duplicated_presence = NULL; jpacket packet = NULL; /* skip our own session (and sanity check) */ if (cur == m->s || cur->presence == NULL) { continue; } /* send the presence to us: we need a new pool as js_session_to() will free the packet's pool */ pool_for_existing_presence = pool_new(); duplicated_presence = xmlnode_dup_pool(pool_for_existing_presence, cur->presence); xmlnode_put_attrib(duplicated_presence, "to", jid_full(m->user->id)); packet = jpacket_new(duplicated_presence); js_session_to(m->s, packet); } /* probe s10ns and populate A */ mod_presence_roster(m,mp->A); /* we broadcast this baby! */ _mod_presence_broadcast(m->s,mp->conf->bcc,m->packet->x,NULL); _mod_presence_broadcast(m->s,mp->A,m->packet->x,NULL); xmlnode_free(m->packet->x); return M_HANDLED;}/** * update the A and I list, because we send a new presence out * * If we sent out an invisible presence, add the destination to the I list. * * If we sent out an available presence, add the destination to the A list and remove from the I list. * * If we sent out an unavailable presence, remove from both A and I lists. * * @note this is our first callback for outgoing presences, mod_presence_out() is the second, that should be called afterwards * * @param m the mapi structure * @param arg pointer to the modpres structure containing the modules session data (especially the lists A and I) * @return M_IGNORE if the stanza is no presence, else always M_PASS */mreturn mod_presence_avails(mapi m, void *arg){ modpres mp = (modpres)arg; if(m->packet->type != JPACKET_PRESENCE) return M_IGNORE; if(m->packet->to == NULL) return M_PASS; log_debug2(ZONE, LOGT_DELIVER, "track presence sent to jids"); /* handle invisibles: put in I and remove from A */ if(jpacket_subtype(m->packet) == JPACKET__INVISIBLE) { if(mp->I == NULL) mp->I = jid_new(m->s->p,jid_full(m->packet->to)); else jid_append(mp->I, m->packet->to); mp->A = _mod_presence_whack(m->packet->to,mp->A); return M_PASS; } /* ensure not invisible from before */ mp->I = _mod_presence_whack(m->packet->to,mp->I); /* avails to A */ if(jpacket_subtype(m->packet) == JPACKET__AVAILABLE) jid_append(mp->A, m->packet->to); /* unavails from A */ if(jpacket_subtype(m->packet) == JPACKET__UNAVAILABLE) mp->A = _mod_presence_whack(m->packet->to,mp->A); return M_PASS;}/** * callback, that gets called if a session ends * * The session manager has set the presence of the user to unavailable, we have to broadcast this presence * to everybody that thinks we are available. * * @param m the mapi structure * @param arg pointer to the modpres structure containing the lists for this session * @return always M_PASS */mreturn mod_presence_avails_end(mapi m, void *arg){ modpres mp = (modpres)arg; log_debug2(ZONE, LOGT_DELIVER, "avail tracker guarantee checker"); /* send the current presence (which the server set to unavail) */ xmlnode_put_attrib(m->s->presence, "from",jid_full(m->s->id)); _mod_presence_broadcast(m->s, mp->conf->bcc, m->s->presence, NULL); _mod_presence_broadcast(m->s, mp->A, m->s->presence, NULL); _mod_presence_broadcast(m->s, mp->I, m->s->presence, NULL); /* store presence in xdb? */ if (mp->conf->pres_to_xdb > 0) mod_presence_store(m); return M_PASS;}/** * callback, that gets called if a new session is establisched, registers all session oriented callbacks * * This callback is responsible for initializing a new instance of the _modpres structure, that holds * the list of entites that know that a user is available. * * @param m the mapi structure * @param arg the list of JabberIDs that get a bcc of all presences * @return always M_PASS */mreturn mod_presence_session(mapi m, void *arg){ modpres_conf conf = (modpres_conf)arg; modpres mp; /* track our session stuff */ mp = pmalloco(m->s->p, sizeof(_modpres)); mp->A = jid_user(m->s->id); mp->conf = conf; /* no no, it's ok, these live longer than us */ js_mapi_session(es_IN, m->s, mod_presence_in, mp); js_mapi_session(es_OUT, m->s, mod_presence_avails, mp); /* must come first, it passes, _out handles */ js_mapi_session(es_OUT, m->s, mod_presence_out, mp); js_mapi_session(es_END, m->s, mod_presence_avails_end, mp); return M_PASS;}/** * deliver presence stanzas to local users * * This callback ignores all stanzas but presence stanzas. presences sent to a user (without specifying a resource) have to * be delivered to all sessions of this user. * * Presences sent to a specified resource are not handled. * * @param m the mapi structure * @param arg ignored/unused * @return M_IGNORED if not a presence stanza, M_PASS if the presence has not been handled, M_HANDLED if the presence has been handled */mreturn mod_presence_deliver(mapi m, void *arg){ session cur; if(m->packet->type != JPACKET_PRESENCE) return M_IGNORE; log_debug2(ZONE, LOGT_DELIVER, "deliver phase"); /* only if we HAVE a user, and it was sent to ONLY the user@server, and there is at least one session available */ if(m->user != NULL && m->packet->to->resource == NULL && js_session_primary(m->user) != NULL) { log_debug2(ZONE, LOGT_DELIVER, "broadcasting to %s",m->user->user); /* broadcast */ for(cur = m->user->sessions; cur != NULL; cur = cur->next) { if(cur->priority < -128) continue; js_session_to(cur, jpacket_new(xmlnode_dup(m->packet->x))); } if(jpacket_subtype(m->packet) != JPACKET__PROBE) { /* probes get handled by the offline thread as well? */ xmlnode_free(m->packet->x); return M_HANDLED; } } return M_PASS;}/** * init the module, register callbacks * * builds a list of JabberIDs where presences should be blind carbon copied to. * (Enclosing each in a <bcc/> element, which are contained in one <presence/> * element in the session manager configuration.) * * registers mod_presence_session() as a callback, that gets notified on new sessions * and mod_presence_deliver() as a callback to deliver presence stanzas locally. * * @param si the session manager instance */void mod_presence(jsmi si){ xmlnode cfg = js_config(si, "presence"); modpres_conf conf = (modpres_conf)pmalloco(si->p, sizeof(_modpres_conf)); log_debug2(ZONE, LOGT_INIT, "init"); for(cfg = xmlnode_get_firstchild(cfg); cfg != NULL; cfg = xmlnode_get_nextsibling(cfg)) { char *element_name = NULL; if(xmlnode_get_type(cfg) != NTYPE_TAG) continue; element_name = xmlnode_get_name(cfg); if (j_strcmp(element_name, "bcc") == 0) { if(conf->bcc == NULL) conf->bcc = jid_new(si->p,xmlnode_get_data(cfg)); else jid_append(conf->bcc,jid_new(si->p,xmlnode_get_data(cfg))); } else if (j_strcmp(element_name, "presence2xdb") == 0) { conf->pres_to_xdb++; } } js_mapi_register(si,e_DELIVER, mod_presence_deliver, NULL); js_mapi_register(si,e_SESSION, mod_presence_session, (void*)conf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -