changeset 3248:ff47e78ad717 HEAD

Renamed mail_get_header() to mail_get_first_header() and mail_gets_headers() to mail_get_header_stream(). Added new mail_get_headers() which returns NULL-terminated string list of all found headers.
author Timo Sirainen <tss@iki.fi>
date Tue, 29 Mar 2005 19:48:42 +0300
parents e7166e2f8b9b
children c913cf1dfb08
files src/imap/imap-sort.c src/imap/imap-thread.c src/lib-storage/index/index-mail-headers.c src/lib-storage/index/index-mail.c src/lib-storage/index/index-mail.h src/lib-storage/index/index-search.c src/lib-storage/index/maildir/maildir-mail.c src/lib-storage/index/mbox/mbox-mail.c src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.h src/lib-storage/mail.c
diffstat 11 files changed, 124 insertions(+), 76 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/imap-sort.c	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/imap/imap-sort.c	Tue Mar 29 19:48:42 2005 +0300
@@ -290,7 +290,7 @@
 	struct message_address *addr;
 	const char *str;
 
-	str = mail_get_header(mail, field);
+	str = mail_get_first_header(mail, field);
 	if (str == NULL)
 		return NULL;
 
@@ -356,7 +356,7 @@
 	}
 
 	if (ctx->common_mask & MAIL_SORT_SUBJECT) {
-		str = mail_get_header(mail, "subject");
+		str = mail_get_first_header(mail, "subject");
 		if (str != NULL) {
 			str = imap_get_base_subject_cased(
 				pool_datastack_create(), str, NULL);
@@ -475,7 +475,7 @@
 		if (ctx->common_mask & MAIL_SORT_SUBJECT)
 			str = ctx->last_subject;
 		else {
-			str = mail_get_header(mail, "subject");
+			str = mail_get_first_header(mail, "subject");
 
 			if (str != NULL) {
 				str = imap_get_base_subject_cased(
@@ -580,7 +580,7 @@
 
 		switch (type) {
 		case MAIL_SORT_SUBJECT:
-			str = mail_get_header(mail, "subject");
+			str = mail_get_first_header(mail, "subject");
 			if (str == NULL)
 				return NULL;
 
--- a/src/imap/imap-thread.c	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/imap/imap-thread.c	Tue Mar 29 19:48:42 2005 +0300
@@ -448,14 +448,14 @@
 	if (sent_date == (time_t)-1)
 		sent_date = 0;
 
-	message_id = mail_get_header(mail, "message-id");
+	message_id = mail_get_first_header(mail, "message-id");
 	node = update_message(ctx, get_msgid(&message_id), sent_date,
 			      ctx->id_is_uid ? mail->uid : mail->seq);
 
 	/* link references */
-	references = mail_get_header(mail, "references");
+	references = mail_get_first_header(mail, "references");
 	if (!link_references(ctx, node, references)) {
-		in_reply_to = mail_get_header(mail, "in-reply-to");
+		in_reply_to = mail_get_first_header(mail, "in-reply-to");
 		refid = in_reply_to == NULL ? NULL : get_msgid(&in_reply_to);
 
 		if (refid != NULL)
@@ -693,7 +693,7 @@
 
 		if (seq != 0 && mail_set_seq(ctx->mail, seq) == 0) {
 			t_push();
-                        subject = mail_get_header(ctx->mail, "subject");
+                        subject = mail_get_first_header(ctx->mail, "subject");
 			add_base_subject(ctx, subject, node);
 			t_pop();
 		}
--- a/src/lib-storage/index/index-mail-headers.c	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/lib-storage/index/index-mail-headers.c	Tue Mar 29 19:48:42 2005 +0300
@@ -35,7 +35,6 @@
 
 static void index_mail_parse_header_finish(struct index_mail *mail)
 {
-	static uint32_t null = 0;
 	struct index_mail_line *lines;
 	const unsigned char *header, *data;
 	const uint8_t *match;
@@ -56,21 +55,35 @@
 	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 match[] doesn't have header_match_value,
+			   it belongs to some older header parsing and we
+			   just want to ignore it. */
+			i_assert(match[match_idx] !=
+				 mail->header_match_value + 1);
 			if (match[match_idx] == mail->header_match_value) {
 				/* this header doesn't exist. remember that. */
-				array_idx_set(&mail->header_offsets,
-					      match_idx, &null);
 				mail_cache_add(mail->trans->cache_trans,
 					       mail->data.seq, match_idx,
 					       NULL, 0);
 			}
 			match_idx++;
 		}
-		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++;
+		}
+
+		/* 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));
@@ -85,7 +98,7 @@
 			buffer_append(buf, &lines[j].line_num,
 				      sizeof(lines[j].line_num));
 		}
-		buffer_append(buf, &null, sizeof(uint32_t));
+		buffer_append_zero(buf, sizeof(uint32_t));
 
 		if (noncontiguous) {
 			for (; i < j; i++) {
@@ -128,19 +141,18 @@
 		ARRAY_CREATE(&mail->header_lines, default_pool,
 			     struct index_mail_line, 32);
 		ARRAY_CREATE(&mail->header_match, default_pool, uint8_t, 32);
-		ARRAY_CREATE(&mail->header_offsets, default_pool,
-			     uint32_t, 32);
+		ARRAY_CREATE(&mail->header_match_lines, default_pool,
+			     unsigned int, 32);
 	} else {
 		buffer_set_used_size(mail->header_data, 0);
 		array_clear(&mail->header_lines);
-		array_clear(&mail->header_offsets);
+		array_clear(&mail->header_match_lines);
 	}
 
         mail->header_match_value += 2;
 	if (mail->header_match_value == 0) {
 		/* @UNSAFE: wrapped, we'll have to clear the buffer */
-		memset(array_modifyable_idx(&mail->header_match, 0), 0,
-		       array_count(&mail->header_match));
+		array_clear(&mail->header_match);
 		mail->header_match_value = 2;
 	}
 
@@ -181,7 +193,7 @@
 	const char *cache_field_name;
 	unsigned int field_idx, count;
 	uint8_t *match;
-	int timezone, first_hdr = FALSE;
+	int timezone;
 
         data->parse_line_num++;
 
@@ -265,7 +277,6 @@
 	match = array_get_modifyable(&mail->header_match, &count);
 	if (field_idx < count && match[field_idx] == mail->header_match_value) {
 		/* first header */
-		first_hdr = TRUE;
 		match[field_idx]++;
 	} else if (!data->parse_line.cache &&
 		   (field_idx >= count ||
@@ -279,12 +290,6 @@
 		data->parse_line.line_num = data->parse_line_num;
 		str_append(mail->header_data, hdr->name);
 		str_append_n(mail->header_data, hdr->middle, hdr->middle_len);
-
-		if (first_hdr) {
-			/* save the offset to first header */
-			uint32_t pos = str_len(mail->header_data);
-			array_idx_set(&mail->header_offsets, field_idx, &pos);
-		}
 	}
 	str_append_n(mail->header_data, hdr->value, hdr->value_len);
 	if (!hdr->no_newline)
@@ -354,7 +359,7 @@
 	mail->data.save_envelope = TRUE;
 	header_ctx = mailbox_header_lookup_init(&mail->ibox->box,
 						imap_envelope_headers);
-	stream = mail_get_headers(&mail->mail.mail, header_ctx);
+	stream = mail_get_header_stream(&mail->mail.mail, header_ctx);
 	if (mail->data.envelope == NULL && stream != NULL) {
 		/* we got the headers from cache - parse them to get the
 		   envelope */
@@ -422,32 +427,49 @@
 	return -1;
 }
 
-static const char *
+static const char *const *
 index_mail_get_parsed_header(struct index_mail *mail, unsigned int field_idx)
 {
-	const unsigned char *data;
-	const uint32_t *offsets;
-	unsigned int count;
-	size_t size;
+	array_t ARRAY_DEFINE(header_values, const char *);
+        const struct index_mail_line *lines;
+	const unsigned char *header;
+	const unsigned int *line_idx;
+	const char *value;
+	unsigned int i, lines_count, first_line_idx;
+
+	line_idx = array_idx(&mail->header_match_lines, field_idx);
+	i_assert(*line_idx != 0);
+	first_line_idx = *line_idx - 1;
+
+	ARRAY_CREATE(&header_values, mail->data_pool, const char *, 4);
+	header = buffer_get_data(mail->header_data, NULL);
 
-	offsets = array_get(&mail->header_offsets, &count);
-	i_assert(field_idx <= count && offsets[field_idx] != 0);
+	lines = array_get(&mail->header_lines, &lines_count);
+	for (i = first_line_idx; i < lines_count; i++) {
+		if (lines[i].field_idx != lines[first_line_idx].field_idx)
+			break;
 
-	data = buffer_get_data(mail->header_data, &size);
-        size = get_header_size(mail->header_data, offsets[field_idx]);
-	return p_strndup(mail->data_pool, data + offsets[field_idx], size);
+		value = p_strndup(mail->data_pool, header + lines[i].start_pos,
+				  lines[i].end_pos - lines[i].start_pos);
+		array_append(&header_values, &value, 1);
+	}
+
+	value = NULL;
+	array_append(&header_values, &value, sizeof(value));
+	return array_idx(&header_values, 0);
 }
 
-const char *index_mail_get_header(struct mail *_mail, const char *field)
+const char *const *index_mail_get_headers(struct mail *_mail, const char *field)
 {
 	struct index_mail *mail = (struct index_mail *)_mail;
-	const char *headers[2];
+	const char *headers[2], *value;
 	struct mailbox_header_lookup_ctx *headers_ctx;
-	const unsigned char *data;
+	unsigned char *data;
 	unsigned int field_idx;
 	string_t *dest;
 	size_t i, len;
 	int ret;
+	array_t ARRAY_DEFINE(header_values, const char *);
 
 	field_idx = get_header_field_idx(mail->ibox, field);
 
@@ -479,26 +501,40 @@
 		return ret == 0 ? NULL :
 			index_mail_get_parsed_header(mail, field_idx);
 	}
+	data = buffer_get_modifyable_data(dest, &len);
 
-	if (str_len(dest) == 0) {
+	if (len == 0) {
 		/* cached as non-existing. */
-		return NULL;
+		return p_new(mail->data_pool, const char *, 1);
 	}
 
-	/* cached. skip "header name: " in dest. */
-	data = str_data(dest);
-	len = str_len(dest);
+	ARRAY_CREATE(&header_values, mail->data_pool, const char *, 4);
+
+	/* cached. skip "header name: " parts in dest. */
 	for (i = 0; i < len; i++) {
 		if (data[i] == ':') {
 			if (i+1 != len && data[++i] == ' ') i++;
-			break;
+
+			/* @UNSAFE */
+			len = get_header_size(dest, i);
+			data[i + len] = '\0';
+			value = (const char *)data + i;
+			i += len + 1;
+
+			array_append(&header_values, &value, sizeof(value));
 		}
 	}
 
-	/* return only the first field in case there's multiple. */
-        len = get_header_size(dest, i);
-	buffer_set_used_size(dest, i + len);
-	return str_c(dest) + i;
+	value = NULL;
+	array_append(&header_values, &value, sizeof(value));
+	return array_idx(&header_values, 0);
+}
+
+const char *index_mail_get_first_header(struct mail *mail, const char *field)
+{
+	const char *const *list = index_mail_get_headers(mail, field);
+
+	return list == NULL ? NULL : list[0];
 }
 
 static void header_cache_callback(struct message_header_line *hdr,
@@ -513,8 +549,8 @@
 }
 
 struct istream *
-index_mail_get_headers(struct mail *_mail,
-		       struct mailbox_header_lookup_ctx *_headers)
+index_mail_get_header_stream(struct mail *_mail,
+			     struct mailbox_header_lookup_ctx *_headers)
 {
 	struct index_mail *mail = (struct index_mail *)_mail;
 	struct index_header_lookup_ctx *headers =
--- a/src/lib-storage/index/index-mail.c	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/lib-storage/index/index-mail.c	Tue Mar 29 19:48:42 2005 +0300
@@ -240,7 +240,7 @@
 
 	if (data->sent_date.time == (time_t)-1) {
 		data->save_sent_date = TRUE;
-		str = mail_get_header(_mail, "Date");
+		str = mail_get_first_header(_mail, "Date");
 		if (data->sent_date.time == (time_t)-1) {
 			if (!message_date_parse((const unsigned char *)str,
 						(size_t)-1,
@@ -763,8 +763,8 @@
 		array_free(&mail->header_lines);
 	if (array_is_created(&mail->header_match))
 		array_free(&mail->header_match);
-	if (array_is_created(&mail->header_offsets))
-		array_free(&mail->header_offsets);
+	if (array_is_created(&mail->header_match_lines))
+		array_free(&mail->header_match_lines);
 
 	pool_unref(mail->data_pool);
 	pool_unref(mail->mail.pool);
--- a/src/lib-storage/index/index-mail.h	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/lib-storage/index/index-mail.h	Tue Mar 29 19:48:42 2005 +0300
@@ -103,7 +103,7 @@
 	string_t *header_data;
 	array_t ARRAY_DEFINE(header_lines, struct index_mail_line);
 	array_t ARRAY_DEFINE(header_match, uint8_t);
-	array_t ARRAY_DEFINE(header_offsets, uint32_t);
+	array_t ARRAY_DEFINE(header_match_lines, unsigned int);
 	uint8_t header_match_value;
 };
 
@@ -123,10 +123,12 @@
 			     struct mailbox_header_lookup_ctx *headers);
 void index_mail_headers_get_envelope(struct index_mail *mail);
 
-const char *index_mail_get_header(struct mail *_mail, const char *field);
+const char *index_mail_get_first_header(struct mail *_mail, const char *field);
+const char *const *
+index_mail_get_headers(struct mail *_mail, const char *field);
 struct istream *
-index_mail_get_headers(struct mail *_mail,
-		       struct mailbox_header_lookup_ctx *headers);
+index_mail_get_header_stream(struct mail *_mail,
+			     struct mailbox_header_lookup_ctx *headers);
 
 enum mail_flags index_mail_get_flags(struct mail *_mail);
 const char *const *index_mail_get_keywords(struct mail *_mail);
--- a/src/lib-storage/index/index-search.c	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/lib-storage/index/index-search.c	Tue Mar 29 19:48:42 2005 +0300
@@ -486,7 +486,7 @@
 			headers_ctx =
 				mailbox_header_lookup_init(&ctx->ibox->box,
 							   headers);
-			input = mail_get_headers(ctx->mail, headers_ctx);
+			input = mail_get_header_stream(ctx->mail, headers_ctx);
 			if (input == NULL) {
 				mailbox_header_lookup_deinit(headers_ctx);
 				return FALSE;
--- a/src/lib-storage/index/maildir/maildir-mail.c	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/lib-storage/index/maildir/maildir-mail.c	Tue Mar 29 19:48:42 2005 +0300
@@ -239,8 +239,9 @@
 	index_mail_get_date,
 	maildir_mail_get_virtual_size,
 	maildir_mail_get_physical_size,
-	index_mail_get_header,
+	index_mail_get_first_header,
 	index_mail_get_headers,
+	index_mail_get_header_stream,
 	maildir_mail_get_stream,
 	maildir_mail_get_special,
 	index_mail_update_flags,
--- a/src/lib-storage/index/mbox/mbox-mail.c	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/lib-storage/index/mbox/mbox-mail.c	Tue Mar 29 19:48:42 2005 +0300
@@ -174,8 +174,9 @@
 	index_mail_get_date,
 	index_mail_get_virtual_size,
 	mbox_mail_get_physical_size,
-	index_mail_get_header,
+	index_mail_get_first_header,
 	index_mail_get_headers,
+	index_mail_get_header_stream,
 	mbox_mail_get_stream,
 	mbox_mail_get_special,
 	index_mail_update_flags,
--- a/src/lib-storage/mail-storage-private.h	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/lib-storage/mail-storage-private.h	Tue Mar 29 19:48:42 2005 +0300
@@ -165,10 +165,11 @@
 	uoff_t (*get_virtual_size)(struct mail *mail);
 	uoff_t (*get_physical_size)(struct mail *mail);
 
-	const char *(*get_header)(struct mail *mail, const char *field);
+	const char *(*get_first_header)(struct mail *mail, const char *field);
+	const char *const *(*get_headers)(struct mail *mail, const char *field);
 	struct istream *
-		(*get_headers)(struct mail *mail,
-			       struct mailbox_header_lookup_ctx *headers);
+		(*get_header_stream)(struct mail *mail,
+				     struct mailbox_header_lookup_ctx *headers);
 	struct istream *(*get_stream)(struct mail *mail,
 				      struct message_size *hdr_size,
 				      struct message_size *body_size);
--- a/src/lib-storage/mail-storage.h	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/lib-storage/mail-storage.h	Tue Mar 29 19:48:42 2005 +0300
@@ -415,10 +415,13 @@
 uoff_t mail_get_physical_size(struct mail *mail);
 
 /* Get value for single header field */
-const char *mail_get_header(struct mail *mail, const char *field);
+const char *mail_get_first_header(struct mail *mail, const char *field);
+/* Return a NULL-terminated list of values for each found field. */
+const char *const *mail_get_headers(struct mail *mail, const char *field);
 /* Returns stream containing specified headers. */
-struct istream *mail_get_headers(struct mail *mail,
-				 struct mailbox_header_lookup_ctx *headers);
+struct istream *
+mail_get_header_stream(struct mail *mail,
+		       struct mailbox_header_lookup_ctx *headers);
 /* Returns input stream pointing to beginning of message header.
    hdr_size and body_size are updated unless they're NULL. */
 struct istream *mail_get_stream(struct mail *mail,
--- a/src/lib-storage/mail.c	Tue Mar 29 18:56:19 2005 +0300
+++ b/src/lib-storage/mail.c	Tue Mar 29 19:48:42 2005 +0300
@@ -74,23 +74,27 @@
 	return p->v.get_physical_size(mail);
 }
 
-const char *mail_get_header(struct mail *mail, const char *field)
+const char *mail_get_first_header(struct mail *mail, const char *field)
 {
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_first_header(mail, field);
+}
+
+const char *const *mail_get_headers(struct mail *mail, const char *field)
 {
 	struct mail_private *p = (struct mail_private *)mail;
 
-	return p->v.get_header(mail, field);
-}
+	return p->v.get_headers(mail, field);
 }
 
-struct istream *mail_get_headers(struct mail *mail,
-				 struct mailbox_header_lookup_ctx *headers)
-{
+struct istream *
+mail_get_header_stream(struct mail *mail,
+		       struct mailbox_header_lookup_ctx *headers)
 {
 	struct mail_private *p = (struct mail_private *)mail;
 
-	return p->v.get_headers(mail, headers);
-}
+	return p->v.get_header_stream(mail, headers);
 }
 
 struct istream *mail_get_stream(struct mail *mail,