#include "sm.h"
static mod_ret_t _presence_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) {
if(!(pkt->type & pkt_PRESENCE))
return mod_PASS;
if(pkt->from == NULL || jid_compare_user(pkt->from, sess->jid) != 0) {
if(pkt->from != NULL)
jid_free(pkt->from);
pkt->from = jid_dup(sess->jid);
nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0);
}
if(pkt->to == NULL)
pres_update(sess, pkt);
else
pres_deliver(sess, pkt);
return mod_HANDLED;
}
mod_ret_t _presence_in_router(mod_instance_t mi, pkt_t pkt) {
user_t user;
sess_t sess;
if(!(pkt->type & pkt_PRESENCE))
return mod_PASS;
user = xhash_get(mi->mod->mm->sm->users, jid_user(pkt->to));
if(user == NULL || user->sessions == NULL) {
pkt_free(pkt);
return mod_HANDLED;
}
for(sess = user->sessions; sess != NULL; sess = sess->next)
if(sess->available && sess->pri >= 0)
return mod_PASS;
pkt_free(pkt);
return mod_HANDLED;
}
static mod_ret_t _presence_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) {
sess_t sess;
if(!(pkt->type & pkt_PRESENCE))
return mod_PASS;
if(pkt->type & pkt_ERROR) {
sess = sess_match(user, pkt->to->resource);
if(sess == NULL) {
log_debug(ZONE, "bounced presence, but no corresponding session anymore, dropping");
pkt_free(pkt);
return mod_HANDLED;
}
log_debug(ZONE, "bounced presence, tracking");
pres_error(sess, pkt->from);
if((pkt->type & pkt_PRESENCE_PROBE) == pkt_PRESENCE_PROBE) {
pkt_free(pkt);
return mod_HANDLED;
}
}
if(pkt->type == pkt_PRESENCE_INVIS) {
log_debug(ZONE, "urgh, broken server sent us an invisible, rewriting it");
nad_set_attr(pkt->nad, 1, -1, "type", "unavailable", 11);
pkt->type = pkt_PRESENCE_UN;
}
if(*pkt->to->resource != '\0') {
sess = sess_match(user, pkt->to->resource);
if(sess == NULL)
return -stanza_err_RECIPIENT_UNAVAILABLE;
pkt_sess(pkt, sess);
return mod_HANDLED;
}
pres_in(user, pkt);
return mod_HANDLED;
}
int presence_init(mod_instance_t mi, char *arg) {
module_t mod = mi->mod;
if(mod->init) return 0;
mod->in_sess = _presence_in_sess;
mod->in_router = _presence_in_router;
mod->pkt_user = _presence_pkt_user;
feature_register(mod->mm->sm, "presence");
feature_register(mod->mm->sm, "presence-invisible");
return 0;
}