imap-commands-util.c revision 10ac3345fef3976ef573122de2a58a50c2fa63ce
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-common.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "array.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "buffer.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "str.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "str-sanitize.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-resp-code.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-parser.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-sync.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-utf7.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-util.h"
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen#include "mail-storage.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "mail-namespace.h"
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen#include "imap-commands-util.h"
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstruct mail_namespace *
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenclient_find_namespace_full(struct client *client,
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen const char **mailbox, const char **error_r)
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen{
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct mail_namespace *namespaces = client->user->namespaces;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen struct mail_namespace *ns;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen string_t *utf8_name;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen utf8_name = t_str_new(64);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (imap_utf7_to_utf8(*mailbox, utf8_name) < 0) {
948b838c8e9896132e3a2d802fb5dad37e8dc716Timo Sirainen *error_r = "NO Mailbox name is not valid mUTF-7";
948b838c8e9896132e3a2d802fb5dad37e8dc716Timo Sirainen return NULL;
948b838c8e9896132e3a2d802fb5dad37e8dc716Timo Sirainen }
948b838c8e9896132e3a2d802fb5dad37e8dc716Timo Sirainen
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen ns = mail_namespace_find(namespaces, str_c(utf8_name));
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen if ((ns->flags & NAMESPACE_FLAG_AUTOCREATED) != 0 &&
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen ns->prefix_len == 0) {
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen /* this matched only the autocreated prefix="" namespace.
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen give a nice human-readable error message */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *error_r = t_strdup_printf(
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen "NO Client tried to access nonexistent namespace. "
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen "(Mailbox name should probably be prefixed with: %s)",
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen mail_namespace_find_inbox(namespaces)->prefix);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return NULL;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen if ((client->set->parsed_workarounds &
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
5a0ac2e5ef482016e00575a7dce83f52c1704732Timo Sirainen str_len(utf8_name) > 0 &&
5a0ac2e5ef482016e00575a7dce83f52c1704732Timo Sirainen str_c(utf8_name)[str_len(utf8_name)-1] == mail_namespace_get_sep(ns)) {
7823ef73e51bb81a17dcb306aff89016d4ce258fTimo Sirainen /* drop the extra trailing hierarchy separator */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_truncate(utf8_name, str_len(utf8_name)-1);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *mailbox = str_c(utf8_name);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return ns;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenstruct mail_namespace *
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenclient_find_namespace(struct client_command_context *cmd, const char **mailbox)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen struct mail_namespace *ns;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const char *error;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ns = client_find_namespace_full(cmd->client, mailbox, &error);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (ns == NULL)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_send_tagline(cmd, error);
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen return ns;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenbool client_verify_open_mailbox(struct client_command_context *cmd)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (cmd->client->mailbox != NULL)
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen return TRUE;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen else {
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen client_send_tagline(cmd, "BAD No mailbox selected.");
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen return FALSE;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen }
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenvoid imap_client_close_mailbox(struct client *client)
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct mailbox *box;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen i_assert(client->mailbox != NULL);
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen if (array_is_created(&client->fetch_failed_uids))
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen array_clear(&client->fetch_failed_uids);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen client_search_updates_free(client);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen box = client->mailbox;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen client->mailbox = NULL;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen mailbox_free(&box);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_update_mailbox_flags(client, NULL);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen}
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainenint client_open_save_dest_box(struct client_command_context *cmd,
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen const char *name, struct mailbox **destbox_r)
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen{
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen struct mail_namespace *ns;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct mailbox *box;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen const char *error_string;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen enum mail_error error;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen ns = client_find_namespace(cmd, &name);
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen if (ns == NULL)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return -1;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen if (cmd->client->mailbox != NULL &&
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen mailbox_equals(cmd->client->mailbox, ns, name)) {
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen *destbox_r = cmd->client->mailbox;
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen return 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_SAVEONLY);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen if (mailbox_open(box) < 0) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen error_string = mailbox_get_last_error(box, &error);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen if (error == MAIL_ERROR_NOTFOUND) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen client_send_tagline(cmd, t_strdup_printf(
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen "NO [TRYCREATE] %s", error_string));
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen } else {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen client_send_box_error(cmd, box);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen }
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen mailbox_free(&box);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen return -1;
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen }
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen if (cmd->client->enabled_features != 0) {
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen if (mailbox_enable(box, cmd->client->enabled_features) < 0) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen client_send_box_error(cmd, box);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen mailbox_free(&box);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen return -1;
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen }
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen }
4afd5082f38342fd688acb5796912329f57dd02cTimo Sirainen *destbox_r = box;
4afd5082f38342fd688acb5796912329f57dd02cTimo Sirainen return 0;
4afd5082f38342fd688acb5796912329f57dd02cTimo Sirainen}
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainenconst char *
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainenimap_get_error_string(struct client_command_context *cmd,
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen const char *error_string, enum mail_error error)
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen{
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen const char *resp_code = NULL;
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen switch (error) {
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen case MAIL_ERROR_NONE:
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen break;
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen case MAIL_ERROR_TEMP:
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen case MAIL_ERROR_LOOKUP_ABORTED: /* BUG: shouldn't be visible here */
0c3ec2538c366bb5583f0b4ca2ce60804756b51cTimo Sirainen resp_code = IMAP_RESP_CODE_SERVERBUG;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen break;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen case MAIL_ERROR_UNAVAILABLE:
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen resp_code = IMAP_RESP_CODE_UNAVAILABLE;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen break;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen case MAIL_ERROR_NOTPOSSIBLE:
548d8f62722578f076b4944e30013675f2605206Timo Sirainen case MAIL_ERROR_PARAMS:
98950c9167dc2fab6c13d6d4c968e1963ecd73d7Timo Sirainen resp_code = IMAP_RESP_CODE_CANNOT;
98950c9167dc2fab6c13d6d4c968e1963ecd73d7Timo Sirainen break;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen case MAIL_ERROR_PERM:
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen resp_code = IMAP_RESP_CODE_NOPERM;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen break;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen case MAIL_ERROR_NOQUOTA:
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen resp_code = IMAP_RESP_CODE_OVERQUOTA;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen break;
64c48ffb71f1cf99acf375768fde4cff9b512648Timo Sirainen case MAIL_ERROR_NOTFOUND:
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen if ((cmd->cmd_flags & COMMAND_FLAG_USE_NONEXISTENT) != 0)
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen resp_code = IMAP_RESP_CODE_NONEXISTENT;
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen break;
2c42748505ef4aed83ff59b34e50ed5606900c86Timo Sirainen case MAIL_ERROR_EXISTS:
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen resp_code = IMAP_RESP_CODE_ALREADYEXISTS;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen break;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen case MAIL_ERROR_EXPUNGED:
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen resp_code = IMAP_RESP_CODE_EXPUNGEISSUED;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen break;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen case MAIL_ERROR_INUSE:
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen resp_code = IMAP_RESP_CODE_INUSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen break;
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen case MAIL_ERROR_CONVERSION:
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen case MAIL_ERROR_INVALIDDATA:
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen break;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen case MAIL_ERROR_LIMIT:
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen resp_code = IMAP_RESP_CODE_LIMIT;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen break;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (resp_code == NULL || *error_string == '[')
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return t_strconcat("NO ", error_string, NULL);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen else
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen return t_strdup_printf("NO [%s] %s", resp_code, error_string);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainenvoid client_send_list_error(struct client_command_context *cmd,
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen struct mailbox_list *list)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const char *error_string;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen enum mail_error error;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen error_string = mailbox_list_get_last_error(list, &error);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen client_send_tagline(cmd, imap_get_error_string(cmd, error_string,
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen error));
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen}
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenvoid client_disconnect_if_inconsistent(struct client *client)
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen{
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen if (client->mailbox != NULL &&
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen mailbox_is_inconsistent(client->mailbox)) {
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen /* we can't do forced CLOSE, so have to disconnect */
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen client_disconnect_with_error(client,
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen "IMAP session state is inconsistent, please relogin.");
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen}
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainenvoid client_send_box_error(struct client_command_context *cmd,
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen struct mailbox *box)
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen{
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen client_send_storage_error(cmd, mailbox_get_storage(box));
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen}
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainenvoid client_send_storage_error(struct client_command_context *cmd,
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen struct mail_storage *storage)
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const char *error_string;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen enum mail_error error;
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen error_string = mail_storage_get_last_error(storage, &error);
a91f2c465f026ca4ebb9e6c8e92800175c0dece6Timo Sirainen client_send_tagline(cmd, imap_get_error_string(cmd, error_string,
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen error));
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_disconnect_if_inconsistent(cmd->client);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainenvoid client_send_untagged_storage_error(struct client *client,
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen struct mail_storage *storage)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const char *error_string;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen enum mail_error error;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen error_string = mail_storage_get_last_error(storage, &error);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_send_line(client, t_strconcat("* NO ", error_string, NULL));
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_disconnect_if_inconsistent(client);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenbool client_parse_mail_flags(struct client_command_context *cmd,
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen const struct imap_arg *args,
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen enum mail_flags *flags_r,
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen const char *const **keywords_r)
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen{
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen const char *atom;
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen enum mail_flags flag;
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen ARRAY(const char *) keywords;
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *flags_r = 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *keywords_r = NULL;
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen p_array_init(&keywords, cmd->pool, 16);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen while (!IMAP_ARG_IS_EOL(args)) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (!imap_arg_get_atom(args, &atom)) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_send_command_error(cmd,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen "Flags list contains non-atoms.");
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (*atom == '\\') {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* system flag */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen atom = t_str_ucase(atom);
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen flag = imap_parse_system_flag(atom);
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen if (flag != 0 && flag != MAIL_RECENT)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen *flags_r |= flag;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen else {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_send_command_error(cmd, t_strconcat(
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen "Invalid system flag ", atom, NULL));
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen return FALSE;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen } else {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* keyword validity checks are done by lib-storage */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen array_append(&keywords, &atom, 1);
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen }
5c92436a61569c0b56a9374e60e779fa4455edefTimo Sirainen
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen args++;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen
6cc5a850bb6c1769f4113009c2067e5a719175a0Timo Sirainen if (array_count(&keywords) == 0)
6cc5a850bb6c1769f4113009c2067e5a719175a0Timo Sirainen *keywords_r = NULL;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen else {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen array_append_zero(&keywords); /* NULL-terminate */
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen *keywords_r = array_idx(&keywords, 0);
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen }
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen return TRUE;
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen}
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainenvoid client_send_mailbox_flags(struct client *client, bool selecting)
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen{
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen struct mailbox_status status;
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen unsigned int count = array_count(client->keywords.names);
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen const char *const *keywords;
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen string_t *str;
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen if (!selecting && count == client->keywords.announce_count) {
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen /* no changes to keywords and we're not selecting a mailbox */
65d8efa66dca27db85f74ee2574188b51569a4c2Timo Sirainen return;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen client->keywords.announce_count = count;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen mailbox_get_open_status(client->mailbox, STATUS_PERMANENT_FLAGS,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen &status);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen keywords = count == 0 ? NULL :
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen array_idx(client->keywords.names, 0);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str = t_str_new(128);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_append(str, "* FLAGS (");
421973339968d444d4433cb4d47d1f150e4ab288Timo Sirainen imap_write_flags(str, status.flags, keywords);
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen str_append_c(str, ')');
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_send_line(client, str_c(str));
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (!status.permanent_keywords)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen keywords = NULL;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_truncate(str, 0);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_append(str, "* OK [PERMANENTFLAGS (");
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen imap_write_flags(str, status.permanent_flags, keywords);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (status.allow_new_keywords) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (status.permanent_flags != 0 || keywords != NULL)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_append_c(str, ' ');
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_append(str, "\\*");
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen }
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_append(str, ")] ");
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen if (mailbox_is_readonly(client->mailbox))
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen str_append(str, "Read-only mailbox.");
0928812e725cd3a4debab2a93d0c9b0436a4de9fTimo Sirainen else
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen str_append(str, "Flags permitted.");
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_send_line(client, str_c(str));
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainenvoid client_update_mailbox_flags(struct client *client,
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen const ARRAY_TYPE(keywords) *keywords)
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client->keywords.names = keywords;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client->keywords.announce_count = 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenconst char *const *
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainenclient_get_keyword_names(struct client *client, ARRAY_TYPE(keywords) *dest,
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen const ARRAY_TYPE(keyword_indexes) *src)
16b5dc27e7db42849510403d37e3629aba14de21Timo Sirainen{
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const unsigned int *kw_indexes;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const char *const *all_names;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen unsigned int all_count;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen client_send_mailbox_flags(client, FALSE);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* convert indexes to names */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen all_names = array_get(client->keywords.names, &all_count);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen array_clear(dest);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen array_foreach(src, kw_indexes) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen unsigned int kw_index = *kw_indexes;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen i_assert(kw_index < all_count);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen array_append(dest, &all_names[kw_index], 1);
da2aa032ccfa8e7e4a4380ef738014549f4d2c2dTimo Sirainen }
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen array_append_zero(dest);
9511a40d933181045343110c8101b75887062aaeTimo Sirainen return array_idx(dest, 0);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen}
void msgset_generator_init(struct msgset_generator_context *ctx, string_t *str)
{
i_zero(ctx);
ctx->str = str;
ctx->last_uid = (uint32_t)-1;
}
void msgset_generator_next(struct msgset_generator_context *ctx, uint32_t uid)
{
i_assert(uid > 0);
if (uid-1 != ctx->last_uid) {
if (ctx->first_uid == 0)
;
else if (ctx->first_uid == ctx->last_uid)
str_printfa(ctx->str, "%u,", ctx->first_uid);
else {
str_printfa(ctx->str, "%u:%u,",
ctx->first_uid, ctx->last_uid);
}
ctx->first_uid = uid;
}
ctx->last_uid = uid;
}
void msgset_generator_finish(struct msgset_generator_context *ctx)
{
if (ctx->first_uid == ctx->last_uid)
str_printfa(ctx->str, "%u", ctx->first_uid);
else
str_printfa(ctx->str, "%u:%u", ctx->first_uid, ctx->last_uid);
}