jabberd2
2.2.16
|
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 }