1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
/* Copyright (c) 2002-2013 Pigeonhole authors, see the included COPYING file
*/
#include "lib.h"
#include "ostream.h"
#include "istream.h"
#include "sieve-storage-script.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, script_offset;
struct sieve_script *script;
struct istream *script_stream;
unsigned int failed:1;
};
static bool cmd_getscript_finish(struct cmd_getscript_context *ctx)
{
struct client *client = ctx->client;
if ( ctx->script != NULL )
sieve_script_unref(&ctx->script);
if ( ctx->failed ) {
if ( client->output->closed ) {
client_disconnect(client, "Disconnected");
return TRUE;
}
client_send_storage_error(client, client->storage);
return TRUE;
}
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;
off_t ret;
ret = o_stream_send_istream(client->output, ctx->script_stream);
if ( ret < 0 ) {
sieve_storage_set_critical(ctx->storage,
"o_stream_send_istream() failed for script `%s' from %s: %m",
sieve_script_name(ctx->script), sieve_script_location(ctx->script));
ctx->failed = TRUE;
return cmd_getscript_finish(ctx);
}
ctx->script_offset += ret;
if ( ctx->script_offset != ctx->script_size && !ctx->failed ) {
/* unfinished */
if ( !i_stream_have_bytes_left(ctx->script_stream) ) {
/* 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_offset, ctx->script_size);
client_disconnect(ctx->client, "GETSCRIPT failed");
ctx->failed = TRUE;
return cmd_getscript_finish(ctx);
}
return FALSE;
}
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, 1, TRUE, &scriptname) )
return FALSE;
ctx = p_new(cmd->pool, struct cmd_getscript_context, 1);
ctx->cmd = cmd;
ctx->client = client;
ctx->storage = client->storage;
ctx->failed = FALSE;
ctx->script = sieve_storage_script_init(client->storage, scriptname);
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);
}
ctx->script_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);
}
|