# HG changeset patch # User Timo Sirainen # Date 1441659331 -10800 # Node ID fa979ccfa34c7e6b0b5b1a3707ca6b400546326b # Parent 73acc70751462083ec7d1a14104a77fb1c00512b Mailbox list notify API changed to return multiple events at once. This fixes some issues where a single event could actually trigger multiple different kinds of events. diff -r 73acc7075146 -r fa979ccfa34c src/imap/imap-notify.c --- a/src/imap/imap-notify.c Mon Sep 07 23:08:44 2015 +0300 +++ b/src/imap/imap-notify.c Mon Sep 07 23:55:31 2015 +0300 @@ -57,27 +57,17 @@ 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 @@ 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 @@ { 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; } - return TRUE; + if ((wanted_events & IMAP_NOTIFY_EVENT_MESSAGE_NEW) != 0) { + if ((rec->events & MAILBOX_LIST_NOTIFY_APPENDS) != 0) + 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, diff -r 73acc7075146 -r fa979ccfa34c src/lib-storage/list/mailbox-list-index-notify.c --- a/src/lib-storage/list/mailbox-list-index-notify.c Mon Sep 07 23:08:44 2015 +0300 +++ b/src/lib-storage/list/mailbox-list-index-notify.c Mon Sep 07 23:55:31 2015 +0300 @@ -591,7 +591,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 { diff -r 73acc7075146 -r fa979ccfa34c src/lib-storage/mailbox-list-notify.h --- a/src/lib-storage/mailbox-list-notify.h Mon Sep 07 23:08:44 2015 +0300 +++ b/src/lib-storage/mailbox-list-notify.h Mon Sep 07 23:55:31 2015 +0300 @@ -30,7 +30,8 @@ }; 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;