jabberd2  2.2.16
sm/mod_presence.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 
00031 static mod_ret_t _presence_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) {
00032     /* only handle presence */
00033     if(!(pkt->type & pkt_PRESENCE))
00034         return mod_PASS;
00035 
00036     /* reset from if necessary */
00037     if(pkt->from == NULL || jid_compare_user(pkt->from, sess->jid) != 0) {
00038         if(pkt->from != NULL)
00039             jid_free(pkt->from);
00040 
00041         pkt->from = jid_dup(sess->jid);
00042         nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0);
00043     }
00044 
00045     /* presence broadcast (T1, T2, T3) */
00046     if(pkt->to == NULL)
00047         pres_update(sess, pkt);
00048 
00049     /* directed presence (T7, T8) */
00050     else
00051         pres_deliver(sess, pkt);
00052 
00053     return mod_HANDLED;
00054 }
00055 
00056 /* drop incoming presence if the user isn't around,
00057  * so we don't have to load them during broadcasts */
00058 mod_ret_t _presence_in_router(mod_instance_t mi, pkt_t pkt) {
00059     user_t user;
00060     sess_t sess;
00061 
00062     /* only check presence to users, pass presence to sm and probes */
00063     if(!(pkt->type & pkt_PRESENCE) || pkt->to->node[0] == '\0' || pkt->type == pkt_PRESENCE_PROBE)
00064         return mod_PASS;
00065 
00066     /* get the user _without_ doing a load */
00067     user = xhash_get(mi->mod->mm->sm->users, jid_user(pkt->to));
00068 
00069     /* no user, or no sessions, bail */
00070     if(user == NULL || user->sessions == NULL) {
00071         pkt_free(pkt);
00072         return mod_HANDLED;
00073     }
00074 
00075     /* only pass if there's at least one available session */
00076     for(sess = user->sessions; sess != NULL; sess = sess->next)
00077         if(sess->available)
00078             return mod_PASS;
00079 
00080     /* no available sessions, drop */
00081     pkt_free(pkt);
00082 
00083     return mod_HANDLED;
00084 }
00085 
00087 static mod_ret_t _presence_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) {
00088     sess_t sess;
00089 
00090     /* only handle presence */
00091     if(!(pkt->type & pkt_PRESENCE))
00092         return mod_PASS;
00093 
00094     /* errors get tracked, but still delivered (T6) */
00095     if(pkt->type & pkt_ERROR) {
00096         /* find the session */
00097         sess = sess_match(user, pkt->to->resource);
00098         if(sess == NULL) {
00099             log_debug(ZONE, "bounced presence, but no corresponding session anymore, dropping");
00100             pkt_free(pkt);
00101             return mod_HANDLED;
00102         }
00103             
00104         log_debug(ZONE, "bounced presence, tracking");
00105         pres_error(sess, pkt->from);
00106 
00107         /* bounced probes get dropped */
00108         if((pkt->type & pkt_PRESENCE_PROBE) == pkt_PRESENCE_PROBE) {
00109             pkt_free(pkt);
00110             return mod_HANDLED;
00111         }
00112     }
00113 
00114     /* if there's a resource, send it direct */
00115     if(pkt->to->resource[0] != '\0') {
00116         sess = sess_match(user, pkt->to->resource);
00117         if(sess == NULL) {
00118             /* resource isn't online - XMPP-IM 11.3 requires we ignore it*/
00119             pkt_free(pkt);
00120             return mod_HANDLED;
00121         }
00122 
00123         pkt_sess(pkt, sess);
00124         return mod_HANDLED;
00125     }
00126 
00127     /* remote presence updates (T4, T5) */
00128     pres_in(user, pkt);
00129 
00130     return mod_HANDLED;
00131 }
00132 
00133 /* presence packets to the sm */
00134 static mod_ret_t _presence_pkt_sm(mod_instance_t mi, pkt_t pkt) {
00135     module_t mod = mi->mod;
00136     jid_t smjid;
00137 
00138     /* only check presence/subs to server JID */
00139     if(!(pkt->type & pkt_PRESENCE || pkt->type & pkt_S10N))
00140         return mod_PASS;
00141 
00142     smjid = jid_new(jid_user(pkt->to), -1);
00143 
00144     /* handle subscription requests */
00145     if(pkt->type == pkt_S10N) {
00146         log_debug(ZONE, "accepting subscription request from %s", jid_full(pkt->from));
00147 
00148         /* accept request */
00149         pkt_router(pkt_create(mod->mm->sm, "presence", "subscribed", jid_user(pkt->from), jid_user(smjid)));
00150 
00151         /* and subscribe back to theirs */
00152         pkt_router(pkt_create(mod->mm->sm, "presence", "subscribe", jid_user(pkt->from), jid_user(smjid)));
00153 
00154         pkt_free(pkt);
00155         jid_free(smjid);
00156         return mod_HANDLED;
00157     }
00158 
00159     /* handle unsubscribe requests */
00160     if(pkt->type == pkt_S10N_UN) {
00161         log_debug(ZONE, "accepting unsubscribe request from %s", jid_full(pkt->from));
00162 
00163         /* ack the request */
00164         pkt_router(pkt_create(mod->mm->sm, "presence", "unsubscribed", jid_user(pkt->from), jid_user(smjid)));
00165 
00166         pkt_free(pkt);
00167         jid_free(smjid);
00168         return mod_HANDLED;
00169     }
00170 
00171     /* drop the rest */
00172     log_debug(ZONE, "dropping presence from %s", jid_full(pkt->from));
00173     pkt_free(pkt);
00174     jid_free(smjid);
00175     return mod_HANDLED;
00176 
00177 }
00178 
00179 static void _presence_free(module_t mod) {
00180     feature_unregister(mod->mm->sm, "presence");
00181 }
00182 
00183 DLLEXPORT int module_init(mod_instance_t mi, char *arg) {
00184     module_t mod = mi->mod;
00185 
00186     if(mod->init) return 0;
00187 
00188     mod->in_sess = _presence_in_sess;
00189     mod->in_router = _presence_in_router;
00190     mod->pkt_user = _presence_pkt_user;
00191     mod->pkt_sm = _presence_pkt_sm;
00192     mod->free = _presence_free;
00193 
00194     feature_register(mod->mm->sm, "presence");
00195 
00196     return 0;
00197 }