quota.c revision e34d170f8f0e084bd94bfbc1a7085ece67e508df
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "lib.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "array.h"
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#include "hash.h"
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen#include "str.h"
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen#include "network.h"
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen#include "write-full.h"
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen#include "eacces-error.h"
b039dabf4c53f72454e795930e7643b6e0e625f9Timo Sirainen#include "mailbox-list-private.h"
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen#include "quota-private.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "quota-fs.h"
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen#include <ctype.h>
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen#include <stdlib.h>
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen#include <sys/wait.h>
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
cb2b5a7d6e7e651191bf9ee1eda94a6e207288b0Timo Sirainen#define DEFAULT_QUOTA_EXCEEDED_MSG \
cb2b5a7d6e7e651191bf9ee1eda94a6e207288b0Timo Sirainen "Quota exceeded (mailbox for user is full)"
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen#define RULE_NAME_DEFAULT_FORCE "*"
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen#define RULE_NAME_DEFAULT_NONFORCE "?"
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root_iter {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota *quota;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mailbox *box;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen};
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainenunsigned int quota_module_id = 0;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenextern struct quota_backend quota_backend_dict;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenextern struct quota_backend quota_backend_dirsize;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenextern struct quota_backend quota_backend_fs;
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainenextern struct quota_backend quota_backend_maildir;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic const struct quota_backend *quota_backends[] = {
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#ifdef HAVE_FS_QUOTA
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &quota_backend_fs,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#endif
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &quota_backend_dict,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &quota_backend_dirsize,
cb951d3282610a9a0960230865bc5f3e3347b203Timo Sirainen &quota_backend_maildir
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen};
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic int quota_default_test_alloc(struct quota_transaction_context *ctx,
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen uoff_t size, bool *too_large_r);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic const struct quota_backend *quota_backend_find(const char *name)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen unsigned int i;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen for (i = 0; i < N_ELEMENTS(quota_backends); i++) {
4316355ca8b7698516272520a972291378698140Timo Sirainen if (strcmp(quota_backends[i]->name, name) == 0)
4316355ca8b7698516272520a972291378698140Timo Sirainen return quota_backends[i];
4316355ca8b7698516272520a972291378698140Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen return NULL;
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int quota_root_add_rules(struct mail_user *user, const char *root_name,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root_settings *root_set,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char **error_r)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *rule_name, *rule, *error;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen unsigned int i;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule_name = t_strconcat(root_name, "_rule", NULL);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen for (i = 2;; i++) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule = mail_user_plugin_getenv(user, rule_name);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (rule == NULL)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen break;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (quota_root_add_rule(root_set, rule, &error) < 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Invalid rule %s: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen rule, error);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule_name = t_strdup_printf("%s_rule%d", root_name, i);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenquota_root_add_warning_rules(struct mail_user *user, const char *root_name,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root_settings *root_set,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char **error_r)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen const char *rule_name, *rule, *error;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen unsigned int i;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule_name = t_strconcat(root_name, "_warning", NULL);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen for (i = 2;; i++) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule = mail_user_plugin_getenv(user, rule_name);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (rule == NULL)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen break;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (quota_root_add_warning_rule(root_set, rule, &error) < 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Invalid warning rule: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen rule);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen rule_name = t_strdup_printf("%s_warning%d", root_name, i);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int
4316355ca8b7698516272520a972291378698140Timo Sirainenquota_root_settings_init(struct quota_settings *quota_set, const char *root_def,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root_settings **set_r,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char **error_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root_settings *root_set;
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen const struct quota_backend *backend;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen const char *p, *args, *backend_name;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* <backend>[:<quota root name>[:<backend args>]] */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen p = strchr(root_def, ':');
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (p == NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backend_name = root_def;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backend_name = t_strdup_until(root_def, p);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = p + 1;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backend = quota_backend_find(backend_name);
d9b8c65d0a0ffc709ba7d23c449dbf2f46b10674Timo Sirainen if (backend == NULL) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Unknown quota backend: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen backend_name);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
d9b8c65d0a0ffc709ba7d23c449dbf2f46b10674Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set = p_new(quota_set->pool, struct quota_root_settings, 1);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->set = quota_set;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->backend = backend;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (args != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* save root's name */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen p = strchr(args, ':');
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (p == NULL) {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->name = p_strdup(quota_set->pool, args);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->name =
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen p_strdup_until(quota_set->pool, args, p);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen args = p + 1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen } else {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->name = "";
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->args = p_strdup(quota_set->pool, args);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (quota_set->debug) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("Quota root: name=%s backend=%s args=%s",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk root_set->name, backend_name, args == NULL ? "" : args);
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen }
e3077468777f5d324224365e34d7bbc449168e52Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen p_array_init(&root_set->rules, quota_set->pool, 4);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen p_array_init(&root_set->warning_rules, quota_set->pool, 4);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen array_append(&quota_set->root_sets, &root_set, 1);
4316355ca8b7698516272520a972291378698140Timo Sirainen *set_r = root_set;
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int
4316355ca8b7698516272520a972291378698140Timo Sirainenquota_root_add(struct quota_settings *quota_set, struct mail_user *user,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char *env, const char *root_name, const char **error_r)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root_settings *root_set;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_root_settings_init(quota_set, env, &root_set, error_r) < 0)
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_root_add_rules(user, root_name, root_set, error_r) < 0)
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_root_add_warning_rules(user, root_name, root_set, error_r) < 0)
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenint quota_user_read_settings(struct mail_user *user,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_settings **set_r,
4316355ca8b7698516272520a972291378698140Timo Sirainen const char **error_r)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_settings *quota_set;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen char root_name[5 + MAX_INT_STRLEN + 1];
4316355ca8b7698516272520a972291378698140Timo Sirainen const char *env, *error;
4316355ca8b7698516272520a972291378698140Timo Sirainen unsigned int i;
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_t pool;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen pool = pool_alloconly_create("quota settings", 2048);
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set = p_new(pool, struct quota_settings, 1);
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->pool = pool;
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->test_alloc = quota_default_test_alloc;
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->debug = user->mail_debug;
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->quota_exceeded_msg =
4316355ca8b7698516272520a972291378698140Timo Sirainen mail_user_plugin_getenv(user, "quota_exceeded_message");
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_set->quota_exceeded_msg == NULL)
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_set->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen p_array_init(&quota_set->root_sets, pool, 4);
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (i_strocpy(root_name, "quota", sizeof(root_name)) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_unreached();
4316355ca8b7698516272520a972291378698140Timo Sirainen for (i = 2;; i++) {
4316355ca8b7698516272520a972291378698140Timo Sirainen env = mail_user_plugin_getenv(user, root_name);
3cfc375f0d939c346b9b0e6f0ac78b9bc367dd95Timo Sirainen if (env == NULL || *env == '\0')
4316355ca8b7698516272520a972291378698140Timo Sirainen break;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen if (quota_root_add(quota_set, user, env, root_name,
4316355ca8b7698516272520a972291378698140Timo Sirainen &error) < 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Invalid quota root %s: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen root_name, error);
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_unref(&pool);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (i_snprintf(root_name, sizeof(root_name), "quota%d", i) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen i_unreached();
4316355ca8b7698516272520a972291378698140Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen if (array_count(&quota_set->root_sets) == 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_unref(&pool);
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen *set_r = quota_set;
4316355ca8b7698516272520a972291378698140Timo Sirainen return 1;
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenvoid quota_settings_deinit(struct quota_settings **_quota_set)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_settings *quota_set = *_quota_set;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen *_quota_set = NULL;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_unref(&quota_set->pool);
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic void quota_root_deinit(struct quota_root *root)
4316355ca8b7698516272520a972291378698140Timo Sirainen{
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_t pool = root->pool;
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainen root->backend.v.deinit(root);
4316355ca8b7698516272520a972291378698140Timo Sirainen pool_unref(&pool);
4316355ca8b7698516272520a972291378698140Timo Sirainen}
4316355ca8b7698516272520a972291378698140Timo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenstatic int
4316355ca8b7698516272520a972291378698140Timo Sirainenquota_root_init(struct quota_root_settings *root_set, struct quota *quota,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota_root **root_r, const char **error_r)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root *root;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen const char *const *tmp;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root = root_set->backend->v.alloc();
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen root->resource_ret = -1;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root->pool = pool_alloconly_create("quota root", 512);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root->set = root_set;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root->quota = quota;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root->backend = *root_set->backend;
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen root->bytes_limit = root_set->default_rule.bytes_limit;
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen root->count_limit = root_set->default_rule.count_limit;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen array_create(&root->quota_module_contexts, root->pool,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen sizeof(void *), 10);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (root->backend.v.init != NULL) {
4316355ca8b7698516272520a972291378698140Timo Sirainen if (root->backend.v.init(root, root_set->args) < 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = "init() failed";
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen } else if (root_set->args != NULL) {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen tmp = t_strsplit_spaces(root_set->args, " ");
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen for (; *tmp != NULL; tmp++) {
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen if (strcmp(*tmp, "noenforcing") == 0)
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen root->no_enforcing = TRUE;
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen else if (strcmp(*tmp, "ignoreunlimited") == 0)
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen root->disable_unlimited_tracking = TRUE;
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen else
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen break;
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen }
65e14cef911d5d3fac8993c8a76911a587f05cd7Timo Sirainen if (*tmp != NULL) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf(
4316355ca8b7698516272520a972291378698140Timo Sirainen "Unknown parameter for backend %s: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen root->backend.name, *tmp);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
608aa112aa7d94a1720c909747dcd0b61c079453Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen if (root_set->default_rule.bytes_limit == 0 &&
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen root_set->default_rule.count_limit == 0 &&
4316355ca8b7698516272520a972291378698140Timo Sirainen root->disable_unlimited_tracking) {
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_root_deinit(root);
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen *root_r = root;
4316355ca8b7698516272520a972291378698140Timo Sirainen return 1;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
4316355ca8b7698516272520a972291378698140Timo Sirainenint quota_init(struct quota_settings *quota_set, struct mail_user *user,
4316355ca8b7698516272520a972291378698140Timo Sirainen struct quota **quota_r, const char **error_r)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota *quota;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root *root;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root_settings *const *root_sets;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
4316355ca8b7698516272520a972291378698140Timo Sirainen const char *error;
4316355ca8b7698516272520a972291378698140Timo Sirainen int ret;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota = i_new(struct quota, 1);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota->user = user;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota->set = quota_set;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen i_array_init(&quota->roots, 8);
8a1c866a4c429f26c8746525f82024bc387f1407Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_sets = array_get(&quota_set->root_sets, &count);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen i_array_init(&quota->namespaces, count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
4316355ca8b7698516272520a972291378698140Timo Sirainen ret = quota_root_init(root_sets[i], quota, &root, &error);
4316355ca8b7698516272520a972291378698140Timo Sirainen if (ret < 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = t_strdup_printf("Quota root %s: %s",
4316355ca8b7698516272520a972291378698140Timo Sirainen root_sets[i]->name, error);
4316355ca8b7698516272520a972291378698140Timo Sirainen quota_deinit(&quota);
4316355ca8b7698516272520a972291378698140Timo Sirainen return -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen if (ret > 0)
d19d3aa4eafa34b48b7d7d311c9db31e1898576aTimo Sirainen array_append(&quota->roots, &root, 1);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
4316355ca8b7698516272520a972291378698140Timo Sirainen *quota_r = quota;
4316355ca8b7698516272520a972291378698140Timo Sirainen return 0;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenvoid quota_deinit(struct quota **_quota)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota *quota = *_quota;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_root *const *roots;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen unsigned int i, count;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen roots = array_get(&quota->roots, &count);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen for (i = 0; i < count; i++)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota_root_deinit(roots[i]);
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen /* deinit quota roots before setting quser->quota=NULL */
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen *_quota = NULL;
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen array_free(&quota->roots);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_free(&quota->namespaces);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen i_free(quota);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainenstruct quota_rule *
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenquota_root_rule_find(struct quota_root_settings *root_set, const char *name)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen struct quota_rule *rule;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen array_foreach_modifiable(&root_set->rules, rule) {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen if (strcmp(rule->mailbox_name, name) == 0)
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen return rule;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainenstatic int
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenquota_rule_parse_percentage(struct quota_root_settings *root_set,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_rule *rule,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen int64_t *limit, const char **error_r)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen{
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen int64_t percentage = *limit;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (percentage <= 0 || percentage >= -1U) {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen *error_r = p_strdup_printf(root_set->set->pool,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen "Invalid rule percentage: %lld", (long long)percentage);
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return -1;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen }
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (rule == &root_set->default_rule) {
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen *error_r = "Default rule can't be a percentage";
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return -1;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen }
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen if (limit == &rule->bytes_limit)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen rule->bytes_percent = percentage;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen else if (limit == &rule->count_limit)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen rule->count_percent = percentage;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen else
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen i_unreached();
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return 0;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen}
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenstatic void
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainenquota_rule_recalculate_relative_rules(struct quota_rule *rule,
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen int64_t bytes_limit, int64_t count_limit)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen{
1e844899e67ba229d39647e53635f78b87c52f38Timo Sirainen if (rule->bytes_percent > 0)
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen rule->bytes_limit = bytes_limit * rule->bytes_percent / 100;
1e844899e67ba229d39647e53635f78b87c52f38Timo Sirainen if (rule->count_percent > 0)
1e844899e67ba229d39647e53635f78b87c52f38Timo Sirainen rule->count_limit = count_limit * rule->count_percent / 100;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen}
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainenvoid quota_root_recalculate_relative_rules(struct quota_root_settings *root_set,
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen int64_t bytes_limit,
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen int64_t count_limit)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen{
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen struct quota_rule *rule;
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen struct quota_warning_rule *warning_rule;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen array_foreach_modifiable(&root_set->rules, rule) {
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen quota_rule_recalculate_relative_rules(rule, bytes_limit,
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen count_limit);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen array_foreach_modifiable(&root_set->warning_rules, warning_rule) {
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen quota_rule_recalculate_relative_rules(&warning_rule->rule,
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen bytes_limit, count_limit);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen}
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainenstatic int
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenquota_rule_parse_limits(struct quota_root_settings *root_set,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota_rule *rule, const char *limits,
5183f82691b9c6e5707d93fe57336cd89462d574Timo Sirainen const char *full_rule_def,
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen bool relative_rule, const char **error_r)
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen{
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen const char **args, *key, *value;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen char *p;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen uint64_t multiply;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen int64_t *limit;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen args = t_strsplit(limits, ":");
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen for (; *args != NULL; args++) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen multiply = 1;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen limit = NULL;
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen key = *args;
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen value = strchr(key, '=');
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen if (value == NULL)
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen value = "";
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen else
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen key = t_strdup_until(key, value++);
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen if (*value == '+') {
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen if (!relative_rule) {
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen *error_r = "Rule limit cannot have '+'";
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen return -1;
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen }
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen value++;
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen } else if (*value != '-' && relative_rule) {
5183f82691b9c6e5707d93fe57336cd89462d574Timo Sirainen i_warning("quota root %s rule %s: "
4c4f6141f1eecc76c3242e37d0016f55c6c43cfdTimo Sirainen "obsolete configuration for rule '%s' "
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen "should be changed to '%s=+%s'",
5183f82691b9c6e5707d93fe57336cd89462d574Timo Sirainen root_set->name, full_rule_def,
5183f82691b9c6e5707d93fe57336cd89462d574Timo Sirainen *args, key, value);
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen }
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen if (strcmp(key, "storage") == 0) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen multiply = 1024;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen limit = &rule->bytes_limit;
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen *limit = strtoll(value, &p, 10);
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen } else if (strcmp(key, "bytes") == 0) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen limit = &rule->bytes_limit;
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen *limit = strtoll(value, &p, 10);
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen } else if (strcmp(key, "messages") == 0) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen limit = &rule->count_limit;
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen *limit = strtoll(value, &p, 10);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen } else {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen *error_r = p_strdup_printf(root_set->set->pool,
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen "Unknown rule limit name: %s", key);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return -1;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen switch (i_toupper(*p)) {
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen case '\0':
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen /* default */
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen break;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen case 'B':
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen multiply = 1;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen break;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen case 'K':
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen multiply = 1024;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen break;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen case 'M':
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen multiply = 1024*1024;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen break;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen case 'G':
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen multiply = 1024*1024*1024;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen break;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen case 'T':
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen multiply = 1024ULL*1024*1024*1024;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen break;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen case '%':
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen multiply = 0;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (quota_rule_parse_percentage(root_set, rule, limit,
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen error_r) < 0)
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen return -1;
a449ed9df03e9f7e93d1ec278754416ac3ad9073Timo Sirainen break;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen default:
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen *error_r = p_strdup_printf(root_set->set->pool,
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen "Invalid rule limit value: %s", *args);
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return -1;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen *limit *= multiply;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen }
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen if (!relative_rule) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (rule->bytes_limit < 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen *error_r = "Bytes limit can't be negative";
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return -1;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (rule->count_limit < 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen *error_r = "Count limit can't be negative";
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return -1;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen return 0;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen}
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenint quota_root_add_rule(struct quota_root_settings *root_set,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen const char *rule_def, const char **error_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_rule *rule;
94e1adead9faddec88a623485b9999a87b1684faTimo Sirainen const char *p, *mailbox_name;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret = 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen p = strchr(rule_def, ':');
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen if (p == NULL) {
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen *error_r = "Invalid rule";
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* <mailbox name>:<quota limits> */
f3bf2314198da2877ce640360581a61d60c90991Timo Sirainen mailbox_name = t_strdup_until(rule_def, p++);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen rule = quota_root_rule_find(root_set, mailbox_name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (rule == NULL) {
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen if (strcmp(mailbox_name, RULE_NAME_DEFAULT_NONFORCE) == 0)
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen rule = &root_set->default_rule;
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen else if (strcmp(mailbox_name, RULE_NAME_DEFAULT_FORCE) == 0) {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen rule = &root_set->default_rule;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen root_set->force_default_rule = TRUE;
7ca2a9f1cca63cbc2ebffc185c7e5a2b32bc2780Timo Sirainen } else {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen rule = array_append_space(&root_set->rules);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen rule->mailbox_name =
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen p_strdup(root_set->set->pool, mailbox_name);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen if (strcmp(p, "ignore") == 0) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen rule->ignore = TRUE;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (root_set->set->debug) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("Quota rule: root=%s mailbox=%s ignored",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk root_set->name, mailbox_name);
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen return 0;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen if (strncmp(p, "backend=", 8) == 0) {
4316355ca8b7698516272520a972291378698140Timo Sirainen if (root_set->backend->v.parse_rule == NULL) {
4316355ca8b7698516272520a972291378698140Timo Sirainen *error_r = "backend rule not supported";
4316355ca8b7698516272520a972291378698140Timo Sirainen ret = -1;
4316355ca8b7698516272520a972291378698140Timo Sirainen } else if (!root_set->backend->v.parse_rule(root_set, rule,
4316355ca8b7698516272520a972291378698140Timo Sirainen p + 8, error_r))
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen ret = -1;
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen } else {
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen bool relative_rule = rule != &root_set->default_rule;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
5183f82691b9c6e5707d93fe57336cd89462d574Timo Sirainen if (quota_rule_parse_limits(root_set, rule, p, rule_def,
4f2315ea4a94311340fc73cb563f61f02dbf29deTimo Sirainen relative_rule, error_r) < 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = -1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen quota_root_recalculate_relative_rules(root_set,
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen root_set->default_rule.bytes_limit,
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen root_set->default_rule.count_limit);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (root_set->set->debug) {
de2e4c8fd028e8318e77e7f9afedaf2dc06fff33Timo Sirainen const char *rule_plus =
de2e4c8fd028e8318e77e7f9afedaf2dc06fff33Timo Sirainen rule == &root_set->default_rule ? "" : "+";
de2e4c8fd028e8318e77e7f9afedaf2dc06fff33Timo Sirainen
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("Quota rule: root=%s mailbox=%s "
de2e4c8fd028e8318e77e7f9afedaf2dc06fff33Timo Sirainen "bytes=%s%lld%s messages=%s%lld%s",
de2e4c8fd028e8318e77e7f9afedaf2dc06fff33Timo Sirainen root_set->name, mailbox_name,
de2e4c8fd028e8318e77e7f9afedaf2dc06fff33Timo Sirainen rule->bytes_limit > 0 ? rule_plus : "",
de2e4c8fd028e8318e77e7f9afedaf2dc06fff33Timo Sirainen (long long)rule->bytes_limit,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk rule->bytes_percent == 0 ? "" :
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk t_strdup_printf(" (%u%%)", rule->bytes_percent),
de2e4c8fd028e8318e77e7f9afedaf2dc06fff33Timo Sirainen rule->count_limit > 0 ? rule_plus : "",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk (long long)rule->count_limit,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk rule->count_percent == 0 ? "" :
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk t_strdup_printf(" (%u%%)", rule->count_percent));
fc84f8af4794f4bb6caf6e5ec3fb1f8cebd0462aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ret;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainenstatic int quota_root_get_rule_limits(struct quota_root *root,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen const char *mailbox_name,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen uint64_t *bytes_limit_r,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen uint64_t *count_limit_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_rule *rule;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int64_t bytes_limit, count_limit;
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen bool enabled;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen if (!root->set->force_default_rule) {
faeaff460d763bb4b574d31d78773f91aaba5510Timo Sirainen if (root->backend.v.init_limits != NULL) {
faeaff460d763bb4b574d31d78773f91aaba5510Timo Sirainen if (root->backend.v.init_limits(root) < 0)
faeaff460d763bb4b574d31d78773f91aaba5510Timo Sirainen return -1;
faeaff460d763bb4b574d31d78773f91aaba5510Timo Sirainen }
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen }
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen bytes_limit = root->bytes_limit;
b1678954f83e1059b981e2def52a70054fa71399Timo Sirainen count_limit = root->count_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen /* if default rule limits are 0, user has unlimited quota.
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen ignore any specific quota rules */
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen enabled = bytes_limit != 0 || count_limit != 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen (void)mail_namespace_find_unalias(root->quota->user->namespaces,
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen &mailbox_name);
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen rule = enabled ? quota_root_rule_find(root->set, mailbox_name) : NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (rule != NULL) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen if (!rule->ignore) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen bytes_limit += rule->bytes_limit;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen count_limit += rule->count_limit;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen } else {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen bytes_limit = 0;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen count_limit = 0;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *bytes_limit_r = bytes_limit <= 0 ? 0 : bytes_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *count_limit_r = count_limit <= 0 ? 0 : count_limit;
426e50e7647009bb22db67d9012043f0a59e7452Timo Sirainen return enabled ? 1 : 0;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid quota_add_user_namespace(struct quota *quota, struct mail_namespace *ns)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mail_namespace *const *namespaces;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_backend **backends;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen const char *path, *path2;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, j, count;
ccd44abfe14f51cc1f6d8c0ec1aa6dc31242e2d3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* first check if there already exists a namespace with the exact same
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen path. we don't want to count them twice. */
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen path = mailbox_list_get_root_path(ns->list, MAILBOX_LIST_PATH_TYPE_MAILBOX);
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen if (path != NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen namespaces = array_get(&quota->namespaces, &count);
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen for (i = 0; i < count; i++) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen path2 = mailbox_list_get_root_path(namespaces[i]->list,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
0d5689dfa8efb1d92258f44a3a60e2bef06a3a68Timo Sirainen if (path2 != NULL && strcmp(path, path2) == 0) {
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen /* duplicate */
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen return;
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen }
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen }
de5c7c99783cd86f3bdbc057345cbee923b51a20Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_append(&quota->namespaces, &ns, 1);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* @UNSAFE: get different backends into one array */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen backends = t_new(struct quota_backend *, count + 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (j = 0; backends[j] != NULL; j++) {
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen if (backends[j]->name == roots[i]->backend.name)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (backends[j] == NULL)
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen backends[j] = &roots[i]->backend;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; backends[i] != NULL; i++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (backends[i]->v.namespace_added != NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen backends[i]->v.namespace_added(quota, ns);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenvoid quota_remove_user_namespace(struct mail_namespace *ns)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota *quota;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mail_namespace *const *namespaces;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota = ns->owner != NULL ?
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(ns->owner) :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(ns->user);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (quota == NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* no quota for this namespace */
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen return;
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen }
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen namespaces = array_get(&quota->namespaces, &count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (namespaces[i] == ns) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen array_delete(&quota->namespaces, i, 1);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenint quota_root_add_warning_rule(struct quota_root_settings *root_set,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen const char *rule_def, const char **error_r)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_warning_rule *warning;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_rule rule;
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen const char *p, *q;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen int ret;
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen bool reverse = FALSE;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen p = strchr(rule_def, ' ');
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen if (p == NULL || p[1] == '\0') {
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen *error_r = "No command specified";
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen if (*rule_def == '+') {
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen /* warn when exceeding quota */
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen q = rule_def+1;
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen } else if (*rule_def == '-') {
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen /* warn when going below quota */
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen q = rule_def+1;
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen reverse = TRUE;
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen } else {
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen /* default: same as '+' */
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen q = rule_def;
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen }
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen memset(&rule, 0, sizeof(rule));
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen ret = quota_rule_parse_limits(root_set, &rule, t_strdup_until(q, p),
5183f82691b9c6e5707d93fe57336cd89462d574Timo Sirainen rule_def, FALSE, error_r);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (ret < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen warning = array_append_space(&root_set->warning_rules);
8ba29b2d23453ee632efc721f3bf2e2433896296Timo Sirainen warning->command = p_strdup(root_set->set->pool, p+1);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen warning->rule = rule;
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen warning->reverse = reverse;
337d77f9903bf56ccd686479dffaf6069991edf2Timo Sirainen
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen quota_root_recalculate_relative_rules(root_set,
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen root_set->default_rule.bytes_limit,
d761c26f2bbf514e0fc0c6ed9bc52627a4179eabTimo Sirainen root_set->default_rule.count_limit);
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (root_set->set->debug) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("Quota warning: bytes=%llu%s "
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen "messages=%llu%s reverse=%s command=%s",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk (unsigned long long)warning->rule.bytes_limit,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk warning->rule.bytes_percent == 0 ? "" :
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk t_strdup_printf(" (%u%%)", warning->rule.bytes_percent),
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk (unsigned long long)warning->rule.count_limit,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk warning->rule.count_percent == 0 ? "" :
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk t_strdup_printf(" (%u%%)", warning->rule.count_percent),
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen warning->reverse ? "yes" : "no",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk warning->command);
337d77f9903bf56ccd686479dffaf6069991edf2Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root_iter *
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenquota_root_iter_init(struct mailbox *box)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root_iter *iter;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen iter = i_new(struct quota_root_iter, 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen iter->quota = box->list->ns->owner != NULL ?
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(box->list->ns->owner) :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(box->list->ns->user);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen iter->box = box;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return iter;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenbool quota_root_is_namespace_visible(struct quota_root *root,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mail_namespace *ns)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen{
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen struct mailbox_list *list = ns->list;
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen struct mail_storage *storage;
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen /* this check works as long as there is only one storage per list */
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen if (mailbox_list_get_storage(&list, "", &storage) == 0 &&
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen (storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NOQUOTA) != 0)
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen return FALSE;
40c24f8fe31037b61f2ac594a6dfcd123080b4b5Timo Sirainen
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen if (root->ns != NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (root->ns != ns)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return FALSE;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen } else {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (ns->owner == NULL)
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return FALSE;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen }
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return TRUE;
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen}
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainenstatic bool
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainenquota_root_is_visible(struct quota_root *root, struct mailbox *box,
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen bool enforce)
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen{
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (root->no_enforcing && enforce) {
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen /* we don't want to include this root in quota enforcing */
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen return FALSE;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (!quota_root_is_namespace_visible(root, box->list->ns))
2d8b23805db6f06b8b38174fb6e135386694f429Timo Sirainen return FALSE;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (array_count(&root->quota->roots) == 1) {
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen /* a single quota root: don't bother checking further */
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen return TRUE;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen }
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen return root->backend.v.match_box == NULL ? TRUE :
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen root->backend.v.match_box(root, box);
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen}
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstruct quota_root *quota_root_iter_next(struct quota_root_iter *iter)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots, *root = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t value, limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&iter->quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (iter->i >= count)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (; iter->i < count; iter->i++) {
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (!quota_root_is_visible(roots[iter->i], iter->box, FALSE))
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen continue;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen ret = roots[iter->i]->resource_ret;
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen if (ret == -1) {
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen ret = quota_get_resource(roots[iter->i], "",
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen QUOTA_NAME_STORAGE_KILOBYTES,
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen &value, &limit);
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret == 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ret = quota_get_resource(roots[iter->i], "",
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen QUOTA_NAME_MESSAGES,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen &value, &limit);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
0e5819a061034f1636b124c03a89f67d37c852b1Timo Sirainen roots[iter->i]->resource_ret = ret;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret > 0) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root = roots[iter->i];
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen iter->i++;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return root;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_root_iter_deinit(struct quota_root_iter **_iter)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen struct quota_root_iter *iter = *_iter;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen *_iter = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_free(iter);
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenstruct quota_root *quota_root_lookup(struct mail_user *user, const char *name)
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen struct quota *quota;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen unsigned int i, count;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen quota = quota_get_mail_user_quota(user);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&quota->roots, &count);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen for (i = 0; i < count; i++) {
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen if (strcmp(roots[i]->set->name, name) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return roots[i];
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return NULL;
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen}
4981827cb5e32cf767b7b0e3070137e6b36f42afTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenconst char *quota_root_get_name(struct quota_root *root)
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen{
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen return root->set->name;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenconst char *const *quota_root_get_resources(struct quota_root *root)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen return root->backend.v.get_resources(root);
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen}
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_get_resource(struct quota_root *root, const char *mailbox_name,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const char *name, uint64_t *value_r, uint64_t *limit_r)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t bytes_limit, count_limit;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen bool kilobytes = FALSE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen int ret;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_KILOBYTES) == 0) {
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen name = QUOTA_NAME_STORAGE_BYTES;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen kilobytes = TRUE;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen }
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* Get the value first. This call may also update quota limits if
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen they're defined externally. */
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen ret = root->backend.v.get_resource(root, name, value_r);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (ret <= 0)
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return ret;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen if (quota_root_get_rule_limits(root, mailbox_name,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen &bytes_limit, &count_limit) < 0)
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen return -1;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *limit_r = bytes_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *limit_r = count_limit;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *limit_r = 0;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (kilobytes) {
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen *value_r /= 1024;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen *limit_r /= 1024;
e392fcb39a06609af20a9e79017683f194de3ddeTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen return *limit_r == 0 ? 0 : 1;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenint quota_set_resource(struct quota_root *root ATTR_UNUSED,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen const char *name ATTR_UNUSED,
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen uint64_t value ATTR_UNUSED, const char **error_r)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* the quota information comes from userdb (or even config file),
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen so there's really no way to support this until some major changes
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen are done */
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen *error_r = MAIL_ERRSTR_NO_PERMISSION;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return -1;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainenstruct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_transaction_context *ctx;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx = i_new(struct quota_transaction_context, 1);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ctx->quota = box->list->ns->owner != NULL ?
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(box->list->ns->owner) :
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen quota_get_mail_user_quota(box->list->ns->user);
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen i_assert(ctx->quota != NULL);
6b43203878bd3c87f5ae690617a1cbc694e24c01Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->box = box;
30ad2b0309119501efad06c72ec9b1561b90d4afTimo Sirainen ctx->bytes_ceil = (uint64_t)-1;
30ad2b0309119501efad06c72ec9b1561b90d4afTimo Sirainen ctx->count_ceil = (uint64_t)-1;
97daba82224dd757b7b7526ab3fd5d574a5f35d8Timo Sirainen
97daba82224dd757b7b7526ab3fd5d574a5f35d8Timo Sirainen if (box->storage->user->admin) {
97daba82224dd757b7b7526ab3fd5d574a5f35d8Timo Sirainen /* ignore quota for admins */
97daba82224dd757b7b7526ab3fd5d574a5f35d8Timo Sirainen ctx->limits_set = TRUE;
97daba82224dd757b7b7526ab3fd5d574a5f35d8Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return ctx;
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen}
1795e934ebcd58175d3b5bbdd811b13c7889efa3Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainenstatic int quota_transaction_set_limits(struct quota_transaction_context *ctx)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen{
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen struct quota_root *const *roots;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen const char *mailbox_name;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen unsigned int i, count;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen uint64_t bytes_limit, count_limit, current, limit, diff;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen int ret;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen ctx->limits_set = TRUE;
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen mailbox_name = mailbox_get_vname(ctx->box);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen /* find the lowest quota limits from all roots and use them */
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen roots = array_get(&ctx->quota->roots, &count);
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen for (i = 0; i < count; i++) {
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (!quota_root_is_visible(roots[i], ctx->box, TRUE))
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen continue;
d5d23d5ff8b7a06d2ead489ddcf55ee8fb5ca7b6Timo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen if (quota_root_get_rule_limits(roots[i], mailbox_name,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen &bytes_limit,
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen &count_limit) < 0) {
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen ctx->failed = TRUE;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen return -1;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen }
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen if (bytes_limit > 0) {
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen QUOTA_NAME_STORAGE_BYTES,
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen &current, &limit);
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen if (ret > 0) {
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (limit < current) {
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->bytes_ceil = 0;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen diff = current - limit;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (ctx->bytes_over < diff)
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->bytes_over = diff;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen } else {
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen diff = limit - current;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (ctx->bytes_ceil > diff)
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->bytes_ceil = diff;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen }
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen } else if (ret < 0) {
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen ctx->failed = TRUE;
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen return -1;
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen if (count_limit > 0) {
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen ret = quota_get_resource(roots[i], mailbox_name,
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen QUOTA_NAME_MESSAGES,
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen &current, &limit);
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen if (ret > 0) {
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (limit < current) {
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->count_ceil = 0;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen diff = current - limit;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (ctx->count_over < diff)
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->count_over = diff;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen } else {
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen diff = limit - current;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen if (ctx->count_ceil > diff)
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen ctx->count_ceil = diff;
269370f66e320a071700e33d9f2584eb46d96a90Timo Sirainen }
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen } else if (ret < 0) {
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen ctx->failed = TRUE;
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen return -1;
7db5ff0dd17c40711bfaa0375aa5cc7f822a82f2Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return 0;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen}
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b40d1ef77181fda648e2ba22188c91a124f5bee6Timo Sirainenstatic void quota_warning_execute(struct quota_root *root, const char *cmd)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen const char *socket_path, *const *args;
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen string_t *str;
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen int fd;
b40d1ef77181fda648e2ba22188c91a124f5bee6Timo Sirainen
b40d1ef77181fda648e2ba22188c91a124f5bee6Timo Sirainen if (root->quota->set->debug)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("quota: Executing warning: %s", cmd);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
4f68fa8a117642e2c134a29d8e35569bce6c3158Timo Sirainen args = t_strsplit_spaces(cmd, " ");
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen socket_path = args[0];
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen args++;
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen if (*socket_path != '/') {
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen socket_path = t_strconcat(root->quota->user->set->base_dir, "/",
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen socket_path, NULL);
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen }
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen if ((fd = net_connect_unix_with_retries(socket_path, 1000)) < 0) {
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen if (errno == EACCES) {
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen i_error("quota: %s",
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen eacces_error_get("net_connect_unix",
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen socket_path));
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen } else {
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen i_error("quota: net_connect_unix(%s) failed: %m",
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen socket_path);
596ec384269cad3b0f0661df89b9cf33cbd171b7Timo Sirainen }
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen str = t_str_new(1024);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen str_append(str, "VERSION\tscript\t3\t0\nnoreply\n");
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen for (; *args != NULL; args++) {
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen str_append(str, *args);
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen str_append_c(str, '\n');
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen }
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen str_append_c(str, '\n');
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen net_set_nonblock(fd, FALSE);
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen if (write_full(fd, str_data(str), str_len(str)) < 0)
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen i_error("write(%s) failed: %m", socket_path);
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen if (close(fd) < 0)
76a99afe0914951d20d96e0bf5e6d8d3ea3fd503Timo Sirainen i_error("close(%s) failed: %m", socket_path);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainenstatic bool
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainenquota_warning_match(const struct quota_warning_rule *w,
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen uint64_t bytes_before, uint64_t bytes_current,
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen uint64_t count_before, uint64_t count_current)
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen{
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen#define QUOTA_EXCEEDED(before, current, limit) \
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen ((before) < (uint64_t)(limit) && (current) >= (uint64_t)(limit))
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen if (!w->reverse) {
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen /* over quota (default) */
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen return QUOTA_EXCEEDED(bytes_before, bytes_current, w->rule.bytes_limit) ||
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen QUOTA_EXCEEDED(count_before, count_current, w->rule.count_limit);
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen } else {
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen return QUOTA_EXCEEDED(bytes_current, bytes_before, w->rule.bytes_limit) ||
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen QUOTA_EXCEEDED(count_current, count_before, w->rule.count_limit);
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen }
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen}
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainenstatic void quota_warnings_execute(struct quota_transaction_context *ctx,
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen struct quota_root *root)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_warning_rule *warnings;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen unsigned int i, count;
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen uint64_t bytes_current, bytes_before, bytes_limit;
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen uint64_t count_current, count_before, count_limit;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen warnings = array_get_modifiable(&root->set->warning_rules, &count);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (count == 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen &bytes_current, &bytes_limit) < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (quota_get_resource(root, "", QUOTA_NAME_MESSAGES,
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen &count_current, &count_limit) < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen bytes_before = bytes_current - ctx->bytes_used;
20dd6f6726db692904794d7daafe5b6e7238b720Timo Sirainen count_before = count_current - ctx->count_used;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen for (i = 0; i < count; i++) {
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen if (quota_warning_match(&warnings[i],
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen bytes_before, bytes_current,
ad4f1b0666975c57dd2d8d3492b223ec814791cdTimo Sirainen count_before, count_current)) {
b40d1ef77181fda648e2ba22188c91a124f5bee6Timo Sirainen quota_warning_execute(root, warnings[i].command);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen break;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenint quota_transaction_commit(struct quota_transaction_context **_ctx)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_transaction_context *ctx = *_ctx;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen struct quota_rule *rule;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_root *const *roots;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen unsigned int i, count;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen const char *mailbox_name;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen int ret = 0;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen *_ctx = NULL;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (ctx->failed)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen ret = -1;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen else if (ctx->bytes_used != 0 || ctx->count_used != 0 ||
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen ctx->recalculate) T_BEGIN {
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen ARRAY_DEFINE(warn_roots, struct quota_root *);
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen
eafecb7ad0fbbde0da8be7e8ae735459b7bb688bTimo Sirainen mailbox_name = mailbox_get_vname(ctx->box);
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen (void)mail_namespace_find_unalias(
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen ctx->box->storage->user->namespaces, &mailbox_name);
b089505afb8b5c5dfb43ef88af0ea7e0920db587Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen roots = array_get(&ctx->quota->roots, &count);
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen t_array_init(&warn_roots, count);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen for (i = 0; i < count; i++) {
89adb28d8f041e8c0b9c5156f089bb2f8f478ee3Timo Sirainen if (!quota_root_is_visible(roots[i], ctx->box, FALSE))
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen continue;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen rule = quota_root_rule_find(roots[i]->set,
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen mailbox_name);
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen if (rule != NULL && rule->ignore) {
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen /* mailbox not included in quota */
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen continue;
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen }
2b682d8d3661800f16aceaa45fa4de9b6b140a59Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen if (roots[i]->backend.v.update(roots[i], ctx) < 0)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen ret = -1;
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen else
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen array_append(&warn_roots, &roots[i], 1);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen }
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen /* execute quota warnings after all updates. this makes it
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen work correctly regardless of whether backend.get_resource()
d8548e14925a06e44c4f1983d7b118b0180939e0Timo Sirainen returns updated values before backend.update() or not */
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen array_foreach(&warn_roots, roots)
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen quota_warnings_execute(ctx, *roots);
968aab2a00d1b53a53854fc2e97d1c632171a54eTimo Sirainen } T_END;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen i_free(ctx);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen return ret;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainenvoid quota_transaction_rollback(struct quota_transaction_context **_ctx)
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen{
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen struct quota_transaction_context *ctx = *_ctx;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen *_ctx = NULL;
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen i_free(ctx);
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen}
503e5ef896c7b4a51cf73efb0d132860a8c747e6Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_try_alloc(struct quota_transaction_context *ctx,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail *mail, bool *too_large_r)
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen{
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen uoff_t size;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen int ret;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_physical_size(mail, &size) < 0)
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen return -1;
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen ret = quota_test_alloc(ctx, size, too_large_r);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (ret <= 0)
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen return ret;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen quota_alloc(ctx, mail);
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen return 1;
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen}
f6f94063c4c3080280b87ab47ac2bb756ba002f9Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenint quota_test_alloc(struct quota_transaction_context *ctx,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uoff_t size, bool *too_large_r)
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen{
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (ctx->failed)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return -1;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (!ctx->limits_set) {
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen if (quota_transaction_set_limits(ctx) < 0)
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen return -1;
b2e181e33889f0a4a3ba9dc23d676cbfe1bf7782Timo Sirainen }
d23c747de9d33966483fbdd41f08ad7766da7c5cTimo Sirainen return ctx->quota->set->test_alloc(ctx, size, too_large_r);
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen}
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainenstatic int quota_default_test_alloc(struct quota_transaction_context *ctx,
3fe44a0df5a0bdd80c495f79cbf0e384441d6fccTimo Sirainen uoff_t size, bool *too_large_r)
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen int ret;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *too_large_r = FALSE;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
723c3049be35a0e1019f9a84d69cb96924ee5064Timo Sirainen if ((ctx->count_used < 0 ||
723c3049be35a0e1019f9a84d69cb96924ee5064Timo Sirainen (uint64_t)ctx->count_used + 1 <= ctx->count_ceil) &&
723c3049be35a0e1019f9a84d69cb96924ee5064Timo Sirainen ((ctx->bytes_used < 0 && size <= ctx->bytes_ceil) ||
723c3049be35a0e1019f9a84d69cb96924ee5064Timo Sirainen (uint64_t)ctx->bytes_used + size <= ctx->bytes_ceil))
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 1;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
30ad2b0309119501efad06c72ec9b1561b90d4afTimo Sirainen /* limit reached. only thing left to do now is to set too_large_r. */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&ctx->quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen uint64_t bytes_limit, count_limit;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (!quota_root_is_visible(roots[i], ctx->box, TRUE))
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen continue;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen ret = quota_root_get_rule_limits(roots[i],
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen mailbox_get_vname(ctx->box),
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen &bytes_limit, &count_limit);
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen if (ret == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen continue;
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen if (ret < 0)
cb931f84e3ec8e3deda253a1c0ae0409023de096Timo Sirainen return -1;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* if size is bigger than any limit, then
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen it is bigger than the lowest limit */
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (size > bytes_limit) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen *too_large_r = TRUE;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen break;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return 0;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_alloc(struct quota_transaction_context *ctx, struct mail *mail)
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen{
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen uoff_t size;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_physical_size(mail, &size) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->bytes_used += size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->count_used++;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenvoid quota_free(struct quota_transaction_context *ctx, struct mail *mail)
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen{
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen uoff_t size;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen
83bb013a99f0936995f9c7a1077822662d8fefdbTimo Sirainen if (mail_get_physical_size(mail, &size) < 0)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_recalculate(ctx);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen else
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen quota_free_bytes(ctx, size);
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_free_bytes(struct quota_transaction_context *ctx,
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen uoff_t physical_size)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ctx->bytes_used -= physical_size;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen ctx->count_used--;
6800c6607013d4fdef5a4f764bae407301c6cce8Timo Sirainen}
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainenvoid quota_recalculate(struct quota_transaction_context *ctx)
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen{
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen ctx->recalculate = TRUE;
bd7b1a9000b12349e2a99bb43b3ce8b96a18e92bTimo Sirainen}