jabberd2  2.2.16
sm/mod_status.c
Go to the documentation of this file.
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 }