From: Stephan Bosch Date: Mon, 27 Aug 2018 21:28:58 +0000 (+0200) Subject: imap: Restructure handling of the STATUS response so that it uses its own flags for... X-Git-Tag: 2.3.10~47 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=82e5d49fdce8db49d5d083bcb76d6dd998ba7dc8;p=thirdparty%2Fdovecot%2Fcore.git imap: Restructure handling of the STATUS response so that it uses its own flags for the items. Before, it used mailbox status and metadata item flags for this purpose. This is needed to allow the existing X-SIZE and the newly standardized SIZE flag to coexist. --- diff --git a/src/imap/cmd-notify.c b/src/imap/cmd-notify.c index d9ff27315b..a378e39d72 100644 --- a/src/imap/cmd-notify.c +++ b/src/imap/cmd-notify.c @@ -429,11 +429,11 @@ imap_notify_box_send_status(struct client_command_context *cmd, i_zero(&items); i_zero(&result); - items.status = STATUS_UIDVALIDITY | STATUS_UIDNEXT | - STATUS_MESSAGES | STATUS_UNSEEN; + items.flags = IMAP_STATUS_ITEM_UIDVALIDITY | IMAP_STATUS_ITEM_UIDNEXT | + IMAP_STATUS_ITEM_MESSAGES | IMAP_STATUS_ITEM_UNSEEN; if ((ctx->global_used_events & (IMAP_NOTIFY_EVENT_FLAG_CHANGE | IMAP_NOTIFY_EVENT_ANNOTATION_CHANGE)) != 0) - items.status |= STATUS_HIGHESTMODSEQ; + items.flags |= IMAP_STATUS_ITEM_HIGHESTMODSEQ; box = mailbox_alloc(info->ns->list, info->vname, MAILBOX_FLAG_READONLY); mailbox_set_reason(box, "NOTIFY send STATUS"); diff --git a/src/imap/imap-notify.c b/src/imap/imap-notify.c index 13f8a4c805..7f47aa40b2 100644 --- a/src/imap/imap-notify.c +++ b/src/imap/imap-notify.c @@ -52,25 +52,27 @@ static int imap_notify_status(struct imap_notify_namespace *notify_ns, i_zero(&items); if (client_has_enabled(client, imap_feature_condstore)) - items.status |= STATUS_HIGHESTMODSEQ; + items.flags |= IMAP_STATUS_ITEM_HIGHESTMODSEQ; box = mailbox_alloc(notify_ns->ns->list, rec->vname, 0); mailbox_set_reason(box, "NOTIFY STATUS"); if ((rec->events & MAILBOX_LIST_NOTIFY_UIDVALIDITY) != 0) { - items.status |= STATUS_UIDVALIDITY | STATUS_UIDNEXT | - STATUS_MESSAGES | STATUS_UNSEEN; + items.flags |= IMAP_STATUS_ITEM_UIDVALIDITY | + IMAP_STATUS_ITEM_UIDNEXT | IMAP_STATUS_ITEM_MESSAGES | + IMAP_STATUS_ITEM_UNSEEN; } if ((rec->events & (MAILBOX_LIST_NOTIFY_APPENDS | MAILBOX_LIST_NOTIFY_EXPUNGES)) != 0) - items.status |= STATUS_UIDNEXT | STATUS_MESSAGES | STATUS_UNSEEN; + items.flags |= IMAP_STATUS_ITEM_UIDNEXT | + IMAP_STATUS_ITEM_MESSAGES | IMAP_STATUS_ITEM_UNSEEN; if ((rec->events & MAILBOX_LIST_NOTIFY_SEEN_CHANGES) != 0) - items.status |= STATUS_UNSEEN; + items.flags |= IMAP_STATUS_ITEM_UNSEEN; if ((rec->events & MAILBOX_LIST_NOTIFY_MODSEQ_CHANGES) != 0) { /* if HIGHESTMODSEQ isn't being sent, don't send anything */ } - if (items.status == 0) { + if (imap_status_items_is_empty(&items)) { /* don't send anything */ - } else if (mailbox_get_status(box, items.status, &result.status) < 0) { + } else if (imap_status_get_result(client, box, &items, &result) < 0) { /* hide permission errors from client. we don't want to leak information about existence of mailboxes where user doesn't have access to */ diff --git a/src/imap/imap-status.c b/src/imap/imap-status.c index 93a2b372f3..4bdf309744 100644 --- a/src/imap/imap-status.c +++ b/src/imap/imap-status.c @@ -10,9 +10,8 @@ int imap_status_parse_items(struct client_command_context *cmd, const struct imap_arg *args, struct imap_status_items *items_r) { + enum imap_status_item_flags flags = 0; const char *item; - enum mailbox_status_items status = 0; - enum mailbox_metadata_items metadata = 0; if (IMAP_ARG_IS_EOL(args)) { client_send_command_error(cmd, "Empty status list."); @@ -30,21 +29,21 @@ int imap_status_parse_items(struct client_command_context *cmd, item = t_str_ucase(item); if (strcmp(item, "MESSAGES") == 0) - status |= STATUS_MESSAGES; + flags |= IMAP_STATUS_ITEM_MESSAGES; else if (strcmp(item, "RECENT") == 0) - status |= STATUS_RECENT; + flags |= IMAP_STATUS_ITEM_RECENT; else if (strcmp(item, "UIDNEXT") == 0) - status |= STATUS_UIDNEXT; + flags |= IMAP_STATUS_ITEM_UIDNEXT; else if (strcmp(item, "UIDVALIDITY") == 0) - status |= STATUS_UIDVALIDITY; + flags |= IMAP_STATUS_ITEM_UIDVALIDITY; else if (strcmp(item, "UNSEEN") == 0) - status |= STATUS_UNSEEN; + flags |= IMAP_STATUS_ITEM_UNSEEN; else if (strcmp(item, "HIGHESTMODSEQ") == 0) - status |= STATUS_HIGHESTMODSEQ; + flags |= IMAP_STATUS_ITEM_HIGHESTMODSEQ; else if (strcmp(item, "X-SIZE") == 0) - metadata |= MAILBOX_METADATA_VIRTUAL_SIZE; + flags |= IMAP_STATUS_ITEM_X_SIZE; else if (strcmp(item, "X-GUID") == 0) - metadata |= MAILBOX_METADATA_GUID; + flags |= IMAP_STATUS_ITEM_X_GUID; else { client_send_command_error(cmd, t_strconcat( "Invalid status item ", item, NULL)); @@ -52,11 +51,44 @@ int imap_status_parse_items(struct client_command_context *cmd, } } - items_r->status = status; - items_r->metadata = metadata; + items_r->flags = flags; return 0; } +int imap_status_get_result(struct client *client, struct mailbox *box, + const struct imap_status_items *items, + struct imap_status_result *result_r) +{ + enum mailbox_status_items status = 0; + enum mailbox_metadata_items metadata = 0; + int ret; + + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_MESSAGES)) + status |= STATUS_MESSAGES; + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_RECENT)) + status |= STATUS_RECENT; + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_UIDNEXT)) + status |= STATUS_UIDNEXT; + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_UIDVALIDITY)) + status |= STATUS_UIDVALIDITY; + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_UNSEEN)) + status |= STATUS_UNSEEN; + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_HIGHESTMODSEQ)) { + client_enable(client, imap_feature_condstore); + status |= STATUS_HIGHESTMODSEQ; + } + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_X_SIZE)) + metadata |= MAILBOX_METADATA_VIRTUAL_SIZE; + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_X_GUID)) + metadata |= MAILBOX_METADATA_GUID; + + ret = mailbox_get_status(box, status, &result_r->status); + if (metadata != 0 && ret == 0) + ret = mailbox_get_metadata(box, metadata, &result_r->metadata); + + return ret; +} + int imap_status_get(struct client_command_context *cmd, struct mail_namespace *ns, const char *mailbox, const struct imap_status_items *items, @@ -78,15 +110,7 @@ int imap_status_get(struct client_command_context *cmd, (void)mailbox_enable(box, client_enabled_mailbox_features(client)); } - if ((items->status & STATUS_HIGHESTMODSEQ) != 0) - client_enable(client, imap_feature_condstore); - - ret = mailbox_get_status(box, items->status, &result_r->status); - if (items->metadata != 0 && ret == 0) { - ret = mailbox_get_metadata(box, items->metadata, - &result_r->metadata); - } - + ret = imap_status_get_result(client, box, items, result_r); if (ret < 0) { errstr = mailbox_get_last_error(box, &result_r->error); result_r->errstr = imap_get_error_string(cmd, errstr, @@ -111,25 +135,25 @@ int imap_status_send(struct client *client, const char *mailbox_mutf7, str_append(str, " ("); prefix_len = str_len(str); - if ((items->status & STATUS_MESSAGES) != 0) + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_MESSAGES)) str_printfa(str, "MESSAGES %u ", status->messages); - if ((items->status & STATUS_RECENT) != 0) + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_RECENT)) str_printfa(str, "RECENT %u ", status->recent); - if ((items->status & STATUS_UIDNEXT) != 0) + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_UIDNEXT)) str_printfa(str, "UIDNEXT %u ", status->uidnext); - if ((items->status & STATUS_UIDVALIDITY) != 0) + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_UIDVALIDITY)) str_printfa(str, "UIDVALIDITY %u ", status->uidvalidity); - if ((items->status & STATUS_UNSEEN) != 0) + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_UNSEEN)) str_printfa(str, "UNSEEN %u ", status->unseen); - if ((items->status & STATUS_HIGHESTMODSEQ) != 0) { + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_HIGHESTMODSEQ)) { str_printfa(str, "HIGHESTMODSEQ %"PRIu64" ", status->highest_modseq); } - if ((items->metadata & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) { + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_X_SIZE)) { str_printfa(str, "X-SIZE %"PRIu64" ", result->metadata.virtual_size); } - if ((items->metadata & MAILBOX_METADATA_GUID) != 0) { + if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_X_GUID)) { str_printfa(str, "X-GUID %s ", guid_128_to_string(result->metadata.guid)); } diff --git a/src/imap/imap-status.h b/src/imap/imap-status.h index fd54c68aa9..07ec8c487b 100644 --- a/src/imap/imap-status.h +++ b/src/imap/imap-status.h @@ -1,9 +1,20 @@ #ifndef IMAP_STATUS_H #define IMAP_STATUS_H +enum imap_status_item_flags { + IMAP_STATUS_ITEM_MESSAGES = BIT(0), + IMAP_STATUS_ITEM_RECENT = BIT(1), + IMAP_STATUS_ITEM_UIDNEXT = BIT(2), + IMAP_STATUS_ITEM_UIDVALIDITY = BIT(3), + IMAP_STATUS_ITEM_UNSEEN = BIT(4), + IMAP_STATUS_ITEM_HIGHESTMODSEQ = BIT(5), + + IMAP_STATUS_ITEM_X_SIZE = BIT(16), + IMAP_STATUS_ITEM_X_GUID = BIT(17), +}; + struct imap_status_items { - enum mailbox_status_items status; - enum mailbox_metadata_items metadata; + enum imap_status_item_flags flags; }; struct imap_status_result { @@ -13,13 +24,24 @@ struct imap_status_result { const char *errstr; }; +static inline bool +imap_status_items_is_empty(const struct imap_status_items *items) +{ + return (items->flags == 0); +} + int imap_status_parse_items(struct client_command_context *cmd, const struct imap_arg *args, struct imap_status_items *items_r); + +int imap_status_get_result(struct client *client, struct mailbox *box, + const struct imap_status_items *items, + struct imap_status_result *result_r); int imap_status_get(struct client_command_context *cmd, struct mail_namespace *ns, const char *mailbox, const struct imap_status_items *items, struct imap_status_result *result_r); + int imap_status_send(struct client *client, const char *mailbox_mutf7, const struct imap_status_items *items, const struct imap_status_result *result)