user-directory.c revision 069d9f1da8dffdce72a80650217eb92450dee643
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2010-2012 Dovecot authors, see the included COPYING file */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "lib.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "ioloop.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "array.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "hash.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "llist.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-user-hash.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "mail-host.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#include "user-directory.h"
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* n% of timeout_secs */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define USER_NEAR_EXPIRING_PERCENTAGE 10
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen/* but max. of this many secs */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#define USER_NEAR_EXPIRING_MAX 30
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct user_directory_iter {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user_directory *dir;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user *pos;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct user_directory {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* const char *username => struct user* */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct hash_table *hash;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* sorted by time */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user *head, *tail;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user *prev_insert_pos;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ARRAY_DEFINE(iters, struct user_directory_iter *);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen char *username_hash_fmt;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int timeout_secs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* If user's expire time is less than this many seconds away,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen don't assume that other directors haven't yet expired it */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int user_near_expiring_secs;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen};
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void user_move_iters(struct user_directory *dir, struct user *user)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen struct user_directory_iter *const *iterp;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen array_foreach(&dir->iters, iterp) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((*iterp)->pos == user)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (*iterp)->pos = user->next;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen }
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen if (dir->prev_insert_pos == user)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen dir->prev_insert_pos = user->next;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen}
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstatic void user_free(struct user_directory *dir, struct user *user)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen{
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen i_assert(user->host->user_count > 0);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen user->host->user_count--;
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen user_move_iters(dir, user);
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen hash_table_remove(dir->hash, POINTER_CAST(user->username_hash));
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen DLLIST2_REMOVE(&dir->head, &dir->tail, user);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen i_free(user);
714c6a150480112eb1a5f309d0cc39b60613a719Timo Sirainen}
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstatic bool user_directory_user_has_connections(struct user_directory *dir,
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen struct user *user)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen{
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen time_t expire_timestamp = user->timestamp + dir->timeout_secs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return expire_timestamp >= ioloop_time;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void user_directory_drop_expired(struct user_directory *dir)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen while (dir->head != NULL &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen !user_directory_user_has_connections(dir, dir->head))
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user_free(dir, dir->head);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct user *user_directory_lookup(struct user_directory *dir,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int username_hash)
9a02317c852face76737763fa6ec43b444688de5Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user_directory_drop_expired(dir);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen return hash_table_lookup(dir->hash, POINTER_CAST(username_hash));
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen}
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenstatic void
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainenuser_directory_insert_backwards(struct user_directory *dir,
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen struct user *pos, struct user *user)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (; pos != NULL; pos = pos->prev) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if ((time_t)pos->timestamp <= user->timestamp)
e237ebeb97f42950eef3efd0d3db85590160d5fbTimo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (pos == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen DLLIST2_PREPEND(&dir->head, &dir->tail, user);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user->prev = pos;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user->next = pos->next;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user->prev->next = user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (user->next != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user->next->prev = user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir->tail = user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void
e2eac5bb5637c2d4aaf453389750740931822b92Timo Sirainenuser_directory_insert_forwards(struct user_directory *dir,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user *pos, struct user *user)
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainen{
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainen for (; pos != NULL; pos = pos->next) {
e2bdacc34dde56aa664059ab56e8b77e82bd1805Timo Sirainen if ((time_t)pos->timestamp >= user->timestamp)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (pos == NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, user);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else {
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen user->prev = pos->prev;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user->next = pos;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (user->prev != NULL)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen user->prev->next = user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir->head = user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user->next->prev = user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct user *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenuser_directory_add(struct user_directory *dir, unsigned int username_hash,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct mail_host *host, time_t timestamp)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user *user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen if (timestamp == (time_t)-1) {
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen /* add it at the end */
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen timestamp = ioloop_time;
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen } else {
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen /* make sure we don't add timestamps higher than ioloop time */
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen if (timestamp > ioloop_time)
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen timestamp = ioloop_time;
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen }
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen
5e702db5540b2303e25554dee21bbf35a4813381Timo Sirainen user = i_new(struct user, 1);
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen user->username_hash = username_hash;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen user->host = host;
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen user->host->user_count++;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user->timestamp = timestamp;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (dir->tail == NULL || (time_t)dir->tail->timestamp <= timestamp)
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, user);
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* need to insert to correct position. we should get here
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen only when handshaking. the handshaking USER requests should
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen come sorted by timestamp. so keep track of the previous
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen insert position, the next USER should be inserted after
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen it. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (dir->prev_insert_pos == NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* find the position starting from tail */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user_directory_insert_backwards(dir, dir->tail, user);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else if (timestamp < dir->prev_insert_pos->timestamp) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user_directory_insert_backwards(dir, dir->prev_insert_pos,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user_directory_insert_forwards(dir, dir->prev_insert_pos,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen dir->prev_insert_pos = user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen hash_table_insert(dir->hash, POINTER_CAST(user->username_hash), user);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return user;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid user_directory_refresh(struct user_directory *dir, struct user *user)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen user_move_iters(dir, user);
1f19649986397419d014febd1337c6eb7b530f26Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user->timestamp = ioloop_time;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen DLLIST2_REMOVE(&dir->head, &dir->tail, user);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, user);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid user_directory_remove_host(struct user_directory *dir,
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen struct mail_host *host)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user *user, *next;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (user = dir->head; user != NULL; user = next) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen next = user->next;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (user->host == host)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen user_free(dir, user);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenunsigned int user_directory_get_username_hash(struct user_directory *dir,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *username)
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return mail_user_hash(username, dir->username_hash_fmt);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
e6440616c02bb1404dc35debf45d9741260c7831Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenbool user_directory_user_is_recently_updated(struct user_directory *dir,
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen struct user *user)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen return (time_t)(user->timestamp + dir->timeout_secs/2) >= ioloop_time;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainenbool user_directory_user_is_near_expiring(struct user_directory *dir,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user *user)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen time_t expire_timestamp;
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen expire_timestamp = user->timestamp +
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen (dir->timeout_secs - dir->user_near_expiring_secs);
06eb8c1371aa06478d8840b1373cab7c2752d5edTimo Sirainen return expire_timestamp < ioloop_time;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct user_directory *
9047d770bfbb93ab6af5363dedb2d01363877243Timo Sirainenuser_directory_init(unsigned int timeout_secs, const char *username_hash_fmt)
836e57b1e7817d008f8ae05cd4b506f420fed80dTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user_directory *dir;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir = i_new(struct user_directory, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir->timeout_secs = timeout_secs;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir->user_near_expiring_secs =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen timeout_secs * USER_NEAR_EXPIRING_PERCENTAGE / 100;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir->user_near_expiring_secs =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen I_MIN(dir->user_near_expiring_secs, USER_NEAR_EXPIRING_MAX);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir->user_near_expiring_secs =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen I_MAX(dir->user_near_expiring_secs, 1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir->username_hash_fmt = i_strdup(username_hash_fmt);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen dir->hash = hash_table_create(default_pool, default_pool,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen 0, NULL, NULL);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_array_init(&dir->iters, 8);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return dir;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid user_directory_deinit(struct user_directory **_dir)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user_directory *dir = *_dir;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *_dir = NULL;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen i_assert(array_count(&dir->iters) == 0);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen while (dir->head != NULL)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen user_free(dir, dir->head);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen hash_table_destroy(&dir->hash);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen array_free(&dir->iters);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen i_free(dir->username_hash_fmt);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen i_free(dir);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen}
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenstruct user_directory_iter *
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenuser_directory_iter_init(struct user_directory *dir)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen{
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen struct user_directory_iter *iter;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen iter = i_new(struct user_directory_iter, 1);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen iter->dir = dir;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen iter->pos = dir->head;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen array_append(&dir->iters, &iter, 1);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen user_directory_drop_expired(dir);
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen return iter;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen}
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainenstruct user *user_directory_iter_next(struct user_directory_iter *iter)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen{
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen struct user *user;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen user = iter->pos;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen if (user == NULL)
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen return FALSE;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen iter->pos = user->next;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen return user;
5833a4972491fdb7b78eac2280f31dc4b9fa2bb7Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenvoid user_directory_iter_deinit(struct user_directory_iter **_iter)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user_directory_iter *iter = *_iter;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct user_directory_iter *const *iters;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int i, count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen *_iter = NULL;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen iters = array_get(&iter->dir->iters, &count);
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen for (i = 0; i < count; i++) {
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen if (iters[i] == iter) {
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen array_delete(&iter->dir->iters, i, 1);
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen break;
ddedc8b77c5bccc8d224ab5f8716d9874f5d8512Timo Sirainen }
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen }
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen i_free(iter);
56aa9083e1742d0083885aaf0c5b8581577731aeTimo Sirainen}
f1612f8421207632e1dc9addd6c23e7f7098a54cTimo Sirainen