316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "imap-common.h"
f49f1c5fa6a9a55a194e5ada042df134907278f4Aki Tuomi#include "hex-binary.h"
f49f1c5fa6a9a55a194e5ada042df134907278f4Aki Tuomi#include "str.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "imap-quote.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "imap-status.h"
285bfe946c2d54928b272270dd5eef9041b24271Timo Sirainen
b3a968f434cbb9e374ea3da0a7d493e20231a4aeAki Tuomiint imap_status_parse_items(struct client_command_context *cmd,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const struct imap_arg *args,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct imap_status_items *items_r)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *item;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi enum mailbox_status_items status = 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi enum mailbox_metadata_items metadata = 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (IMAP_ARG_IS_EOL(args)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi client_send_command_error(cmd, "Empty status list.");
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
cd24dc2196f7480d4793ca5d5f9f8d70741bc103Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
452d0005a47c6872590346f5ea8b247974689ac9Aki Tuomi i_zero(items_r);
c6108c1bfa10d5fcd1def9c6a23ebcd5204d1775Timo Sirainen for (; !IMAP_ARG_IS_EOL(args); args++) {
345f36ebc7dd445cfa3dbf157342d110cc74d7c7Aki Tuomi if (!imap_arg_get_atom(args, &item)) {
c6108c1bfa10d5fcd1def9c6a23ebcd5204d1775Timo Sirainen /* list may contain only atoms */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi client_send_command_error(cmd,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi "Status list contains non-atoms.");
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi item = t_str_ucase(item);
17fbd200b78112bd0d89e89598aa01cea72a74e5Martti Rannanjärvi if (strcmp(item, "MESSAGES") == 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi status |= STATUS_MESSAGES;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi else if (strcmp(item, "RECENT") == 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi status |= STATUS_RECENT;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi else if (strcmp(item, "UIDNEXT") == 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi status |= STATUS_UIDNEXT;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi else if (strcmp(item, "UIDVALIDITY") == 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi status |= STATUS_UIDVALIDITY;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi else if (strcmp(item, "UNSEEN") == 0)
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi status |= STATUS_UNSEEN;
7c9a9ac8cd5652f0e12a24b07c8559a7be0f5554Timo Sirainen else if (strcmp(item, "HIGHESTMODSEQ") == 0)
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi status |= STATUS_HIGHESTMODSEQ;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi else if (strcmp(item, "X-SIZE") == 0)
7e1a69e513739a7c12e3c5ec53dff1eb01b90524Aki Tuomi metadata |= MAILBOX_METADATA_VIRTUAL_SIZE;
7e1a69e513739a7c12e3c5ec53dff1eb01b90524Aki Tuomi else if (strcmp(item, "X-GUID") == 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi metadata |= MAILBOX_METADATA_GUID;
149299c7d5136a8fb425ef3cf8953026a1358002Timo Sirainen else {
7e1a69e513739a7c12e3c5ec53dff1eb01b90524Aki Tuomi client_send_command_error(cmd, t_strconcat(
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi "Invalid status item ", item, NULL));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
ff95c6488eb3239654ed7fd51ed787a6b2c44506Timo Sirainen }
f089a10e4816e772992346c9837ec10db3894c65Timo Sirainen
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi items_r->status = status;
ff95c6488eb3239654ed7fd51ed787a6b2c44506Timo Sirainen items_r->metadata = metadata;
ff95c6488eb3239654ed7fd51ed787a6b2c44506Timo Sirainen return 0;
ff95c6488eb3239654ed7fd51ed787a6b2c44506Timo Sirainen}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint imap_status_get(struct client_command_context *cmd,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct mail_namespace *ns, const char *mailbox,
ff95c6488eb3239654ed7fd51ed787a6b2c44506Timo Sirainen const struct imap_status_items *items,
86ad487452c763152f3ff4dd4650512f3cecdc55Aki Tuomi struct imap_status_result *result_r)
86ad487452c763152f3ff4dd4650512f3cecdc55Aki Tuomi{
86ad487452c763152f3ff4dd4650512f3cecdc55Aki Tuomi struct client *client = cmd->client;
b3a968f434cbb9e374ea3da0a7d493e20231a4aeAki Tuomi struct mailbox *box;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *errstr;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi int ret = 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
ff95c6488eb3239654ed7fd51ed787a6b2c44506Timo Sirainen if (client->mailbox != NULL &&
86ad487452c763152f3ff4dd4650512f3cecdc55Aki Tuomi mailbox_equals(client->mailbox, ns, mailbox)) {
86ad487452c763152f3ff4dd4650512f3cecdc55Aki Tuomi /* this mailbox is selected */
86ad487452c763152f3ff4dd4650512f3cecdc55Aki Tuomi box = client->mailbox;
b3a968f434cbb9e374ea3da0a7d493e20231a4aeAki Tuomi } else {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* open the mailbox */
box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY);
mailbox_set_reason(box, "STATUS");
if (client->enabled_features != 0)
(void)mailbox_enable(box, client->enabled_features);
}
if ((items->status & STATUS_HIGHESTMODSEQ) != 0)
(void)client_enable(client, MAILBOX_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);
}
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 ((items->status & STATUS_MESSAGES) != 0)
str_printfa(str, "MESSAGES %u ", status->messages);
if ((items->status & STATUS_RECENT) != 0)
str_printfa(str, "RECENT %u ", status->recent);
if ((items->status & STATUS_UIDNEXT) != 0)
str_printfa(str, "UIDNEXT %u ", status->uidnext);
if ((items->status & STATUS_UIDVALIDITY) != 0)
str_printfa(str, "UIDVALIDITY %u ", status->uidvalidity);
if ((items->status & STATUS_UNSEEN) != 0)
str_printfa(str, "UNSEEN %u ", status->unseen);
if ((items->status & STATUS_HIGHESTMODSEQ) != 0) {
str_printfa(str, "HIGHESTMODSEQ %"PRIu64" ",
status->highest_modseq);
}
if ((items->metadata & MAILBOX_METADATA_VIRTUAL_SIZE) != 0) {
str_printfa(str, "X-SIZE %"PRIu64" ",
result->metadata.virtual_size);
}
if ((items->metadata & MAILBOX_METADATA_GUID) != 0) {
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));
}