jabberd2
2.2.16
|
00001 /* 00002 * jabberd mod_status - Jabber Open Source Server 00003 * Copyright (c) 2004 Lucas Nussbaum <lucas@lucas-nussbaum.net> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA 00018 */ 00019 00027 /* for strndup */ 00028 #define _GNU_SOURCE 00029 #include <string.h> 00030 #include "sm.h" 00031 00032 typedef struct _status_st { 00033 sm_t sm; 00034 char *resource; 00035 } *status_t; 00036 00037 static void _status_os_replace(storage_t st, const unsigned char *jid, char *status, char *show, time_t *lastlogin, time_t *lastlogout, nad_t nad) { 00038 os_t os = os_new(); 00039 os_object_t o = os_object_new(os); 00040 os_object_put(o, "status", status, os_type_STRING); 00041 os_object_put(o, "show", show, os_type_STRING); 00042 os_object_put(o, "last-login", (void **) lastlogin, os_type_INTEGER); 00043 os_object_put(o, "last-logout", (void **) lastlogout, os_type_INTEGER); 00044 if(nad != NULL) os_object_put(o, "xml", nad, os_type_NAD); 00045 storage_replace(st, "status", jid, NULL, os); 00046 os_free(os); 00047 } 00048 00049 static void _status_store(storage_t st, const unsigned char *jid, pkt_t pkt, time_t *lastlogin, time_t *lastlogout) { 00050 char *show; 00051 int show_free = 0; 00052 00053 switch(pkt->type) 00054 { 00055 int elem; 00056 case pkt_PRESENCE_UN: 00057 show = "unavailable"; 00058 break; 00059 default: 00060 elem = nad_find_elem(pkt->nad, 1, NAD_ENS(pkt->nad, 1), "show", 1); 00061 if (elem < 0) 00062 { 00063 show = ""; 00064 } 00065 else 00066 { 00067 if (NAD_CDATA_L(pkt->nad, elem) <= 0 || NAD_CDATA_L(pkt->nad, elem) > 19) 00068 show = ""; 00069 else 00070 { 00071 show = strndup(NAD_CDATA(pkt->nad, elem), NAD_CDATA_L(pkt->nad, elem)); 00072 show_free = 1; 00073 } 00074 } 00075 } 00076 00077 _status_os_replace(st, jid, "online", show, lastlogin, lastlogout, pkt->nad); 00078 if(show_free) free(show); 00079 } 00080 00081 static int _status_sess_start(mod_instance_t mi, sess_t sess) { 00082 time_t t, lastlogout; 00083 os_t os; 00084 os_object_t o; 00085 st_ret_t ret; 00086 nad_t nad; 00087 00088 /* not interested if there is other top session */ 00089 if(sess->user->top != NULL && sess != sess->user->top) 00090 return mod_PASS; 00091 00092 ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os); 00093 if (ret == st_SUCCESS) 00094 { 00095 if (os_iter_first(os)) 00096 { 00097 o = os_iter_object(os); 00098 os_object_get_time(os, o, "last-logout", &lastlogout); 00099 os_object_get_nad(os, o, "xml", &nad); 00100 nad = nad_copy(nad); 00101 } 00102 os_free(os); 00103 } 00104 else 00105 { 00106 lastlogout = (time_t) 0; 00107 nad = NULL; 00108 } 00109 00110 t = time(NULL); 00111 _status_os_replace(sess->user->sm->st, jid_user(sess->jid), "online", "", &t, &lastlogout, nad); 00112 00113 if(nad != NULL) nad_free(nad); 00114 00115 return mod_PASS; 00116 } 00117 00118 static void _status_sess_end(mod_instance_t mi, sess_t sess) { 00119 time_t t, lastlogin; 00120 os_t os; 00121 os_object_t o; 00122 st_ret_t ret; 00123 nad_t nad; 00124 00125 /* not interested if there is other top session */ 00126 if(sess->user->top != NULL && sess != sess->user->top) 00127 return; 00128 00129 ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os); 00130 if (ret == st_SUCCESS) 00131 { 00132 if (os_iter_first(os)) 00133 { 00134 o = os_iter_object(os); 00135 os_object_get_time(os, o, "last-login", &lastlogin); 00136 os_object_get_nad(os, o, "xml", &nad); 00137 nad = nad_copy(nad); 00138 } 00139 os_free(os); 00140 } 00141 else 00142 { 00143 lastlogin = (time_t) 0; 00144 nad = NULL; 00145 } 00146 00147 t = time(NULL); 00148 _status_os_replace(sess->user->sm->st, jid_user(sess->jid), "offline", "", &lastlogin, &t, nad); 00149 00150 if(nad != NULL) nad_free(nad); 00151 } 00152 00153 static mod_ret_t _status_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { 00154 time_t lastlogin, lastlogout; 00155 os_t os; 00156 os_object_t o; 00157 st_ret_t ret; 00158 00159 /* only handle presence */ 00160 if(!(pkt->type & pkt_PRESENCE)) 00161 return mod_PASS; 00162 00163 ret = storage_get(sess->user->sm->st, "status", jid_user(sess->jid), NULL, &os); 00164 if (ret == st_SUCCESS) 00165 { 00166 if (os_iter_first(os)) 00167 { 00168 o = os_iter_object(os); 00169 os_object_get_time(os, o, "last-login", &lastlogin); 00170 os_object_get_time(os, o, "last-logout", &lastlogout); 00171 } 00172 os_free(os); 00173 } 00174 else 00175 { 00176 lastlogin = (time_t) 0; 00177 lastlogout = (time_t) 0; 00178 } 00179 00180 /* Store only presence broadcasts. If the presence is for a specific user, ignore it. */ 00181 if (pkt->to == NULL) 00182 _status_store(sess->user->sm->st, jid_user(sess->jid), pkt, &lastlogin, &lastlogout); 00183 00184 return mod_PASS; 00185 } 00186 00187 /* presence packets incoming from other servers */ 00188 static mod_ret_t _status_pkt_sm(mod_instance_t mi, pkt_t pkt) { 00189 time_t t; 00190 jid_t jid; 00191 module_t mod = mi->mod; 00192 status_t st = (status_t) mod->private; 00193 00194 /* store presence information */ 00195 if(pkt->type == pkt_PRESENCE || pkt->type == pkt_PRESENCE_UN) { 00196 log_debug(ZONE, "storing presence from %s", jid_full(pkt->from)); 00197 00198 t = (time_t) 0; 00199 00200 _status_store(mod->mm->sm->st, jid_user(pkt->from), pkt, &t, &t); 00201 } 00202 00203 /* answer to probes and subscription requests*/ 00204 if(st->resource && (pkt->type == pkt_PRESENCE_PROBE || pkt->type == pkt_S10N)) { 00205 log_debug(ZONE, "answering presence probe/sub from %s with /%s resource", jid_full(pkt->from), st->resource); 00206 00207 /* send presence */ 00208 jid = jid_new(pkt->to->domain, -1); 00209 jid = jid_reset_components(jid, jid->node, jid->domain, st->resource); 00210 pkt_router(pkt_create(st->sm, "presence", NULL, jid_user(pkt->from), jid_full(jid))); 00211 jid_free(jid); 00212 } 00213 00214 /* and handle over */ 00215 return mod_PASS; 00216 00217 } 00218 00219 static void _status_user_delete(mod_instance_t mi, jid_t jid) { 00220 log_debug(ZONE, "deleting status information of %s", jid_user(jid)); 00221 00222 storage_delete(mi->sm->st, "status", jid_user(jid), NULL); 00223 } 00224 00225 static void _status_free(module_t mod) { 00226 free(mod->private); 00227 } 00228 00229 DLLEXPORT int module_init(mod_instance_t mi, char *arg) { 00230 module_t mod = mi->mod; 00231 00232 status_t tr; 00233 00234 if (mod->init) return 0; 00235 00236 tr = (status_t) calloc(1, sizeof(struct _status_st)); 00237 00238 tr->sm = mod->mm->sm; 00239 tr->resource = config_get_one(mod->mm->sm->config, "status.resource", 0); 00240 00241 mod->private = tr; 00242 00243 mod->sess_start = _status_sess_start; 00244 mod->sess_end = _status_sess_end; 00245 mod->in_sess = _status_in_sess; 00246 mod->pkt_sm = _status_pkt_sm; 00247 mod->user_delete = _status_user_delete; 00248 mod->free = _status_free; 00249 00250 return 0; 00251 }