jabberd2  2.3.2
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 
183 DLLEXPORT int module_init(mod_instance_t mi, const char *arg) {
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 }
mod_ret_t(* pkt_sm)(mod_instance_t mi, pkt_t pkt)
pkt-sm handler
Definition: sm.h:428
pkt_type_t type
packet type
Definition: sm.h:138
jid_t jid
session jid (user@host/res)
Definition: sm.h:257
data structures and prototypes for the session manager
subscribe request
Definition: sm.h:102
packet error
Definition: sm.h:115
const char * jid_user(jid_t jid)
expand and return the user
Definition: jid.c:339
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:347
jid_t jid_new(const char *id, int len)
make a new jid
Definition: jid.c:81
single instance of a module in a chain
Definition: sm.h:445
int init
number of times the module intialiser has been called
Definition: sm.h:415
char * resource
Definition: jid.h:46
static void _presence_free(module_t mod)
Definition: mod_presence.c:179
xht users
pointers to currently loaded users (key is user@domain)
Definition: sm.h:188
mm_t mm
module manager
Definition: sm.h:403
#define DLLEXPORT
Definition: c2s.h:47
static mod_ret_t _presence_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt)
presence to a user
Definition: mod_presence.c:87
sess_t next
next session (in a list of sessions)
Definition: sm.h:275
void nad_set_attr(nad_t nad, int elem, int ns, const char *name, const char *val, int vallen)
create, update, or zap any matching attr on this elem
Definition: nad.c:375
sm_t sm
sm context
Definition: sm.h:365
sess_t sessions
list of action sessions
Definition: sm.h:242
module_t mod
module that this is an instance of
Definition: sm.h:448
jid_t from
packet addressing (not used for routing)
Definition: sm.h:140
void feature_unregister(sm_t sm, const char *feature)
unregister feature
Definition: feature.c:45
packet summary data wrapper
Definition: sm.h:129
static mod_ret_t _presence_pkt_sm(mod_instance_t mi, pkt_t pkt)
Definition: mod_presence.c:134
nad_t nad
nad of the entire packet
Definition: sm.h:146
void pres_in(user_t user, pkt_t pkt)
presence updates from a remote jid - RFC 3921bis 4.3.2.
Definition: pres.c:212
void jid_free(jid_t jid)
free a jid
Definition: jid.c:286
mod_ret_t(* in_sess)(mod_instance_t mi, sess_t sess, pkt_t pkt)
in-sess handler
Definition: sm.h:422
Definition: jid.h:42
void pkt_router(pkt_t pkt)
Definition: pkt.c:379
void pkt_free(pkt_t pkt)
Definition: pkt.c:315
#define log_debug(...)
Definition: log.h:65
DLLEXPORT int module_init(mod_instance_t mi, const char *arg)
Definition: mod_presence.c:183
void feature_register(sm_t sm, const char *feature)
register a feature
Definition: feature.c:37
sess_t sess_match(user_t user, const char *resource)
match a session by resource
Definition: sess.c:206
presence
Definition: sm.h:99
packet was unhandled, should be passed to the next module
Definition: sm.h:339
mod_ret_t _presence_in_router(mod_instance_t mi, pkt_t pkt)
Definition: mod_presence.c:58
packet was handled (and freed)
Definition: sm.h:338
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
unsubscribe request
Definition: sm.h:104
int jid_compare_user(jid_t a, jid_t b)
compare the user portion of two jids
Definition: jid.c:355
void pres_error(sess_t sess, jid_t jid)
Definition: pres.c:296
void(* free)(module_t mod)
called when module is freed
Definition: sm.h:441
int available
true if this session is available
Definition: sm.h:266
jid_t to
Definition: sm.h:140
static mod_ret_t _presence_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt)
presence from the session
Definition: mod_presence.c:31
mod_ret_t(* pkt_user)(mod_instance_t mi, user_t user, pkt_t pkt)
pkt-user handler
Definition: sm.h:429
mod_ret_t(* in_router)(mod_instance_t mi, pkt_t pkt)
in-router handler
Definition: sm.h:423
jid_t jid_dup(jid_t jid)
duplicate a jid
Definition: jid.c:373
void * xhash_get(xht h, const char *key)
Definition: xhash.c:184
#define ZONE
Definition: mio_impl.h:76
data for a single module
Definition: sm.h:402
void pres_update(sess_t sess, pkt_t pkt)
presence updates from a session
Definition: pres.c:72
presence (probe)
Definition: sm.h:101
pkt_t pkt_create(sm_t sm, const char *elem, const char *type, const char *to, const char *from)
Definition: pkt.c:328
mod_ret_t
module return values
Definition: sm.h:337
void pres_deliver(sess_t sess, pkt_t pkt)
outgoing directed presence
Definition: pres.c:304
void pkt_sess(pkt_t pkt, sess_t sess)
Definition: pkt.c:459
char * node
Definition: jid.h:44
data for a single user
Definition: sm.h:233