summaryrefslogtreecommitdiffstats
path: root/src/imap/imap-status.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/imap/imap-status.c')
-rw-r--r--src/imap/imap-status.c172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/imap/imap-status.c b/src/imap/imap-status.c
new file mode 100644
index 0000000..341e537
--- /dev/null
+++ b/src/imap/imap-status.c
@@ -0,0 +1,172 @@
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
+
+#include "imap-common.h"
+#include "hex-binary.h"
+#include "str.h"
+#include "imap-quote.h"
+#include "imap-status.h"
+
+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;
+
+ if (IMAP_ARG_IS_EOL(args)) {
+ client_send_command_error(cmd, "Empty status list.");
+ return -1;
+ }
+
+ i_zero(items_r);
+ for (; !IMAP_ARG_IS_EOL(args); args++) {
+ if (!imap_arg_get_atom(args, &item)) {
+ /* list may contain only atoms */
+ client_send_command_error(cmd,
+ "Status list contains non-atoms.");
+ return -1;
+ }
+
+ item = t_str_ucase(item);
+ if (strcmp(item, "MESSAGES") == 0)
+ flags |= IMAP_STATUS_ITEM_MESSAGES;
+ else if (strcmp(item, "RECENT") == 0)
+ flags |= IMAP_STATUS_ITEM_RECENT;
+ else if (strcmp(item, "UIDNEXT") == 0)
+ flags |= IMAP_STATUS_ITEM_UIDNEXT;
+ else if (strcmp(item, "UIDVALIDITY") == 0)
+ flags |= IMAP_STATUS_ITEM_UIDVALIDITY;
+ else if (strcmp(item, "UNSEEN") == 0)
+ flags |= IMAP_STATUS_ITEM_UNSEEN;
+ else if (strcmp(item, "HIGHESTMODSEQ") == 0)
+ flags |= IMAP_STATUS_ITEM_HIGHESTMODSEQ;
+ else if (strcmp(item, "SIZE") == 0)
+ flags |= IMAP_STATUS_ITEM_SIZE;
+ else if (strcmp(item, "X-SIZE") == 0)
+ flags |= IMAP_STATUS_ITEM_X_SIZE;
+ else if (strcmp(item, "X-GUID") == 0)
+ flags |= IMAP_STATUS_ITEM_X_GUID;
+ else {
+ client_send_command_error(cmd, t_strconcat(
+ "Invalid status item ", item, NULL));
+ return -1;
+ }
+ }
+
+ 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_ANY_BITS(items->flags, IMAP_STATUS_ITEM_SIZE |
+ 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,
+ struct imap_status_result *result_r)
+{
+ struct client *client = cmd->client;
+ struct mailbox *box;
+ const char *errstr;
+ int ret = 0;
+
+ if (client->mailbox != NULL &&
+ mailbox_equals(client->mailbox, ns, mailbox)) {
+ /* this mailbox is selected */
+ box = client->mailbox;
+ } else {
+ /* open the mailbox */
+ box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY);
+ (void)mailbox_enable(box, client_enabled_mailbox_features(client));
+ }
+
+ 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,
+ result_r->error);
+ }
+ if (box != client->mailbox)
+ mailbox_free(&box);
+ return ret;
+}
+
+int imap_status_send(struct client *client, const char *mailbox_mutf7,
+ const struct imap_status_items *items,
+ const struct imap_status_result *result)
+{
+ const struct mailbox_status *status = &result->status;
+ string_t *str;
+ size_t prefix_len;
+
+ str = t_str_new(128);
+ str_append(str, "* STATUS ");
+ imap_append_astring(str, mailbox_mutf7);
+ str_append(str, " (");
+
+ prefix_len = str_len(str);
+ if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_MESSAGES))
+ str_printfa(str, "MESSAGES %u ", status->messages);
+ if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_RECENT))
+ str_printfa(str, "RECENT %u ", status->recent);
+ if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_UIDNEXT))
+ str_printfa(str, "UIDNEXT %u ", status->uidnext);
+ if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_UIDVALIDITY))
+ str_printfa(str, "UIDVALIDITY %u ", status->uidvalidity);
+ if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_UNSEEN))
+ str_printfa(str, "UNSEEN %u ", status->unseen);
+ if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_HIGHESTMODSEQ)) {
+ str_printfa(str, "HIGHESTMODSEQ %"PRIu64" ",
+ status->highest_modseq);
+ }
+ if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_SIZE)) {
+ str_printfa(str, "SIZE %"PRIu64" ",
+ result->metadata.virtual_size);
+ }
+ if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_X_SIZE)) {
+ str_printfa(str, "X-SIZE %"PRIu64" ",
+ result->metadata.virtual_size);
+ }
+ if (HAS_ALL_BITS(items->flags, IMAP_STATUS_ITEM_X_GUID)) {
+ str_printfa(str, "X-GUID %s ",
+ guid_128_to_string(result->metadata.guid));
+ }
+
+ if (str_len(str) != prefix_len)
+ str_truncate(str, str_len(str)-1);
+ str_append_c(str, ')');
+
+ return client_send_line_next(client, str_c(str));
+}