~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/lib-index/mail-index-transaction-update.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2003-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
/* Inside transaction we keep messages stored in sequences in uid fields.
4
4
   Before they're written to transaction log the sequences are changed to
59
59
                }
60
60
                array_free(&t->keyword_updates);
61
61
        }
62
 
        if (array_is_created(&t->keyword_resets))
63
 
                array_free(&t->keyword_resets);
64
62
 
65
63
        if (array_is_created(&t->appends))
66
64
                array_free(&t->appends);
78
76
                array_free(&t->ext_reset_ids);
79
77
        if (array_is_created(&t->ext_reset_atomic))
80
78
                array_free(&t->ext_reset_atomic);
 
79
        if (t->attribute_updates != NULL)
 
80
                buffer_free(&t->attribute_updates);
 
81
        if (t->attribute_updates_suffix != NULL)
 
82
                buffer_free(&t->attribute_updates_suffix);
81
83
 
82
84
        t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
83
85
        t->last_new_seq = 0;
107
109
        t->log_updates = array_is_created(&t->appends) ||
108
110
                array_is_created(&t->modseq_updates) ||
109
111
                array_is_created(&t->expunges) ||
110
 
                array_is_created(&t->keyword_resets) ||
111
112
                array_is_created(&t->keyword_updates) ||
 
113
                t->attribute_updates != NULL ||
112
114
                t->pre_hdr_changed || t->post_hdr_changed ||
113
115
                t->min_highest_modseq != 0;
114
116
}
222
224
        for (i = 0; i < count; i++) {
223
225
                if (recs[i].uid == 0 || recs[i].uid < first_uid)
224
226
                        recs[i].uid = next_uid++;
 
227
                else {
 
228
                        if (next_uid != first_uid)
 
229
                                t->appends_nonsorted = TRUE;
 
230
                }
225
231
        }
226
232
 
227
233
        /* write the saved uids range */
304
310
        t->log_ext_updates = mail_index_transaction_has_ext_changes(t);
305
311
 
306
312
        /* remove keywords */
307
 
        if (array_is_created(&t->keyword_resets))
308
 
                seq_range_array_remove(&t->keyword_resets, seq);
309
313
        if (array_is_created(&t->keyword_updates)) {
310
314
                array_foreach_modifiable(&t->keyword_updates, kw_update) {
311
315
                        if (array_is_created(&kw_update->add_seq)) {
393
397
                                           unsigned int right_idx,
394
398
                                           uint32_t seq)
395
399
{
396
 
        const struct mail_transaction_flag_update *updates;
 
400
        const struct mail_index_flag_update *updates;
397
401
        unsigned int idx, count;
398
402
 
399
403
        updates = array_get(&t->updates, &count);
400
404
        i_assert(left_idx <= right_idx && right_idx <= count);
 
405
        i_assert(count < INT_MAX);
401
406
 
402
407
        /* find the first update with either overlapping range,
403
408
           or the update which will come after our insert */
419
424
 
420
425
static void
421
426
mail_index_insert_flag_update(struct mail_index_transaction *t,
422
 
                              struct mail_transaction_flag_update u,
 
427
                              struct mail_index_flag_update u,
423
428
                              unsigned int idx)
424
429
{
425
 
        struct mail_transaction_flag_update *updates, tmp_update;
 
430
        struct mail_index_flag_update *updates, tmp_update;
426
431
        unsigned int count, first_idx, max;
427
432
 
428
433
        updates = array_get_modifiable(&t->updates, &count);
548
553
                                   enum mail_flags flags)
549
554
{
550
555
        struct mail_index_record *rec;
551
 
        struct mail_transaction_flag_update u, *last_update;
 
556
        struct mail_index_flag_update u, *last_update;
552
557
        unsigned int idx, first_idx, count;
553
558
 
554
559
        update_minmax_flagupdate_seq(t, seq1, seq2);
648
653
        mail_index_update_flags_range(t, seq, seq, modify_type, flags);
649
654
}
650
655
 
 
656
static void
 
657
mail_index_attribute_set_full(struct mail_index_transaction *t,
 
658
                              const char *key, bool pvt, char prefix,
 
659
                              time_t timestamp, uint32_t value_len)
 
660
{
 
661
        uint32_t ts = timestamp;
 
662
 
 
663
        if (t->attribute_updates == NULL) {
 
664
                t->attribute_updates = buffer_create_dynamic(default_pool, 64);
 
665
                t->attribute_updates_suffix = buffer_create_dynamic(default_pool, 64);
 
666
        }
 
667
        buffer_append_c(t->attribute_updates, prefix);
 
668
        buffer_append_c(t->attribute_updates, pvt ? 'p' : 's');
 
669
        buffer_append(t->attribute_updates, key, strlen(key)+1);
 
670
 
 
671
        buffer_append(t->attribute_updates_suffix, &ts, sizeof(ts));
 
672
        if (prefix == '+') {
 
673
                buffer_append(t->attribute_updates_suffix,
 
674
                              &value_len, sizeof(value_len));
 
675
        }
 
676
        t->log_updates = TRUE;
 
677
}
 
678
 
 
679
void mail_index_attribute_set(struct mail_index_transaction *t,
 
680
                              bool pvt, const char *key,
 
681
                              time_t timestamp, uint32_t value_len)
 
682
{
 
683
        mail_index_attribute_set_full(t, key, pvt, '+', timestamp, value_len);
 
684
}
 
685
 
 
686
void mail_index_attribute_unset(struct mail_index_transaction *t,
 
687
                                bool pvt, const char *key,
 
688
                                time_t timestamp)
 
689
{
 
690
        mail_index_attribute_set_full(t, key, pvt, '-', timestamp, 0);
 
691
}
 
692
 
651
693
void mail_index_update_header(struct mail_index_transaction *t,
652
694
                              size_t offset, const void *data, size_t size,
653
695
                              bool prepend)
675
717
                           uint16_t record_align)
676
718
{
677
719
        struct mail_transaction_ext_intro intro;
678
 
        uint32_t old_record_size, old_record_align;
 
720
        uint32_t old_record_size, old_record_align, old_header_size;
679
721
 
680
722
        memset(&intro, 0, sizeof(intro));
681
723
 
688
730
                rext = array_idx(&t->view->index->extensions, ext_id);
689
731
                old_record_size = rext->record_size;
690
732
                old_record_align = rext->record_align;
 
733
                old_header_size = rext->hdr_size;
691
734
        } else {
692
735
                const struct mail_index_ext *ext;
693
736
 
694
737
                ext = array_idx(&t->view->map->extensions, intro.ext_id);
695
738
                old_record_size = ext->record_size;
696
739
                old_record_align = ext->record_align;
 
740
                old_header_size = ext->hdr_size;
697
741
        }
698
742
 
699
743
        /* allow only header size changes if extension records have already
700
744
           been changed in transaction */
701
745
        i_assert(!array_is_created(&t->ext_rec_updates) ||
 
746
                 record_size == (uint16_t)-1 ||
702
747
                 (old_record_size == record_size &&
703
748
                  old_record_align == record_align));
704
749
 
707
752
        if (!array_is_created(&t->ext_resizes))
708
753
                i_array_init(&t->ext_resizes, ext_id + 2);
709
754
 
710
 
        intro.hdr_size = hdr_size;
711
 
        intro.record_size = record_size;
712
 
        intro.record_align = record_align;
 
755
        intro.hdr_size = hdr_size != (uint32_t)-1 ? hdr_size : old_header_size;
 
756
        if (record_size != (uint16_t)-1) {
 
757
                i_assert(record_align != (uint16_t)-1);
 
758
                intro.record_size = record_size;
 
759
                intro.record_align = record_align;
 
760
        } else {
 
761
                i_assert(record_align == (uint16_t)-1);
 
762
                intro.record_size = old_record_size;
 
763
                intro.record_align = old_record_align;
 
764
        }
713
765
        intro.name_size = 1;
714
766
        array_idx_set(&t->ext_resizes, ext_id, &intro);
715
767
}
716
768
 
 
769
void mail_index_ext_resize_hdr(struct mail_index_transaction *t,
 
770
                               uint32_t ext_id, uint32_t hdr_size)
 
771
{
 
772
        mail_index_ext_resize(t, ext_id, hdr_size, (uint16_t)-1, (uint16_t)-1);
 
773
}
 
774
 
717
775
void mail_index_ext_reset(struct mail_index_transaction *t, uint32_t ext_id,
718
776
                          uint32_t reset_id, bool clear_data)
719
777
{
838
896
        t->log_ext_updates = mail_index_transaction_has_ext_changes(t);
839
897
}
840
898
 
841
 
bool mail_index_ext_using_reset_id(struct mail_index_transaction *t,
 
899
void mail_index_ext_using_reset_id(struct mail_index_transaction *t,
842
900
                                   uint32_t ext_id, uint32_t reset_id)
843
901
{
844
902
        uint32_t *reset_id_p;
853
911
                /* reset_id changed, clear existing changes */
854
912
                mail_index_ext_reset_changes(t, ext_id);
855
913
        }
856
 
        return changed;
857
914
}
858
915
 
859
916
void mail_index_ext_set_reset_id(struct mail_index_transaction *t,
871
928
        struct mail_index_transaction_ext_hdr_update *hdr;
872
929
        size_t new_size;
873
930
 
874
 
        i_assert(offset <= (uint16_t)-1 && size <= (uint16_t)-1 &&
875
 
                 offset + size <= (uint16_t)-1);
 
931
        i_assert(offset <= (uint32_t)-1 && size <= (uint32_t)-1 &&
 
932
                 offset + size <= (uint32_t)-1);
876
933
 
877
934
        if (!array_is_created(&t->ext_hdr_updates))
878
935
                i_array_init(&t->ext_hdr_updates, ext_id + 2);
958
1015
                                     &old_diff32)) {
959
1016
                /* already incremented this sequence in this transaction */
960
1017
                diff32 += old_diff32;
961
 
                mail_index_seq_array_add(array, seq, &diff32, sizeof(diff32),
962
 
                                         NULL);
 
1018
                (void)mail_index_seq_array_add(array, seq, &diff32,
 
1019
                                               sizeof(diff32), NULL);
963
1020
        }
964
1021
        return diff32;
965
1022
}
969
1026
                           enum modify_type modify_type,
970
1027
                           struct mail_keywords *keywords)
971
1028
{
972
 
        struct mail_index_transaction_keyword_update *u;
973
1029
        ARRAY_TYPE(keyword_indexes) existing;
974
1030
        const unsigned int *existing_idx;
975
1031
        unsigned int i, j, existing_count;
984
1040
                return TRUE;
985
1041
 
986
1042
        for (i = 0; i < keywords->count; i++) {
987
 
                u = array_idx_modifiable(&t->keyword_updates,
988
 
                                         keywords->idx[i]);
989
 
                if (array_is_created(&u->add_seq) ||
990
 
                    array_is_created(&u->remove_seq))
991
 
                        return TRUE;
992
 
 
993
1043
                found = FALSE;
994
1044
                for (j = 0; j < existing_count; j++) {
995
1045
                        if (existing_idx[j] == keywords->idx[i]) {
1012
1062
        return FALSE;
1013
1063
}
1014
1064
 
 
1065
static struct mail_keywords *
 
1066
keyword_update_remove_existing(struct mail_index_transaction *t, uint32_t seq)
 
1067
{
 
1068
        ARRAY_TYPE(keyword_indexes) keywords;
 
1069
        uint32_t i, keywords_count;
 
1070
 
 
1071
        t_array_init(&keywords, 32);
 
1072
        if (t->view->v.lookup_full == NULL) {
 
1073
                /* syncing is saving a list of changes into this transaction.
 
1074
                   the seq is actual an uid, so we can't lookup the existing
 
1075
                   keywords. we shouldn't get here unless we're reading
 
1076
                   pre-v2.2 keyword-reset records from .log files. so we don't
 
1077
                   really care about performance that much here, */
 
1078
                keywords_count = array_count(&t->view->index->keywords);
 
1079
                for (i = 0; i < keywords_count; i++)
 
1080
                        array_append(&keywords, &i, 1);
 
1081
        } else {
 
1082
                mail_index_transaction_lookup_latest_keywords(t, seq, &keywords);
 
1083
        }
 
1084
        if (array_count(&keywords) == 0)
 
1085
                return NULL;
 
1086
        return mail_index_keywords_create_from_indexes(t->view->index,
 
1087
                                                       &keywords);
 
1088
}
 
1089
 
1015
1090
void mail_index_update_keywords(struct mail_index_transaction *t, uint32_t seq,
1016
1091
                                enum modify_type modify_type,
1017
1092
                                struct mail_keywords *keywords)
1018
1093
{
1019
1094
        struct mail_index_transaction_keyword_update *u;
 
1095
        struct mail_keywords *add_keywords = NULL, *remove_keywords = NULL;
 
1096
        struct mail_keywords *unref_keywords = NULL;
1020
1097
        unsigned int i;
1021
1098
        bool changed;
1022
1099
 
1028
1105
 
1029
1106
        update_minmax_flagupdate_seq(t, seq, seq);
1030
1107
 
1031
 
        if (!array_is_created(&t->keyword_updates) && keywords->count > 0) {
1032
 
                uint32_t max_idx = keywords->idx[keywords->count-1];
 
1108
        if (!array_is_created(&t->keyword_updates)) {
 
1109
                uint32_t max_idx = keywords->count == 0 ? 3 :
 
1110
                        keywords->idx[keywords->count-1];
1033
1111
 
1034
1112
                i_array_init(&t->keyword_updates, max_idx + 1);
1035
1113
        }
1044
1122
                        return;
1045
1123
        }
1046
1124
 
 
1125
        switch (modify_type) {
 
1126
        case MODIFY_REPLACE:
 
1127
                /* split this into add+remove. remove all existing keywords not
 
1128
                   included in the keywords list */
 
1129
                if (seq < t->first_new_seq) {
 
1130
                        /* remove the ones currently in index */
 
1131
                        remove_keywords = keyword_update_remove_existing(t, seq);
 
1132
                        unref_keywords = remove_keywords;
 
1133
                }
 
1134
                /* remove from all changes we've done in this transaction */
 
1135
                array_foreach_modifiable(&t->keyword_updates, u)
 
1136
                        seq_range_array_remove(&u->add_seq, seq);
 
1137
                add_keywords = keywords;
 
1138
                break;
 
1139
        case MODIFY_ADD:
 
1140
                add_keywords = keywords;
 
1141
                break;
 
1142
        case MODIFY_REMOVE:
 
1143
                remove_keywords = keywords;
 
1144
                break;
 
1145
        }
 
1146
 
1047
1147
        /* Update add_seq and remove_seq arrays which describe the keyword
1048
 
           changes. Don't bother updating remove_seq or keyword resets for
1049
 
           newly added messages since they default to not having any
1050
 
           keywords anyway. */
1051
 
        switch (modify_type) {
1052
 
        case MODIFY_ADD:
1053
 
                for (i = 0; i < keywords->count; i++) {
1054
 
                        u = array_idx_modifiable(&t->keyword_updates,
1055
 
                                                 keywords->idx[i]);
1056
 
                        seq_range_array_add(&u->add_seq, 16, seq);
 
1148
           changes. First do the removes, since replace removes everything
 
1149
           first. */
 
1150
        if (remove_keywords != NULL) {
 
1151
                for (i = 0; i < remove_keywords->count; i++) {
 
1152
                        u = array_idx_modifiable(&t->keyword_updates,
 
1153
                                                 remove_keywords->idx[i]);
 
1154
                        seq_range_array_remove(&u->add_seq, seq);
 
1155
                        /* Don't bother updating remove_seq for new messages,
 
1156
                           since their initial state is "no keyword" anyway */
 
1157
                        if (seq < t->first_new_seq) {
 
1158
                                seq_range_array_add_with_init(&u->remove_seq,
 
1159
                                                              16, seq);
 
1160
                        }
 
1161
                }
 
1162
        }
 
1163
        if (add_keywords != NULL) {
 
1164
                for (i = 0; i < add_keywords->count; i++) {
 
1165
                        u = array_idx_modifiable(&t->keyword_updates,
 
1166
                                                 add_keywords->idx[i]);
 
1167
                        seq_range_array_add_with_init(&u->add_seq, 16, seq);
1057
1168
                        seq_range_array_remove(&u->remove_seq, seq);
1058
1169
                }
1059
 
                break;
1060
 
        case MODIFY_REMOVE:
1061
 
                for (i = 0; i < keywords->count; i++) {
1062
 
                        u = array_idx_modifiable(&t->keyword_updates,
1063
 
                                                 keywords->idx[i]);
1064
 
                        seq_range_array_remove(&u->add_seq, seq);
1065
 
                        if (seq < t->first_new_seq)
1066
 
                                seq_range_array_add(&u->remove_seq, 16, seq);
1067
 
                }
1068
 
                break;
1069
 
        case MODIFY_REPLACE:
1070
 
                /* Remove sequence from all add/remove arrays */
1071
 
                if (array_is_created(&t->keyword_updates)) {
1072
 
                        array_foreach_modifiable(&t->keyword_updates, u) {
1073
 
                                seq_range_array_remove(&u->add_seq, seq);
1074
 
                                seq_range_array_remove(&u->remove_seq, seq);
1075
 
                        }
1076
 
                }
1077
 
                /* Add the wanted keyword back */
1078
 
                for (i = 0; i < keywords->count; i++) {
1079
 
                        u = array_idx_modifiable(&t->keyword_updates,
1080
 
                                                 keywords->idx[i]);
1081
 
                        seq_range_array_add(&u->add_seq, 16, seq);
1082
 
                }
1083
 
 
1084
 
                if (seq < t->first_new_seq)
1085
 
                        seq_range_array_add(&t->keyword_resets, 16, seq);
1086
 
                break;
1087
1170
        }
 
1171
        if (unref_keywords != NULL)
 
1172
                mail_index_keywords_unref(&unref_keywords);
1088
1173
 
1089
1174
        t->log_updates = TRUE;
1090
1175
}
1092
1177
bool mail_index_cancel_flag_updates(struct mail_index_transaction *t,
1093
1178
                                    uint32_t seq)
1094
1179
{
1095
 
        struct mail_transaction_flag_update *updates, tmp_update;
 
1180
        struct mail_index_flag_update *updates, tmp_update;
1096
1181
        unsigned int i, count;
1097
1182
 
1098
1183
        if (!array_is_created(&t->updates))
1144
1229
                                       uint32_t seq)
1145
1230
{
1146
1231
        struct mail_index_transaction_keyword_update *kw;
1147
 
        bool ret, have_kw_changes = FALSE;
 
1232
        bool ret = FALSE, have_kw_changes = FALSE;
1148
1233
 
1149
 
        ret = mail_index_cancel_array(&t->keyword_resets, seq);
1150
1234
        if (!array_is_created(&t->keyword_updates))
1151
 
                return ret;
 
1235
                return FALSE;
1152
1236
 
1153
1237
        array_foreach_modifiable(&t->keyword_updates, kw) {
1154
1238
                if (mail_index_cancel_array(&kw->add_seq, seq))