Esempio n. 1
0
static int
cmd_import_box_contents(struct doveadm_mail_iter *iter, struct mail *src_mail,
			struct mailbox *dest_box)
{
	struct mail_save_context *save_ctx;
	struct mailbox_transaction_context *dest_trans;
	const char *mailbox = mailbox_get_vname(dest_box);
	int ret = 0;

	dest_trans = mailbox_transaction_begin(dest_box,
				MAILBOX_TRANSACTION_FLAG_EXTERNAL);
	do {
		if (doveadm_debug) {
			i_debug("import: box=%s uid=%u",
				mailbox, src_mail->uid);
		}
		save_ctx = mailbox_save_alloc(dest_trans);
		mailbox_save_copy_flags(save_ctx, src_mail);
		if (mailbox_copy(&save_ctx, src_mail) < 0) {
			i_error("Copying box=%s uid=%u failed: %s",
				mailbox, src_mail->uid,
				mailbox_get_last_error(dest_box, NULL));
			ret = -1;
		}
	} while (doveadm_mail_iter_next(iter, &src_mail));

	if (mailbox_transaction_commit(&dest_trans) < 0) {
		i_error("Committing copied mails to %s failed: %s", mailbox,
			mailbox_get_last_error(dest_box, NULL));
		ret = -1;
	}
	return ret;
}
static int
cmd_deduplicate_box(struct doveadm_mail_cmd_context *_ctx,
		    const struct mailbox_info *info,
		    struct mail_search_args *search_args)
{
	struct deduplicate_cmd_context *ctx =
		(struct deduplicate_cmd_context *)_ctx;
	struct doveadm_mail_iter *iter;
	struct mailbox *box;
	struct mail *mail;
	enum mail_error error;
	pool_t pool;
	HASH_TABLE(const char *, struct uidlist *) hash;
	const char *key, *errstr;
	struct uidlist *value;
	int ret = 0;

	if (doveadm_mail_iter_init(_ctx, info, search_args, 0, NULL,
				   &iter) < 0)
		return -1;

	pool = pool_alloconly_create("deduplicate", 10240);
	hash_table_create(&hash, pool, 0, str_hash, strcmp);
	while (doveadm_mail_iter_next(iter, &mail)) {
		if (ctx->by_msgid) {
			if (mail_get_first_header(mail, "Message-ID", &key) < 0) {
				errstr = mailbox_get_last_error(mail->box, &error);
				if (error == MAIL_ERROR_NOTFOUND)
					continue;
				i_error("Couldn't lookup Message-ID: for UID=%u: %s",
					mail->uid, errstr);
				doveadm_mail_failed_error(_ctx, error);
				ret = -1;
				break;
			}
		} else {
			if (mail_get_special(mail, MAIL_FETCH_GUID, &key) < 0) {
				errstr = mailbox_get_last_error(mail->box, &error);
				if (error == MAIL_ERROR_NOTFOUND)
					continue;
				i_error("Couldn't lookup GUID: for UID=%u: %s",
					mail->uid, errstr);
				doveadm_mail_failed_error(_ctx, error);
				ret = -1;
				break;
			}
		}
		if (key != NULL && *key != '\0') {
			value = p_new(pool, struct uidlist, 1);
			value->uid = mail->uid;
			value->next = hash_table_lookup(hash, key);

			if (value->next == NULL) {
				key = p_strdup(pool, key);
				hash_table_insert(hash, key, value);
			} else {
				hash_table_update(hash, key, value);
			}
		}
	}
Esempio n. 3
0
static int
cmd_save_to_mailbox(struct save_cmd_context *ctx, struct mailbox *box,
		    struct istream *input)
{
	struct mail_storage *storage = mailbox_get_storage(box);
	struct mailbox_transaction_context *trans;
	struct mail_save_context *save_ctx;
	ssize_t ret;
	bool save_failed = FALSE;

	if (mailbox_open(box) < 0) {
		i_error("Failed to open mailbox %s: %s",
			mailbox_get_vname(box), mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_storage(&ctx->ctx, storage);
		return -1;
	}

	trans = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL);
	save_ctx = mailbox_save_alloc(trans);
	if (mailbox_save_begin(&save_ctx, input) < 0) {
		i_error("Saving failed: %s", mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_storage(&ctx->ctx, storage);
		mailbox_transaction_rollback(&trans);
		return -1;
	}
	while ((ret = i_stream_read(input)) > 0 || ret == -2) {
		if (mailbox_save_continue(save_ctx) < 0) {
			save_failed = TRUE;
			ret = -1;
			break;
		}
	}
	i_assert(ret == -1);

	if (input->stream_errno != 0) {
		i_error("read(msg input) failed: %s", i_stream_get_error(input));
		doveadm_mail_failed_error(&ctx->ctx, MAIL_ERROR_TEMP);
	} else if (save_failed) {
		i_error("Saving failed: %s", mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_storage(&ctx->ctx, storage);
	} else if (mailbox_save_finish(&save_ctx) < 0) {
		i_error("Saving failed: %s",
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_storage(&ctx->ctx, storage);
	} else if (mailbox_transaction_commit(&trans) < 0) {
		i_error("Save transaction commit failed: %s",
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_storage(&ctx->ctx, storage);
	} else {
		ret = 0;
	}
	if (save_ctx != NULL)
		mailbox_save_cancel(&save_ctx);
	if (trans != NULL)
		mailbox_transaction_rollback(&trans);
	i_assert(input->eof);
	return ret < 0 ? -1 : 0;
}
Esempio n. 4
0
static int
cmd_expunge_box(struct doveadm_mail_cmd_context *_ctx,
		const struct mailbox_info *info,
		struct mail_search_args *search_args)
{
	struct expunge_cmd_context *ctx = (struct expunge_cmd_context *)_ctx;
	struct doveadm_mail_iter *iter;
	struct mailbox *box;
	struct mail *mail;
	enum mail_error error;
	int ret = 0;

	if (doveadm_mail_iter_init(_ctx, info, search_args, 0, NULL,
				   &iter) < 0)
		return -1;

	while (doveadm_mail_iter_next(iter, &mail)) {
		if (doveadm_debug) {
			i_debug("expunge: box=%s uid=%u",
				info->vname, mail->uid);
		}
		mail_expunge(mail);
	}

	if (doveadm_mail_iter_deinit_keep_box(&iter, &box) < 0)
		ret = -1;
	else if (mailbox_sync(box, 0) < 0) {
		i_error("Syncing mailbox '%s' failed: %s",
			mailbox_get_vname(box),
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_mailbox(_ctx, box);
		ret = -1;
	}

	if (ctx->delete_empty_mailbox && ret == 0) {
		if (mailbox_delete_empty(box) < 0) {
			error = mailbox_get_last_mail_error(box);
			if (error != MAIL_ERROR_EXISTS) {
				i_error("Deleting mailbox '%s' failed: %s",
					mailbox_get_vname(box),
					mailbox_get_last_error(box, NULL));
				doveadm_mail_failed_mailbox(_ctx, box);
				ret = -1;
			}
		} else {
			if (mailbox_set_subscribed(box, FALSE) < 0) {
				i_error("Unsubscribing mailbox '%s' failed: %s",
					mailbox_get_vname(box),
					mailbox_get_last_error(box, NULL));
				doveadm_mail_failed_mailbox(_ctx, box);
				ret = -1;
			}
		}
	}
	mailbox_free(&box);
	return ret;
}
Esempio n. 5
0
static int
dest_mailbox_open_or_create(struct import_cmd_context *ctx,
			    struct mail_user *user,
			    const struct mailbox_info *info,
			    struct mailbox **box_r)
{
	struct mail_namespace *ns;
	struct mailbox *box;
	enum mail_error error;
	const char *name, *errstr;

	if (*ctx->dest_parent != '\0') {
		/* prefix destination mailbox name with given parent mailbox */
		ns = mail_namespace_find(user->namespaces, ctx->dest_parent);
	} else {
		ns = mail_namespace_find(user->namespaces, info->vname);
	}
	name = convert_vname_separators(info->vname,
					mail_namespace_get_sep(info->ns),
					mail_namespace_get_sep(ns));

	if (*ctx->dest_parent != '\0') {
		name = t_strdup_printf("%s%c%s", ctx->dest_parent,
				       mail_namespace_get_sep(ns), name);
	}

	box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_SAVEONLY);
	if (mailbox_create(box, NULL, FALSE) < 0) {
		errstr = mailbox_get_last_error(box, &error);
		if (error != MAIL_ERROR_EXISTS) {
			i_error("Couldn't create mailbox %s: %s", name, errstr);
			doveadm_mail_failed_mailbox(&ctx->ctx, box);
			mailbox_free(&box);
			return -1;
		}
	}
	if (ctx->subscribe) {
		if (mailbox_set_subscribed(box, TRUE) < 0) {
			i_error("Couldn't subscribe to mailbox %s: %s",
				name, mailbox_get_last_error(box, NULL));
		}
	}
	if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
		i_error("Syncing mailbox %s failed: %s", name,
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_mailbox(&ctx->ctx, box);
		mailbox_free(&box);
		return -1;
	}
	*box_r = box;
	return 0;
}
static int
cmd_copy_box(struct copy_cmd_context *ctx, struct mailbox *destbox,
	     const struct mailbox_info *info)
{
	struct doveadm_mail_iter *iter;
	struct mailbox_transaction_context *desttrans;
	struct mail_save_context *save_ctx;
	struct mail *mail;
	int ret = 0;

	if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args, 0,
				   NULL, &iter) < 0)
		return -1;

	/* use a separately committed transaction for each mailbox.
	   this guarantees that mails aren't expunged without actually having
	   been copied. */
	desttrans = mailbox_transaction_begin(destbox,
					MAILBOX_TRANSACTION_FLAG_EXTERNAL);

	while (doveadm_mail_iter_next(iter, &mail)) {
		save_ctx = mailbox_save_alloc(desttrans);
		mailbox_save_copy_flags(save_ctx, mail);
		if (mailbox_copy(&save_ctx, mail) == 0) {
			if (ctx->move)
				mail_expunge(mail);
		} else {
			i_error("Copying message UID %u from '%s' failed: %s",
				mail->uid, info->vname,
				mailbox_get_last_error(destbox, NULL));
			doveadm_mail_failed_mailbox(&ctx->ctx, destbox);
			ret = -1;
		}
	}

	if (mailbox_transaction_commit(&desttrans) < 0) {
		i_error("Committing %s mails failed: %s",
			ctx->move ? "moved" : "copied",
			mailbox_get_last_error(destbox, NULL));
		doveadm_mail_failed_mailbox(&ctx->ctx, destbox);
		/* rollback expunges */
		doveadm_mail_iter_deinit_rollback(&iter);
		ret = -1;
	} else {
		if (doveadm_mail_iter_deinit_sync(&iter) < 0)
			ret = -1;
	}
	return ret;
}
static int
cmd_mailbox_metadata_get_run(struct doveadm_mail_cmd_context *_ctx,
			     struct mail_user *user)
{
	struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx;
	struct mail_namespace *ns;
	struct mailbox *box;
	struct mail_attribute_value value;
	int ret;

	ret = cmd_mailbox_metadata_open_mailbox(ctx, user, "get attribute",
						&ns, &box);
	if (ret != 0)
		return ret;

	ret = mailbox_attribute_get_stream(box, ctx->key_type, ctx->key, &value);
	if (ret < 0) {
		i_error("Failed to get attribute: %s",
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_mailbox(_ctx, box);
	} else if (ret == 0) {
		/* not found, print as empty */
		doveadm_print("");
	} else if (value.value_stream != NULL) {
		doveadm_print_istream(value.value_stream);
	} else {
		doveadm_print(value.value);
	}

	mailbox_free(&box);
	return ret;
}
Esempio n. 8
0
static int
cmd_acl_mailbox_open(struct doveadm_mail_cmd_context *ctx,
		     struct mail_user *user, const char *mailbox,
		     struct mailbox **box_r)
{
	struct acl_user *auser = ACL_USER_CONTEXT(user);
	struct mail_namespace *ns;
	struct mailbox *box;

	if (auser == NULL) {
		i_error("ACL not enabled for %s", user->username);
		doveadm_mail_failed_error(ctx, MAIL_ERROR_NOTFOUND);
		return -1;
	}

	ns = mail_namespace_find(user->namespaces, mailbox);
	box = mailbox_alloc(ns->list, mailbox,
			    MAILBOX_FLAG_READONLY | MAILBOX_FLAG_IGNORE_ACLS);
	if (mailbox_open(box) < 0) {
		i_error("Can't open mailbox %s: %s", mailbox,
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_mailbox(ctx, box);
		mailbox_free(&box);
		return -1;
	}
	*box_r = box;
	return 0;
}
Esempio n. 9
0
static int
ns_mailbox_try_alloc(struct dsync_brain *brain, struct mail_namespace *ns,
		     const guid_128_t guid, struct mailbox **box_r,
		     const char **errstr_r, enum mail_error *error_r)
{
	enum mailbox_flags flags = 0;
	struct mailbox *box;
	enum mailbox_existence existence;
	int ret;

	if (brain->backup_send) {
		/* make sure mailbox isn't modified */
		flags |= MAILBOX_FLAG_READONLY;
	}

	box = mailbox_alloc_guid(ns->list, guid, flags);
	ret = mailbox_exists(box, FALSE, &existence);
	if (ret < 0) {
		*errstr_r = mailbox_get_last_error(box, error_r);
		mailbox_free(&box);
		return -1;
	}
	if (existence != MAILBOX_EXISTENCE_SELECT) {
		mailbox_free(&box);
		*errstr_r = existence == MAILBOX_EXISTENCE_NONE ?
			"Mailbox was already deleted" :
			"Mailbox is no longer selectable";
		return 0;
	}
	*box_r = box;
	return 1;
}
Esempio n. 10
0
static int
lmtp_rcpt_to_is_over_quota(struct client *client,
			   const struct mail_recipient *rcpt)
{
	struct mail_user *user;
	struct mail_namespace *ns;
	struct mailbox *box;
	struct mailbox_status status;
	const char *errstr;
	enum mail_error error;
	int ret;

	if (!client->lmtp_set->lmtp_rcpt_check_quota)
		return 0;

	ret = mail_storage_service_next(storage_service,
					rcpt->service_user, &user);
	if (ret < 0)
		return -1;

	ns = mail_namespace_find_inbox(user->namespaces);
	box = mailbox_alloc(ns->list, "INBOX", 0);
	ret = mailbox_get_status(box, STATUS_CHECK_OVER_QUOTA, &status);
	if (ret < 0) {
		errstr = mailbox_get_last_error(box, &error);
		if (error == MAIL_ERROR_NOSPACE) {
			client_send_line(client, "552 5.2.2 <%s> %s",
					 rcpt->address, errstr);
			ret = 1;
		}
	}
	mailbox_free(&box);
	mail_user_unref(&user);
	return ret;
}
static int
ns_mailbox_try_alloc(struct mail_namespace *ns, const guid_128_t guid,
		     struct mailbox **box_r, const char **error_r)
{
	struct mailbox *box;
	enum mailbox_existence existence;
	enum mail_error err;
	int ret;

	box = mailbox_alloc_guid(ns->list, guid, 0);
	ret = mailbox_exists(box, FALSE, &existence);
	if (ret < 0) {
		*error_r = mailbox_get_last_error(box, &err);
		mailbox_free(&box);
		return -1;
	}
	if (existence != MAILBOX_EXISTENCE_SELECT) {
		mailbox_free(&box);
		*error_r = existence == MAILBOX_EXISTENCE_NONE ?
			"Mailbox was already deleted" :
			"Mailbox is no longer selectable";
		return 0;
	}
	*box_r = box;
	return 1;
}
static int
cmd_flags_run_box(struct flags_cmd_context *ctx,
		  const struct mailbox_info *info)
{
	struct doveadm_mail_iter *iter;
	struct mailbox *box;
	struct mail *mail;
	struct mail_keywords *kw = NULL;

	if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args,
				   0, NULL, &iter) < 0)
		return -1;
	box = doveadm_mail_iter_get_mailbox(iter);

	if (ctx->keywords != NULL) {
		if (mailbox_keywords_create(box, ctx->keywords, &kw) < 0) {
			i_error("Invalid keywords: %s",
				mailbox_get_last_error(box, NULL));
			(void)doveadm_mail_iter_deinit(&iter);
			ctx->ctx.exit_code = DOVEADM_EX_NOTPOSSIBLE;
			return -1;
		}
	}

	while (doveadm_mail_iter_next(iter, &mail)) {
		mail_update_flags(mail, ctx->modify_type, ctx->flags);
		if (kw != NULL)
			mail_update_keywords(mail, ctx->modify_type, kw);
	}
	if (kw != NULL)
		mailbox_keywords_unref(&kw);
	return doveadm_mail_iter_deinit(&iter);
}
Esempio n. 13
0
cmd_expunge_finish(struct client_command_context *cmd,
		   struct mail_search_args *search_args)
{
	struct client *client = cmd->client;
	const char *errstr;
	enum mail_error error = MAIL_ERROR_NONE;
	int ret;

	ret = imap_expunge(client->mailbox, search_args == NULL ? NULL :
			   search_args->args);
	if (search_args != NULL)
		mail_search_args_unref(&search_args);
	if (ret < 0) {
		errstr = mailbox_get_last_error(client->mailbox, &error);
		if (error != MAIL_ERROR_PERM) {
			client_send_box_error(cmd, client->mailbox);
			return TRUE;
		} else {
			return cmd_sync(cmd, 0, IMAP_SYNC_FLAG_SAFE,
				t_strdup_printf("OK Expunge ignored: %s.",
						errstr));
		}
	}

	client->sync_seen_deletes = FALSE;
	if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) {
		return cmd_sync(cmd, MAILBOX_SYNC_FLAG_EXPUNGE,
				IMAP_SYNC_FLAG_SAFE, "OK Expunge completed.");
	} else {
		return cmd_sync_callback(cmd, MAILBOX_SYNC_FLAG_EXPUNGE,
					 IMAP_SYNC_FLAG_SAFE,
					 cmd_expunge_callback);
	}
}
Esempio n. 14
0
int imap_msgpart_url_read_part(struct imap_msgpart_url *mpurl,
			       struct imap_msgpart_open_result *result_r,
			       const char **error_r)
{
	struct mail *mail;
	int ret;

	if (mpurl->result.input != NULL) {
		i_stream_seek(mpurl->result.input, 0);
		*result_r = mpurl->result;
		return 1;
	}

	/* open mail if it is not yet open */
	ret = imap_msgpart_url_open_mail(mpurl, &mail, error_r);
	if (ret <= 0)
		return ret;

	/* open the referenced part as a stream */
	ret = imap_msgpart_open(mail, mpurl->part, result_r);
	if (ret < 0) {
		*error_r = mailbox_get_last_error(mpurl->box, NULL);
		return ret;
	}

	mpurl->result = *result_r;
	return 1;
}
Esempio n. 15
0
static int cmd_deduplicate_uidlist(struct doveadm_mail_cmd_context *_ctx,
				   struct mailbox *box, struct uidlist *uidlist)
{
	struct mailbox_transaction_context *trans;
	struct mail_search_context *search_ctx;
	struct mail_search_args *search_args;
	struct mail_search_arg *arg;
	struct mail *mail;
	ARRAY_TYPE(seq_range) uids;
	int ret = 0;

	/* the uidlist is reversed with oldest mails at the end.
	   we'll delete everything but the oldest mail. */
	if (uidlist->next == NULL)
		return 0;

	t_array_init(&uids, 8);
	for (; uidlist->next != NULL; uidlist = uidlist->next)
		seq_range_array_add(&uids, uidlist->uid);

	search_args = mail_search_build_init();
	arg = mail_search_build_add(search_args, SEARCH_UIDSET);
	arg->value.seqset = uids;

	trans = mailbox_transaction_begin(box, 0);
	search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
	mail_search_args_unref(&search_args);

	while (mailbox_search_next(search_ctx, &mail))
		mail_expunge(mail);
	if (mailbox_search_deinit(&search_ctx) < 0) {
		i_error("Searching mailbox '%s' failed: %s",
			mailbox_get_vname(box),
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_mailbox(_ctx, box);
		ret = -1;
	}
	if (mailbox_transaction_commit(&trans) < 0) {
		i_error("Committing mailbox '%s' transaction failed: %s",
			mailbox_get_vname(box),
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_mailbox(_ctx, box);
		ret = -1;
	}
	return ret;
}
Esempio n. 16
0
static int
cmd_copy_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
{
	struct copy_cmd_context *ctx = (struct copy_cmd_context *)_ctx;
	const enum mailbox_list_iter_flags iter_flags =
		MAILBOX_LIST_ITER_NO_AUTO_BOXES |
		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
	struct doveadm_mailbox_list_iter *iter;
	struct mail_user *src_user;
	struct mail_namespace *ns;
	struct mailbox *destbox;
	const struct mailbox_info *info;
	int ret = 0;

	if (ctx->source_username != NULL && ctx->source_user == NULL)
		cmd_copy_alloc_source_user(ctx);

	ns = mail_namespace_find(user->namespaces, ctx->destname);
	destbox = mailbox_alloc(ns->list, ctx->destname, MAILBOX_FLAG_SAVEONLY);
	if (mailbox_open(destbox) < 0) {
		i_error("Can't open mailbox '%s': %s", ctx->destname,
			mailbox_get_last_error(destbox, NULL));
		doveadm_mail_failed_mailbox(&ctx->ctx, destbox);
		mailbox_free(&destbox);
		return -1;
	}

	src_user = ctx->source_user != NULL ? ctx->source_user : user;
	iter = doveadm_mailbox_list_iter_init(_ctx, src_user, _ctx->search_args,
					      iter_flags);
	while ((info = doveadm_mailbox_list_iter_next(iter)) != NULL) T_BEGIN {
		if (cmd_copy_box(ctx, destbox, info) < 0)
			ret = -1;
	} T_END;
	if (doveadm_mailbox_list_iter_deinit(&iter) < 0)
		ret = -1;

	if (mailbox_sync(destbox, 0) < 0) {
		i_error("Syncing mailbox '%s' failed: %s", ctx->destname,
			mailbox_get_last_error(destbox, NULL));
		doveadm_mail_failed_mailbox(&ctx->ctx, destbox);
		ret = -1;
	}
	mailbox_free(&destbox);
	return ret;
}
Esempio n. 17
0
static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree,
				  const struct mailbox_info *info,
				  const guid_128_t box_guid,
				  enum mail_error *error_r)
{
	struct dsync_mailbox_node *node;
	struct mailbox *box;
	struct mailbox_metadata metadata;
	struct mailbox_status status;
	const char *errstr;
	enum mail_error error;
	int ret = 0;

	if ((info->flags & MAILBOX_NONEXISTENT) != 0)
		return 0;
	if ((info->flags & MAILBOX_NOSELECT) != 0) {
		return !guid_128_is_empty(box_guid) ? 0 :
			dsync_mailbox_tree_add_exists_node(tree, info, &node, error_r);
	}

	/* get GUID and UIDVALIDITY for selectable mailbox */
	box = mailbox_alloc(info->ns->list, info->vname, MAILBOX_FLAG_READONLY);
	if (dsync_mailbox_tree_get_selectable(box, &metadata, &status) < 0) {
		errstr = mailbox_get_last_error(box, &error);
		switch (error) {
		case MAIL_ERROR_NOTFOUND:
			/* mailbox was just deleted? */
			break;
		case MAIL_ERROR_NOTPOSSIBLE:
			/* invalid mbox files? ignore */
			break;
		default:
			i_error("Failed to access mailbox %s: %s",
				info->vname, errstr);
			*error_r = error;
			ret = -1;
		}
		mailbox_free(&box);
		return ret;
	}
	mailbox_free(&box);

	if (!guid_128_is_empty(box_guid) &&
	    !guid_128_equals(box_guid, metadata.guid)) {
		/* unwanted mailbox */
		return 0;
	}
	if (dsync_mailbox_tree_add_exists_node(tree, info, &node, error_r) < 0)
		return -1;
	memcpy(node->mailbox_guid, metadata.guid,
	       sizeof(node->mailbox_guid));
	node->uid_validity = status.uidvalidity;
	node->uid_next = status.uidnext;
	return 0;
}
void virtual_box_copy_error(struct mailbox *dest, struct mailbox *src)
{
	const char *name, *str;
	enum mail_error error;

	name = get_user_visible_mailbox_name(src);
	str = mailbox_get_last_error(src, &error);

	str = t_strdup_printf("%s (for backend mailbox %s)", str, name);
	mail_storage_set_error(dest->storage, error, str);
}
Esempio n. 19
0
static struct mail_raw *mail_raw_create
(struct mail_user *ruser, struct istream *input,
	const char *mailfile, const char *sender, time_t mtime)
{
	struct mail_raw *mailr;
	struct mailbox_header_lookup_ctx *headers_ctx;
	const char *envelope_sender;
	int ret;

	if ( mailfile != NULL && *mailfile != '/' )
		mailfile = t_abspath(mailfile);

	mailr = i_new(struct mail_raw, 1);

	envelope_sender = sender != NULL ? sender : DEFAULT_ENVELOPE_SENDER;
	if ( mailfile == NULL ) {
		ret = raw_mailbox_alloc_stream(ruser, input, mtime,
					       envelope_sender, &mailr->box);
	} else {
		ret = raw_mailbox_alloc_path(ruser, mailfile, (time_t)-1,
					     envelope_sender, &mailr->box);
	}

	if ( ret < 0 ) {
		if ( mailfile == NULL ) {
			i_fatal("Can't open delivery mail as raw: %s",
				mailbox_get_last_error(mailr->box, NULL));
		} else {
			i_fatal("Can't open delivery mail as raw (file=%s): %s",
				mailfile, mailbox_get_last_error(mailr->box, NULL));
		}
	}

	mailr->trans = mailbox_transaction_begin(mailr->box, 0);
	headers_ctx = mailbox_header_lookup_init(mailr->box, wanted_headers);
	mailr->mail = mail_alloc(mailr->trans, 0, headers_ctx);
	mailbox_header_lookup_unref(&headers_ctx);
	mail_set_seq(mailr->mail, 1);

	return mailr;
}
static int
cmd_mailbox_metadata_set_run(struct doveadm_mail_cmd_context *_ctx,
			     struct mail_user *user)
{
	struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx;
	struct mail_namespace *ns;
	struct mailbox *box;
	struct mailbox_transaction_context *trans;
	int ret;

	ret = cmd_mailbox_metadata_open_mailbox(ctx, user, "set attribute",
						&ns, &box);
	if (ret != 0)
		return ret;

	trans = mailbox_transaction_begin(box, ctx->empty_mailbox_name ?
					  MAILBOX_TRANSACTION_FLAG_EXTERNAL : 0);

	ret = ctx->value.value == NULL ?
		mailbox_attribute_unset(trans, ctx->key_type, ctx->key) :
		mailbox_attribute_set(trans, ctx->key_type, ctx->key, &ctx->value);
	if (ret < 0) {
		i_error("Failed to set attribute: %s",
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_mailbox(_ctx, box);
		mailbox_transaction_rollback(&trans);
	} else if (mailbox_transaction_commit(&trans) < 0) {
		i_error("Failed to commit transaction: %s",
			mailbox_get_last_error(box, NULL));
		doveadm_mail_failed_mailbox(_ctx, box);
		ret = -1;
	}

	mailbox_free(&box);
	return ret;
}
static int dsync_mail_error(struct dsync_mailbox_exporter *exporter,
                            struct mail *mail, const char *field)
{
    const char *errstr;
    enum mail_error error;

    errstr = mailbox_get_last_error(exporter->box, &error);
    if (error == MAIL_ERROR_EXPUNGED)
        return 0;

    exporter->error = p_strdup_printf(exporter->pool,
                                      "Can't lookup %s for UID=%u: %s",
                                      field, mail->uid, errstr);
    return -1;
}
static int dsync_box_get(struct mailbox *box, struct dsync_mailbox *dsync_box_r)
{
	const enum mailbox_status_items status_items =
		STATUS_UIDVALIDITY | STATUS_UIDNEXT | STATUS_MESSAGES |
		STATUS_FIRST_RECENT_UID | STATUS_HIGHESTMODSEQ |
		STATUS_HIGHESTPVTMODSEQ;
	const enum mailbox_metadata_items metadata_items =
		MAILBOX_METADATA_CACHE_FIELDS | MAILBOX_METADATA_GUID;
	struct mailbox_status status;
	struct mailbox_metadata metadata;
	const char *errstr;
	enum mail_error error;

	/* get metadata first, since it may autocreate the mailbox */
	if (mailbox_get_metadata(box, metadata_items, &metadata) < 0 ||
	    mailbox_get_status(box, status_items, &status) < 0) {
		errstr = mailbox_get_last_error(box, &error);
		if (error == MAIL_ERROR_NOTFOUND ||
		    error == MAIL_ERROR_NOTPOSSIBLE) {
			/* Mailbox isn't selectable, try the next one. We
			   should have already caught \Noselect mailboxes, but
			   check them anyway here. The NOTPOSSIBLE check is
			   mainly for invalid mbox files. */
			return 0;
		}
		i_error("Failed to access mailbox %s: %s",
			mailbox_get_vname(box), errstr);
		return -1;
	}

	i_assert(status.uidvalidity != 0 || status.messages == 0);

	memset(dsync_box_r, 0, sizeof(*dsync_box_r));
	memcpy(dsync_box_r->mailbox_guid, metadata.guid,
	       sizeof(dsync_box_r->mailbox_guid));
	dsync_box_r->uid_validity = status.uidvalidity;
	dsync_box_r->uid_next = status.uidnext;
	dsync_box_r->messages_count = status.messages;
	dsync_box_r->first_recent_uid = status.first_recent_uid;
	dsync_box_r->highest_modseq = status.highest_modseq;
	dsync_box_r->highest_pvt_modseq = status.highest_pvt_modseq;
	dsync_box_r->cache_fields = *metadata.cache_fields;
	dsync_box_r->have_guids = status.have_guids;
	dsync_box_r->have_save_guids = status.have_save_guids;
	dsync_box_r->have_only_guid128 = status.have_only_guid128;
	return 1;
}
Esempio n. 23
0
static int
quota_count_mailbox(struct quota_root *root, struct mail_namespace *ns,
		    const char *vname, uint64_t *bytes, uint64_t *count)
{
	struct quota_rule *rule;
	struct mailbox *box;
	struct mailbox_metadata metadata;
	struct mailbox_status status;
	enum mail_error error;
	const char *errstr;
	int ret;

	rule = quota_root_rule_find(root->set, vname);
	if (rule != NULL && rule->ignore) {
		/* mailbox not included in quota */
		return 0;
	}

	box = mailbox_alloc(ns->list, vname, MAILBOX_FLAG_READONLY);
	if ((box->storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NOQUOTA) != 0) {
		/* quota doesn't exist for this mailbox/storage */
		ret = 0;
	} else if (mailbox_get_metadata(box, root->quota->set->vsizes ?
					MAILBOX_METADATA_VIRTUAL_SIZE :
					MAILBOX_METADATA_PHYSICAL_SIZE,
					&metadata) < 0 ||
	    mailbox_get_status(box, STATUS_MESSAGES, &status) < 0) {
		errstr = mailbox_get_last_error(box, &error);
		if (error == MAIL_ERROR_TEMP) {
			i_error("quota: Couldn't get size of mailbox %s: %s",
				vname, errstr);
			ret = -1;
		} else {
			/* non-temporary error, e.g. ACLs denied access. */
			ret = 0;
		}
	} else {
		ret = 1;
		*bytes += root->quota->set->vsizes ?
			metadata.virtual_size : metadata.physical_size;
		*count += status.messages;
	}
	mailbox_free(&box);
	return ret;
}
Esempio n. 24
0
static bool cmd_fetch_finish(struct imap_fetch_context *ctx,
			     struct client_command_context *cmd)
{
	static const char *ok_message = "OK Fetch completed.";
	const char *tagged_reply = ok_message;
	enum mail_error error;
	bool failed, seen_flags_changed = ctx->state.seen_flags_changed;

	if (ctx->state.skipped_expunged_msgs) {
		tagged_reply = "OK ["IMAP_RESP_CODE_EXPUNGEISSUED"] "
			"Some messages were already expunged.";
	}

	failed = imap_fetch_end(ctx) < 0;
	imap_fetch_free(&ctx);

	if (failed) {
		const char *errstr;

		if (cmd->client->output->closed) {
			client_disconnect(cmd->client, "Disconnected");
			return TRUE;
		}

		errstr = mailbox_get_last_error(cmd->client->mailbox, &error);
		if (error == MAIL_ERROR_CONVERSION ||
		    error == MAIL_ERROR_INVALIDDATA) {
			/* a) BINARY found unsupported Content-Transfer-Encoding
			   b) Content was invalid */
			tagged_reply = t_strdup_printf(
				"NO ["IMAP_RESP_CODE_UNKNOWN_CTE"] %s", errstr);
		} else {
			/* We never want to reply NO to FETCH requests,
			   BYE is preferrable (see imap-ml for reasons). */
			client_disconnect_with_error(cmd->client, errstr);
			return TRUE;
		}
	}

	return cmd_sync(cmd,
			(seen_flags_changed ? 0 : MAILBOX_SYNC_FLAG_FAST) |
			(cmd->uid ? 0 : MAILBOX_SYNC_FLAG_NO_EXPUNGES), 0,
			tagged_reply);
}
Esempio n. 25
0
static int imap_map_read(struct mailbox *box)
{
	struct pop3_migration_mailbox *mbox = POP3_MIGRATION_CONTEXT(box);
	struct mailbox_status status;
        struct mailbox_transaction_context *t;
	struct mail_search_args *search_args;
	struct mail_search_context *ctx;
	struct mail *mail;
	struct imap_msg_map *map;
	uoff_t psize;
	int ret = 0;

	mailbox_get_open_status(box, STATUS_MESSAGES, &status);

	i_assert(!array_is_created(&mbox->imap_msg_map));
	p_array_init(&mbox->imap_msg_map, box->pool, status.messages);

	t = mailbox_transaction_begin(box, 0);
	search_args = mail_search_build_init();
	mail_search_build_add_all(search_args);
	ctx = mailbox_search_init(t, search_args, NULL,
				  MAIL_FETCH_PHYSICAL_SIZE, NULL);
	mail_search_args_unref(&search_args);

	while (mailbox_search_next(ctx, &mail)) {
		if (mail_get_physical_size(mail, &psize) < 0) {
			i_error("pop3_migration: Failed to get psize for imap uid %u: %s",
				mail->uid,
				mailbox_get_last_error(box, NULL));
			ret = -1;
			break;
		}

		map = array_append_space(&mbox->imap_msg_map);
		map->uid = mail->uid;
		map->psize = psize;
	}

	if (mailbox_search_deinit(&ctx) < 0)
		ret = -1;
	(void)mailbox_transaction_commit(&t);
	return ret;
}
Esempio n. 26
0
int imap_msgpart_url_get_bodypartstructure(struct imap_msgpart_url *mpurl,
					   const char **bpstruct_r,
					   const char **error_r)
{
	struct mail *mail;
	int ret;

	/* open mail if it is not yet open */
	ret = imap_msgpart_url_open_mail(mpurl, &mail, error_r);
	if (ret <= 0)
		return ret;

	ret = imap_msgpart_bodypartstructure(mail, mpurl->part, bpstruct_r);
	if (ret < 0)
		*error_r = mailbox_get_last_error(mpurl->box, NULL);
	else if (ret == 0)
		*error_r = "Message part not found";
	return ret;
}
static int
cmd_mailbox_metadata_list_run_iter(struct metadata_cmd_context *ctx,
				   struct mailbox *box,
				   enum mail_attribute_type type)
{
	struct mailbox_attribute_iter *iter;
	const char *key;

	iter = mailbox_attribute_iter_init(box, type, ctx->key);
	while ((key = mailbox_attribute_iter_next(iter)) != NULL)
		doveadm_print(key);
	if (mailbox_attribute_iter_deinit(&iter) < 0) {
		i_error("Mailbox %s: Failed to iterate mailbox attributes: %s",
			mailbox_get_vname(box),
			mailbox_get_last_error(box, NULL));
		return -1;
	}
	return 0;
}
Esempio n. 28
0
void dsync_brain_mailbox_update_pre(struct dsync_brain *brain,
				    struct mailbox *box,
				    const struct dsync_mailbox *local_box,
				    const struct dsync_mailbox *remote_box)
{
	struct mailbox_update update;
	const struct dsync_mailbox_state *state;

	memset(&update, 0, sizeof(update));

	if (local_box->uid_validity != remote_box->uid_validity) {
		/* Keep the UIDVALIDITY for the mailbox that has more
		   messages. If they equal, use the higher UIDVALIDITY. */
		if (remote_box->messages_count > local_box->messages_count ||
		    (remote_box->messages_count == local_box->messages_count &&
		     remote_box->uid_validity > local_box->uid_validity))
			update.uid_validity = remote_box->uid_validity;

		state = dsync_mailbox_state_find(brain, local_box->mailbox_guid);
		if (state != NULL && state->last_common_uid > 0) {
			/* we can't continue syncing this mailbox in this
			   session, because the other side already started
			   sending mailbox changes, but not for all mails. */
			dsync_mailbox_state_remove(brain, local_box->mailbox_guid);
			// FIXME: handle this properly
		}
	}

	dsync_cache_fields_update(local_box, remote_box, &update);

	if (update.uid_validity == 0 &&
	    update.cache_updates == NULL) {
		/* no changes */
		return;
	}

	if (mailbox_update(box, &update) < 0) {
		i_error("Couldn't update mailbox %s metadata: %s",
			mailbox_get_vname(box),
			mailbox_get_last_error(box, NULL));
		brain->failed = TRUE;
	}
}
Esempio n. 29
0
static int
dsync_mailbox_tree_fix_guid_duplicate(struct dsync_mailbox_tree *tree,
				      struct dsync_mailbox_node *node1,
				      struct dsync_mailbox_node *node2)
{
	struct mailbox *box;
	struct mailbox_update update;
	struct dsync_mailbox_node *change_node;
	const char *change_vname;
	int ret = 0;

	memset(&update, 0, sizeof(update));
	guid_128_generate(update.mailbox_guid);

	/* just in case the duplication exists in both sides,
	   make them choose the same node */
	if (strcmp(dsync_mailbox_node_get_full_name(tree, node1),
		   dsync_mailbox_node_get_full_name(tree, node2)) <= 0)
		change_node = node1;
	else
		change_node = node2;

	change_vname = dsync_mailbox_node_get_full_name(tree, change_node);
	i_error("Duplicate mailbox GUID %s for mailboxes %s and %s - "
		"giving a new GUID %s to %s",
		guid_128_to_string(node1->mailbox_guid),
		dsync_mailbox_node_get_full_name(tree, node1),
		dsync_mailbox_node_get_full_name(tree, node2),
		guid_128_to_string(update.mailbox_guid), change_vname);

	i_assert(node1->ns != NULL && node2->ns != NULL);
	box = mailbox_alloc(change_node->ns->list, change_vname, 0);
	if (mailbox_update(box, &update) < 0) {
		i_error("Couldn't update mailbox %s GUID: %s",
			change_vname, mailbox_get_last_error(box, NULL));
		ret = -1;
	} else {
		memcpy(change_node->mailbox_guid, update.mailbox_guid,
		       sizeof(change_node->mailbox_guid));
	}
	mailbox_free(&box);
	return ret;
}
Esempio n. 30
0
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;
}