1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "index-storage.h"
#include "index-mail.h"
#include "index-pop3-uidl.h"
void index_pop3_uidl_set_max_uid(struct mailbox *box,
struct mail_index_transaction *trans,
uint32_t uid)
{
struct mailbox_index_pop3_uidl uidl;
i_zero(&uidl);
uidl.max_uid_with_pop3_uidl = uid;
mail_index_update_header_ext(trans, box->pop3_uidl_hdr_ext_id,
0, &uidl, sizeof(uidl));
}
bool index_pop3_uidl_can_exist(struct mail *mail)
{
struct mailbox_index_pop3_uidl uidl;
const void *data;
size_t size;
/* We'll assume that if the header exists, it's up-to-date. normally
UIDLs are set only during migration, so this value never changes.
Also even if it does, it becomes out-of-date only when the mailbox
is modified with old Dovecot versions. To fix that we'd have to
add and keep updating "max tracked uid" in this header for every
saved mail, which isn't worth it. */
mail_index_get_header_ext(mail->transaction->view,
mail->box->pop3_uidl_hdr_ext_id,
&data, &size);
if (size < sizeof(uidl)) {
/* this header isn't set yet */
return TRUE;
}
memcpy(&uidl, data, sizeof(uidl));
return mail->uid <= uidl.max_uid_with_pop3_uidl;
}
void index_pop3_uidl_update_exists(struct mail *mail, bool exists)
{
struct mailbox_transaction_context *trans = mail->transaction;
if (exists) {
if (trans->highest_pop3_uidl_uid < mail->uid) {
trans->highest_pop3_uidl_uid = mail->uid;
trans->prev_pop3_uidl_tracking_seq = mail->seq;
}
} else if (mail->seq == trans->prev_pop3_uidl_tracking_seq+1) {
trans->prev_pop3_uidl_tracking_seq++;
} else {
/* skipping mails. we don't know the state. */
}
}
void index_pop3_uidl_update_exists_finish(struct mailbox_transaction_context *trans)
{
struct mail_index_view *view;
struct mailbox_index_pop3_uidl uidl;
const void *data;
size_t size;
bool seen_all_msgs;
mail_index_get_header_ext(trans->view, trans->box->pop3_uidl_hdr_ext_id,
&data, &size);
if (trans->highest_pop3_uidl_uid == 0 && size >= sizeof(uidl)) {
/* header already set and nothing to change */
return;
}
/* First check that we actually looked at UIDL for all messages.
Otherwise we can't say for sure if the newest messages had UIDLs. */
if (trans->prev_pop3_uidl_tracking_seq !=
mail_index_view_get_messages_count(trans->view))
return;
/* Just to be sure: Refresh the index and check again. POP3 keeps
transactions open for duration of the entire session. Maybe another
process already added new mails (and already updated this header).
This check is racy, but normally UIDLs aren't added after migration
so it's a bit questionable if it's even worth having this check in
there. */
view = mail_index_view_open(trans->box->index);
seen_all_msgs = mail_index_refresh(trans->box->index) == 0 &&
trans->prev_pop3_uidl_tracking_seq ==
mail_index_view_get_messages_count(view);
mail_index_view_close(&view);
if (!seen_all_msgs)
return;
/* check if we have already the same header */
if (size >= sizeof(uidl)) {
memcpy(&uidl, data, sizeof(uidl));
if (trans->highest_pop3_uidl_uid == uidl.max_uid_with_pop3_uidl)
return;
}
index_pop3_uidl_set_max_uid(trans->box, trans->itrans,
trans->highest_pop3_uidl_uid);
}
|