bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen#include "lib.h"
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen#include "index-storage.h"
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen#include "index-mail.h"
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen#include "index-pop3-uidl.h"
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainenvoid index_pop3_uidl_set_max_uid(struct mailbox *box,
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen struct mail_index_transaction *trans,
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen uint32_t uid)
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen{
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen struct mailbox_index_pop3_uidl uidl;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&uidl);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen uidl.max_uid_with_pop3_uidl = uid;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen mail_index_update_header_ext(trans, box->pop3_uidl_hdr_ext_id,
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen 0, &uidl, sizeof(uidl));
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen}
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainenbool index_pop3_uidl_can_exist(struct mail *mail)
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen{
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen struct mailbox_index_pop3_uidl uidl;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen const void *data;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen size_t size;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen /* We'll assume that if the header exists, it's up-to-date. normally
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen UIDLs are set only during migration, so this value never changes.
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen Also even if it does, it becomes out-of-date only when the mailbox
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen is modified with old Dovecot versions. To fix that we'd have to
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen add and keep updating "max tracked uid" in this header for every
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen saved mail, which isn't worth it. */
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen mail_index_get_header_ext(mail->transaction->view,
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen mail->box->pop3_uidl_hdr_ext_id,
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen &data, &size);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (size < sizeof(uidl)) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen /* this header isn't set yet */
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen return TRUE;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen }
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen memcpy(&uidl, data, size);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen return mail->uid <= uidl.max_uid_with_pop3_uidl;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen}
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainenvoid index_pop3_uidl_update_exists(struct mail *mail, bool exists)
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen{
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen struct mailbox_transaction_context *trans = mail->transaction;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (exists) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (trans->highest_pop3_uidl_uid < mail->uid) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen trans->highest_pop3_uidl_uid = mail->uid;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen trans->prev_pop3_uidl_tracking_seq = mail->seq;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen }
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen } else if (mail->seq == trans->prev_pop3_uidl_tracking_seq+1) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen trans->prev_pop3_uidl_tracking_seq++;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen } else {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen /* skipping mails. we don't know the state. */
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen }
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen}
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainenvoid index_pop3_uidl_update_exists_finish(struct mailbox_transaction_context *trans)
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen{
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen struct mail_index_view *view;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen struct mailbox_index_pop3_uidl uidl;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen const void *data;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen size_t size;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen bool seen_all_msgs;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
9342a5f69cc6d58ce000016dcf52d9587b4c7073Timo Sirainen mail_index_get_header_ext(trans->view, trans->box->pop3_uidl_hdr_ext_id,
9342a5f69cc6d58ce000016dcf52d9587b4c7073Timo Sirainen &data, &size);
9342a5f69cc6d58ce000016dcf52d9587b4c7073Timo Sirainen
9342a5f69cc6d58ce000016dcf52d9587b4c7073Timo Sirainen if (trans->highest_pop3_uidl_uid == 0 && size >= sizeof(uidl)) {
9342a5f69cc6d58ce000016dcf52d9587b4c7073Timo Sirainen /* header already set and nothing to change */
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen return;
9342a5f69cc6d58ce000016dcf52d9587b4c7073Timo Sirainen }
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen /* First check that we actually looked at UIDL for all messages.
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen Otherwise we can't say for sure if the newest messages had UIDLs. */
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (trans->prev_pop3_uidl_tracking_seq !=
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen mail_index_view_get_messages_count(trans->view))
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen return;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen /* Just to be sure: Refresh the index and check again. POP3 keeps
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen transactions open for duration of the entire session. Maybe another
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen process already added new mails (and already updated this header).
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen This check is racy, but normally UIDLs aren't added after migration
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen so it's a bit questionable if it's even worth having this check in
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen there. */
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen view = mail_index_view_open(trans->box->index);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen seen_all_msgs = mail_index_refresh(trans->box->index) == 0 &&
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen trans->prev_pop3_uidl_tracking_seq ==
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen mail_index_view_get_messages_count(view);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen mail_index_view_close(&view);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (!seen_all_msgs)
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen return;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen /* check if we have already the same header */
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (size >= sizeof(uidl)) {
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen memcpy(&uidl, data, size);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen if (trans->highest_pop3_uidl_uid == uidl.max_uid_with_pop3_uidl)
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen return;
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen }
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen index_pop3_uidl_set_max_uid(trans->box, trans->itrans,
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen trans->highest_pop3_uidl_uid);
2b9dbb270ad82e58d5f3581436e6f143176d5819Timo Sirainen}