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); }
int imap_msgpart_url_open_mailbox(struct imap_msgpart_url *mpurl, struct mailbox **box_r, enum mail_error *error_code_r, const char **error_r) { struct mailbox_status box_status; enum mailbox_flags flags = MAILBOX_FLAG_READONLY; struct mail_namespace *ns; struct mailbox *box; if (mpurl->box != NULL) { *box_r = mpurl->box; *error_code_r = MAIL_ERROR_NONE; return 1; } /* find mailbox namespace */ ns = mail_namespace_find(mpurl->user->namespaces, mpurl->mailbox); /* open mailbox */ if (mpurl->selected_box != NULL && mailbox_equals(mpurl->selected_box, ns, mpurl->mailbox)) box = mpurl->selected_box; else box = mailbox_alloc(ns->list, mpurl->mailbox, flags); if (mailbox_open(box) < 0) { *error_r = mail_storage_get_last_error(mailbox_get_storage(box), error_code_r); if (box != mpurl->selected_box) mailbox_free(&box); return *error_code_r == MAIL_ERROR_TEMP ? -1 : 0; } /* verify UIDVALIDITY */ mailbox_get_open_status(box, STATUS_UIDVALIDITY, &box_status); if (mpurl->uidvalidity > 0 && box_status.uidvalidity != mpurl->uidvalidity) { *error_r = "Invalid UIDVALIDITY"; *error_code_r = MAIL_ERROR_EXPUNGED; if (box != mpurl->selected_box) mailbox_free(&box); return 0; } mpurl->box = box; *box_r = box; return 1; }
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; }
int imap_status_get(struct client_command_context *cmd, struct mail_namespace *ns, const char *mailbox, const struct imap_status_items *items, struct imap_status_result *result_r) { struct client *client = cmd->client; struct mailbox *box; const char *errstr; int ret = 0; if (client->mailbox != NULL && mailbox_equals(client->mailbox, ns, mailbox)) { /* this mailbox is selected */ box = client->mailbox; } else { /* 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 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); }