dict.c revision 75bb83681e30d6a86109bbafdfe6b513c11124bc
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "lib.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "array.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "str.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "dict-sql.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "dict-private.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic ARRAY_DEFINE(dict_drivers, struct dict *);
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomistatic struct dict_iterate_context dict_iter_unsupported;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic struct dict *dict_driver_lookup(const char *name)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dict *const *dicts;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi array_foreach(&dict_drivers, dicts) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dict *dict = *dicts;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (strcmp(dict->name, name) == 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return dict;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return NULL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_driver_register(struct dict *driver)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!array_is_created(&dict_drivers))
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_array_init(&dict_drivers, 8);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (dict_driver_lookup(driver->name) != NULL) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_fatal("dict_driver_register(%s): Already registered",
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi driver->name);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi array_append(&dict_drivers, &driver, 1);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_driver_unregister(struct dict *driver)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dict *const *dicts;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned int idx = -1U;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi array_foreach(&dict_drivers, dicts) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (*dicts == driver) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi idx = array_foreach_idx(&dict_drivers, dicts);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi break;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(idx != -1U);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi array_delete(&dict_drivers, idx, 1);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (array_count(&dict_drivers) == 0)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi array_free(&dict_drivers);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_drivers_register_builtin(void)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dict_driver_register(&dict_driver_client);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dict_driver_register(&dict_driver_file);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dict_driver_register(&dict_driver_memcached);
b0c472c7a93dfc869e2124ca738d62f1d6794e43Timo Sirainen dict_driver_register(&dict_driver_memcached_ascii);
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi dict_driver_register(&dict_driver_redis);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_drivers_unregister_builtin(void)
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi{
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi dict_driver_unregister(&dict_driver_client);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dict_driver_unregister(&dict_driver_file);
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi dict_driver_unregister(&dict_driver_memcached);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dict_driver_unregister(&dict_driver_memcached_ascii);
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi dict_driver_unregister(&dict_driver_redis);
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomistruct dict *dict_init(const char *uri, enum dict_data_type value_type,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *username, const char *base_dir)
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dict *dict;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *p, *name;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(username != NULL);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi p = strchr(uri, ':');
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (p == NULL) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_error("Dictionary URI is missing ':': %s", uri);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return NULL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi T_BEGIN {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi name = t_strdup_until(uri, p);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dict = dict_driver_lookup(name);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (dict == NULL)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_error("Unknown dict module: %s", name);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } T_END;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
b0c472c7a93dfc869e2124ca738d62f1d6794e43Timo Sirainen return dict == NULL ? NULL :
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi dict->v.init(dict, p+1, value_type, username, base_dir);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_deinit(struct dict **_dict)
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi{
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi struct dict *dict = *_dict;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi *_dict = NULL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dict->v.deinit(dict);
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi}
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint dict_wait(struct dict *dict)
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return dict->v.wait == NULL ? 1 : dict->v.wait(dict);
de1c645a79d42c37dffb7f52e9c643b6251fdcd0Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic bool dict_key_prefix_is_valid(const char *key)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return strncmp(key, DICT_PATH_SHARED, strlen(DICT_PATH_SHARED)) == 0 ||
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE)) == 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint dict_lookup(struct dict *dict, pool_t pool, const char *key,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char **value_r)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(dict_key_prefix_is_valid(key));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return dict->v.lookup(dict, pool, key, value_r);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistruct dict_iterate_context *
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomidict_iterate_init(struct dict *dict, const char *path,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi enum dict_iterate_flags flags)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *paths[2];
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi paths[0] = path;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi paths[1] = NULL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return dict_iterate_init_multiple(dict, paths, flags);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistruct dict_iterate_context *
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomidict_iterate_init_multiple(struct dict *dict, const char *const *paths,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi enum dict_iterate_flags flags)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned int i;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(paths[0] != NULL);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi for (i = 0; paths[i] != NULL; i++)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(dict_key_prefix_is_valid(paths[i]));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (dict->v.iterate_init == NULL) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* not supported by backend */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_error("%s: dict iteration not supported", dict->name);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return &dict_iter_unsupported;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return dict->v.iterate_init(dict, paths, flags);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomibool dict_iterate(struct dict_iterate_context *ctx,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char **key_r, const char **value_r)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return ctx == &dict_iter_unsupported ? FALSE :
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->dict->v.iterate(ctx, key_r, value_r);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint dict_iterate_deinit(struct dict_iterate_context **_ctx)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dict_iterate_context *ctx = *_ctx;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi *_ctx = NULL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return ctx == &dict_iter_unsupported ? -1 :
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->dict->v.iterate_deinit(ctx);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistruct dict_transaction_context *dict_transaction_begin(struct dict *dict)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return dict->v.transaction_init(dict);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint dict_transaction_commit(struct dict_transaction_context **_ctx)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dict_transaction_context *ctx = *_ctx;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi *_ctx = NULL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return ctx->dict->v.transaction_commit(ctx, FALSE, NULL, NULL);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_transaction_commit_async(struct dict_transaction_context **_ctx,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dict_transaction_commit_callback_t *callback,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi void *context)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dict_transaction_context *ctx = *_ctx;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi *_ctx = NULL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->dict->v.transaction_commit(ctx, TRUE, callback, context);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_transaction_rollback(struct dict_transaction_context **_ctx)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dict_transaction_context *ctx = *_ctx;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi *_ctx = NULL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->dict->v.transaction_rollback(ctx);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_set(struct dict_transaction_context *ctx,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *key, const char *value)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(dict_key_prefix_is_valid(key));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->dict->v.set(ctx, key, value);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->changed = TRUE;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_unset(struct dict_transaction_context *ctx,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *key)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(dict_key_prefix_is_valid(key));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->dict->v.unset(ctx, key);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->changed = TRUE;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid dict_append(struct dict_transaction_context *ctx,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *key, const char *value)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
a62dad9ec88bb112079dd95be456d258c6c86369Timo Sirainen i_assert(dict_key_prefix_is_valid(key));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->dict->v.append(ctx, key, value);
6b136bb200a5f803d0ef5af225ad891e862b6b75Timo Sirainen ctx->changed = TRUE;
6b136bb200a5f803d0ef5af225ad891e862b6b75Timo Sirainen}
6b136bb200a5f803d0ef5af225ad891e862b6b75Timo Sirainen
6b136bb200a5f803d0ef5af225ad891e862b6b75Timo Sirainenvoid dict_atomic_inc(struct dict_transaction_context *ctx,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *key, long long diff)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(dict_key_prefix_is_valid(key));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (diff != 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->dict->v.atomic_inc(ctx, key, diff);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ctx->changed = TRUE;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiconst char *dict_escape_string(const char *str)
{
const char *p;
string_t *ret;
/* see if we need to escape it */
for (p = str; *p != '\0'; p++) {
if (*p == '/' || *p == '\\')
break;
}
if (*p == '\0')
return str;
/* escape */
ret = t_str_new((size_t) (p - str) + 128);
str_append_n(ret, str, (size_t) (p - str));
for (; *p != '\0'; p++) {
switch (*p) {
case '/':
str_append_c(ret, '\\');
str_append_c(ret, '|');
break;
case '\\':
str_append_c(ret, '\\');
str_append_c(ret, '\\');
break;
default:
str_append_c(ret, *p);
break;
}
}
return str_c(ret);
}
const char *dict_unescape_string(const char *str)
{
const char *p;
string_t *ret;
/* see if we need to unescape it */
for (p = str; *p != '\0'; p++) {
if (*p == '\\')
break;
}
if (*p == '\0')
return str;
/* unescape */
ret = t_str_new((size_t) (p - str) + strlen(p) + 1);
str_append_n(ret, str, (size_t) (p - str));
for (; *p != '\0'; p++) {
if (*p != '\\')
str_append_c(ret, *p);
else {
if (*++p == '|')
str_append_c(ret, '/');
else if (*p == '\0')
break;
else
str_append_c(ret, *p);
}
}
return str_c(ret);
}