bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "ioloop.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "array.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "hash.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "llist.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "mail-host.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen/* n% of timeout_secs */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen#define USER_NEAR_EXPIRING_PERCENTAGE 10
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen/* but min/max. of this many secs */
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen#define USER_NEAR_EXPIRING_MIN 3
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen#define USER_NEAR_EXPIRING_MAX 30
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen/* This shouldn't matter what it is exactly, just try it sometimes later. */
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen#define USER_BEING_KILLED_EXPIRE_RETRY_SECS 60
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct user_directory_iter {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory *dir;
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen struct user *pos, *stop_after_tail;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct user_directory {
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen /* unsigned int username_hash => user */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen HASH_TABLE(void *, struct user *) hash;
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen /* sorted by time. may be unsorted while handshakes are going on. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *head, *tail;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct user_directory_iter *) iters;
1a7ed931e58827e3048360be8341f29dfb85837bAki Tuomi user_free_hook_t *user_free_hook;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int timeout_secs;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen /* If user's expire time is less than this many seconds away,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen don't assume that other directors haven't yet expired it */
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen unsigned int user_near_expiring_secs;
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen struct timeout *to_expire;
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen time_t to_expire_timestamp;
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen bool sort_pending;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen};
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void user_move_iters(struct user_directory *dir, struct user *user)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory_iter *const *iterp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_foreach(&dir->iters, iterp) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if ((*iterp)->pos == user)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (*iterp)->pos = user->next;
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen if ((*iterp)->stop_after_tail == user) {
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen (*iterp)->stop_after_tail =
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen user->prev != NULL ? user->prev : user->next;
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void user_free(struct user_directory *dir, struct user *user)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(user->host->user_count > 0);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->host->user_count--;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (dir->user_free_hook != NULL)
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen dir->user_free_hook(user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_move_iters(dir, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_remove(dir->hash, POINTER_CAST(user->username_hash));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DLLIST2_REMOVE(&dir->head, &dir->tail, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainenstatic bool user_directory_user_has_connections(struct user_directory *dir,
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen struct user *user,
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen time_t *expire_timestamp_r)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen{
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen time_t expire_timestamp = user->timestamp + dir->timeout_secs;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen if (expire_timestamp > ioloop_time) {
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen *expire_timestamp_r = expire_timestamp;
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen return TRUE;
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen }
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen
79ee504bdf920f01e12e28f238799bf2616489dfTimo Sirainen if (USER_IS_BEING_KILLED(user)) {
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen /* don't free this user until the kill is finished */
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen *expire_timestamp_r = ioloop_time +
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen USER_BEING_KILLED_EXPIRE_RETRY_SECS;
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen return TRUE;
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen }
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen if (user->weak) {
7d8c1ba766770ea1c6d4d6770a31832b5b518648Timo Sirainen if (expire_timestamp + USER_NEAR_EXPIRING_MAX > ioloop_time) {
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen *expire_timestamp_r = expire_timestamp +
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen USER_NEAR_EXPIRING_MAX;
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen return TRUE;
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen }
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen i_warning("User %u weakness appears to be stuck, removing it",
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen user->username_hash);
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen }
d40c98b71de3acd7dd9e41178d449ca84d26e406Timo Sirainen return FALSE;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen}
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void user_directory_drop_expired(struct user_directory *dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen time_t expire_timestamp = 0;
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while (dir->head != NULL &&
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen !user_directory_user_has_connections(dir, dir->head, &expire_timestamp)) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_free(dir, dir->head);
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen expire_timestamp = 0;
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen }
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen i_assert(expire_timestamp > ioloop_time || expire_timestamp == 0);
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen if (expire_timestamp != dir->to_expire_timestamp) {
d90a924480a061683786e459a2e1c1d0b6e4f1e4Josef 'Jeff' Sipek timeout_remove(&dir->to_expire);
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen if (expire_timestamp != 0) {
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen struct timeval tv = { .tv_sec = expire_timestamp };
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen dir->to_expire_timestamp = tv.tv_sec;
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen dir->to_expire = timeout_add_absolute(&tv,
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen user_directory_drop_expired, dir);
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen }
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainenunsigned int user_directory_count(struct user_directory *dir)
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen{
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen return hash_table_count(dir->hash);
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen}
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct user *user_directory_lookup(struct user_directory *dir,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int username_hash)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen struct user *user;
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen time_t expire_timestamp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen user_directory_drop_expired(dir);
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen user = hash_table_lookup(dir->hash, POINTER_CAST(username_hash));
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen if (user != NULL && !user_directory_user_has_connections(dir, user, &expire_timestamp)) {
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen user_free(dir, user);
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen user = NULL;
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen }
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen return user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct user *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenuser_directory_add(struct user_directory *dir, unsigned int username_hash,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host, time_t timestamp)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen struct user *user;
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen
32a93320fd2b6ada5ac8027166819463c1a007b6Timo Sirainen /* make sure we don't add timestamps higher than ioloop time */
32a93320fd2b6ada5ac8027166819463c1a007b6Timo Sirainen if (timestamp > ioloop_time)
447bf65ddb82ec279e7386828748ef47e199a6afTimo Sirainen timestamp = ioloop_time;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user = i_new(struct user, 1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->username_hash = username_hash;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->host = host;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->host->user_count++;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->timestamp = timestamp;
94fb15fffc814d7dcecabf8d90691502311d4b88Timo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen if (dir->to_expire == NULL) {
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen struct timeval tv = { .tv_sec = ioloop_time + dir->timeout_secs };
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen dir->to_expire_timestamp = tv.tv_sec;
27006b32276426acf449bd0ea7a35ed19389ae6bTimo Sirainen dir->to_expire = timeout_add_absolute(&tv, user_directory_drop_expired, dir);
8017d6c67481d2bcfa1ba1fe229939a0ba8b56e9Timo Sirainen }
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_insert(dir->hash, POINTER_CAST(user->username_hash), user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid user_directory_refresh(struct user_directory *dir, struct user *user)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_move_iters(dir, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user->timestamp = ioloop_time;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DLLIST2_REMOVE(&dir->head, &dir->tail, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid user_directory_remove_host(struct user_directory *dir,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_host *host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user, *next;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (user = dir->head; user != NULL; user = next) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen next = user->next;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (user->host == host)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_free(dir, user);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainenstatic int user_timestamp_cmp(struct user *const *user1,
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen struct user *const *user2)
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen{
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen if ((*user1)->timestamp < (*user2)->timestamp)
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen return -1;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen if ((*user1)->timestamp > (*user2)->timestamp)
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen return 1;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen return 0;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen}
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainenvoid user_directory_sort(struct user_directory *dir)
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen{
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen ARRAY(struct user *) users;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen struct user *user, *const *userp;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen unsigned int i, users_count = hash_table_count(dir->hash);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen dir->sort_pending = FALSE;
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen if (users_count == 0) {
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen i_assert(dir->head == NULL);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen return;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen }
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen if (array_count(&dir->iters) > 0) {
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen /* We can't sort the directory while there are iterators
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen or they'll skip users. Do the sort after there are no more
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen iterators. */
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen dir->sort_pending = TRUE;
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen return;
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen }
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen /* place all users into array and sort it */
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen i_array_init(&users, users_count);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen user = dir->head;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen for (i = 0; i < users_count; i++, user = user->next)
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen array_append(&users, &user, 1);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen i_assert(user == NULL);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen array_sort(&users, user_timestamp_cmp);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen /* recreate the linked list */
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen dir->head = dir->tail = NULL;
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen array_foreach(&users, userp)
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, *userp);
430d256a6244b2a780c298febc66e74d6b6e8cc2Timo Sirainen i_assert(dir->head != NULL &&
430d256a6244b2a780c298febc66e74d6b6e8cc2Timo Sirainen dir->head->timestamp <= dir->tail->timestamp);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen array_free(&users);
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen}
8621be3846dc097420cce325ad36d1b646f72a09Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainenbool user_directory_user_is_recently_updated(struct user_directory *dir,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct user *user)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
7dd73e056c7d9976080393d9cd731f69111818eeTimo Sirainen return (time_t)(user->timestamp + dir->timeout_secs/2) >= ioloop_time;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen}
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainenbool user_directory_user_is_near_expiring(struct user_directory *dir,
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen struct user *user)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen{
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen time_t expire_timestamp;
dc1bc1685e4a0d58ae7bacaecc282d0ebde2d7daTimo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen expire_timestamp = user->timestamp +
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen (dir->timeout_secs - dir->user_near_expiring_secs);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen return expire_timestamp < ioloop_time;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
5733207dc3ec10e6e5a6e0a8b30fbd1b061062b9Timo Sirainenstruct user_directory *
de92873c366becfaea1554642f89b9169d7955e2Timo Sirainenuser_directory_init(unsigned int timeout_secs,
1a7ed931e58827e3048360be8341f29dfb85837bAki Tuomi user_free_hook_t *user_free_hook)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory *dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen i_assert(timeout_secs > USER_NEAR_EXPIRING_MIN);
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir = i_new(struct user_directory, 1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dir->timeout_secs = timeout_secs;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen dir->user_near_expiring_secs =
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen timeout_secs * USER_NEAR_EXPIRING_PERCENTAGE / 100;
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen dir->user_near_expiring_secs =
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen I_MIN(dir->user_near_expiring_secs, USER_NEAR_EXPIRING_MAX);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen dir->user_near_expiring_secs =
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen I_MAX(dir->user_near_expiring_secs, USER_NEAR_EXPIRING_MIN);
2dcf09e68a6d84aba506b0a93897b186ea11520fTimo Sirainen i_assert(dir->timeout_secs/2 > dir->user_near_expiring_secs);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen dir->user_free_hook = user_free_hook;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create_direct(&dir->hash, default_pool, 0);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_array_init(&dir->iters, 8);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid user_directory_deinit(struct user_directory **_dir)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory *dir = *_dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *_dir = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(array_count(&dir->iters) == 0);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen while (dir->head != NULL)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user_free(dir, dir->head);
d90a924480a061683786e459a2e1c1d0b6e4f1e4Josef 'Jeff' Sipek timeout_remove(&dir->to_expire);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen hash_table_destroy(&dir->hash);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_free(&dir->iters);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct user_directory_iter *
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainenuser_directory_iter_init(struct user_directory *dir,
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen bool iter_until_current_tail)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory_iter *iter;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen iter = i_new(struct user_directory_iter, 1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen iter->dir = dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen iter->pos = dir->head;
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen iter->stop_after_tail = iter_until_current_tail ? dir->tail : NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_append(&dir->iters, &iter, 1);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen user_directory_drop_expired(dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return iter;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct user *user_directory_iter_next(struct user_directory_iter *iter)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user *user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen user = iter->pos;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (user == NULL)
ba5c8b0ae7460752adaf911901bf263788f62c72Phil Carmody return NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen iter->pos = user->next;
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen if (user == iter->stop_after_tail) {
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen /* this is the last user we want to iterate */
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen iter->pos = NULL;
14660f677e16a5c36f3c43e9e64f5e021fda627bTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen return user;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid user_directory_iter_deinit(struct user_directory_iter **_iter)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory_iter *iter = *_iter;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct user_directory_iter *const *iters;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen unsigned int i, count;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *_iter = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen iters = array_get(&iter->dir->iters, &count);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen for (i = 0; i < count; i++) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (iters[i] == iter) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen array_delete(&iter->dir->iters, i, 1);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen if (array_count(&iter->dir->iters) == 0 && iter->dir->sort_pending)
efd72f0559ac15585ec5f48893f2e13eb6cf7738Timo Sirainen user_directory_sort(iter->dir);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_free(iter);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}