mbox-sync-update.c revision 84e1634acc701d14e358e27f1beff5ad74f5004a
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen#include "lib.h"
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen#include "buffer.h"
5dd05e966ffd69181ab3067f6939b03ced68ebc3Timo Sirainen#include "str.h"
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen#include "message-parser.h"
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen#include "index-storage.h"
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen#include "mbox-storage.h"
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen#include "mbox-sync-private.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainenstatic void status_flags_append(struct mbox_sync_mail_context *ctx,
93ae7fcd39c6982f7e338adfe71139942d9bbad1Timo Sirainen const struct mbox_flag_type *flags_list)
93ae7fcd39c6982f7e338adfe71139942d9bbad1Timo Sirainen{
93ae7fcd39c6982f7e338adfe71139942d9bbad1Timo Sirainen int i;
93ae7fcd39c6982f7e338adfe71139942d9bbad1Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen for (i = 0; flags_list[i].chr != 0; i++) {
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen if ((ctx->mail.flags & flags_list[i].flag) != 0)
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen str_append_c(ctx->header, flags_list[i].chr);
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen }
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen}
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainenvoid mbox_sync_move_buffer(struct mbox_sync_mail_context *ctx,
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen size_t pos, size_t need, size_t have)
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen{
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen ssize_t diff = (ssize_t)need - (ssize_t)have;
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen int i;
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen i_assert(have < SSIZE_T_MAX);
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (diff == 0) {
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen if (ctx->header_last_change < pos + have ||
cd466fe7b84b0223735a6469c7f7bc225f65996dTimo Sirainen ctx->header_last_change == (size_t)-1)
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen ctx->header_last_change = pos + have;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen } else {
0e3f8c6edad565112d91f0a53568c0313d657e48Timo Sirainen /* FIXME: if (diff < ctx->space && pos < ctx->offset) then
0e3f8c6edad565112d91f0a53568c0313d657e48Timo Sirainen move the data only up to space offset and give/take the
0e3f8c6edad565112d91f0a53568c0313d657e48Timo Sirainen space from there. update header_last_change accordingly.
0e3f8c6edad565112d91f0a53568c0313d657e48Timo Sirainen (except pos and offset can't be compared directly) */
0e3f8c6edad565112d91f0a53568c0313d657e48Timo Sirainen ctx->header_last_change = (size_t)-1;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen for (i = 0; i < MBOX_HDR_COUNT; i++) {
d56384d5226c8860079d0d0b08b83404e8c42986Timo Sirainen if (ctx->hdr_pos[i] > pos &&
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen ctx->hdr_pos[i] != (size_t)-1)
d56384d5226c8860079d0d0b08b83404e8c42986Timo Sirainen ctx->hdr_pos[i] += diff;
d56384d5226c8860079d0d0b08b83404e8c42986Timo Sirainen }
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen if (diff < 0)
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen str_delete(ctx->header, pos, -diff);
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen else {
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen ctx->header_last_change = (size_t)-1;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen buffer_copy(ctx->header, pos + diff,
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen ctx->header, pos, (size_t)-1);
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen }
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen }
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen}
d6af1e63bc7824f1cc5b9b73a1c5f8f8789788d6Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainenstatic void status_flags_replace(struct mbox_sync_mail_context *ctx, size_t pos,
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen const struct mbox_flag_type *flags_list)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
6a9f9a5101b665fd2ef80c9e048a5eace78e01efTimo Sirainen unsigned char *data;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen size_t size;
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen int i, need, have;
6a9f9a5101b665fd2ef80c9e048a5eace78e01efTimo Sirainen
6a9f9a5101b665fd2ef80c9e048a5eace78e01efTimo Sirainen ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen if (ctx->header_first_change > pos)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen ctx->header_first_change = pos;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen /* how many bytes do we need? */
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen for (i = 0, need = 0; flags_list[i].chr != 0; i++) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if ((ctx->mail.flags & flags_list[i].flag) != 0)
a3ea111cfdbfd4f32baeb0bd7f1d72568c60a023Timo Sirainen need++;
a3ea111cfdbfd4f32baeb0bd7f1d72568c60a023Timo Sirainen }
a3ea111cfdbfd4f32baeb0bd7f1d72568c60a023Timo Sirainen
a3ea111cfdbfd4f32baeb0bd7f1d72568c60a023Timo Sirainen /* how many bytes do we have now? */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen data = buffer_get_modifyable_data(ctx->header, &size);
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen for (have = 0; pos < size; pos++) {
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen if (data[pos] == '\n')
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen break;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen /* see if this is unknown flag for us */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen for (i = 0; flags_list[i].chr != 0; i++) {
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen if (flags_list[i].chr == data[pos])
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen break;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen }
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
1f57716285d4c5bc9bf2fd5569e3c85fd496afd9Timo Sirainen if (flags_list[i].chr != 0)
1f57716285d4c5bc9bf2fd5569e3c85fd496afd9Timo Sirainen have++;
1f57716285d4c5bc9bf2fd5569e3c85fd496afd9Timo Sirainen else {
1f57716285d4c5bc9bf2fd5569e3c85fd496afd9Timo Sirainen /* save this one */
1f57716285d4c5bc9bf2fd5569e3c85fd496afd9Timo Sirainen data[pos-have] = data[pos];
1f57716285d4c5bc9bf2fd5569e3c85fd496afd9Timo Sirainen }
1f57716285d4c5bc9bf2fd5569e3c85fd496afd9Timo Sirainen }
1f57716285d4c5bc9bf2fd5569e3c85fd496afd9Timo Sirainen pos -= have;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen mbox_sync_move_buffer(ctx, pos, need, have);
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen /* @UNSAFE */
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen data = buffer_get_space_unsafe(ctx->header, pos, need);
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen for (i = 0, need = 0; flags_list[i].chr != 0; i++) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if ((ctx->mail.flags & flags_list[i].flag) != 0)
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen *data++ = flags_list[i].chr;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen }
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
a3ea111cfdbfd4f32baeb0bd7f1d72568c60a023Timo Sirainen}
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainenstatic void keywords_append(struct mbox_sync_context *sync_ctx, string_t *dest,
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen const array_t *keyword_indexes_arr)
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen{
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen ARRAY_SET_TYPE(keyword_indexes_arr, unsigned int);
a29a5b7520f7b8d6cdaf97e66d184b6a9e4f4ecfTimo Sirainen const char *const *keyword_names;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen const unsigned int *keyword_indexes;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen unsigned int i, idx_count, keywords_count;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen size_t last_break;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen keyword_names = array_get(sync_ctx->ibox->keyword_names,
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen &keywords_count);
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen keyword_indexes = array_get(keyword_indexes_arr, &idx_count);
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen for (i = 0, last_break = 0; i < idx_count; i++) {
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen i_assert(keyword_indexes[i] < keywords_count);
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen /* try avoid overly long lines but cutting them
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen every 70 chars or so */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (str_len(dest) - last_break < 70) {
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen if (i > 0)
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen str_append_c(dest, ' ');
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen } else {
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen str_append(dest, "\n\t");
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen last_break = str_len(dest);
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen }
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen str_append(dest, keyword_names[keyword_indexes[i]]);
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen}
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
af208f4a43a81a39a2ec44e68d65d12b95f1b386Timo Sirainenstatic void
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainenkeywords_append_all(struct mbox_sync_mail_context *ctx, string_t *dest)
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen{
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen const char *const *names;
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen const unsigned char *p;
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen unsigned int i, count;
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen size_t last_break;
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen p = str_data(dest);
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen if (str_len(dest) < 70)
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen last_break = 0;
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen else {
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen /* set last_break to beginning of line */
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen for (last_break = str_len(dest); last_break > 0; last_break--) {
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen if (p[last_break-1] == '\n')
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen break;
743c3ba9d4b06d4797d06136ec53a4a652422a57Timo Sirainen }
743c3ba9d4b06d4797d06136ec53a4a652422a57Timo Sirainen }
22c1ec434d7323e125c150e3fd237316c74de6d5Timo Sirainen
22c1ec434d7323e125c150e3fd237316c74de6d5Timo Sirainen names = array_get(ctx->sync_ctx->ibox->keyword_names, &count);
743c3ba9d4b06d4797d06136ec53a4a652422a57Timo Sirainen for (i = 0; i < count; i++) {
22c1ec434d7323e125c150e3fd237316c74de6d5Timo Sirainen /* try avoid overly long lines but cutting them
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen every 70 chars or so */
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen if (str_len(dest) - last_break < 70)
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen str_append_c(dest, ' ');
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen else {
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen str_append(dest, "\n\t");
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen last_break = str_len(dest);
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen }
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen str_append(dest, names[i]);
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen }
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen}
5dd05e966ffd69181ab3067f6939b03ced68ebc3Timo Sirainen
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainenstatic void mbox_sync_add_missing_headers(struct mbox_sync_mail_context *ctx)
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen{
b09be485e9373be4288f5615bbce6ebed65a425aTimo Sirainen size_t old_hdr_size, new_hdr_size;
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen old_hdr_size = ctx->body_offset - ctx->hdr_offset;
9453e8d75cfd8fab2232cf772e9b120f308fb3eeTimo Sirainen new_hdr_size = str_len(ctx->header);
9453e8d75cfd8fab2232cf772e9b120f308fb3eeTimo Sirainen
9453e8d75cfd8fab2232cf772e9b120f308fb3eeTimo Sirainen if (new_hdr_size > 0 &&
9453e8d75cfd8fab2232cf772e9b120f308fb3eeTimo Sirainen str_data(ctx->header)[new_hdr_size-1] != '\n') {
9453e8d75cfd8fab2232cf772e9b120f308fb3eeTimo Sirainen /* broken header - doesn't end with \n. fix it. */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen str_append_c(ctx->header, '\n');
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen }
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen if (ctx->sync_ctx->dest_first_mail &&
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen ctx->hdr_pos[MBOX_HDR_X_IMAPBASE] == (size_t)-1) {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen i_assert(ctx->sync_ctx->base_uid_validity != 0);
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen str_append(ctx->header, "X-IMAPbase: ");
33ca6b017b6ebbd048651b5e3d16915001dbc291Timo Sirainen ctx->hdr_pos[MBOX_HDR_X_IMAPBASE] = str_len(ctx->header);
str_printfa(ctx->header, "%u ",
ctx->sync_ctx->base_uid_validity);
ctx->last_uid_value_start_pos = str_len(ctx->header) -
ctx->hdr_pos[MBOX_HDR_X_IMAPBASE];
str_printfa(ctx->header, "%010u", ctx->sync_ctx->next_uid-1);
keywords_append_all(ctx, ctx->header);
str_append_c(ctx->header, '\n');
}
if (ctx->hdr_pos[MBOX_HDR_X_UID] == (size_t)-1 && !ctx->pseudo) {
str_append(ctx->header, "X-UID: ");
ctx->hdr_pos[MBOX_HDR_X_UID] = str_len(ctx->header);
str_printfa(ctx->header, "%u\n", ctx->mail.uid);
}
ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
if (ctx->hdr_pos[MBOX_HDR_STATUS] == (size_t)-1 &&
(ctx->mail.flags & STATUS_FLAGS_MASK) != 0) {
str_append(ctx->header, "Status: ");
ctx->hdr_pos[MBOX_HDR_STATUS] = str_len(ctx->header);
status_flags_append(ctx, mbox_status_flags);
str_append_c(ctx->header, '\n');
}
if (ctx->hdr_pos[MBOX_HDR_X_STATUS] == (size_t)-1 &&
(ctx->mail.flags & XSTATUS_FLAGS_MASK) != 0) {
str_append(ctx->header, "X-Status: ");
ctx->hdr_pos[MBOX_HDR_X_STATUS] = str_len(ctx->header);
status_flags_append(ctx, mbox_xstatus_flags);
str_append_c(ctx->header, '\n');
}
ctx->mail.flags ^= MBOX_NONRECENT_KLUDGE;
if (ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] == (size_t)-1 &&
array_is_created(&ctx->mail.keywords) &&
array_count(&ctx->mail.keywords) > 0) {
str_append(ctx->header, "X-Keywords: ");
ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] = str_len(ctx->header);
keywords_append(ctx->sync_ctx, ctx->header,
&ctx->mail.keywords);
str_append_c(ctx->header, '\n');
}
if (ctx->content_length == (uoff_t)-1 &&
ctx->mail.body_size >= MBOX_MIN_CONTENT_LENGTH_SIZE) {
str_printfa(ctx->header, "Content-Length: %"PRIuUOFF_T"\n",
ctx->mail.body_size);
}
if (str_len(ctx->header) != new_hdr_size) {
if (ctx->header_first_change == (size_t)-1)
ctx->header_first_change = new_hdr_size;
ctx->header_last_change = (size_t)-1;
}
if (ctx->have_eoh)
str_append_c(ctx->header, '\n');
}
static void mbox_sync_update_status(struct mbox_sync_mail_context *ctx)
{
if (ctx->hdr_pos[MBOX_HDR_STATUS] != (size_t)-1) {
status_flags_replace(ctx, ctx->hdr_pos[MBOX_HDR_STATUS],
mbox_status_flags);
}
}
static void mbox_sync_update_xstatus(struct mbox_sync_mail_context *ctx)
{
if (ctx->hdr_pos[MBOX_HDR_X_STATUS] != (size_t)-1) {
status_flags_replace(ctx, ctx->hdr_pos[MBOX_HDR_X_STATUS],
mbox_xstatus_flags);
}
}
static void mbox_sync_update_line(struct mbox_sync_mail_context *ctx,
size_t pos, string_t *new_line)
{
const char *hdr, *p;
uoff_t file_pos;
if (ctx->header_first_change > pos)
ctx->header_first_change = pos;
hdr = str_c(ctx->header) + pos;
p = strchr(hdr, '\n');
if (p == NULL) {
/* shouldn't really happen, but allow anyway.. */
p = hdr + strlen(hdr);
}
file_pos = pos + ctx->hdr_offset;
if (ctx->mail.space > 0 && ctx->mail.offset >= file_pos &&
ctx->mail.offset < file_pos + (p - hdr)) {
/* extra space points to this line. remove it. */
ctx->mail.offset = ctx->hdr_offset;
ctx->mail.space = 0;
}
mbox_sync_move_buffer(ctx, pos, str_len(new_line), p - hdr + 1);
buffer_copy(ctx->header, pos, new_line, 0, (size_t)-1);
}
static void mbox_sync_update_xkeywords(struct mbox_sync_mail_context *ctx)
{
string_t *str;
if (ctx->hdr_pos[MBOX_HDR_X_KEYWORDS] == (size_t)-1)
return;
t_push();
str = t_str_new(256);
keywords_append(ctx->sync_ctx, str, &ctx->mail.keywords);
str_append_c(str, '\n');
mbox_sync_update_line(ctx, ctx->hdr_pos[MBOX_HDR_X_KEYWORDS], str);
t_pop();
}
static void mbox_sync_update_x_imap_base(struct mbox_sync_mail_context *ctx)
{
struct mbox_sync_context *sync_ctx = ctx->sync_ctx;
string_t *str;
i_assert(sync_ctx->base_uid_validity != 0);
if (!sync_ctx->dest_first_mail ||
ctx->hdr_pos[MBOX_HDR_X_IMAPBASE] == (size_t)-1)
return;
if (!ctx->imapbase_rewrite) {
/* uid-last might need updating, but we'll do it later by
writing it directly where needed. */
return;
}
/* a) keyword list changed, b) uid-last didn't use 10 digits */
t_push();
str = t_str_new(200);
str_printfa(str, "%u ", sync_ctx->base_uid_validity);
ctx->last_uid_value_start_pos =
str_len(str) - ctx->hdr_pos[MBOX_HDR_X_IMAPBASE];
str_printfa(str, "%010u", sync_ctx->next_uid - 1);
keywords_append_all(ctx, str);
str_append_c(str, '\n');
mbox_sync_update_line(ctx, ctx->hdr_pos[MBOX_HDR_X_IMAPBASE], str);
t_pop();
}
static void mbox_sync_update_x_uid(struct mbox_sync_mail_context *ctx)
{
string_t *str;
if (ctx->hdr_pos[MBOX_HDR_X_UID] == (size_t)-1 ||
ctx->mail.uid == ctx->parsed_uid)
return;
t_push();
str = t_str_new(64);
str_printfa(str, "%u\n", ctx->mail.uid);
mbox_sync_update_line(ctx, ctx->hdr_pos[MBOX_HDR_X_UID], str);
t_pop();
}
void mbox_sync_update_header(struct mbox_sync_mail_context *ctx)
{
uint8_t old_flags;
int keywords_changed;
i_assert(ctx->mail.uid != 0 || ctx->pseudo);
old_flags = ctx->mail.flags;
if (array_count(&ctx->sync_ctx->syncs) > 0) {
mbox_sync_apply_index_syncs(ctx->sync_ctx, &ctx->mail,
&keywords_changed);
if ((old_flags & XSTATUS_FLAGS_MASK) !=
(ctx->mail.flags & XSTATUS_FLAGS_MASK))
mbox_sync_update_xstatus(ctx);
if (keywords_changed)
mbox_sync_update_xkeywords(ctx);
}
if (!ctx->sync_ctx->ibox->keep_recent)
ctx->mail.flags &= ~MAIL_RECENT;
if ((old_flags & STATUS_FLAGS_MASK) !=
(ctx->mail.flags & STATUS_FLAGS_MASK))
mbox_sync_update_status(ctx);
mbox_sync_update_x_imap_base(ctx);
mbox_sync_update_x_uid(ctx);
mbox_sync_add_missing_headers(ctx);
ctx->updated = TRUE;
}
void mbox_sync_update_header_from(struct mbox_sync_mail_context *ctx,
const struct mbox_sync_mail *mail)
{
if ((ctx->mail.flags & STATUS_FLAGS_MASK) !=
(mail->flags & STATUS_FLAGS_MASK) ||
(ctx->mail.flags & MAIL_RECENT) != 0) {
ctx->mail.flags = (ctx->mail.flags & ~STATUS_FLAGS_MASK) |
(mail->flags & STATUS_FLAGS_MASK);
if (!ctx->sync_ctx->ibox->keep_recent)
ctx->mail.flags &= ~MAIL_RECENT;
mbox_sync_update_status(ctx);
}
if ((ctx->mail.flags & XSTATUS_FLAGS_MASK) !=
(mail->flags & XSTATUS_FLAGS_MASK)) {
ctx->mail.flags = (ctx->mail.flags & ~XSTATUS_FLAGS_MASK) |
(mail->flags & XSTATUS_FLAGS_MASK);
mbox_sync_update_xstatus(ctx);
}
if (!array_is_created(&mail->keywords) ||
array_count(&mail->keywords) == 0) {
/* no keywords for this mail */
if (array_is_created(&ctx->mail.keywords)) {
array_clear(&ctx->mail.keywords);
mbox_sync_update_xkeywords(ctx);
}
} else if (!array_is_created(&ctx->mail.keywords)) {
/* adding first keywords */
ARRAY_CREATE(&ctx->mail.keywords,
ctx->sync_ctx->mail_keyword_pool,
unsigned int,
array_count(&mail->keywords));
array_append_array(&ctx->mail.keywords,
&mail->keywords);
mbox_sync_update_xkeywords(ctx);
} else if (!buffer_cmp(ctx->mail.keywords.buffer,
mail->keywords.buffer)) {
/* keywords changed. */
array_clear(&ctx->mail.keywords);
array_append_array(&ctx->mail.keywords,
&mail->keywords);
mbox_sync_update_xkeywords(ctx);
}
i_assert(ctx->mail.uid == 0 || ctx->mail.uid == mail->uid);
ctx->mail.uid = mail->uid;
mbox_sync_update_x_imap_base(ctx);
mbox_sync_update_x_uid(ctx);
mbox_sync_add_missing_headers(ctx);
}