dovecot-2.2: NOTIFY: Implemented SubscriptionChange
dovecot at dovecot.org
dovecot at dovecot.org
Tue Sep 4 18:52:00 EEST 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/fcd480c4a0db
changeset: 15027:fcd480c4a0db
user: Timo Sirainen <tss at iki.fi>
date: Tue Sep 04 18:51:43 2012 +0300
description:
NOTIFY: Implemented SubscriptionChange
diffstat:
src/imap/imap-notify.c | 22 ++-
src/lib-storage/list/mailbox-list-index-notify.c | 124 ++++++++++++++++++++++-
src/lib-storage/list/mailbox-list-index.c | 40 +++++++
src/lib-storage/list/mailbox-list-index.h | 2 +-
src/lib-storage/list/mailbox-list-iter.c | 2 +-
src/lib-storage/mailbox-list-notify.h | 13 +-
src/lib-storage/mailbox-list-private.h | 1 +
src/lib-storage/mailbox-tree.c | 87 +++++++++++++++-
src/lib-storage/mailbox-tree.h | 5 +
9 files changed, 280 insertions(+), 16 deletions(-)
diffs (truncated from 527 to 300 lines):
diff -r e2c85551268d -r fcd480c4a0db src/imap/imap-notify.c
--- a/src/imap/imap-notify.c Tue Sep 04 17:26:37 2012 +0300
+++ b/src/imap/imap-notify.c Tue Sep 04 18:51:43 2012 +0300
@@ -74,7 +74,8 @@
case MAILBOX_LIST_NOTIFY_CREATE:
case MAILBOX_LIST_NOTIFY_DELETE:
case MAILBOX_LIST_NOTIFY_RENAME:
- case MAILBOX_LIST_NOTIFY_SUBSCRIPTION_CHANGE:
+ case MAILBOX_LIST_NOTIFY_SUBSCRIBE:
+ case MAILBOX_LIST_NOTIFY_UNSUBSCRIBE:
i_unreached();
}
if (items.status == 0) {
@@ -116,8 +117,14 @@
mailbox_flags = 0;
ret = imap_notify_list(notify_ns, rec, mailbox_flags);
break;
- case MAILBOX_LIST_NOTIFY_SUBSCRIPTION_CHANGE:
- /* FIXME: set \subscribed when needed */
+ case MAILBOX_LIST_NOTIFY_SUBSCRIBE:
+ if (mailbox_list_mailbox(notify_ns->ns->list, rec->storage_name,
+ &mailbox_flags) < 0)
+ mailbox_flags = 0;
+ ret = imap_notify_list(notify_ns, rec,
+ mailbox_flags | MAILBOX_SUBSCRIBED);
+ break;
+ case MAILBOX_LIST_NOTIFY_UNSUBSCRIBE:
if (mailbox_list_mailbox(notify_ns->ns->list, rec->storage_name,
&mailbox_flags) < 0)
mailbox_flags = 0;
@@ -150,7 +157,8 @@
if ((wanted_events & IMAP_NOTIFY_EVENT_MAILBOX_NAME) == 0)
return FALSE;
break;
- case MAILBOX_LIST_NOTIFY_SUBSCRIPTION_CHANGE:
+ case MAILBOX_LIST_NOTIFY_SUBSCRIBE:
+ case MAILBOX_LIST_NOTIFY_UNSUBSCRIBE:
if ((wanted_events & IMAP_NOTIFY_EVENT_SUBSCRIPTION_CHANGE) == 0)
return FALSE;
break;
@@ -378,8 +386,10 @@
MAILBOX_LIST_NOTIFY_DELETE |
MAILBOX_LIST_NOTIFY_RENAME;
}
- if ((events & IMAP_NOTIFY_EVENT_SUBSCRIPTION_CHANGE) != 0)
- ret |= MAILBOX_LIST_NOTIFY_SUBSCRIPTION_CHANGE;
+ if ((events & IMAP_NOTIFY_EVENT_SUBSCRIPTION_CHANGE) != 0) {
+ ret |= MAILBOX_LIST_NOTIFY_SUBSCRIBE |
+ MAILBOX_LIST_NOTIFY_UNSUBSCRIBE;
+ }
return ret;
}
diff -r e2c85551268d -r fcd480c4a0db src/lib-storage/list/mailbox-list-index-notify.c
--- a/src/lib-storage/list/mailbox-list-index-notify.c Tue Sep 04 17:26:37 2012 +0300
+++ b/src/lib-storage/list/mailbox-list-index-notify.c Tue Sep 04 18:51:43 2012 +0300
@@ -35,6 +35,7 @@
struct mailbox_list_notify_index {
struct mailbox_list_notify notify;
+ struct mailbox_tree_context *subscriptions;
struct mailbox_list_notify_tree *tree;
struct mail_index_view *view, *old_view;
struct mail_index_view_sync_ctx *sync_ctx;
@@ -47,11 +48,12 @@
struct timeout *to_wait, *to_notify;
ARRAY_TYPE(seq_range) new_uids, expunged_uids, changed_uids;
+ ARRAY_TYPE(const_string) new_subscriptions, new_unsubscriptions;
ARRAY(struct mailbox_list_notify_rename) renames;
struct seq_range_iter new_uids_iter, expunged_uids_iter;
struct seq_range_iter changed_uids_iter;
unsigned int new_uids_n, expunged_uids_n, changed_uids_n;
- unsigned int rename_idx;
+ unsigned int rename_idx, subscription_idx, unsubscription_idx;
struct mailbox_list_notify_rec notify_rec;
string_t *rec_name;
@@ -86,7 +88,15 @@
i_array_init(&inotify->expunged_uids, 8);
i_array_init(&inotify->changed_uids, 16);
i_array_init(&inotify->renames, 16);
+ i_array_init(&inotify->new_subscriptions, 16);
+ i_array_init(&inotify->new_unsubscriptions, 16);
inotify->rec_name = str_new(default_pool, 64);
+ if ((mask & (MAILBOX_LIST_NOTIFY_SUBSCRIBE |
+ MAILBOX_LIST_NOTIFY_UNSUBSCRIBE)) != 0) {
+ (void)mailbox_list_iter_subscriptions_refresh(list);
+ mailbox_tree_sort(list->subscriptions);
+ inotify->subscriptions = mailbox_tree_dup(list->subscriptions);
+ }
*notify_r = &inotify->notify;
return 1;
@@ -98,6 +108,8 @@
(struct mailbox_list_notify_index *)notify;
bool b;
+ if (inotify->subscriptions != NULL)
+ mailbox_tree_deinit(&inotify->subscriptions);
if (inotify->io_wait != NULL)
io_remove(&inotify->io_wait);
if (inotify->to_wait != NULL)
@@ -109,6 +121,8 @@
mail_index_view_close(&inotify->view);
mail_index_view_close(&inotify->old_view);
mailbox_list_notify_tree_deinit(&inotify->tree);
+ array_free(&inotify->new_subscriptions);
+ array_free(&inotify->new_unsubscriptions);
array_free(&inotify->new_uids);
array_free(&inotify->expunged_uids);
array_free(&inotify->changed_uids);
@@ -400,6 +414,66 @@
}
static void
+mailbox_list_index_notify_find_subscribes(struct mailbox_list_notify_index *inotify)
+{
+ struct mailbox_tree_iterate_context *old_iter, *new_iter;
+ struct mailbox_tree_context *old_tree, *new_tree;
+ const char *old_path = NULL, *new_path = NULL;
+ pool_t pool;
+ int ret;
+
+ if (mailbox_list_iter_subscriptions_refresh(inotify->notify.list) < 0)
+ return;
+ mailbox_tree_sort(inotify->notify.list->subscriptions);
+
+ old_tree = inotify->subscriptions;
+ new_tree = mailbox_tree_dup(inotify->notify.list->subscriptions);
+
+ old_iter = mailbox_tree_iterate_init(old_tree, NULL, MAILBOX_SUBSCRIBED);
+ new_iter = mailbox_tree_iterate_init(new_tree, NULL, MAILBOX_SUBSCRIBED);
+
+ pool = mailbox_tree_get_pool(new_tree);
+ for (;;) {
+ if (old_path == NULL) {
+ if (mailbox_tree_iterate_next(old_iter, &old_path) == NULL)
+ old_path = NULL;
+ }
+ if (new_path == NULL) {
+ if (mailbox_tree_iterate_next(new_iter, &new_path) == NULL)
+ new_path = NULL;
+ }
+
+ if (old_path == NULL) {
+ if (new_path == NULL)
+ break;
+ ret = 1;
+ } else if (new_path == NULL)
+ ret = -1;
+ else {
+ ret = strcmp(old_path, new_path);
+ }
+
+ if (ret == 0) {
+ old_path = NULL;
+ new_path = NULL;
+ } else if (ret > 0) {
+ new_path = p_strdup(pool, new_path);
+ array_append(&inotify->new_subscriptions, &new_path, 1);
+ new_path = NULL;
+ } else {
+ old_path = p_strdup(pool, old_path);
+ array_append(&inotify->new_unsubscriptions, &old_path, 1);
+ old_path = NULL;
+ }
+ }
+ mailbox_tree_iterate_deinit(&old_iter);
+ mailbox_tree_iterate_deinit(&new_iter);
+
+ mailbox_tree_deinit(&inotify->subscriptions);
+ inotify->subscriptions = new_tree;
+}
+
+static void
mailbox_list_index_notify_reset_iters(struct mailbox_list_notify_index *inotify)
{
seq_range_array_iter_init(&inotify->new_uids_iter,
@@ -412,6 +486,8 @@
inotify->new_uids_n = 0;
inotify->expunged_uids_n = 0;
inotify->rename_idx = 0;
+ inotify->subscription_idx = 0;
+ inotify->unsubscription_idx = 0;
}
static void
@@ -439,6 +515,8 @@
mailbox_list_index_notify_find_renames(inotify);
mailbox_list_index_notify_reset_iters(inotify);
}
+ if (inotify->subscriptions != NULL)
+ mailbox_list_index_notify_find_subscribes(inotify);
inotify->initialized = TRUE;
}
@@ -450,6 +528,8 @@
mail_index_view_close(&inotify->old_view);
inotify->old_view = mail_index_view_dup_private(inotify->view);
+ array_clear(&inotify->new_subscriptions);
+ array_clear(&inotify->new_unsubscriptions);
array_clear(&inotify->new_uids);
array_clear(&inotify->expunged_uids);
array_clear(&inotify->changed_uids);
@@ -516,6 +596,38 @@
}
static bool
+mailbox_list_index_notify_subscribe(struct mailbox_list_notify_index *inotify,
+ unsigned int idx)
+{
+ struct mailbox_list_notify_rec *rec = &inotify->notify_rec;
+ const char *const *vnamep;
+
+ memset(rec, 0, sizeof(*rec));
+ vnamep = array_idx(&inotify->new_subscriptions, idx);
+ rec->vname = *vnamep;
+ rec->storage_name = mailbox_list_get_storage_name(inotify->notify.list,
+ rec->vname);
+ rec->event = MAILBOX_LIST_NOTIFY_SUBSCRIBE;
+ return TRUE;
+}
+
+static bool
+mailbox_list_index_notify_unsubscribe(struct mailbox_list_notify_index *inotify,
+ unsigned int idx)
+{
+ struct mailbox_list_notify_rec *rec = &inotify->notify_rec;
+ const char *const *vnamep;
+
+ memset(rec, 0, sizeof(*rec));
+ vnamep = array_idx(&inotify->new_unsubscriptions, idx);
+ rec->vname = *vnamep;
+ rec->storage_name = mailbox_list_get_storage_name(inotify->notify.list,
+ rec->vname);
+ rec->event = MAILBOX_LIST_NOTIFY_UNSUBSCRIBE;
+ return TRUE;
+}
+
+static bool
mailbox_list_index_notify_expunge(struct mailbox_list_notify_index *inotify,
uint32_t uid)
{
@@ -608,6 +720,16 @@
inotify->new_uids_n++, &uid))
return mailbox_list_index_notify_new(inotify, uid);
+ /* subscribes */
+ if (inotify->subscription_idx < array_count(&inotify->new_subscriptions)) {
+ return mailbox_list_index_notify_subscribe(inotify,
+ inotify->subscription_idx++);
+ }
+ if (inotify->unsubscription_idx < array_count(&inotify->new_unsubscriptions)) {
+ return mailbox_list_index_notify_unsubscribe(inotify,
+ inotify->unsubscription_idx++);
+ }
+
/* STATUS updates */
while (seq_range_array_iter_nth(&inotify->changed_uids_iter,
inotify->changed_uids_n++, &uid)) {
diff -r e2c85551268d -r fcd480c4a0db src/lib-storage/list/mailbox-list-index.c
--- a/src/lib-storage/list/mailbox-list-index.c Tue Sep 04 17:26:37 2012 +0300
+++ b/src/lib-storage/list/mailbox-list-index.c Tue Sep 04 18:51:43 2012 +0300
@@ -386,6 +386,42 @@
newlist, newname, rename_children);
}
+static int
+mailbox_list_index_set_subscribed(struct mailbox_list *_list,
+ const char *name, bool set)
+{
+ struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(_list);
+ struct mail_index_view *view;
+ struct mail_index_transaction *trans;
+ const void *data;
+ size_t size;
+ uint32_t counter;
+
+ if (ilist->module_ctx.super.set_subscribed(_list, name, set) < 0)
+ return -1;
+
+ /* update the "subscriptions changed" counter/timestamp. its purpose
+ is to trigger NOTIFY watcher to handle SubscriptionChange events */
+ mailbox_list_index_index_open(_list);
+ view = mail_index_view_open(ilist->index);
+ mail_index_get_header_ext(view, ilist->subs_hdr_ext_id, &data, &size);
+ if (size != sizeof(counter))
+ counter = ioloop_time;
+ else {
+ memcpy(&counter, data, size);
+ if (++counter < ioloop_time)
+ counter = ioloop_time;
+ }
+
+ trans = mail_index_transaction_begin(view,
+ MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
+ mail_index_update_header_ext(trans, ilist->subs_hdr_ext_id,
+ 0, &counter, sizeof(counter));
More information about the dovecot-cvs
mailing list