/* Copyright (c) 2014-2018 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "dict.h" #include "doveadm.h" #include "doveadm-print.h" #include #include static int cmd_dict_init_full(struct doveadm_cmd_context *cctx, doveadm_command_ver2_t *cmd ATTR_UNUSED, enum dict_iterate_flags *iter_flags, struct dict **dict_r, struct dict_op_settings *dopset_r) { struct dict_settings dict_set; struct dict *dict; bool set = FALSE; const char *dict_uri, *error, *key, *username = ""; i_zero(dopset_r); if (doveadm_cmd_param_bool(cctx, "exact", &set) && set) *iter_flags |= DICT_ITERATE_FLAG_EXACT_KEY; if (doveadm_cmd_param_bool(cctx, "recurse", &set) && set) *iter_flags |= DICT_ITERATE_FLAG_RECURSE; if (doveadm_cmd_param_bool(cctx, "no-value", &set) && set) *iter_flags |= DICT_ITERATE_FLAG_NO_VALUE; (void)doveadm_cmd_param_str(cctx, "user", &username); dopset_r->username = username; if (!doveadm_cmd_param_str(cctx, "dict-uri", &dict_uri)) { i_error("dictionary URI must be specified"); doveadm_exit_code = EX_USAGE; return -1; } if (!doveadm_cmd_param_str(cctx, "prefix", &key) && !doveadm_cmd_param_str(cctx, "key", &key)) key = ""; if (!str_begins(key, DICT_PATH_PRIVATE) && !str_begins(key, DICT_PATH_SHARED)) { i_error("Key must begin with '"DICT_PATH_PRIVATE "' or '"DICT_PATH_SHARED"': %s", key); doveadm_exit_code = EX_USAGE; return -1; } if (username[0] == '\0' && str_begins(key, DICT_PATH_PRIVATE)) { i_error("-u must be specified for "DICT_PATH_PRIVATE" keys"); doveadm_exit_code = EX_USAGE; return -1; } dict_drivers_register_builtin(); i_zero(&dict_set); dict_set.base_dir = doveadm_settings->base_dir; if (dict_init(dict_uri, &dict_set, &dict, &error) < 0) { i_error("dict_init(%s) failed: %s", dict_uri, error); doveadm_exit_code = EX_TEMPFAIL; return -1; } *dict_r = dict; return 0; } static int cmd_dict_init(struct doveadm_cmd_context *cctx, doveadm_command_ver2_t *cmd, struct dict **dict_r, struct dict_op_settings *set_r) { enum dict_iterate_flags iter_flags = 0; return cmd_dict_init_full(cctx, cmd, &iter_flags, dict_r, set_r); } struct doveadm_dict_ctx { pool_t pool; int ret; const char *const *values; const char *error; }; static void dict_lookup_callback(const struct dict_lookup_result *result, struct doveadm_dict_ctx *ctx) { ctx->ret = result->ret; ctx->values = result->values == NULL ? NULL : p_strarray_dup(ctx->pool, result->values); ctx->error = p_strdup(ctx->pool, result->error); } static void cmd_dict_get(struct doveadm_cmd_context *cctx) { struct doveadm_dict_ctx ctx; struct dict *dict; const char *key; struct dict_op_settings set; if (!doveadm_cmd_param_str(cctx, "key", &key)) { i_error("dict-get: Missing key"); doveadm_exit_code = EX_USAGE; return; } if (cmd_dict_init(cctx, cmd_dict_get, &dict, &set) < 0) return; doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE); doveadm_print_header("value", "", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); i_zero(&ctx); ctx.pool = pool_alloconly_create("doveadm dict lookup", 512); ctx.ret = -2; dict_lookup_async(dict, &set, key, dict_lookup_callback, &ctx); while (ctx.ret == -2) dict_wait(dict); if (ctx.ret < 0) { i_error("dict_lookup(%s) failed: %s", key, ctx.error); doveadm_exit_code = EX_TEMPFAIL; } else if (ctx.ret == 0) { i_error("%s doesn't exist", key); doveadm_exit_code = DOVEADM_EX_NOTFOUND; } else { unsigned int i, values_count = str_array_length(ctx.values); for (i = 1; i < values_count; i++) doveadm_print_header("value", "", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); for (i = 0; i < values_count; i++) doveadm_print(ctx.values[i]); } pool_unref(&ctx.pool); dict_deinit(&dict); } static void cmd_dict_set(struct doveadm_cmd_context *cctx) { struct dict *dict; struct dict_transaction_context *trans; const char *error; const char *key, *value = ""; struct dict_op_settings set; if (!doveadm_cmd_param_str(cctx, "key", &key) || !doveadm_cmd_param_str(cctx, "value", &value)) { i_error("dict set: Missing parameters"); doveadm_exit_code = EX_USAGE; return; } if (cmd_dict_init(cctx, cmd_dict_set, &dict, &set) < 0) return; trans = dict_transaction_begin(dict, &set); dict_set(trans, key, value); if (dict_transaction_commit(&trans, &error) <= 0) { i_error("dict_transaction_commit() failed: %s", error); doveadm_exit_code = EX_TEMPFAIL; } dict_deinit(&dict); } static void cmd_dict_unset(struct doveadm_cmd_context *cctx) { struct dict *dict; struct dict_transaction_context *trans; const char *error; const char *key; struct dict_op_settings set; if (!doveadm_cmd_param_str(cctx, "key", &key)) { i_error("dict unset: Missing key"); doveadm_exit_code = EX_USAGE; return; } if (cmd_dict_init(cctx, cmd_dict_unset, &dict, &set) < 0) return; trans = dict_transaction_begin(dict, &set); dict_unset(trans, key); if (dict_transaction_commit(&trans, &error) <= 0) { i_error("dict_transaction_commit() failed: %s", error); doveadm_exit_code = EX_TEMPFAIL; } dict_deinit(&dict); } static void cmd_dict_inc(struct doveadm_cmd_context *cctx) { struct dict *dict; struct dict_transaction_context *trans; const char *error; const char *key; int64_t diff; int ret; struct dict_op_settings set; if (!doveadm_cmd_param_str(cctx, "key", &key) || !doveadm_cmd_param_int64(cctx, "difference", &diff)) { i_error("dict-inc: Missing parameters"); doveadm_exit_code = EX_USAGE; return; } if (cmd_dict_init(cctx, cmd_dict_inc, &dict, &set) < 0) return; trans = dict_transaction_begin(dict, &set); dict_atomic_inc(trans, key, diff); ret = dict_transaction_commit(&trans, &error); if (ret < 0) { i_error("dict_transaction_commit() failed: %s", error); doveadm_exit_code = EX_TEMPFAIL; } else if (ret == 0) { i_error("%s doesn't exist", key); doveadm_exit_code = DOVEADM_EX_NOTFOUND; } dict_deinit(&dict); } static void cmd_dict_iter(struct doveadm_cmd_context *cctx) { struct dict *dict; struct dict_iterate_context *iter; enum dict_iterate_flags iter_flags = 0; const char *prefix, *key, *const *values, *error; bool header_printed = FALSE; struct dict_op_settings set; if (!doveadm_cmd_param_str(cctx, "prefix", &prefix)) { i_error("dict-iter: Missing prefix"); doveadm_exit_code = EX_USAGE; return; } if (cmd_dict_init_full(cctx, cmd_dict_iter, &iter_flags, &dict, &set) < 0) return; doveadm_print_init(DOVEADM_PRINT_TYPE_TAB); doveadm_print_header_simple("key"); if ((iter_flags & DICT_ITERATE_FLAG_NO_VALUE) == 0) doveadm_print_header_simple("value"); iter = dict_iterate_init(dict, &set, prefix, iter_flags); while (dict_iterate_values(iter, &key, &values)) { unsigned int values_count = str_array_length(values); if (!header_printed) { for (unsigned int i = 1; i < values_count; i++) doveadm_print_header_simple("value"); header_printed = TRUE; } doveadm_print(key); if ((iter_flags & DICT_ITERATE_FLAG_NO_VALUE) == 0) { for (unsigned int i = 0; i < values_count; i++) doveadm_print(values[i]); } } if (dict_iterate_deinit(&iter, &error) < 0) { i_error("dict_iterate_deinit(%s) failed: %s", prefix, error); doveadm_exit_code = EX_TEMPFAIL; } dict_deinit(&dict); } static struct doveadm_cmd_ver2 doveadm_cmd_dict[] = { { .name = "dict get", .cmd = cmd_dict_get, .usage = "[-u ] ", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_PARAM('u', "user", CMD_PARAM_STR, 0) DOVEADM_CMD_PARAM('\0', "dict-uri", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END }, { .name = "dict set", .cmd = cmd_dict_set, .usage = "[-u ] ", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_PARAM('u', "user", CMD_PARAM_STR, 0) DOVEADM_CMD_PARAM('\0', "dict-uri", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "value", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END }, { .name = "dict unset", .cmd = cmd_dict_unset, .usage = "[-u ] ", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_PARAM('u', "user", CMD_PARAM_STR, 0) DOVEADM_CMD_PARAM('\0', "dict-uri", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END }, { .name = "dict inc", .cmd = cmd_dict_inc, .usage = "[-u ] ", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_PARAM('u', "user", CMD_PARAM_STR, 0) DOVEADM_CMD_PARAM('\0', "dict-uri", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "difference", CMD_PARAM_INT64, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END }, { .name = "dict iter", .cmd = cmd_dict_iter, .usage = "[-u ] [-1RV] ", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_PARAM('u', "user", CMD_PARAM_STR, 0) DOVEADM_CMD_PARAM('1', "exact", CMD_PARAM_BOOL, 0) DOVEADM_CMD_PARAM('R', "recurse", CMD_PARAM_BOOL, 0) DOVEADM_CMD_PARAM('V', "no-value", CMD_PARAM_BOOL, 0) DOVEADM_CMD_PARAM('\0', "dict-uri", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "prefix", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END } }; void doveadm_register_dict_commands(void) { unsigned int i; for (i = 0; i < N_ELEMENTS(doveadm_cmd_dict); i++) doveadm_cmd_register_ver2(&doveadm_cmd_dict[i]); }