bool cmd_append(struct client_command_context *cmd) { struct client *client = cmd->client; struct cmd_append_context *ctx; const char *mailbox; if (client->syncing) { /* if transaction is created while its view is synced, appends aren't allowed for it. */ cmd->state = CLIENT_COMMAND_STATE_WAIT_UNAMBIGUITY; return FALSE; } /* <mailbox> */ if (!client_read_string_args(cmd, 1, &mailbox)) return FALSE; /* we keep the input locked all the time */ client->input_lock = cmd; ctx = p_new(cmd->pool, struct cmd_append_context, 1); ctx->cmd = cmd; ctx->client = client; ctx->started = ioloop_time; if (client_open_save_dest_box(cmd, mailbox, &ctx->box) < 0) ctx->failed = TRUE; else { ctx->t = mailbox_transaction_begin(ctx->box, MAILBOX_TRANSACTION_FLAG_EXTERNAL | MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS); } io_remove(&client->io); client->io = io_add(i_stream_get_fd(client->input), IO_READ, client_input_append, cmd); /* append is special because we're only waiting on client input, not client output, so disable the standard output handler until we're finished */ o_stream_unset_flush_callback(client->output); ctx->save_parser = imap_parser_create(client->input, client->output, client->set->imap_max_line_length); cmd->func = cmd_append_parse_new_msg; cmd->context = ctx; return cmd_append_parse_new_msg(cmd); }
static bool cmd_copy_full(struct client_command_context *cmd, bool move) { struct client *client = cmd->client; struct mail_storage *dest_storage; struct mailbox *destbox; struct mailbox_transaction_context *t, *src_trans; struct mail_search_args *search_args; 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; 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; if (client_open_save_dest_box(cmd, mailbox, &destbox) < 0) { mail_search_args_unref(&search_args); return TRUE; } t = mailbox_transaction_begin(destbox, MAILBOX_TRANSACTION_FLAG_EXTERNAL | MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS); ret = fetch_and_copy(client, move, t, &src_trans, 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 found."); pool_unref(&changes.pool); } else if (seq_range_count(&changes.saved_uids) == 0 || changes.no_read_perm) { /* not supported by backend (virtual) or no read permissions for mailbox */ str_append(msg, move ? "OK Move completed." : "OK Copy completed."); pool_unref(&changes.pool); } else if (move) { 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, "] Moved UIDs."); client_send_line(client, str_c(msg)); str_truncate(msg, 0); str_append(msg, "OK Move 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); } if (ret <= 0 && move) { /* move failed, don't expunge anything */ mailbox_transaction_rollback(&src_trans); } else { if (mailbox_transaction_commit(&src_trans) < 0) ret = -1; } dest_storage = mailbox_get_storage(destbox); if (destbox != client->mailbox) { if (move) sync_flags |= MAILBOX_SYNC_FLAG_EXPUNGE; else sync_flags |= MAILBOX_SYNC_FLAG_FAST; imap_flags |= IMAP_SYNC_FLAG_SAFE; mailbox_free(&destbox); } else if (move) { sync_flags |= MAILBOX_SYNC_FLAG_EXPUNGE; imap_flags |= IMAP_SYNC_FLAG_SAFE; } 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; } }