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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
*/
#include "lib.h"
#include "istream.h"
#include "doveadm-mail.h"
#include "sieve.h"
#include "sieve-script.h"
#include "sieve-storage.h"
#include "doveadm-sieve-cmd.h"
struct doveadm_sieve_put_cmd_context {
struct doveadm_sieve_cmd_context ctx;
const char *scriptname;
bool activate:1;
};
static int cmd_sieve_put_run
(struct doveadm_sieve_cmd_context *_ctx)
{
struct doveadm_sieve_put_cmd_context *ctx =
(struct doveadm_sieve_put_cmd_context *)_ctx;
struct sieve_storage_save_context *save_ctx;
struct sieve_storage *storage = _ctx->storage;
struct istream *input = _ctx->ctx.cmd_input;
enum sieve_error error;
ssize_t ret;
bool save_failed = FALSE;
save_ctx = sieve_storage_save_init
(storage, ctx->scriptname, input);
if ( save_ctx == NULL ) {
i_error("Saving failed: %s",
sieve_storage_get_last_error(storage, &error));
doveadm_sieve_cmd_failed_error(_ctx, error);
return -1;
}
while ( (ret = i_stream_read(input)) > 0 || ret == -2 ) {
if ( sieve_storage_save_continue(save_ctx) < 0 ) {
save_failed = TRUE;
ret = -1;
break;
}
}
i_assert(ret == -1);
if ( input->stream_errno != 0 ) {
i_error("read(script input) failed: %s", i_stream_get_error(input));
doveadm_sieve_cmd_failed_error
(&ctx->ctx, SIEVE_ERROR_TEMP_FAILURE);
} else if ( save_failed ) {
i_error("Saving failed: %s",
sieve_storage_get_last_error(storage, NULL));
doveadm_sieve_cmd_failed_storage(&ctx->ctx, storage);
} else if ( sieve_storage_save_finish(save_ctx) < 0 ) {
i_error("Saving failed: %s",
sieve_storage_get_last_error(storage, NULL));
doveadm_sieve_cmd_failed_storage(&ctx->ctx, storage);
} else {
ret = 0;
}
/* Verify that script compiles */
if ( ret == 0 ) {
struct sieve_error_handler *ehandler;
enum sieve_compile_flags cpflags =
SIEVE_COMPILE_FLAG_NOGLOBAL | SIEVE_COMPILE_FLAG_UPLOADED;
struct sieve_script *script;
struct sieve_binary *sbin;
/* Obtain script object for uploaded script */
script = sieve_storage_save_get_tempscript(save_ctx);
/* Check result */
if ( script == NULL ) {
i_error("Saving failed: %s",
sieve_storage_get_last_error(storage, &error));
doveadm_sieve_cmd_failed_error(_ctx, error);
ret = -1;
} else {
/* Mark this as an activation when we are replacing the active script */
if ( ctx->activate || sieve_storage_save_will_activate(save_ctx) )
cpflags |= SIEVE_COMPILE_FLAG_ACTIVATED;
/* Compile */
ehandler = sieve_master_ehandler_create(ctx->ctx.svinst, 0);
if ( (sbin=sieve_compile_script
(script, ehandler, cpflags, &error)) == NULL ) {
doveadm_sieve_cmd_failed_error(_ctx, error);
ret = -1;
} else {
sieve_close(&sbin);
/* Script is valid; commit it to storage */
ret = sieve_storage_save_commit(&save_ctx);
if (ret < 0) {
i_error("Saving failed: %s",
sieve_storage_get_last_error(storage, &error));
doveadm_sieve_cmd_failed_error(_ctx, error);
ret = -1;
}
}
sieve_error_handler_unref(&ehandler);
}
}
if ( save_ctx != NULL )
sieve_storage_save_cancel(&save_ctx);
if ( ctx->activate && ret == 0 ) {
struct sieve_script *script = sieve_storage_open_script
(storage, ctx->scriptname, NULL);
if ( script == NULL ||
sieve_script_activate(script, (time_t)-1) < 0) {
i_error("Failed to activate Sieve script: %s",
sieve_storage_get_last_error(storage, &error));
doveadm_sieve_cmd_failed_error(_ctx, error);
ret = -1;
}
if (script != NULL)
sieve_script_unref(&script);
}
i_assert(input->eof);
return ret < 0 ? -1 : 0;
}
static void cmd_sieve_put_init
(struct doveadm_mail_cmd_context *_ctx,
const char *const args[])
{
struct doveadm_sieve_put_cmd_context *ctx =
(struct doveadm_sieve_put_cmd_context *)_ctx;
if ( str_array_length(args) != 1 )
doveadm_mail_help_name("sieve put");
doveadm_sieve_cmd_scriptnames_check(args);
ctx->scriptname = p_strdup(ctx->ctx.ctx.pool, args[0]);
doveadm_mail_get_input(_ctx);
}
static bool
cmd_sieve_put_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c)
{
struct doveadm_sieve_put_cmd_context *ctx =
(struct doveadm_sieve_put_cmd_context *)_ctx;
switch ( c ) {
case 'a':
ctx->activate = TRUE;
break;
default:
return FALSE;
}
return TRUE;
}
static struct doveadm_mail_cmd_context *
cmd_sieve_put_alloc(void)
{
struct doveadm_sieve_put_cmd_context *ctx;
ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_put_cmd_context);
ctx->ctx.ctx.getopt_args = "a";
ctx->ctx.ctx.v.parse_arg = cmd_sieve_put_parse_arg;
ctx->ctx.ctx.v.init = cmd_sieve_put_init;
ctx->ctx.v.run = cmd_sieve_put_run;
return &ctx->ctx.ctx;
}
struct doveadm_cmd_ver2 doveadm_sieve_cmd_put = {
.name = "sieve put",
.mail_cmd = cmd_sieve_put_alloc,
.usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-a] <scriptname>",
DOVEADM_CMD_PARAMS_START
DOVEADM_CMD_MAIL_COMMON
DOVEADM_CMD_PARAM('a',"activate",CMD_PARAM_BOOL,0)
DOVEADM_CMD_PARAM('\0',"scriptname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL)
DOVEADM_CMD_PARAM('\0',"file",CMD_PARAM_ISTREAM,CMD_PARAM_FLAG_POSITIONAL)
DOVEADM_CMD_PARAMS_END
};
|