]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
mail_get_flags/keywords() now returns updated values if they've been changed within...
authorTimo Sirainen <tss@iki.fi>
Sun, 14 Dec 2008 05:19:48 +0000 (07:19 +0200)
committerTimo Sirainen <tss@iki.fi>
Sun, 14 Dec 2008 05:19:48 +0000 (07:19 +0200)
--HG--
branch : HEAD

src/lib-index/mail-index-dummy-view.c
src/lib-index/mail-index-transaction-private.h
src/lib-index/mail-index-transaction-view.c
src/lib-index/mail-index-transaction.c
src/lib-index/mail-index-view-private.h
src/lib-index/mail-index-view.c
src/lib-storage/index/index-mail.c
src/lib-storage/index/index-mail.h
src/plugins/virtual/virtual-mail.c

index 9ca058b276e3052bca8905184656565ebb8b2acf..c625a4ae58967445d520b93c025f109580488c62 100644 (file)
@@ -29,6 +29,7 @@ static struct mail_index_view_vfuncs dummy_view_vfuncs = {
        NULL,
        NULL,
        NULL,
+       NULL,
        NULL
 };
 
index 979c639e86b75be1efbe3ec521d44f9839d632b7..99bc50589cfb912d8ed6b8f0268fddcceb81d833 100644 (file)
@@ -100,6 +100,12 @@ uint32_t mail_index_transaction_get_next_uid(struct mail_index_transaction *t);
 void mail_index_transaction_convert_to_uids(struct mail_index_transaction *t);
 void mail_index_transaction_check_conflicts(struct mail_index_transaction *t);
 
+unsigned int
+mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t,
+                                          unsigned int left_idx,
+                                          unsigned int right_idx,
+                                          uint32_t seq);
+
 bool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array,
                                 uint32_t seq, unsigned int *idx_r);
 
index 87e5576332697376c710d25797538222246e0563..3c16ad7a0b9e51203feae4aa29da502fbcd1c44b 100644 (file)
@@ -15,8 +15,12 @@ struct mail_index_view_transaction {
 
        struct mail_index_map *lookup_map;
        struct mail_index_header hdr;
+
        buffer_t *lookup_return_data;
        uint32_t lookup_prev_seq;
+
+       unsigned int recs_count;
+       struct mail_index_record *recs;
 };
 
 static void tview_close(struct mail_index_view *view)
@@ -29,6 +33,7 @@ static void tview_close(struct mail_index_view *view)
                mail_index_unmap(&tview->lookup_map);
        if (tview->lookup_return_data != NULL)
                buffer_free(&tview->lookup_return_data);
+       i_free(tview->recs);
 
        tview->super->close(view);
        mail_index_transaction_unref(&t);
@@ -64,6 +69,42 @@ tview_get_header(struct mail_index_view *view)
        return hdr;
 }
 
+static const struct mail_index_record *
+tview_apply_flag_updates(struct mail_index_view_transaction *tview,
+                        const struct mail_index_record *rec, uint32_t seq)
+{
+       struct mail_index_transaction *t = tview->t;
+       const struct mail_transaction_flag_update *updates;
+       unsigned int idx, count;
+
+       /* see if there are any flag updates */
+       if (seq < t->min_flagupdate_seq || seq > t->max_flagupdate_seq ||
+           !array_is_created(&t->updates))
+               return rec;
+
+       updates = array_get(&t->updates, &count);
+       idx = mail_index_transaction_get_flag_update_pos(t, 0, count, seq);
+       if (seq < updates[idx].uid1 || seq > updates[idx].uid2)
+               return rec;
+
+       /* yes, we have flag updates. since we can't modify rec directly and
+          we want to be able to handle multiple mail_index_lookup() calls
+          without the second one overriding the first one's data, we'll
+          create a records array and return data from there */
+       if (tview->recs == NULL) {
+               tview->recs_count = t->first_new_seq;
+               tview->recs = i_new(struct mail_index_record,
+                                   tview->recs_count);
+       }
+       i_assert(tview->recs_count == t->first_new_seq);
+       i_assert(seq > 0 && seq <= tview->recs_count);
+
+       tview->recs[seq-1] = *rec;
+       tview->recs[seq-1].flags |= updates[idx].add_flags;
+       tview->recs[seq-1].flags &= ~updates[idx].remove_flags;
+       return &tview->recs[seq-1];
+}
+
 static const struct mail_index_record *
 tview_lookup_full(struct mail_index_view *view, uint32_t seq,
                  struct mail_index_map **map_r, bool *expunged_r)
@@ -81,8 +122,8 @@ tview_lookup_full(struct mail_index_view *view, uint32_t seq,
        }
 
        rec = tview->super->lookup_full(view, seq, map_r, expunged_r);
+       rec = tview_apply_flag_updates(tview, rec, seq);
 
-       /* if we're expunged within this transaction, return 0 */
        if (array_is_created(&tview->t->expunges) &&
            seq_range_exists(&tview->t->expunges, seq))
                *expunged_r = TRUE;
@@ -190,6 +231,73 @@ static void tview_lookup_first(struct mail_index_view *view,
        }
 }
 
+static void keyword_index_add(ARRAY_TYPE(keyword_indexes) *keywords,
+                             unsigned int idx)
+{
+       const unsigned int *indexes;
+       unsigned int i, count;
+
+       indexes = array_get(keywords, &count);
+       for (i = 0; i < count; i++) {
+               if (indexes[i] == idx)
+                       return;
+       }
+       array_append(keywords, &idx, 1);
+}
+
+static void keyword_index_remove(ARRAY_TYPE(keyword_indexes) *keywords,
+                                unsigned int idx)
+{
+       const unsigned int *indexes;
+       unsigned int i, count;
+
+       indexes = array_get(keywords, &count);
+       for (i = 0; i < count; i++) {
+               if (indexes[i] == idx) {
+                       array_delete(keywords, i, 1);
+                       break;
+               }
+       }
+}
+
+static void tview_lookup_keywords(struct mail_index_view *view, uint32_t seq,
+                                 ARRAY_TYPE(keyword_indexes) *keyword_idx)
+{
+       struct mail_index_view_transaction *tview =
+               (struct mail_index_view_transaction *)view;
+       struct mail_index_transaction *t = tview->t;
+       const struct mail_index_transaction_keyword_update *updates;
+       unsigned int i, count;
+
+       tview->super->lookup_keywords(view, seq, keyword_idx);
+
+       if (seq < t->min_flagupdate_seq || seq > t->max_flagupdate_seq) {
+               /* no keyword updates for this sequence */
+               return;
+       }
+
+       /* apply any keyword updates in this transaction */
+       if (array_is_created(&t->keyword_resets)) {
+               if (seq_range_exists(&t->keyword_resets, seq))
+                       array_clear(keyword_idx);
+       }
+
+       if (array_is_created(&t->keyword_updates))
+               updates = array_get(&t->keyword_updates, &count);
+       else {
+               updates = NULL;
+               count = 0;
+       }
+       for (i = 0; i < count; i++) {
+               if (array_is_created(&updates[i].add_seq) &&
+                   seq_range_exists(&updates[i].add_seq, seq))
+                       keyword_index_add(keyword_idx, i);
+               else if (array_is_created(&updates[i].remove_seq) &&
+                        seq_range_exists(&updates[i].remove_seq, seq))
+                       keyword_index_remove(keyword_idx, i);
+       }
+}
+
 static struct mail_index_map *
 tview_get_lookup_map(struct mail_index_view_transaction *tview)
 {
@@ -336,6 +444,7 @@ static struct mail_index_view_vfuncs trans_view_vfuncs = {
        tview_lookup_uid,
        tview_lookup_seq_range,
        tview_lookup_first,
+       tview_lookup_keywords,
        tview_lookup_ext_full,
        tview_get_header_ext,
        tview_ext_get_reset_id
index 90268a098508dee185b408dd21ea0f2e9b48d6ce..f3593c5eb064a86a4ecdc15a06b49b99a818883b 100644 (file)
@@ -805,10 +805,11 @@ mail_transaction_update_want_add(struct mail_index_transaction *t,
        return FALSE;
 }
 
-static uint32_t
-mail_index_find_update_insert_pos(struct mail_index_transaction *t,
-                                 unsigned int left_idx, unsigned int right_idx,
-                                 uint32_t seq)
+unsigned int
+mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t,
+                                          unsigned int left_idx,
+                                          unsigned int right_idx,
+                                          uint32_t seq)
 {
        const struct mail_transaction_flag_update *updates;
        unsigned int idx, count;
@@ -1038,8 +1039,8 @@ void mail_index_update_flags_range(struct mail_index_transaction *t,
                        first_idx = 0;
                        count = t->last_update_idx + 1;
                }
-               idx = mail_index_find_update_insert_pos(t, first_idx, count,
-                                                       u.uid1);
+               idx = mail_index_transaction_get_flag_update_pos(t, first_idx,
+                                                                count, u.uid1);
                mail_index_insert_flag_update(t, u, idx);
        }
 }
@@ -1567,7 +1568,7 @@ mail_index_update_cancel(struct mail_index_transaction *t, uint32_t seq)
                return ret;
 
        updates = array_get_modifiable(&t->updates, &count);
-       i = mail_index_find_update_insert_pos(t, 0, count, seq);
+       i = mail_index_transaction_get_flag_update_pos(t, 0, count, seq);
        if (i < count && updates[i].uid1 <= seq && updates[i].uid2 >= seq) {
                /* exists */
                ret = TRUE;
index af27c24986901d13e4ec2bd43b6ba1eda87ddb35..ead2c51b701231eb250b46483703a447871406db 100644 (file)
@@ -26,6 +26,8 @@ struct mail_index_view_vfuncs {
        void (*lookup_first)(struct mail_index_view *view,
                             enum mail_flags flags, uint8_t flags_mask,
                             uint32_t *seq_r);
+       void (*lookup_keywords)(struct mail_index_view *view, uint32_t seq,
+                               ARRAY_TYPE(keyword_indexes) *keyword_idx);
        void (*lookup_ext_full)(struct mail_index_view *view, uint32_t seq,
                                uint32_t ext_id, struct mail_index_map **map_r,
                                const void **data_r, bool *expunged_r);
index e54ad467b271df25fa45fd8c87b268072b86aa33..58e4aed767107c0bfd292a3e7fbf1bef662e1f4f 100644 (file)
@@ -332,6 +332,62 @@ static void view_lookup_first(struct mail_index_view *view,
        }
 }
 
+static void
+mail_index_data_lookup_keywords(struct mail_index_map *map,
+                               const unsigned char *data,
+                               ARRAY_TYPE(keyword_indexes) *keyword_idx)
+{
+       const unsigned int *keyword_idx_map;
+       unsigned int i, j, keyword_count, index_idx;
+       uint32_t idx;
+       uint16_t record_size;
+
+       array_clear(keyword_idx);
+       if (data == NULL) {
+               /* no keywords at all in index */
+               return;
+       }
+       (void)mail_index_ext_get_size(NULL, map->index->keywords_ext_id,
+                                     map, NULL, &record_size, NULL);
+
+       /* keyword_idx_map[] contains file => index keyword mapping */
+       if (!array_is_created(&map->keyword_idx_map))
+               return;
+
+       keyword_idx_map = array_get(&map->keyword_idx_map, &keyword_count);
+       for (i = 0, idx = 0; i < record_size; i++) {
+               /* first do the quick check to see if there's keywords at all */
+               if (data[i] == 0)
+                       continue;
+
+               idx = i * CHAR_BIT;
+               for (j = 0; j < CHAR_BIT; j++, idx++) {
+                       if ((data[i] & (1 << j)) == 0)
+                               continue;
+
+                       if (idx >= keyword_count) {
+                               /* extra bits set in keyword bytes.
+                                  shouldn't happen, but just ignore. */
+                               break;
+                       }
+
+                       index_idx = keyword_idx_map[idx];
+                       array_append(keyword_idx, &index_idx, 1);
+               }
+       }
+}
+
+static void view_lookup_keywords(struct mail_index_view *view, uint32_t seq,
+                                ARRAY_TYPE(keyword_indexes) *keyword_idx)
+{
+       struct mail_index_map *map;
+       const void *data;
+
+       mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id,
+                                  &map, &data, NULL);
+       mail_index_data_lookup_keywords(map, data, keyword_idx);
+}
+
 static void
 view_lookup_ext_full(struct mail_index_view *view, uint32_t seq,
                     uint32_t ext_id, struct mail_index_map **map_r,
@@ -442,51 +498,6 @@ bool mail_index_is_expunged(struct mail_index_view *view, uint32_t seq)
        return expunged;
 }
 
-static void
-mail_index_data_lookup_keywords(struct mail_index_map *map,
-                               const unsigned char *data,
-                               ARRAY_TYPE(keyword_indexes) *keyword_idx)
-{
-       const unsigned int *keyword_idx_map;
-       unsigned int i, j, keyword_count, index_idx;
-       uint32_t idx;
-       uint16_t record_size;
-
-       array_clear(keyword_idx);
-       if (data == NULL) {
-               /* no keywords at all in index */
-               return;
-       }
-       (void)mail_index_ext_get_size(NULL, map->index->keywords_ext_id,
-                                     map, NULL, &record_size, NULL);
-
-       /* keyword_idx_map[] contains file => index keyword mapping */
-       if (!array_is_created(&map->keyword_idx_map))
-               return;
-
-       keyword_idx_map = array_get(&map->keyword_idx_map, &keyword_count);
-       for (i = 0, idx = 0; i < record_size; i++) {
-               /* first do the quick check to see if there's keywords at all */
-               if (data[i] == 0)
-                       continue;
-
-               idx = i * CHAR_BIT;
-               for (j = 0; j < CHAR_BIT; j++, idx++) {
-                       if ((data[i] & (1 << j)) == 0)
-                               continue;
-
-                       if (idx >= keyword_count) {
-                               /* extra bits set in keyword bytes.
-                                  shouldn't happen, but just ignore. */
-                               break;
-                       }
-
-                       index_idx = keyword_idx_map[idx];
-                       array_append(keyword_idx, &index_idx, 1);
-               }
-       }
-}
-
 void mail_index_map_lookup_keywords(struct mail_index_map *map, uint32_t seq,
                                    ARRAY_TYPE(keyword_indexes) *keyword_idx)
 {
@@ -509,12 +520,7 @@ void mail_index_map_lookup_keywords(struct mail_index_map *map, uint32_t seq,
 void mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
                                ARRAY_TYPE(keyword_indexes) *keyword_idx)
 {
-       struct mail_index_map *map;
-       const void *data;
-
-       mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id,
-                                  &map, &data, NULL);
-       mail_index_data_lookup_keywords(map, data, keyword_idx);
+       view->v.lookup_keywords(view, seq, keyword_idx);
 }
 
 void mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
@@ -625,6 +631,7 @@ static struct mail_index_view_vfuncs view_vfuncs = {
        view_lookup_uid,
        view_lookup_seq_range,
        view_lookup_first,
+       view_lookup_keywords,
        view_lookup_ext_full,
        view_get_header_ext,
        view_ext_get_reset_id
index 7c440ae76c92a5de5a49aa2ffb9041c6006f255d..65bac036ae869903e20e1fa4a386e2f8fe7a7f20 100644 (file)
@@ -122,12 +122,17 @@ bool index_mail_get_cached_uoff_t(struct index_mail *mail,
 enum mail_flags index_mail_get_flags(struct mail *_mail)
 {
        struct index_mail *mail = (struct index_mail *)_mail;
-       struct index_mail_data *data = &mail->data;
+       const struct mail_index_record *rec;
+       enum mail_flags flags;
+
+       rec = mail_index_lookup(mail->trans->trans_view, _mail->seq);
+       flags = rec->flags & (MAIL_FLAGS_NONRECENT |
+                             MAIL_INDEX_MAIL_FLAG_BACKEND);
 
        if (index_mailbox_is_recent(mail->ibox, _mail->uid))
-               data->flags |= MAIL_RECENT;
+               flags |= MAIL_RECENT;
 
-       return data->flags;
+       return flags;
 }
 
 uint64_t index_mail_get_modseq(struct mail *_mail)
@@ -180,7 +185,8 @@ index_mail_get_keyword_indexes(struct mail *_mail)
 
        if (!array_is_created(&data->keyword_indexes)) {
                p_array_init(&data->keyword_indexes, mail->data_pool, 32);
-               mail_index_lookup_keywords(mail->ibox->view, mail->data.seq,
+               mail_index_lookup_keywords(mail->trans->trans_view,
+                                          mail->data.seq,
                                           &data->keyword_indexes);
        }
        return &data->keyword_indexes;
@@ -1176,7 +1182,6 @@ void index_mail_set_seq(struct mail *_mail, uint32_t seq)
        struct index_mail_data *data = &mail->data;
        struct mail_cache_field *cache_fields = mail->ibox->cache_fields;
         struct mail_cache_view *cache_view = mail->trans->cache_view;
-       const struct mail_index_record *rec;
        struct istream *input;
 
        if (data->seq == seq)
@@ -1184,13 +1189,11 @@ void index_mail_set_seq(struct mail *_mail, uint32_t seq)
 
        index_mail_reset(mail);
 
-       rec = mail_index_lookup(mail->trans->trans_view, seq);
        data->seq = seq;
-       data->flags = rec->flags & (MAIL_FLAGS_NONRECENT |
-                                   MAIL_INDEX_MAIL_FLAG_BACKEND);
 
        mail->mail.mail.seq = seq;
-       mail->mail.mail.uid = rec->uid;
+       mail_index_lookup_uid(mail->trans->trans_view, seq,
+                             &mail->mail.mail.uid);
 
        if (mail_index_view_is_inconsistent(mail->trans->trans_view)) {
                mail_set_expunged(&mail->mail.mail);
@@ -1395,6 +1398,18 @@ void index_mail_update_keywords(struct mail *mail, enum modify_type modify_type,
 {
        struct index_mail *imail = (struct index_mail *)mail;
 
+       if (array_is_created(&imail->data.keyword_indexes))
+               array_free(&imail->data.keyword_indexes);
+       if (array_is_created(&imail->data.keywords)) {
+               /* clear the keywords array so the next mail_get_keywords()
+                  returns the updated keywords. don't free the array, because
+                  then any existing mail_get_keywords() return values would
+                  point to broken data. this won't leak memory because the
+                  array is allocated from mail's memory pool. */
+               memset(&imail->data.keywords, 0,
+                      sizeof(imail->data.keywords));
+       }
+
        mail_index_update_keywords(imail->trans->trans, mail->seq, modify_type,
                                   keywords);
 }
index 141782376bea31f00c9c2652dceae9d02533dc3a..d63cc9d8ce21954d1320548dee9d635855ac5490 100644 (file)
@@ -69,7 +69,6 @@ struct index_mail_line {
 struct message_header_line;
 
 struct index_mail_data {
-       enum mail_flags flags;
        time_t date, received_date, save_date;
        uoff_t virtual_size, physical_size;
 
index 1b132a8c5232156f5d1a758d5101bb8ffb6fa7eb..234bdf5d49c4948ea91c40cd9ac92773d6c06cb5 100644 (file)
@@ -83,7 +83,6 @@ static void virtual_mail_set_seq(struct mail *mail, uint32_t seq)
        struct mailbox_transaction_context *backend_trans;
        struct mailbox_header_lookup_ctx *backend_headers;
        const struct virtual_mail_index_record *vrec;
-       const struct mail_index_record *rec;
        const void *data;
        bool expunged;
 
@@ -112,12 +111,9 @@ static void virtual_mail_set_seq(struct mail *mail, uint32_t seq)
        memset(&vmail->imail.data, 0, sizeof(vmail->imail.data));
        p_clear(vmail->imail.data_pool);
 
-       rec = mail_index_lookup(mbox->ibox.view, seq);
        vmail->imail.data.seq = seq;
-       vmail->imail.data.flags = rec->flags & MAIL_FLAGS_NONRECENT;
-
        mail->seq = seq;
-       mail->uid = rec->uid;
+       mail_index_lookup_uid(mbox->ibox.view, seq, &mail->uid);
 
        mail->expunged = vmail->backend_mail->expunged;
        mail->has_nuls = vmail->backend_mail->has_nuls;