user-directory.c revision 2dcf09e68a6d84aba506b0a93897b186ea11520f
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/* Copyright (c) 2010-2013 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "ioloop.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "array.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "hash.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "llist.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-user-hash.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mail-host.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "user-directory.h"
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen/* n% of timeout_secs */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define USER_NEAR_EXPIRING_PERCENTAGE 10
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen/* but min/max. of this many secs */
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#define USER_NEAR_EXPIRING_MIN 3
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#define USER_NEAR_EXPIRING_MAX 30
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct user_directory_iter {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct user_directory *dir;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct user *pos;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen};
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct user_directory {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* unsigned int username_hash => user */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen HASH_TABLE(void *, struct user *) hash;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* sorted by time */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct user *head, *tail;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct user *prev_insert_pos;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen ARRAY(struct user_directory_iter *) iters;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen char *username_hash_fmt;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int timeout_secs;
2c25e1360d4b5cc55eda969a3a7204d950de5a8fTimo Sirainen /* If user's expire time is less than this many seconds away,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen don't assume that other directors haven't yet expired it */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int user_near_expiring_secs;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen};
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void user_move_iters(struct user_directory *dir, struct user *user)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct user_directory_iter *const *iterp;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen array_foreach(&dir->iters, iterp) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if ((*iterp)->pos == user)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (*iterp)->pos = user->next;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (dir->prev_insert_pos == user)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen dir->prev_insert_pos = user->next;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void user_free(struct user_directory *dir, struct user *user)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(user->host->user_count > 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user->host->user_count--;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user_move_iters(dir, user);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen hash_table_remove(dir->hash, POINTER_CAST(user->username_hash));
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen DLLIST2_REMOVE(&dir->head, &dir->tail, user);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_free(user);
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen}
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainenstatic bool user_directory_user_has_connections(struct user_directory *dir,
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen struct user *user)
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen{
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen time_t expire_timestamp = user->timestamp + dir->timeout_secs;
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen if (expire_timestamp > ioloop_time)
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen return TRUE;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (user->kill_state != USER_KILL_STATE_NONE) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* don't free this user until the kill is finished */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return TRUE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (user->weak) {
af81f402ddc897c74c1e85abd02879612ce44882Timo Sirainen if (expire_timestamp + USER_NEAR_EXPIRING_MAX >= ioloop_time)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return TRUE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_warning("User %u weakness appears to be stuck, removing it",
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user->username_hash);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen return FALSE;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic void user_directory_drop_expired(struct user_directory *dir)
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen{
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen while (dir->head != NULL &&
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen !user_directory_user_has_connections(dir, dir->head))
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen user_free(dir, dir->head);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct user *user_directory_lookup(struct user_directory *dir,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int username_hash)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct user *user;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user_directory_drop_expired(dir);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user = hash_table_lookup(dir->hash, POINTER_CAST(username_hash));
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (user != NULL && !user_directory_user_has_connections(dir, user)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user_free(dir, user);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return user;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen
af81f402ddc897c74c1e85abd02879612ce44882Timo Sirainenstatic void
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenuser_directory_insert_backwards(struct user_directory *dir,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct user *pos, struct user *user)
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (; pos != NULL; pos = pos->prev) {
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen if (pos->timestamp <= user->timestamp)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen break;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (pos == NULL)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen DLLIST2_PREPEND(&dir->head, &dir->tail, user);
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen else {
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen user->prev = pos;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user->next = pos->next;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen user->prev->next = user;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen if (user->next != NULL)
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen user->next->prev = user;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen else
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen dir->tail = user;
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen }
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen}
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainen
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainenstatic void
67c24901ac5e1521e38a91efc452faeb3e2135a1Timo Sirainenuser_directory_insert_forwards(struct user_directory *dir,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct user *pos, struct user *user)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen for (; pos != NULL; pos = pos->next) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (pos->timestamp >= user->timestamp)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen break;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (pos == NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, user);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen user->prev = pos->prev;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen user->next = pos;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (user->prev != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user->prev->next = user;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen else
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen dir->head = user;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user->next->prev = user;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainenstruct user *
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainenuser_directory_add(struct user_directory *dir, unsigned int username_hash,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct mail_host *host, time_t timestamp)
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct user *user;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* make sure we don't add timestamps higher than ioloop time */
b3142c8e513bc78da821fa70f479016148fa95e5Timo Sirainen if (timestamp > ioloop_time)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen timestamp = ioloop_time;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user = i_new(struct user, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user->username_hash = username_hash;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user->host = host;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user->host->user_count++;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user->timestamp = timestamp;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (dir->tail == NULL || (time_t)dir->tail->timestamp <= timestamp)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, user);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen else {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen /* need to insert to correct position. we should get here
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen only when handshaking. the handshaking USER requests should
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen come sorted by timestamp. so keep track of the previous
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen insert position, the next USER should be inserted after
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen it. */
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (dir->prev_insert_pos == NULL) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen /* find the position starting from tail */
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user_directory_insert_backwards(dir, dir->tail, user);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen } else if (timestamp < (time_t)dir->prev_insert_pos->timestamp) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user_directory_insert_backwards(dir, dir->prev_insert_pos,
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen } else {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user_directory_insert_forwards(dir, dir->prev_insert_pos,
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen dir->prev_insert_pos = user;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen hash_table_insert(dir->hash, POINTER_CAST(user->username_hash), user);
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen return user;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenvoid user_directory_refresh(struct user_directory *dir, struct user *user)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user_move_iters(dir, user);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen user->timestamp = ioloop_time;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen DLLIST2_REMOVE(&dir->head, &dir->tail, user);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, user);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid user_directory_remove_host(struct user_directory *dir,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen struct mail_host *host)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct user *user, *next;
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (user = dir->head; user != NULL; user = next) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen next = user->next;
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen
e11a64ffc7f08b4cb05bcc27668d154d33d0c2e0Timo Sirainen if (user->host == host)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen user_free(dir, user);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenunsigned int user_directory_get_username_hash(struct user_directory *dir,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const char *username)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return mail_user_hash(username, dir->username_hash_fmt);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenbool user_directory_user_is_recently_updated(struct user_directory *dir,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct user *user)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen return (time_t)(user->timestamp + dir->timeout_secs/2) >= ioloop_time;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenbool user_directory_user_is_near_expiring(struct user_directory *dir,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct user *user)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen time_t expire_timestamp;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen expire_timestamp = user->timestamp +
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (dir->timeout_secs - dir->user_near_expiring_secs);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return expire_timestamp < ioloop_time;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstruct user_directory *
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainenuser_directory_init(unsigned int timeout_secs, const char *username_hash_fmt)
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen{
03f5c621d06d6b6d77a145196c9633a7aa64dc78Timo Sirainen struct user_directory *dir;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
i_assert(timeout_secs > USER_NEAR_EXPIRING_MIN);
dir = i_new(struct user_directory, 1);
dir->timeout_secs = timeout_secs;
dir->user_near_expiring_secs =
timeout_secs * USER_NEAR_EXPIRING_PERCENTAGE / 100;
dir->user_near_expiring_secs =
I_MIN(dir->user_near_expiring_secs, USER_NEAR_EXPIRING_MAX);
dir->user_near_expiring_secs =
I_MAX(dir->user_near_expiring_secs, USER_NEAR_EXPIRING_MIN);
i_assert(dir->timeout_secs/2 > dir->user_near_expiring_secs);
dir->username_hash_fmt = i_strdup(username_hash_fmt);
hash_table_create_direct(&dir->hash, default_pool, 0);
i_array_init(&dir->iters, 8);
return dir;
}
void user_directory_deinit(struct user_directory **_dir)
{
struct user_directory *dir = *_dir;
*_dir = NULL;
i_assert(array_count(&dir->iters) == 0);
while (dir->head != NULL)
user_free(dir, dir->head);
hash_table_destroy(&dir->hash);
array_free(&dir->iters);
i_free(dir->username_hash_fmt);
i_free(dir);
}
struct user_directory_iter *
user_directory_iter_init(struct user_directory *dir)
{
struct user_directory_iter *iter;
iter = i_new(struct user_directory_iter, 1);
iter->dir = dir;
iter->pos = dir->head;
array_append(&dir->iters, &iter, 1);
user_directory_drop_expired(dir);
return iter;
}
struct user *user_directory_iter_next(struct user_directory_iter *iter)
{
struct user *user;
user = iter->pos;
if (user == NULL)
return FALSE;
iter->pos = user->next;
return user;
}
void user_directory_iter_deinit(struct user_directory_iter **_iter)
{
struct user_directory_iter *iter = *_iter;
struct user_directory_iter *const *iters;
unsigned int i, count;
*_iter = NULL;
iters = array_get(&iter->dir->iters, &count);
for (i = 0; i < count; i++) {
if (iters[i] == iter) {
array_delete(&iter->dir->iters, i, 1);
break;
}
}
i_free(iter);
}