]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
get_index() wasn't working with caching disabled
authorTimo Sirainen <tss@iki.fi>
Fri, 23 Jul 2004 16:28:40 +0000 (19:28 +0300)
committerTimo Sirainen <tss@iki.fi>
Fri, 23 Jul 2004 16:28:40 +0000 (19:28 +0300)
--HG--
branch : HEAD

src/lib-storage/index/index-mail-headers.c
src/lib-storage/index/index-mail.c
src/lib-storage/index/index-mail.h

index 270c03e7d1f016c43472a427e3f9cb6790dc3c07..b97709524f5947cc7bdc3e4f6702e69f4b365270 100644 (file)
@@ -61,6 +61,9 @@ static void index_mail_parse_header_finish(struct index_mail *mail)
                       match_idx < match_size) {
                        if (match[match_idx] == mail->header_match_value) {
                                /* this header doesn't exist. remember that. */
+                               buffer_write(mail->header_offsets,
+                                            match_idx * sizeof(null),
+                                            &null, sizeof(null));
                                mail_cache_add(mail->trans->cache_trans,
                                               mail->data.seq, match_idx,
                                               NULL, 0);
@@ -120,6 +123,7 @@ void index_mail_parse_header_init(struct index_mail *mail,
                (struct index_header_lookup_ctx *)_headers;
        size_t i;
 
+       mail->header_seq = mail->data.seq;
        if (mail->header_data == NULL) {
                mail->header_data =
                        buffer_create_dynamic(default_pool, 4096, (size_t)-1);
@@ -127,16 +131,20 @@ void index_mail_parse_header_init(struct index_mail *mail,
                        buffer_create_dynamic(default_pool, 256, (size_t)-1);
                mail->header_match =
                        buffer_create_dynamic(default_pool, 64, (size_t)-1);
+               mail->header_offsets =
+                       buffer_create_dynamic(default_pool, 256, (size_t)-1);
        } else {
                buffer_set_used_size(mail->header_data, 0);
                buffer_set_used_size(mail->header_lines, 0);
+               buffer_set_used_size(mail->header_offsets, 0);
        }
 
-       if (++mail->header_match_value == 0) {
+        mail->header_match_value += 2;
+       if (mail->header_match_value == 0) {
                /* wrapped, we'll have to clear the buffer */
                memset(buffer_get_modifyable_data(mail->header_match, NULL), 0,
                       buffer_get_size(mail->header_match));
-               mail->header_match_value++;
+               mail->header_match_value = 2;
        }
 
        if (headers != NULL) {
@@ -175,7 +183,7 @@ int index_mail_parse_header(struct message_part *part,
        enum mail_cache_decision_type decision;
        const char *cache_field_name;
        unsigned int field_idx;
-       int timezone;
+       int timezone, first_hdr = FALSE;
 
         data->parse_line_num++;
 
@@ -257,15 +265,20 @@ int index_mail_parse_header(struct message_part *part,
        }
 
        if (!data->parse_line.cache) {
-               const uint8_t *match;
+               uint8_t *match;
                size_t size;
 
-               match = buffer_get_data(mail->header_match, &size);
+               match = buffer_get_modifyable_data(mail->header_match, &size);
                if (field_idx >= size ||
-                   match[field_idx] != mail->header_match_value) {
+                   (match[field_idx] & ~1) != mail->header_match_value) {
                        /* we don't need to do anything with this header */
                        return TRUE;
                }
+               if (match[field_idx] == mail->header_match_value) {
+                       /* first header */
+                       first_hdr = TRUE;
+                       match[field_idx]++;
+               }
        }
 
        if (!hdr->continued) {
@@ -273,6 +286,14 @@ int index_mail_parse_header(struct message_part *part,
                data->parse_line.line_num = data->parse_line_num;
                str_append(mail->header_data, hdr->name);
                str_append(mail->header_data, ": ");
+
+               if (first_hdr) {
+                       /* save the offset to first header */
+                       uint32_t pos = str_len(mail->header_data);
+                       buffer_write(mail->header_offsets,
+                                    field_idx * sizeof(pos),
+                                    &pos, sizeof(pos));
+               }
        }
        str_append_n(mail->header_data, hdr->value, hdr->value_len);
        if (!hdr->no_newline)
@@ -377,6 +398,57 @@ get_header_field_idx(struct index_mailbox *ibox, const char *field)
        return field_idx;
 }
 
+static size_t get_header_size(buffer_t *buffer, size_t pos)
+{
+       const unsigned char *data;
+       size_t i, size;
+
+       data = buffer_get_data(buffer, &size);
+       i_assert(pos <= size);
+
+       for (i = pos; i < size; i++) {
+               if (data[i] == '\n') {
+                       if (i+1 == size ||
+                           (data[i+1] != ' ' && data[i+1] != '\t'))
+                               return i - pos;
+               }
+       }
+       return size - pos;
+}
+
+static int index_mail_header_is_parsed(struct index_mail *mail,
+                                      unsigned int field_idx)
+{
+       const uint8_t *match;
+       size_t size;
+
+       match = buffer_get_data(mail->header_match, &size);
+       if (field_idx >= size)
+               return -1;
+
+       if (match[field_idx] == mail->header_match_value)
+               return 0;
+       else if (match[field_idx] == mail->header_match_value + 1)
+               return 1;
+       return -1;
+}
+
+static const char *
+index_mail_get_parsed_header(struct index_mail *mail, unsigned int field_idx)
+{
+       const unsigned char *data;
+       const uint32_t *offsets;
+       size_t size;
+
+       offsets = buffer_get_data(mail->header_offsets, &size);
+       i_assert(field_idx * sizeof(*offsets) >= size &&
+                offsets[field_idx] != 0);
+
+       data = buffer_get_data(mail->header_data, &size);
+        size = get_header_size(mail->header_data, offsets[field_idx]);
+       return p_strndup(mail->pool, data + offsets[field_idx], size);
+}
+
 const char *index_mail_get_header(struct mail *_mail, const char *field)
 {
        struct index_mail *mail = (struct index_mail *)_mail;
@@ -385,7 +457,7 @@ const char *index_mail_get_header(struct mail *_mail, const char *field)
        const unsigned char *data;
        unsigned int field_idx;
        string_t *dest;
-       size_t i, len, value_pos;
+       size_t i, len;
        int ret;
 
        field_idx = get_header_field_idx(mail->ibox, field);
@@ -393,21 +465,30 @@ const char *index_mail_get_header(struct mail *_mail, const char *field)
        dest = str_new(mail->pool, 128);
        if (mail_cache_lookup_headers(mail->trans->cache_view, dest,
                                      mail->data.seq, &field_idx, 1) <= 0) {
-               /* not in cache / error */
+               /* not in cache / error - first see if it's already parsed */
+               p_free(mail->pool, dest);
+               if (mail->header_seq == mail->data.seq) {
+                       ret = index_mail_header_is_parsed(mail, field_idx);
+                       if (ret != -1) {
+                               return ret == 0 ? NULL :
+                                       index_mail_get_parsed_header(mail,
+                                                                    field_idx);
+                       }
+               }
+
+               /* parse */
                headers[0] = field; headers[1] = NULL;
                headers_ctx = mailbox_header_lookup_init(&mail->ibox->box,
                                                         headers);
                ret = index_mail_parse_headers(mail, headers_ctx);
                mailbox_header_lookup_deinit(headers_ctx);
-
                if (ret < 0)
                        return NULL;
 
-               ret = mail_cache_lookup_headers(mail->trans->cache_view, dest,
-                                               mail->data.seq, &field_idx, 1);
-               i_assert(ret != 0);
-               if (ret < 0)
-                       return NULL;
+               ret = index_mail_header_is_parsed(mail, field_idx);
+               i_assert(ret != -1);
+               return ret == 0 ? NULL :
+                       index_mail_get_parsed_header(mail, field_idx);
        }
 
        /* cached. skip "header name: " in dest. */
@@ -419,20 +500,11 @@ const char *index_mail_get_header(struct mail *_mail, const char *field)
                        break;
                }
        }
-       value_pos = i;
 
        /* return only the first field in case there's multiple. */
-       for (; i < len; i++) {
-               if (data[i] == '\n') {
-                       if (i+1 == len ||
-                           (data[i+1] != ' ' && data[i+1] != '\t')) {
-                               buffer_set_used_size(dest, i);
-                               break;
-                       }
-               }
-       }
-
-       return str_c(dest) + value_pos;
+        len = get_header_size(dest, i);
+       buffer_set_used_size(dest, i + len);
+       return str_c(dest) + i;
 }
 
 static void header_cache_callback(struct message_header_line *hdr,
index d85a3e231f21d5c0dde454f7114023d67e570d12..fcc5363f59629317f8261a175e169d1ff8063e8e 100644 (file)
@@ -671,6 +671,8 @@ void index_mail_deinit(struct index_mail *mail)
                buffer_free(mail->header_lines);
        if (mail->header_match != NULL)
                buffer_free(mail->header_match);
+       if (mail->header_offsets != NULL)
+               buffer_free(mail->header_offsets);
 
        pool_unref(mail->pool);
        memset(mail, 0, sizeof(*mail));
index 265f876769370843bef623813ec4d2afc63cb99a..c67207f2885c9b37d4575d9efbb44b8791b2ee23 100644 (file)
@@ -96,9 +96,11 @@ struct index_mail {
        struct index_header_lookup_ctx *wanted_headers;
 
        /* per-mail variables, here for performance reasons: */
+       uint32_t header_seq;
        string_t *header_data;
        buffer_t *header_lines;
        buffer_t *header_match;
+       buffer_t *header_offsets;
        uint8_t header_match_value;
 };