imap-notify.c revision 906a651134bead2be605f2be6c47bd91a4cb94be
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int imap_notify_list(struct imap_notify_namespace *notify_ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen char ns_sep = mail_namespace_get_sep(notify_ns->ns);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return client_send_line_next(notify_ns->ctx->client, str_c(str));
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int imap_notify_status(struct imap_notify_namespace *notify_ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct client *client = notify_ns->ctx->client;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_CONDSTORE) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen box = mailbox_alloc(notify_ns->ns->list, rec->vname, 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_UIDVALIDITY) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen items.status |= STATUS_UIDVALIDITY | STATUS_UIDNEXT |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & (MAILBOX_LIST_NOTIFY_APPENDS |
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen items.status |= STATUS_UIDNEXT | STATUS_MESSAGES | STATUS_UNSEEN;
0001f76bf725c5cf403bade8556f142dd43144eeTimo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_SEEN_CHANGES) != 0)
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 /* 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 ret = imap_status_send(client, rec->vname, &items, &result);
5fc7434595b04687b14efafdc0c1597538da5c09Timo Sirainenimap_notify_next(struct imap_notify_namespace *notify_ns,
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_CREATE) != 0) {
2b5818150ab6701eebd0cf35fc143dc5c7a71aa8Timo Sirainen if (mailbox_list_mailbox(notify_ns->ns->list, rec->storage_name,
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if ((ret = imap_notify_list(notify_ns, rec, mailbox_flags)) <= 0)
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 if ((rec->events & MAILBOX_LIST_NOTIFY_RENAME) != 0) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (mailbox_list_mailbox(notify_ns->ns->list, rec->storage_name,
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if ((ret = imap_notify_list(notify_ns, rec, mailbox_flags)) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_SUBSCRIBE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mailbox_list_mailbox(notify_ns->ns->list, rec->storage_name,
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 if ((ret = imap_notify_list(notify_ns, rec, mailbox_flags)) < 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((rec->events & (MAILBOX_LIST_NOTIFY_UIDVALIDITY |
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen if ((ret = imap_notify_status(notify_ns, rec)) < 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenimap_notify_match_event(struct imap_notify_namespace *notify_ns,
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen const struct imap_notify_mailboxes *notify_boxes,
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen enum imap_notify_event wanted_events = notify_boxes->events;
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 |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((wanted_events & IMAP_NOTIFY_EVENT_SUBSCRIPTION_CHANGE) != 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((rec->events & (MAILBOX_LIST_NOTIFY_SUBSCRIBE |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* if this is an event for the selected mailbox, ignore it */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (box != NULL && mailbox_equals(box, notify_ns->ns, rec->vname))
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((wanted_events & (IMAP_NOTIFY_EVENT_MESSAGE_NEW |
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_UIDVALIDITY) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((wanted_events & IMAP_NOTIFY_EVENT_MESSAGE_NEW) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_APPENDS) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((wanted_events & IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((rec->events & MAILBOX_LIST_NOTIFY_EXPUNGES) != 0)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((wanted_events & IMAP_NOTIFY_EVENT_FLAG_CHANGE) != 0) {
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen if ((rec->events & (MAILBOX_LIST_NOTIFY_SEEN_CHANGES |
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainenbool imap_notify_match_mailbox(struct imap_notify_namespace *notify_ns,
b8d314c6355009ad0b9e332b6acecdfac5cc8891Timo Sirainen const struct imap_notify_mailboxes *notify_boxes,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *const *namep;
f776b9a125c59a96de6807e9558942cf7b7ab079Timo Sirainen box = mailbox_alloc(notify_ns->ns->list, vname, 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mailbox_set_reason(box, "NOTIFY is subscribed");
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen ns_sep = mail_namespace_get_sep(notify_ns->ns);
a62470cd293855dff816317d35356a989bda8f20Timo Sirainen /* everything under root. NOTIFY spec itself
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen doesn't define this, but we use it for
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen implementing "personal" */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenimap_notify_match(struct imap_notify_namespace *notify_ns,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct imap_notify_mailboxes *notify_boxes;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_foreach(¬ify_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 Sirainenstatic int imap_client_notify_ns(struct imap_notify_namespace *notify_ns)
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainen return 0; /* notifications not supported in this namespace */
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen while ((ret = mailbox_list_notify_next(notify_ns->notify, &rec)) > 0) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (imap_notify_match(notify_ns, rec)) T_BEGIN {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* failed to get some notifications */
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainenimap_client_notify_selected(struct client *client)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen struct imap_fetch_context *fetch_ctx = client->notify_ctx->fetch_ctx;
172b6edea36e425b0d0c35a854721ae63f57c289Timo Sirainen if ((ret = imap_fetch_more_no_lock_update(fetch_ctx)) <= 0)
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen /* finished the FETCH */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic int imap_client_notify_more(struct client *client)
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 ((ret = imap_client_notify_selected(client)) < 0) {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen client->notify_ctx->fetch_ctx->state.failed = FALSE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* send notifications for non-selected mailboxes */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_foreach_modifiable(&client->notify_ctx->namespaces, notify_ns) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "* NO NOTIFY error, some events may have got lost");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenint imap_client_notify_newmails(struct client *client)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct imap_fetch_context *fetch_ctx = client->notify_ctx->fetch_ctx;
9865d9e7c5713e41db939222ed9c0225a11fb99eTimo Sirainen /* FETCH notifications not enabled in this session */
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen mailbox_get_open_status(client->mailbox, STATUS_UIDNEXT, &status);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen arg = mail_search_build_add(search_args, SEARCH_UIDSET);
e42e27fcc497c7b4a5cc0b6ff304abca5ccfcb4fTimo Sirainen p_array_init(&arg->value.seqset, search_args->pool, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen imap_fetch_begin(fetch_ctx, client->mailbox, search_args);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainenvoid imap_client_notify_finished(struct client *client)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct imap_notify_namespace *notify_ns = context;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen o_stream_cork(notify_ns->ctx->client->output);
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen o_stream_uncork(notify_ns->ctx->client->output);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenimap_events_to_notify(enum imap_notify_event events)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if ((events & IMAP_NOTIFY_EVENT_MESSAGE_NEW) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((events & IMAP_NOTIFY_EVENT_MESSAGE_EXPUNGE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((events & IMAP_NOTIFY_EVENT_FLAG_CHANGE) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((events & IMAP_NOTIFY_EVENT_MAILBOX_NAME) != 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((events & IMAP_NOTIFY_EVENT_SUBSCRIPTION_CHANGE) != 0) {
return ret;
i_unreached();
notify_events = 0;
ret = 0;
return ret;