Common subdirectories: ../jabberd-2.0s6.orig/sm/.deps and sm/.deps Only in ../jabberd-2.0s6.orig/sm/: .libs diff -u ../jabberd-2.0s6.orig/sm/mod_offline.c sm/mod_offline.c --- ../jabberd-2.0s6.orig/sm/mod_offline.c Thu Dec 30 14:59:02 2004 +++ sm/mod_offline.c Thu Dec 30 16:39:50 2004 @@ -27,6 +27,12 @@ * $Revision: 1.20.2.2 $ */ +typedef struct _mod_offline_st { + int dropmessages; + int dropsubscriptions; + int userquota; +} *mod_offline_t; + static mod_ret_t _offline_in_sess(mod_instance_t mi, sess_t sess, pkt_t pkt) { st_ret_t ret; os_t os; @@ -95,10 +101,13 @@ } static mod_ret_t _offline_pkt_user(mod_instance_t mi, user_t user, pkt_t pkt) { + mod_offline_t offline = (mod_offline_t) mi->mod->private; int ns, elem, attr; os_t os; os_object_t o; pkt_t event; + st_ret_t ret; + int queuesize; /* send messages and s10ns to the top session */ if(user->top != NULL && (pkt->type & pkt_MESSAGE || pkt->type & pkt_S10N)) { @@ -106,8 +115,20 @@ return mod_HANDLED; } + /* if user quotas are enabled, count the number of offline messages this user has in the queue */ + if(offline->userquota > 0) { + ret = storage_count(user->sm->st, "queue", jid_user(user->jid), NULL, &queuesize); + + log_debug(ZONE, "storage_count ret is %i queue size is %i", ret, queuesize); + + /* if the user's quota is exceeded, return an error */ + if (ret == st_SUCCESS && (pkt->type & pkt_MESSAGE) && queuesize >= offline->userquota) + return -stanza_err_SERVICE_UNAVAILABLE; + } + /* save messages and s10ns for later */ - if(pkt->type & pkt_MESSAGE || pkt->type & pkt_S10N) { + if((pkt->type & pkt_MESSAGE && !offline->dropmessages) || + (pkt->type & pkt_S10N && !offline->dropsubscriptions)) { log_debug(ZONE, "saving message for later"); pkt_delay(pkt, time(NULL), user->sm->id); @@ -222,14 +243,38 @@ storage_delete(mi->sm->st, "queue", jid_user(jid), NULL); } +static void _offline_free(module_t mod) { + mod_offline_t offline = (mod_offline_t) mod->private; + + free(offline); +} + int offline_init(mod_instance_t mi, char *arg) { module_t mod = mi->mod; + char *configval; + mod_offline_t offline; if(mod->init) return 0; + offline = (mod_offline_t) malloc(sizeof(struct _mod_offline_st)); + memset(offline, 0, sizeof(struct _mod_offline_st)); + + configval = config_get_one(mod->mm->sm->config, "offline.dropmessages", 0); + if (configval != NULL) + offline->dropmessages = 1; + + configval = config_get_one(mod->mm->sm->config, "offline.dropsubscriptions", 0); + if (configval != NULL) + offline->dropsubscriptions = 1; + + offline->userquota = j_atoi(config_get_one(mod->mm->sm->config, "offline.userquota", 0), 0); + + mod->private = offline; + mod->in_sess = _offline_in_sess; mod->pkt_user = _offline_pkt_user; mod->user_delete = _offline_user_delete; + mod->free = _offline_free; return 0; } Only in ../jabberd-2.0s6.orig/sm/: sm diff -u ../jabberd-2.0s6.orig/sm/sm.h sm/sm.h --- ../jabberd-2.0s6.orig/sm/sm.h Thu Dec 30 14:59:02 2004 +++ sm/sm.h Thu Dec 30 15:06:59 2004 @@ -584,6 +584,8 @@ st_ret_t (*put)(st_driver_t drv, const char *type, const char *owner, os_t os); /** get handler */ st_ret_t (*get)(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os); + /** count handler */ + st_ret_t (*count)(st_driver_t drv, const char *type, const char *owner, const char *filter, int *count); /** delete handler */ st_ret_t (*delete)(st_driver_t drv, const char *type, const char *owner, const char *filter); /** replace handler */ @@ -605,6 +607,8 @@ st_ret_t storage_put(storage_t st, const char *type, const char *owner, os_t os); /** get objects matching this filter */ st_ret_t storage_get(storage_t st, const char *type, const char *owner, const char *filter, os_t *os); +/** count objects matching this filter */ +st_ret_t storage_count(storage_t st, const char *type, const char *owner, const char *filter, int *count); /** delete objects matching this filter */ st_ret_t storage_delete(storage_t st, const char *type, const char *owner, const char *filter); /** replace objects matching this filter with objects in this set (atomic delete + get) */ Only in sm: smlog diff -u ../jabberd-2.0s6.orig/sm/storage.c sm/storage.c --- ../jabberd-2.0s6.orig/sm/storage.c Thu Dec 30 14:59:02 2004 +++ sm/storage.c Thu Dec 30 16:42:34 2004 @@ -270,6 +270,32 @@ return (drv->get)(drv, type, owner, filter, os); } +st_ret_t storage_count(storage_t st, const char *type, const char *owner, const char *filter, int *count) { + st_driver_t drv; + st_ret_t ret; + + log_debug(ZONE, "storage_count: type=%s owner=%s filter=%s", type, owner, filter); + + /* find the handler for this type */ + drv = xhash_get(st->types, type); + if(drv == NULL) { + /* never seen it before, so it goes to the default driver */ + drv = st->default_drv; + if(drv == NULL) { + log_debug(ZONE, "no driver associated with type, and no default driver"); + return st_NOTIMPL; + } + + /* register the type */ + ret = storage_add_type(st, drv->name, type); + if(ret != st_SUCCESS) + return ret; + } + + return (drv->count != NULL) ? (drv->count)(drv, type, owner, filter, count) : st_NOTIMPL; +} + + st_ret_t storage_delete(storage_t st, const char *type, const char *owner, const char *filter) { st_driver_t drv; st_ret_t ret; diff -u ../jabberd-2.0s6.orig/sm/storage_mysql.c sm/storage_mysql.c --- ../jabberd-2.0s6.orig/sm/storage_mysql.c Thu Dec 30 14:59:02 2004 +++ sm/storage_mysql.c Thu Dec 30 16:44:37 2004 @@ -438,6 +438,74 @@ return st_SUCCESS; } +static st_ret_t _st_mysql_count(st_driver_t drv, const char *type, const char *owner, const char *filter, int *count) { + drvdata_t data = (drvdata_t) drv->private; + char *cond, *buf = NULL; + int buflen = 0; + MYSQL_RES *res; + int ntuples, nfields; + MYSQL_ROW tuple; + char tbuf[128]; + + if(mysql_ping(data->conn) != 0) { + log_write(drv->st->sm->log, LOG_ERR, "mysql: connection to database lost"); + return st_FAILED; + } + + if(data->prefix != NULL) { + snprintf(tbuf, sizeof(tbuf), "%s%s", data->prefix, type); + type = tbuf; + } + + cond = _st_mysql_convert_filter(drv, owner, filter); + log_debug(ZONE, "generated filter: %s", cond); + + MYSQL_SAFE(buf, strlen(type) + strlen(cond) + 31, buflen); + sprintf(buf, "SELECT COUNT(*) FROM `%s` WHERE %s", type, cond); + free(cond); + + log_debug(ZONE, "prepared sql: %s", buf); + + if(mysql_query(data->conn, buf) != 0) { + log_write(drv->st->sm->log, LOG_ERR, "mysql: sql select failed: %s", mysql_error(data->conn)); + free(buf); + return st_FAILED; + } + free(buf); + + res = mysql_store_result(data->conn); + if(res == NULL) { + log_write(drv->st->sm->log, LOG_ERR, "mysql: sql result retrieval failed: %s", mysql_error(data->conn)); + return st_FAILED; + } + + ntuples = mysql_num_rows(res); + if(ntuples == 0) { + mysql_free_result(res); + return st_NOTFOUND; + } + + log_debug(ZONE, "%d tuples returned", ntuples); + + nfields = mysql_num_fields(res); + + if(nfields == 0) { + log_debug(ZONE, "weird, tuples were returned but no fields *shrug*"); + mysql_free_result(res); + return st_NOTFOUND; + } + + if((tuple = mysql_fetch_row(res)) == NULL) + return st_NOTFOUND; + + if (count!=NULL) + *count = atoi(tuple[0]); + + mysql_free_result(res); + + return st_SUCCESS; +} + static st_ret_t _st_mysql_delete(st_driver_t drv, const char *type, const char *owner, const char *filter) { drvdata_t data = (drvdata_t) drv->private; char *cond, *buf = NULL; @@ -571,6 +639,7 @@ drv->add_type = _st_mysql_add_type; drv->put = _st_mysql_put; + drv->count = _st_mysql_count; drv->get = _st_mysql_get; drv->delete = _st_mysql_delete; drv->replace = _st_mysql_replace;