dovecot-2.2: imap: Implemented NOTIFY extension.

dovecot at dovecot.org dovecot at dovecot.org
Mon Aug 13 15:23:46 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/f9d0ea98157f
changeset: 14899:f9d0ea98157f
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Aug 13 15:23:32 2012 +0300
description:
imap: Implemented NOTIFY extension.
Requires mailbox_list_index=yes to work (and to show up in capabilities).
SubscriptionChange event is still unimplemented.

diffstat:

 src/imap/Makefile.am        |    5 +
 src/imap/cmd-cancelupdate.c |    4 +-
 src/imap/cmd-fetch.c        |   23 +-
 src/imap/cmd-idle.c         |    2 +-
 src/imap/cmd-list.c         |   29 +-
 src/imap/cmd-notify.c       |  542 ++++++++++++++++++++++++++++++++++++++++++++
 src/imap/cmd-search.c       |    5 +-
 src/imap/cmd-select.c       |    9 +-
 src/imap/cmd-sort.c         |   10 +-
 src/imap/imap-client.c      |  105 +++++---
 src/imap/imap-client.h      |   13 +-
 src/imap/imap-commands.c    |    1 +
 src/imap/imap-commands.h    |    1 +
 src/imap/imap-fetch.c       |   97 +++++--
 src/imap/imap-fetch.h       |   12 +-
 src/imap/imap-list.c        |   35 ++
 src/imap/imap-list.h        |    7 +
 src/imap/imap-notify.c      |  518 ++++++++++++++++++++++++++++++++++++++++++
 src/imap/imap-notify.h      |   71 +++++
 src/imap/imap-search.c      |   70 +++++-
 src/imap/imap-search.h      |    5 +
 src/imap/imap-sync.c        |  298 +++++++++++++++++------
 src/imap/main.c             |    2 +-
 23 files changed, 1665 insertions(+), 199 deletions(-)

diffs (truncated from 2672 to 300 lines):

diff -r a16d77a075bb -r f9d0ea98157f src/imap/Makefile.am
--- a/src/imap/Makefile.am	Mon Aug 13 15:20:33 2012 +0300
+++ b/src/imap/Makefile.am	Mon Aug 13 15:23:32 2012 +0300
@@ -43,6 +43,7 @@
 	cmd-lsub.c \
 	cmd-namespace.c \
 	cmd-noop.c \
+	cmd-notify.c \
 	cmd-rename.c \
 	cmd-search.c \
 	cmd-select.c \
@@ -64,6 +65,8 @@
 	imap-expunge.c \
 	imap-fetch.c \
 	imap-fetch-body.c \
+	imap-list.c \
+	imap-notify.c \
 	imap-search.c \
 	imap-search-args.c \
 	imap-settings.c \
@@ -79,6 +82,8 @@
 	imap-common.h \
 	imap-expunge.h \
 	imap-fetch.h \
+	imap-list.h \
+	imap-notify.h \
 	imap-search.h \
 	imap-search-args.h \
 	imap-settings.h \
diff -r a16d77a075bb -r f9d0ea98157f src/imap/cmd-cancelupdate.c
--- a/src/imap/cmd-cancelupdate.c	Mon Aug 13 15:20:33 2012 +0300
+++ b/src/imap/cmd-cancelupdate.c	Mon Aug 13 15:23:32 2012 +0300
@@ -1,6 +1,7 @@
 /* Copyright (c) 2008-2012 Dovecot authors, see the included COPYING file */
 
 #include "imap-common.h"
+#include "imap-search.h"
 #include "imap-commands.h"
 
 static bool client_search_update_cancel(struct client *client, const char *tag)
@@ -12,8 +13,7 @@
 	if (update == NULL)
 		return FALSE;
 
-	i_free(update->tag);
-	mailbox_search_result_free(&update->result);
+	imap_search_update_free(update);
 	array_delete(&client->search_updates, idx, 1);
 	return TRUE;
 }
diff -r a16d77a075bb -r f9d0ea98157f src/imap/cmd-fetch.c
--- a/src/imap/cmd-fetch.c	Mon Aug 13 15:20:33 2012 +0300
+++ b/src/imap/cmd-fetch.c	Mon Aug 13 15:23:32 2012 +0300
@@ -103,6 +103,7 @@
 static bool
 fetch_parse_modifier(struct imap_fetch_context *ctx,
 		     struct client_command_context *cmd,
+		     struct mail_search_args *search_args,
 		     const char *name, const struct imap_arg **args,
 		     bool *send_vanished)
 {
@@ -117,7 +118,7 @@
 			return FALSE;
 		}
 		*args += 1;
-		imap_fetch_add_changed_since(ctx, modseq);
+		imap_fetch_add_changed_since(ctx, search_args, modseq);
 		return TRUE;
 	}
 	if (strcmp(name, "VANISHED") == 0 && cmd->uid) {
@@ -137,6 +138,7 @@
 static bool
 fetch_parse_modifiers(struct imap_fetch_context *ctx,
 		      struct client_command_context *cmd,
+		      struct mail_search_args *search_args,
 		      const struct imap_arg *args, bool *send_vanished_r)
 {
 	const char *name;
@@ -150,13 +152,14 @@
 			return FALSE;
 		}
 		args++;
-		if (!fetch_parse_modifier(ctx, cmd, t_str_ucase(name),
+		if (!fetch_parse_modifier(ctx, cmd, search_args,
+					  t_str_ucase(name),
 					  &args, send_vanished_r))
 			return FALSE;
 	}
 	if (*send_vanished_r &&
-	    (ctx->search_args->args->next == NULL ||
-	     ctx->search_args->args->next->type != SEARCH_MODSEQ)) {
+	    (search_args->args->next == NULL ||
+	     search_args->args->next->type != SEARCH_MODSEQ)) {
 		client_send_command_error(cmd,
 			"VANISHED used without CHANGEDSINCE");
 		return FALSE;
@@ -250,23 +253,27 @@
 		return ret < 0;
 
 	ctx = imap_fetch_alloc(client, cmd->pool);
-	ctx->search_args = search_args;
 
 	if (!fetch_parse_args(ctx, cmd, &args[1], &next_arg) ||
 	    (imap_arg_get_list(next_arg, &list_arg) &&
-	     !fetch_parse_modifiers(ctx, cmd, list_arg, &send_vanished))) {
+	     !fetch_parse_modifiers(ctx, cmd, search_args, list_arg,
+				    &send_vanished))) {
 		imap_fetch_free(&ctx);
+		mail_search_args_unref(&search_args);
 		return TRUE;
 	}
 
 	if (send_vanished) {
 		memset(&qresync_args, 0, sizeof(qresync_args));
 		if (imap_fetch_send_vanished(client, client->mailbox,
-					     search_args, &qresync_args) < 0)
+					     search_args, &qresync_args) < 0) {
+			mail_search_args_unref(&search_args);
 			return cmd_fetch_finish(ctx, cmd);
+		}
 	}
 
-	imap_fetch_begin_once(ctx, client->mailbox);
+	imap_fetch_begin(ctx, client->mailbox, search_args);
+	mail_search_args_unref(&search_args);
 
 	if (imap_fetch_more(ctx, cmd) == 0) {
 		/* unfinished */
diff -r a16d77a075bb -r f9d0ea98157f src/imap/cmd-idle.c
--- a/src/imap/cmd-idle.c	Mon Aug 13 15:20:33 2012 +0300
+++ b/src/imap/cmd-idle.c	Mon Aug 13 15:23:32 2012 +0300
@@ -115,7 +115,7 @@
 
 static void keepalive_timeout(struct cmd_idle_context *ctx)
 {
-	if (ctx->client->output_lock != NULL) {
+	if (ctx->client->output_locked) {
 		/* it's busy sending output */
 		return;
 	}
diff -r a16d77a075bb -r f9d0ea98157f src/imap/cmd-list.c
--- a/src/imap/cmd-list.c	Mon Aug 13 15:20:33 2012 +0300
+++ b/src/imap/cmd-list.c	Mon Aug 13 15:23:32 2012 +0300
@@ -9,6 +9,7 @@
 #include "imap-match.h"
 #include "imap-status.h"
 #include "imap-commands.h"
+#include "imap-list.h"
 #include "mail-namespace.h"
 
 struct cmd_list_context {
@@ -49,40 +50,22 @@
 	if ((ctx->list_flags & MAILBOX_LIST_ITER_RETURN_CHILDREN) == 0)
 		flags &= ~(MAILBOX_CHILDREN|MAILBOX_NOCHILDREN);
 
-	if ((flags & MAILBOX_SUBSCRIBED) != 0 &&
-	    (ctx->list_flags & MAILBOX_LIST_ITER_RETURN_SUBSCRIBED) != 0)
-		str_append(str, "\\Subscribed ");
+	if ((ctx->list_flags & MAILBOX_LIST_ITER_RETURN_SUBSCRIBED) == 0)
+		flags &= ~MAILBOX_SUBSCRIBED;
 
 	if ((flags & MAILBOX_CHILD_SUBSCRIBED) != 0 &&
 	    (flags & MAILBOX_SUBSCRIBED) == 0 && !ctx->used_listext) {
 		/* LSUB uses \Noselect for this */
 		flags |= MAILBOX_NOSELECT;
 	}
-
-	if ((flags & MAILBOX_NOSELECT) != 0)
-		str_append(str, "\\Noselect ");
-	if ((flags & MAILBOX_NONEXISTENT) != 0)
-		str_append(str, "\\NonExistent ");
-
-	if ((flags & MAILBOX_CHILDREN) != 0)
-		str_append(str, "\\HasChildren ");
-	else if ((flags & MAILBOX_NOINFERIORS) != 0)
-		str_append(str, "\\NoInferiors ");
-	else if ((flags & MAILBOX_NOCHILDREN) != 0)
-		str_append(str, "\\HasNoChildren ");
-
-	if ((flags & MAILBOX_MARKED) != 0)
-		str_append(str, "\\Marked ");
-	if ((flags & MAILBOX_UNMARKED) != 0)
-		str_append(str, "\\UnMarked ");
+	imap_mailbox_flags2str(str, flags);
 
 	if ((ctx->list_flags & MAILBOX_LIST_ITER_RETURN_SPECIALUSE) != 0 &&
 	    special_use != NULL) {
+		if (str_len(str) != orig_len)
+			str_append_c(str, ' ');
 		str_append(str, special_use);
-		str_append_c(str, ' ');
 	}
-	if (str_len(str) != orig_len)
-		str_truncate(str, str_len(str)-1);
 }
 
 static void
diff -r a16d77a075bb -r f9d0ea98157f src/imap/cmd-notify.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imap/cmd-notify.c	Mon Aug 13 15:23:32 2012 +0300
@@ -0,0 +1,542 @@
+/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
+#include "imap-common.h"
+#include "str.h"
+#include "imap-quote.h"
+#include "imap-commands.h"
+#include "imap-fetch.h"
+#include "imap-list.h"
+#include "imap-status.h"
+#include "imap-notify.h"
+
+#define IMAP_NOTIFY_MAX_NAMES_PER_NS 100
+
+static const char *imap_notify_event_names[] = {
+	"MessageNew", "MessageExpunge", "FlagChange", "AnnotationChange",
+	"MailboxName", "SubscriptionChange", "MailboxMetadataChange",
+	"ServerMetadataChange"
+};
+
+static int
+cmd_notify_parse_event(const struct imap_arg *arg,
+		       enum imap_notify_event *event_r)
+{
+	const char *str;
+	unsigned int i;
+
+	if (!imap_arg_get_atom(arg, &str))
+		return -1;
+
+	for (i = 0; i < N_ELEMENTS(imap_notify_event_names); i++) {
+		if (strcasecmp(str, imap_notify_event_names[i]) == 0) {
+			*event_r = (enum imap_notify_event)(1 << i);
+			return 0;
+		}
+	}
+	return -1;
+}
+
+static int
+cmd_notify_parse_fetch(struct imap_notify_context *ctx,
+		       const struct imap_arg *list)
+{
+	return imap_fetch_att_list_parse(ctx->client, ctx->pool, list,
+					 &ctx->fetch_ctx, &ctx->error);
+}
+
+static int
+cmd_notify_set_selected(struct imap_notify_context *ctx,
+			const struct imap_arg *events)
+{
+#define EV_NEW_OR_EXPUNGE \
+	(IMAP_NOTIFY_EVENT_MESSAGE_NEW | IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE)
+	const struct imap_arg *list, *fetch_att_list;
+	const char *str;
+	enum imap_notify_event event;
+
+	if (imap_arg_get_atom(events, &str) &&
+	    strcasecmp(str, "NONE") == 0) {
+		/* no events for selected mailbox. this is also the default
+		   when NOTIFY command doesn't specify it explicitly */
+		return 0;
+	}
+
+	if (!imap_arg_get_list(events, &list))
+		return -1;
+
+	for (; list->type != IMAP_ARG_EOL; list++) {
+		if (cmd_notify_parse_event(list, &event) < 0)
+			return -1;
+		ctx->selected_events |= event;
+		ctx->global_used_events |= event;
+
+		if (event == IMAP_NOTIFY_EVENT_MESSAGE_NEW &&
+		    imap_arg_get_list(&list[1], &fetch_att_list)) {
+			/* MessageNew: list of fetch-att */
+			if (cmd_notify_parse_fetch(ctx, fetch_att_list) < 0)
+				return -1;
+			list++;
+		}
+	}
+
+	/* if MessageNew or MessageExpunge is specified, both of them must */
+	if ((ctx->selected_events & EV_NEW_OR_EXPUNGE) != 0 &&
+	    (ctx->selected_events & EV_NEW_OR_EXPUNGE) != EV_NEW_OR_EXPUNGE) {
+		ctx->error = "MessageNew and MessageExpunge must be together";
+		return -1;
+	}
+
+	/* if FlagChange or AnnotationChange is specified,
+	   MessageNew and MessageExpunge must also be specified */
+	if ((ctx->selected_events &
+	     (IMAP_NOTIFY_EVENT_FLAG_CHANGE |
+	      IMAP_NOTIFY_EVENT_ANNOTATION_CHANGE)) != 0 &&
+	    (ctx->selected_events & IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE) == 0) {
+		ctx->error = "FlagChange requires MessageNew and MessageExpunge";
+		return -1;
+	}
+	return 0;
+}


More information about the dovecot-cvs mailing list