jabberd2  2.3.1
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;
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  nad = NULL;
108  }
109 
110  t = time(NULL);
111  _status_os_replace(sess->user->sm->st, jid_user(sess->jid), "online", "", &t, &lastlogout, nad);
112 
113  if(nad != NULL) nad_free(nad);
114 
115  return mod_PASS;
116 }
117 
118 static void _status_sess_end(mod_instance_t mi, sess_t sess) {
119  time_t t, lastlogin;
120  os_t os;
121  os_object_t o;
122  st_ret_t ret;
123  nad_t nad;
124 
125  /* not interested if there is other top session */
126  if(sess->user->top != NULL && sess != sess->user->top)
127  return;
128 
129  ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os);
130  if (ret == st_SUCCESS)
131  {
132  if (os_iter_first(os))
133  {
134  o = os_iter_object(os);
135  os_object_get_time(os, o, "last-login", &lastlogin);
136  os_object_get_nad(os, o, "xml", &nad);
137  nad = nad_copy(nad);
138  }
139  os_free(os);
140  }
141  else
142  {
143  lastlogin = (time_t) 0;
144  nad = NULL;
145  }
146 
147  t = time(NULL);
148  _status_os_replace(sess->user->sm->st, jid_user(sess->jid), "offline", "", &lastlogin, &t, nad);
149 
150  if(nad != NULL) nad_free(nad);
151 }
152 
154  time_t lastlogin, lastlogout;
155  os_t os;
156  os_object_t o;
157  st_ret_t ret;
158 
159  /* only handle presence */
160  if(!(pkt->type & pkt_PRESENCE))
161  return mod_PASS;
162 
163  ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os);
164  if (ret == st_SUCCESS)
165  {
166  if (os_iter_first(os))
167  {
168  o = os_iter_object(os);
169  os_object_get_time(os, o, "last-login", &lastlogin);
170  os_object_get_time(os, o, "last-logout", &lastlogout);
171  }
172  os_free(os);
173  }
174  else
175  {
176  lastlogin = (time_t) 0;
177  lastlogout = (time_t) 0;
178  }
179 
180  /* Store only presence broadcasts. If the presence is for a specific user, ignore it. */
181  if (pkt->to == NULL)
182  _status_store(sess->user->sm->st, jid_user(sess->jid), pkt, &lastlogin, &lastlogout);
183 
184  return mod_PASS;
185 }
186 
187 /* presence packets incoming from other servers */
189  time_t t;
190  jid_t jid;
191  module_t mod = mi->mod;
192  status_t st = (status_t) mod->private;
193 
194  /* store presence information */
195  if(pkt->type == pkt_PRESENCE || pkt->type == pkt_PRESENCE_UN) {
196  log_debug(ZONE, "storing presence from %s", jid_full(pkt->from));
197 
198  t = (time_t) 0;
199 
200  _status_store(mod->mm->sm->st, jid_user(pkt->from), pkt, &t, &t);
201  }
202 
203  /* answer to probes and subscription requests*/
204  if(st->resource && (pkt->type == pkt_PRESENCE_PROBE || pkt->type == pkt_S10N)) {
205  log_debug(ZONE, "answering presence probe/sub from %s with /%s resource", jid_full(pkt->from), st->resource);
206 
207  /* send presence */
208  jid = jid_new(pkt->to->domain, -1);
209  jid = jid_reset_components(jid, jid->node, jid->domain, st->resource);
210  pkt_router(pkt_create(st->sm, "presence", NULL, jid_user(pkt->from), jid_full(jid)));
211  jid_free(jid);
212  }
213 
214  /* and handle over */
215  return mod_PASS;
216 
217 }
218 
220  log_debug(ZONE, "deleting status information of %s", jid_user(jid));
221 
222  storage_delete(mi->sm->st, "status", jid_user(jid), NULL);
223 }
224 
225 static void _status_free(module_t mod) {
226  free(mod->private);
227 }
228 
229 DLLEXPORT int module_init(mod_instance_t mi, const char *arg) {
230  module_t mod = mi->mod;
231 
232  status_t tr;
233 
234  if (mod->init) return 0;
235 
236  tr = (status_t) calloc(1, sizeof(struct _status_st));
237 
238  tr->sm = mod->mm->sm;
239  tr->resource = config_get_one(mod->mm->sm->config, "status.resource", 0);
240 
241  mod->private = tr;
242 
244  mod->sess_end = _status_sess_end;
245  mod->in_sess = _status_in_sess;
246  mod->pkt_sm = _status_pkt_sm;
248  mod->free = _status_free;
249 
250  return 0;
251 }
mod_ret_t(* pkt_sm)(mod_instance_t mi, pkt_t pkt)
pkt-sm handler
Definition: sm.h:428
user_t user
user this session belongs to
Definition: sm.h:255
static void _status_sess_end(mod_instance_t mi, sess_t sess)
Definition: mod_status.c:118
pkt_type_t type
packet type
Definition: sm.h:138
jid_t jid
session jid (user@host/res)
Definition: sm.h:257
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:219
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 nad_find_elem(nad_t nad, 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:204
config_t config
config context
Definition: sm.h:197
int init
number of times the module intialiser has been called
Definition: sm.h:415
sm_t sm
sm context
Definition: sm.h:236
void nad_free(nad_t nad)
free that nad
Definition: nad.c:178
nad_t nad_copy(nad_t nad)
copy a nad
Definition: nad.c:145
mm_t mm
module manager
Definition: sm.h:403
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:243
sm_t sm
sm context
Definition: sm.h:365
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:448
jid_t from
packet addressing (not used for routing)
Definition: sm.h:140
void * private
module private data
Definition: sm.h:417
packet summary data wrapper
Definition: sm.h:129
storage_t st
storage subsystem
Definition: sm.h:210
nad_t nad
nad of the entire packet
Definition: sm.h:146
int(* sess_start)(mod_instance_t mi, sess_t sess)
sess-start handler
Definition: sm.h:419
session manager global context
Definition: sm.h:167
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
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
DLLEXPORT int module_init(mod_instance_t mi, const char *arg)
Definition: mod_active.c:70
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
void(* user_delete)(mod_instance_t mi, jid_t jid)
user-delete handler
Definition: sm.h:437
presence
Definition: sm.h:99
packet was unhandled, should be passed to the next module
Definition: sm.h:339
static void _status_free(module_t mod)
Definition: mod_status.c:225
There is one instance of this struct per user who is logged in to this c2s instance.
Definition: c2s.h:74
void(* free)(module_t mod)
called when module is freed
Definition: sm.h:441
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:188
#define ZONE
Definition: mio_impl.h:76
const char * config_get_one(config_t c, const char *key, int num)
get config value n for this key
Definition: config.c:277
data for a single module
Definition: sm.h:402
static mod_ret_t _status_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt)
Definition: mod_status.c:153
void(* sess_end)(mod_instance_t mi, sess_t sess)
sess-end handler
Definition: sm.h:420
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:337
sm_t sm
sm context
Definition: sm.h:446
char * node
Definition: jid.h:44
#define NAD_ENS(N, E)
Definition: nad.h:196