示例#1
0
static bool cmd_append_finish_parsing(struct client_command_context *cmd)
{
	struct cmd_append_context *ctx = cmd->context;
	enum mailbox_sync_flags sync_flags;
	enum imap_sync_flags imap_flags;
	struct mail_transaction_commit_changes changes;
	unsigned int save_count;
	string_t *msg;
	int ret;

	/* eat away the trailing CRLF */
	cmd->client->input_skip_line = TRUE;

	if (ctx->failed) {
		/* we failed earlier, error message is sent */
		cmd_append_finish(ctx);
		return TRUE;
	}
	if (ctx->count == 0) {
		client_send_command_error(cmd, "Missing message size.");
		cmd_append_finish(ctx);
		return TRUE;
	}

	ret = mailbox_transaction_commit_get_changes(&ctx->t, &changes);
	if (ret < 0) {
		client_send_box_error(cmd, ctx->box);
		cmd_append_finish(ctx);
		return TRUE;
	}

	msg = t_str_new(256);
	save_count = seq_range_count(&changes.saved_uids);
	if (save_count == 0 || changes.no_read_perm) {
		/* not supported by backend (virtual) */
		str_append(msg, "OK Append completed.");
	} else {
		i_assert(ctx->count == save_count);
		str_printfa(msg, "OK [APPENDUID %u ",
			    changes.uid_validity);
		imap_write_seq_range(msg, &changes.saved_uids);
		str_append(msg, "] Append completed.");
	}
	pool_unref(&changes.pool);

	if (ctx->box == cmd->client->mailbox) {
		sync_flags = 0;
		imap_flags = IMAP_SYNC_FLAG_SAFE;
	} else {
		sync_flags = MAILBOX_SYNC_FLAG_FAST;
		imap_flags = 0;
	}

	cmd_append_finish(ctx);
	return cmd_sync(cmd, sync_flags, imap_flags, str_c(msg));
}
示例#2
0
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, &copy_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;
	}
}
示例#3
0
static int
maildir_save_sync_index(struct maildir_save_context *ctx)
{
	struct mailbox_transaction_context *_t = ctx->ctx.transaction;
	struct maildir_mailbox *mbox = ctx->mbox;
	uint32_t first_uid, next_uid, first_recent_uid;
	int ret;

	/* we'll need to keep the lock past the sync deinit */
	ret = maildir_uidlist_lock(mbox->uidlist);
	i_assert(ret > 0);

	if (maildir_sync_header_refresh(mbox) < 0)
		return -1;
	if ((ret = maildir_uidlist_refresh_fast_init(mbox->uidlist)) < 0)
		return -1;

	if (ret == 0) {
		/* uidlist doesn't exist. make sure all existing message
		   are added to uidlist first. */
		(void)maildir_storage_sync_force(mbox, 0);
	}

	if (maildir_sync_index_begin(mbox, NULL, &ctx->sync_ctx) < 0)
		return -1;
	ctx->keywords_sync_ctx =
		maildir_sync_get_keywords_sync_ctx(ctx->sync_ctx);

	/* now that uidlist is locked, make sure all the existing mails
	   have been added to index. we don't really look into the
	   maildir, just add all the new mails listed in
	   dovecot-uidlist to index. */
	if (maildir_sync_index(ctx->sync_ctx, TRUE) < 0)
		return -1;

	/* if messages were added to index, assign them UIDs */
	first_uid = maildir_uidlist_get_next_uid(mbox->uidlist);
	i_assert(first_uid != 0);
	mail_index_append_finish_uids(ctx->trans, first_uid,
				      &_t->changes->saved_uids);
	i_assert(ctx->files_count == seq_range_count(&_t->changes->saved_uids));

	/* these mails are all recent in our session */
	T_BEGIN {
		next_uid = maildir_save_set_recent_flags(ctx);
	} T_END;

	if ((mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) != 0)
		first_recent_uid = next_uid;
	else if (ctx->last_nonrecent_uid != 0)
		first_recent_uid = ctx->last_nonrecent_uid + 1;
	else
		first_recent_uid = 0;

	if (first_recent_uid != 0) {
		/* maildir_sync_index() dropped recent flags from
		   existing messages. we'll still need to drop recent
		   flags from these newly added messages. */
		mail_index_update_header(ctx->trans,
					 offsetof(struct mail_index_header,
						  first_recent_uid),
					 &first_recent_uid,
					 sizeof(first_recent_uid), FALSE);
	}
示例#4
0
文件: cmd-copy.c 项目: aosm/dovecot
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, &copy_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;
	}
}