1
/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
4
#include "module-context.h"
6
#include "mail-storage-private.h"
8
#include "quota-clone-plugin.h"
10
#define DICT_QUOTA_CLONE_PATH DICT_PATH_PRIVATE"quota/"
11
#define DICT_QUOTA_CLONE_BYTES_PATH DICT_QUOTA_CLONE_PATH"storage"
12
#define DICT_QUOTA_CLONE_COUNT_PATH DICT_QUOTA_CLONE_PATH"messages"
14
#define QUOTA_CLONE_USER_CONTEXT(obj) \
15
MODULE_CONTEXT(obj, quota_clone_user_module)
16
#define QUOTA_CLONE_CONTEXT(obj) \
17
MODULE_CONTEXT(obj, quota_clone_storage_module)
19
static MODULE_CONTEXT_DEFINE_INIT(quota_clone_user_module,
20
&mail_user_module_register);
21
static MODULE_CONTEXT_DEFINE_INIT(quota_clone_storage_module,
22
&mail_storage_module_register);
24
struct quota_clone_user {
25
union mail_user_module_context module_ctx;
29
struct quota_clone_mailbox {
30
union mailbox_module_context module_ctx;
34
static void quota_clone_flush(struct mailbox *box)
36
struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
37
struct quota_clone_user *quser =
38
QUOTA_CLONE_USER_CONTEXT(box->storage->user);
39
struct dict_transaction_context *trans;
40
struct quota_root_iter *iter;
41
struct quota_root *root;
42
uint64_t value, limit;
45
/* we'll clone the first quota root */
46
iter = quota_root_iter_init(box);
47
root = quota_root_iter_next(iter);
49
/* no quota roots defined for this mailbox - ignore */
50
qbox->quota_changed = FALSE;
53
quota_root_iter_deinit(&iter);
55
trans = dict_transaction_begin(quser->dict);
57
ret = quota_get_resource(root, "", QUOTA_NAME_STORAGE_BYTES,
60
i_error("quota_clone_plugin: Failed to lookup current quota bytes");
62
dict_set(trans, DICT_QUOTA_CLONE_BYTES_PATH,
63
t_strdup_printf("%llu", (unsigned long long)value));
66
ret = quota_get_resource(root, "", QUOTA_NAME_MESSAGES,
69
i_error("quota_clone_plugin: Failed to lookup current quota count");
71
dict_set(trans, DICT_QUOTA_CLONE_COUNT_PATH,
72
t_strdup_printf("%llu", (unsigned long long)value));
74
if (dict_transaction_commit(&trans) < 0)
75
i_error("quota_clone_plugin: Failed to commit dict update");
77
qbox->quota_changed = FALSE;
80
static int quota_clone_save_finish(struct mail_save_context *ctx)
82
struct quota_clone_mailbox *qbox =
83
QUOTA_CLONE_CONTEXT(ctx->transaction->box);
85
qbox->quota_changed = TRUE;
86
return qbox->module_ctx.super.save_finish(ctx);
90
quota_clone_copy(struct mail_save_context *ctx, struct mail *mail)
92
struct quota_clone_mailbox *qbox =
93
QUOTA_CLONE_CONTEXT(ctx->transaction->box);
95
qbox->quota_changed = TRUE;
96
return qbox->module_ctx.super.copy(ctx, mail);
100
quota_clone_mailbox_sync_notify(struct mailbox *box, uint32_t uid,
101
enum mailbox_sync_type sync_type)
103
struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
105
if (qbox->module_ctx.super.sync_notify != NULL)
106
qbox->module_ctx.super.sync_notify(box, uid, sync_type);
108
if (sync_type == MAILBOX_SYNC_TYPE_EXPUNGE)
109
qbox->quota_changed = TRUE;
112
static void quota_clone_mailbox_close(struct mailbox *box)
114
struct quota_clone_mailbox *qbox = QUOTA_CLONE_CONTEXT(box);
116
qbox->module_ctx.super.close(box);
117
if (qbox->quota_changed)
118
quota_clone_flush(box);
121
static void quota_clone_mailbox_allocated(struct mailbox *box)
123
struct quota_clone_user *quser =
124
QUOTA_CLONE_USER_CONTEXT(box->storage->user);
125
struct mailbox_vfuncs *v = box->vlast;
126
struct quota_clone_mailbox *qbox;
131
qbox = p_new(box->pool, struct quota_clone_mailbox, 1);
132
qbox->module_ctx.super = *v;
133
box->vlast = &qbox->module_ctx.super;
135
v->save_finish = quota_clone_save_finish;
136
v->copy = quota_clone_copy;
137
v->sync_notify = quota_clone_mailbox_sync_notify;
138
v->close = quota_clone_mailbox_close;
139
MODULE_CONTEXT_SET(box, quota_clone_storage_module, qbox);
142
static void quota_clone_mail_user_deinit(struct mail_user *user)
144
struct quota_clone_user *quser = QUOTA_CLONE_USER_CONTEXT(user);
146
dict_deinit(&quser->dict);
147
quser->module_ctx.super.deinit(user);
150
static void quota_clone_mail_user_created(struct mail_user *user)
152
struct quota_clone_user *quser;
153
struct mail_user_vfuncs *v = user->vlast;
154
struct dict_settings dict_set;
156
const char *uri, *error;
158
uri = mail_user_plugin_getenv(user, "quota_clone_dict");
159
if (uri == NULL || uri[0] == '\0') {
160
i_error("The quota_clone_dict setting is missing from configuration");
164
memset(&dict_set, 0, sizeof(dict_set));
165
dict_set.username = user->username;
166
dict_set.base_dir = user->set->base_dir;
167
(void)mail_user_get_home(user, &dict_set.home_dir);
168
if (dict_init_full(uri, &dict_set, &dict, &error) < 0) {
169
i_error("quota_clone_dict: Failed to initialize '%s': %s",
174
quser = p_new(user->pool, struct quota_clone_user, 1);
175
quser->module_ctx.super = *v;
176
user->vlast = &quser->module_ctx.super;
177
v->deinit = quota_clone_mail_user_deinit;
179
MODULE_CONTEXT_SET(user, quota_clone_user_module, quser);
182
static struct mail_storage_hooks quota_clone_mail_storage_hooks = {
183
.mailbox_allocated = quota_clone_mailbox_allocated,
184
.mail_user_created = quota_clone_mail_user_created
187
void quota_clone_plugin_init(struct module *module ATTR_UNUSED)
189
mail_storage_hooks_add(module, "a_clone_mail_storage_hooks);
192
void quota_clone_plugin_deinit(void)
194
mail_storage_hooks_remove("a_clone_mail_storage_hooks);
197
const char *quota_clone_plugin_dependencies[] = { "quota", NULL };