dict-commands.c revision 79fff61b8fa0ec3c892e22cf792109dc1b398a30
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2005-2016 Dovecot authors, see the included COPYING file */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "lib.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "array.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "ostream.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "str.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "strescape.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "dict-client.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "dict-settings.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "dict-connection.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#include "dict-commands.h"
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch#define DICT_OUTPUT_OPTIMAL_SIZE 1024
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct dict_cmd_func {
70375a50991814959d061db0e2d4da35e542e437Timo Sirainen enum dict_protocol_cmd cmd;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int (*func)(struct dict_connection_cmd *cmd, const char *line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstruct dict_connection_cmd {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct dict_cmd_func *cmd;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection *conn;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch char *reply;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_iterate_context *iter;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch enum dict_iterate_flags iter_flags;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int trans_id;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void dict_connection_cmd_output_more(struct dict_connection_cmd *cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void dict_connection_cmd_free(struct dict_connection_cmd *cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *error;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmd->iter != NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_iterate_deinit(&cmd->iter, &error) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict_iterate() failed: %s", error);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_free(cmd->reply);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_connection_unref(cmd->conn))
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_continue_input(cmd->conn);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_free(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void dict_connection_cmd_remove(struct dict_connection_cmd *cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_cmd *const *cmds;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int i, count;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmds = array_get(&cmd->conn->cmds, &count);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (i = 0; i < count; i++) {
2d8ff6cda406da5c53e635fe31dfadc3bdb05235Timo Sirainen if (cmds[i] == cmd) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_delete(&cmd->conn->cmds, i, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_cmd_free(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_unreached();
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void dict_connection_cmds_flush(struct dict_connection *conn)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_cmd *cmd, *const *first_cmdp;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_ref(conn);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch while (array_count(&conn->cmds) > 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch first_cmdp = array_idx(&conn->cmds, 0);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd = *first_cmdp;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmd->reply == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* command not finished yet */
6541da94741ea43514cdac3dd2ebbcf839ffb783Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_nsend_str(conn->output, cmd->reply);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_cmd_remove(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_unref_safe(conn);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschcmd_lookup_callback(const struct dict_lookup_result *result, void *context)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_cmd *cmd = context;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch if (result->ret > 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->reply = i_strdup_printf("%c%s\n",
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch DICT_PROTOCOL_REPLY_OK, str_tabescape(result->value));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else if (result->ret == 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->reply = i_strdup_printf("%c\n", DICT_PROTOCOL_REPLY_NOTFOUND);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch } else {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("%s", result->error);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->reply = i_strdup_printf("%c%s\n", DICT_PROTOCOL_REPLY_FAIL,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_tabescape(result->error));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_cmds_flush(cmd->conn);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int cmd_lookup(struct dict_connection_cmd *cmd, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* <key> */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_lookup_async(cmd->conn->dict, line, cmd_lookup_callback, cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int cmd_iterate_flush(struct dict_connection_cmd *cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch string_t *str;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *key, *value, *error;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str = t_str_new(256);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_cork(cmd->conn->output);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch while (dict_iterate(cmd->iter, &key, &value)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_truncate(str, 0);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(str, DICT_PROTOCOL_REPLY_OK);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_tabescaped(str, key);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(str, '\t');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((cmd->iter_flags & DICT_ITERATE_FLAG_NO_VALUE) == 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_tabescaped(str, value);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(str, '\n');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_nsend(cmd->conn->output, str_data(str), str_len(str));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (o_stream_get_buffer_used_size(cmd->conn->output) >
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch DICT_OUTPUT_OPTIMAL_SIZE) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (o_stream_flush(cmd->conn->output) <= 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* continue later when there's more space
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch in output buffer */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_uncork(cmd->conn->output);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_set_flush_pending(cmd->conn->output, TRUE);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* flushed everything, continue */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_iterate_has_more(cmd->iter)) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* wait for the next iteration callback */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_truncate(str, 0);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_iterate_deinit(&cmd->iter, &error) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict_iterate() failed: %s", error);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_printfa(str, "%c%s", DICT_PROTOCOL_REPLY_FAIL, error);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(str, '\n');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch o_stream_uncork(cmd->conn->output);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->reply = i_strdup(str_c(str));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_cmds_flush(cmd->conn);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void cmd_iterate_callback(void *context)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_cmd *cmd = context;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_cmd_output_more(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int cmd_iterate(struct dict_connection_cmd *cmd, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *const *args;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int flags;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch args = t_strsplit_tabescaped(line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (str_array_length(args) < 2 ||
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_to_uint(args[0], &flags) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict client: ITERATE: broken input");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* <flags> <path> */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch flags |= DICT_ITERATE_FLAG_ASYNC;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->iter = dict_iterate_init_multiple(cmd->conn->dict, args+1, flags);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->iter_flags = flags;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_iterate_set_async_callback(cmd->iter, cmd_iterate_callback, cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_cmd_output_more(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic struct dict_connection_transaction *
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschdict_connection_transaction_lookup(struct dict_connection *conn,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int id)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_transaction *transaction;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!array_is_created(&conn->transactions))
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_foreach_modifiable(&conn->transactions, transaction) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (transaction->id == id)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return transaction;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschdict_connection_transaction_array_remove(struct dict_connection *conn,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int id)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct dict_connection_transaction *transactions;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen unsigned int i, count;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch transactions = array_get(&conn->transactions, &count);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (i = 0; i < count; i++) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (transactions[i].id == id) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(transactions[i].ctx == NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_delete(&conn->transactions, i, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_unreached();
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int cmd_begin(struct dict_connection_cmd *cmd, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen struct dict_connection_transaction *trans;
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen unsigned int id;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (str_to_uint(line, &id) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict client: Invalid transaction ID %s", line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch if (dict_connection_transaction_lookup(cmd->conn, id) != NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict client: Transaction ID %u already exists", id);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (!array_is_created(&cmd->conn->transactions))
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_array_init(&cmd->conn->transactions, 4);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* <id> */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch trans = array_append_space(&cmd->conn->transactions);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch trans->id = id;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch trans->conn = cmd->conn;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch trans->ctx = dict_transaction_begin(cmd->conn->dict);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschdict_connection_transaction_lookup_parse(struct dict_connection *conn,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *line,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_transaction **trans_r)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int id;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (str_to_uint(line, &id) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict client: Invalid transaction ID %s", line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch *trans_r = dict_connection_transaction_lookup(conn, id);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (*trans_r == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict client: Transaction ID %u doesn't exist", id);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschcmd_commit_finish(struct dict_connection_cmd *cmd,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct dict_commit_result *result, bool async)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch string_t *str = t_str_new(64);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch char chr;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch switch (result->ret) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case 1:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch chr = DICT_PROTOCOL_REPLY_OK;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch case 0:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch chr = DICT_PROTOCOL_REPLY_NOTFOUND;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch default:
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_assert(result->error != NULL);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch chr = DICT_PROTOCOL_REPLY_FAIL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (async)
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody str_append_c(str, DICT_PROTOCOL_REPLY_ASYNC_COMMIT);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_printfa(str, "%c%u", chr, cmd->trans_id);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (chr == DICT_PROTOCOL_REPLY_FAIL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(str, '\t');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_tabescaped(str, result->error);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch str_append_c(str, '\n');
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->reply = i_strdup(str_c(str));
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch dict_connection_transaction_array_remove(cmd->conn, cmd->trans_id);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_cmds_flush(cmd->conn);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void cmd_commit_callback(const struct dict_commit_result *result,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch void *context)
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_cmd *cmd = context;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd_commit_finish(cmd, result, FALSE);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
4fa772eefd5a22a597601488be44997e788cb60dStephan Boschstatic void cmd_commit_callback_async(const struct dict_commit_result *result,
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch void *context)
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_cmd *cmd = context;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd_commit_finish(cmd, result, TRUE);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschcmd_commit(struct dict_connection_cmd *cmd, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_transaction *trans;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->trans_id = trans->id;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_transaction_commit_async(&trans->ctx, cmd_commit_callback, cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschcmd_commit_async(struct dict_connection_cmd *cmd, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_transaction *trans;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->trans_id = trans->id;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_transaction_commit_async(&trans->ctx, cmd_commit_callback_async, cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int cmd_rollback(struct dict_connection_cmd *cmd, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_transaction *trans;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_connection_transaction_lookup_parse(cmd->conn, line, &trans) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_transaction_rollback(&trans->ctx);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_transaction_array_remove(cmd->conn, trans->id);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int cmd_set(struct dict_connection_cmd *cmd, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_transaction *trans;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *const *args;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* <id> <key> <value> */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch args = t_strsplit_tabescaped(line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (str_array_length(args) != 3) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict client: SET: broken input");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_set(trans->ctx, args[1], args[2]);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int cmd_unset(struct dict_connection_cmd *cmd, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_transaction *trans;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const char *const *args;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* <id> <key> */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch args = t_strsplit_tabescaped(line);
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen if (str_array_length(args) != 2) {
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen i_error("dict client: UNSET: broken input");
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen dict_unset(trans->ctx, args[1]);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic int cmd_atomic_inc(struct dict_connection_cmd *cmd, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_transaction *trans;
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen const char *const *args;
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen long long diff;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* <id> <key> <diff> */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch args = t_strsplit_tabescaped(line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (str_array_length(args) != 3 ||
2d72e8492960794037a1ca90df34f7ab2a170a81Timo Sirainen str_to_llong(args[2], &diff) < 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict client: ATOMIC_INC: broken input");
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (dict_connection_transaction_lookup_parse(cmd->conn, args[0], &trans) < 0)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_atomic_inc(trans->ctx, args[1], diff);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic const struct dict_cmd_func cmds[] = {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { DICT_PROTOCOL_CMD_LOOKUP, cmd_lookup },
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { DICT_PROTOCOL_CMD_ITERATE, cmd_iterate },
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { DICT_PROTOCOL_CMD_BEGIN, cmd_begin },
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { DICT_PROTOCOL_CMD_COMMIT, cmd_commit },
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { DICT_PROTOCOL_CMD_COMMIT_ASYNC, cmd_commit_async },
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { DICT_PROTOCOL_CMD_ROLLBACK, cmd_rollback },
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { DICT_PROTOCOL_CMD_SET, cmd_set },
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { DICT_PROTOCOL_CMD_UNSET, cmd_unset },
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { DICT_PROTOCOL_CMD_ATOMIC_INC, cmd_atomic_inc },
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch { 0, NULL }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch};
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic const struct dict_cmd_func *dict_command_find(enum dict_protocol_cmd cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch unsigned int i;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch for (i = 0; cmds[i].cmd != '\0'; i++) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmds[i].cmd == cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return &cmds[i];
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return NULL;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschint dict_command_input(struct dict_connection *conn, const char *line)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch const struct dict_cmd_func *cmd_func;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_cmd *cmd;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch int ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd_func = dict_command_find((enum dict_protocol_cmd)*line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmd_func == NULL) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch i_error("dict client: Unknown command %c", *line);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return -1;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd = i_new(struct dict_connection_cmd, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->conn = conn;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd->cmd = cmd_func;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch array_append(&conn->cmds, &cmd, 1);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_ref(conn);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if ((ret = cmd_func->func(cmd, line + 1)) <= 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch dict_connection_cmd_remove(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return ret;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch return 0;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschstatic void dict_connection_cmd_output_more(struct dict_connection_cmd *cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_cmd *const *first_cmdp;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch first_cmdp = array_idx(&cmd->conn->cmds, 0);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (*first_cmdp == cmd)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch (void)cmd_iterate_flush(cmd);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Boschvoid dict_connection_cmds_output_more(struct dict_connection *conn)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch{
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch struct dict_connection_cmd *cmd, *const *first_cmdp;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch /* only iterators may be returning a lot of data */
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch while (array_count(&conn->cmds) > 0) {
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch first_cmdp = array_idx(&conn->cmds, 0);
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch cmd = *first_cmdp;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmd->iter == NULL)
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch break;
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch if (cmd_iterate_flush(cmd) == 0) {
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch /* unfinished */
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch break;
9008daea438f0e389b37aabbbde62a1f02725e32Timo Sirainen }
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch /* cmd should be freed now */
4fa772eefd5a22a597601488be44997e788cb60dStephan Bosch }
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch}
f9511e684858bf5f6ac77ab12254b85b737beae8Stephan Bosch