return FALSE;
}
-static struct mailbox *
-get_mailbox(struct client_command_context *cmd, const char *name)
-{
- struct mail_namespace *ns;
- struct mailbox *box;
- enum mailbox_name_status status;
- const char *storage_name;
-
- ns = client_find_namespace(cmd, name, &storage_name, &status);
- if (ns == NULL)
- return NULL;
-
- switch (status) {
- case MAILBOX_NAME_EXISTS_MAILBOX:
- break;
- case MAILBOX_NAME_EXISTS_DIR:
- status = MAILBOX_NAME_VALID;
- /* fall through */
- case MAILBOX_NAME_VALID:
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, name, "TRYCREATE", status);
- return NULL;
- }
-
- if (cmd->client->mailbox != NULL &&
- mailbox_equals(cmd->client->mailbox, ns, storage_name))
- return cmd->client->mailbox;
-
- box = mailbox_alloc(ns->list, storage_name, MAILBOX_FLAG_SAVEONLY |
- MAILBOX_FLAG_KEEP_RECENT);
- if (mailbox_open(box) < 0) {
- client_send_storage_error(cmd, mailbox_get_storage(box));
- mailbox_free(&box);
- return NULL;
- }
- if (cmd->client->enabled_features != 0)
- mailbox_enable(box, cmd->client->enabled_features);
- return box;
-}
-
bool cmd_append(struct client_command_context *cmd)
{
struct client *client = cmd->client;
ctx = p_new(cmd->pool, struct cmd_append_context, 1);
ctx->cmd = cmd;
ctx->client = client;
- ctx->box = get_mailbox(cmd, mailbox);
- if (ctx->box == NULL)
+ if (client_open_save_dest_box(cmd, mailbox, &ctx->box) < 0)
ctx->failed = TRUE;
else {
ctx->storage = mailbox_get_storage(ctx->box);
bool cmd_copy(struct client_command_context *cmd)
{
struct client *client = cmd->client;
- struct mail_namespace *dest_ns;
struct mail_storage *dest_storage;
struct mailbox *destbox;
struct mailbox_transaction_context *t;
struct mail_search_args *search_args;
- const char *messageset, *mailbox, *storage_name, *src_uidset;
- enum mailbox_name_status status;
+ const char *messageset, *mailbox, *src_uidset;
enum mailbox_sync_flags sync_flags = 0;
enum imap_sync_flags imap_flags = 0;
struct mail_transaction_commit_changes changes;
if (ret <= 0)
return ret < 0;
- /* open the destination mailbox */
- dest_ns = client_find_namespace(cmd, mailbox, &storage_name, &status);
- if (dest_ns == NULL)
+ if (client_open_save_dest_box(cmd, mailbox, &destbox) < 0)
return TRUE;
- switch (status) {
- case MAILBOX_NAME_EXISTS_MAILBOX:
- break;
- case MAILBOX_NAME_EXISTS_DIR:
- status = MAILBOX_NAME_VALID;
- /* fall through */
- case MAILBOX_NAME_VALID:
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, mailbox,
- "TRYCREATE", status);
- return NULL;
- }
-
- if (mailbox_equals(client->mailbox, dest_ns, storage_name))
- destbox = client->mailbox;
- else {
- destbox = mailbox_alloc(dest_ns->list, storage_name,
- MAILBOX_FLAG_SAVEONLY |
- MAILBOX_FLAG_KEEP_RECENT);
- if (mailbox_open(destbox) < 0) {
- client_send_storage_error(cmd,
- mailbox_get_storage(destbox));
- mailbox_free(&destbox);
- return TRUE;
- }
- if (client->enabled_features != 0)
- mailbox_enable(destbox, client->enabled_features);
- }
-
t = mailbox_transaction_begin(destbox,
MAILBOX_TRANSACTION_FLAG_EXTERNAL |
MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS);
bool cmd_create(struct client_command_context *cmd)
{
- enum mailbox_name_status status;
struct mail_namespace *ns;
const char *mailbox, *storage_name;
struct mailbox *box;
if (!client_read_string_args(cmd, 1, &mailbox))
return FALSE;
- ns = client_find_namespace(cmd, mailbox, &storage_name, NULL);
+ ns = client_find_namespace(cmd, mailbox, &storage_name);
if (ns == NULL)
return TRUE;
informing us that it wants to create children under this
mailbox. */
directory = TRUE;
- storage_name = t_strndup(storage_name, strlen(storage_name)-1);
mailbox = t_strndup(mailbox, len-1);
+
+ /* drop also from storage_name. it's already dropped when
+ WORKAROUND_TB_EXTRA_MAILBOX_SEP is enabled */
+ len = strlen(storage_name);
+ if (storage_name[len-1] == ns->real_sep)
+ storage_name = t_strndup(storage_name, len-1);
}
- ns = client_find_namespace(cmd, mailbox, &storage_name, &status);
+ ns = client_find_namespace(cmd, mailbox, &storage_name);
if (ns == NULL)
return TRUE;
- switch (status) {
- case MAILBOX_NAME_VALID:
- break;
- case MAILBOX_NAME_EXISTS_DIR:
- if (!directory)
- break;
- /* fall through */
- case MAILBOX_NAME_EXISTS_MAILBOX:
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, mailbox, NULL, status);
- return TRUE;
- }
box = mailbox_alloc(ns->list, storage_name, 0);
if (mailbox_create(box, NULL, directory) < 0)
bool cmd_delete(struct client_command_context *cmd)
{
struct client *client = cmd->client;
- enum mailbox_name_status status;
struct mail_namespace *ns;
struct mailbox *box;
const char *name, *storage_name;
return TRUE;
}
- ns = client_find_namespace(cmd, name, &storage_name, &status);
+ ns = client_find_namespace(cmd, name, &storage_name);
if (ns == NULL)
return TRUE;
- switch (status) {
- case MAILBOX_NAME_EXISTS_MAILBOX:
- case MAILBOX_NAME_EXISTS_DIR:
- break;
- case MAILBOX_NAME_VALID:
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, name, NULL, status);
- return TRUE;
- }
box = mailbox_alloc(ns->list, storage_name, 0);
if (client->mailbox != NULL &&
bool cmd_rename(struct client_command_context *cmd)
{
- enum mailbox_name_status status;
struct mail_namespace *old_ns, *new_ns;
struct mailbox *old_box, *new_box;
const char *oldname, *newname, *storage_oldname, *storage_newname;
if (!client_read_string_args(cmd, 2, &oldname, &newname))
return FALSE;
- old_ns = client_find_namespace(cmd, oldname, &storage_oldname, &status);
+ old_ns = client_find_namespace(cmd, oldname, &storage_oldname);
if (old_ns == NULL)
return TRUE;
- switch (status) {
- case MAILBOX_NAME_EXISTS_MAILBOX:
- case MAILBOX_NAME_EXISTS_DIR:
- break;
- case MAILBOX_NAME_VALID:
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, oldname, NULL, status);
- return TRUE;
- }
-
- new_ns = client_find_namespace(cmd, newname, &storage_newname, &status);
+ new_ns = client_find_namespace(cmd, newname, &storage_newname);
if (new_ns == NULL)
return TRUE;
- switch (status) {
- case MAILBOX_NAME_VALID:
- break;
- case MAILBOX_NAME_EXISTS_MAILBOX:
- case MAILBOX_NAME_EXISTS_DIR:
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, newname, NULL, status);
- return TRUE;
- }
if (old_ns == new_ns) {
/* disallow box -> box/child, because it may break clients and
struct client *client = cmd->client;
struct imap_select_context *ctx;
const struct imap_arg *args, *list_args;
- enum mailbox_name_status status;
const char *mailbox, *storage_name;
int ret;
ctx = p_new(cmd->pool, struct imap_select_context, 1);
ctx->cmd = cmd;
- ctx->ns = client_find_namespace(cmd, mailbox, &storage_name, &status);
+ ctx->ns = client_find_namespace(cmd, mailbox, &storage_name);
if (ctx->ns == NULL) {
close_selected_mailbox(client);
return TRUE;
}
- switch (status) {
- case MAILBOX_NAME_EXISTS_MAILBOX:
- break;
- case MAILBOX_NAME_EXISTS_DIR:
- status = MAILBOX_NAME_VALID;
- /* fall through */
- case MAILBOX_NAME_VALID:
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, mailbox, NULL, status);
- close_selected_mailbox(client);
- return TRUE;
- }
if (imap_arg_get_list(&args[1], &list_args)) {
if (!select_parse_options(ctx, list_args)) {
bool cmd_status(struct client_command_context *cmd)
{
struct client *client = cmd->client;
- enum mailbox_name_status status;
const struct imap_arg *args, *list_args;
struct imap_status_items items;
struct imap_status_result result;
if (imap_status_parse_items(cmd, list_args, &items) < 0)
return TRUE;
- ns = client_find_namespace(cmd, mailbox, &storage_name, &status);
+ ns = client_find_namespace(cmd, mailbox, &storage_name);
if (ns == NULL)
return TRUE;
- switch (status) {
- case MAILBOX_NAME_EXISTS_MAILBOX:
- break;
- case MAILBOX_NAME_EXISTS_DIR:
- status = MAILBOX_NAME_VALID;
- /* fall through */
- case MAILBOX_NAME_VALID:
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, mailbox, NULL, status);
- return TRUE;
- }
selected_mailbox = client->mailbox != NULL &&
mailbox_equals(client->mailbox, ns, storage_name);
return FALSE;
}
+static bool
+subscribe_is_valid_name(struct client_command_context *cmd, const char *mailbox)
+{
+ enum mailbox_name_status name_status;
+ struct mail_namespace *ns;
+ const char *storage_name;
+
+ if (have_listable_namespace_prefix(cmd->client->user->namespaces,
+ mailbox)) {
+ /* subscribing to a listable namespace prefix, allow it. */
+ return TRUE;
+ }
+
+ /* see if the mailbox exists */
+ ns = client_find_namespace(cmd, mailbox, &storage_name);
+ if (ns == NULL)
+ return FALSE;
+
+ if (mailbox_list_get_mailbox_name_status(ns->list, storage_name,
+ &name_status) < 0) {
+ client_send_list_error(cmd, ns->list);
+ return FALSE;
+ }
+ if (name_status == MAILBOX_NAME_NONEXISTENT) {
+ client_send_tagline(cmd, t_strdup_printf(
+ "NO "MAIL_ERRSTR_MAILBOX_NOT_FOUND, mailbox));
+ return FALSE;
+ }
+ return TRUE;
+}
+
bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe)
{
- enum mailbox_name_status status;
struct mail_namespace *ns, *box_ns;
const char *mailbox, *storage_name, *subs_name, *subs_name2 = NULL;
bool unsubscribed_mailbox2;
if (!client_read_string_args(cmd, 1, &mailbox))
return FALSE;
- box_ns = client_find_namespace(cmd, mailbox, &storage_name, NULL);
+ box_ns = client_find_namespace(cmd, mailbox, &storage_name);
if (box_ns == NULL)
return TRUE;
subs_name = t_strndup(subs_name, strlen(subs_name)-1);
}
- if (have_listable_namespace_prefix(cmd->client->user->namespaces,
- mailbox)) {
- /* subscribing to a listable namespace prefix, allow it. */
- } else if (subscribe) {
- if (client_find_namespace(cmd, mailbox,
- &storage_name, &status) == NULL)
- return TRUE;
- switch (status) {
- case MAILBOX_NAME_EXISTS_MAILBOX:
- case MAILBOX_NAME_EXISTS_DIR:
- break;
- case MAILBOX_NAME_VALID:
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, mailbox,
- NULL, status);
- return TRUE;
- }
- } else {
- if (client_find_namespace(cmd, mailbox,
- &storage_name, &status) == NULL)
- return TRUE;
- switch (status) {
- case MAILBOX_NAME_EXISTS_MAILBOX:
- case MAILBOX_NAME_EXISTS_DIR:
- case MAILBOX_NAME_VALID:
- break;
- case MAILBOX_NAME_INVALID:
- case MAILBOX_NAME_NOINFERIORS:
- client_fail_mailbox_name_status(cmd, mailbox,
- NULL, status);
+ if (subscribe) {
+ if (!subscribe_is_valid_name(cmd, mailbox))
return TRUE;
- }
}
unsubscribed_mailbox2 = FALSE;
#include "mail-namespace.h"
#include "imap-commands-util.h"
-/* Maximum length for mailbox name, including it's path. This isn't fully
- exact since the user can create folder hierarchy with small names, then
- rename them to larger names. Mail storages should set more strict limits
- to them, mbox/maildir currently allow paths only up to PATH_MAX. */
-#define MAILBOX_MAX_NAME_LEN 512
-
struct mail_namespace *
client_find_namespace(struct client_command_context *cmd, const char *mailbox,
- const char **storage_name_r,
- enum mailbox_name_status *mailbox_status_r)
+ const char **storage_name_r)
{
struct mail_namespace *namespaces = cmd->client->user->namespaces;
struct mail_namespace *ns;
return NULL;
}
- if (mailbox_status_r == NULL) {
- *storage_name_r = storage_name;
- return ns;
- }
-
- /* make sure it even looks valid */
- if (*storage_name == '\0' && !(*mailbox != '\0' && ns->list)) {
- client_send_tagline(cmd, "NO Empty mailbox name.");
- return NULL;
- }
-
storage_name_len = strlen(storage_name);
if ((cmd->client->set->parsed_workarounds &
WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
}
}
- /* make sure two hierarchy separators aren't next to each others */
- for (p = storage_name+1; *p != '\0'; p++) {
- if (p[0] == ns->real_sep && p[-1] == ns->real_sep) {
- client_send_tagline(cmd, "NO Invalid mailbox name.");
- return NULL;
- }
- }
-
- if (storage_name_len > MAILBOX_MAX_NAME_LEN) {
- client_send_tagline(cmd, "NO Mailbox name too long.");
- return NULL;
- }
-
- /* check what our storage thinks of it */
- if (mailbox_list_get_mailbox_name_status(ns->list, storage_name,
- mailbox_status_r) < 0) {
- client_send_list_error(cmd, ns->list);
- return NULL;
- }
*storage_name_r = storage_name;
return ns;
}
-void client_fail_mailbox_name_status(struct client_command_context *cmd,
- const char *mailbox_name,
- const char *resp_code,
- enum mailbox_name_status status)
-{
- switch (status) {
- case MAILBOX_NAME_EXISTS_MAILBOX:
- case MAILBOX_NAME_EXISTS_DIR:
- client_send_tagline(cmd, t_strconcat(
- "NO [", IMAP_RESP_CODE_ALREADYEXISTS,
- "] Mailbox already exists: ",
- str_sanitize(mailbox_name, MAILBOX_MAX_NAME_LEN),
- NULL));
- break;
- case MAILBOX_NAME_VALID:
- if (resp_code == NULL)
- resp_code = "";
- else
- resp_code = t_strconcat("[", resp_code, "] ", NULL);
- client_send_tagline(cmd, t_strconcat(
- "NO ", resp_code, "Mailbox doesn't exist: ",
- str_sanitize(mailbox_name, MAILBOX_MAX_NAME_LEN),
- NULL));
- break;
- case MAILBOX_NAME_INVALID:
- client_send_tagline(cmd, t_strconcat(
- "NO Invalid mailbox name: ",
- str_sanitize(mailbox_name, MAILBOX_MAX_NAME_LEN),
- NULL));
- break;
- case MAILBOX_NAME_NOINFERIORS:
- client_send_tagline(cmd,
- "NO Parent mailbox doesn't allow child mailboxes.");
- break;
- }
-}
-
bool client_verify_open_mailbox(struct client_command_context *cmd)
{
if (cmd->client->mailbox != NULL)
}
}
+int client_open_save_dest_box(struct client_command_context *cmd,
+ const char *name, struct mailbox **destbox_r)
+{
+ struct mail_namespace *ns;
+ struct mailbox *box;
+ const char *storage_name, *error_string;
+ enum mail_error error;
+
+ ns = client_find_namespace(cmd, name, &storage_name);
+ if (ns == NULL)
+ return -1;
+
+ if (cmd->client->mailbox != NULL &&
+ mailbox_equals(cmd->client->mailbox, ns, storage_name)) {
+ *destbox_r = cmd->client->mailbox;
+ return 0;
+ }
+ box = mailbox_alloc(ns->list, storage_name,
+ MAILBOX_FLAG_SAVEONLY | MAILBOX_FLAG_KEEP_RECENT);
+ if (mailbox_open(box) < 0) {
+ struct mail_storage *storage = mailbox_get_storage(box);
+
+ error_string = mail_storage_get_last_error(storage, &error);
+ if (error == MAIL_ERROR_NOTFOUND) {
+ client_send_tagline(cmd, t_strdup_printf(
+ "NO [TRYCREATE] %s", error_string));
+ } else {
+ client_send_storage_error(cmd, storage);
+ }
+ mailbox_free(&box);
+ return -1;
+ }
+ if (cmd->client->enabled_features != 0)
+ mailbox_enable(box, cmd->client->enabled_features);
+ *destbox_r = box;
+ return 0;
+}
+
const char *
imap_get_error_string(struct client_command_context *cmd,
const char *error_string, enum mail_error error)
or mailbox name is invalid, sends a tagged NO reply to client. */
struct mail_namespace *
client_find_namespace(struct client_command_context *cmd, const char *mailbox,
- const char **storage_name_r,
- enum mailbox_name_status *mailbox_status_r);
-
-/* Send tagged NO reply based on mailbox name status. */
-void client_fail_mailbox_name_status(struct client_command_context *cmd,
- const char *mailbox_name,
- const char *resp_code,
- enum mailbox_name_status status);
+ const char **storage_name_r);
/* Returns TRUE if mailbox is selected. If not, sends "No mailbox selected"
error message to client. */
bool client_verify_open_mailbox(struct client_command_context *cmd);
+/* Open APPEND/COPY destination mailbox. */
+int client_open_save_dest_box(struct client_command_context *cmd,
+ const char *name, struct mailbox **destbox_r);
+
const char *
imap_get_error_string(struct client_command_context *cmd,
const char *error_string, enum mail_error error);