dovecot
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
January 2008
- 204 participants
- 212 discussions
Hi,
can someone confirm returning "maildir:storage=0" from userdb will
effectively disable the quota check for *this* user ?
if not what's the way to do it ?
thanks
frederic beuserie
2
1
I wanted to know if more than one INBOX - entry is possible.
My situation:
Three users with user@domain
One Mail-Adress office@domain, where all three users can get the mails.
But i dont want to copy the mails from office to the user (like
mailinglist), because if one reads a new mail it should be marked as
read at all users. Same with answered and deleted.
Thanks in advance,
Christian
3
2
Hi People
I have a two question
I use dovecot 1.0.10
I have quota maildir
1- I want to use the last version of quota 1.1 in my dovecot , i have to patch
then, so which file i have to apply ?
http://dovecot.org/patches/1.0/
this one quota-rewrite-1.0.9.diff ???
When i using the original version with out quota new 1.1 , in my mailbox is
created a file called maildirsize with the quota , but when a apply the patch
the quota this stop work for me.
2- if is posible define a quota per domain?
%n(a)domain1.com = 100M
%n(a)domain2.com = 0 --- no limit quota
or
@domain1.com = 100M
@domain2.com = 0 --- no limit quota
Once again , sorry for my english
Thanks
2
1
[Dovecot] deliver can't connect to auth server at */usr/local*/var/run/dovecot/auth-master
by Andreas Ntaflos 20 Jan '08
by Andreas Ntaflos 20 Jan '08
20 Jan '08
Hello list,
while fiddling around with the configuration so Dovecot's LDA "deliver" can be
used by multiple users by means of Getmail (you can read about that in [1]) I
always end up running into the error message posted in the subject line:
Jan 15 00:00:02 HOSTNAME deliver(USERID): Can't connect to auth server
at /usr/local/var/run/dovecot/auth-master: Permission denied
Notice how it says "/usr/local/var/run/dovecot"! How and why does dovecot
^^^^^^^^^^
think that anything of any importance can be found under /usr/local/var/... ?
Please see dovecot -n at the end of this message, but as far as I can tell I
never ever specified that the /var directory (configure --localstatedir)
should end up under the prefix /usr/local.
Now I am quite sure that my configuration for auth-master is not yet quite
correct but I can't go any further without asking what this error message
could mean and how to resolve the problem.
Anybody have any ideas? I am currently running 1.0.10 (previously, until this
afternoon 1.0.5, same problem) with the latest MANAGESIEVE patch (v9) applied
and the dovecot-sieve plugin.
TIA for any hints! I am at a loss here.
Andreas
[1] http://thread.gmane.org/gmane.mail.imap.dovecot/27062
# 1.0.10: /usr/local/etc/dovecot.conf
base_dir: /var/run/dovecot/
protocols: imap imaps pop3 pop3s managesieve
listen(default): *
listen(imap): *
listen(pop3): *
listen(managesieve): *:2000
ssl_cert_file: /etc/ssl/certs/DOMAINNAME.crt
ssl_key_file: /etc/ssl/private/DOMAINNAME.key
login_dir: /var/run/dovecot//login
login_executable(default): /usr/local/libexec/dovecot/imap-login
login_executable(imap): /usr/local/libexec/dovecot/imap-login
login_executable(pop3): /usr/local/libexec/dovecot/pop3-login
login_executable(managesieve): /usr/local/libexec/dovecot/managesieve-login
mail_extra_groups: mail
mail_location: maildir:~/Maildir
maildir_copy_with_hardlinks: yes
mail_executable(default): /usr/local/libexec/dovecot/imap
mail_executable(imap): /usr/local/libexec/dovecot/imap
mail_executable(pop3): /usr/local/libexec/dovecot/pop3
mail_executable(managesieve): /usr/local/libexec/dovecot/managesieve
mail_plugin_dir(default): /usr/local/lib/dovecot/imap
mail_plugin_dir(imap): /usr/local/lib/dovecot/imap
mail_plugin_dir(pop3): /usr/local/lib/dovecot/pop3
mail_plugin_dir(managesieve): /usr/local/lib/dovecot/managesieve
imap_client_workarounds(default): outlook-idle delay-newmail
tb-extra-mailbox-sep
imap_client_workarounds(imap): outlook-idle delay-newmail tb-extra-mailbox-sep
imap_client_workarounds(pop3): outlook-idle
imap_client_workarounds(managesieve): outlook-idle
pop3_uidl_format(default):
pop3_uidl_format(imap):
pop3_uidl_format(pop3): %08Xu%08Xv
pop3_uidl_format(managesieve):
namespace:
type: public
separator: /
prefix: Public/
location:
maildir:/var/mail/public:CONTROL=~/Maildir/control/public:INDEX=~/Maildir/index/public
namespace:
type: private
separator: /
inbox: yes
auth default:
mechanisms: login plain
verbose: yes
passdb:
driver: pam
userdb:
driver: passwd
socket:
type: listen
client:
path: /var/spool/postfix/private/auth
mode: 432
user: postfix
group: postfix
master:
path: /var/run/dovecot/auth-master
mode: 432
user: root
group: dovecot
--
Andreas "daff" Ntaflos
Vienna, Austria
GPG Fingerprint: 6234 2E8E 5C81 C6CB E5EC 7E65 397C E2A8 090C A9B4
5
6
Hello List,
i'm looking for a way to increase log-level for imap-processes. Pop3 Server
writes all necessary infos about mails-transfered/deleted etc. Imap-Log
writes just times and ip's of Userlogins.
Is there a way to increase the imap-output? The Conf-Parameters i found did
not really fit my requirements. Best result would be a collected log of
transfering/deleting mails for one imap-session.
Ist there a way to achieve this?
Thank you
Andre
2
3
[Dovecot] quota_wrning not working for me (quota_rewrite patch for dovecot 1.0.8)
by Juan C. Blanco 20 Jan '08
by Juan C. Blanco 20 Jan '08
20 Jan '08
Hello, We are using dovecot 1.0.8 with LDAP authentication and extra
variebles (like quota limit) storage.
Since some of our users are asking for warning of quota use I have been
playing around with the quota rewrite patch for dovecot 1.0.8 and found
that it does not work for us as it is now.
I've applied the patch recompiled dovecot reconfigured using the new
"quota_warning" options for a test user with a 10MB quota and warning
limits in the 45 and 50 percent.
The script for the warnings was never executed and then I've done some
debugging with the code and found two different problems (well, at least
I think that there are two problems but I may be wrong)
The first problem is with the parsing of percentage limits in the
quota_warning options. The function "quota_rule_parse_percentage" was
using the same value for the variables "percentage" and "*limit" and
then the calculated value is not a percentage of the default quota rule
limit but of the percentage itself (i.e. using a 80% limit returns a
value of 64 for the internal saved limit, instead of 80% of the default
rule value). In my sample a 50% limit returned a value of 25 bytes for
the limit instead of 5,120.
The other problem is when checking the limits to execute the scripts,
the "quota_warnings_execute" function is checking if the warning limit
is reached with this comparison:
if ((bytes_current < warnings[i].bytes_limit &&
bytes_current +
ctx->bytes_used >= warnings[i].bytes_limit) || ...
My debug have reported that at the point of the execution of this
function the "bytes_current" variable already includes the size of the
current transaction (at least it was in all my tests) and then the first
part of the comparison (that we are under the limit prior to this
transaction)is false.
I've changed this to:
if ((bytes_current -
ctx->bytes_used < warnings[i].bytes_limit &&
bytes_current >= warnings[i].bytes_limit) || ...
I've included the modified patch in this messag but since this is my
first contact with dovecot code I'm not sure enough if the problems was
with the code or if it was my fault.
There is someone using the quota-rewrite patch and can confirm if it was
working fine?.
Can the author of the original patch take a look at it and confirm if
I'm wrong or my changes are valid
I don't have a Dovecot 1.1 working here and can not verify if the
problems occurs also with this vesion, however the code seems the same
after a quick look at it and I think that may be usefull to recheck the
code prior to the RC stage.
Regards
Juan C. Blanco
--
+----------------------------------------------------------------+
| Juan C. Blanco |
| |
| Centro de Calculo | |
| Facultad de Informatica U.P.M. | E-mail: jcblanco(a)fi.upm.es |
| Campus de Montegancedo | |
| Boadilla del Monte | Tel.: (+34) 91 336 7466 |
| 28660 MADRID (Spain) | Fax : (+34) 91 336 6913 |
+----------------------------------------------------------------+
diff -ru dovecot-1.0/dovecot-example.conf dovecot-1.0-quotarewrite/dovecot-example.conf
--- dovecot-1.0/dovecot-example.conf 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/dovecot-example.conf 2007-11-27 05:42:11.000000000 +0200
@@ -1031,6 +1031,27 @@
# dict: Keep quota stored in dictionary (eg. SQL)
# maildir: Maildir++ quota
# fs: Read-only support for filesystem quota
+ #
+ # Quota limits are set using "quota_rule" parameters, either in here or in
+ # userdb. It's also possible to give mailbox-specific limits, for example:
+ # quota_rule = *:storage=1048576
+ # quota_rule2 = Trash:storage=102400
+ # User has now 1GB quota, but when saving to Trash mailbox the user gets
+ # additional 100MB.
+ #
+ # Multiple quota roots are also possible, for example:
+ # quota = dict:user::proxy::quota
+ # quota2 = dict:domain:%d:proxy::quota_domain
+ # quota_rule = *:storage=102400
+ # quota2_rule = *:storage=1048576
+ # Gives each user their own 100MB quota and one shared 1GB quota within
+ # the domain.
+ #
+ # You can execute a given command when user exceeds a specified quota limit.
+ # Each quota root has separate limits. Only the command for the first
+ # exceeded limit is excecuted, so put the highest limit first.
+ # quota_warning = storage=95% /usr/local/bin/quota-warning.sh 95
+ # quota_warning2 = storage=80% /usr/local/bin/quota-warning.sh 80
#quota = maildir
# ACL plugin. vfile backend reads ACLs from "dovecot-acl" file from maildir
diff -ru dovecot-1.0/src/plugins/imap-quota/imap-quota-plugin.c dovecot-1.0-quotarewrite/src/plugins/imap-quota/imap-quota-plugin.c
--- dovecot-1.0/src/plugins/imap-quota/imap-quota-plugin.c 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/imap-quota/imap-quota-plugin.c 2007-07-27 13:18:23.000000000 +0300
@@ -30,7 +30,7 @@
str_append(str, " (");
list = quota_root_get_resources(root);
for (i = 0; *list != NULL; list++) {
- ret = quota_get_resource(root, *list, &value, &limit);
+ ret = quota_get_resource(root, "", *list, &value, &limit);
if (ret > 0) {
if (i > 0)
str_append_c(str, ' ');
@@ -39,8 +39,8 @@
(unsigned long long)limit);
i++;
} else if (ret < 0) {
- client_send_line(cmd->client, t_strconcat(
- "* BAD ", quota_last_error(quota_set), NULL));
+ client_send_line(cmd->client,
+ "* BAD Internal quota calculation error");
}
}
str_append_c(str, ')');
@@ -86,7 +86,7 @@
str_append(str, "* QUOTAROOT ");
imap_quote_append_string(str, orig_mailbox, FALSE);
- iter = quota_root_iter_init(box);
+ iter = quota_root_iter_init(quota_set, box);
while ((root = quota_root_iter_next(iter)) != NULL) {
str_append_c(str, ' ');
imap_quote_append_string(str, quota_root_get_name(root), FALSE);
@@ -95,7 +95,7 @@
client_send_line(cmd->client, str_c(str));
/* send QUOTA reply for each quotaroot */
- iter = quota_root_iter_init(box);
+ iter = quota_root_iter_init(quota_set, box);
while ((root = quota_root_iter_next(iter)) != NULL)
quota_send(cmd, root);
quota_root_iter_deinit(iter);
@@ -135,7 +135,7 @@
{
struct quota_root *root;
struct imap_arg *args, *arg;
- const char *root_name, *name;
+ const char *root_name, *name, *error;
uint64_t value;
/* <quota root> <resource limits> */
@@ -169,9 +169,8 @@
}
value = strtoull(IMAP_ARG_STR_NONULL(&arg[1]), NULL, 10);
- if (quota_set_resource(root, name, value) < 0) {
- client_send_command_error(cmd,
- quota_last_error(quota_set));
+ if (quota_set_resource(root, name, value, &error) < 0) {
+ client_send_command_error(cmd, error);
return TRUE;
}
}
diff -ru dovecot-1.0/src/plugins/imap-quota/Makefile.am dovecot-1.0-quotarewrite/src/plugins/imap-quota/Makefile.am
--- dovecot-1.0/src/plugins/imap-quota/Makefile.am 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/imap-quota/Makefile.am 2007-07-27 13:18:23.000000000 +0300
@@ -8,12 +8,12 @@
imap_moduledir = $(moduledir)/imap
-lib11_imap_quota_plugin_la_LDFLAGS = -module -avoid-version
+lib12_imap_quota_plugin_la_LDFLAGS = -module -avoid-version
imap_module_LTLIBRARIES = \
- lib11_imap_quota_plugin.la
+ lib12_imap_quota_plugin.la
-lib11_imap_quota_plugin_la_SOURCES = \
+lib12_imap_quota_plugin_la_SOURCES = \
imap-quota-plugin.c
noinst_HEADERS = \
diff -ru dovecot-1.0/src/plugins/Makefile.am dovecot-1.0-quotarewrite/src/plugins/Makefile.am
--- dovecot-1.0/src/plugins/Makefile.am 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/Makefile.am 2007-07-27 13:18:23.000000000 +0300
@@ -2,4 +2,4 @@
ZLIB = zlib
endif
-SUBDIRS = acl convert quota imap-quota lazy-expunge mail-log trash $(ZLIB)
+SUBDIRS = acl convert quota imap-quota lazy-expunge mail-log $(ZLIB)
diff -ru dovecot-1.0/src/plugins/quota/Makefile.am dovecot-1.0-quotarewrite/src/plugins/quota/Makefile.am
--- dovecot-1.0/src/plugins/quota/Makefile.am 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/Makefile.am 2007-07-27 13:18:23.000000000 +0300
@@ -14,7 +14,7 @@
lib10_quota_plugin_la_SOURCES = \
quota.c \
- quota-count.c \
+ quota-count.c \
quota-fs.c \
quota-dict.c \
quota-dirsize.c \
diff -ru dovecot-1.0/src/plugins/quota/quota.c dovecot-1.0-quotarewrite/src/plugins/quota/quota.c
--- dovecot-1.0/src/plugins/quota/quota.c 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota.c 2007-07-27 13:25:18.000000000 +0300
@@ -6,6 +6,19 @@
#include "quota-private.h"
#include "quota-fs.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+
+#define RULE_NAME_ALL_MAILBOXES "*"
+
+struct quota_root_iter {
+ struct quota *quota;
+ struct mailbox *box;
+
+ unsigned int i;
+};
+
unsigned int quota_module_id = 0;
extern struct quota_backend quota_backend_dict;
@@ -13,7 +26,7 @@
extern struct quota_backend quota_backend_fs;
extern struct quota_backend quota_backend_maildir;
-static struct quota_backend *quota_backends[] = {
+static const struct quota_backend *quota_backends[] = {
#ifdef HAVE_FS_QUOTA
"a_backend_fs,
#endif
@@ -23,449 +36,745 @@
};
#define QUOTA_CLASS_COUNT (sizeof(quota_backends)/sizeof(quota_backends[0]))
-void (*hook_quota_root_created)(struct quota_root *root);
+static int quota_default_test_alloc(struct quota_transaction_context *ctx,
+ uoff_t size, bool *too_large_r);
struct quota *quota_init(void)
{
struct quota *quota;
quota = i_new(struct quota, 1);
- ARRAY_CREATE("a->setups, default_pool, struct quota_setup *, 4);
+ quota->test_alloc = quota_default_test_alloc;
+ quota->debug = getenv("DEBUG") != NULL;
+ ARRAY_CREATE("a->roots, system_pool, struct quota_root *, 4);
+ ARRAY_CREATE("a->storages, system_pool, struct mail_storage *, 8);
+
return quota;
}
void quota_deinit(struct quota *quota)
{
- while (array_count("a->setups) > 0) {
- struct quota_setup *const *setup;
+ struct quota_root **root;
- setup = array_idx("a->setups, 0);
- quota_setup_deinit(*setup);
+ while (array_count("a->roots) > 0) {
+ root = array_idx_modifyable("a->roots, 0);
+ quota_root_deinit(*root);
}
- array_free("a->setups);
+ array_free("a->roots);
+ array_free("a->storages);
i_free(quota);
}
-struct quota_setup *
-quota_setup_init(struct quota *quota, const char *data, bool user_root)
+static const struct quota_backend *quota_backend_find(const char *name)
{
- struct quota_setup *setup;
- const char *backend_name, *p;
unsigned int i;
- setup = i_new(struct quota_setup, 1);
- setup->quota = quota;
- setup->data = i_strdup(data);
- setup->user_root = user_root;
- ARRAY_CREATE(&setup->roots, default_pool, struct quota_root *, 4);
+ for (i = 0; i < QUOTA_CLASS_COUNT; i++) {
+ if (strcmp(quota_backends[i]->name, name) == 0)
+ return quota_backends[i];
+ }
+
+ return NULL;
+}
+
+struct quota_root *quota_root_init(struct quota *quota, const char *root_def)
+{
+ struct quota_root *root;
+ const struct quota_backend *backend;
+ const char *p, *args, *backend_name;
t_push();
- p = strchr(setup->data, ':');
+
+ /* <backend>[:<quota root name>[:<backend args>]] */
+ p = strchr(root_def, ':');
if (p == NULL) {
- backend_name = setup->data;
- data = "";
+ backend_name = root_def;
+ args = NULL;
} else {
- backend_name = t_strdup_until(setup->data, p);
- data = p+1;
+ backend_name = t_strdup_until(root_def, p);
+ args = p + 1;
}
- for (i = 0; i < QUOTA_CLASS_COUNT; i++) {
- if (strcmp(quota_backends[i]->name, backend_name) == 0) {
- setup->backend = quota_backends[i];
- break;
+
+ backend = quota_backend_find(backend_name);
+ if (backend == NULL)
+ i_fatal("Unknown quota backend: %s", backend_name);
+
+ t_pop();
+
+ root = backend->v.alloc();
+ root->quota = quota;
+ root->backend = *backend;
+ root->pool = pool_alloconly_create("quota root", 512);
+
+ if (args != NULL) {
+ /* save root's name */
+ p = strchr(args, ':');
+ if (p == NULL) {
+ root->name = p_strdup(root->pool, args);
+ args = NULL;
+ } else {
+ root->name = p_strdup_until(root->pool, args, p);
+ args = p + 1;
}
+ } else {
+ root->name = "";
}
- if (setup->backend == NULL)
- i_fatal("Unknown quota backend: %s", backend_name);
+ ARRAY_CREATE(&root->rules, system_pool, struct quota_rule, 4);
+ ARRAY_CREATE(&root->warning_rules, system_pool,
+ struct quota_warning_rule, 4);
+ array_create(&root->quota_module_contexts, default_pool,
+ sizeof(void *), 5);
- t_pop();
+ array_append("a->roots, &root, 1);
- array_append("a->setups, &setup, 1);
- return setup;
+ if (backend->v.init != NULL) {
+ if (backend->v.init(root, args) < 0) {
+ quota_root_deinit(root);
+ return NULL;
+ }
+ }
+ return root;
}
-void quota_setup_deinit(struct quota_setup *setup)
+void quota_root_deinit(struct quota_root *root)
{
- struct quota_setup *const *setups;
+ pool_t pool = root->pool;
+ struct quota_root *const *roots;
+ struct quota_warning_rule *warnings;
unsigned int i, count;
- setups = array_get(&setup->quota->setups, &count);
+ roots = array_get(&root->quota->roots, &count);
for (i = 0; i < count; i++) {
- if (setups[i] == setup) {
- array_delete(&setup->quota->setups, i, 1);
- break;
- }
+ if (roots[i] == root)
+ array_delete(&root->quota->roots, i, 1);
}
- i_assert(i != count);
- while (array_count(&setup->roots) > 0) {
- struct quota_root *const *root;
+ warnings = array_get_modifyable(&root->warning_rules, &count);
+ for (i = 0; i < count; i++)
+ i_free(warnings[i].command);
+ array_free(&root->warning_rules);
- root = array_idx(&setup->roots, 0);
- quota_root_deinit(*root);
- }
+ array_free(&root->rules);
+ array_free(&root->quota_module_contexts);
- array_free(&setup->roots);
- i_free(setup->data);
- i_free(setup);
+ root->backend.v.deinit(root);
+ pool_unref(pool);
}
-struct quota_root *
-quota_root_init(struct quota_setup *setup, const char *name)
+static struct quota_rule *
+quota_root_rule_find(struct quota_root *root, const char *name)
{
- struct quota_root *root;
-
- root = setup->backend->v.init(setup, name);
- root->setup = setup;
- ARRAY_CREATE(&root->storages, default_pool, struct mail_storage *, 8);
- array_create(&root->quota_module_contexts,
- default_pool, sizeof(void *), 5);
- array_append(&setup->roots, &root, 1);
+ struct quota_rule *rules;
+ unsigned int i, count;
- if (hook_quota_root_created != NULL)
- hook_quota_root_created(root);
- return root;
+ rules = array_get_modifyable(&root->rules, &count);
+ for (i = 0; i < count; i++) {
+ if (strcmp(rules[i].mailbox_name, name) == 0)
+ return &rules[i];
+ }
+ return NULL;
}
-void quota_root_deinit(struct quota_root *root)
-{
- /* make a copy, since root is freed */
- array_t module_contexts = root->quota_module_contexts;
- struct mail_storage *const *storage_p;
- struct quota_root *const *roots;
- unsigned int i, count;
+static int
+quota_rule_parse_percentage(struct quota_root *root, struct quota_rule *rule,
+ int64_t *limit, const char **error_r)
+{
+ struct quota_rule *defrule;
+ int64_t percentage = *limit;
+
+ if (percentage < 0) {
+ *error_r = p_strdup_printf(root->pool,
+ "Invalid rule percentage: %lld", (long long)percentage);
+ return -1;
+ }
- /* remove from all storages */
- while (array_count(&root->storages) > 0) {
- storage_p = array_idx(&root->storages, 0);
- quota_mail_storage_remove_root(*storage_p, root);
+ if (rule == &root->default_rule) {
+ *error_r = "Default rule can't be a percentage";
+ return -1;
+ }
+ defrule = &root->default_rule;
+ if (defrule == NULL) {
+ *error_r = "Default rule not defined";
+ return -1;
}
- /* remove from setup */
- roots = array_get(&root->setup->roots, &count);
- for (i = 0; i < count; i++) {
- if (roots[i] == root) {
- array_delete(&root->setup->roots, i, 1);
+ if (limit == &rule->bytes_limit)
+ *limit = root->default_rule.bytes_limit * percentage / 100;
+ else if (limit == &rule->count_limit)
+ *limit = root->default_rule.count_limit * percentage / 100;
+ else
+ i_unreached();
+ return 0;
+}
+
+static int
+quota_rule_parse_limits(struct quota_root *root, struct quota_rule *rule,
+ const char *limits, const char **error_r)
+{
+ const char **args;
+ char *p;
+ uint64_t multiply;
+ int64_t *limit;
+
+ args = t_strsplit(limits, ":");
+ for (; *args != NULL; args++) {
+ multiply = 1;
+ limit = NULL;
+ if (strncmp(*args, "storage=", 8) == 0) {
+ multiply = 1024;
+ limit = &rule->bytes_limit;
+ *limit = strtoll(*args + 8, &p, 10);
+ } else if (strncmp(*args, "bytes=", 6) == 0) {
+ limit = &rule->bytes_limit;
+ *limit = strtoll(*args + 6, &p, 10);
+ } else if (strncmp(*args, "messages=", 9) == 0) {
+ limit = &rule->count_limit;
+ *limit = strtoll(*args + 9, &p, 10);
+ } else {
+ *error_r = p_strdup_printf(root->pool,
+ "Unknown rule limit name: %s", *args);
+ return -1;
+ }
+
+ switch (i_toupper(*p)) {
+ case '\0':
+ /* default */
+ break;
+ case 'B':
+ multiply = 1;
+ break;
+ case 'K':
+ multiply = 1024;
+ break;
+ case 'M':
+ multiply = 1024*1024;
break;
+ case 'G':
+ multiply = 1024*1024*1024;
+ break;
+ case 'T':
+ multiply = 1024ULL*1024*1024*1024;
+ break;
+ case '%':
+ multiply = 1;
+ if (quota_rule_parse_percentage(root, rule, limit,
+ error_r) < 0)
+ return -1;
+ break;
+ default:
+ *error_r = p_strdup_printf(root->pool,
+ "Invalid rule limit value: %s", *args);
+ return -1;
}
+ *limit *= multiply;
}
- i_assert(i != count);
-
- array_free(&root->storages);
- root->v.deinit(root);
- array_free(&module_contexts);
+ return 0;
}
-void quota_add_user_storage(struct quota *quota, struct mail_storage *storage)
+int quota_root_add_rule(struct quota_root *root, const char *rule_def,
+ const char **error_r)
{
- struct quota_setup *const *setups;
- struct quota_root *const *roots;
- unsigned int i, j, setup_count, root_count;
- bool found = FALSE;
+ struct quota_rule *rule;
+ const char *p, *mailbox_name;
+ int ret = 0;
- setups = array_get("a->setups, &setup_count);
- for (i = 0; i < setup_count; i++) {
- roots = array_get(&setups[i]->roots, &root_count);
- for (j = 0; j < root_count; j++) {
- if (!roots[j]->user_root)
- continue;
+ p = strchr(rule_def, ':');
+ if (p == NULL) {
+ *error_r = "Invalid rule";
+ return -1;
+ }
- if (quota_mail_storage_add_root(storage, roots[j]))
- found = TRUE;
+ /* <mailbox name>:<quota limits> */
+ t_push();
+ mailbox_name = t_strdup_until(rule_def, p++);
+
+ rule = quota_root_rule_find(root, mailbox_name);
+ if (rule == NULL) {
+ if (strcmp(mailbox_name, RULE_NAME_ALL_MAILBOXES) == 0)
+ rule = &root->default_rule;
+ else {
+ rule = array_append_space(&root->rules);
+ rule->mailbox_name = p_strdup(root->pool, mailbox_name);
}
}
- if (!found && setup_count > 0) {
- /* create a new quota root for the storage */
- struct quota_root *root;
+ if (strncmp(p, "backend=", 8) == 0) {
+ if (!root->backend.v.parse_rule(root, rule, p, error_r))
+ ret = -1;
+ } else {
+ if (quota_rule_parse_limits(root, rule, p, error_r) < 0)
+ ret = -1;
+ }
- root = quota_root_init(setups[0], ""); /* FIXME: name? */
- found = quota_mail_storage_add_root(storage, root);
- i_assert(found);
+ if (root->quota->debug) {
+ i_info("Quota rule: root=%s mailbox=%s "
+ "storage=%lldkB messages=%lld", root->name,
+ rule->mailbox_name != NULL ? rule->mailbox_name : "",
+ (long long)rule->bytes_limit / 1024,
+ (long long)rule->count_limit);
}
+
+ t_pop();
+ return ret;
}
-struct quota_root *quota_root_lookup(struct quota *quota, const char *name)
+static bool quota_root_get_rule_limits(struct quota_root *root,
+ const char *mailbox_name,
+ uint64_t *bytes_limit_r,
+ uint64_t *count_limit_r)
+{
+ struct quota_rule *rule;
+ int64_t bytes_limit, count_limit;
+ bool found;
+
+ bytes_limit = root->default_rule.bytes_limit;
+ count_limit = root->default_rule.count_limit;
+
+ /* if default rule limits are 0, this rule applies only to specific
+ mailboxes */
+ found = bytes_limit != 0 || count_limit != 0;
+
+ rule = quota_root_rule_find(root, mailbox_name);
+ if (rule != NULL) {
+ bytes_limit += rule->bytes_limit;
+ count_limit += rule->count_limit;
+ found = TRUE;
+ }
+
+ *bytes_limit_r = bytes_limit <= 0 ? 0 : bytes_limit;
+ *count_limit_r = count_limit <= 0 ? 0 : count_limit;
+ return found;
+}
+
+void quota_add_user_storage(struct quota *quota, struct mail_storage *storage)
{
- struct quota_setup *const *setups;
struct quota_root *const *roots;
- unsigned int i, j, setup_count, root_count;
+ struct mail_storage *const *storages;
+ struct quota_backend **backends;
+ const char *path, *path2;
+ unsigned int i, j, count;
+ bool is_file;
+
+ /* first check if there already exists a storage with the exact same
+ path. we don't want to count them twice. */
+ path = mail_storage_get_mailbox_path(storage, "", &is_file);
+ if (path != NULL) {
+ storages = array_get("a->storages, &count);
+ for (i = 0; i < count; i++) {
+ path2 = mail_storage_get_mailbox_path(storages[i], "",
+ &is_file);
+ if (path2 != NULL && strcmp(path, path2) == 0) {
+ /* duplicate */
+ return;
+ }
+ }
+ }
- setups = array_get("a->setups, &setup_count);
- for (i = 0; i < setup_count; i++) {
- roots = array_get(&setups[i]->roots, &root_count);
- for (j = 0; j < root_count; j++) {
- if (strcmp(roots[j]->name, name) == 0)
- return roots[j];
+ array_append("a->storages, &storage, 1);
+
+ roots = array_get("a->roots, &count);
+ /* @UNSAFE: get different backends into one array */
+ backends = t_new(struct quota_backend *, count + 1);
+ for (i = 0; i < count; i++) {
+ for (j = 0; backends[j] != NULL; j++) {
+ if (backends[j]->name == roots[i]->backend.name)
+ break;
}
+ if (backends[j] == NULL)
+ backends[j] = &roots[i]->backend;
}
- return NULL;
-}
-const char *quota_root_get_name(struct quota_root *root)
-{
- return root->name;
+ for (i = 0; backends[i] != NULL; i++) {
+ if (backends[i]->v.storage_added != NULL)
+ backends[i]->v.storage_added(quota, storage);
+ }
}
-const char *const *quota_root_get_resources(struct quota_root *root)
+void quota_remove_user_storage(struct quota *quota,
+ struct mail_storage *storage)
{
- return root->v.get_resources(root);
+ struct mail_storage *const *storages;
+ unsigned int i, count;
+
+ storages = array_get("a->storages, &count);
+ for (i = 0; i < count; i++) {
+ if (storages[i] == storage) {
+ array_delete("a->storages, i, 1);
+ break;
+ }
+ }
}
-int quota_get_resource(struct quota_root *root, const char *name,
- uint64_t *value_r, uint64_t *limit_r)
+int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def,
+ const char **error_r)
{
- return root->v.get_resource(root, name, value_r, limit_r);
-}
+ struct quota_warning_rule *warning;
+ struct quota_rule rule;
+ const char *p;
+ int ret;
-int quota_set_resource(struct quota_root *root,
- const char *name, uint64_t value)
-{
- return root->v.set_resource(root, name, value);
+ p = strchr(rule_def, ' ');
+ if (p == NULL) {
+ *error_r = "No command specified";
+ return -1;
+ }
+
+ memset(&rule, 0, sizeof(rule));
+ t_push();
+ ret = quota_rule_parse_limits(root, &rule, t_strdup_until(rule_def, p),
+ error_r);
+ t_pop();
+ if (ret < 0)
+ return -1;
+
+ if (rule.bytes_limit < 0) {
+ *error_r = "Bytes limit can't be negative";
+ return -1;
+ }
+ if (rule.count_limit < 0) {
+ *error_r = "Count limit can't be negative";
+ return -1;
+ }
+
+ warning = array_append_space(&root->warning_rules);
+ warning->command = i_strdup(p+1);
+ warning->bytes_limit = rule.bytes_limit;
+ warning->count_limit = rule.count_limit;
+ return 0;
}
-struct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
+struct quota_root_iter *
+quota_root_iter_init(struct quota *quota, struct mailbox *box)
{
- struct quota_transaction_context *ctx;
- struct quota_root_transaction_context *root_ctx;
struct quota_root_iter *iter;
- struct quota_root *root;
- ctx = i_new(struct quota_transaction_context, 1);
- ARRAY_CREATE(&ctx->root_transactions, default_pool,
- struct quota_root_transaction_context *, 4);
+ iter = i_new(struct quota_root_iter, 1);
+ iter->quota = quota;
+ iter->box = box;
+ return iter;
+}
+
+struct quota_root *quota_root_iter_next(struct quota_root_iter *iter)
+{
+ struct quota_root *const *roots, *root = NULL;
+ unsigned int count;
+ uint64_t value, limit;
+ int ret;
- iter = quota_root_iter_init(box);
- while ((root = quota_root_iter_next(iter)) != NULL) {
- root_ctx = root->v.transaction_begin(root, ctx, box);
- array_append(&ctx->root_transactions, &root_ctx, 1);
+ roots = array_get(&iter->quota->roots, &count);
+ if (iter->i >= count)
+ return NULL;
+
+ for (; iter->i < count; iter->i++) {
+ ret = quota_get_resource(roots[iter->i], "",
+ QUOTA_NAME_STORAGE_KILOBYTES,
+ &value, &limit);
+ if (ret == 0) {
+ ret = quota_get_resource(roots[iter->i], "",
+ QUOTA_NAME_MESSAGES,
+ &value, &limit);
+ }
+ if (ret > 0) {
+ root = roots[iter->i];
+ break;
+ }
}
- quota_root_iter_deinit(iter);
- return ctx;
+
+ iter->i++;
+ return root;
}
-static void quota_transaction_free(struct quota_transaction_context *ctx)
+void quota_root_iter_deinit(struct quota_root_iter *iter)
{
- array_free(&ctx->root_transactions);
- i_free(ctx);
+ i_free(iter);
}
-int quota_transaction_commit(struct quota_transaction_context *ctx)
+struct quota_root *quota_root_lookup(struct quota *quota, const char *name)
{
- struct quota_root_transaction_context *const *root_transactions;
+ struct quota_root *const *roots;
unsigned int i, count;
- int ret = 0;
- root_transactions = array_get(&ctx->root_transactions, &count);
+ roots = array_get("a->roots, &count);
for (i = 0; i < count; i++) {
- struct quota_root_transaction_context *t =
- root_transactions[i];
-
- if (t->root->v.transaction_commit(t) < 0)
- ret = -1;
+ if (strcmp(roots[i]->name, name) == 0)
+ return roots[i];
}
-
- quota_transaction_free(ctx);
- return ret;
+ return NULL;
}
-void quota_transaction_rollback(struct quota_transaction_context *ctx)
+const char *quota_root_get_name(struct quota_root *root)
{
- struct quota_root_transaction_context *const *root_transactions;
- unsigned int i, count;
-
- root_transactions = array_get(&ctx->root_transactions, &count);
- for (i = 0; i < count; i++) {
- struct quota_root_transaction_context *t =
- root_transactions[i];
-
- t->root->v.transaction_rollback(t);
- }
+ return root->name;
+}
- quota_transaction_free(ctx);
+const char *const *quota_root_get_resources(struct quota_root *root)
+{
+ return root->backend.v.get_resources(root);
}
-int quota_try_alloc(struct quota_transaction_context *ctx,
- struct mail *mail, bool *too_large_r)
+int quota_get_resource(struct quota_root *root, const char *mailbox_name,
+ const char *name, uint64_t *value_r, uint64_t *limit_r)
{
- struct quota_root_transaction_context *const *root_transactions;
- unsigned int i, count;
- int ret = 1;
+ uint64_t bytes_limit, count_limit;
+ bool kilobytes = FALSE;
+ int ret;
- root_transactions = array_get(&ctx->root_transactions, &count);
- for (i = 0; i < count; i++) {
- struct quota_root_transaction_context *t =
- root_transactions[i];
+ if (strcmp(name, QUOTA_NAME_STORAGE_KILOBYTES) == 0) {
+ name = QUOTA_NAME_STORAGE_BYTES;
+ kilobytes = TRUE;
+ }
+
+ (void)quota_root_get_rule_limits(root, mailbox_name,
+ &bytes_limit, &count_limit);
+ if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
+ *limit_r = bytes_limit;
+ else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
+ *limit_r = count_limit;
+ else
+ *limit_r = 0;
+
+ ret = root->backend.v.get_resource(root, name, value_r, limit_r);
+ if (kilobytes && ret > 0) {
+ *value_r /= 1024;
+ *limit_r /= 1024;
+ }
+ return ret <= 0 ? ret :
+ (*limit_r == 0 ? 0 : 1);
+}
+
+int quota_set_resource(struct quota_root *root __attr_unused__,
+ const char *name __attr_unused__,
+ uint64_t value __attr_unused__, const char **error_r)
+{
+ /* the quota information comes from userdb (or even config file),
+ so there's really no way to support this until some major changes
+ are done */
+ *error_r = MAIL_STORAGE_ERR_NO_PERMISSION;
+ return -1;
+}
- ret = t->root->v.try_alloc(t, mail, too_large_r);
- if (ret <= 0)
- break;
- }
- return ret;
+struct quota_transaction_context *quota_transaction_begin(struct quota *quota,
+ struct mailbox *box)
+{
+ struct quota_transaction_context *ctx;
+
+ ctx = i_new(struct quota_transaction_context, 1);
+ ctx->quota = quota;
+ ctx->box = box;
+ ctx->bytes_left = (uint64_t)-1;
+ ctx->count_left = (uint64_t)-1;
+ return ctx;
}
-int quota_try_alloc_bytes(struct quota_transaction_context *ctx,
- uoff_t size, bool *too_large_r)
+static int quota_transaction_set_limits(struct quota_transaction_context *ctx)
{
- struct quota_root_transaction_context *const *root_transactions;
+ struct quota_root *const *roots;
+ const char *mailbox_name;
unsigned int i, count;
- int ret = 1;
+ uint64_t current, limit, left;
+ int ret;
- root_transactions = array_get(&ctx->root_transactions, &count);
- for (i = 0; i < count; i++) {
- struct quota_root_transaction_context *t =
- root_transactions[i];
+ ctx->limits_set = TRUE;
+ mailbox_name = mailbox_get_name(ctx->box);
- ret = t->root->v.try_alloc_bytes(t, size, too_large_r);
- if (ret <= 0)
- break;
+ /* find the lowest quota limits from all roots and use them */
+ roots = array_get(&ctx->quota->roots, &count);
+ for (i = 0; i < count; i++) {
+ ret = quota_get_resource(roots[i], mailbox_name,
+ QUOTA_NAME_STORAGE_BYTES,
+ ¤t, &limit);
+ if (ret > 0) {
+ current += ctx->bytes_used;
+ left = limit < current ? 0 : limit - current;
+ if (ctx->bytes_left > left)
+ ctx->bytes_left = left;
+ } else if (ret < 0) {
+ ctx->failed = TRUE;
+ return -1;
+ }
+
+ ret = quota_get_resource(roots[i], mailbox_name,
+ QUOTA_NAME_MESSAGES, ¤t, &limit);
+ if (ret > 0) {
+ current += ctx->count_used;
+ left = limit < current ? 0 : limit - current;
+ if (ctx->count_left > left)
+ ctx->count_left = left;
+ } else if (ret < 0) {
+ ctx->failed = TRUE;
+ return -1;
+ }
}
- return ret;
+ return 0;
}
-int quota_test_alloc_bytes(struct quota_transaction_context *ctx,
- uoff_t size, bool *too_large_r)
+static void quota_warning_execute(const char *cmd)
{
- struct quota_root_transaction_context *const *root_transactions;
- unsigned int i, count;
- int ret = 1;
-
- root_transactions = array_get(&ctx->root_transactions, &count);
- for (i = 0; i < count; i++) {
- struct quota_root_transaction_context *t =
- root_transactions[i];
+ int ret = system(cmd);
- ret = t->root->v.test_alloc_bytes(t, size, too_large_r);
- if (ret <= 0)
- break;
+ if (ret < 0) {
+ i_error("system(%s) failed: %m", cmd);
+ } else if (WIFSIGNALED(ret)) {
+ i_error("system(%s) died with signal %d", cmd, WTERMSIG(ret));
+ } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
+ i_error("system(%s) exited with status %d",
+ cmd, WIFEXITED(ret) ? WEXITSTATUS(ret) : ret);
}
- return ret;
}
-void quota_alloc(struct quota_transaction_context *ctx, struct mail *mail)
+static void quota_warnings_execute(struct quota_root *root,
+ struct quota_transaction_context *ctx)
{
- struct quota_root_transaction_context *const *root_transactions;
+ struct quota_warning_rule *warnings;
unsigned int i, count;
+ uint64_t bytes_current, bytes_limit, count_current, count_limit;
- root_transactions = array_get(&ctx->root_transactions, &count);
- for (i = 0; i < count; i++) {
- struct quota_root_transaction_context *t =
- root_transactions[i];
+ warnings = array_get_modifyable(&root->warning_rules, &count);
+ if (count == 0)
+ return;
+
+ if (quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES,
+ &bytes_current, &bytes_limit) < 0)
+ return;
+ if (quota_get_resource(root, "", QUOTA_NAME_MESSAGES,
+ &count_current, &count_limit) < 0)
+ return;
- t->root->v.alloc(t, mail);
+ for (i = 0; i < count; i++) {
+ if ((bytes_current -
+ ctx->bytes_used < warnings[i].bytes_limit &&
+ bytes_current >= warnings[i].bytes_limit) ||
+ (count_current -
+ ctx->count_used < warnings[i].count_limit &&
+ count_current >= warnings[i].count_limit)) {
+ quota_warning_execute(warnings[i].command);
+ break;
+ }
}
}
-void quota_free(struct quota_transaction_context *ctx, struct mail *mail)
+int quota_transaction_commit(struct quota_transaction_context **_ctx)
{
- struct quota_root_transaction_context *const *root_transactions;
+ struct quota_transaction_context *ctx = *_ctx;
+ struct quota_root *const *roots;
unsigned int i, count;
+ int ret = 0;
- root_transactions = array_get(&ctx->root_transactions, &count);
- for (i = 0; i < count; i++) {
- struct quota_root_transaction_context *t =
- root_transactions[i];
+ *_ctx = NULL;
- t->root->v.free(t, mail);
+ if (ctx->failed)
+ ret = -1;
+ else if (ctx->bytes_used != 0 || ctx->count_used != 0 ||
+ ctx->recalculate) {
+ roots = array_get(&ctx->quota->roots, &count);
+ for (i = 0; i < count; i++) {
+ quota_warnings_execute(roots[i], ctx);
+ if (roots[i]->backend.v.update(roots[i], ctx) < 0)
+ ret = -1;
+ }
}
-}
-const char *quota_last_error(struct quota *quota)
-{
- return quota->last_error != NULL ? quota->last_error :
- "Unknown quota error";
+ i_free(ctx);
+ return ret;
}
-void quota_set_error(struct quota *quota, const char *errormsg)
+void quota_transaction_rollback(struct quota_transaction_context **_ctx)
{
- i_free(quota->last_error);
- quota->last_error = i_strdup(errormsg);
-}
+ struct quota_transaction_context *ctx = *_ctx;
-void
-quota_default_transaction_rollback(struct quota_root_transaction_context *ctx)
-{
+ *_ctx = NULL;
i_free(ctx);
}
-int quota_default_try_alloc_bytes(struct quota_root_transaction_context *ctx,
- uoff_t size, bool *too_large_r)
+int quota_try_alloc(struct quota_transaction_context *ctx,
+ struct mail *mail, bool *too_large_r)
{
int ret;
- ret = quota_default_test_alloc_bytes(ctx, size, too_large_r);
- if (ret <= 0 || ctx->disabled)
+ ret = quota_test_alloc(ctx, mail_get_physical_size(mail), too_large_r);
+ if (ret <= 0)
return ret;
- ctx->count_diff++;
- ctx->bytes_diff += size;
+ quota_alloc(ctx, mail);
return 1;
}
-int quota_default_test_alloc_bytes(struct quota_root_transaction_context *ctx,
- uoff_t size, bool *too_large_r)
+int quota_test_alloc(struct quota_transaction_context *ctx,
+ uoff_t size, bool *too_large_r)
{
- if (ctx->disabled) {
- *too_large_r = FALSE;
- return 1;
- }
- if (ctx->bytes_current == (uint64_t)-1) {
- /* failure in transaction initialization */
+ if (ctx->failed)
return -1;
- }
- *too_large_r = size > ctx->bytes_limit;
-
- if (ctx->bytes_current + ctx->bytes_diff + size > ctx->bytes_limit)
- return 0;
- if (ctx->count_current + ctx->count_diff + 1 > ctx->count_limit)
- return 0;
- return 1;
+ if (!ctx->limits_set) {
+ if (quota_transaction_set_limits(ctx) < 0)
+ return -1;
+ }
+ return ctx->quota->test_alloc(ctx, size, too_large_r);
}
-int quota_default_try_alloc(struct quota_root_transaction_context *ctx,
- struct mail *mail, bool *too_large_r)
+static int quota_default_test_alloc(struct quota_transaction_context *ctx,
+ uoff_t size, bool *too_large_r)
{
- uoff_t size;
+ struct quota_root *const *roots;
+ unsigned int i, count;
+
+ *too_large_r = FALSE;
- if (ctx->disabled)
+ if (ctx->count_left != 0 && ctx->bytes_left >= ctx->bytes_used + size)
return 1;
- size = mail_get_physical_size(mail);
- if (size == (uoff_t)-1) {
- mail_storage_set_critical(mail->box->storage,
- "Quota: Couldn't get new message's size");
- return -1;
+ roots = array_get(&ctx->quota->roots, &count);
+ for (i = 0; i < count; i++) {
+ uint64_t bytes_limit, count_limit;
+
+ if (!quota_root_get_rule_limits(roots[i],
+ mailbox_get_name(ctx->box),
+ &bytes_limit, &count_limit))
+ continue;
+
+ /* if size is bigger than any limit, then
+ it is bigger than the lowest limit */
+ if (size > bytes_limit) {
+ *too_large_r = TRUE;
+ break;
+ }
}
- return quota_default_try_alloc_bytes(ctx, size, too_large_r);
+ return 0;
}
-void quota_default_alloc(struct quota_root_transaction_context *ctx,
- struct mail *mail)
+void quota_alloc(struct quota_transaction_context *ctx, struct mail *mail)
{
uoff_t size;
- if (ctx->disabled)
- return;
-
size = mail_get_physical_size(mail);
if (size != (uoff_t)-1)
- ctx->bytes_diff += size;
- ctx->count_diff++;
+ ctx->bytes_used += size;
+
+ ctx->count_used++;
}
-void quota_default_free(struct quota_root_transaction_context *ctx,
- struct mail *mail)
+void quota_free(struct quota_transaction_context *ctx, struct mail *mail)
{
uoff_t size;
- if (ctx->disabled)
- return;
-
size = mail_get_physical_size(mail);
- if (size != (uoff_t)-1)
- ctx->bytes_diff -= size;
- ctx->count_diff--;
+ if (size == (uoff_t)-1)
+ quota_recalculate(ctx);
+ else
+ quota_free_bytes(ctx, size);
+}
+
+void quota_free_bytes(struct quota_transaction_context *ctx,
+ uoff_t physical_size)
+{
+ ctx->bytes_used -= physical_size;
+ ctx->count_used--;
+}
+
+void quota_recalculate(struct quota_transaction_context *ctx)
+{
+ ctx->recalculate = TRUE;
}
diff -ru dovecot-1.0/src/plugins/quota/quota-count.c dovecot-1.0-quotarewrite/src/plugins/quota/quota-count.c
--- dovecot-1.0/src/plugins/quota/quota-count.c 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota-count.c 2007-07-27 13:18:36.000000000 +0300
@@ -1,6 +1,7 @@
/* Copyright (C) 2006 Timo Sirainen */
#include "lib.h"
+#include "array.h"
#include "mail-search.h"
#include "mail-storage.h"
#include "quota-private.h"
@@ -46,24 +47,20 @@
return ret;
}
-int quota_count_storage(struct mail_storage *storage,
- uint64_t *bytes_r, uint64_t *count_r)
+static int quota_count_storage(struct mail_storage *storage,
+ uint64_t *bytes, uint64_t *count)
{
struct mailbox_list_context *ctx;
- struct mailbox_list *list;
+ struct mailbox_list *info;
int ret = 0;
- *bytes_r = *count_r = 0;
-
ctx = mail_storage_mailbox_list_init(storage, "", "*",
- MAILBOX_LIST_FAST_FLAGS |
- MAILBOX_LIST_INBOX);
- while ((list = mail_storage_mailbox_list_next(ctx)) != NULL) {
- if ((list->flags & (MAILBOX_NONEXISTENT |
- MAILBOX_PLACEHOLDER |
+ MAILBOX_LIST_FAST_FLAGS);
+ while ((info = mail_storage_mailbox_list_next(ctx)) != NULL) {
+ if ((info->flags & (MAILBOX_NONEXISTENT |
MAILBOX_NOSELECT)) == 0) {
- ret = quota_count_mailbox(storage, list->name,
- bytes_r, count_r);
+ ret = quota_count_mailbox(storage, info->name,
+ bytes, count);
if (ret < 0)
break;
}
@@ -73,3 +70,20 @@
return ret;
}
+
+int quota_count(struct quota *quota, uint64_t *bytes_r, uint64_t *count_r)
+{
+ struct mail_storage *const *storages;
+ unsigned int i, count;
+ int ret = 0;
+
+ *bytes_r = *count_r = 0;
+
+ storages = array_get("a->storages, &count);
+ for (i = 0; i < count; i++) {
+ ret = quota_count_storage(storages[i], bytes_r, count_r);
+ if (ret < 0)
+ break;
+ }
+ return ret;
+}
diff -ru dovecot-1.0/src/plugins/quota/quota-dict.c dovecot-1.0-quotarewrite/src/plugins/quota/quota-dict.c
--- dovecot-1.0/src/plugins/quota/quota-dict.c 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota-dict.c 2007-07-27 13:18:23.000000000 +0300
@@ -1,7 +1,6 @@
/* Copyright (C) 2005-2006 Timo Sirainen */
#include "lib.h"
-#include "array.h"
#include "str.h"
#include "dict.h"
#include "quota-private.h"
@@ -15,291 +14,164 @@
struct dict_quota_root {
struct quota_root root;
struct dict *dict;
-
- uint64_t message_bytes_limit;
- uint64_t message_count_limit;
-
- unsigned int counting:1;
};
extern struct quota_backend quota_backend_dict;
-static struct quota_root *
-dict_quota_init(struct quota_setup *setup, const char *name)
+static struct quota_root *dict_quota_alloc(void)
{
struct dict_quota_root *root;
- struct dict *dict;
- const char *uri, *const *args;
- unsigned long long message_bytes_limit = 0, message_count_limit = 0;
- uri = strchr(setup->data, ' ');
- if (uri == NULL) {
- i_fatal("dict quota: URI missing from parameters: %s",
- setup->data);
- }
+ root = i_new(struct dict_quota_root, 1);
+ return &root->root;
+}
- t_push();
- args = t_strsplit(t_strdup_until(setup->data, uri++), ":");
- for (; *args != '\0'; args++) {
- if (strncmp(*args, "storage=", 8) == 0) {
- message_bytes_limit =
- strtoull(*args + 8, NULL, 10) * 1024;
- } else if (strncmp(*args, "messages=", 9) == 0)
- message_count_limit = strtoull(*args + 9, NULL, 10);
- }
- t_pop();
+static int dict_quota_init(struct quota_root *_root, const char *args)
+{
+ struct dict_quota_root *root = (struct dict_quota_root *)_root;
+ const char *username, *p;
- if (getenv("DEBUG") != NULL) {
- i_info("dict quota: uri = %s", uri);
- i_info("dict quota: byte limit = %llu", message_bytes_limit);
- i_info("dict quota: count limit = %llu", message_count_limit);
+ p = args == NULL ? NULL : strchr(args, ':');
+ if (p == NULL) {
+ i_error("dict quota: URI missing from parameters");
+ return -1;
}
- dict = dict_init(uri, getenv("USER"));
- if (dict == NULL)
- i_fatal("dict quota: dict_init() failed");
+ username = t_strdup_until(args, p);
+ args = p+1;
- root = i_new(struct dict_quota_root, 1);
- root->root.name = i_strdup(name);
- root->root.v = quota_backend_dict.v;
- root->dict = dict;
-
- root->message_bytes_limit =
- message_bytes_limit == 0 ? (uint64_t)-1 : message_bytes_limit;
- root->message_count_limit =
- message_count_limit == 0 ? (uint64_t)-1 : message_count_limit;
- return &root->root;
+ if (*username == '\0')
+ username = getenv("USER");
+
+ if (getenv("DEBUG") != NULL)
+ i_info("dict quota: user = %s, uri = %s", username, args);
+
+ /* FIXME: we should use 64bit integer as datatype instead but before
+ it can actually be used don't bother */
+ root->dict = dict_init(args, username);
+ return root->dict != NULL ? 0 : -1;
}
static void dict_quota_deinit(struct quota_root *_root)
{
struct dict_quota_root *root = (struct dict_quota_root *)_root;
- i_free(root->root.name);
+ if (root->dict != NULL)
+ dict_deinit(&root->dict);
i_free(root);
}
-static bool
-dict_quota_add_storage(struct quota_root *root __attr_unused__,
- struct mail_storage *storage __attr_unused__)
-{
- return TRUE;
-}
-
-static void
-dict_quota_remove_storage(struct quota_root *root __attr_unused__,
- struct mail_storage *storage __attr_unused__)
-{
-}
-
static const char *const *
dict_quota_root_get_resources(struct quota_root *root __attr_unused__)
{
- static const char *resources[] = { QUOTA_NAME_STORAGE, NULL };
+ static const char *resources[] = {
+ QUOTA_NAME_STORAGE_KILOBYTES, QUOTA_NAME_MESSAGES, NULL
+ };
return resources;
}
-static struct mail_storage *
-dict_quota_root_get_storage(struct quota_root *root)
-{
- /* FIXME: figure out how to support multiple storages */
- struct mail_storage *const *storages;
- unsigned int count;
-
- storages = array_get(&root->storages, &count);
- i_assert(count > 0);
-
- return storages[0];
-}
-
-static int dict_quota_lookup(struct dict_quota_root *root, const char *path,
- uint64_t *value_r)
+static int
+dict_quota_count(struct dict_quota_root *root,
+ bool want_bytes, uint64_t *value_r)
{
struct dict_transaction_context *dt;
- const char *value;
uint64_t bytes, count;
- int ret;
- i_assert(!root->counting);
-
- t_push();
- ret = dict_lookup(root->dict, unsafe_data_stack_pool, path, &value);
- if (ret > 0) {
- long long tmp;
-
- tmp = strtoll(value, NULL, 10);
- if (tmp >= 0) {
- *value_r = tmp;
- t_pop();
- return 0;
- }
- /* negative quota. recalculate it. we don't track expunges
- entirely correctly, so this can happen if two processes
- expunge at the same time. */
- }
- t_pop();
-
- if (ret < 0)
- return -1;
-
- /* not found, recalculate the quota */
- root->counting = TRUE;
- ret = quota_count_storage(dict_quota_root_get_storage(&root->root),
- &bytes, &count);
- root->counting = FALSE;
-
- if (ret < 0)
+ if (quota_count(root->root.quota, &bytes, &count) < 0)
return -1;
t_push();
dt = dict_transaction_begin(root->dict);
- if (root->message_bytes_limit != (uint64_t)-1)
- dict_set(dt, DICT_QUOTA_CURRENT_BYTES_PATH, dec2str(bytes));
- if (root->message_count_limit != (uint64_t)-1)
- dict_set(dt, DICT_QUOTA_CURRENT_COUNT_PATH, dec2str(count));
+ dict_set(dt, DICT_QUOTA_CURRENT_BYTES_PATH, dec2str(bytes));
+ dict_set(dt, DICT_QUOTA_CURRENT_COUNT_PATH, dec2str(count));
t_pop();
if (dict_transaction_commit(dt) < 0)
i_error("dict_quota: Couldn't update quota");
- if (strcmp(path, DICT_QUOTA_CURRENT_BYTES_PATH) == 0)
- *value_r = bytes;
- else {
- i_assert(strcmp(path, DICT_QUOTA_CURRENT_COUNT_PATH) == 0);
- *value_r = count;
- }
- return 0;
+ *value_r = want_bytes ? bytes : count;
+ return 1;
}
static int
dict_quota_get_resource(struct quota_root *_root, const char *name,
- uint64_t *value_r, uint64_t *limit_r)
+ uint64_t *value_r, uint64_t *limit __attr_unused__)
{
struct dict_quota_root *root = (struct dict_quota_root *)_root;
+ const char *value;
+ bool want_bytes;
+ int ret;
- if (strcmp(name, QUOTA_NAME_STORAGE) == 0) {
- if (root->message_bytes_limit == (uint64_t)-1)
- return 0;
-
- *limit_r = root->message_bytes_limit / 1024;
- if (dict_quota_lookup(root, DICT_QUOTA_CURRENT_BYTES_PATH,
- value_r) < 0)
- return -1;
- *value_r /= 1024;
- } else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0) {
- if (root->message_count_limit == (uint64_t)-1)
- return 0;
-
- *limit_r = root->message_count_limit;
- if (dict_quota_lookup(root, DICT_QUOTA_CURRENT_COUNT_PATH,
- value_r) < 0)
- return -1;
- } else {
+ if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
+ want_bytes = TRUE;
+ else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
+ want_bytes = FALSE;
+ else
return 0;
- }
- return 1;
-}
-
-static int
-dict_quota_set_resource(struct quota_root *root,
- const char *name __attr_unused__,
- uint64_t value __attr_unused__)
-{
- quota_set_error(root->setup->quota, MAIL_STORAGE_ERR_NO_PERMISSION);
- return -1;
-}
-
-static struct quota_root_transaction_context *
-dict_quota_transaction_begin(struct quota_root *_root,
- struct quota_transaction_context *_ctx,
- struct mailbox *box __attr_unused__)
-{
- struct dict_quota_root *root = (struct dict_quota_root *)_root;
- struct quota_root_transaction_context *ctx;
+ t_push();
+ ret = dict_lookup(root->dict, unsafe_data_stack_pool,
+ want_bytes ? DICT_QUOTA_CURRENT_BYTES_PATH :
+ DICT_QUOTA_CURRENT_COUNT_PATH, &value);
+ if (ret < 0)
+ *value_r = 0;
+ else if (ret == 0)
+ ret = dict_quota_count(root, want_bytes, value_r);
+ else {
+ long long tmp;
- ctx = i_new(struct quota_root_transaction_context, 1);
- ctx->root = _root;
- ctx->ctx = _ctx;
-
- ctx->bytes_limit = root->message_bytes_limit;
- ctx->count_limit = root->message_count_limit;
-
- if (root->counting) {
- /* created by quota_count_storage(), we don't care about
- the quota there */
- ctx->bytes_limit = (uint64_t)-1;
- ctx->count_limit = (uint64_t)-1;
- return ctx;
+ /* recalculate quota if it's negative or if it wasn't found */
+ tmp = ret == 0 ? -1 : strtoll(value, NULL, 10);
+ if (tmp < 0)
+ ret = dict_quota_count(root, want_bytes, value_r);
+ else
+ *value_r = tmp;
}
- t_push();
- if (ctx->bytes_limit != (uint64_t)-1) {
- if (dict_quota_lookup(root, DICT_QUOTA_CURRENT_BYTES_PATH,
- &ctx->bytes_current) < 0)
- ctx->bytes_current = 0;
- }
- if (ctx->count_limit != (uint64_t)-1) {
- if (dict_quota_lookup(root, DICT_QUOTA_CURRENT_COUNT_PATH,
- &ctx->count_current) < 0)
- ctx->bytes_current = 0;
- }
t_pop();
- return ctx;
+ return ret;
}
static int
-dict_quota_transaction_commit(struct quota_root_transaction_context *ctx)
+dict_quota_update(struct quota_root *_root,
+ struct quota_transaction_context *ctx)
{
- struct dict_quota_root *root = (struct dict_quota_root *)ctx->root;
+ struct dict_quota_root *root = (struct dict_quota_root *) _root;
struct dict_transaction_context *dt;
dt = dict_transaction_begin(root->dict);
- if (ctx->bytes_limit != (uint64_t)-1) {
- dict_atomic_inc(dt, DICT_QUOTA_CURRENT_BYTES_PATH,
- ctx->bytes_diff);
- }
- if (ctx->count_limit != (uint64_t)-1) {
- dict_atomic_inc(dt, DICT_QUOTA_CURRENT_COUNT_PATH,
- ctx->count_diff);
+
+ if (ctx->recalculate) {
+ dict_set(dt, DICT_QUOTA_CURRENT_BYTES_PATH, "-1");
+ dict_set(dt, DICT_QUOTA_CURRENT_COUNT_PATH, "-1");
+ } else {
+ if (ctx->bytes_used != 0) {
+ dict_atomic_inc(dt, DICT_QUOTA_CURRENT_BYTES_PATH,
+ ctx->bytes_used);
+ }
+ if (ctx->count_used != 0) {
+ dict_atomic_inc(dt, DICT_QUOTA_CURRENT_COUNT_PATH,
+ ctx->count_used);
+ }
}
+
if (dict_transaction_commit(dt) < 0)
- i_error("dict_quota: Couldn't update quota");
-
- i_free(ctx);
+ return -1;
return 0;
}
-static void
-dict_quota_transaction_rollback(struct quota_root_transaction_context *ctx)
-{
- i_free(ctx);
-}
-
struct quota_backend quota_backend_dict = {
"dict",
{
+ dict_quota_alloc,
dict_quota_init,
dict_quota_deinit,
-
- dict_quota_add_storage,
- dict_quota_remove_storage,
-
+ NULL,
+ NULL,
dict_quota_root_get_resources,
-
dict_quota_get_resource,
- dict_quota_set_resource,
-
- dict_quota_transaction_begin,
- dict_quota_transaction_commit,
- dict_quota_transaction_rollback,
-
- quota_default_try_alloc,
- quota_default_try_alloc_bytes,
- quota_default_test_alloc_bytes,
- quota_default_alloc,
- quota_default_free
+ dict_quota_update
}
};
diff -ru dovecot-1.0/src/plugins/quota/quota-dirsize.c dovecot-1.0-quotarewrite/src/plugins/quota/quota-dirsize.c
--- dovecot-1.0/src/plugins/quota/quota-dirsize.c 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota-dirsize.c 2007-11-27 05:42:11.000000000 +0200
@@ -13,66 +13,27 @@
#include <dirent.h>
#include <sys/stat.h>
-struct dirsize_quota_root {
- struct quota_root root;
-
- uint64_t storage_limit;
+struct quota_count_path {
+ const char *path;
+ bool is_file;
};
extern struct quota_backend quota_backend_dirsize;
-static struct quota_root *
-dirsize_quota_init(struct quota_setup *setup, const char *name)
+static struct quota_root *dirsize_quota_alloc(void)
{
- struct dirsize_quota_root *root;
- const char *const *args;
-
- root = i_new(struct dirsize_quota_root, 1);
- root->root.name = i_strdup(name);
- root->root.v = quota_backend_dirsize.v;
-
- t_push();
- args = t_strsplit(setup->data, ":");
-
- for (; *args != '\0'; args++) {
- if (strncmp(*args, "storage=", 8) == 0)
- root->storage_limit = strtoull(*args + 8, NULL, 10);
- }
- t_pop();
-
- if (getenv("DEBUG") != NULL) {
- i_info("dirsize quota limit = %llukB",
- (unsigned long long)root->storage_limit);
- }
-
- return &root->root;
+ return i_new(struct quota_root, 1);
}
static void dirsize_quota_deinit(struct quota_root *_root)
{
- struct dirsize_quota_root *root = (struct dirsize_quota_root *)_root;
-
- i_free(root->root.name);
- i_free(root);
-}
-
-static bool
-dirsize_quota_add_storage(struct quota_root *root __attr_unused__,
- struct mail_storage *storage __attr_unused__)
-{
- return TRUE;
-}
-
-static void
-dirsize_quota_remove_storage(struct quota_root *root __attr_unused__,
- struct mail_storage *storage __attr_unused__)
-{
+ i_free(_root);
}
static const char *const *
dirsize_quota_root_get_resources(struct quota_root *root __attr_unused__)
{
- static const char *resources[] = { QUOTA_NAME_STORAGE, NULL };
+ static const char *resources[] = { QUOTA_NAME_STORAGE_KILOBYTES, NULL };
return resources;
}
@@ -133,8 +94,7 @@
return ret;
}
-static int get_usage(struct dirsize_quota_root *root,
- const char *path, bool is_file, uint64_t *value_r)
+static int get_usage(const char *path, bool is_file, uint64_t *value_r)
{
struct stat st;
@@ -148,21 +108,14 @@
}
*value_r += st.st_size;
} else {
- if (get_dir_usage(path, value_r) < 0) {
- quota_set_error(root->root.setup->quota,
- "Internal quota calculation error");
+ if (get_dir_usage(path, value_r) < 0)
return -1;
- }
}
return 0;
}
-struct quota_count_path {
- const char *path;
- bool is_file;
-};
-
-static void quota_count_path_add(array_t *paths, const char *path, bool is_file)
+static void quota_count_path_add(array_t *paths,
+ const char *path, bool is_file)
{
ARRAY_SET_TYPE(paths, struct quota_count_path);
struct quota_count_path *count_path;
@@ -173,7 +126,7 @@
for (i = 0; i < count; ) {
if (strncmp(count_path[i].path, path,
strlen(count_path[i].path)) == 0) {
- /* this path is already being counted */
+ /* this path has already been counted */
return;
}
if (strncmp(count_path[i].path, path, path_len) == 0 &&
@@ -193,7 +146,7 @@
}
static int
-get_quota_root_usage(struct dirsize_quota_root *root, uint64_t *value_r)
+get_quota_root_usage(struct quota_root *root, uint64_t *value_r)
{
struct mail_storage *const *storages;
array_t ARRAY_DEFINE(paths, struct quota_count_path);
@@ -205,7 +158,7 @@
t_push();
ARRAY_CREATE(&paths, pool_datastack_create(),
struct quota_count_path, 8);
- storages = array_get(&root->root.storages, &count);
+ storages = array_get(&root->quota->storages, &count);
for (i = 0; i < count; i++) {
path = mail_storage_get_mailbox_path(storages[i], "", &is_file);
quota_count_path_add(&paths, path, is_file);
@@ -217,9 +170,10 @@
}
/* now sum up the found paths */
+ *value_r = 0;
count_paths = array_get(&paths, &count);
for (i = 0; i < count; i++) {
- if (get_usage(root, count_paths[i].path, count_paths[i].is_file,
+ if (get_usage(count_paths[i].path, count_paths[i].is_file,
value_r) < 0) {
t_pop();
return -1;
@@ -227,98 +181,40 @@
}
t_pop();
-
return 0;
}
static int
dirsize_quota_get_resource(struct quota_root *_root, const char *name,
- uint64_t *value_r, uint64_t *limit_r)
+ uint64_t *value_r, uint64_t *limit __attr_unused__)
{
- struct dirsize_quota_root *root = (struct dirsize_quota_root *)_root;
-
- *value_r = 0;
- *limit_r = 0;
-
- if (strcasecmp(name, QUOTA_NAME_STORAGE) != 0)
+ if (strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) != 0)
return 0;
- if (get_quota_root_usage(root, value_r) < 0)
+ if (get_quota_root_usage(_root, value_r) < 0)
return -1;
- *value_r /= 1024;
- *limit_r = root->storage_limit;
return 1;
}
-static int
-dirsize_quota_set_resource(struct quota_root *root,
- const char *name __attr_unused__,
- uint64_t value __attr_unused__)
-{
- quota_set_error(root->setup->quota, MAIL_STORAGE_ERR_NO_PERMISSION);
- return -1;
-}
-
-static struct quota_root_transaction_context *
-dirsize_quota_transaction_begin(struct quota_root *_root,
- struct quota_transaction_context *_ctx,
- struct mailbox *box __attr_unused__)
-{
- struct dirsize_quota_root *root = (struct dirsize_quota_root *)_root;
- struct quota_root_transaction_context *ctx;
-
- ctx = i_new(struct quota_root_transaction_context, 1);
- ctx->root = _root;
- ctx->ctx = _ctx;
-
- /* Get dir usage only once at the beginning of transaction.
- When copying/appending lots of mails we don't want to re-read the
- entire directory structure after each mail. */
- if (get_quota_root_usage(root, &ctx->bytes_current) < 0 ||
- ctx->bytes_current == (uint64_t)-1) {
- ctx->bytes_current = (uint64_t)-1;
- quota_set_error(_root->setup->quota,
- "Internal quota calculation error");
- }
-
- ctx->bytes_limit = root->storage_limit * 1024;
- ctx->count_limit = (uint64_t)-1;
- return ctx;
-}
-
-static int
-dirsize_quota_transaction_commit(struct quota_root_transaction_context *ctx)
+static int
+dirsize_quota_update(struct quota_root *root __attr_unused__,
+ struct quota_transaction_context *ctx __attr_unused__)
{
- int ret = ctx->bytes_current == (uint64_t)-1 ? -1 : 0;
-
- i_free(ctx);
- return ret;
+ return 0;
}
struct quota_backend quota_backend_dirsize = {
"dirsize",
{
- dirsize_quota_init,
+ dirsize_quota_alloc,
+ NULL,
dirsize_quota_deinit,
-
- dirsize_quota_add_storage,
- dirsize_quota_remove_storage,
-
+ NULL,
+ NULL,
dirsize_quota_root_get_resources,
-
dirsize_quota_get_resource,
- dirsize_quota_set_resource,
-
- dirsize_quota_transaction_begin,
- dirsize_quota_transaction_commit,
- quota_default_transaction_rollback,
-
- quota_default_try_alloc,
- quota_default_try_alloc_bytes,
- quota_default_test_alloc_bytes,
- quota_default_alloc,
- quota_default_free
+ dirsize_quota_update
}
};
diff -ru dovecot-1.0/src/plugins/quota/quota-fs.c dovecot-1.0-quotarewrite/src/plugins/quota/quota-fs.c
--- dovecot-1.0/src/plugins/quota/quota-fs.c 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota-fs.c 2007-07-27 13:18:23.000000000 +0300
@@ -56,22 +56,13 @@
struct fs_quota_mountpoint *mount;
};
-struct fs_quota_root_iter {
- struct quota_root_iter iter;
-
- bool sent;
-};
-
extern struct quota_backend quota_backend_fs;
-static struct quota_root *
-fs_quota_init(struct quota_setup *setup __attr_unused__, const char *name)
+static struct quota_root *fs_quota_alloc(void)
{
struct fs_quota_root *root;
root = i_new(struct fs_quota_root, 1);
- root->root.name = i_strdup(name);
- root->root.v = quota_backend_fs.v;
root->uid = geteuid();
return &root->root;
@@ -99,7 +90,6 @@
if (root->mount != NULL)
fs_quota_mountpoint_free(root->mount);
- i_free(root->root.name);
i_free(root);
}
@@ -120,42 +110,66 @@
return mount;
}
-static bool fs_quota_add_storage(struct quota_root *_root,
- struct mail_storage *storage)
+static struct fs_quota_root *
+fs_quota_root_find_mountpoint(struct quota *quota,
+ const struct fs_quota_mountpoint *mount)
+{
+ struct quota_root *const *roots;
+ struct fs_quota_root *empty = NULL;
+ unsigned int i, count;
+
+ roots = array_get("a->roots, &count);
+ for (i = 0; i < count; i++) {
+ if (roots[i]->backend.name == quota_backend_fs.name) {
+ struct fs_quota_root *root =
+ (struct fs_quota_root *)roots[i];
+
+ if (root->mount == NULL)
+ empty = root;
+ else if (strcmp(root->mount->mount_path,
+ mount->mount_path) == 0)
+ return root;
+ }
+ }
+ return empty;
+}
+
+static void fs_quota_storage_added(struct quota *quota,
+ struct mail_storage *storage)
{
- struct fs_quota_root *root = (struct fs_quota_root *)_root;
struct fs_quota_mountpoint *mount;
+ struct quota_root *_root;
+ struct fs_quota_root *root;
const char *dir;
bool is_file;
dir = mail_storage_get_mailbox_path(storage, "", &is_file);
-
- if (getenv("DEBUG") != NULL)
- i_info("fs quota add storage dir = %s", dir);
-
mount = fs_quota_mountpoint_get(dir);
- if (root->mount == NULL) {
- if (mount == NULL) {
- /* Not found */
- return TRUE;
- }
- root->mount = mount;
- } else {
- bool match = strcmp(root->mount->mount_path,
- mount->mount_path) == 0;
+ if (getenv("DEBUG") != NULL) {
+ i_info("fs quota add storage dir = %s", dir);
+ i_info("fs quota block device = %s", mount->device_path);
+ i_info("fs quota mount point = %s", mount->mount_path);
+ }
+ root = fs_quota_root_find_mountpoint(quota, mount);
+ if (root != NULL && root->mount != NULL) {
+ /* already exists */
fs_quota_mountpoint_free(mount);
- if (!match) {
- /* different mountpoints, can't use this */
- return FALSE;
- }
- mount = root->mount;
+ return;
}
- if (getenv("DEBUG") != NULL) {
- i_info("fs quota block device = %s", mount->device_path);
- i_info("fs quota mount point = %s", mount->mount_path);
+ if (root == NULL) {
+ /* create a new root for this mountpoint */
+ _root = quota_root_init(quota, quota_backend_fs.name);
+ root = (struct fs_quota_root *)_root;
+ root->root.name =
+ p_strdup_printf(root->root.pool, "%s%d",
+ quota_backend_fs.name,
+ array_count("a->roots));
+ } else {
+ /* this is the default root. */
}
+ root->mount = mount;
#ifdef HAVE_Q_QUOTACTL
if (mount->path == NULL) {
@@ -165,19 +179,12 @@
i_error("open(%s) failed: %m", mount->path);
}
#endif
- return TRUE;
-}
-
-static void
-fs_quota_remove_storage(struct quota_root *root __attr_unused__,
- struct mail_storage *storage __attr_unused__)
-{
}
static const char *const *
fs_quota_root_get_resources(struct quota_root *root __attr_unused__)
{
- static const char *resources[] = { QUOTA_NAME_STORAGE, NULL };
+ static const char *resources[] = { QUOTA_NAME_STORAGE_KILOBYTES, NULL };
return resources;
}
@@ -195,7 +202,8 @@
*value_r = 0;
*limit_r = 0;
- if (strcasecmp(name, QUOTA_NAME_STORAGE) != 0 || root->mount == NULL)
+ if (strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) != 0 ||
+ root->mount == NULL)
return 0;
#if defined (HAVE_QUOTACTL) && defined(HAVE_SYS_QUOTA_H)
@@ -210,14 +218,12 @@
root->uid, (caddr_t)&xdqblk) < 0) {
i_error("quotactl(Q_XGETQUOTA, %s) failed: %m",
root->mount->device_path);
- quota_set_error(_root->setup->quota,
- "Internal quota error");
return -1;
}
/* values always returned in 512 byte blocks */
- *value_r = xdqblk.d_bcount >> 1;
- *limit_r = xdqblk.d_blk_softlimit >> 1;
+ *value_r = xdqblk.d_bcount * 512;
+ *limit_r = xdqblk.d_blk_softlimit * 512;
} else
#endif
{
@@ -233,17 +239,15 @@
"(--with-linux-quota configure option)",
_LINUX_QUOTA_VERSION);
}
- quota_set_error(_root->setup->quota,
- "Internal quota error");
return -1;
}
#if _LINUX_QUOTA_VERSION == 1
- *value_r = dqblk.dqb_curblocks;
+ *value_r = dqblk.dqb_curblocks * 1024;
#else
- *value_r = dqblk.dqb_curblocks / 1024;
+ *value_r = dqblk.dqb_curblocks;
#endif
- *limit_r = dqblk.dqb_bsoftlimit;
+ *limit_r = dqblk.dqb_bsoftlimit * 1024;
}
#elif defined(HAVE_QUOTACTL)
/* BSD, AIX */
@@ -251,11 +255,10 @@
root->uid, (void *)&dqblk) < 0) {
i_error("quotactl(Q_GETQUOTA, %s) failed: %m",
root->mount->mount_path);
- quota_set_error(_root->setup->quota, "Internal quota error");
return -1;
}
- *value_r = (uint64_t)dqblk.dqb_curblocks * DEV_BSIZE / 1024;
- *limit_r = (uint64_t)dqblk.dqb_bsoftlimit * DEV_BSIZE / 1024;
+ *value_r = (uint64_t)dqblk.dqb_curblocks * DEV_BSIZE;
+ *limit_r = (uint64_t)dqblk.dqb_bsoftlimit * DEV_BSIZE;
#else
/* Solaris */
if (root->mount->fd == -1)
@@ -266,42 +269,18 @@
ctl.addr = (caddr_t)&dqblk;
if (ioctl(root->mount->fd, Q_QUOTACTL, &ctl) < 0) {
i_error("ioctl(%s, Q_QUOTACTL) failed: %m", root->mount->path);
- quota_set_error(_root->setup->quota, "Internal quota error");
return -1;
}
- *value_r = (uint64_t)dqblk.dqb_curblocks * 1024 / DEV_BSIZE;
- *limit_r = (uint64_t)dqblk.dqb_bsoftlimit * 1024 / DEV_BSIZE;
+ *value_r = (uint64_t)dqblk.dqb_curblocks * DEV_BSIZE;
+ *limit_r = (uint64_t)dqblk.dqb_bsoftlimit * DEV_BSIZE;
#endif
return 1;
}
-static int
-fs_quota_set_resource(struct quota_root *root,
- const char *name __attr_unused__,
- uint64_t value __attr_unused__)
-{
- quota_set_error(root->setup->quota, MAIL_STORAGE_ERR_NO_PERMISSION);
- return -1;
-}
-
-static struct quota_root_transaction_context *
-fs_quota_transaction_begin(struct quota_root *root,
- struct quota_transaction_context *ctx,
- struct mailbox *box __attr_unused__)
-{
- struct quota_root_transaction_context *root_ctx;
-
- root_ctx = i_new(struct quota_root_transaction_context, 1);
- root_ctx->root = root;
- root_ctx->ctx = ctx;
- root_ctx->disabled = TRUE;
- return root_ctx;
-}
-
-static int
-fs_quota_transaction_commit(struct quota_root_transaction_context *ctx)
+static int
+fs_quota_update(struct quota_root *root __attr_unused__,
+ struct quota_transaction_context *ctx __attr_unused__)
{
- i_free(ctx);
return 0;
}
@@ -309,26 +288,16 @@
"fs",
{
- fs_quota_init,
+ fs_quota_alloc,
+ NULL,
fs_quota_deinit,
+ NULL,
- fs_quota_add_storage,
- fs_quota_remove_storage,
+ fs_quota_storage_added,
fs_quota_root_get_resources,
-
fs_quota_get_resource,
- fs_quota_set_resource,
-
- fs_quota_transaction_begin,
- fs_quota_transaction_commit,
- quota_default_transaction_rollback,
-
- quota_default_try_alloc,
- quota_default_try_alloc_bytes,
- quota_default_test_alloc_bytes,
- quota_default_alloc,
- quota_default_free
+ fs_quota_update
}
};
diff -ru dovecot-1.0/src/plugins/quota/quota.h dovecot-1.0-quotarewrite/src/plugins/quota/quota.h
--- dovecot-1.0/src/plugins/quota/quota.h 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota.h 2007-07-27 13:24:10.000000000 +0300
@@ -5,7 +5,9 @@
struct mailbox;
/* Message storage size kilobytes. */
-#define QUOTA_NAME_STORAGE "STORAGE"
+#define QUOTA_NAME_STORAGE_KILOBYTES "STORAGE"
+/* Message storage size bytes. This is used only internally. */
+#define QUOTA_NAME_STORAGE_BYTES "STORAGE_BYTES"
/* Number of messages. */
#define QUOTA_NAME_MESSAGES "MESSAGES"
@@ -14,25 +16,24 @@
struct quota_root_iter;
struct quota_transaction_context;
-extern void (*hook_quota_root_created)(struct quota_root *root);
-
struct quota *quota_init(void);
void quota_deinit(struct quota *quota);
-/* Create a new quota setup under which quota roots are created.
- user_root is TRUE if this quota points to user's own mailboxes instead of
- shared mailboxes. */
-struct quota_setup *
-quota_setup_init(struct quota *quota, const char *data, bool user_root);
-void quota_setup_deinit(struct quota_setup *setup);
-
/* Create a new quota root. */
-struct quota_root *
-quota_root_init(struct quota_setup *setup, const char *name);
+struct quota_root *quota_root_init(struct quota *quota, const char *root_def);
void quota_root_deinit(struct quota_root *root);
+/* Add a new rule too the quota root. Returns 0 if ok, -1 if rule is invalid. */
+int quota_root_add_rule(struct quota_root *root, const char *rule_def,
+ const char **error_r);
+/* Add a new warning rule for the quota root. Returns 0 if ok, -1 if rule is
+ invalid. */
+int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def,
+ const char **error_r);
+
/* List all quota roots. Returned quota roots are freed by quota_deinit(). */
-struct quota_root_iter *quota_root_iter_init(struct mailbox *box);
+struct quota_root_iter *
+quota_root_iter_init(struct quota *quota, struct mailbox *box);
struct quota_root *quota_root_iter_next(struct quota_root_iter *iter);
void quota_root_iter_deinit(struct quota_root_iter *iter);
@@ -45,34 +46,34 @@
const char *const *quota_root_get_resources(struct quota_root *root);
/* Returns 1 if quota value was found, 0 if not, -1 if error. */
-int quota_get_resource(struct quota_root *root,
+int quota_get_resource(struct quota_root *root, const char *mailbox_name,
const char *name, uint64_t *value_r, uint64_t *limit_r);
/* Returns 0 if OK, -1 if error (eg. permission denied, invalid name). */
-int quota_set_resource(struct quota_root *root,
- const char *name, uint64_t value);
+int quota_set_resource(struct quota_root *root, const char *name,
+ uint64_t value, const char **error_r);
/* Start a new quota transaction. */
-struct quota_transaction_context *quota_transaction_begin(struct mailbox *box);
+struct quota_transaction_context *quota_transaction_begin(struct quota *quota,
+ struct mailbox *box);
/* Commit quota transaction. Returns 0 if ok, -1 if failed. */
-int quota_transaction_commit(struct quota_transaction_context *ctx);
+int quota_transaction_commit(struct quota_transaction_context **ctx);
/* Rollback quota transaction changes. */
-void quota_transaction_rollback(struct quota_transaction_context *ctx);
+void quota_transaction_rollback(struct quota_transaction_context **ctx);
/* Allocate from quota if there's space. Returns 1 if updated, 0 if not,
-1 if error. If mail size is larger than even maximum allowed quota,
too_large_r is set to TRUE. */
int quota_try_alloc(struct quota_transaction_context *ctx,
struct mail *mail, bool *too_large_r);
-int quota_try_alloc_bytes(struct quota_transaction_context *ctx,
- uoff_t size, bool *too_large_r);
-/* Like quota_try_alloc_bytes(), but don't actually update the quota. */
-int quota_test_alloc_bytes(struct quota_transaction_context *ctx,
- uoff_t size, bool *too_large_r);
+/* Like quota_try_alloc(), but don't actually allocate anything. */
+int quota_test_alloc(struct quota_transaction_context *ctx,
+ uoff_t size, bool *too_large_r);
/* Update quota by allocating/freeing space used by mail. */
void quota_alloc(struct quota_transaction_context *ctx, struct mail *mail);
void quota_free(struct quota_transaction_context *ctx, struct mail *mail);
-
-/* Returns the last error message. */
-const char *quota_last_error(struct quota *quota);
+void quota_free_bytes(struct quota_transaction_context *ctx,
+ uoff_t physical_size);
+/* Mark the quota to be recalculated */
+void quota_recalculate(struct quota_transaction_context *ctx);
#endif
diff -ru dovecot-1.0/src/plugins/quota/quota-maildir.c dovecot-1.0-quotarewrite/src/plugins/quota/quota-maildir.c
--- dovecot-1.0/src/plugins/quota/quota-maildir.c 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota-maildir.c 2007-11-27 05:42:11.000000000 +0200
@@ -16,14 +16,13 @@
#include <dirent.h>
#include <sys/stat.h>
-#define MAILDIR_TRASH_MAILBOX "Trash"
#define MAILDIRSIZE_FILENAME "maildirsize"
#define MAILDIRSIZE_STALE_SECS (60*15)
struct maildir_quota_root {
struct quota_root root;
- char *ignore;
+ const char *maildirsize_path;
uint64_t message_bytes_limit;
uint64_t message_count_limit;
@@ -31,13 +30,13 @@
uint64_t total_count;
int fd;
+ time_t recalc_last_stamp;
+ unsigned int limits_initialized:1;
unsigned int master_message_limits:1;
};
struct maildir_list_context {
- struct maildir_quota_root *root;
-
struct mailbox_list_context *ctx;
struct mailbox_list *list;
@@ -60,8 +59,8 @@
MEMBER(use_excl_lock) FALSE
};
-static int maildir_sum_dir(struct mail_storage *storage, const char *dir,
- uint64_t *total_bytes, uint64_t *total_count)
+static int maildir_sum_dir(const char *dir, uint64_t *total_bytes,
+ uint64_t *total_count)
{
DIR *dirp;
struct dirent *dp;
@@ -75,8 +74,7 @@
if (dirp == NULL) {
if (errno == ENOENT || errno == ESTALE)
return 0;
- mail_storage_set_critical(storage, "opendir(%s) failed: %m",
- dir);
+ i_error("opendir(%s) failed: %m", dir);
return -1;
}
@@ -115,28 +113,25 @@
*total_bytes += st.st_size;
*total_count += 1;
} else if (errno != ENOENT && errno != ESTALE) {
- mail_storage_set_critical(storage,
- "stat(%s) failed: %m", str_c(path));
+ i_error("stat(%s) failed: %m", str_c(path));
ret = -1;
}
}
}
if (closedir(dirp) < 0) {
- mail_storage_set_critical(storage, "closedir(%s) failed: %m",
- dir);
+ i_error("closedir(%s) failed: %m", dir);
return -1;
}
return ret;
}
static struct maildir_list_context *
-maildir_list_init(struct maildir_quota_root *root, struct mail_storage *storage)
+maildir_list_init(struct mail_storage *storage)
{
struct maildir_list_context *ctx;
ctx = i_new(struct maildir_list_context, 1);
- ctx->root = root;
ctx->path = str_new(default_pool, 512);
ctx->ctx = mail_storage_mailbox_list_init(storage, "", "*",
MAILBOX_LIST_FAST_FLAGS |
@@ -158,10 +153,6 @@
return NULL;
}
- if (ctx->root->ignore != NULL &&
- strcmp(ctx->list->name, ctx->root->ignore) == 0)
- continue;
-
t_push();
path = mail_storage_get_mailbox_path(ctx->ctx->storage,
ctx->list->name,
@@ -179,8 +170,7 @@
/* ignore if the directory got lost, stale or if it was
actually a file and not a directory */
if (errno != ENOENT && errno != ESTALE && errno != ENOTDIR) {
- mail_storage_set_critical(ctx->ctx->storage,
- "stat(%s) failed: %m", str_c(ctx->path));
+ i_error("stat(%s) failed: %m", str_c(ctx->path));
ctx->state = 0;
}
}
@@ -199,14 +189,13 @@
}
static int
-maildirs_check_have_changed(struct maildir_quota_root *root,
- struct mail_storage *storage, time_t latest_mtime)
+maildirs_check_have_changed(struct mail_storage *storage, time_t latest_mtime)
{
struct maildir_list_context *ctx;
time_t mtime;
int ret = 0;
- ctx = maildir_list_init(root, storage);
+ ctx = maildir_list_init(storage);
while (maildir_list_next(ctx, &mtime) != NULL) {
if (mtime > latest_mtime) {
ret = 1;
@@ -218,8 +207,7 @@
return ret;
}
-static int maildirsize_write(struct maildir_quota_root *root,
- struct mail_storage *storage, const char *path)
+static int maildirsize_write(struct maildir_quota_root *root, const char *path)
{
struct dotlock *dotlock;
string_t *str;
@@ -227,8 +215,7 @@
i_assert(root->fd == -1);
- dotlock_settings.use_excl_lock =
- (storage->flags & MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
+ dotlock_settings.use_excl_lock = getenv("DOTLOCK_USE_EXCL") != NULL;
fd = file_dotlock_open(&dotlock_settings, path,
DOTLOCK_CREATE_FLAG_NONBLOCK, &dotlock);
if (fd == -1) {
@@ -237,8 +224,7 @@
return 1;
}
- mail_storage_set_critical(storage,
- "file_dotlock_open(%s) failed: %m", path);
+ i_error("file_dotlock_open(%s) failed: %m", path);
return -1;
}
@@ -257,8 +243,7 @@
(unsigned long long)root->total_bytes,
(unsigned long long)root->total_count);
if (write_full(fd, str_data(str), str_len(str)) < 0) {
- mail_storage_set_critical(storage,
- "write_full(%s) failed: %m", path);
+ i_error("write_full(%s) failed: %m", path);
file_dotlock_delete(&dotlock);
return -1;
}
@@ -266,38 +251,34 @@
/* keep the fd open since we might want to update it later */
if (file_dotlock_replace(&dotlock,
DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) < 0) {
- mail_storage_set_critical(storage,
- "file_dotlock_replace(%s) failed: %m", path);
+ i_error("file_dotlock_replace(%s) failed: %m", path);
return -1;
}
root->fd = fd;
return 0;
}
-static const char *maildirsize_get_path(struct mail_storage *storage)
+static void maildirsize_recalculate_init(struct maildir_quota_root *root)
{
- return t_strconcat(mail_storage_get_mailbox_control_dir(storage, ""),
- "/"MAILDIRSIZE_FILENAME, NULL);
+ root->total_bytes = root->total_count = 0;
+ root->recalc_last_stamp = 0;
}
-static int maildirsize_recalculate(struct maildir_quota_root *root,
- struct mail_storage *storage)
+static int maildirsize_recalculate_storage(struct maildir_quota_root *root,
+ struct mail_storage *storage)
{
struct maildir_list_context *ctx;
- const char *dir, *path;
- time_t mtime, last_stamp = 0;
+ const char *dir;
+ time_t mtime;
int ret = 0;
- root->total_bytes = root->total_count = 0;
-
- ctx = maildir_list_init(root, storage);
+ ctx = maildir_list_init(storage);
while ((dir = maildir_list_next(ctx, &mtime)) != NULL) {
- if (mtime > last_stamp)
- last_stamp = mtime;
+ if (mtime > root->recalc_last_stamp)
+ root->recalc_last_stamp = mtime;
t_push();
- if (maildir_sum_dir(storage, dir,
- &root->total_bytes,
+ if (maildir_sum_dir(dir, &root->total_bytes,
&root->total_count) < 0)
ret = -1;
t_pop();
@@ -305,59 +286,107 @@
if (maildir_list_deinit(ctx) < 0)
ret = -1;
- if (ret == 0)
- ret = maildirs_check_have_changed(root, storage, last_stamp);
+ return ret;
+}
- t_push();
- path = maildirsize_get_path(storage);
+static int maildirsize_recalculate_finish(struct maildir_quota_root *root,
+ int ret)
+{
if (ret == 0) {
/* maildir didn't change, we can write the maildirsize file */
- ret = maildirsize_write(root, storage, path);
+ ret = maildirsize_write(root, root->maildirsize_path);
}
if (ret != 0) {
/* make sure it gets rebuilt later */
- if (unlink(path) < 0 && errno != ENOENT && errno != ESTALE) {
- mail_storage_set_critical(storage,
- "unlink(%s) failed: %m", path);
+ if (unlink(root->maildirsize_path) < 0 &&
+ errno != ENOENT && errno != ESTALE) {
+ i_error("unlink(%s) failed: %m",
+ root->maildirsize_path);
}
}
- t_pop();
return ret;
}
-static int maildirsize_parse(struct maildir_quota_root *root,
- int fd, const char *const *lines)
+static int maildirsize_recalculate(struct maildir_quota_root *root)
+{
+ struct mail_storage *const *storages;
+ unsigned int i, count;
+ int ret = 0;
+
+ maildirsize_recalculate_init(root);
+
+ /* count mails from all storages */
+ storages = array_get(&root->root.quota->storages, &count);
+ for (i = 0; i < count; i++) {
+ if (maildirsize_recalculate_storage(root, storages[i]) < 0) {
+ ret = -1;
+ break;
+ }
+ }
+
+ if (ret == 0) {
+ /* check if any of the directories have changed */
+ for (i = 0; i < count; i++) {
+ ret = maildirs_check_have_changed(storages[i],
+ root->recalc_last_stamp);
+ if (ret != 0)
+ break;
+ }
+ }
+
+ return maildirsize_recalculate_finish(root, ret);
+}
+
+static bool
+maildir_parse_limit(const char *str, uint64_t *bytes_r, uint64_t *count_r)
{
- unsigned long long bytes;
- uint64_t message_bytes_limit, message_count_limit;
- long long bytes_diff, total_bytes;
- int count_diff, total_count;
- unsigned int line_count = 0;
const char *const *limit;
+ unsigned long long value;
char *pos;
+ bool ret = TRUE;
- if (*lines == NULL)
- return -1;
+ *bytes_r = (uint64_t)-1;
+ *count_r = (uint64_t)-1;
- /* first line contains the limits. 0 value mean unlimited. */
- message_bytes_limit = (uint64_t)-1;
- message_count_limit = (uint64_t)-1;
- for (limit = t_strsplit(lines[0], ","); *limit != NULL; limit++) {
- bytes = strtoull(*limit, &pos, 10);
+ /* 0 values mean unlimited */
+ for (limit = t_strsplit(str, ","); *limit != NULL; limit++) {
+ value = strtoull(*limit, &pos, 10);
if (pos[0] != '\0' && pos[1] == '\0') {
switch (pos[0]) {
case 'C':
- if (bytes != 0)
- message_count_limit = bytes;
+ if (value != 0)
+ *count_r = value;
break;
case 'S':
- if (bytes != 0)
- message_bytes_limit = bytes;
+ if (value != 0)
+ *bytes_r = value;
+ break;
+ default:
+ ret = FALSE;
break;
}
+ } else {
+ ret = FALSE;
}
}
+ return ret;
+}
+
+static int maildirsize_parse(struct maildir_quota_root *root,
+ int fd, const char *const *lines)
+{
+ uint64_t message_bytes_limit, message_count_limit;
+ long long bytes_diff, total_bytes;
+ int count_diff, total_count;
+ unsigned int line_count = 0;
+
+ if (*lines == NULL)
+ return -1;
+
+ /* first line contains the limits */
+ (void)maildir_parse_limit(lines[0], &message_bytes_limit,
+ &message_count_limit);
if (!root->master_message_limits) {
/* we don't know the limits, use whatever the file says */
@@ -409,32 +438,26 @@
return 1;
}
-static int maildirsize_read(struct maildir_quota_root *root,
- struct mail_storage *storage)
+static int maildirsize_read(struct maildir_quota_root *root)
{
- const char *path;
char buf[5120+1];
unsigned int i, size;
int fd, ret = 0;
t_push();
- path = maildirsize_get_path(storage);
if (root->fd != -1) {
- if (close(root->fd) < 0) {
- mail_storage_set_critical(storage,
- "close(%s) failed: %m", path);
- }
+ if (close(root->fd) < 0)
+ i_error("close(%s) failed: %m", root->maildirsize_path);
root->fd = -1;
}
- fd = nfs_safe_open(path, O_RDWR | O_APPEND);
+ fd = nfs_safe_open(root->maildirsize_path, O_RDWR | O_APPEND);
if (fd == -1) {
if (errno == ENOENT)
ret = 0;
else {
ret = -1;
- mail_storage_set_critical(storage,
- "open(%s) failed: %m", path);
+ i_error("open(%s) failed: %m", root->maildirsize_path);
}
t_pop();
return ret;
@@ -447,8 +470,7 @@
if (ret < 0) {
if (errno == ESTALE)
break;
- mail_storage_set_critical(storage, "read(%s) failed: %m",
- path);
+ i_error("read(%s) failed: %m", root->maildirsize_path);
}
size += ret;
}
@@ -488,12 +510,26 @@
return ret;
}
-static int maildirquota_refresh(struct maildir_quota_root *root,
- struct mail_storage *storage)
+static void maildirquota_init_limits(struct maildir_quota_root *root)
+{
+ root->limits_initialized = TRUE;
+
+ if (root->root.default_rule.bytes_limit != 0 ||
+ root->root.default_rule.count_limit != 0) {
+ root->master_message_limits = TRUE;
+ root->message_bytes_limit = root->root.default_rule.bytes_limit;
+ root->message_count_limit = root->root.default_rule.count_limit;
+ }
+}
+
+static int maildirquota_refresh(struct maildir_quota_root *root)
{
int ret;
- ret = maildirsize_read(root, storage);
+ if (!root->limits_initialized)
+ maildirquota_init_limits(root);
+
+ ret = maildirsize_read(root);
if (ret == 0) {
if (root->message_bytes_limit == (uint64_t)-1 &&
root->message_count_limit == (uint64_t)-1) {
@@ -501,13 +537,12 @@
return 0;
}
- ret = maildirsize_recalculate(root, storage);
+ ret = maildirsize_recalculate(root);
}
return ret < 0 ? -1 : 0;
}
static int maildirsize_update(struct maildir_quota_root *root,
- struct mail_storage *storage,
int count_diff, int64_t bytes_diff)
{
const char *str;
@@ -529,52 +564,22 @@
if (errno == ESTALE) {
/* deleted/replaced already, ignore */
} else {
- mail_storage_set_critical(storage,
- "write_full(%s) failed: %m",
- maildirsize_get_path(storage));
+ i_error("write_full(%s) failed: %m",
+ root->maildirsize_path);
}
}
t_pop();
return ret;
}
-static struct quota_root *
-maildir_quota_init(struct quota_setup *setup, const char *name __attr_unused__)
+static struct quota_root *maildir_quota_alloc(void)
{
struct maildir_quota_root *root;
- const char *const *args;
- unsigned long long size;
root = i_new(struct maildir_quota_root, 1);
- root->root.name = i_strdup(name);
- root->root.v = quota_backend_maildir.v;
root->fd = -1;
root->message_bytes_limit = (uint64_t)-1;
root->message_count_limit = (uint64_t)-1;
-
- t_push();
- args = t_strsplit(setup->data, ":");
-
- for (args++; *args != '\0'; args++) {
- if (strncmp(*args, "storage=", 8) == 0) {
- size = strtoull(*args + 8, NULL, 10) * 1024;
- if (size != 0)
- root->message_bytes_limit = size;
- root->master_message_limits = TRUE;
- } else if (strncmp(*args, "messages=", 9) == 0) {
- size = strtoull(*args + 9, NULL, 10);
- if (size != 0)
- root->message_count_limit = size;
- root->master_message_limits = TRUE;
- } else if (strncmp(*args, "ignore=", 7) == 0) {
- i_free(root->ignore);
- root->ignore = i_strdup(*args + 7);
- } else {
- i_error("maildir quota: Unknown setting: %s", *args);
- }
- }
- t_pop();
-
return &root->root;
}
@@ -584,37 +589,69 @@
if (root->fd != -1)
(void)close(root->fd);
-
- i_free(root->ignore);
- i_free(root->root.name);
i_free(root);
}
static bool
-maildir_quota_add_storage(struct quota_root *root __attr_unused__,
- struct mail_storage *_storage)
+maildir_quota_parse_rule(struct quota_root *root __attr_unused__,
+ struct quota_rule *rule,
+ const char *str, const char **error_r)
{
- if (strcmp(_storage->name, "maildir") == 0) {
- struct maildir_storage *storage =
- (struct maildir_storage *)_storage;
+ uint64_t bytes, count;
- /* For newly generated filenames add ,S=size. */
- storage->save_size_in_filename = TRUE;
+ if (!maildir_parse_limit(str, &bytes, &count)) {
+ *error_r = "Invalid Maildir++ quota rule";
+ return FALSE;
}
+
+ rule->bytes_limit = bytes;
+ rule->count_limit = count;
return TRUE;
}
static void
-maildir_quota_remove_storage(struct quota_root *root __attr_unused__,
- struct mail_storage *storage __attr_unused__)
+maildir_quota_root_storage_added(struct quota_root *_root,
+ struct mail_storage *storage)
{
+ struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
+ const char *control_dir;
+
+ if (root->maildirsize_path != NULL)
+ return;
+
+ control_dir = mail_storage_get_mailbox_control_dir(storage, "");
+ root->maildirsize_path =
+ p_strconcat(_root->pool, control_dir,
+ "/"MAILDIRSIZE_FILENAME, NULL);
+}
+
+static void
+maildir_quota_storage_added(struct quota *quota,
+ struct mail_storage *_storage)
+{
+ struct maildir_storage *storage =
+ (struct maildir_storage *)_storage;
+ struct quota_root **roots;
+ unsigned int i, count;
+
+ if (strcmp(_storage->name, "maildir") != 0)
+ return;
+
+ roots = array_get_modifyable("a->roots, &count);
+ for (i = 0; i < count; i++) {
+ if (roots[i]->backend.name == quota_backend_maildir.name)
+ maildir_quota_root_storage_added(roots[i], _storage);
+ }
+
+ /* For newly generated filenames add ,S=size. */
+ storage->save_size_in_filename = TRUE;
}
static const char *const *
maildir_quota_root_get_resources(struct quota_root *root __attr_unused__)
{
static const char *resources_both[] = {
- QUOTA_NAME_STORAGE,
+ QUOTA_NAME_STORAGE_KILOBYTES,
QUOTA_NAME_MESSAGES,
NULL
};
@@ -622,129 +659,50 @@
return resources_both;
}
-static struct mail_storage *
-maildir_quota_root_get_storage(struct quota_root *root)
-{
- /* FIXME: figure out how to support multiple storages */
- struct mail_storage *const *storages;
- unsigned int count;
-
- storages = array_get(&root->storages, &count);
- i_assert(count > 0);
-
- return storages[0];
-}
-
static int
maildir_quota_get_resource(struct quota_root *_root, const char *name,
- uint64_t *value_r, uint64_t *limit_r)
+ uint64_t *value_r, uint64_t *limit __attr_unused__)
{
struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
- if (maildirquota_refresh(root,
- maildir_quota_root_get_storage(_root)) < 0)
+ if (maildirquota_refresh(root) < 0)
return -1;
- if (strcmp(name, QUOTA_NAME_STORAGE) == 0) {
- if (root->message_bytes_limit == (uint64_t)-1)
- return 0;
-
- *limit_r = root->message_bytes_limit / 1024;
- *value_r = root->total_bytes / 1024;
- } else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0) {
- if (root->message_count_limit == (uint64_t)-1)
- return 0;
-
- *limit_r = root->message_count_limit;
+ if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
+ *value_r = root->total_bytes;
+ else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
*value_r = root->total_count;
- } else {
+ else
return 0;
- }
return 1;
}
static int
-maildir_quota_set_resource(struct quota_root *root,
- const char *name __attr_unused__,
- uint64_t value __attr_unused__)
-{
- quota_set_error(root->setup->quota, MAIL_STORAGE_ERR_NO_PERMISSION);
- return -1;
-}
-
-static struct quota_root_transaction_context *
-maildir_quota_transaction_begin(struct quota_root *_root,
- struct quota_transaction_context *_ctx,
- struct mailbox *box)
-{
- struct maildir_quota_root *root = (struct maildir_quota_root *)_root;
- struct quota_root_transaction_context *ctx;
-
- ctx = i_new(struct quota_root_transaction_context, 1);
- ctx->root = _root;
- ctx->ctx = _ctx;
-
- if (root->ignore != NULL &&
- strcmp(mailbox_get_name(box), root->ignore) == 0) {
- ctx->bytes_limit = (uint64_t)-1;
- ctx->count_limit = (uint64_t)-1;
- ctx->ignored = TRUE;
- return ctx;
- }
-
- if (maildirquota_refresh(root,
- maildir_quota_root_get_storage(_root)) < 0) {
- /* failed calculating the current quota */
- ctx->bytes_current = (uint64_t)-1;
- } else {
- ctx->bytes_limit = root->message_bytes_limit;
- ctx->count_limit = root->message_count_limit;
- ctx->bytes_current = root->total_bytes;
- ctx->count_current = root->total_count;
- }
- return ctx;
-}
-
-static int
-maildir_quota_transaction_commit(struct quota_root_transaction_context *ctx)
+maildir_quota_update(struct quota_root *_root,
+ struct quota_transaction_context *ctx)
{
struct maildir_quota_root *root =
- (struct maildir_quota_root *)ctx->root;
- int ret = ctx->bytes_current == (uint64_t)-1 ? -1 : 0;
+ (struct maildir_quota_root *) _root;
- if (root->fd != -1 && ret == 0 && !ctx->ignored) {
+ if (root->fd != -1) {
/* if writing fails, we don't care all that much */
- (void)maildirsize_update(root,
- maildir_quota_root_get_storage(ctx->root),
- ctx->count_diff, ctx->bytes_diff);
+ (void)maildirsize_update(root, ctx->count_used,
+ ctx->bytes_used);
}
- i_free(ctx);
- return ret;
+ return 0;
}
struct quota_backend quota_backend_maildir = {
"maildir",
{
- maildir_quota_init,
+ maildir_quota_alloc,
+ NULL,
maildir_quota_deinit,
-
- maildir_quota_add_storage,
- maildir_quota_remove_storage,
-
+ maildir_quota_parse_rule,
+ maildir_quota_storage_added,
maildir_quota_root_get_resources,
-
maildir_quota_get_resource,
- maildir_quota_set_resource,
-
- maildir_quota_transaction_begin,
- maildir_quota_transaction_commit,
- quota_default_transaction_rollback,
-
- quota_default_try_alloc,
- quota_default_try_alloc_bytes,
- quota_default_test_alloc_bytes,
- quota_default_alloc,
- quota_default_free
+ maildir_quota_update
}
};
diff -ru dovecot-1.0/src/plugins/quota/quota-plugin.c dovecot-1.0-quotarewrite/src/plugins/quota/quota-plugin.c
--- dovecot-1.0/src/plugins/quota/quota-plugin.c 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota-plugin.c 2007-07-27 13:24:10.000000000 +0300
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 Timo Sirainen */
+/* Copyright (C) 2005 Timo Sirainen & Tianyan Liu */
#include "lib.h"
#include "mail-storage.h"
@@ -15,20 +15,95 @@
const char *quota_plugin_version = PACKAGE_VERSION;
struct quota *quota_set;
+static void quota_root_add_rules(const char *root_name,
+ struct quota_root *root)
+{
+ const char *rule_name, *rule, *error;
+ unsigned int i;
+
+ t_push();
+
+ rule_name = t_strconcat(root_name, "_RULE", NULL);
+ for (i = 2;; i++) {
+ rule = getenv(rule_name);
+
+ if (rule == NULL)
+ break;
+
+ if (quota_root_add_rule(root, rule, &error) < 0) {
+ i_fatal("Quota root %s: Invalid rule: %s",
+ root_name, rule);
+ }
+ rule_name = t_strdup_printf("%s_RULE%d", root_name, i);
+ }
+
+ t_pop();
+}
+
+static void quota_root_add_warning_rules(const char *root_name,
+ struct quota_root *root)
+{
+ const char *rule_name, *rule, *error;
+ unsigned int i;
+
+ t_push();
+
+ rule_name = t_strconcat(root_name, "_WARNING", NULL);
+ for (i = 2;; i++) {
+ rule = getenv(rule_name);
+
+ if (rule == NULL)
+ break;
+
+ if (quota_root_add_warning_rule(root, rule, &error) < 0) {
+ i_fatal("Quota root %s: Invalid warning rule: %s",
+ root_name, rule);
+ }
+ rule_name = t_strdup_printf("%s_WARNING%d", root_name, i);
+ }
+
+ t_pop();
+}
+
void quota_plugin_init(void)
{
+ struct quota_root *root;
+ unsigned int i;
const char *env;
env = getenv("QUOTA");
- if (env != NULL) {
- quota_set = quota_init();
- /* Currently we support only one quota setup */
- (void)quota_setup_init(quota_set, env, TRUE);
-
- quota_next_hook_mail_storage_created =
- hook_mail_storage_created;
- hook_mail_storage_created = quota_mail_storage_created;
+ if (env == NULL)
+ return;
+
+ quota_set = quota_init();
+
+ root = quota_root_init(quota_set, env);
+ if (root == NULL)
+ i_fatal("Couldn't create quota root: %s", env);
+ quota_root_add_rules("QUOTA", root);
+ quota_root_add_warning_rules("QUOTA", root);
+
+ t_push();
+ for (i = 2;; i++) {
+ const char *root_name;
+
+ root_name = t_strdup_printf("QUOTA%d", i);
+ env = getenv(root_name);
+
+ if (env == NULL)
+ break;
+
+ root = quota_root_init(quota_set, env);
+ if (root == NULL)
+ i_fatal("Couldn't create quota root: %s", env);
+ quota_root_add_rules(root_name, root);
+ quota_root_add_warning_rules(root_name, root);
}
+ t_pop();
+
+ quota_next_hook_mail_storage_created =
+ hook_mail_storage_created;
+ hook_mail_storage_created = quota_mail_storage_created;
}
void quota_plugin_deinit(void)
diff -ru dovecot-1.0/src/plugins/quota/quota-private.h dovecot-1.0-quotarewrite/src/plugins/quota/quota-private.h
--- dovecot-1.0/src/plugins/quota/quota-private.h 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota-private.h 2007-07-27 13:24:29.000000000 +0300
@@ -9,129 +9,93 @@
extern unsigned int quota_module_id;
struct quota {
- array_t ARRAY_DEFINE(setups, struct quota_setup *);
- char *last_error;
+ array_t ARRAY_DEFINE(roots, struct quota_root *);
+ array_t ARRAY_DEFINE(storages, struct mail_storage *);
+
+ int (*test_alloc)(struct quota_transaction_context *ctx,
+ uoff_t size, bool *too_large_r);
+
+ unsigned int debug:1;
};
-struct quota_setup {
- struct quota *quota;
+struct quota_rule {
+ char *mailbox_name;
- struct quota_backend *backend;
- char *data;
+ int64_t bytes_limit, count_limit;
+};
- /* List of quota roots. It's array because there shouldn't be many. */
- array_t ARRAY_DEFINE(roots, struct quota_root *);
+struct quota_warning_rule {
+ uint64_t bytes_limit;
+ uint64_t count_limit;
- unsigned int user_root:1;
+ char *command;
};
struct quota_backend_vfuncs {
- struct quota_root *(*init)(struct quota_setup *setup, const char *name);
+ struct quota_root *(*alloc)(void);
+ int (*init)(struct quota_root *root, const char *args);
void (*deinit)(struct quota_root *root);
- bool (*add_storage)(struct quota_root *root,
- struct mail_storage *storage);
- void (*remove_storage)(struct quota_root *root,
- struct mail_storage *storage);
+ bool (*parse_rule)(struct quota_root *root, struct quota_rule *rule,
+ const char *str, const char **error_r);
+
+ /* called once for each backend */
+ void (*storage_added)(struct quota *quota,
+ struct mail_storage *storage);
const char *const *(*get_resources)(struct quota_root *root);
+ /* the limit is set by default, so it shouldn't normally need to
+ be changed. */
int (*get_resource)(struct quota_root *root, const char *name,
- uint64_t *value_r, uint64_t *limit_r);
- int (*set_resource)(struct quota_root *root,
- const char *name, uint64_t value);
-
- struct quota_root_transaction_context *
- (*transaction_begin)(struct quota_root *root,
- struct quota_transaction_context *ctx,
- struct mailbox *box);
- int (*transaction_commit)(struct quota_root_transaction_context *ctx);
- void (*transaction_rollback)
- (struct quota_root_transaction_context *ctx);
-
- int (*try_alloc)(struct quota_root_transaction_context *ctx,
- struct mail *mail, bool *too_large_r);
- int (*try_alloc_bytes)(struct quota_root_transaction_context *ctx,
- uoff_t size, bool *too_large_r);
- int (*test_alloc_bytes)(struct quota_root_transaction_context *ctx,
- uoff_t size, bool *too_large_r);
- void (*alloc)(struct quota_root_transaction_context *ctx,
- struct mail *mail);
- void (*free)(struct quota_root_transaction_context *ctx,
- struct mail *mail);
+ uint64_t *value_r, uint64_t *limit);
+
+ int (*update)(struct quota_root *root,
+ struct quota_transaction_context *ctx);
};
struct quota_backend {
+ /* quota backends equal if backend1.name == backend2.name */
const char *name;
struct quota_backend_vfuncs v;
};
struct quota_root {
- struct quota_setup *setup;
+ pool_t pool;
/* Unique quota root name. */
- char *name;
+ const char *name;
- struct quota_backend_vfuncs v;
+ /* pointer to the quota that owns this root */
+ struct quota *quota;
+
+ struct quota_backend backend;
+ struct quota_rule default_rule;
+ array_t ARRAY_DEFINE(rules, struct quota_rule);
+ array_t ARRAY_DEFINE(warning_rules, struct quota_warning_rule);
- /* Mail storages using this quota root. */
- array_t ARRAY_DEFINE(storages, struct mail_storage *);
/* Module-specific contexts. See quota_module_id. */
array_t ARRAY_DEFINE(quota_module_contexts, void);
-
- unsigned int user_root:1;
-};
-
-struct quota_root_iter {
- struct quota_mail_storage *qstorage;
- unsigned int idx;
};
struct quota_transaction_context {
- array_t ARRAY_DEFINE(root_transactions,
- struct quota_root_transaction_context *);
-};
-
-struct quota_root_transaction_context {
- struct quota_root *root;
- struct quota_transaction_context *ctx;
+ struct quota *quota;
+ struct mailbox *box;
- int count_diff;
- int64_t bytes_diff;
+ int64_t bytes_used, count_used;
+ uint64_t bytes_left, count_left;
- uint64_t bytes_limit, count_limit;
- uint64_t bytes_current, count_current;
+ struct mail *tmp_mail;
- unsigned int ignored:1;
- unsigned int disabled:1;
+ unsigned int limits_set:1;
+ unsigned int failed:1;
+ unsigned int recalculate:1;
};
/* Register storage to all user's quota roots. */
void quota_add_user_storage(struct quota *quota, struct mail_storage *storage);
+void quota_remove_user_storage(struct quota *quota,
+ struct mail_storage *storage);
-/* Likn root and storage together. Returns TRUE if successful, FALSE if it
- can't be done (eg. different filesystems with filesystem quota) */
-bool quota_mail_storage_add_root(struct mail_storage *storage,
- struct quota_root *root);
-void quota_mail_storage_remove_root(struct mail_storage *storage,
- struct quota_root *root);
-
-void quota_set_error(struct quota *quota, const char *errormsg);
-
-/* default simple implementations for bytes/count updating */
-void
-quota_default_transaction_rollback(struct quota_root_transaction_context *ctx);
-int quota_default_try_alloc(struct quota_root_transaction_context *ctx,
- struct mail *mail, bool *too_large_r);
-int quota_default_try_alloc_bytes(struct quota_root_transaction_context *ctx,
- uoff_t size, bool *too_large_r);
-int quota_default_test_alloc_bytes(struct quota_root_transaction_context *ctx,
- uoff_t size, bool *too_large_r);
-void quota_default_alloc(struct quota_root_transaction_context *ctx,
- struct mail *mail);
-void quota_default_free(struct quota_root_transaction_context *ctx,
- struct mail *mail);
-
-int quota_count_storage(struct mail_storage *storage,
- uint64_t *bytes_r, uint64_t *count_r);
+int quota_count(struct quota *quota, uint64_t *bytes_r, uint64_t *count_r);
#endif
diff -ru dovecot-1.0/src/plugins/quota/quota-storage.c dovecot-1.0-quotarewrite/src/plugins/quota/quota-storage.c
--- dovecot-1.0/src/plugins/quota/quota-storage.c 2007-11-27 05:41:59.000000000 +0200
+++ dovecot-1.0-quotarewrite/src/plugins/quota/quota-storage.c 2007-11-27 05:44:09.000000000 +0200
@@ -16,10 +16,6 @@
struct quota_mail_storage {
struct mail_storage_vfuncs super;
- struct quota *quota;
-
- /* List of quota roots this storage belongs to. */
- array_t ARRAY_DEFINE(roots, struct quota_root *);
};
struct quota_mailbox {
@@ -58,7 +54,7 @@
struct quota_transaction_context *qt;
t = qbox->super.transaction_begin(box, flags);
- qt = quota_transaction_begin(box);
+ qt = quota_transaction_begin(quota_set, box);
array_idx_set(&t->module_contexts, quota_storage_module_id, &qt);
return t;
@@ -72,10 +68,12 @@
struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
if (qbox->super.transaction_commit(ctx, flags) < 0) {
- quota_transaction_rollback(qt);
+ quota_transaction_rollback(&qt);
return -1;
} else {
- (void)quota_transaction_commit(qt);
+ if (qt->tmp_mail != NULL)
+ mail_free(&qt->tmp_mail);
+ (void)quota_transaction_commit(&qt);
return 0;
}
}
@@ -87,7 +85,10 @@
struct quota_transaction_context *qt = QUOTA_CONTEXT(ctx);
qbox->super.transaction_rollback(ctx);
- quota_transaction_rollback(qt);
+
+ if (qt->tmp_mail != NULL)
+ mail_free(&qt->tmp_mail);
+ quota_transaction_rollback(&qt);
}
static struct mail *
@@ -124,8 +125,8 @@
mail_storage_set_error(t->box->storage, "Quota exceeded");
return -1;
} else {
- mail_storage_set_error(t->box->storage, "%s",
- quota_last_error(quota_set));
+ mail_storage_set_critical(t->box->storage,
+ "Internal quota calculation error");
return -1;
}
}
@@ -135,26 +136,25 @@
enum mail_flags flags, struct mail_keywords *keywords,
struct mail *dest_mail)
{
+ struct quota_transaction_context *qt = QUOTA_CONTEXT(t);
struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
- struct mail *copy_dest_mail;
- int ret;
- if (dest_mail != NULL)
- copy_dest_mail = dest_mail;
- else
- copy_dest_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE, NULL);
+ if (dest_mail == NULL) {
+ /* we always want to know the mail size */
+ if (qt->tmp_mail == NULL) {
+ qt->tmp_mail = mail_alloc(t, MAIL_FETCH_PHYSICAL_SIZE,
+ NULL);
+ }
+ dest_mail = qt->tmp_mail;
+ }
qbox->save_hack = FALSE;
- if (qbox->super.copy(t, mail, flags, keywords, copy_dest_mail) < 0)
+ if (qbox->super.copy(t, mail, flags, keywords, dest_mail) < 0)
return -1;
/* if copying used saving internally, we already checked the quota
and set qbox->save_hack = TRUE. */
- ret = qbox->save_hack ? 0 : quota_check(t, copy_dest_mail);
-
- if (copy_dest_mail != dest_mail)
- mail_free(©_dest_mail);
- return ret;
+ return qbox->save_hack ? 0 : quota_check(t, dest_mail);
}
static int
@@ -183,14 +183,14 @@
full mail. */
bool too_large;
- ret = quota_test_alloc_bytes(qt, st->st_size, &too_large);
+ ret = quota_test_alloc(qt, st->st_size, &too_large);
if (ret == 0) {
mail_storage_set_error(t->box->storage,
"Quota exceeded");
return -1;
} else if (ret < 0) {
- mail_storage_set_error(t->box->storage, "%s",
- quota_last_error(quota_set));
+ mail_storage_set_critical(t->box->storage,
+ "Internal quota calculation error");
return -1;
}
}
@@ -300,22 +300,8 @@
static void quota_storage_destroy(struct mail_storage *storage)
{
struct quota_mail_storage *qstorage = QUOTA_CONTEXT(storage);
- struct quota_root *const *roots;
- struct mail_storage *const *storages;
- unsigned int i, j, root_count, storage_count;
-
- /* remove the storage from all roots' storages list */
- roots = array_get(&qstorage->roots, &root_count);
- for (i = 0; i < root_count; i++) {
- storages = array_get(&roots[i]->storages, &storage_count);
- for (j = 0; j < storage_count; j++) {
- if (storages[j] == storage) {
- array_delete(&roots[i]->storages, j, 1);
- break;
- }
- }
- i_assert(j != storage_count);
- }
+
+ quota_remove_user_storage(quota_set, storage);
qstorage->super.destroy(storage);
}
@@ -333,8 +319,6 @@
storage->v.mailbox_open = quota_mailbox_open;
storage->v.mailbox_delete = quota_mailbox_delete;
- ARRAY_CREATE(&qstorage->roots, storage->pool, struct quota_root *, 4);
-
if (!quota_storage_module_id_set) {
quota_storage_module_id = mail_storage_module_id++;
quota_storage_module_id_set = TRUE;
@@ -348,74 +332,3 @@
quota_add_user_storage(quota_set, storage);
}
}
-
-bool quota_mail_storage_add_root(struct mail_storage *storage,
- struct quota_root *root)
-{
- struct quota_mail_storage *qstorage = QUOTA_CONTEXT(storage);
-
- if (!root->v.add_storage(root, storage))
- return FALSE;
-
- array_append(&root->storages, &storage, 1);
- array_append(&qstorage->roots, &root, 1);
- return TRUE;
-}
-
-void quota_mail_storage_remove_root(struct mail_storage *storage,
- struct quota_root *root)
-{
- struct quota_mail_storage *qstorage = QUOTA_CONTEXT(storage);
- struct mail_storage *const *storages;
- struct quota_root *const *roots;
- unsigned int i, count;
-
- storages = array_get(&root->storages, &count);
- for (i = 0; i < count; i++) {
- if (storages[i] == storage) {
- array_delete(&root->storages, i, 1);
- break;
- }
- }
- i_assert(i != count);
-
- roots = array_get(&qstorage->roots, &count);
- for (i = 0; i < count; i++) {
- if (roots[i] == root) {
- array_delete(&qstorage->roots, i, 1);
- break;
- }
- }
- i_assert(i != count);
-
- root->v.remove_storage(root, storage);
-}
-
-struct quota_root_iter *quota_root_iter_init(struct mailbox *box)
-{
- struct quota_mail_storage *qstorage = QUOTA_CONTEXT(box->storage);
- struct quota_root_iter *iter;
-
- iter = i_new(struct quota_root_iter, 1);
- iter->qstorage = qstorage;
- return iter;
-}
-
-struct quota_root *quota_root_iter_next(struct quota_root_iter *iter)
-{
- struct quota_root *const *roots;
- unsigned int count;
-
- roots = array_get(&iter->qstorage->roots, &count);
- i_assert(iter->idx <= count);
-
- if (iter->idx >= count)
- return NULL;
-
- return roots[iter->idx++];
-}
-
-void quota_root_iter_deinit(struct quota_root_iter *iter)
-{
- i_free(iter);
-}
2
3
I am using Maildir and virtual domains.
I have the following definitions in the dovecot.conf:
mail_uid = 10000
mail_gid = 10000
mail_location = maildir:/var/mail/apps/%d/%n/Maildir
...
Userdb database is LDAP based. Some users in LDAP might have a uid/gid
defined. If thats the case, I want dovecot to use those uid/gid. If
the user in LDAP does not have a uid/gid attribute, it'll fall back to
using mail_uid/mail_gid as defined above.
(atleast thats what I am hoping to do...)
I set the permissions of /var/mail/apps, /var/mail/apps/%d directories 1777.
I also see the following error message when a message is received to
one of the users:
Jan 13 18:33:33 vds5 deliver(admin(a)domain.com): [ID 702911 mail.error]
stat(/var/mail/apps/domain.com/admin/Maildir/tmp) failed: Permission
denied
The permissions of this tmp directory are:
drwx------ 2 vmail vmail 2 Jan 13 18:31 tmp
Why is deliver having problems writing to that? At this point, what
uid is deliver running as?
Thanks!
3
4
20 Jan '08
Dear All,
We would like to migrate our existing courier to dovecot. After reading
document on website and doing some tests, here are some issues we met.
1. According the the wiki, it seems to imply that once migrating from
courier to dovecot, pop3 users may "lost/forget" their download "index/
history" which cause them to download again old mails that are kept on
server side.
If this is true, it would seriously annoy our users since they always
keep old mails on server so that they can access them through webmail
interface.
Is there anyway to avoid this kind of situation?
2. Currently, we use only /etc/passwd to store our user information. Postfix
is our MTA and maildrop is MDA. Quota settings were wriiten in the
maildirsize file reside under Maildir directory at everyone's home.
The command we use to set user quota:
/usr/local/bin/maildirmake -q 315000000S Maildir
After installing a test environment using dovecot v1.1.beta13, we found
that it
does not read the quota settings from the maildirsize file, instead, it
only rely on the
system wide settings. This could be a problem since we have different
quota
settings for different groups of users. Is this a bug of v1.1? Or should
I
use v1.0 instead? Will v1.1 fix this bug in the future?
Best regards,
Tim Chen
3
7
Hi!
Am Samstag, 19. Januar 2008 schrieb Luigi Rosa:
> > How about first starting ntpd, forcing a time-update using ntpdate
> > even before starting ntpd, and delaying the dovecot start until after
> > the time has been adjusted?
> The problem is tha you cannot tell when the time is adjusted because
> it take some time to the ntp protocol to synchronize.
That's why I suggested to use ntpdate to force the correct time to be set
before ntpd even starts and the ntp init script returns.
Admittedly, this won't work if you have no network connectivity during
boot up, but if you have, this paticular problem is most likely solved.
ntpdate optionally can be given a timeout value and indicates success or
failure via its return code so that a calling script might initiate
appropriate measures.
Greetings,
Gunter
--
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
"You're dead," he said. Keli waited. She couldn't think of any suitable
reply. "I'm not" lacked a certain style, while "Is it serious?" seemed
somehow too frivolous. -- Princess Keli in trouble
(Terry Pratchett, Mort)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ PGP-verschlüsselte Mails bevorzugt! +
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4
3
Scenario: server PC abruptly switched off due to power cable problems
(an UPS cannot solve this issue), so during shutdown Linux was not
able to resinchronize the system clock. After a few hours the server
come back on, Linux booted and the services (ntpd, dovecot and many
others) started
But the system clock was 45 minutes ahead, so:
Jan 19 11:13:39 gw ntpd[2112]: synchronized to LOCAL(0), stratum 10
Jan 19 11:13:39 gw ntpd[2112]: kernel time sync disabled 0041
Jan 19 11:14:43 gw ntpd[2112]: synchronized to 62.48.35.100, stratum 2
Jan 19 10:31:55 gw ntpd[2112]: time reset -3600.221385 s
Jan 19 10:31:55 gw ntpd[2112]: kernel time sync enabled 0001
Jan 19 10:31:55 gw dovecot: Time just moved backwards by 3600 seconds.
This might cause a lot of problems, so I'll just kill myself now.
http://wiki.dovecot.org/TimeMovedBackwards
Ciao,
luigi
--
/
+--[Luigi Rosa]--
\
Spoon boy: Do not try and bend the spoon. That's impossible.
Instead... only try to realize the truth.
Neo: What truth?
Spoon boy: There is no spoon.
Neo: There is no spoon?
Spoon boy: Then you'll see, that it is not the spoon that bends, it is
only yourself.
--The Matrix
4
6