static void
fts_backend_solr_update_set_mailbox(struct fts_backend_update_context *_ctx,
				    struct mailbox *box)
{
	struct solr_fts_backend_update_context *ctx =
		(struct solr_fts_backend_update_context *)_ctx;
	struct mailbox_status status;
	struct mail_namespace *ns;

	if (ctx->prev_uid != 0) {
		fts_index_set_last_uid(ctx->cur_box, ctx->prev_uid);
		ctx->prev_uid = 0;
	}

	ctx->cur_box = box;
	ctx->uid_validity = 0;
	i_free_and_null(ctx->id_box_name);

	if (box != NULL) {
		ctx->id_box_name = i_strdup(fts_box_get_root(box, &ns));

		mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status);
		ctx->uid_validity = status.uidvalidity;
	}
}
Esempio n. 2
0
int fts_indexer_init(struct fts_backend *backend, struct mailbox *box,
		     struct fts_indexer_context **ctx_r)
{
	struct fts_indexer_context *ctx;
	struct mailbox_status status;
	uint32_t last_uid, seq1, seq2;
	const char *path, *cmd, *value, *error;
	int fd;

	if (fts_backend_get_last_uid(backend, box, &last_uid) < 0)
		return -1;

	mailbox_get_open_status(box, STATUS_UIDNEXT, &status);
	if (status.uidnext == last_uid+1) {
		/* everything is already indexed */
		return 0;
	}

	mailbox_get_seq_range(box, last_uid+1, (uint32_t)-1, &seq1, &seq2);
	if (seq1 == 0) {
		/* no new messages (last messages in mailbox were expunged) */
		return 0;
	}

	cmd = t_strdup_printf("PREPEND\t1\t%s\t%s\t0\t%s\n",
			      str_tabescape(box->storage->user->username),
			      str_tabescape(box->vname),
			      str_tabescape(box->storage->user->session_id));
	fd = fts_indexer_cmd(box->storage->user, cmd, &path);
	if (fd == -1)
		return -1;

	/* connect to indexer and request immediate indexing of the mailbox */
	ctx = i_new(struct fts_indexer_context, 1);
	ctx->box = box;
	ctx->path = i_strdup(path);
	ctx->fd = fd;
	ctx->input = i_stream_create_fd(fd, 128, FALSE);
	ctx->search_start_time = ioloop_timeval;

	value = mail_user_plugin_getenv(box->storage->user, "fts_index_timeout");
	if (value != NULL) {
		if (settings_get_time(value, &ctx->timeout_secs, &error) < 0)
			i_error("Invalid fts_index_timeout setting: %s", error);
	}


	*ctx_r = ctx;
	return 1;
}
static int
fts_backend_solr_get_last_uid_fallback(struct solr_fts_backend *backend,
				       struct mailbox *box,
				       uint32_t *last_uid_r)
{
	struct mail_namespace *ns;
	struct mailbox_status status;
	struct solr_result **results;
	const struct seq_range *uidvals;
	const char *box_name;
	unsigned int count;
	string_t *str;
	pool_t pool;
	int ret = 0;

	str = t_str_new(256);
	str_append(str, "fl=uid&rows=1&sort=uid+desc&q=");

	box_name = fts_box_get_root(box, &ns);

	mailbox_get_open_status(box, STATUS_UIDVALIDITY, &status);
	str_printfa(str, "uidv:%u+AND+box:", status.uidvalidity);
	solr_quote_http(str, box_name);
	solr_add_ns_query_http(str, backend, ns);
	str_append(str, "+AND+user:"******"solr last uid lookup", 1024);
	if (solr_connection_select(backend->solr_conn, str_c(str),
				   pool, &results) < 0)
		ret = -1;
	else if (results[0] == NULL) {
		/* no UIDs */
		*last_uid_r = 0;
	} else {
		uidvals = array_get(&results[0]->uids, &count);
		i_assert(count > 0);
		if (count == 1 && uidvals[0].seq1 == uidvals[0].seq2) {
			*last_uid_r = uidvals[0].seq1;
		} else {
			i_error("fts_solr: Last UID lookup returned multiple rows");
			ret = -1;
		}
	}
	pool_unref(&pool);
	return ret;
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
void client_send_mailbox_flags(struct client *client, bool selecting)
{
	struct mailbox_status status;
	unsigned int count = array_count(client->keywords.names);
	const char *const *keywords;
	string_t *str;

	if (!selecting && count == client->keywords.announce_count) {
		/* no changes to keywords and we're not selecting a mailbox */
		return;
	}

	client->keywords.announce_count = count;
	mailbox_get_open_status(client->mailbox, STATUS_PERMANENT_FLAGS,
				&status);

	keywords = count == 0 ? NULL :
		array_idx(client->keywords.names, 0);
	str = t_str_new(128);
	str_append(str, "* FLAGS (");
	imap_write_flags(str, MAIL_FLAGS_NONRECENT, keywords);
	str_append_c(str, ')');
	client_send_line(client, str_c(str));

	if (!status.permanent_keywords)
		keywords = NULL;

	str_truncate(str, 0);
	str_append(str, "* OK [PERMANENTFLAGS (");
	imap_write_flags(str, status.permanent_flags, keywords);
	if (status.allow_new_keywords) {
		if (status.permanent_flags != 0 || keywords != NULL)
			str_append_c(str, ' ');
		str_append(str, "\\*");
	}
	str_append(str, ")] ");

	if (mailbox_is_readonly(client->mailbox))
		str_append(str, "Read-only mailbox.");
	else
		str_append(str, "Flags permitted.");
	client_send_line(client, str_c(str));
}
Esempio n. 6
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;
}
static int
get_metadata_virtual_size(struct mailbox *box,
			  struct mailbox_metadata *metadata_r)
{
	struct index_mailbox_context *ibox = INDEX_STORAGE_CONTEXT(box);
	struct index_vsize_header vsize_hdr;
	struct mailbox_status status;
	const void *data;
	size_t size;
	int ret;

	mailbox_get_open_status(box, STATUS_MESSAGES | STATUS_UIDNEXT, &status);
	mail_index_get_header_ext(box->view, ibox->vsize_hdr_ext_id,
				  &data, &size);
	if (size == sizeof(vsize_hdr))
		memcpy(&vsize_hdr, data, sizeof(vsize_hdr));
	else {
		if (size != 0) {
			mail_storage_set_critical(box->storage,
				"vsize-hdr has invalid size: %"PRIuSIZE_T,
				size);
		}
		memset(&vsize_hdr, 0, sizeof(vsize_hdr));
	}

	if (vsize_hdr.highest_uid + 1 == status.uidnext &&
	    vsize_hdr.message_count == status.messages) {
		/* up to date */
		metadata_r->virtual_size = vsize_hdr.vsize;
		return 0;
	}
	if (vsize_hdr.highest_uid >= status.uidnext) {
		mail_storage_set_critical(box->storage,
			"vsize-hdr has invalid highest-uid (%u >= %u)",
			vsize_hdr.highest_uid, status.uidnext);
		memset(&vsize_hdr, 0, sizeof(vsize_hdr));
	}
	ret = virtual_size_add_new(box, &vsize_hdr);
	metadata_r->virtual_size = vsize_hdr.vsize;
	return ret;
}
Esempio n. 8
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;
}
Esempio n. 9
0
static int
index_mailbox(struct master_connection *conn, struct mail_user *user,
	      const char *mailbox, unsigned int max_recent_msgs,
	      const char *what)
{
	struct mail_namespace *ns;
	struct mailbox *box;
	struct mailbox_status status;
	const char *path, *errstr;
	enum mail_error error;
	enum mailbox_sync_flags sync_flags = MAILBOX_SYNC_FLAG_FULL_READ;
	int ret;

	ns = mail_namespace_find(user->namespaces, mailbox);
	box = mailbox_alloc(ns->list, mailbox, 0);
	mailbox_set_reason(box, "indexing");
	ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_INDEX, &path);
	if (ret < 0) {
		i_error("Getting path to mailbox %s failed: %s",
			mailbox, mailbox_get_last_internal_error(box, NULL));
		mailbox_free(&box);
		return -1;
	}
	if (ret == 0) {
		i_info("Indexes disabled for mailbox %s, skipping", mailbox);
		mailbox_free(&box);
		return 0;
	}
	ret = 0;

	if (max_recent_msgs != 0) {
		/* index only if there aren't too many recent messages.
		   don't bother syncing the mailbox, that alone can take a
		   while with large maildirs. */
		if (mailbox_open(box) < 0) {
			i_error("Opening mailbox %s failed: %s", mailbox,
				mailbox_get_last_internal_error(box, NULL));
			ret = -1;
		} else {
			mailbox_get_open_status(box, STATUS_RECENT, &status);
		}
		if (ret < 0 || status.recent > max_recent_msgs) {
			mailbox_free(&box);
			return ret;
		}
	}

	if (strchr(what, 'o') != NULL)
		sync_flags |= MAILBOX_SYNC_FLAG_OPTIMIZE;

	if (mailbox_sync(box, sync_flags) < 0) {
		errstr = mailbox_get_last_internal_error(box, &error);
		if (error != MAIL_ERROR_NOTFOUND) {
			i_error("Syncing mailbox %s failed: %s",
				mailbox, errstr);
		} else if (user->mail_debug) {
			i_debug("Syncing mailbox %s failed: %s",
				mailbox, errstr);
		}
		ret = -1;
	} else if (strchr(what, 'i') != NULL) {
		if (index_mailbox_precache(conn, box) < 0)
			ret = -1;
	}
	mailbox_free(&box);
	return ret;
}