imap-notify.c revision 906a651134bead2be605f2be6c47bd91a4cb94be
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-common.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "str.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ostream.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-quote.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mailbox-list-iter.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mailbox-list-notify.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-search.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-search-build.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-commands.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-fetch.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-list.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "imap-status.h"
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen#include "imap-notify.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define IMAP_NOTIFY_WATCH_ADD_DELAY_MSECS 1000
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int imap_notify_list(struct imap_notify_namespace *notify_ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mailbox_list_notify_rec *rec,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen enum mailbox_info_flags flags)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen string_t *str = t_str_new(128);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen char ns_sep = mail_namespace_get_sep(notify_ns->ns);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "* LIST (");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_mailbox_flags2str(str, flags);
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen str_append(str, ") \"");
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen if (ns_sep == '\\')
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append_c(str, '\\');
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append_c(str, ns_sep);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "\" ");
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_append_astring(str, rec->vname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (rec->old_vname != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, " (\"OLDNAME\" (");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_append_astring(str, rec->old_vname);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen str_append(str, "))");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return client_send_line_next(notify_ns->ctx->client, str_c(str));
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int imap_notify_status(struct imap_notify_namespace *notify_ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mailbox_list_notify_rec *rec)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct client *client = notify_ns->ctx->client;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox *box;
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainen struct imap_status_items items;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct imap_status_result result;
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen enum mail_error error;
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen int ret = 1;
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_zero(&items);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_CONDSTORE) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen items.status |= STATUS_HIGHESTMODSEQ;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen box = mailbox_alloc(notify_ns->ns->list, rec->vname, 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_set_reason(box, "NOTIFY STATUS");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_UIDVALIDITY) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen items.status |= STATUS_UIDVALIDITY | STATUS_UIDNEXT |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen STATUS_MESSAGES | STATUS_UNSEEN;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & (MAILBOX_LIST_NOTIFY_APPENDS |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_EXPUNGES)) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen items.status |= STATUS_UIDNEXT | STATUS_MESSAGES | STATUS_UNSEEN;
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_SEEN_CHANGES) != 0)
e2eac5bb5637c2d4aaf453389750740931822b92Timo Sirainen items.status |= STATUS_UNSEEN;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES) != 0) {
2f5954db411ea9d63e831a01dd57211e55448463Timo Sirainen /* if HIGHESTMODSEQ isn't being sent, don't send anything */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (items.status == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* don't send anything */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (mailbox_get_status(box, items.status, &result.status) < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* hide permission errors from client. we don't want to leak
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen information about existence of mailboxes where user doesn't
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen have access to */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)mailbox_get_last_error(box, &error);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (error != MAIL_ERROR_PERM)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = imap_status_send(client, rec->vname, &items, &result);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen mailbox_free(&box);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen return ret;
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen}
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainenstatic int
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainenimap_notify_next(struct imap_notify_namespace *notify_ns,
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainen const struct mailbox_list_notify_rec *rec)
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen{
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen enum mailbox_info_flags mailbox_flags;
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen int ret;
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_CREATE) != 0) {
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen if (mailbox_list_mailbox(notify_ns->ns->list, rec->storage_name,
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen &mailbox_flags) < 0)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen mailbox_flags = 0;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if ((ret = imap_notify_list(notify_ns, rec, mailbox_flags)) <= 0)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_DELETE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ret = imap_notify_list(notify_ns, rec, MAILBOX_NONEXISTENT)) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_RENAME) != 0) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (mailbox_list_mailbox(notify_ns->ns->list, rec->storage_name,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &mailbox_flags) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_flags = 0;
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if ((ret = imap_notify_list(notify_ns, rec, mailbox_flags)) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_SUBSCRIBE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mailbox_list_mailbox(notify_ns->ns->list, rec->storage_name,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &mailbox_flags) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_flags = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ret = imap_notify_list(notify_ns, rec,
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen mailbox_flags | MAILBOX_SUBSCRIBED)) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_UNSUBSCRIBE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mailbox_list_mailbox(notify_ns->ns->list, rec->storage_name,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &mailbox_flags) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_flags = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((ret = imap_notify_list(notify_ns, rec, mailbox_flags)) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((rec->events & (MAILBOX_LIST_NOTIFY_UIDVALIDITY |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen MAILBOX_LIST_NOTIFY_APPENDS |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen MAILBOX_LIST_NOTIFY_EXPUNGES |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_SEEN_CHANGES |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES)) != 0) {
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen if ((ret = imap_notify_status(notify_ns, rec)) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenimap_notify_match_event(struct imap_notify_namespace *notify_ns,
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen const struct imap_notify_mailboxes *notify_boxes,
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen const struct mailbox_list_notify_rec *rec)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen enum imap_notify_event wanted_events = notify_boxes->events;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox *box;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* check for mailbox list events first */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((wanted_events & IMAP_NOTIFY_EVENT_MAILBOX_NAME) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & (MAILBOX_LIST_NOTIFY_CREATE |
cc0a651962a3e54d5a62231ac5847ae7f9f7de7fTimo Sirainen MAILBOX_LIST_NOTIFY_DELETE |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen MAILBOX_LIST_NOTIFY_RENAME)) != 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((wanted_events & IMAP_NOTIFY_EVENT_SUBSCRIPTION_CHANGE) != 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((rec->events & (MAILBOX_LIST_NOTIFY_SUBSCRIBE |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen MAILBOX_LIST_NOTIFY_UNSUBSCRIBE)) != 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* if this is an event for the selected mailbox, ignore it */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen box = notify_ns->ctx->client->mailbox;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (box != NULL && mailbox_equals(box, notify_ns->ns, rec->vname))
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((wanted_events & (IMAP_NOTIFY_EVENT_MESSAGE_NEW |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen IMAP_NOTIFY_EVENT_FLAG_CHANGE)) != 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_UIDVALIDITY) != 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return TRUE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((wanted_events & IMAP_NOTIFY_EVENT_MESSAGE_NEW) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_APPENDS) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((wanted_events & IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_EXPUNGES) != 0)
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((wanted_events & IMAP_NOTIFY_EVENT_FLAG_CHANGE) != 0) {
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if ((rec->events & (MAILBOX_LIST_NOTIFY_SEEN_CHANGES |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES)) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen }
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen return FALSE;
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen}
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainenbool imap_notify_match_mailbox(struct imap_notify_namespace *notify_ns,
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen const struct imap_notify_mailboxes *notify_boxes,
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen const char *vname)
c3d9da3955043aef88c17b71f2081e894186aa6bTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox *box;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *const *namep;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen size_t name_len;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen char ns_sep;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen bool ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen switch (notify_boxes->type) {
9047d770bfbb93ab6af5363dedb2d01363877243Timo Sirainen case IMAP_NOTIFY_TYPE_SUBSCRIBED:
f776b9a125c59a96de6807e9558942cf7b7ab079Timo Sirainen box = mailbox_alloc(notify_ns->ns->list, vname, 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_set_reason(box, "NOTIFY is subscribed");
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen ret = mailbox_is_subscribed(box);
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen mailbox_free(&box);
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen return ret;
9047d770bfbb93ab6af5363dedb2d01363877243Timo Sirainen case IMAP_NOTIFY_TYPE_SUBTREE:
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen ns_sep = mail_namespace_get_sep(notify_ns->ns);
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen array_foreach(&notify_boxes->names, namep) {
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen name_len = strlen(*namep);
9a790c932a9e5d52939c5d9e56e8b0ef02166d43Timo Sirainen if (name_len == 0) {
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen /* everything under root. NOTIFY spec itself
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen doesn't define this, but we use it for
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen implementing "personal" */
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strncmp(*namep, vname, name_len) == 0 &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (vname[name_len] == '\0' ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen vname[name_len] == ns_sep))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen case IMAP_NOTIFY_TYPE_MAILBOX:
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_foreach(&notify_boxes->names, namep) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (strcmp(*namep, vname) == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
804fa3f03bd9170272168a5ad214053bbe3160c7Josef 'Jeff' Sipek}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic bool
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenimap_notify_match(struct imap_notify_namespace *notify_ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mailbox_list_notify_rec *rec)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct imap_notify_mailboxes *notify_boxes;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_foreach(&notify_ns->mailboxes, notify_boxes) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (imap_notify_match_event(notify_ns, notify_boxes, rec) &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_notify_match_mailbox(notify_ns, notify_boxes, rec->vname))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int imap_client_notify_ns(struct imap_notify_namespace *notify_ns)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct mailbox_list_notify_rec *rec;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int ret, ret2 = 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (notify_ns->notify == NULL)
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainen return 0; /* notifications not supported in this namespace */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen while ((ret = mailbox_list_notify_next(notify_ns->notify, &rec)) > 0) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (imap_notify_match(notify_ns, rec)) T_BEGIN {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen ret2 = imap_notify_next(notify_ns, rec);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen } T_END;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret2 <= 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* failed to get some notifications */
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return -1;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen }
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return ret2;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen}
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainenstatic int
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainenimap_client_notify_selected(struct client *client)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen{
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen struct imap_fetch_context *fetch_ctx = client->notify_ctx->fetch_ctx;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen int ret;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if (!fetch_ctx->state.fetching)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return 1;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainen if ((ret = imap_fetch_more_no_lock_update(fetch_ctx)) <= 0)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return ret;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen /* finished the FETCH */
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if (imap_fetch_end(fetch_ctx) < 0)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return -1;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return 1;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int imap_client_notify_more(struct client *client)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct imap_notify_namespace *notify_ns;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen int ret = 1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* send notifications for selected mailbox first. note that it may
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen leave the client's output stream in the middle of a FETCH reply. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (client->notify_ctx->fetch_ctx != NULL) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((ret = imap_client_notify_selected(client)) < 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen client->notify_ctx->fetch_ctx->state.failed = FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* send notifications for non-selected mailboxes */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_foreach_modifiable(&client->notify_ctx->namespaces, notify_ns) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret == 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (imap_client_notify_ns(notify_ns) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = -1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret < 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen client_send_line(notify_ns->ctx->client,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "* NO NOTIFY error, some events may have got lost");
c7a50b2c29780eaa3668bbac738e3fa3e4e171e8Timo Sirainen }
c7a50b2c29780eaa3668bbac738e3fa3e4e171e8Timo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
c7a50b2c29780eaa3668bbac738e3fa3e4e171e8Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint imap_client_notify_newmails(struct client *client)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct imap_fetch_context *fetch_ctx = client->notify_ctx->fetch_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mailbox_status status;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_search_args *search_args;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_search_arg *arg;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen i_assert(client->mailbox != NULL);
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen if (fetch_ctx == NULL) {
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen /* FETCH notifications not enabled in this session */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return 1;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen }
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen if (client->notify_ctx->notifying)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen return imap_client_notify_more(client);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen client->notify_ctx->notifying = TRUE;
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen i_assert(!fetch_ctx->state.fetching);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen mailbox_get_open_status(client->mailbox, STATUS_UIDNEXT, &status);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen search_args = mail_search_build_init();
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen arg = mail_search_build_add(search_args, SEARCH_UIDSET);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen p_array_init(&arg->value.seqset, search_args->pool, 1);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen seq_range_array_add_range(&arg->value.seqset,
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen client->notify_uidnext, status.uidnext-1);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen client->notify_uidnext = status.uidnext;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_fetch_begin(fetch_ctx, client->mailbox, search_args);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mail_search_args_unref(&search_args);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return imap_client_notify_more(client);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenvoid imap_client_notify_finished(struct client *client)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (client->notify_ctx != NULL)
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen client->notify_ctx->notifying = FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void notify_callback(void *context)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct imap_notify_namespace *notify_ns = context;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen o_stream_cork(notify_ns->ctx->client->output);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_client_notify_ns(notify_ns);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen o_stream_uncork(notify_ns->ctx->client->output);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen}
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic enum mailbox_list_notify_event
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenimap_events_to_notify(enum imap_notify_event events)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen enum mailbox_list_notify_event ret = 0;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if ((events & IMAP_NOTIFY_EVENT_MESSAGE_NEW) != 0) {
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen ret |= MAILBOX_LIST_NOTIFY_APPENDS |
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen MAILBOX_LIST_NOTIFY_UIDVALIDITY;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((events & IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret |= MAILBOX_LIST_NOTIFY_EXPUNGES |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_UIDVALIDITY;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((events & IMAP_NOTIFY_EVENT_FLAG_CHANGE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret |= MAILBOX_LIST_NOTIFY_SEEN_CHANGES |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_UIDVALIDITY;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((events & IMAP_NOTIFY_EVENT_MAILBOX_NAME) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret |= MAILBOX_LIST_NOTIFY_CREATE |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_DELETE |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_RENAME;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((events & IMAP_NOTIFY_EVENT_SUBSCRIPTION_CHANGE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret |= MAILBOX_LIST_NOTIFY_SUBSCRIBE |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen MAILBOX_LIST_NOTIFY_UNSUBSCRIBE;
}
return ret;
}
static void imap_notify_callback(struct mailbox *box, struct client *client)
{
struct client_command_context *cmd;
enum mailbox_sync_flags sync_flags = 0;
i_assert(client->command_queue_size == 0);
i_assert(box == client->mailbox);
/* create a fake command to handle this */
cmd = client_command_alloc(client);
cmd->tag = "*";
cmd->name = "NOTIFY-CALLBACK";
if (!client->notify_ctx->selected_immediate_expunges)
sync_flags |= MAILBOX_SYNC_FLAG_NO_EXPUNGES;
if (cmd_sync(cmd, sync_flags, 0, NULL))
i_unreached();
(void)cmd_sync_delayed(client);
}
static void imap_notify_watch_selected_mailbox(struct client *client)
{
i_assert(client->command_queue_size == 0);
if (client->mailbox == NULL) {
/* mailbox not selected */
return;
}
if (client->notify_ctx == NULL || !client->notify_ctx->selected_set) {
/* client doesn't want selected mailbox notifications */
return;
}
mailbox_notify_changes(client->mailbox, imap_notify_callback, client);
client->notify_ctx->watching_mailbox = TRUE;
}
static void imap_notify_watch_timeout(struct client *client)
{
timeout_remove(&client->notify_ctx->to_watch);
imap_notify_watch_selected_mailbox(client);
}
void imap_client_notify_command_freed(struct client *client)
{
struct imap_notify_context *ctx = client->notify_ctx;
if (ctx == NULL)
return;
if (client->command_queue_size > 0) {
/* don't add it until all commands are finished */
i_assert(ctx->to_watch == NULL);
return;
}
/* add mailbox watch back after a small delay. if another command
is started this timeout is aborted. */
ctx->to_watch = timeout_add(IMAP_NOTIFY_WATCH_ADD_DELAY_MSECS,
imap_notify_watch_timeout, client);
}
void imap_client_notify_command_allocated(struct client *client)
{
struct imap_notify_context *ctx = client->notify_ctx;
if (ctx == NULL)
return;
/* remove mailbox watcher before starting any commands */
if (ctx->watching_mailbox) {
mailbox_notify_changes_stop(client->mailbox);
ctx->watching_mailbox = FALSE;
}
if (ctx->to_watch != NULL)
timeout_remove(&ctx->to_watch);
}
int imap_notify_begin(struct imap_notify_context *ctx)
{
struct imap_notify_namespace *notify_ns;
const struct imap_notify_mailboxes *notify_boxes;
enum mailbox_list_notify_event notify_events;
int ret = -1;
array_foreach_modifiable(&ctx->namespaces, notify_ns) {
notify_events = 0;
array_foreach(&notify_ns->mailboxes, notify_boxes) {
notify_events |=
imap_events_to_notify(notify_boxes->events);
}
if (mailbox_list_notify_init(notify_ns->ns->list, notify_events,
&notify_ns->notify) < 0) {
/* notifications not supported */
} else {
ret = 0;
mailbox_list_notify_wait(notify_ns->notify,
notify_callback, notify_ns);
}
}
/* enable NOTIFY as long as even one namespace supports it,
ignore the rest */
return ret;
}
void imap_notify_deinit(struct imap_notify_context **_ctx)
{
struct imap_notify_context *ctx = *_ctx;
struct imap_notify_namespace *notify_ns;
*_ctx = NULL;
array_foreach_modifiable(&ctx->namespaces, notify_ns) {
if (notify_ns->notify != NULL)
mailbox_list_notify_deinit(&notify_ns->notify);
}
if (ctx->to_watch != NULL)
timeout_remove(&ctx->to_watch);
if (ctx->fetch_ctx != NULL)
imap_fetch_free(&ctx->fetch_ctx);
pool_unref(&ctx->pool);
}
void imap_notify_flush(struct imap_notify_context *ctx)
{
struct imap_notify_namespace *notify_ns;
array_foreach_modifiable(&ctx->namespaces, notify_ns) {
if (notify_ns->notify != NULL)
mailbox_list_notify_flush(notify_ns->notify);
}
}