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; bool directory; size_t len; /* <mailbox> */ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); if (ns == NULL) return TRUE; len = strlen(mailbox); if (len == 0 || mailbox[len-1] != ns->sep) directory = FALSE; else if (*storage_name == '\0') { client_send_tagline(cmd, "NO ["IMAP_RESP_CODE_ALREADYEXISTS "] Namespace already exists."); return TRUE; } else { /* name ends with hierarchy separator - client is just 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); } ns = client_find_namespace(cmd, mailbox, &storage_name, &status); 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) client_send_storage_error(cmd, mailbox_get_storage(box)); else client_send_tagline(cmd, "OK Create completed."); mailbox_free(&box); return TRUE; }
static bool cmd_getquotaroot(struct client_command_context *cmd) { struct client *client = cmd->client; struct quota_user *quser = QUOTA_USER_CONTEXT(client->user); struct mail_namespace *ns; struct mailbox *box; struct quota_root_iter *iter; struct quota_root *root; const char *mailbox, *storage_name, *name; string_t *quotaroot_reply, *quota_reply; /* <mailbox> */ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; ns = client_find_namespace(cmd, mailbox, &storage_name, NULL); if (ns == NULL) return TRUE; if (quser == NULL) { client_send_tagline(cmd, "OK No quota."); return TRUE; } if (ns->owner != NULL && ns->owner != client->user && !client->user->admin) { client_send_tagline(cmd, "NO Not showing other users' quota."); return TRUE; } box = mailbox_alloc(ns->list, storage_name, MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT); /* build QUOTAROOT reply and QUOTA reply for all quota roots */ quotaroot_reply = t_str_new(128); quota_reply = t_str_new(256); str_append(quotaroot_reply, "* QUOTAROOT "); imap_quote_append_string(quotaroot_reply, mailbox, FALSE); iter = quota_root_iter_init(box); while ((root = quota_root_iter_next(iter)) != NULL) { str_append_c(quotaroot_reply, ' '); name = imap_quota_root_get_name(client->user, ns->owner, root); imap_quote_append_string(quotaroot_reply, name, FALSE); quota_reply_write(quota_reply, client->user, ns->owner, root); } quota_root_iter_deinit(&iter); mailbox_free(&box); /* send replies */ if (str_len(quota_reply) == 0) client_send_tagline(cmd, "OK No quota."); else { client_send_line(client, str_c(quotaroot_reply)); o_stream_send(client->output, str_data(quota_reply), str_len(quota_reply)); client_send_tagline(cmd, "OK Getquotaroot completed."); } return TRUE; }
static bool cmd_setmetadata_mailbox(struct imap_setmetadata_context *ctx, const char *mailbox) { struct client_command_context *cmd = ctx->cmd; struct client *client = cmd->client; struct mail_namespace *ns; ns = client_find_namespace(cmd, &mailbox); if (ns == NULL) return TRUE; if (client->mailbox != NULL && !client->mailbox_examined && mailbox_equals(client->mailbox, ns, mailbox)) ctx->box = client->mailbox; else { ctx->box = mailbox_alloc(ns->list, mailbox, 0); if (mailbox_open(ctx->box) < 0) { client_send_box_error(cmd, ctx->box); mailbox_free(&ctx->box); return TRUE; } } ctx->trans = imap_metadata_transaction_begin(ctx->box); return cmd_setmetadata_start(ctx); }
bool cmd_status(struct client_command_context *cmd) { struct client *client = cmd->client; const struct imap_arg *args, *list_args; struct imap_status_items items; struct imap_status_result result; struct mail_namespace *ns; const char *mailbox, *orig_mailbox; bool selected_mailbox; /* <mailbox> <status items> */ if (!client_read_args(cmd, 2, 0, &args)) return FALSE; if (!imap_arg_get_astring(&args[0], &mailbox) || !imap_arg_get_list(&args[1], &list_args)) { client_send_command_error(cmd, "Invalid arguments."); return TRUE; } /* get the items client wants */ if (imap_status_parse_items(cmd, list_args, &items) < 0) return TRUE; orig_mailbox = mailbox; ns = client_find_namespace(cmd, &mailbox); if (ns == NULL) return TRUE; selected_mailbox = client->mailbox != NULL && mailbox_equals(client->mailbox, ns, mailbox); if (imap_status_get(cmd, ns, mailbox, &items, &result) < 0) { client_send_tagline(cmd, result.errstr); return TRUE; } imap_status_send(client, orig_mailbox, &items, &result); if (!selected_mailbox) client_send_tagline(cmd, "OK Status completed."); else { client_send_tagline(cmd, "OK ["IMAP_RESP_CODE_CLIENTBUG"] " "Status on selected mailbox completed."); } return TRUE; }
bool cmd_create(struct client_command_context *cmd) { struct mail_namespace *ns; const char *mailbox, *orig_mailbox; struct mailbox *box; bool directory; size_t len; /* <mailbox> */ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; orig_mailbox = mailbox; ns = client_find_namespace(cmd, &mailbox); if (ns == NULL) return TRUE; len = strlen(orig_mailbox); if (len == 0 || orig_mailbox[len-1] != mail_namespace_get_sep(ns)) directory = FALSE; else { /* name ends with hierarchy separator - client is just informing us that it wants to create children under this mailbox. */ directory = TRUE; /* drop separator from mailbox. it's already dropped when WORKAROUND_TB_EXTRA_MAILBOX_SEP is enabled */ if (len == strlen(mailbox)) mailbox = t_strndup(mailbox, len-1); } box = mailbox_alloc(ns->list, mailbox, 0); mailbox_set_reason(box, "CREATE"); if (mailbox_create(box, NULL, directory) < 0) client_send_box_error(cmd, box); else client_send_tagline(cmd, "OK Create completed."); mailbox_free(&box); return TRUE; }
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 *error_string; enum mail_error error; ns = client_find_namespace(cmd, &name); if (ns == NULL) return -1; if (cmd->client->mailbox != NULL && mailbox_equals(cmd->client->mailbox, ns, name)) { *destbox_r = cmd->client->mailbox; return 0; } box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_SAVEONLY); if (mailbox_open(box) < 0) { error_string = mailbox_get_last_error(box, &error); if (error == MAIL_ERROR_NOTFOUND) { client_send_tagline(cmd, t_strdup_printf( "NO [TRYCREATE] %s", error_string)); } else { client_send_box_error(cmd, box); } mailbox_free(&box); return -1; } if (cmd->client->enabled_features != 0) { if (mailbox_enable(box, cmd->client->enabled_features) < 0) { client_send_box_error(cmd, box); mailbox_free(&box); return -1; } } *destbox_r = box; return 0; }
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; enum mailbox_sync_flags sync_flags = 0; enum imap_sync_flags imap_flags = 0; struct mail_transaction_commit_changes changes; unsigned int copy_count; string_t *msg; int ret; /* <message set> <mailbox> */ if (!client_read_string_args(cmd, 2, &messageset, &mailbox)) return FALSE; if (!client_verify_open_mailbox(cmd)) return TRUE; ret = imap_search_get_seqset(cmd, messageset, cmd->uid, &search_args); if (ret <= 0) return ret < 0; /* open the destination mailbox */ dest_ns = client_find_namespace(cmd, mailbox, &storage_name, &status); if (dest_ns == NULL) { mail_search_args_unref(&search_args); 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); mail_search_args_unref(&search_args); return TRUE; } 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); mail_search_args_unref(&search_args); 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); ret = fetch_and_copy(client, t, search_args, &src_uidset, ©_count); mail_search_args_unref(&search_args); msg = t_str_new(256); if (ret <= 0) mailbox_transaction_rollback(&t); else if (mailbox_transaction_commit_get_changes(&t, &changes) < 0) ret = -1; else if (copy_count == 0) { str_append(msg, "OK No messages copied."); pool_unref(&changes.pool); } else if (seq_range_count(&changes.saved_uids) == 0) { /* not supported by backend (virtual) */ str_append(msg, "OK Copy completed."); pool_unref(&changes.pool); } else { i_assert(copy_count == seq_range_count(&changes.saved_uids)); str_printfa(msg, "OK [COPYUID %u %s ", changes.uid_validity, src_uidset); imap_write_seq_range(msg, &changes.saved_uids); str_append(msg, "] Copy completed."); pool_unref(&changes.pool); } dest_storage = mailbox_get_storage(destbox); if (destbox != client->mailbox) { sync_flags |= MAILBOX_SYNC_FLAG_FAST; imap_flags |= IMAP_SYNC_FLAG_SAFE; mailbox_free(&destbox); } if (ret > 0) return cmd_sync(cmd, sync_flags, imap_flags, str_c(msg)); else if (ret == 0) { /* some messages were expunged, sync them */ return cmd_sync(cmd, 0, 0, "NO ["IMAP_RESP_CODE_EXPUNGEISSUED"] " "Some of the requested messages no longer exist."); } else { client_send_storage_error(cmd, dest_storage); return TRUE; } }
bool cmd_setmetadata(struct client_command_context *cmd) { struct imap_setmetadata_context *ctx; const struct imap_arg *args; const char *mailbox; struct mail_namespace *ns; int ret; ret = imap_parser_read_args(cmd->parser, 2, IMAP_PARSE_FLAG_STOP_AT_LIST, &args); if (ret == -1) { client_send_command_error(cmd, NULL); return TRUE; } if (ret == -2) return FALSE; if (!imap_arg_get_astring(&args[0], &mailbox) || args[1].type != IMAP_ARG_LIST) { client_send_command_error(cmd, "Invalid arguments."); return TRUE; } if (!cmd->client->imap_metadata_enabled) { client_send_command_error(cmd, "METADATA disabled."); return TRUE; } ctx = p_new(cmd->pool, struct imap_setmetadata_context, 1); ctx->cmd = cmd; ctx->cmd->context = ctx; if (mailbox[0] == '\0') { /* server attribute */ ctx->key_prefix = MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER; ns = mail_namespace_find_inbox(cmd->client->user->namespaces); mailbox = "INBOX"; } else { ns = client_find_namespace(cmd, &mailbox); if (ns == NULL) return TRUE; } if (cmd->client->mailbox != NULL && !cmd->client->mailbox_examined && mailbox_equals(cmd->client->mailbox, ns, mailbox)) ctx->box = cmd->client->mailbox; else { ctx->box = mailbox_alloc(ns->list, mailbox, 0); if (mailbox_open(ctx->box) < 0) { client_send_box_error(cmd, ctx->box); mailbox_free(&ctx->box); return TRUE; } } ctx->trans = mailbox_transaction_begin(ctx->box, 0); /* we support large literals, so read the values from client asynchronously the same way as APPEND does. */ cmd->client->input_lock = cmd; ctx->parser = imap_parser_create(cmd->client->input, cmd->client->output, cmd->client->set->imap_max_line_length); o_stream_unset_flush_callback(cmd->client->output); cmd->func = cmd_setmetadata_continue; cmd->context = ctx; return cmd_setmetadata_continue(cmd); }