Mercurial > dovecot > core-2.2
changeset 15787:473c0389eb10
pop3_lock_session: Use a separate dovecot-pop3-session.lock file instead of mailbox lock.
This changes the behavior in a way that it's now possible for IMAP sessions
to expunge mails during a POP3 session. But now it's no longer possible for
POP3 sessions to hang new mail deliveries.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 16 Feb 2013 18:22:23 +0200 |
parents | 35194cf0693e |
children | 890b5b52ffd0 |
files | doc/example-config/conf.d/20-pop3.conf src/pop3/pop3-client.c src/pop3/pop3-client.h |
diffstat | 3 files changed, 74 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/example-config/conf.d/20-pop3.conf Sat Feb 16 17:58:20 2013 +0200 +++ b/doc/example-config/conf.d/20-pop3.conf Sat Feb 16 18:22:23 2013 +0200 @@ -16,7 +16,7 @@ # If mail has X-UIDL header, use it as the mail's UIDL. #pop3_reuse_xuidl = no - # Keep the mailbox locked for the entire POP3 session. + # Allow only one POP3 session to run simultaneously for the same user. #pop3_lock_session = no # POP3 requires message sizes to be listed as if they had CR+LF linefeeds.
--- a/src/pop3/pop3-client.c Sat Feb 16 17:58:20 2013 +0200 +++ b/src/pop3/pop3-client.c Sat Feb 16 18:22:23 2013 +0200 @@ -10,6 +10,7 @@ #include "str.h" #include "llist.h" #include "hostpid.h" +#include "file-dotlock.h" #include "var-expand.h" #include "master-service.h" #include "mail-storage.h" @@ -37,6 +38,9 @@ transaction. This allows the mailbox to become unlocked. */ #define CLIENT_COMMIT_TIMEOUT_MSECS (10*1000) +#define POP3_LOCK_FNAME "dovecot-pop3-session.lock" +#define POP3_SESSION_DOTLOCK_STALE_TIMEOUT_SECS (60*5) + extern struct pop3_client_vfuncs pop3_client_vfuncs; struct pop3_module_register pop3_module_register = { 0 }; @@ -49,6 +53,13 @@ MAIL_SORT_END }; +static const struct dotlock_settings session_dotlock_set = { + .timeout = 10, + .stale_timeout = POP3_SESSION_DOTLOCK_STALE_TIMEOUT_SECS, + .lock_suffix = "", + .use_io_notify = TRUE +}; + static void client_input(struct client *client); static int client_output(struct client *client); @@ -273,6 +284,49 @@ return mask; } +static void pop3_lock_session_refresh(struct client *client) +{ + if (file_dotlock_touch(client->session_dotlock) < 0) { + client_send_line(client, + "-ERR [SYS/TEMP] Couldn't update POP3 session lock."); + client_destroy(client, "Couldn't lock POP3 session"); + } +} + +static int pop3_lock_session(struct client *client) +{ + const struct mail_storage_settings *mail_set = + mail_storage_service_user_get_mail_set(client->service_user); + struct dotlock_settings dotlock_set; + const char *dir, *path; + int ret; + + if (!mailbox_list_get_root_path(client->inbox_ns->list, + MAILBOX_LIST_PATH_TYPE_DIR, &dir) && + !mailbox_list_get_root_path(client->inbox_ns->list, + MAILBOX_LIST_PATH_TYPE_INDEX, &dir)) { + i_error("pop3_lock_session: Storage has no root/index directory, " + "can't create a POP3 session lock file"); + return -1; + } + path = t_strdup_printf("%s/"POP3_LOCK_FNAME, dir); + + dotlock_set = session_dotlock_set; + dotlock_set.use_excl_lock = mail_set->dotlock_use_excl; + dotlock_set.nfs_flush = mail_set->mail_nfs_storage; + + ret = file_dotlock_create(&dotlock_set, path, 0, + &client->session_dotlock); + if (ret < 0) + i_error("file_dotlock_create(%s) failed: %m", path); + else if (ret > 0) { + client->to_session_dotlock_refresh = + timeout_add(POP3_SESSION_DOTLOCK_STALE_TIMEOUT_SECS*1000, + pop3_lock_session_refresh, client); + } + return ret; +} + int client_create(int fd_in, int fd_out, const char *session_id, struct mail_user *user, struct mail_storage_service_user *service_user, @@ -284,6 +338,7 @@ enum mailbox_flags flags; const char *errmsg; pool_t pool; + int ret; /* always use nonblocking I/O */ net_set_nonblock(fd_in, TRUE); @@ -308,10 +363,8 @@ client->last_input = ioloop_time; client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS, client_idle_timeout, client); - if (!set->pop3_lock_session) { - client->to_commit = timeout_add(CLIENT_COMMIT_TIMEOUT_MSECS, - client_commit_timeout, client); - } + client->to_commit = timeout_add(CLIENT_COMMIT_TIMEOUT_MSECS, + client_commit_timeout, client); client->user = user; @@ -321,11 +374,17 @@ client->inbox_ns = mail_namespace_find_inbox(user->namespaces); i_assert(client->inbox_ns != NULL); + if (set->pop3_lock_session && (ret = pop3_lock_session(client)) <= 0) { + client_send_line(client, ret < 0 ? + "-ERR [SYS/TEMP] Failed to create POP3 session lock." : + "-ERR [IN-USE] Mailbox is locked by another POP3 session."); + client_destroy(client, "Couldn't lock POP3 session"); + return -1; + } + flags = MAILBOX_FLAG_POP3_SESSION; if (!set->pop3_no_flag_updates) flags |= MAILBOX_FLAG_DROP_RECENT; - if (set->pop3_lock_session) - flags |= MAILBOX_FLAG_KEEP_LOCKED; client->mailbox = mailbox_alloc(client->inbox_ns->list, "INBOX", flags); storage = mailbox_get_storage(client->mailbox); if (mailbox_open(client->mailbox) < 0) { @@ -508,6 +567,11 @@ } mail_user_unref(&client->user); + if (client->session_dotlock != NULL) + file_dotlock_delete(&client->session_dotlock); + if (client->to_session_dotlock_refresh != NULL) + timeout_remove(&client->to_session_dotlock_refresh); + if (client->uidl_pool != NULL) pool_unref(&client->uidl_pool); i_free(client->message_sizes);
--- a/src/pop3/pop3-client.h Sat Feb 16 17:58:20 2013 +0200 +++ b/src/pop3/pop3-client.h Sat Feb 16 18:22:23 2013 +0200 @@ -45,6 +45,9 @@ struct mailbox *mailbox; struct mailbox_transaction_context *trans; + struct timeout *to_session_dotlock_refresh; + struct dotlock *session_dotlock; + time_t last_input, last_output; unsigned int bad_counter; unsigned int highest_expunged_fetch_msgnum;