summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/managesieve/cmd-getscript.c
diff options
context:
space:
mode:
Diffstat (limited to 'pigeonhole/src/managesieve/cmd-getscript.c')
-rw-r--r--pigeonhole/src/managesieve/cmd-getscript.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/pigeonhole/src/managesieve/cmd-getscript.c b/pigeonhole/src/managesieve/cmd-getscript.c
new file mode 100644
index 0000000..2f0a5f9
--- /dev/null
+++ b/pigeonhole/src/managesieve/cmd-getscript.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
+ */
+
+#include "lib.h"
+#include "ostream.h"
+#include "istream.h"
+#include "iostream.h"
+
+#include "sieve-script.h"
+#include "sieve-storage.h"
+
+#include "managesieve-common.h"
+#include "managesieve-commands.h"
+
+struct cmd_getscript_context {
+ struct client *client;
+ struct client_command_context *cmd;
+ struct sieve_storage *storage;
+ uoff_t script_size;
+
+ const char *scriptname;
+ struct sieve_script *script;
+ struct istream *script_stream;
+
+ bool failed:1;
+};
+
+static bool cmd_getscript_finish(struct cmd_getscript_context *ctx)
+{
+ struct client_command_context *cmd = ctx->cmd;
+ struct client *client = ctx->client;
+
+ if (ctx->script != NULL)
+ sieve_script_unref(&ctx->script);
+
+ if (ctx->failed) {
+ if (client->output->closed) {
+ client_disconnect(client, NULL);
+ return TRUE;
+ }
+
+ client_command_storage_error(
+ cmd, "Failed to retrieve script `%s'", ctx->scriptname);
+ return TRUE;
+ }
+
+ client->get_count++;
+ client->get_bytes += ctx->script_size;
+
+ struct event_passthrough *e =
+ client_command_create_finish_event(cmd);
+ e_debug(e->event(), "Retrieved script `%s'", ctx->scriptname);
+
+ client_send_line(client, "");
+ client_send_ok(client, "Getscript completed.");
+ return TRUE;
+}
+
+static bool cmd_getscript_continue(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct cmd_getscript_context *ctx = cmd->context;
+
+ switch (o_stream_send_istream(client->output, ctx->script_stream)) {
+ case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
+ if (ctx->script_stream->v_offset != ctx->script_size &&
+ !ctx->failed) {
+ /* Input stream gave less data than expected */
+ sieve_storage_set_critical(
+ ctx->storage, "GETSCRIPT for script `%s' "
+ "from %s got too little data: "
+ "%"PRIuUOFF_T" vs %"PRIuUOFF_T,
+ sieve_script_name(ctx->script),
+ sieve_script_location(ctx->script),
+ ctx->script_stream->v_offset, ctx->script_size);
+ client_disconnect(ctx->client, "GETSCRIPT failed");
+ ctx->failed = TRUE;
+ }
+ break;
+ case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
+ i_unreached();
+ case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
+ return FALSE;
+ case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
+ sieve_storage_set_critical(ctx->storage,
+ "o_stream_send_istream() failed for script `%s' "
+ "from %s: %s",
+ sieve_script_name(ctx->script),
+ sieve_script_location(ctx->script),
+ i_stream_get_error(ctx->script_stream));
+ ctx->failed = TRUE;
+ break;
+ case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
+ client_disconnect(ctx->client, NULL);
+ ctx->failed = TRUE;
+ break;
+ }
+ return cmd_getscript_finish(ctx);
+}
+
+bool cmd_getscript(struct client_command_context *cmd)
+{
+ struct client *client = cmd->client;
+ struct cmd_getscript_context *ctx;
+ const char *scriptname;
+ enum sieve_error error;
+
+ /* <scriptname> */
+ if (!client_read_string_args(cmd, TRUE, 1, &scriptname))
+ return FALSE;
+
+ event_add_str(cmd->event, "script_name", scriptname);
+
+ ctx = p_new(cmd->pool, struct cmd_getscript_context, 1);
+ ctx->cmd = cmd;
+ ctx->client = client;
+ ctx->scriptname = p_strdup(cmd->pool, scriptname);
+ ctx->storage = client->storage;
+ ctx->failed = FALSE;
+
+ ctx->script = sieve_storage_open_script(client->storage, scriptname,
+ NULL);
+ if (ctx->script == NULL) {
+ ctx->failed = TRUE;
+ return cmd_getscript_finish(ctx);
+ }
+
+ if (sieve_script_get_stream(ctx->script, &ctx->script_stream,
+ &error) < 0 ) {
+ if (error == SIEVE_ERROR_NOT_FOUND) {
+ sieve_storage_set_error(client->storage, error,
+ "Script does not exist.");
+ }
+ ctx->failed = TRUE;
+ return cmd_getscript_finish(ctx);
+ }
+
+ if (sieve_script_get_size(ctx->script, &ctx->script_size) <= 0) {
+ sieve_storage_set_critical(ctx->storage,
+ "failed to obtain script size for script `%s' from %s",
+ sieve_script_name(ctx->script),
+ sieve_script_location(ctx->script));
+ ctx->failed = TRUE;
+ return cmd_getscript_finish(ctx);
+ }
+
+ i_assert(ctx->script_stream->v_offset == 0);
+
+ client_send_line(client, t_strdup_printf("{%"PRIuUOFF_T"}",
+ ctx->script_size));
+
+ client->command_pending = TRUE;
+ cmd->func = cmd_getscript_continue;
+ cmd->context = ctx;
+
+ return cmd_getscript_continue(cmd);
+}