bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen#include "lib.h"
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen#include "array.h"
5012586ed3a75857ced48302bf0b8a8dc049796aTimo Sirainen#include "llist.h"
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen#include "str.h"
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen#include "dict-private.h"
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainenstatic ARRAY(struct dict *) dict_drivers;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenstatic struct dict *dict_driver_lookup(const char *name)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen struct dict *const *dicts;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&dict_drivers, dicts) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen struct dict *dict = *dicts;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (strcmp(dict->name, name) == 0)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen return dict;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen }
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen return NULL;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainenvoid dict_transaction_commit_async_noop_callback(
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainen const struct dict_commit_result *result ATTR_UNUSED,
75a7ba70c7b377eff0f7124b8943cf2976ac2533Aki Tuomi void *context ATTR_UNUSED)
75a7ba70c7b377eff0f7124b8943cf2976ac2533Aki Tuomi{
75a7ba70c7b377eff0f7124b8943cf2976ac2533Aki Tuomi /* do nothing */
75a7ba70c7b377eff0f7124b8943cf2976ac2533Aki Tuomi}
75a7ba70c7b377eff0f7124b8943cf2976ac2533Aki Tuomi
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenvoid dict_driver_register(struct dict *driver)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen if (!array_is_created(&dict_drivers))
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen i_array_init(&dict_drivers, 8);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen if (dict_driver_lookup(driver->name) != NULL) {
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen i_fatal("dict_driver_register(%s): Already registered",
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen driver->name);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen }
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen array_append(&dict_drivers, &driver, 1);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenvoid dict_driver_unregister(struct dict *driver)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen struct dict *const *dicts;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen unsigned int idx = UINT_MAX;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&dict_drivers, dicts) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (*dicts == driver) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen idx = array_foreach_idx(&dict_drivers, dicts);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen break;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen }
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen }
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen i_assert(idx != UINT_MAX);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_delete(&dict_drivers, idx, 1);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen if (array_count(&dict_drivers) == 0)
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen array_free(&dict_drivers);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
20e04227229970d148801c507946666e2a9bd838Timo Sirainenint dict_init(const char *uri, const struct dict_settings *set,
20e04227229970d148801c507946666e2a9bd838Timo Sirainen struct dict **dict_r, const char **error_r)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen struct dict *dict;
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen const char *p, *name, *error;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen i_assert(set->username != NULL);
080a75584cfbe21ffd2d23c6bbb4cd8fdfd0990cTimo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen p = strchr(uri, ':');
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen if (p == NULL) {
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *error_r = t_strdup_printf("Dictionary URI is missing ':': %s",
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen uri);
10399559650f552a23949772be79eb6a80198c5aTimo Sirainen return -1;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen }
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen name = t_strdup_until(uri, p);
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen dict = dict_driver_lookup(name);
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen if (dict == NULL) {
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *error_r = t_strdup_printf("Unknown dict module: %s", name);
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen return -1;
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen }
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen if (dict->v.init(dict, p+1, set, dict_r, &error) < 0) {
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *error_r = t_strdup_printf("dict %s: %s", name, error);
10399559650f552a23949772be79eb6a80198c5aTimo Sirainen return -1;
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen }
8e066cce954f6d23acec4b669b09b358401bd386Aki Tuomi i_assert(*dict_r != NULL);
8e066cce954f6d23acec4b669b09b358401bd386Aki Tuomi
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen return 0;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid dict_deinit(struct dict **_dict)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct dict *dict = *_dict;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_dict = NULL;
be64b3bbf9e1664071516f2a4a68a0916da7abacAki Tuomi
be64b3bbf9e1664071516f2a4a68a0916da7abacAki Tuomi i_assert(dict->iter_count == 0);
be64b3bbf9e1664071516f2a4a68a0916da7abacAki Tuomi i_assert(dict->transaction_count == 0);
5012586ed3a75857ced48302bf0b8a8dc049796aTimo Sirainen i_assert(dict->transactions == NULL);
be64b3bbf9e1664071516f2a4a68a0916da7abacAki Tuomi
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen dict->v.deinit(dict);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
c4478af52de63804efef2055580adf1dfc8679c6Timo Sirainenvoid dict_wait(struct dict *dict)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
c4478af52de63804efef2055580adf1dfc8679c6Timo Sirainen if (dict->v.wait != NULL)
c4478af52de63804efef2055580adf1dfc8679c6Timo Sirainen dict->v.wait(dict);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainenbool dict_switch_ioloop(struct dict *dict)
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen{
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen if (dict->v.switch_ioloop != NULL)
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen return dict->v.switch_ioloop(dict);
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen else
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen return FALSE;
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen}
a5ec9755556e3d97d7e6d78cb1b53046370e6598Timo Sirainen
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainenstatic bool dict_key_prefix_is_valid(const char *key)
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen{
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen return strncmp(key, DICT_PATH_SHARED, strlen(DICT_PATH_SHARED)) == 0 ||
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE)) == 0;
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen}
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen
f8ead0942a9b7c8fcf91414ed1b534d5807ca555Timo Sirainenint dict_lookup(struct dict *dict, pool_t pool, const char *key,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char **value_r, const char **error_r)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen i_assert(dict_key_prefix_is_valid(key));
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen return dict->v.lookup(dict, pool, key, value_r, error_r);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainenvoid dict_lookup_async(struct dict *dict, const char *key,
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen dict_lookup_callback_t *callback, void *context)
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen{
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen if (dict->v.lookup_async == NULL) {
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen struct dict_lookup_result result;
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&result);
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen result.ret = dict_lookup(dict, pool_datastack_create(),
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen key, &result.value, &result.error);
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen const char *const values[] = { result.value, NULL };
85b234661baa110e046d3d9ad22f59e69fa75c69Timo Sirainen result.values = values;
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen callback(&result, context);
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen return;
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen }
f990dde096949bd2b76aab28936211689bd6cadcTimo Sirainen dict->v.lookup_async(dict, key, callback, context);
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen}
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainenstruct dict_iterate_context *
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainendict_iterate_init(struct dict *dict, const char *path,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen enum dict_iterate_flags flags)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen const char *paths[2];
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen paths[0] = path;
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen paths[1] = NULL;
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen return dict_iterate_init_multiple(dict, paths, flags);
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen}
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainenstruct dict_iterate_context *
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainendict_iterate_init_multiple(struct dict *dict, const char *const *paths,
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen enum dict_iterate_flags flags)
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen{
b198cd6da331eb55d300b0e83f59695c58d5885cTimo Sirainen struct dict_iterate_context *ctx;
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen unsigned int i;
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen i_assert(paths[0] != NULL);
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen for (i = 0; paths[i] != NULL; i++)
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen i_assert(dict_key_prefix_is_valid(paths[i]));
b198cd6da331eb55d300b0e83f59695c58d5885cTimo Sirainen
e3237982a4e6346c2fec4b8f8fb946c826a363fdTimo Sirainen if (dict->v.iterate_init == NULL) {
e3237982a4e6346c2fec4b8f8fb946c826a363fdTimo Sirainen /* not supported by backend */
b198cd6da331eb55d300b0e83f59695c58d5885cTimo Sirainen ctx = &dict_iter_unsupported;
b198cd6da331eb55d300b0e83f59695c58d5885cTimo Sirainen } else {
b198cd6da331eb55d300b0e83f59695c58d5885cTimo Sirainen ctx = dict->v.iterate_init(dict, paths, flags);
e3237982a4e6346c2fec4b8f8fb946c826a363fdTimo Sirainen }
10f126b558e39b0f69fe2baecc9e74d2bfad8c7dAki Tuomi /* the dict in context can differ from the dict
10f126b558e39b0f69fe2baecc9e74d2bfad8c7dAki Tuomi passed as parameter, e.g. it can be dict-fail when
10f126b558e39b0f69fe2baecc9e74d2bfad8c7dAki Tuomi iteration is not supported. */
10f126b558e39b0f69fe2baecc9e74d2bfad8c7dAki Tuomi ctx->dict->iter_count++;
b198cd6da331eb55d300b0e83f59695c58d5885cTimo Sirainen return ctx;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainenbool dict_iterate(struct dict_iterate_context *ctx,
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen const char **key_r, const char **value_r)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen if (ctx->max_rows > 0 && ctx->row_count >= ctx->max_rows) {
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen /* row count was limited */
ea90267d457a03b5b1e0e2a5111949609edb4cb3Timo Sirainen ctx->has_more = FALSE;
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen return FALSE;
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen }
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen if (!ctx->dict->v.iterate(ctx, key_r, value_r))
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen return FALSE;
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen ctx->row_count++;
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen return TRUE;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainenvoid dict_iterate_set_async_callback(struct dict_iterate_context *ctx,
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen dict_iterate_callback_t *callback,
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen void *context)
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen{
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen ctx->async_callback = callback;
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen ctx->async_context = context;
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen}
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainenvoid dict_iterate_set_limit(struct dict_iterate_context *ctx,
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen uint64_t max_rows)
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen{
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen ctx->max_rows = max_rows;
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen}
6acd1a48e1377e74d3008288e5e95e006f41265cTimo Sirainen
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainenbool dict_iterate_has_more(struct dict_iterate_context *ctx)
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen{
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen return ctx->has_more;
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen}
d694b6009574ee6e3cfaee3834cbdbcd431affb0Timo Sirainen
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainenint dict_iterate_deinit(struct dict_iterate_context **_ctx,
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen const char **error_r)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainen struct dict_iterate_context *ctx = *_ctx;
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainen
b198cd6da331eb55d300b0e83f59695c58d5885cTimo Sirainen i_assert(ctx->dict->iter_count > 0);
b198cd6da331eb55d300b0e83f59695c58d5885cTimo Sirainen ctx->dict->iter_count--;
b198cd6da331eb55d300b0e83f59695c58d5885cTimo Sirainen
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainen *_ctx = NULL;
055389c58fa3915e12fb4e72ec86782ce77c5c72Timo Sirainen return ctx->dict->v.iterate_deinit(ctx, error_r);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainenstruct dict_transaction_context *dict_transaction_begin(struct dict *dict)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi struct dict_transaction_context *ctx;
7932885c8a996991f46f877cca0043d2cd2cc9daAki Tuomi if (dict->v.transaction_init == NULL)
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi ctx = &dict_transaction_unsupported;
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi else
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi ctx = dict->v.transaction_init(dict);
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi /* the dict in context can differ from the dict
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi passed as parameter, e.g. it can be dict-fail when
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi transactions are not supported. */
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi ctx->dict->transaction_count++;
5012586ed3a75857ced48302bf0b8a8dc049796aTimo Sirainen DLLIST_PREPEND(&ctx->dict->transactions, ctx);
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi return ctx;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainenvoid dict_transaction_no_slowness_warning(struct dict_transaction_context *ctx)
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainen{
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainen ctx->no_slowness_warning = TRUE;
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainen}
aef407f147034a569591c0f59593342a8c7b39eaTimo Sirainen
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainenvoid dict_transaction_set_timestamp(struct dict_transaction_context *ctx,
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen const struct timespec *ts)
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen{
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen /* These asserts are mainly here to guarantee a possibility in future
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen to change the API to support multiple timestamps within the same
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen transaction, so this call would apply only to the following
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen changes. */
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen i_assert(!ctx->changed);
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen i_assert(ctx->timestamp.tv_sec == 0);
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen i_assert(ts->tv_sec > 0);
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen ctx->timestamp = *ts;
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen if (ctx->dict->v.set_timestamp != NULL)
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen ctx->dict->v.set_timestamp(ctx, ts);
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen}
e28b4fc2b62be020156a857485b61842b3b5d791Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstruct dict_commit_sync_result {
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen int ret;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen char *error;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen};
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainendict_transaction_commit_sync_callback(const struct dict_commit_result *result,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen void *context)
c2a66e7950cb4d3fc4d68e4480ea8f39bdd7c871Timo Sirainen{
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen struct dict_commit_sync_result *sync_result = context;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen sync_result->ret = result->ret;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen sync_result->error = i_strdup(result->error);
c2a66e7950cb4d3fc4d68e4480ea8f39bdd7c871Timo Sirainen}
c2a66e7950cb4d3fc4d68e4480ea8f39bdd7c871Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenint dict_transaction_commit(struct dict_transaction_context **_ctx,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const char **error_r)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainen struct dict_transaction_context *ctx = *_ctx;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen struct dict_commit_sync_result result;
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainen
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainen *_ctx = NULL;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&result);
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi i_assert(ctx->dict->transaction_count > 0);
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi ctx->dict->transaction_count--;
5012586ed3a75857ced48302bf0b8a8dc049796aTimo Sirainen DLLIST_REMOVE(&ctx->dict->transactions, ctx);
c2a66e7950cb4d3fc4d68e4480ea8f39bdd7c871Timo Sirainen ctx->dict->v.transaction_commit(ctx, FALSE,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen dict_transaction_commit_sync_callback, &result);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen *error_r = t_strdup(result.error);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen i_free(result.error);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen return result.ret;
d3fce898d31ad40b554c91f3035a7f4d7d52ed52Timo Sirainen}
d3fce898d31ad40b554c91f3035a7f4d7d52ed52Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenvoid dict_transaction_commit_async(struct dict_transaction_context **_ctx,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen dict_transaction_commit_callback_t *callback,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen void *context)
d3fce898d31ad40b554c91f3035a7f4d7d52ed52Timo Sirainen{
d3fce898d31ad40b554c91f3035a7f4d7d52ed52Timo Sirainen struct dict_transaction_context *ctx = *_ctx;
d3fce898d31ad40b554c91f3035a7f4d7d52ed52Timo Sirainen
d3fce898d31ad40b554c91f3035a7f4d7d52ed52Timo Sirainen *_ctx = NULL;
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi i_assert(ctx->dict->transaction_count > 0);
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi ctx->dict->transaction_count--;
5012586ed3a75857ced48302bf0b8a8dc049796aTimo Sirainen DLLIST_REMOVE(&ctx->dict->transactions, ctx);
75a7ba70c7b377eff0f7124b8943cf2976ac2533Aki Tuomi if (callback == NULL)
701eb90460d6c57845dc4e0bf595a5d0b90b01c1Timo Sirainen callback = dict_transaction_commit_async_noop_callback;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ctx->dict->v.transaction_commit(ctx, TRUE, callback, context);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainenvoid dict_transaction_rollback(struct dict_transaction_context **_ctx)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainen struct dict_transaction_context *ctx = *_ctx;
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainen
1dc6f277f5ac6a3dd5cd6aa75a7ef691de9acb7aTimo Sirainen *_ctx = NULL;
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi i_assert(ctx->dict->transaction_count > 0);
f32da6b73c1edb6963eae0d4a5c1f995ad23151aAki Tuomi ctx->dict->transaction_count--;
5012586ed3a75857ced48302bf0b8a8dc049796aTimo Sirainen DLLIST_REMOVE(&ctx->dict->transactions, ctx);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen ctx->dict->v.transaction_rollback(ctx);
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainenvoid dict_set(struct dict_transaction_context *ctx,
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen const char *key, const char *value)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen i_assert(dict_key_prefix_is_valid(key));
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen T_BEGIN {
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen ctx->dict->v.set(ctx, key, value);
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen } T_END;
2be7df5df08ac4639ad83559ec5fcf552c84fb4aTimo Sirainen ctx->changed = TRUE;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenvoid dict_unset(struct dict_transaction_context *ctx,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen const char *key)
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen{
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen i_assert(dict_key_prefix_is_valid(key));
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen T_BEGIN {
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen ctx->dict->v.unset(ctx, key);
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen } T_END;
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen ctx->changed = TRUE;
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen}
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainenvoid dict_atomic_inc(struct dict_transaction_context *ctx,
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen const char *key, long long diff)
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen{
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen i_assert(dict_key_prefix_is_valid(key));
fd1a8db8fa61f9c38f063f62753d1bfef0261e19Timo Sirainen
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen if (diff != 0) T_BEGIN {
52de9d38fcad80df481667bac821cb8222785fe6Timo Sirainen ctx->dict->v.atomic_inc(ctx, key, diff);
2be7df5df08ac4639ad83559ec5fcf552c84fb4aTimo Sirainen ctx->changed = TRUE;
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen } T_END;
28c75d59f1d1a7caeb85635964f3881c0038eb23Timo Sirainen}
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainenconst char *dict_escape_string(const char *str)
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen{
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen const char *p;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen string_t *ret;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen /* see if we need to escape it */
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen for (p = str; *p != '\0'; p++) {
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen if (*p == '/' || *p == '\\')
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen break;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen }
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen if (*p == '\0')
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen return str;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen /* escape */
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen ret = t_str_new((size_t) (p - str) + 128);
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_n(ret, str, (size_t) (p - str));
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen for (; *p != '\0'; p++) {
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen switch (*p) {
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen case '/':
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_c(ret, '\\');
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_c(ret, '|');
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen break;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen case '\\':
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_c(ret, '\\');
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_c(ret, '\\');
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen break;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen default:
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_c(ret, *p);
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen break;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen }
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen }
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen return str_c(ret);
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen}
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainenconst char *dict_unescape_string(const char *str)
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen{
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen const char *p;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen string_t *ret;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen /* see if we need to unescape it */
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen for (p = str; *p != '\0'; p++) {
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen if (*p == '\\')
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen break;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen }
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen if (*p == '\0')
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen return str;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen /* unescape */
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen ret = t_str_new((size_t) (p - str) + strlen(p) + 1);
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_n(ret, str, (size_t) (p - str));
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen for (; *p != '\0'; p++) {
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen if (*p != '\\')
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_c(ret, *p);
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen else {
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen if (*++p == '|')
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_c(ret, '/');
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen else if (*p == '\0')
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen break;
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen else
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen str_append_c(ret, *p);
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen }
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen }
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen return str_c(ret);
8971ca621b7a7337947306494731b75d1d3919e5Timo Sirainen}