jabberd2  2.2.17
mod_presence.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "sm.h"
22 
32  /* only handle presence */
33  if(!(pkt->type & pkt_PRESENCE))
34  return mod_PASS;
35 
36  /* reset from if necessary */
37  if(pkt->from == NULL || jid_compare_user(pkt->from, sess->jid) != 0) {
38  if(pkt->from != NULL)
39  jid_free(pkt->from);
40 
41  pkt->from = jid_dup(sess->jid);
42  nad_set_attr(pkt->nad, 1, -1, "from", jid_full(pkt->from), 0);
43  }
44 
45  /* presence broadcast (T1, T2, T3) */
46  if(pkt->to == NULL)
47  pres_update(sess, pkt);
48 
49  /* directed presence (T7, T8) */
50  else
51  pres_deliver(sess, pkt);
52 
53  return mod_HANDLED;
54 }
55 
56 /* drop incoming presence if the user isn't around,
57  * so we don't have to load them during broadcasts */
59  user_t user;
60  sess_t sess;
61 
62  /* only check presence to users, pass presence to sm and probes */
63  if(!(pkt->type & pkt_PRESENCE) || pkt->to->node[0] == '\0' || pkt->type == pkt_PRESENCE_PROBE)
64  return mod_PASS;
65 
66  /* get the user _without_ doing a load */
67  user = xhash_get(mi->mod->mm->sm->users, jid_user(pkt->to));
68 
69  /* no user, or no sessions, bail */
70  if(user == NULL || user->sessions == NULL) {
71  pkt_free(pkt);
72  return mod_HANDLED;
73  }
74 
75  /* only pass if there's at least one available session */
76  for(sess = user->sessions; sess != NULL; sess = sess->next)
77  if(sess->available)
78  return mod_PASS;
79 
80  /* no available sessions, drop */
81  pkt_free(pkt);
82 
83  return mod_HANDLED;
84 }
85 
88  sess_t sess;
89 
90  /* only handle presence */
91  if(!(pkt->type & pkt_PRESENCE))
92  return mod_PASS;
93 
94  /* errors get tracked, but still delivered (T6) */
95  if(pkt->type & pkt_ERROR) {
96  /* find the session */
97  sess = sess_match(user, pkt->to->resource);
98  if(sess == NULL) {
99  log_debug(ZONE, "bounced presence, but no corresponding session anymore, dropping");
100  pkt_free(pkt);
101  return mod_HANDLED;
102  }
103 
104  log_debug(ZONE, "bounced presence, tracking");
105  pres_error(sess, pkt->from);
106 
107  /* bounced probes get dropped */
108  if((pkt->type & pkt_PRESENCE_PROBE) == pkt_PRESENCE_PROBE) {
109  pkt_free(pkt);
110  return mod_HANDLED;
111  }
112  }
113 
114  /* if there's a resource, send it direct */
115  if(pkt->to->resource[0] != '\0') {
116  sess = sess_match(user, pkt->to->resource);
117  if(sess == NULL) {
118  /* resource isn't online - XMPP-IM 11.3 requires we ignore it*/
119  pkt_free(pkt);
120  return mod_HANDLED;
121  }
122 
123  pkt_sess(pkt, sess);
124  return mod_HANDLED;
125  }
126 
127  /* remote presence updates (T4, T5) */
128  pres_in(user, pkt);
129 
130  return mod_HANDLED;
131 }
132 
133 /* presence packets to the sm */
135  module_t mod = mi->mod;
136  jid_t smjid;
137 
138  /* only check presence/subs to server JID */
139  if(!(pkt->type & pkt_PRESENCE || pkt->type & pkt_S10N))
140  return mod_PASS;
141 
142  smjid = jid_new(jid_user(pkt->to), -1);
143 
144  /* handle subscription requests */
145  if(pkt->type == pkt_S10N) {
146  log_debug(ZONE, "accepting subscription request from %s", jid_full(pkt->from));
147 
148  /* accept request */
149  pkt_router(pkt_create(mod->mm->sm, "presence", "subscribed", jid_user(pkt->from), jid_user(smjid)));
150 
151  /* and subscribe back to theirs */
152  pkt_router(pkt_create(mod->mm->sm, "presence", "subscribe", jid_user(pkt->from), jid_user(smjid)));
153 
154  pkt_free(pkt);
155  jid_free(smjid);
156  return mod_HANDLED;
157  }
158 
159  /* handle unsubscribe requests */
160  if(pkt->type == pkt_S10N_UN) {
161  log_debug(ZONE, "accepting unsubscribe request from %s", jid_full(pkt->from));
162 
163  /* ack the request */
164  pkt_router(pkt_create(mod->mm->sm, "presence", "unsubscribed", jid_user(pkt->from), jid_user(smjid)));
165 
166  pkt_free(pkt);
167  jid_free(smjid);
168  return mod_HANDLED;
169  }
170 
171  /* drop the rest */
172  log_debug(ZONE, "dropping presence from %s", jid_full(pkt->from));
173  pkt_free(pkt);
174  jid_free(smjid);
175  return mod_HANDLED;
176 
177 }
178 
179 static void _presence_free(module_t mod) {
180  feature_unregister(mod->mm->sm, "presence");
181 }
182 
184  module_t mod = mi->mod;
185 
186  if(mod->init) return 0;
187 
188  mod->in_sess = _presence_in_sess;
191  mod->pkt_sm = _presence_pkt_sm;
192  mod->free = _presence_free;
193 
194  feature_register(mod->mm->sm, "presence");
195 
196  return 0;
197 }