Initial revision
[OpenSRF.git] / src / patch / mod_offline.c
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
22 /** ! ! !  Patched version to disable offline storage for jabberd-2.0s4 ! ! ! */
23
24 #include "sm.h"
25
26 /** @file sm/mod_offline.c
27   * @brief offline storage
28   * @author Robert Norris
29   * $Date$
30   * $Revision$
31   */
32
33 typedef struct _mod_offline_st {
34     int dropmessages;
35     int dropsubscriptions;
36 } *mod_offline_t;
37
38 static mod_ret_t _offline_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) {
39     st_ret_t ret;
40     os_t os;
41     os_object_t o;
42     os_type_t ot;
43     nad_t nad;
44     pkt_t queued;
45     int ns, elem, attr;
46     char cttl[15], cstamp[18];
47     time_t ttl, stamp;
48
49     /* if they're becoming available for the first time */
50     if(pkt->type == pkt_PRESENCE && pkt->to == NULL && sess->user->top == NULL) {
51
52         ret = storage_get(pkt->sm->st, "queue", jid_user(sess->jid), NULL, &os);
53         if(ret != st_SUCCESS) {
54             log_debug(ZONE, "storage_get returned %d", ret);
55             return mod_PASS;
56         }
57         
58         if(os_iter_first(os))
59             do {
60                 o = os_iter_object(os);
61
62                 if(os_object_get(o, "xml", (void **) &nad, &ot)) {
63                     queued = pkt_new(pkt->sm, nad_copy(nad));
64                     if(queued == NULL) {
65                         log_debug(ZONE, "invalid queued packet, not delivering");
66                     } else {
67                         /* check expiry as necessary */
68                         if((ns = nad_find_scoped_namespace(queued->nad, uri_EXPIRE, NULL)) >= 0 &&
69                            (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 &&
70                            (attr = nad_find_attr(queued->nad, elem, -1, "seconds", NULL)) >= 0) {
71                             snprintf(cttl, 15, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr));
72                             ttl = atoi(cttl);
73
74                             /* it should have a x:delay stamp, because we stamp everything we store */
75                             if((ns = nad_find_scoped_namespace(queued->nad, uri_DELAY, NULL)) >= 0 &&
76                                (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 &&
77                                (attr = nad_find_attr(queued->nad, elem, -1, "stamp", NULL)) >= 0) {
78                                 snprintf(cstamp, 18, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr));
79                                 stamp = datetime_in(cstamp);
80
81                                 if(stamp + ttl <= time(NULL)) {
82                                     log_debug(ZONE, "queued packet has expired, dropping");
83                                     pkt_free(queued);
84                                     continue;
85                                 }
86                             }
87                         }
88
89                         log_debug(ZONE, "delivering queued packet to %s", jid_full(sess->jid));
90                         pkt_sess(queued, sess);
91                     }
92                 }
93             } while(os_iter_next(os));
94
95         os_free(os);
96
97         /* drop the spool */
98         storage_delete(pkt->sm->st, "queue", jid_user(sess->jid), NULL);
99     }
100
101     /* pass it so that other modules and mod_presence can get it */
102     return mod_PASS;
103 }
104
105 static mod_ret_t _offline_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) {
106     mod_offline_t offline = (mod_offline_t) mi->mod->private;
107     int ns, elem, attr;
108     os_t os;
109     os_object_t o;
110     pkt_t event;
111
112     /* send messages and s10ns to the top session */
113     if(user->top != NULL && (pkt->type & pkt_MESSAGE || pkt->type & pkt_S10N)) {
114         pkt_sess(pkt, user->top);
115         return mod_HANDLED;
116     }
117
118     /* save messages and s10ns for later */
119     if((pkt->type & pkt_MESSAGE && !offline->dropmessages) ||
120        (pkt->type & pkt_S10N && !offline->dropsubscriptions)) {
121         log_debug(ZONE, "saving message for later");
122
123         pkt_delay(pkt, time(NULL), user->sm->id);
124
125         /* new object */
126         os = os_new();
127         o = os_object_new(os);
128
129         os_object_put(o, "xml", pkt->nad, os_type_NAD);
130
131         /* store it */
132         switch(storage_put(user->sm->st, "queue", jid_user(user->jid), os)) {
133             case st_FAILED:
134                 os_free(os);
135                 return -stanza_err_INTERNAL_SERVER_ERROR;
136
137             case st_NOTIMPL:
138                 os_free(os);
139                 return -stanza_err_SERVICE_UNAVAILABLE;     /* xmpp-im 9.5#4 */
140
141             default:
142                 os_free(os);
143
144                 /* send offline events if they asked for it */
145                 if((ns = nad_find_scoped_namespace(pkt->nad, uri_EVENT, NULL)) >= 0 &&
146                    (elem = nad_find_elem(pkt->nad, 1, ns, "x", 1)) >= 0 &&
147                    nad_find_elem(pkt->nad, elem, ns, "offline", 1) >= 0) {
148
149                     event = pkt_create(user->sm, "message", NULL, jid_full(pkt->from), jid_full(pkt->to));
150
151                     attr = nad_find_attr(pkt->nad, 1, -1, "type", NULL);
152                     if(attr >= 0)
153                         nad_set_attr(event->nad, 1, -1, "type", NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
154
155                     ns = nad_add_namespace(event->nad, uri_EVENT, NULL);
156                     nad_append_elem(event->nad, ns, "x", 2);
157                     nad_append_elem(event->nad, ns, "offline", 3);
158
159                     nad_append_elem(event->nad, ns, "id", 3);
160                     attr = nad_find_attr(pkt->nad, 1, -1, "id", NULL);
161                     if(attr >= 0)
162                         nad_append_cdata(event->nad, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr), 4);
163
164                     pkt_router(event);
165                 }
166
167                 pkt_free(pkt);
168                 return mod_HANDLED;
169         }
170     }
171
172     return mod_PASS;
173 }
174
175 static void _offline_user_delete(mod_instance_t mi, jid_t jid) {
176     os_t os;
177     os_object_t o;
178     os_type_t ot;
179     nad_t nad;
180     pkt_t queued;
181     int ns, elem, attr;
182     char cttl[15], cstamp[18];
183     time_t ttl, stamp;
184
185     log_debug(ZONE, "deleting queue for %s", jid_user(jid));
186
187     /* bounce the queue */
188     if(storage_get(mi->mod->mm->sm->st, "queue", jid_user(jid), NULL, &os) == st_SUCCESS) {
189         if(os_iter_first(os))
190             do {
191                 o = os_iter_object(os);
192
193                 if(os_object_get(o, "xml", (void **) &nad, &ot)) {
194                     queued = pkt_new(mi->mod->mm->sm, nad);
195                     if(queued == NULL) {
196                         log_debug(ZONE, "invalid queued packet, not delivering");
197                     } else {
198                         /* check expiry as necessary */
199                         if((ns = nad_find_scoped_namespace(queued->nad, uri_EXPIRE, NULL)) >= 0 &&
200                            (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 &&
201                            (attr = nad_find_attr(queued->nad, elem, -1, "seconds", NULL)) >= 0) {
202                             snprintf(cttl, 15, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr));
203                             ttl = atoi(cttl);
204
205                             /* it should have a x:delay stamp, because we stamp everything we store */
206                             if((ns = nad_find_scoped_namespace(queued->nad, uri_DELAY, NULL)) >= 0 &&
207                                (elem = nad_find_elem(queued->nad, 1, ns, "x", 1)) >= 0 &&
208                                (attr = nad_find_attr(queued->nad, elem, -1, "stamp", NULL)) >= 0) {
209                                 snprintf(cstamp, 18, "%.*s", NAD_AVAL_L(queued->nad, attr), NAD_AVAL(queued->nad, attr));
210                                 stamp = datetime_in(cstamp);
211
212                                 if(stamp + ttl <= time(NULL)) {
213                                     log_debug(ZONE, "queued packet has expired, dropping");
214                                     pkt_free(queued);
215                                     continue;
216                                 }
217                             }
218                         }
219
220                         log_debug(ZONE, "bouncing queued packet from %s", jid_full(queued->from));
221                         pkt_router(pkt_error(queued, stanza_err_ITEM_NOT_FOUND));
222                     }
223                 }
224             } while(os_iter_next(os));
225
226         os_free(os);
227     }
228     
229     storage_delete(mi->sm->st, "queue", jid_user(jid), NULL);
230 }
231
232 static void _offline_free(module_t mod) {
233     mod_offline_t offline = (mod_offline_t) mod->private;
234
235     free(offline);
236 }
237
238 int offline_init(mod_instance_t mi, char *arg) {
239     module_t mod = mi->mod;
240     char *configval;
241     mod_offline_t offline;
242     int dropmessages = 0;
243     int dropsubscriptions = 0;
244
245     if(mod->init) return 0;
246
247     configval = config_get_one(mod->mm->sm->config, "offline.dropmessages", 0);
248     if (configval != NULL)
249         dropmessages = 1;
250     configval = config_get_one(mod->mm->sm->config, "offline.dropsubscriptions", 0);
251     if (configval != NULL)
252         dropsubscriptions = 1;
253
254     offline = (mod_offline_t) malloc(sizeof(struct _mod_offline_st));
255     offline->dropmessages = dropmessages;
256     offline->dropsubscriptions = dropsubscriptions;
257
258     mod->private = offline;
259
260     mod->in_sess = _offline_in_sess;
261     mod->pkt_user = _offline_pkt_user;
262     mod->user_delete = _offline_user_delete;
263     mod->free = _offline_free;
264
265     return 0;
266 }