quota-dict.c revision 9c0cd052c03799d764938ffe500cf510bf9eb464
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2005-2015 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DICT_QUOTA_CURRENT_PATH DICT_PATH_PRIVATE"quota/"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#define DICT_QUOTA_CURRENT_BYTES_PATH DICT_QUOTA_CURRENT_PATH"storage"
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen#define DICT_QUOTA_CURRENT_COUNT_PATH DICT_QUOTA_CURRENT_PATH"messages"
4fe3f07477bae6da3fb8d8fa9bab10ab82ada2bdTimo Sirainenextern struct quota_backend quota_backend_dict;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic struct quota_root *dict_quota_alloc(void)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic int dict_quota_init(struct quota_root *_root, const char *args,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen const char **error_r)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct dict_quota_root *root = (struct dict_quota_root *)_root;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* FIXME: pretty ugly in here. the parameters should have
a356c4736fe6041142c6096045bc00c15a80af4eTimo Sirainen been designed to be extensible. do it in a future version */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (strncmp(args, "hidden:", 7) == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (strncmp(args, "ignoreunlimited:", 16) == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen _root->ns_prefix = p_strdup_until(_root->pool,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_debug("dict quota: user=%s, uri=%s, noenforcing=%d",
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* FIXME: we should use 64bit integer as datatype instead but before
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen it can actually be used don't bother */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen set.base_dir = _root->quota->user->set->base_dir;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (mail_user_get_home(_root->quota->user, &set.home_dir) <= 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (dict_init_full(args, &set, &root->dict, &error) < 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *error_r = t_strdup_printf("dict_init(%s) failed: %s", args, error);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void dict_quota_deinit(struct quota_root *_root)
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen struct dict_quota_root *root = (struct dict_quota_root *)_root;
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainenstatic const char *const *
4c20178a7f70bfe43d252e50796013aac1d8c74aTimo Sirainendict_quota_root_get_resources(struct quota_root *root ATTR_UNUSED)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen static const char *resources[] = {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen QUOTA_NAME_STORAGE_KILOBYTES, QUOTA_NAME_MESSAGES, NULL
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if (quota_count(&root->root, &bytes, &count) < 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* these unsets are mainly necessary for pgsql, because its
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen trigger otherwise increases quota without deleting it */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dict_unset(dt, DICT_QUOTA_CURRENT_BYTES_PATH);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dict_unset(dt, DICT_QUOTA_CURRENT_COUNT_PATH);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dict_set(dt, DICT_QUOTA_CURRENT_BYTES_PATH, dec2str(bytes));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dict_set(dt, DICT_QUOTA_CURRENT_COUNT_PATH, dec2str(count));
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen dict_transaction_commit_async(&dt, NULL, NULL);
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainendict_quota_get_resource(struct quota_root *_root,
8e1ecc6542da1e14c14e2e59d39dbccdbf68e2b5Timo Sirainen struct dict_quota_root *root = (struct dict_quota_root *)_root;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen ret = dict_lookup(root->dict, unsafe_data_stack_pool,
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* recalculate quota if it's negative or if it
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen wasn't found */
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen tmp = ret == 0 ? -1 : strtoll(value, NULL, 10);
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainenstatic void dict_quota_update_callback(int ret, void *context)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen /* row doesn't exist, need to recalculate it */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen } else if (ret < 0) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen i_error("dict quota: Quota update failed, it's now desynced");
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct dict_quota_root *root = (struct dict_quota_root *) _root;
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dict_atomic_inc(dt, DICT_QUOTA_CURRENT_BYTES_PATH,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dict_atomic_inc(dt, DICT_QUOTA_CURRENT_COUNT_PATH,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen dict_transaction_commit_async(&dt, dict_quota_update_callback,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainenstatic void dict_quota_flush(struct quota_root *_root)
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen struct dict_quota_root *root = (struct dict_quota_root *)_root;