imap-commands-util.c revision 4e1f733fa64d01785de4ec987d83af65c273b9d1
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "imap-common.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "array.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "buffer.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "str.h"
9afe19d634946d50eab30e3b90cb5cebcde39eeaDaniel Lezcano#include "str-sanitize.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "imap-resp-code.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "imap-parser.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "imap-sync.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "imap-utf7.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "imap-util.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "mail-storage.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "mail-namespace.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand#include "imap-commands-util.h"
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandstruct mail_namespace *
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandclient_find_namespace_full(struct client *client,
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char **mailbox, const char **error_r)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand{
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand struct mail_namespace *namespaces = client->user->namespaces;
250b1eec71b074acdff1c5f6b5a1f0d7d2c20b77Stéphane Graber struct mail_namespace *ns;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand string_t *utf8_name;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand utf8_name = t_str_new(64);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (imap_utf7_to_utf8(*mailbox, utf8_name) < 0) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand *error_r = "NO Mailbox name is not valid mUTF-7";
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return NULL;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand ns = mail_namespace_find(namespaces, str_c(utf8_name));
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if ((ns->flags & NAMESPACE_FLAG_AUTOCREATED) != 0 &&
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand ns->prefix_len == 0) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand /* this matched only the autocreated prefix="" namespace.
67e571de63a8e465dc8f1b17e16744a1d3fb552cStéphane Graber give a nice human-readable error message */
7f12cae956c003445e6ee182b414617b52532af6Stéphane Graber *error_r = t_strdup_printf(
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand "NO Client tried to access nonexistent namespace. "
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand "(Mailbox name should probably be prefixed with: %s)",
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand mail_namespace_find_inbox(namespaces)->prefix);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return NULL;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
6ad1226343b309a6a54b54151b4dd2ad61004494staticfox if ((client->set->parsed_workarounds &
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand str_len(utf8_name) > 0 &&
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand str_c(utf8_name)[str_len(utf8_name)-1] == mail_namespace_get_sep(ns)) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand /* drop the extra trailing hierarchy separator */
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand str_truncate(utf8_name, str_len(utf8_name)-1);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand *mailbox = str_c(utf8_name);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return ns;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand}
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandstruct mail_namespace *
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandclient_find_namespace(struct client_command_context *cmd, const char **mailbox)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand{
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand struct mail_namespace *ns;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char *error;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand ns = client_find_namespace_full(cmd->client, mailbox, &error);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (ns == NULL)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand client_send_tagline(cmd, error);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return ns;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand}
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandbool client_verify_open_mailbox(struct client_command_context *cmd)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand{
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (cmd->client->mailbox != NULL)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return TRUE;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand else {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand client_send_tagline(cmd, "BAD No mailbox selected.");
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return FALSE;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand}
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandint client_open_save_dest_box(struct client_command_context *cmd,
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char *name, struct mailbox **destbox_r)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand{
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand struct mail_namespace *ns;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand struct mailbox *box;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char *error_string;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand enum mail_error error;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand ns = client_find_namespace(cmd, &name);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (ns == NULL)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return -1;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (cmd->client->mailbox != NULL &&
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand mailbox_equals(cmd->client->mailbox, ns, name)) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand *destbox_r = cmd->client->mailbox;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return 0;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_SAVEONLY);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (mailbox_open(box) < 0) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand error_string = mailbox_get_last_error(box, &error);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (error == MAIL_ERROR_NOTFOUND) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand client_send_tagline(cmd, t_strdup_printf(
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand "NO [TRYCREATE] %s", error_string));
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand } else {
6d10f1fcdc50789ffab87313a9b54d15ba4365dbMichael Santos client_send_box_error(cmd, box);
6d10f1fcdc50789ffab87313a9b54d15ba4365dbMichael Santos }
6d10f1fcdc50789ffab87313a9b54d15ba4365dbMichael Santos mailbox_free(&box);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return -1;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (cmd->client->enabled_features != 0) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (mailbox_enable(box, cmd->client->enabled_features) < 0) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand client_send_box_error(cmd, box);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand mailbox_free(&box);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return -1;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand *destbox_r = box;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return 0;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand}
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandconst char *
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandimap_get_error_string(struct client_command_context *cmd,
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char *error_string, enum mail_error error)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand{
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char *resp_code = NULL;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand switch (error) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand case MAIL_ERROR_NONE:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand break;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand case MAIL_ERROR_TEMP:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand resp_code = IMAP_RESP_CODE_SERVERBUG;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand break;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand case MAIL_ERROR_NOTPOSSIBLE:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand case MAIL_ERROR_PARAMS:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand resp_code = IMAP_RESP_CODE_CANNOT;
7f12cae956c003445e6ee182b414617b52532af6Stéphane Graber break;
7f12cae956c003445e6ee182b414617b52532af6Stéphane Graber case MAIL_ERROR_PERM:
7f12cae956c003445e6ee182b414617b52532af6Stéphane Graber resp_code = IMAP_RESP_CODE_NOPERM;
7f12cae956c003445e6ee182b414617b52532af6Stéphane Graber break;
7f12cae956c003445e6ee182b414617b52532af6Stéphane Graber case MAIL_ERROR_NOSPACE:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand resp_code = IMAP_RESP_CODE_OVERQUOTA;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand break;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand case MAIL_ERROR_NOTFOUND:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if ((cmd->cmd_flags & COMMAND_FLAG_USE_NONEXISTENT) != 0)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand resp_code = IMAP_RESP_CODE_NONEXISTENT;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand break;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand case MAIL_ERROR_EXISTS:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand resp_code = IMAP_RESP_CODE_ALREADYEXISTS;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand break;
67e571de63a8e465dc8f1b17e16744a1d3fb552cStéphane Graber case MAIL_ERROR_EXPUNGED:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand resp_code = IMAP_RESP_CODE_EXPUNGEISSUED;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand break;
7f12cae956c003445e6ee182b414617b52532af6Stéphane Graber case MAIL_ERROR_INUSE:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand resp_code = IMAP_RESP_CODE_INUSE;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand break;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand case MAIL_ERROR_CONVERSION:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand case MAIL_ERROR_INVALIDDATA:
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand break;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (resp_code == NULL || *error_string == '[')
f002c8a7655e42a325ef6bad9fb0844fad4e410bSerge Hallyn return t_strconcat("NO ", error_string, NULL);
f002c8a7655e42a325ef6bad9fb0844fad4e410bSerge Hallyn else
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return t_strdup_printf("NO [%s] %s", resp_code, error_string);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand}
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
8d06bd135af4852f24660be965aba2d781223af4Dwight Engenvoid client_send_list_error(struct client_command_context *cmd,
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen struct mailbox_list *list)
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen{
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen const char *error_string;
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen enum mail_error error;
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen error_string = mailbox_list_get_last_error(list, &error);
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen client_send_tagline(cmd, imap_get_error_string(cmd, error_string,
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen error));
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen}
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen
8d06bd135af4852f24660be965aba2d781223af4Dwight Engenvoid client_send_box_error(struct client_command_context *cmd,
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen struct mailbox *box)
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen{
63c3090c913142cd19f443b040cdede2c0522ce8Qiang Huang client_send_storage_error(cmd, mailbox_get_storage(box));
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen}
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen
8d06bd135af4852f24660be965aba2d781223af4Dwight Engenvoid client_send_storage_error(struct client_command_context *cmd,
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen struct mail_storage *storage)
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen{
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char *error_string;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand enum mail_error error;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (cmd->client->mailbox != NULL &&
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand mailbox_is_inconsistent(cmd->client->mailbox)) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand /* we can't do forced CLOSE, so have to disconnect */
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand client_disconnect_with_error(cmd->client,
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand "IMAP session state is inconsistent, please relogin.");
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand error_string = mail_storage_get_last_error(storage, &error);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand client_send_tagline(cmd, imap_get_error_string(cmd, error_string,
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand error));
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand}
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandvoid client_send_untagged_storage_error(struct client *client,
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand struct mail_storage *storage)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand{
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char *error_string;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand enum mail_error error;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (client->mailbox != NULL &&
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand mailbox_is_inconsistent(client->mailbox)) {
fe3b02ff94da199a8a327b3e92b6e42f2d875a45Wolfgang Bumiller /* we can't do forced CLOSE, so have to disconnect */
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen client_disconnect_with_error(client,
e555005b15a1d8e95997bd2d72abd0bc230a541dQiang Huang "IMAP session state is inconsistent, please relogin.");
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen return;
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen }
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen error_string = mail_storage_get_last_error(storage, &error);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand client_send_line(client, t_strconcat("* NO ", error_string, NULL));
7f12cae956c003445e6ee182b414617b52532af6Stéphane Graber}
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normandbool client_parse_mail_flags(struct client_command_context *cmd,
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const struct imap_arg *args,
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand enum mail_flags *flags_r,
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char *const **keywords_r)
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand{
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand const char *atom;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand enum mail_flags flag;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand ARRAY(const char *) keywords;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand *flags_r = 0;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand *keywords_r = NULL;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand p_array_init(&keywords, cmd->pool, 16);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand while (!IMAP_ARG_IS_EOL(args)) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (!imap_arg_get_atom(args, &atom)) {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand client_send_command_error(cmd,
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen "Flags list contains non-atoms.");
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen return FALSE;
593e84786e2b4709059989bee489deab5c923779Stéphane Graber }
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen if (*atom == '\\') {
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen /* system flag */
8d06bd135af4852f24660be965aba2d781223af4Dwight Engen atom = t_str_ucase(atom);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand flag = imap_parse_system_flag(atom);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand if (flag != 0 && flag != MAIL_RECENT)
a6adab20ff4b58887ff1d4314c5736f54e139386Stéphane Graber *flags_r |= flag;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand else {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand client_send_command_error(cmd, t_strconcat(
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand "Invalid system flag ", atom, NULL));
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand return FALSE;
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand } else {
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand /* keyword validity checks are done by lib-storage */
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand array_append(&keywords, &atom, 1);
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand }
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand
cda02a28c0f41feb359ebbddd68ed5f1dcd4930eMichel Normand args++;
fa7eddbbbbaf493268941bb013ed7477a5cc25b1Daniel Lezcano }
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand if (array_count(&keywords) == 0)
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand *keywords_r = NULL;
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand else {
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand array_append_zero(&keywords); /* NULL-terminate */
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand *keywords_r = array_idx(&keywords, 0);
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand }
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand return TRUE;
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand}
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normandvoid client_send_mailbox_flags(struct client *client, bool selecting)
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand{
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand struct mailbox_status status;
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand unsigned int count = array_count(client->keywords.names);
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand const char *const *keywords;
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand string_t *str;
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand if (!selecting && count == client->keywords.announce_count) {
501cbc717f4a6d9cace36ea78c88d9f00e9b7fdbMichel Normand /* no changes to keywords and we're not selecting a mailbox */
return;
}
client->keywords.announce_count = count;
mailbox_get_open_status(client->mailbox, STATUS_PERMANENT_FLAGS,
&status);
keywords = count == 0 ? NULL :
array_idx(client->keywords.names, 0);
str = t_str_new(128);
str_append(str, "* FLAGS (");
imap_write_flags(str, MAIL_FLAGS_NONRECENT, keywords);
str_append_c(str, ')');
client_send_line(client, str_c(str));
if (!status.permanent_keywords)
keywords = NULL;
str_truncate(str, 0);
str_append(str, "* OK [PERMANENTFLAGS (");
imap_write_flags(str, status.permanent_flags, keywords);
if (status.allow_new_keywords) {
if (status.permanent_flags != 0 || keywords != NULL)
str_append_c(str, ' ');
str_append(str, "\\*");
}
str_append(str, ")] ");
if (mailbox_is_readonly(client->mailbox))
str_append(str, "Read-only mailbox.");
else
str_append(str, "Flags permitted.");
client_send_line(client, str_c(str));
}
void client_update_mailbox_flags(struct client *client,
const ARRAY_TYPE(keywords) *keywords)
{
client->keywords.names = keywords;
client->keywords.announce_count = 0;
}
const char *const *
client_get_keyword_names(struct client *client, ARRAY_TYPE(keywords) *dest,
const ARRAY_TYPE(keyword_indexes) *src)
{
const unsigned int *kw_indexes;
const char *const *all_names;
unsigned int all_count;
client_send_mailbox_flags(client, FALSE);
/* convert indexes to names */
all_names = array_get(client->keywords.names, &all_count);
array_clear(dest);
array_foreach(src, kw_indexes) {
unsigned int kw_index = *kw_indexes;
i_assert(kw_index < all_count);
array_append(dest, &all_names[kw_index], 1);
}
array_append_zero(dest);
return array_idx(dest, 0);
}
void msgset_generator_init(struct msgset_generator_context *ctx, string_t *str)
{
memset(ctx, 0, sizeof(*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);
}