+++ /dev/null
-Index: sm/mod_roster.c
-===================================================================
---- sm/mod_roster.c (wersja 29)
-+++ sm/mod_roster.c (kopia robocza)
-@@ -199,9 +199,9 @@
- }
-
- /* a request */
-- if(pkt->type == pkt_S10N)
-+ if(pkt->type == pkt_S10N && ! item->to)
- item->ask = 1;
-- else if(pkt->type == pkt_S10N_UN)
-+ else if(pkt->type == pkt_S10N_UN && item->to)
- item->ask = 2;
-
- /* changing states */
-@@ -508,8 +508,8 @@
- /* get the roster item */
- item = (item_t) xhash_get(user->roster, jid_full(pkt->from));
- if(item == NULL) {
-- /* they're not on the roster, so subs / unsubs go direct */
-- if(pkt->type == pkt_S10N || pkt->type == pkt_S10N_UN)
-+ /* subs go direct */
-+ if(pkt->type == pkt_S10N)
- return mod_PASS;
-
- /* we didn't ask for this, so we don't care */
-@@ -517,6 +517,23 @@
- return mod_HANDLED;
- }
-
-+ /* ignore bogus answers */
-+ if( (pkt->type == pkt_S10N_ED && (item->ask != 1 || item->to) )
-+ || (pkt->type == pkt_S10N_UNED && ! item->to) )
-+ {
-+ /* remove pending ask */
-+ if( (pkt->type == pkt_S10N_ED && item->ask == 1)
-+ || (pkt->type == pkt_S10N_UNED && item->ask == 2) )
-+ {
-+ item->ask = 0;
-+ /* save changes */
-+ _roster_save_item(user, item);
-+ }
-+
-+ pkt_free(pkt);
-+ return mod_HANDLED;
-+ }
-+
- /* trying to subscribe */
- if(pkt->type == pkt_S10N)
- {
-@@ -536,7 +553,7 @@
- return mod_PASS;
- }
-
-- /* trying to unsubscribe */
-+ /* handle unsubscribe */
- if(pkt->type == pkt_S10N_UN)
- {
- if(!item->from)
-@@ -545,24 +562,34 @@
- nad_set_attr(pkt->nad, 1, -1, "type", "unsubscribed", 12);
- pkt_router(pkt_tofrom(pkt));
-
-- /* update their presence from the leading session */
-- if(user->top != NULL)
-- pres_roster(user->top, item);
--
- return mod_HANDLED;
- }
-
-- return mod_PASS;
-+ /* change state */
-+ item->from = 0;
-+
-+ /* confirm unsubscription */
-+ pkt_router(pkt_create(user->sm, "presence", "unsubscribed", jid_user(pkt->from), jid_user(user->jid)));
-+
-+ /* update their presence from the leading session */
-+ if(user->top != NULL)
-+ pres_roster(user->top, item);
- }
-
- /* update our s10n */
- if(pkt->type == pkt_S10N_ED)
-+ {
- item->to = 1;
-- else
-+ if(item->ask == 1)
-+ item->ask = 0;
-+ }
-+ if(pkt->type == pkt_S10N_UNED)
-+ {
- item->to = 0;
-+ if(item->ask == 2)
-+ item->ask = 0;
-+ }
-
-- item->ask = 0;
--
- /* save changes */
- _roster_save_item(user, item);
-
+++ /dev/null
-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$
- */
-
-+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;