1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "lib.h"
5 #include "ostream.h"
6 #include "istream.h"
7 #include "iostream.h"
8
9 #include "sieve-script.h"
10 #include "sieve-storage.h"
11
12 #include "managesieve-common.h"
13 #include "managesieve-commands.h"
14
15 struct cmd_getscript_context {
16 struct client *client;
17 struct client_command_context *cmd;
18 struct sieve_storage *storage;
19 uoff_t script_size;
20
21 const char *scriptname;
22 struct sieve_script *script;
23 struct istream *script_stream;
24
25 bool failed:1;
26 };
27
cmd_getscript_finish(struct cmd_getscript_context * ctx)28 static bool cmd_getscript_finish(struct cmd_getscript_context *ctx)
29 {
30 struct client_command_context *cmd = ctx->cmd;
31 struct client *client = ctx->client;
32
33 if (ctx->script != NULL)
34 sieve_script_unref(&ctx->script);
35
36 if (ctx->failed) {
37 if (client->output->closed) {
38 client_disconnect(client, NULL);
39 return TRUE;
40 }
41
42 client_command_storage_error(
43 cmd, "Failed to retrieve script `%s'", ctx->scriptname);
44 return TRUE;
45 }
46
47 client->get_count++;
48 client->get_bytes += ctx->script_size;
49
50 struct event_passthrough *e =
51 client_command_create_finish_event(cmd);
52 e_debug(e->event(), "Retrieved script `%s'", ctx->scriptname);
53
54 client_send_line(client, "");
55 client_send_ok(client, "Getscript completed.");
56 return TRUE;
57 }
58
cmd_getscript_continue(struct client_command_context * cmd)59 static bool cmd_getscript_continue(struct client_command_context *cmd)
60 {
61 struct client *client = cmd->client;
62 struct cmd_getscript_context *ctx = cmd->context;
63
64 switch (o_stream_send_istream(client->output, ctx->script_stream)) {
65 case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
66 if (ctx->script_stream->v_offset != ctx->script_size &&
67 !ctx->failed) {
68 /* Input stream gave less data than expected */
69 sieve_storage_set_critical(
70 ctx->storage, "GETSCRIPT for script `%s' "
71 "from %s got too little data: "
72 "%"PRIuUOFF_T" vs %"PRIuUOFF_T,
73 sieve_script_name(ctx->script),
74 sieve_script_location(ctx->script),
75 ctx->script_stream->v_offset, ctx->script_size);
76 client_disconnect(ctx->client, "GETSCRIPT failed");
77 ctx->failed = TRUE;
78 }
79 break;
80 case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
81 i_unreached();
82 case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
83 return FALSE;
84 case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
85 sieve_storage_set_critical(ctx->storage,
86 "o_stream_send_istream() failed for script `%s' "
87 "from %s: %s",
88 sieve_script_name(ctx->script),
89 sieve_script_location(ctx->script),
90 i_stream_get_error(ctx->script_stream));
91 ctx->failed = TRUE;
92 break;
93 case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
94 client_disconnect(ctx->client, NULL);
95 ctx->failed = TRUE;
96 break;
97 }
98 return cmd_getscript_finish(ctx);
99 }
100
cmd_getscript(struct client_command_context * cmd)101 bool cmd_getscript(struct client_command_context *cmd)
102 {
103 struct client *client = cmd->client;
104 struct cmd_getscript_context *ctx;
105 const char *scriptname;
106 enum sieve_error error;
107
108 /* <scriptname> */
109 if (!client_read_string_args(cmd, TRUE, 1, &scriptname))
110 return FALSE;
111
112 event_add_str(cmd->event, "script_name", scriptname);
113
114 ctx = p_new(cmd->pool, struct cmd_getscript_context, 1);
115 ctx->cmd = cmd;
116 ctx->client = client;
117 ctx->scriptname = p_strdup(cmd->pool, scriptname);
118 ctx->storage = client->storage;
119 ctx->failed = FALSE;
120
121 ctx->script = sieve_storage_open_script(client->storage, scriptname,
122 NULL);
123 if (ctx->script == NULL) {
124 ctx->failed = TRUE;
125 return cmd_getscript_finish(ctx);
126 }
127
128 if (sieve_script_get_stream(ctx->script, &ctx->script_stream,
129 &error) < 0 ) {
130 if (error == SIEVE_ERROR_NOT_FOUND) {
131 sieve_storage_set_error(client->storage, error,
132 "Script does not exist.");
133 }
134 ctx->failed = TRUE;
135 return cmd_getscript_finish(ctx);
136 }
137
138 if (sieve_script_get_size(ctx->script, &ctx->script_size) <= 0) {
139 sieve_storage_set_critical(ctx->storage,
140 "failed to obtain script size for script `%s' from %s",
141 sieve_script_name(ctx->script),
142 sieve_script_location(ctx->script));
143 ctx->failed = TRUE;
144 return cmd_getscript_finish(ctx);
145 }
146
147 i_assert(ctx->script_stream->v_offset == 0);
148
149 client_send_line(client, t_strdup_printf("{%"PRIuUOFF_T"}",
150 ctx->script_size));
151
152 client->command_pending = TRUE;
153 cmd->func = cmd_getscript_continue;
154 cmd->context = ctx;
155
156 return cmd_getscript_continue(cmd);
157 }
158