summaryrefslogtreecommitdiffstats
path: root/src/lib-storage/index/index-pop3-uidl.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-storage/index/index-pop3-uidl.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/lib-storage/index/index-pop3-uidl.c b/src/lib-storage/index/index-pop3-uidl.c
new file mode 100644
index 0000000..e537e9f
--- /dev/null
+++ b/src/lib-storage/index/index-pop3-uidl.c
@@ -0,0 +1,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);
+}