]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Mailbox list notify API changed to return multiple events at once.
authorTimo Sirainen <tss@iki.fi>
Mon, 7 Sep 2015 20:55:31 +0000 (23:55 +0300)
committerTimo Sirainen <tss@iki.fi>
Mon, 7 Sep 2015 20:55:31 +0000 (23:55 +0300)
This fixes some issues where a single event could actually trigger multiple
different kinds of events.

src/imap/imap-notify.c
src/lib-storage/list/mailbox-list-index-notify.c
src/lib-storage/mailbox-list-notify.h

index 34d8b0e610d0f92dd744aac4433e7a9df8fd0c9e..f5b001e45b7fdb7f89c7e4f3fef59d818ed73920 100644 (file)
@@ -57,27 +57,17 @@ static int imap_notify_status(struct imap_notify_namespace *notify_ns,
                items.status |= STATUS_HIGHESTMODSEQ;
 
        box = mailbox_alloc(notify_ns->ns->list, rec->vname, 0);
-       switch (rec->event) {
-       case MAILBOX_LIST_NOTIFY_UIDVALIDITY:
+       if ((rec->events & MAILBOX_LIST_NOTIFY_UIDVALIDITY) != 0) {
                items.status |= STATUS_UIDVALIDITY | STATUS_UIDNEXT |
                        STATUS_MESSAGES | STATUS_UNSEEN;
-               break;
-       case MAILBOX_LIST_NOTIFY_APPENDS:
-       case MAILBOX_LIST_NOTIFY_EXPUNGES:
+       }
+       if ((rec->events & (MAILBOX_LIST_NOTIFY_APPENDS |
+                           MAILBOX_LIST_NOTIFY_EXPUNGES)) != 0)
                items.status |= STATUS_UIDNEXT | STATUS_MESSAGES | STATUS_UNSEEN;
-               break;
-       case MAILBOX_LIST_NOTIFY_SEEN_CHANGES:
+       if ((rec->events & MAILBOX_LIST_NOTIFY_SEEN_CHANGES) != 0)
                items.status |= STATUS_UNSEEN;
-               break;
-       case MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES:
+       if ((rec->events & MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES) != 0) {
                /* if HIGHESTMODSEQ isn't being sent, don't send anything */
-               break;
-       case MAILBOX_LIST_NOTIFY_CREATE:
-       case MAILBOX_LIST_NOTIFY_DELETE:
-       case MAILBOX_LIST_NOTIFY_RENAME:
-       case MAILBOX_LIST_NOTIFY_SUBSCRIBE:
-       case MAILBOX_LIST_NOTIFY_UNSUBSCRIBE:
-               i_unreached();
        }
        if (items.status == 0) {
                /* don't send anything */
@@ -100,46 +90,50 @@ imap_notify_next(struct imap_notify_namespace *notify_ns,
                 const struct mailbox_list_notify_rec *rec)
 {
        enum mailbox_info_flags mailbox_flags;
-       int ret = 1;
+       int ret;
 
-       switch (rec->event) {
-       case MAILBOX_LIST_NOTIFY_CREATE:
+       if ((rec->events & MAILBOX_LIST_NOTIFY_CREATE) != 0) {
                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);
-               break;
-       case MAILBOX_LIST_NOTIFY_DELETE:
-               ret = imap_notify_list(notify_ns, rec, MAILBOX_NONEXISTENT);
-               break;
-       case MAILBOX_LIST_NOTIFY_RENAME:
+               if ((ret = imap_notify_list(notify_ns, rec, mailbox_flags)) <= 0)
+                       return ret;
+       }
+       if ((rec->events & MAILBOX_LIST_NOTIFY_DELETE) != 0) {
+               if ((ret = imap_notify_list(notify_ns, rec, MAILBOX_NONEXISTENT)) < 0)
+                       return ret;
+       }
+       if ((rec->events & MAILBOX_LIST_NOTIFY_RENAME) != 0) {
                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);
-               break;
-       case MAILBOX_LIST_NOTIFY_SUBSCRIBE:
+               if ((ret = imap_notify_list(notify_ns, rec, mailbox_flags)) < 0)
+                       return ret;
+       }
+       if ((rec->events & MAILBOX_LIST_NOTIFY_SUBSCRIBE) != 0) {
                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 ((ret = imap_notify_list(notify_ns, rec,
+                                    mailbox_flags | MAILBOX_SUBSCRIBED)) < 0)
+                       return ret;
+       }
+       if ((rec->events & MAILBOX_LIST_NOTIFY_UNSUBSCRIBE) != 0) {
                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);
-               break;
-       case MAILBOX_LIST_NOTIFY_UIDVALIDITY:
-       case MAILBOX_LIST_NOTIFY_APPENDS:
-       case MAILBOX_LIST_NOTIFY_EXPUNGES:
-       case MAILBOX_LIST_NOTIFY_SEEN_CHANGES:
-       case MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES:
-               ret = imap_notify_status(notify_ns, rec);
-               break;
+               if ((ret = imap_notify_list(notify_ns, rec, mailbox_flags)) < 0)
+                       return ret;
        }
-       return ret;
+       if ((rec->events & (MAILBOX_LIST_NOTIFY_UIDVALIDITY |
+                           MAILBOX_LIST_NOTIFY_APPENDS |
+                           MAILBOX_LIST_NOTIFY_EXPUNGES |
+                           MAILBOX_LIST_NOTIFY_SEEN_CHANGES |
+                           MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES)) != 0) {
+               if ((ret = imap_notify_status(notify_ns, rec)) < 0)
+                       return ret;
+       }
+       return 1;
 }
 
 static bool
@@ -149,53 +143,45 @@ imap_notify_match_event(struct imap_notify_namespace *notify_ns,
 {
        enum imap_notify_event wanted_events = notify_boxes->events;
        struct mailbox *box;
-       bool mailbox_event = FALSE;
-
-       switch (rec->event) {
-       case MAILBOX_LIST_NOTIFY_CREATE:
-       case MAILBOX_LIST_NOTIFY_DELETE:
-       case MAILBOX_LIST_NOTIFY_RENAME:
-               if ((wanted_events & IMAP_NOTIFY_EVENT_MAILBOX_NAME) == 0)
-                       return FALSE;
-               break;
-       case MAILBOX_LIST_NOTIFY_SUBSCRIBE:
-       case MAILBOX_LIST_NOTIFY_UNSUBSCRIBE:
-               if ((wanted_events & IMAP_NOTIFY_EVENT_SUBSCRIPTION_CHANGE) == 0)
-                       return FALSE;
-               break;
-       case MAILBOX_LIST_NOTIFY_UIDVALIDITY:
-               if ((wanted_events & (IMAP_NOTIFY_EVENT_MESSAGE_NEW |
-                                     IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE |
-                                     IMAP_NOTIFY_EVENT_FLAG_CHANGE)) == 0)
-                       return FALSE;
-               mailbox_event = TRUE;
-               break;
-       case MAILBOX_LIST_NOTIFY_APPENDS:
-               if ((wanted_events & IMAP_NOTIFY_EVENT_MESSAGE_NEW) == 0)
-                       return FALSE;
-               mailbox_event = TRUE;
-               break;
-       case MAILBOX_LIST_NOTIFY_EXPUNGES:
-               if ((wanted_events & IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE) == 0)
-                       return FALSE;
-               mailbox_event = TRUE;
-               break;
-       case MAILBOX_LIST_NOTIFY_SEEN_CHANGES:
-       case MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES:
-               if ((wanted_events & IMAP_NOTIFY_EVENT_FLAG_CHANGE) == 0)
-                       return FALSE;
-               mailbox_event = TRUE;
-               break;
+
+       /* check for mailbox list events first */
+       if ((wanted_events & IMAP_NOTIFY_EVENT_MAILBOX_NAME) != 0) {
+               if ((rec->events & (MAILBOX_LIST_NOTIFY_CREATE |
+                                   MAILBOX_LIST_NOTIFY_DELETE |
+                                   MAILBOX_LIST_NOTIFY_RENAME)) != 0)
+                       return TRUE;
+       }
+       if ((wanted_events & IMAP_NOTIFY_EVENT_SUBSCRIPTION_CHANGE) != 0) {
+               if ((rec->events & (MAILBOX_LIST_NOTIFY_SUBSCRIBE |
+                                   MAILBOX_LIST_NOTIFY_UNSUBSCRIBE)) != 0)
+                       return TRUE;
        }
 
-       if (mailbox_event) {
-               /* if this is an even for selected mailbox, ignore it */
-               box = notify_ns->ctx->client->mailbox;
-               if (box != NULL &&
-                   mailbox_equals(box, notify_ns->ns, rec->vname))
-                       return FALSE;
+       /* if this is an event for the selected mailbox, ignore it */
+       box = notify_ns->ctx->client->mailbox;
+       if (box != NULL && mailbox_equals(box, notify_ns->ns, rec->vname))
+               return FALSE;
+
+       if ((wanted_events & (IMAP_NOTIFY_EVENT_MESSAGE_NEW |
+                             IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE |
+                             IMAP_NOTIFY_EVENT_FLAG_CHANGE)) != 0) {
+               if ((rec->events & MAILBOX_LIST_NOTIFY_UIDVALIDITY) != 0)
+                       return TRUE;
+       }
+       if ((wanted_events & IMAP_NOTIFY_EVENT_MESSAGE_NEW) != 0) {
+               if ((rec->events & MAILBOX_LIST_NOTIFY_APPENDS) != 0)
+                       return TRUE;
        }
-       return TRUE;
+       if ((wanted_events & IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE) != 0) {
+               if ((rec->events & MAILBOX_LIST_NOTIFY_EXPUNGES) != 0)
+                       return TRUE;
+       }
+       if ((wanted_events & IMAP_NOTIFY_EVENT_FLAG_CHANGE) != 0) {
+               if ((rec->events & (MAILBOX_LIST_NOTIFY_SEEN_CHANGES |
+                                   MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES)) != 0)
+                       return TRUE;
+       }
+       return FALSE;
 }
 
 bool imap_notify_match_mailbox(struct imap_notify_namespace *notify_ns,
index 88c4ab6aa05fee43346e9f650c1574b0f75a4833..868253df8f2f65b1ed719b84ffde26fe31a38248 100644 (file)
@@ -591,7 +591,7 @@ mailbox_list_index_notify_rename(struct mailbox_list_notify_index *inotify,
                return FALSE;
 
        rec->old_vname = old_vname;
-       rec->event = MAILBOX_LIST_NOTIFY_RENAME;
+       rec->events = MAILBOX_LIST_NOTIFY_RENAME;
        return TRUE;
 }
 
@@ -607,7 +607,7 @@ mailbox_list_index_notify_subscribe(struct mailbox_list_notify_index *inotify,
        rec->vname = *vnamep;
        rec->storage_name = mailbox_list_get_storage_name(inotify->notify.list,
                                                          rec->vname);
-       rec->event = MAILBOX_LIST_NOTIFY_SUBSCRIBE;
+       rec->events = MAILBOX_LIST_NOTIFY_SUBSCRIBE;
        return TRUE;
 }
 
@@ -623,7 +623,7 @@ mailbox_list_index_notify_unsubscribe(struct mailbox_list_notify_index *inotify,
        rec->vname = *vnamep;
        rec->storage_name = mailbox_list_get_storage_name(inotify->notify.list,
                                                          rec->vname);
-       rec->event = MAILBOX_LIST_NOTIFY_UNSUBSCRIBE;
+       rec->events = MAILBOX_LIST_NOTIFY_UNSUBSCRIBE;
        return TRUE;
 }
 
@@ -637,7 +637,7 @@ mailbox_list_index_notify_expunge(struct mailbox_list_notify_index *inotify,
        if (!mailbox_list_index_notify_lookup(inotify, inotify->old_view,
                                              uid, 0, &status, &rec))
                return FALSE;
-       rec->event = MAILBOX_LIST_NOTIFY_DELETE;
+       rec->events = MAILBOX_LIST_NOTIFY_DELETE;
        return TRUE;
 }
 
@@ -651,7 +651,7 @@ mailbox_list_index_notify_new(struct mailbox_list_notify_index *inotify,
        if (!mailbox_list_index_notify_lookup(inotify, inotify->view,
                                              uid, 0, &status, &rec))
                i_unreached();
-       rec->event = MAILBOX_LIST_NOTIFY_CREATE;
+       rec->events = MAILBOX_LIST_NOTIFY_CREATE;
        return TRUE;
 }
 
@@ -674,15 +674,20 @@ mailbox_list_index_notify_change(struct mailbox_list_notify_index *inotify,
        nnode = mailbox_list_notify_tree_lookup(inotify->tree,
                                                rec->storage_name);
        if (nnode == NULL || nnode->uidvalidity != status.uidvalidity)
-               rec->event = MAILBOX_LIST_NOTIFY_UIDVALIDITY;
-       else if (nnode->uidnext != status.uidnext)
-               rec->event = MAILBOX_LIST_NOTIFY_APPENDS;
-       else if (nnode->messages > status.messages)
-               rec->event = MAILBOX_LIST_NOTIFY_EXPUNGES;
-       else if (nnode->unseen != status.unseen)
-               rec->event = MAILBOX_LIST_NOTIFY_SEEN_CHANGES;
-       else if (nnode->highest_modseq < status.highest_modseq)
-               rec->event = MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES;
+               rec->events |= MAILBOX_LIST_NOTIFY_UIDVALIDITY;
+       if (nnode->uidnext != status.uidnext)
+               rec->events |= MAILBOX_LIST_NOTIFY_APPENDS;
+       if (nnode->messages > status.messages) {
+               /* NOTE: not entirely reliable, since there could be both
+                  expunges and appends.. but it shouldn't make any difference
+                  in practise, since anybody interested in expunges is most
+                  likely also interested in appends. */
+               rec->events |= MAILBOX_LIST_NOTIFY_EXPUNGES;
+       }
+       if (nnode->unseen != status.unseen)
+               rec->events |= MAILBOX_LIST_NOTIFY_SEEN_CHANGES;
+       if (nnode->highest_modseq < status.highest_modseq)
+               rec->events |= MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES;
        else {
                /* nothing changed */
                return FALSE;
@@ -748,7 +753,7 @@ int mailbox_list_index_notify_next(struct mailbox_list_notify *notify,
        if (!inotify->initialized)
                mailbox_list_index_notify_read_init(inotify);
        while (mailbox_list_index_notify_try_next(inotify)) {
-               if ((inotify->notify_rec.event & inotify->notify.mask) != 0) {
+               if ((inotify->notify_rec.events & inotify->notify.mask) != 0) {
                        *rec_r = &inotify->notify_rec;
                        return 1;
                } else {
index 5f15b9461661aab4a0d9673de6fa0d85aa496ef3..7e63909e65b19fae71d2b2b0ff329e7c1cbdd9f7 100644 (file)
@@ -30,7 +30,8 @@ struct mailbox_list_notify {
 };
 
 struct mailbox_list_notify_rec {
-       enum mailbox_list_notify_event event;
+       /* Each record can contain multiple events */
+       enum mailbox_list_notify_event events;
 
        /* For all events: */
        const char *storage_name, *vname;