Example #1
0
static int
dbox_get_cached_metadata(struct dbox_mail *mail, enum dbox_metadata_key key,
			 enum index_cache_field cache_field,
			 const char **value_r)
{
	struct index_mail *imail = &mail->imail;
	struct index_mailbox_context *ibox =
		INDEX_STORAGE_CONTEXT(imail->mail.mail.box);
	const char *value;
	string_t *str;
	uint32_t order;

	str = str_new(imail->mail.data_pool, 64);
	if (mail_cache_lookup_field(imail->mail.mail.transaction->cache_view,
				    str, imail->mail.mail.seq,
				    ibox->cache_fields[cache_field].idx) > 0) {
		if (cache_field == MAIL_CACHE_POP3_ORDER) {
			i_assert(str_len(str) == sizeof(order));
			memcpy(&order, str_data(str), sizeof(order));
			str_truncate(str, 0);
			if (order != 0)
				str_printfa(str, "%u", order);
			else {
				/* order=0 means it doesn't exist. we don't
				   want to return "0" though, because then the
				   mails get ordered to beginning, while
				   nonexistent are supposed to be ordered at
				   the end. */
			}
		}
		*value_r = str_c(str);
		return 0;
	}

	if (dbox_mail_metadata_get(mail, key, &value) < 0)
		return -1;

	if (value == NULL)
		value = "";
	if (cache_field != MAIL_CACHE_POP3_ORDER) {
		index_mail_cache_add_idx(imail, ibox->cache_fields[cache_field].idx,
					 value, strlen(value)+1);
	} else {
		if (str_to_uint(value, &order) < 0)
			order = 0;
		index_mail_cache_add_idx(imail, ibox->cache_fields[cache_field].idx,
					 &order, sizeof(order));
	}

	/* don't return pointer to dbox metadata directly, since it may
	   change unexpectedly */
	str_truncate(str, 0);
	str_append(str, value);
	*value_r = str_c(str);
	return 0;
}
Example #2
0
static int imapc_mail_get_guid(struct mail *_mail, const char **value_r)
{
	struct index_mail *imail = (struct index_mail *)_mail;
	struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
	const enum index_cache_field cache_idx =
		imail->ibox->cache_fields[MAIL_CACHE_GUID].idx;

	if (imapc_mail_get_cached_guid(_mail)) {
		*value_r = imail->data.guid;
		return 0;
	}

	/* GUID not in cache, fetch it */
	if (mbox->guid_fetch_field_name != NULL) {
		if (imapc_mail_fetch(_mail, MAIL_FETCH_GUID, NULL) < 0)
			return -1;
		if (imail->data.guid == NULL) {
			(void)imapc_mail_failed(_mail, mbox->guid_fetch_field_name);
			return -1;
		}
	} else {
		/* use hash of message headers as the GUID */
		if (imapc_mail_get_hdr_hash(imail) < 0)
			return -1;
	}

	index_mail_cache_add_idx(imail, cache_idx,
				 imail->data.guid, strlen(imail->data.guid)+1);
	*value_r = imail->data.guid;
	return 0;
}
Example #3
0
static bool imapc_mail_get_cached_guid(struct mail *_mail)
{
	struct index_mail *imail = (struct index_mail *)_mail;
	const enum index_cache_field cache_idx =
		imail->ibox->cache_fields[MAIL_CACHE_GUID].idx;
	string_t *str;

	if (imail->data.guid != NULL) {
		if (mail_cache_field_can_add(_mail->transaction->cache_trans,
					     _mail->seq, cache_idx)) {
			/* GUID was prefetched - add to cache */
			index_mail_cache_add_idx(imail, cache_idx,
				imail->data.guid, strlen(imail->data.guid)+1);
		}
		return TRUE;
	}

	str = str_new(imail->mail.data_pool, 64);
	if (mail_cache_lookup_field(_mail->transaction->cache_view,
				    str, imail->mail.mail.seq, cache_idx) > 0) {
		imail->data.guid = str_c(str);
		return TRUE;
	}
	return FALSE;
}
Example #4
0
static void index_mail_body_parsed_cache_flags(struct index_mail *mail)
{
	struct index_mail_data *data = &mail->data;
	unsigned int cache_flags_idx;
	uint32_t cache_flags = data->cache_flags;
	bool want_cached;

	cache_flags_idx = mail->ibox->cache_fields[MAIL_CACHE_FLAGS].idx;
	want_cached = mail_cache_field_want_add(mail->trans->cache_trans,
						data->seq, cache_flags_idx);

	if (data->parsed_bodystructure &&
	    imap_bodystructure_is_plain_7bit(data->parts) &&
	    (want_cached || want_plain_bodystructure_cached(mail))) {
		cache_flags |= MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII;
		/* we need message_parts cached to be able to
		   actually use it in BODY/BODYSTRUCTURE reply */
		want_cached = TRUE;
		data->save_message_parts = TRUE;
	}

	/* cache flags should never get unset as long as the message doesn't
	   change, but try to handle it anyway */
	cache_flags &= ~(MAIL_CACHE_FLAG_BINARY_HEADER |
			 MAIL_CACHE_FLAG_BINARY_BODY |
			 MAIL_CACHE_FLAG_HAS_NULS |
			 MAIL_CACHE_FLAG_HAS_NO_NULS);
	if ((data->parts->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) {
		mail->mail.mail.has_nuls = TRUE;
		mail->mail.mail.has_no_nuls = FALSE;
		cache_flags |= MAIL_CACHE_FLAG_HAS_NULS;
	} else {
		mail->mail.mail.has_nuls = FALSE;
		mail->mail.mail.has_no_nuls = TRUE;
		cache_flags |= MAIL_CACHE_FLAG_HAS_NO_NULS;
	}

	if (data->hdr_size.virtual_size == data->hdr_size.physical_size)
		cache_flags |= MAIL_CACHE_FLAG_BINARY_HEADER;
	if (data->body_size.virtual_size == data->body_size.physical_size)
		cache_flags |= MAIL_CACHE_FLAG_BINARY_BODY;

	if (cache_flags != data->cache_flags && want_cached) {
		index_mail_cache_add_idx(mail, cache_flags_idx,
					 &cache_flags, sizeof(cache_flags));
	}
	data->cache_flags = cache_flags;
}
static void index_mail_parse_finish_imap_envelope(struct index_mail *mail)
{
	struct mail *_mail = &mail->mail.mail;
	const unsigned int cache_field_envelope =
		mail->ibox->cache_fields[MAIL_CACHE_IMAP_ENVELOPE].idx;
	string_t *str;

	str = str_new(mail->mail.data_pool, 256);
	imap_envelope_write_part_data(mail->data.envelope_data, str);
	mail->data.envelope = str_c(str);

	if (mail_cache_field_can_add(_mail->transaction->cache_trans,
				     _mail->seq, cache_field_envelope)) {
		index_mail_cache_add_idx(mail, cache_field_envelope,
					 str_data(str), str_len(str));
	}
}
Example #6
0
static void pop3c_mail_cache_size(struct index_mail *mail)
{
	struct mail *_mail = &mail->mail.mail;
	uoff_t size;
	unsigned int cache_idx;

	if (i_stream_get_size(mail->data.stream, TRUE, &size) <= 0)
		return;
	mail->data.virtual_size = size;

	cache_idx = mail->ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
	if (mail_cache_field_exists(_mail->transaction->cache_view,
				    _mail->seq, cache_idx) == 0) {
		index_mail_cache_add_idx(mail, cache_idx, &size, sizeof(size));
		/* make sure it's not cached twice */
		mail->data.dont_cache_fetch_fields |=
			MAIL_CACHE_VIRTUAL_FULL_SIZE;
	}
}
Example #7
0
static int imapc_mail_get_guid(struct mail *_mail, const char **value_r)
{
	struct index_mail *imail = (struct index_mail *)_mail;
	struct imapc_mailbox *mbox = (struct imapc_mailbox *)_mail->box;
	const enum index_cache_field cache_idx =
		imail->ibox->cache_fields[MAIL_CACHE_GUID].idx;
	string_t *str;

	if (imail->data.guid != NULL) {
		*value_r = imail->data.guid;
		return 0;
	}

	str = str_new(imail->mail.data_pool, 64);
	if (mail_cache_lookup_field(_mail->transaction->cache_view,
				    str, imail->mail.mail.seq, cache_idx) > 0) {
		*value_r = str_c(str);
		return 0;
	}

	/* GUID not in cache, fetch it */
	if (mbox->guid_fetch_field_name != NULL) {
		if (imapc_mail_fetch(_mail, MAIL_FETCH_GUID) < 0)
			return -1;
		if (imail->data.guid == NULL) {
			(void)imapc_mail_failed(_mail, mbox->guid_fetch_field_name);
			return -1;
		}
	} else {
		/* use hash of message headers as the GUID */
		if (imapc_mail_get_hdr_hash(imail) < 0)
			return -1;
	}

	index_mail_cache_add_idx(imail, cache_idx,
				 imail->data.guid, strlen(imail->data.guid)+1);
	*value_r = imail->data.guid;
	return 0;
}
Example #8
0
static void index_mail_body_parsed_cache_message_parts(struct index_mail *mail)
{
	struct index_mail_data *data = &mail->data;
	unsigned int cache_field =
		mail->ibox->cache_fields[MAIL_CACHE_MESSAGE_PARTS].idx;
	enum mail_cache_decision_type decision;
	buffer_t *buffer;

	if (data->messageparts_saved_to_cache ||
	    mail_cache_field_exists(mail->trans->cache_view, mail->data.seq,
				    cache_field) != 0) {
		/* already cached */
		return;
	}

	decision = mail_cache_field_get_decision(mail->mail.mail.box->cache,
						 cache_field);
	if (decision == (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED)) {
		/* we never want it cached */
		return;
	}
	if (decision == MAIL_CACHE_DECISION_NO &&
	    !data->save_message_parts &&
	    (mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) == 0) {
		/* we didn't really care about the message parts themselves,
		   just wanted to use something that depended on it */
		return;
	}

	T_BEGIN {
		buffer = buffer_create_dynamic(pool_datastack_create(), 1024);
		message_part_serialize(mail->data.parts, buffer);
		index_mail_cache_add_idx(mail, cache_field,
					 buffer->data, buffer->used);
	} T_END;

	data->messageparts_saved_to_cache = TRUE;
}
static void index_mail_parse_header_finish(struct index_mail *mail)
{
	struct mail *_mail = &mail->mail.mail;
	const struct index_mail_line *lines;
	const unsigned char *header, *data;
	const uint8_t *match;
	buffer_t *buf;
	size_t data_size;
	unsigned int i, j, count, match_idx, match_count;
	bool noncontiguous;

	/* sort it first so fields are grouped together and ordered by
	   line number */
	array_sort(&mail->header_lines, header_line_cmp);

	lines = array_get(&mail->header_lines, &count);
	match = array_get(&mail->header_match, &match_count);
	header = buffer_get_data(mail->header_data, NULL);
	buf = buffer_create_dynamic(pool_datastack_create(), 256);

	/* go through all the header lines we found */
	for (i = match_idx = 0; i < count; i = j) {
		/* matches and header lines are both sorted, all matches
		   until lines[i] weren't found */
		while (match_idx < lines[i].field_idx &&
		       match_idx < match_count) {
			if (HEADER_MATCH_USABLE(mail, match[match_idx]) &&
			    mail_cache_field_can_add(_mail->transaction->cache_trans,
						     _mail->seq, match_idx)) {
				/* this header doesn't exist. remember that. */
				i_assert((match[match_idx] &
					  HEADER_MATCH_FLAG_FOUND) == 0);
				index_mail_cache_add_idx(mail, match_idx,
							 "", 0);
			}
			match_idx++;
		}

		if (match_idx < match_count) {
			/* save index to first header line */
			j = i + 1;
			array_idx_set(&mail->header_match_lines, match_idx, &j);
			match_idx++;
		}

		if (!mail_cache_field_can_add(_mail->transaction->cache_trans,
					      _mail->seq, lines[i].field_idx)) {
			/* header is already cached */
			j = i + 1;
			continue;
		}

		/* buffer contains: { uint32_t line_num[], 0, header texts }
		   noncontiguous is just a small optimization.. */
		buffer_set_used_size(buf, 0);
		buffer_append(buf, &lines[i].line_num,
			      sizeof(lines[i].line_num));

		noncontiguous = FALSE;
		for (j = i+1; j < count; j++) {
			if (lines[j].field_idx != lines[i].field_idx)
				break;

			if (lines[j].start_pos != lines[j-1].end_pos)
				noncontiguous = TRUE;
			buffer_append(buf, &lines[j].line_num,
				      sizeof(lines[j].line_num));
		}
		buffer_append_zero(buf, sizeof(uint32_t));

		if (noncontiguous) {
			for (; i < j; i++) {
				buffer_append(buf, header + lines[i].start_pos,
					      lines[i].end_pos -
					      lines[i].start_pos);
			}
			i--;
		} else {
			buffer_append(buf, header + lines[i].start_pos,
				      lines[j-1].end_pos - lines[i].start_pos);
		}

		data = buffer_get_data(buf, &data_size);
		index_mail_cache_add_idx(mail, lines[i].field_idx,
					 data, data_size);
	}

	for (; match_idx < match_count; match_idx++) {
		if (HEADER_MATCH_USABLE(mail, match[match_idx]) &&
		    mail_cache_field_can_add(_mail->transaction->cache_trans,
					     _mail->seq, match_idx)) {
			/* this header doesn't exist. remember that. */
			i_assert((match[match_idx] &
				  HEADER_MATCH_FLAG_FOUND) == 0);
			index_mail_cache_add_idx(mail, match_idx, "", 0);
		}
	}

	mail->data.dont_cache_field_idx = UINT_MAX;
}
Example #10
0
void index_mail_cache_add(struct index_mail *mail, enum index_cache_field field,
			  const void *data, size_t data_size)
{
	index_mail_cache_add_idx(mail, mail->ibox->cache_fields[field].idx,
				 data, data_size);
}