jabberd2  2.5.0
mod_status.c
Go to the documentation of this file.
1 /*
2  * jabberd mod_status - Jabber Open Source Server
3  * Copyright (c) 2004 Lucas Nussbaum <lucas@lucas-nussbaum.net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
18  */
19 
27 /* for strndup */
28 #define _GNU_SOURCE
29 #include <string.h>
30 #include "sm.h"
31 
32 typedef struct _status_st {
34  const char *resource;
35 } *status_t;
36 
37 static void _status_os_replace(storage_t st, const char *jid, char *status, char *show, time_t *lastlogin, time_t *lastlogout, nad_t nad) {
38  os_t os = os_new();
39  os_object_t o = os_object_new(os);
40  os_object_put(o, "status", status, os_type_STRING);
41  os_object_put(o, "show", show, os_type_STRING);
42  os_object_put(o, "last-login", (void **) lastlogin, os_type_INTEGER);
43  os_object_put(o, "last-logout", (void **) lastlogout, os_type_INTEGER);
44  if(nad != NULL) os_object_put(o, "xml", nad, os_type_NAD);
45  storage_replace(st, "status", jid, NULL, os);
46  os_free(os);
47 }
48 
49 static void _status_store(storage_t st, const char *jid, pkt_t pkt, time_t *lastlogin, time_t *lastlogout) {
50  char *show;
51  int show_free = 0;
52 
53  switch(pkt->type)
54  {
55  int elem;
56  case pkt_PRESENCE_UN:
57  show = "unavailable";
58  break;
59  default:
60  elem = nad_find_elem(pkt->nad, 1, NAD_ENS(pkt->nad, 1), "show", 1);
61  if (elem < 0)
62  {
63  show = "";
64  }
65  else
66  {
67  if (NAD_CDATA_L(pkt->nad, elem) <= 0 || NAD_CDATA_L(pkt->nad, elem) > 19)
68  show = "";
69  else
70  {
71  show = strndup(NAD_CDATA(pkt->nad, elem), NAD_CDATA_L(pkt->nad, elem));
72  show_free = 1;
73  }
74  }
75  }
76 
77  _status_os_replace(st, jid, "online", show, lastlogin, lastlogout, pkt->nad);
78  if(show_free) free(show);
79 }
80 
82  time_t t, lastlogout;
83  os_t os;
84  os_object_t o;
85  st_ret_t ret;
86  nad_t nad = NULL;
87 
88  /* not interested if there is other top session */
89  if(sess->user->top != NULL && sess != sess->user->top)
90  return mod_PASS;
91 
92  ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os);
93  if (ret == st_SUCCESS)
94  {
95  if (os_iter_first(os))
96  {
97  o = os_iter_object(os);
98  os_object_get_time(os, o, "last-logout", &lastlogout);
99  os_object_get_nad(os, o, "xml", &nad);
100  nad = nad_copy(nad);
101  }
102  os_free(os);
103  }
104  else
105  {
106  lastlogout = (time_t) 0;
107  }
108 
109  t = time(NULL);
110  _status_os_replace(sess->user->sm->st, jid_user(sess->jid), "online", "", &t, &lastlogout, nad);
111 
112  if(nad != NULL) nad_free(nad);
113 
114  return mod_PASS;
115 }
116 
117 static void _status_sess_end(mod_instance_t mi, sess_t sess) {
118  time_t t, lastlogin;
119  os_t os;
120  os_object_t o;
121  st_ret_t ret;
122  nad_t nad = NULL;
123 
124  /* not interested if there is other top session */
125  if(sess->user->top != NULL && sess != sess->user->top)
126  return;
127 
128  ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os);
129  if (ret == st_SUCCESS)
130  {
131  if (os_iter_first(os))
132  {
133  o = os_iter_object(os);
134  os_object_get_time(os, o, "last-login", &lastlogin);
135  os_object_get_nad(os, o, "xml", &nad);
136  nad = nad_copy(nad);
137  }
138  os_free(os);
139  }
140  else
141  {
142  lastlogin = (time_t) 0;
143  }
144 
145  t = time(NULL);
146  _status_os_replace(sess->user->sm->st, jid_user(sess->jid), "offline", "", &lastlogin, &t, nad);
147 
148  if(nad != NULL) nad_free(nad);
149 }
150 
152  time_t lastlogin, lastlogout;
153  os_t os;
154  os_object_t o;
155  st_ret_t ret;
156 
157  /* only handle presence */
158  if(!(pkt->type == pkt_PRESENCE))
159  return mod_PASS;
160 
161  ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os);
162  if (ret == st_SUCCESS)
163  {
164  if (os_iter_first(os))
165  {
166  o = os_iter_object(os);
167  os_object_get_time(os, o, "last-login", &lastlogin);
168  os_object_get_time(os, o, "last-logout", &lastlogout);
169  }
170  os_free(os);
171  }
172  else
173  {
174  lastlogin = (time_t) 0;
175  lastlogout = (time_t) 0;
176  }
177 
178  /* Store only presence broadcasts. If the presence is for a specific user, ignore it. */
179  if (pkt->to == NULL)
180  _status_store(sess->user->sm->st, jid_user(sess->jid), pkt, &lastlogin, &lastlogout);
181 
182  return mod_PASS;
183 }
184 
185 /* presence packets incoming from other servers */
187  time_t t;
188  jid_t jid;
189  module_t mod = mi->mod;
190  status_t st = (status_t) mod->private;
191 
192  /* store presence information */
193  if(pkt->type == pkt_PRESENCE || pkt->type == pkt_PRESENCE_UN) {
194  log_debug(ZONE, "storing presence from %s", jid_full(pkt->from));
195 
196  t = (time_t) 0;
197 
198  _status_store(mod->mm->sm->st, jid_user(pkt->from), pkt, &t, &t);
199  }
200 
201  /* answer to probes and subscription requests*/
202  if(st->resource && (pkt->type == pkt_PRESENCE_PROBE || pkt->type == pkt_S10N)) {
203  log_debug(ZONE, "answering presence probe/sub from %s with /%s resource", jid_full(pkt->from), st->resource);
204 
205  /* send presence */
206  jid = jid_new(pkt->to->domain, -1);
207  jid = jid_reset_components(jid, jid->node, jid->domain, st->resource);
208  pkt_router(pkt_create(st->sm, "presence", NULL, jid_user(pkt->from), jid_full(jid)));
209  jid_free(jid);
210  }
211 
212  /* and handle over */
213  return mod_PASS;
214 
215 }
216 
218  log_debug(ZONE, "deleting status information of %s", jid_user(jid));
219 
220  storage_delete(mi->sm->st, "status", jid_user(jid), NULL);
221 }
222 
223 static void _status_free(module_t mod) {
224  free(mod->private);
225 }
226 
227 DLLEXPORT int module_init(mod_instance_t mi, const char *arg) {
228  module_t mod = mi->mod;
229 
230  status_t tr;
231 
232  if (mod->init) return 0;
233 
234  tr = (status_t) calloc(1, sizeof(struct _status_st));
235 
236  tr->sm = mod->mm->sm;
237  tr->resource = config_get_one(mod->mm->sm->config, "status.resource", 0);
238 
239  mod->private = tr;
240 
242  mod->sess_end = _status_sess_end;
243  mod->in_sess = _status_in_sess;
244  mod->pkt_sm = _status_pkt_sm;
246  mod->free = _status_free;
247 
248  return 0;
249 }
user_t user
user this session belongs to
Definition: sm.h:256
static void _status_sess_end(mod_instance_t mi, sess_t sess)
Definition: mod_status.c:117
pkt_type_t type
packet type
Definition: sm.h:138
jid_t jid
session jid (user@host/res)
Definition: sm.h:258
Definition: nad.h:93
static int _status_sess_start(mod_instance_t mi, sess_t sess)
Definition: mod_status.c:81
data structures and prototypes for the session manager
subscribe request
Definition: sm.h:102
#define NAD_CDATA_L(N, E)
Definition: nad.h:186
static void _status_user_delete(mod_instance_t mi, jid_t jid)
Definition: mod_status.c:217
const char * jid_user(jid_t jid)
expand and return the user
Definition: jid.c:338
const char * jid_full(jid_t jid)
expand and return the full
Definition: jid.c:346
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:446
config_t config
config context
Definition: sm.h:198
int init
number of times the module intialiser has been called
Definition: sm.h:416
void(* sess_end)(mod_instance_t mi, sess_t sess)
sess-end handler
Definition: sm.h:421
sm_t sm
sm context
Definition: sm.h:237
void nad_free(nad_t nad)
free that nad
Definition: nad.c:180
nad_t nad_copy(nad_t nad)
copy a nad
Definition: nad.c:147
mm_t mm
module manager
Definition: sm.h:404
const char * resource
Definition: mod_status.c:34
#define DLLEXPORT
Definition: c2s.h:47
presence (unavailable)
Definition: sm.h:100
sess_t top
top priority session
Definition: sm.h:244
sm_t sm
sm context
Definition: sm.h:366
mod_ret_t(* in_sess)(mod_instance_t mi, sess_t sess, pkt_t pkt)
in-sess handler
Definition: sm.h:423
jid_t jid_reset_components(jid_t jid, const char *node, const char *domain, const char *resource)
build a jid from components
Definition: jid.c:281
module_t mod
module that this is an instance of
Definition: sm.h:449
jid_t from
packet addressing (not used for routing)
Definition: sm.h:140
void * private
module private data
Definition: sm.h:418
packet summary data wrapper
Definition: sm.h:129
storage_t st
storage subsystem
Definition: sm.h:211
nad_t nad
nad of the entire packet
Definition: sm.h:146
session manager global context
Definition: sm.h:167
void jid_free(jid_t jid)
free a jid
Definition: jid.c:286
char * domain
Definition: jid.h:45
Definition: jid.h:42
void pkt_router(pkt_t pkt)
Definition: pkt.c:379
#define log_debug(...)
Definition: log.h:65
static void _status_os_replace(storage_t st, const char *jid, char *status, char *show, time_t *lastlogin, time_t *lastlogout, nad_t nad)
Definition: mod_status.c:37
presence
Definition: sm.h:99
packet was unhandled, should be passed to the next module
Definition: sm.h:340
static void _status_free(module_t mod)
Definition: mod_status.c:223
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
int nad_find_elem(nad_t nad, unsigned int elem, int ns, const char *name, int depth)
locate the next elem at a given depth with an optional matching name
Definition: nad.c:206
void(* user_delete)(mod_instance_t mi, jid_t jid)
user-delete handler
Definition: sm.h:438
mod_ret_t(* pkt_sm)(mod_instance_t mi, pkt_t pkt)
pkt-sm handler
Definition: sm.h:429
jid_t to
Definition: sm.h:140
static void _status_store(storage_t st, const char *jid, pkt_t pkt, time_t *lastlogin, time_t *lastlogout)
Definition: mod_status.c:49
#define NAD_CDATA(N, E)
Definition: nad.h:185
static mod_ret_t _status_pkt_sm(mod_instance_t mi, pkt_t pkt)
Definition: mod_status.c:186
DLLEXPORT int module_init(mod_instance_t mi, const char *arg)
Definition: mod_status.c:227
#define ZONE
Definition: mio_impl.h:76
int(* sess_start)(mod_instance_t mi, sess_t sess)
sess-start handler
Definition: sm.h:420
const char * config_get_one(config_t c, const char *key, int num)
get config value n for this key
Definition: config.c:278
void(* free)(module_t mod)
called when module is freed
Definition: sm.h:442
data for a single module
Definition: sm.h:403
static mod_ret_t _status_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt)
Definition: mod_status.c:151
presence (probe)
Definition: sm.h:101
struct _status_st * status_t
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:338
sm_t sm
sm context
Definition: sm.h:447
char * node
Definition: jid.h:44
#define NAD_ENS(N, E)
Definition: nad.h:196