case MAIL_TRANSACTION_FLAG_UPDATE:
case MAIL_TRANSACTION_KEYWORD_UPDATE:
case MAIL_TRANSACTION_KEYWORD_RESET:
+ case MAIL_TRANSACTION_ATTRIBUTE_UPDATE:
/* these changes increase modseq */
return TRUE;
}
case MAIL_TRANSACTION_BOUNDARY:
name = "boundary";
break;
+ case MAIL_TRANSACTION_ATTRIBUTE_UPDATE:
+ name = "attribute-update";
+ break;
default:
name = t_strdup_printf("unknown: %x", type);
break;
printf(" - size=%u\n", rec->size);
break;
}
+ case MAIL_TRANSACTION_ATTRIBUTE_UPDATE: {
+ const char *keys = data;
+ unsigned int i;
+
+ for (i = 0; i < size && keys[i] != '\0'; ) {
+ printf(" - %s\n", keys+i);
+ i += strlen(keys+i) + 1;
+ }
+ break;
+ }
default:
break;
}
buffer_t uid_buf;
unsigned int i, count;
uint32_t seq1, seq2;
+ uint64_t modseq;
switch (thdr->type & MAIL_TRANSACTION_TYPE_MASK) {
case MAIL_TRANSACTION_APPEND: {
array_create_from_buffer(&uids, &uid_buf,
sizeof(struct mail_transaction_keyword_reset));
break;
+ case MAIL_TRANSACTION_ATTRIBUTE_UPDATE:
+ break;
default:
return;
}
+ /* update highestmodseq regardless of whether any mails were updated */
+ modseq = mail_transaction_log_view_get_prev_modseq(ctx->log_view);
+ if (modseq > ctx->highest_modseq)
+ ctx->highest_modseq = modseq;
+
/* update modseqs */
- count = array_count(&uids);
+ count = array_is_created(&uids) ? array_count(&uids) : 0;
for (i = 0; i < count; i++) {
rec = array_idx(&uids, i);
if (mail_index_lookup_seq_range(ctx->view, rec->seq1, rec->seq2,
const struct mail_transaction_header *hdr,
const void *data)
{
+ uint64_t modseq;
int ret = 0;
switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
break;
case MAIL_TRANSACTION_BOUNDARY:
break;
+ case MAIL_TRANSACTION_ATTRIBUTE_UPDATE:
+ modseq = mail_transaction_log_view_get_prev_modseq(ctx->view->log_view);
+ mail_index_modseq_update_highest(ctx->modseq_ctx, modseq);
+ break;
default:
mail_index_sync_set_corrupted(ctx,
"Unknown transaction record type 0x%x",
log_append_buffer(&ctx, log_get_hdr_update_buffer(t, TRUE),
MAIL_TRANSACTION_HEADER_UPDATE);
}
+ if (t->attribute_updates != NULL) {
+ /* need to have 32bit alignment */
+ if (t->attribute_updates->used % 4 != 0) {
+ buffer_append_zero(t->attribute_updates,
+ 4 - t->attribute_updates->used % 4);
+ }
+ log_append_buffer(&ctx, t->attribute_updates,
+ MAIL_TRANSACTION_ATTRIBUTE_UPDATE);
+ }
if (array_is_created(&t->appends)) {
change_mask |= MAIL_INDEX_FSYNC_MASK_APPENDS;
log_append_buffer(&ctx, t->appends.arr.buffer,
ARRAY(uint32_t) ext_reset_atomic;
ARRAY(struct mail_index_transaction_keyword_update) keyword_updates;
+ buffer_t *attribute_updates; /* [+-][ps]key\0.. */
uint64_t min_highest_modseq;
uint64_t max_modseq;
array_free(&t->ext_reset_ids);
if (array_is_created(&t->ext_reset_atomic))
array_free(&t->ext_reset_atomic);
+ if (t->attribute_updates != NULL)
+ buffer_free(&t->attribute_updates);
t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
t->last_new_seq = 0;
array_is_created(&t->modseq_updates) ||
array_is_created(&t->expunges) ||
array_is_created(&t->keyword_updates) ||
+ t->attribute_updates != NULL ||
t->pre_hdr_changed || t->post_hdr_changed ||
t->min_highest_modseq != 0;
}
mail_index_update_flags_range(t, seq, seq, modify_type, flags);
}
+static void
+mail_index_attribute_set_full(struct mail_index_transaction *t,
+ const char *key, bool pvt, char prefix)
+{
+ if (t->attribute_updates == NULL)
+ t->attribute_updates = buffer_create_dynamic(default_pool, 64);
+ buffer_append_c(t->attribute_updates, prefix);
+ buffer_append_c(t->attribute_updates, pvt ? 'p' : 's');
+ buffer_append(t->attribute_updates, key, strlen(key)+1);
+ t->log_updates = TRUE;
+}
+
+void mail_index_attribute_set(struct mail_index_transaction *t,
+ bool pvt, const char *key)
+{
+ mail_index_attribute_set_full(t, key, pvt, '+');
+}
+
+void mail_index_attribute_unset(struct mail_index_transaction *t,
+ bool pvt, const char *key)
+{
+ mail_index_attribute_set_full(t, key, pvt, '-');
+}
+
void mail_index_update_header(struct mail_index_transaction *t,
size_t offset, const void *data, size_t size,
bool prepend)
uint32_t seq1, uint32_t seq2,
enum modify_type modify_type,
enum mail_flags flags);
+/* Specified attribute's value was changed. This is just a notification so the
+ change gets assigned its own modseq and any log readers can find out about
+ this change. */
+void mail_index_attribute_set(struct mail_index_transaction *t,
+ bool pvt, const char *key);
+/* Attribute was deleted. */
+void mail_index_attribute_unset(struct mail_index_transaction *t,
+ bool pvt, const char *key);
/* Update message's modseq to be at least min_modseq. */
void mail_index_update_modseq(struct mail_index_transaction *t, uint32_t seq,
uint64_t min_modseq);
case MAIL_TRANSACTION_FLAG_UPDATE:
case MAIL_TRANSACTION_KEYWORD_UPDATE:
case MAIL_TRANSACTION_KEYWORD_RESET:
+ case MAIL_TRANSACTION_ATTRIBUTE_UPDATE:
/* these changes increase modseq */
*cur_modseq += 1;
break;
if ((i % 4) != 0)
i += 4 - (i % 4);
}
+ break;
+ }
+ case MAIL_TRANSACTION_ATTRIBUTE_UPDATE: {
+ const char *attr_changes = data;
+ unsigned int i;
+
+ for (i = 0; i+2 < rec_size && attr_changes[i] != '\0'; ) {
+ if (attr_changes[i] != '+' && attr_changes[i] != '-') {
+ mail_transaction_log_file_set_corrupted(file,
+ "attribute update: Invalid prefix 0x%02x",
+ attr_changes[i]);
+ return FALSE;
+ }
+ i++;
+ if (attr_changes[i] != 'p' && attr_changes[i] != 's') {
+ mail_transaction_log_file_set_corrupted(file,
+ "attribute update: Invalid type 0x%02x",
+ attr_changes[i]);
+ return FALSE;
+ }
+ i++;
+ if (attr_changes[i] == '\0') {
+ mail_transaction_log_file_set_corrupted(file,
+ "attribute update: Empty key");
+ return FALSE;
+ }
+ i += strlen(attr_changes+i) + 1;
+ }
+ if (i == 0 || (i < rec_size && attr_changes[i] != '\0')) {
+ mail_transaction_log_file_set_corrupted(file,
+ "attribute update doesn't end with NUL");
+ return FALSE;
+ }
+ break;
}
default:
break;
MAIL_TRANSACTION_INDEX_DELETED = 0x00020000,
MAIL_TRANSACTION_INDEX_UNDELETED = 0x00040000,
MAIL_TRANSACTION_BOUNDARY = 0x00080000,
+ MAIL_TRANSACTION_ATTRIBUTE_UPDATE = 0x00100000,
- MAIL_TRANSACTION_TYPE_MASK = 0x000fffff,
+ MAIL_TRANSACTION_TYPE_MASK = 0x0fffffff,
#define MAIL_TRANSACTION_EXT_MASK \
(MAIL_TRANSACTION_EXT_INTRO | MAIL_TRANSACTION_EXT_RESET | \