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