Пример #1
0
static int
index_mailbox_precache(struct master_connection *conn, struct mailbox *box)
{
    struct mail_storage *storage = mailbox_get_storage(box);
    const char *username = mail_storage_get_user(storage)->username;
    const char *box_vname = mailbox_get_vname(box);
    struct mailbox_status status;
    struct mailbox_transaction_context *trans;
    struct mail_search_args *search_args;
    struct mail_search_context *ctx;
    struct mail *mail;
    struct mailbox_metadata metadata;
    uint32_t seq;
    char percentage_str[2+1+1];
    unsigned int counter = 0, max, percentage, percentage_sent = 0;
    int ret = 0;

    if (mailbox_get_metadata(box, MAILBOX_METADATA_PRECACHE_FIELDS,
                             &metadata) < 0 ||
            mailbox_get_status(box, STATUS_MESSAGES | STATUS_LAST_CACHED_SEQ,
                               &status) < 0)
        return -1;
    seq = status.last_cached_seq + 1;

    trans = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_NO_CACHE_DEC);
    search_args = mail_search_build_init();
    mail_search_build_add_seqset(search_args, seq, status.messages);
    ctx = mailbox_search_init(trans, search_args, NULL,
                              metadata.precache_fields, NULL);
    mail_search_args_unref(&search_args);

    max = status.messages - seq + 1;
    while (mailbox_search_next(ctx, &mail)) {
        mail_precache(mail);
        if (++counter % 100 == 0) {
            percentage = counter*100 / max;
            if (percentage != percentage_sent && percentage < 100) {
                percentage_sent = percentage;
                if (i_snprintf(percentage_str,
                               sizeof(percentage_str), "%u\n",
                               percentage) < 0)
                    i_unreached();
                (void)write_full(conn->fd, percentage_str,
                                 strlen(percentage_str));
            }
            indexer_worker_refresh_proctitle(username, box_vname,
                                             counter, max);
        }
    }
    if (mailbox_search_deinit(&ctx) < 0)
        ret = -1;
    if (mailbox_transaction_commit(&trans) < 0)
        ret = -1;
    if (ret == 0) {
        i_info("Indexed %u messages in %s",
               counter, mailbox_get_vname(box));
    }
    return ret;
}
Пример #2
0
bool imap_client_hibernate(struct client **_client)
{
	struct client *client = *_client;
	buffer_t *state;
	const char *error;
	int ret, fd_notify = -1;

	if (client->fd_in != client->fd_out) {
		/* we won't try to hibernate stdio clients */
		return FALSE;
	}
	if (o_stream_get_buffer_used_size(client->output) > 0) {
		/* wait until we've sent the pending output to client */
		return FALSE;
	}

	state = buffer_create_dynamic(default_pool, 1024);
	ret = imap_state_export_internal(client, state, &error);
	if (ret < 0) {
		i_error("Couldn't hibernate imap client: "
			"Couldn't export state: %s (mailbox=%s)", error,
			client->mailbox == NULL ? "" :
			mailbox_get_vname(client->mailbox));
	} else if (ret == 0 && client->user->mail_debug) {
		i_debug("Couldn't hibernate imap client: "
			"Couldn't export state: %s (mailbox=%s)", error,
			client->mailbox == NULL ? "" :
			mailbox_get_vname(client->mailbox));
	}
	if (ret > 0 && client->mailbox != NULL) {
		fd_notify = mailbox_watch_extract_notify_fd(client->mailbox,
							    &error);
		if (fd_notify == -1) {
			if (client->user->mail_debug) {
				i_debug("Couldn't hibernate imap client: "
					"Couldn't extract notifications fd: %s",
					error);
			}
			ret = -1;
		}
	}
	if (ret > 0) {
		if (imap_hibernate_process_send(client, state, fd_notify) < 0)
			ret = -1;
	}
	if (fd_notify != -1)
		i_close_fd(&fd_notify);
	if (ret > 0) {
		/* hide the disconnect log message, because the client didn't
		   actually log out */
		client->disconnected = TRUE;
		client_destroy(client, NULL);
		*_client = NULL;
	}
	buffer_free(&state);
	return ret > 0;
}
Пример #3
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, FALSE,
				   &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_internal_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_internal_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_internal_error(box, NULL));
				doveadm_mail_failed_mailbox(_ctx, box);
				ret = -1;
			}
		}
	}
	mailbox_free(&box);
	return ret;
}
Пример #4
0
static bool fts_autoindex_exclude_match(struct mailbox *box)
{
	const char *const *exclude_list;
	unsigned int i;
	const struct mailbox_settings *set;
	const char *const *special_use;
	struct mail_user *user = box->storage->user;

	exclude_list = fts_exclude_get_patterns(user);
	if (exclude_list == NULL)
		return FALSE;

	set = mailbox_settings_find(mailbox_get_namespace(box),
				    mailbox_get_vname(box));
	special_use = set == NULL ? NULL :
		t_strsplit_spaces(set->special_use, " ");
	for (i = 0; exclude_list[i] != NULL; i++) {
		if (exclude_list[i][0] == '\\') {
			/* \Special-use flag */
			if (str_array_icase_find(special_use, exclude_list[i]))
				return TRUE;
		} else {
			/* mailbox name with wildcards */
			if (wildcard_match(box->name, exclude_list[i]))
				return TRUE;
		}
	}
	return FALSE;
}
Пример #5
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;
}
Пример #6
0
static void
i_stream_mail_set_size_corrupted(struct mail_istream *mstream, size_t size)
{
	uoff_t cur_size = mstream->istream.istream.v_offset + size;
	const char *str, *mail_id;
	char chr;

	if (mstream->expected_size < cur_size) {
		str = "smaller";
		chr = '<';
	} else {
		str = "larger";
		chr = '>';
	}

	mail_id = i_stream_mail_get_cached_mail_id(mstream);
	if (mail_id[0] != '\0')
		mail_id = t_strconcat(", cached ", mail_id, NULL);
	io_stream_set_error(&mstream->istream.iostream,
		"Cached message size %s than expected "
		"(%"PRIuUOFF_T" %c %"PRIuUOFF_T", box=%s, UID=%u%s)", str,
		mstream->expected_size, chr, cur_size,
		mailbox_get_vname(mstream->mail->box),
		mstream->mail->uid, mail_id);
	mail_set_cache_corrupted_reason(mstream->mail, MAIL_FETCH_PHYSICAL_SIZE,
		t_strdup_printf("read(%s) failed: %s",
				i_stream_get_name(&mstream->istream.istream),
				mstream->istream.iostream.error));
	mstream->istream.istream.stream_errno = EINVAL;
}
Пример #7
0
static void mail_log_append_mailbox_name(string_t *str, struct mail *mail)
{
	const char *mailbox_str;

	mailbox_str = mailbox_get_vname(mail->box);
	str_printfa(str, "box=%s",
		    str_sanitize(mailbox_str, MAILBOX_NAME_LOG_LEN));
}
Пример #8
0
static void fetch_read_error(struct imap_fetch_context *ctx)
{
	errno = ctx->cur_input->stream_errno;
	mail_storage_set_critical(ctx->box->storage,
		"read(%s) failed: %m (FETCH for mailbox %s UID %u)",
		i_stream_get_name(ctx->cur_input),
		mailbox_get_vname(ctx->mail->box), ctx->mail->uid);
}
Пример #9
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;
}
Пример #10
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;
}
Пример #11
0
int mail_set_attachment_keywords(struct mail *mail)
{
	int ret;
	const struct mail_storage_settings *mail_set =
		mail_storage_get_settings(mailbox_get_storage(mail->box));

	const char *const keyword_has_attachment[] = {
		MAIL_KEYWORD_HAS_ATTACHMENT,
		NULL,
	};
	const char *const keyword_has_no_attachment[] = {
		MAIL_KEYWORD_HAS_NO_ATTACHMENT,
		NULL
	};
	struct message_part_attachment_settings set = {
		.content_type_filter =
			mail_set->parsed_mail_attachment_content_type_filter,
		.exclude_inlined =
			mail_set->parsed_mail_attachment_exclude_inlined,
	};
	struct mail_keywords *kw_has = NULL, *kw_has_not = NULL;

	/* walk all parts and see if there is an attachment */
	struct message_part *parts;
	if (mail_get_parts(mail, &parts) < 0) {
		mail_set_critical(mail, "Failed to add attachment keywords: "
				  "mail_get_parts() failed: %s",
				  mail_storage_get_last_internal_error(mail->box->storage, NULL));
		ret = -1;
	} else if (parts->data == NULL &&
		   mail_parse_parts(mail, &parts) < 0) {
		ret = -1;
	} else if (mailbox_keywords_create(mail->box, keyword_has_attachment, &kw_has) < 0 ||
		   mailbox_keywords_create(mail->box, keyword_has_no_attachment, &kw_has_not) < 0) {
		mail_set_critical(mail, "Failed to add attachment keywords: "
				  "mailbox_keywords_create(%s) failed: %s",
				  mailbox_get_vname(mail->box),
				  mail_storage_get_last_internal_error(mail->box->storage, NULL));
		ret = -1;
	} else {
		bool has_attachment = mail_message_has_attachment(parts, &set);

		/* make sure only one of the keywords gets set */
		mail_update_keywords(mail, MODIFY_REMOVE, has_attachment ? kw_has_not : kw_has);
		mail_update_keywords(mail, MODIFY_ADD, has_attachment ? kw_has : kw_has_not);
		ret = has_attachment ? 1 : 0;
	}

	if (kw_has != NULL)
		mailbox_keywords_unref(&kw_has);
	if (kw_has_not != NULL)
		mailbox_keywords_unref(&kw_has_not);

	return ret;
}
Пример #12
0
static void copy_update_trashed(struct client *client, struct mailbox *box,
				unsigned int count)
{
	const struct mailbox_settings *set;

	set = mailbox_settings_find(mailbox_get_namespace(box),
				    mailbox_get_vname(box));
	if (set != NULL && set->special_use[0] != '\0' &&
	    str_array_icase_find(t_strsplit_spaces(set->special_use, " "),
				 "\\Trash"))
		client->trashed_count += count;
}
Пример #13
0
static void fetch_read_error(struct imap_fetch_context *ctx)
{
	struct imap_fetch_state *state = &ctx->state;

	errno = state->cur_input->stream_errno;
	mail_storage_set_critical(state->cur_mail->box->storage,
		"read(%s) failed: %s (FETCH %s for mailbox %s UID %u)",
		i_stream_get_name(state->cur_input),
		i_stream_get_error(state->cur_input),
		state->cur_human_name,
		mailbox_get_vname(state->cur_mail->box), state->cur_mail->uid);
}
Пример #14
0
static void dsync_brain_sync_half_finished(struct dsync_brain *brain)
{
	struct dsync_mailbox_state state;
	const char *errstr;
	enum mail_error error;

	if (brain->box_recv_state < DSYNC_BOX_STATE_RECV_LAST_COMMON ||
	    brain->box_send_state < DSYNC_BOX_STATE_RECV_LAST_COMMON)
		return;

	/* finished with this mailbox */
	if (brain->box_exporter != NULL) {
		if (dsync_mailbox_export_deinit(&brain->box_exporter,
						&errstr, &error) < 0) {
			i_error("Exporting mailbox %s failed: %s",
				mailbox_get_vname(brain->box), errstr);
			brain->mail_error = error;
			brain->failed = TRUE;
			return;
		}
	}

	memset(&state, 0, sizeof(state));
	memcpy(state.mailbox_guid, brain->local_dsync_box.mailbox_guid,
	       sizeof(state.mailbox_guid));
	state.last_uidvalidity = brain->local_dsync_box.uid_validity;
	if (brain->box_importer == NULL) {
		/* this mailbox didn't exist on remote */
		state.last_common_uid = brain->local_dsync_box.uid_next-1;
		state.last_common_modseq =
			brain->local_dsync_box.highest_modseq;
		state.last_common_pvt_modseq =
			brain->local_dsync_box.highest_pvt_modseq;
		state.last_messages_count =
			brain->local_dsync_box.messages_count;
	} else {
		if (dsync_mailbox_import_deinit(&brain->box_importer, TRUE,
						&state.last_common_uid,
						&state.last_common_modseq,
						&state.last_common_pvt_modseq,
						&state.last_messages_count,
						&state.changes_during_sync,
						&brain->mail_error) < 0) {
			brain->failed = TRUE;
			return;
		}
		if (state.changes_during_sync)
			brain->changes_during_sync = TRUE;
	}
	brain->mailbox_state = state;
	dsync_ibc_send_mailbox_state(brain->ibc, &state);
}
static void push_notification_event_mailboxrename_event(
    struct push_notification_txn *ptxn,
    struct push_notification_event_config *ec,
    struct push_notification_txn_mbox *mbox,
    struct mailbox *old)
{
    struct push_notification_event_mailboxrename_data *data;

    data = p_new(ptxn->pool,
                 struct push_notification_event_mailboxrename_data, 1);
    data->old_mbox = mailbox_get_vname(old);

    push_notification_txn_mbox_set_eventdata(ptxn, mbox, ec, data);
}
Пример #16
0
static int dsync_brain_export_deinit(struct dsync_brain *brain)
{
	const char *errstr;
	enum mail_error error;

	if (dsync_mailbox_export_deinit(&brain->box_exporter,
					&errstr, &error) < 0) {
		i_error("Exporting mailbox %s failed: %s",
			mailbox_get_vname(brain->box), errstr);
		brain->mail_error = error;
		brain->failed = TRUE;
		return -1;
	}
	return 0;
}
Пример #17
0
static int fetch_stream_continue(struct imap_fetch_context *ctx)
{
	struct imap_fetch_state *state = &ctx->state;
	const char *disconnect_reason;
	off_t ret;

	o_stream_set_max_buffer_size(ctx->client->output, 0);
	ret = o_stream_send_istream(ctx->client->output, state->cur_input);
	o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);

	if (ret > 0) {
		state->cur_offset += ret;
		if (ctx->state.cur_stats_sizep != NULL)
			*ctx->state.cur_stats_sizep += ret;
	}

	if (state->cur_offset != state->cur_size) {
		/* unfinished */
		if (state->cur_input->stream_errno != 0) {
			fetch_read_error(ctx, &disconnect_reason);
			client_disconnect(ctx->client, disconnect_reason);
			return -1;
		}
		if (!i_stream_have_bytes_left(state->cur_input)) {
			/* Input stream gave less data than expected */
			i_error("read(%s): FETCH %s for mailbox %s UID %u "
				"got too little data: "
				"%"PRIuUOFF_T" vs %"PRIuUOFF_T,
				i_stream_get_name(state->cur_input),
				state->cur_human_name,
				mailbox_get_vname(state->cur_mail->box),
				state->cur_mail->uid,
				state->cur_offset, state->cur_size);
			mail_set_cache_corrupted(state->cur_mail,
						 state->cur_size_field);
			client_disconnect(ctx->client, "FETCH failed");
			return -1;
		}
		if (ret < 0) {
			/* client probably disconnected */
			return -1;
		}

		o_stream_set_flush_pending(ctx->client->output, TRUE);
		return 0;
	}
	return 1;
}
Пример #18
0
static void dbox_mail_set_expunged(struct dbox_mail *mail, uint32_t map_uid)
{
	struct mail *_mail = &mail->imail.mail.mail;
	struct mdbox_mailbox *mbox = (struct mdbox_mailbox *)_mail->box;

	(void)mail_index_refresh(_mail->box->index);
	if (mail_index_is_expunged(_mail->transaction->view, _mail->seq)) {
		mail_set_expunged(_mail);
		return;
	}

	mdbox_map_set_corrupted(mbox->storage->map,
				"Unexpectedly lost %s uid=%u map_uid=%u",
				mailbox_get_vname(_mail->box),
				_mail->uid, map_uid);
}
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;
}
Пример #20
0
static void fetch_read_error(struct imap_fetch_context *ctx,
			     const char **disconnect_reason_r)
{
	struct imap_fetch_state *state = &ctx->state;

	if (state->cur_input->stream_errno == ENOENT) {
		if (state->cur_mail->expunged) {
			*disconnect_reason_r = "Mail expunged while it was being FETCHed";
			return;
		}
	}
	mail_storage_set_critical(state->cur_mail->box->storage,
		"read(%s) failed: %s (FETCH %s for mailbox %s UID %u)",
		i_stream_get_name(state->cur_input),
		i_stream_get_error(state->cur_input),
		state->cur_human_name,
		mailbox_get_vname(state->cur_mail->box), state->cur_mail->uid);
	*disconnect_reason_r = "FETCH read() failed";
}
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;
}
Пример #22
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;
	}
}
int dsync_brain_sync_mailbox_open(struct dsync_brain *brain,
				  const struct dsync_mailbox *remote_dsync_box)
{
	enum dsync_mailbox_exporter_flags exporter_flags = 0;
	uint32_t last_common_uid, highest_wanted_uid;
	uint64_t last_common_modseq, last_common_pvt_modseq;

	i_assert(brain->log_scan == NULL);
	i_assert(brain->box_exporter == NULL);

	last_common_uid = brain->mailbox_state.last_common_uid;
	last_common_modseq = brain->mailbox_state.last_common_modseq;
	last_common_pvt_modseq = brain->mailbox_state.last_common_pvt_modseq;
	highest_wanted_uid = last_common_uid == 0 ?
		(uint32_t)-1 : last_common_uid;
	if (dsync_transaction_log_scan_init(brain->box->view,
					    brain->box->view_pvt,
					    highest_wanted_uid,
					    last_common_modseq,
					    last_common_pvt_modseq,
					    &brain->log_scan) < 0) {
		i_error("Failed to read transaction log for mailbox %s",
			mailbox_get_vname(brain->box));
		brain->failed = TRUE;
		return -1;
	}

	if (!brain->mail_requests)
		exporter_flags |= DSYNC_MAILBOX_EXPORTER_FLAG_AUTO_EXPORT_MAILS;
	if (remote_dsync_box->have_save_guids &&
	    (brain->local_dsync_box.have_save_guids ||
	     (brain->backup_send && brain->local_dsync_box.have_guids)))
		exporter_flags |= DSYNC_MAILBOX_EXPORTER_FLAG_MAILS_HAVE_GUIDS;

	brain->box_exporter = brain->backup_recv ? NULL :
		dsync_mailbox_export_init(brain->box, brain->log_scan,
					  last_common_uid,
					  exporter_flags);
	dsync_brain_sync_mailbox_init_remote(brain, remote_dsync_box);
	return 0;
}
Пример #24
0
static int fetch_stream_send_direct(struct imap_fetch_context *ctx)
{
	off_t ret;

	o_stream_set_max_buffer_size(ctx->client->output, 0);
	ret = o_stream_send_istream(ctx->client->output, ctx->cur_input);
	o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);

	if (ret < 0)
		return -1;

	ctx->cur_offset += ret;

	if (ctx->cur_append_eoh && ctx->cur_offset + 2 == ctx->cur_size) {
		/* Netscape missing EOH workaround. */
		if (o_stream_send(ctx->client->output, "\r\n", 2) < 0)
			return -1;
		ctx->cur_offset += 2;
		ctx->cur_append_eoh = FALSE;
	}

	if (ctx->cur_offset != ctx->cur_size) {
		/* unfinished */
		if (!i_stream_have_bytes_left(ctx->cur_input)) {
			/* Input stream gave less data than expected */
			i_error("FETCH %s for mailbox %s UID %u "
				"got too little data (copying): "
				"%"PRIuUOFF_T" vs %"PRIuUOFF_T,
				ctx->cur_name, mailbox_get_vname(ctx->mail->box),
				ctx->mail->uid, ctx->cur_offset, ctx->cur_size);
			mail_set_cache_corrupted(ctx->mail,
						 ctx->cur_size_field);
			client_disconnect(ctx->client, "FETCH failed");
			return -1;
		}

		o_stream_set_flush_pending(ctx->client->output, TRUE);
		return 0;
	}
	return 1;
}
Пример #25
0
int imap_msgpart_url_parse(struct mail_user *user, struct mailbox *selected_box,
			   const char *urlstr, struct imap_msgpart_url **mpurl_r,
			   const char **error_r)
{
	struct mailbox_status box_status;
	struct imap_url base_url, *url;
	const char  *error;

	/* build base url */
	memset(&base_url, 0, sizeof(base_url));
	if (selected_box != NULL) {
		mailbox_get_open_status(selected_box, STATUS_UIDVALIDITY,
					&box_status);
		base_url.mailbox = mailbox_get_vname(selected_box);
		base_url.uidvalidity = box_status.uidvalidity;
	}

	/* parse url */
	if (imap_url_parse(urlstr, &base_url,
			   IMAP_URL_PARSE_REQUIRE_RELATIVE, &url, &error) < 0) {
		*error_r = t_strconcat("Invalid IMAP URL: ", error, NULL);
		return 0;
	}
	if (url->mailbox == NULL) {
		*error_r = "Mailbox-relative IMAP URL, but no mailbox selected";
		return 0;
	}
	if (url->uid == 0 || url->search_program != NULL) {
		*error_r = "Invalid messagepart IMAP URL";
		return 0;
	}
	if (imap_msgpart_url_create(user, url, mpurl_r, error_r) < 0)
		return -1;
	(*mpurl_r)->selected_box = selected_box;
	return 1;
}
Пример #26
0
status_output(struct status_cmd_context *ctx, struct mailbox *box,
	      const struct mailbox_status *status,
	      const struct mailbox_metadata *metadata)
{
	if (box != NULL)
		doveadm_print(mailbox_get_vname(box));

	if ((ctx->status_items & STATUS_MESSAGES) != 0)
		doveadm_print_num(status->messages);
	if ((ctx->status_items & STATUS_RECENT) != 0)
		doveadm_print_num(status->recent);
	if ((ctx->status_items & STATUS_UIDNEXT) != 0)
		doveadm_print_num(status->uidnext);
	if ((ctx->status_items & STATUS_UIDVALIDITY) != 0)
		doveadm_print_num(status->uidvalidity);
	if ((ctx->status_items & STATUS_UNSEEN) != 0)
		doveadm_print_num(status->unseen);
	if ((ctx->status_items & STATUS_HIGHESTMODSEQ) != 0)
		doveadm_print_num(status->highest_modseq);
	if ((ctx->metadata_items & MAILBOX_METADATA_VIRTUAL_SIZE) != 0)
		doveadm_print_num(metadata->virtual_size);
	if ((ctx->metadata_items & MAILBOX_METADATA_GUID) != 0)
		doveadm_print(guid_128_to_string(metadata->guid));
}
Пример #27
0
bool dsync_brain_slave_recv_mailbox(struct dsync_brain *brain)
{
	const struct dsync_mailbox *dsync_box;
	struct dsync_mailbox local_dsync_box;
	struct mailbox *box;
	int ret;

	i_assert(!brain->master_brain);
	i_assert(brain->box == NULL);

	if ((ret = dsync_ibc_recv_mailbox(brain->ibc, &dsync_box)) == 0)
		return FALSE;
	if (ret < 0) {
		brain->state = DSYNC_STATE_DONE;
		return TRUE;
	}

	if (dsync_brain_mailbox_alloc(brain, dsync_box->mailbox_guid, &box) < 0) {
		i_assert(brain->failed);
		return TRUE;
	}
	if (box == NULL) {
		/* mailbox was probably deleted/renamed during sync */
		//FIXME: verify this from log, and if not log an error.
		brain->changes_during_sync = TRUE;
		dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
		return TRUE;
	}
	if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
		i_error("Can't sync mailbox %s: %s",
			mailbox_get_vname(box),
			mailbox_get_last_error(box, NULL));
		mailbox_free(&box);
		brain->failed = TRUE;
		return TRUE;
	}

	if ((ret = dsync_box_get(box, &local_dsync_box)) <= 0) {
		mailbox_free(&box);
		if (ret < 0) {
			brain->failed = TRUE;
			return TRUE;
		}
		/* another process just deleted this mailbox? */
		dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
		return TRUE;
	}
	i_assert(local_dsync_box.uid_validity != 0);
	i_assert(memcmp(dsync_box->mailbox_guid, local_dsync_box.mailbox_guid,
			sizeof(dsync_box->mailbox_guid)) == 0);
	dsync_ibc_send_mailbox(brain->ibc, &local_dsync_box);

	dsync_brain_mailbox_update_pre(brain, box, &local_dsync_box, dsync_box);

	if (brain->sync_type == DSYNC_BRAIN_SYNC_TYPE_CHANGED &&
	    !dsync_boxes_need_sync(&local_dsync_box, dsync_box)) {
		/* no fields appear to have changed, skip this mailbox */
		mailbox_free(&box);
		return TRUE;
	}

	/* start export/import */
	dsync_brain_sync_mailbox_init(brain, box, &local_dsync_box, FALSE);
	if (dsync_brain_sync_mailbox_open(brain, dsync_box) < 0)
		return TRUE;

	brain->state = DSYNC_STATE_SYNC_MAILS;
	return TRUE;
}
Пример #28
0
static int
dsync_brain_try_next_mailbox(struct dsync_brain *brain, struct mailbox **box_r,
			     struct dsync_mailbox *dsync_box_r)
{
	enum mailbox_flags flags = 0;
	struct dsync_mailbox dsync_box;
	struct mailbox *box;
	struct dsync_mailbox_node *node;
	const char *vname = NULL;
	bool synced = FALSE;
	int ret;

	*box_r = NULL;

	while (dsync_mailbox_tree_iter_next(brain->local_tree_iter, &vname, &node)) {
		if (node->existence == DSYNC_MAILBOX_NODE_EXISTS &&
		    !guid_128_is_empty(node->mailbox_guid))
			break;
		vname = NULL;
	}
	if (vname == NULL) {
		/* no more mailboxes */
		dsync_mailbox_tree_iter_deinit(&brain->local_tree_iter);
		return -1;
	}

	if (brain->backup_send) {
		/* make sure mailbox isn't modified */
		flags |= MAILBOX_FLAG_READONLY;
	}
	box = mailbox_alloc(node->ns->list, vname, flags);
	for (;;) {
		if ((ret = dsync_box_get(box, &dsync_box)) <= 0) {
			if (ret < 0)
				brain->failed = TRUE;
			mailbox_free(&box);
			return ret;
		}

		/* if mailbox's last_common_* state equals the current state,
		   we can skip the mailbox */
		if (!dsync_brain_has_mailbox_state_changed(brain, &dsync_box)) {
			mailbox_free(&box);
			return 0;
		}
		if (synced) {
			/* ok, the mailbox really changed */
			break;
		}

		/* mailbox appears to have changed. do a full sync here and get the
		   state again */
		if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
			i_error("Can't sync mailbox %s: %s",
				mailbox_get_vname(box),
				mailbox_get_last_error(box, NULL));
			brain->failed = TRUE;
			mailbox_free(&box);
			return -1;
		}
		synced = TRUE;
	}

	*box_r = box;
	*dsync_box_r = dsync_box;
	return 1;
}
bool dsync_brain_slave_recv_mailbox(struct dsync_brain *brain)
{
	const struct dsync_mailbox *dsync_box;
	struct dsync_mailbox local_dsync_box;
	struct mailbox *box;
	const char *error;
	int ret;

	i_assert(!brain->master_brain);
	i_assert(brain->box == NULL);

	if ((ret = dsync_ibc_recv_mailbox(brain->ibc, &dsync_box)) == 0)
		return FALSE;
	if (ret < 0) {
		brain->state = DSYNC_STATE_DONE;
		return TRUE;
	}

	if (dsync_brain_mailbox_alloc(brain, dsync_box->mailbox_guid,
				      &box, &error) < 0) {
		i_error("Couldn't allocate mailbox GUID %s: %s",
			guid_128_to_string(dsync_box->mailbox_guid), error);
		i_assert(brain->failed);
		return TRUE;
	}
	if (box == NULL) {
		/* mailbox was probably deleted/renamed during sync */
		if (brain->backup_send && brain->no_backup_overwrite) {
			if (brain->debug) {
				i_debug("brain %c: Ignore nonexistent "
					"mailbox GUID %s with -1 sync",
					brain->master_brain ? 'M' : 'S',
					guid_128_to_string(dsync_box->mailbox_guid));
			}
			dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
			return TRUE;
		}
		//FIXME: verify this from log, and if not log an error.
		if (brain->debug) {
			i_debug("brain %c: Change during sync: "
				"Mailbox GUID %s was lost",
				brain->master_brain ? 'M' : 'S',
				guid_128_to_string(dsync_box->mailbox_guid));
		}
		brain->changes_during_sync = TRUE;
		dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
		return TRUE;
	}
	if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
		i_error("Can't sync mailbox %s: %s",
			mailbox_get_vname(box),
			mailbox_get_last_error(box, NULL));
		mailbox_free(&box);
		brain->failed = TRUE;
		return TRUE;
	}

	if ((ret = dsync_box_get(box, &local_dsync_box)) <= 0) {
		mailbox_free(&box);
		if (ret < 0) {
			brain->failed = TRUE;
			return TRUE;
		}
		/* another process just deleted this mailbox? */
		dsync_brain_slave_send_mailbox_lost(brain, dsync_box);
		return TRUE;
	}
	i_assert(local_dsync_box.uid_validity != 0);
	i_assert(memcmp(dsync_box->mailbox_guid, local_dsync_box.mailbox_guid,
			sizeof(dsync_box->mailbox_guid)) == 0);
	dsync_ibc_send_mailbox(brain->ibc, &local_dsync_box);

	dsync_brain_mailbox_update_pre(brain, box, &local_dsync_box, dsync_box);

	if (!dsync_boxes_need_sync(brain, &local_dsync_box, dsync_box)) {
		/* no fields appear to have changed, skip this mailbox */
		mailbox_free(&box);
		return TRUE;
	}

	/* start export/import */
	dsync_brain_sync_mailbox_init(brain, box, &local_dsync_box, FALSE);
	if (dsync_brain_sync_mailbox_open(brain, dsync_box) < 0)
		return TRUE;

	brain->state = DSYNC_STATE_SYNC_MAILS;
	return TRUE;
}
Пример #30
0
static int
mail_crypt_mail_save_begin(struct mail_save_context *ctx,
			   struct istream *input)
{
	const char *pubid;
	struct mailbox *box = ctx->transaction->box;
	struct mail_crypt_mailbox *mbox = MAIL_CRYPT_CONTEXT(box);
	struct mail_crypt_user *muser =
		MAIL_CRYPT_USER_CONTEXT(box->storage->user);
	i_assert(muser != NULL);

	enum io_stream_encrypt_flags enc_flags;
	if (muser->save_version == 1) {
		enc_flags = IO_STREAM_ENC_VERSION_1;
	} else if (muser->save_version == 2) {
		enc_flags = IO_STREAM_ENC_INTEGRITY_AEAD;
	} else {
		i_assert(muser->save_version == 0);
		i_panic("mail_crypt_mail_save_begin not supposed to be called"
				"when mail_crypt_save_version is 0");
	}

	if (mbox->module_ctx.super.save_begin(ctx, input) < 0)
		return -1;

	struct dcrypt_public_key *pub_key;
	if (muser->global_keys.public_key != NULL)
		pub_key = muser->global_keys.public_key;
	else if (mbox->pub_key != NULL)
		pub_key = mbox->pub_key;
	else {
		const char *error;
		int ret;

		if ((ret = mail_crypt_box_get_public_key(box, &pub_key,
							 &error)) <= 0)
		{
			struct dcrypt_keypair pair;

			if (ret < 0) {
				mail_storage_set_error(box->storage,
					MAIL_ERROR_PARAMS,
					t_strdup_printf("get_public_key(%s) failed: %s",
							mailbox_get_vname(box),
							error));
				return ret;
			}

			if (muser->save_version < 2) {
				mail_storage_set_error(box->storage,
                                        MAIL_ERROR_PARAMS,
                                        t_strdup_printf("generate_keypair(%s) failed: "
                                                        "unsupported save_version=%d",
                                                        mailbox_get_vname(box),
                                                        muser->save_version));
                                return -1;
			}

			if (mail_crypt_box_generate_keypair(box, &pair, NULL,
							    &pubid, &error) < 0) {
				mail_storage_set_error(box->storage,
					MAIL_ERROR_PARAMS,
					t_strdup_printf("generate_keypair(%s) failed: %s",
							mailbox_get_vname(box),
							error));
				return -1;
			}
			pub_key = pair.pub;
			dcrypt_key_unref_private(&pair.priv);

		}
		mbox->pub_key = pub_key;
	}

	/* encryption is the outermost layer (zlib etc. are inside) */
	struct ostream *output = o_stream_create_encrypt(ctx->data.output,
			MAIL_CRYPT_ENC_ALGORITHM, pub_key, enc_flags);

	o_stream_unref(&ctx->data.output);
	ctx->data.output = output;
	o_stream_cork(ctx->data.output);
	return 0;
}