summaryrefslogtreecommitdiffstats
path: root/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.c
blob: eb9318ccd7e3834fabb167fb1566e4230e44d6a7 (plain)
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
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
 */

#include "lib.h"
#include "unichar.h"
#include "mail-storage.h"
#include "doveadm-mail.h"

#include "sieve.h"
#include "sieve-script.h"
#include "sieve-storage.h"

#include "doveadm-sieve-cmd.h"

void doveadm_sieve_cmd_failed_error
(struct doveadm_sieve_cmd_context *ctx, enum sieve_error error)
{
	struct doveadm_mail_cmd_context *mctx = &ctx->ctx;
	int exit_code = 0;

	switch ( error ) {
	case SIEVE_ERROR_NONE:
		i_unreached();
		return;
	case SIEVE_ERROR_TEMP_FAILURE:
		exit_code = EX_TEMPFAIL;
		break;
	case SIEVE_ERROR_NOT_POSSIBLE:
	case SIEVE_ERROR_EXISTS:
	case SIEVE_ERROR_NOT_VALID:
	case SIEVE_ERROR_ACTIVE:
		exit_code = DOVEADM_EX_NOTPOSSIBLE;
		break;
	case SIEVE_ERROR_BAD_PARAMS:
		exit_code = EX_USAGE;
		break;
	case SIEVE_ERROR_NO_PERMISSION:
		exit_code = EX_NOPERM;
		break;
	case SIEVE_ERROR_NO_QUOTA:
		exit_code = EX_CANTCREAT;
		break;
	case SIEVE_ERROR_NOT_FOUND:
		exit_code = DOVEADM_EX_NOTFOUND;
		break;
	default:
		i_unreached();
	}
	/* tempfail overrides all other exit codes, otherwise use whatever
	   error happened first */
	if ( mctx->exit_code == 0 || exit_code == EX_TEMPFAIL )
		mctx->exit_code = exit_code;
}

void doveadm_sieve_cmd_failed_storage
(struct doveadm_sieve_cmd_context *ctx,	 struct sieve_storage *storage)
{
	enum sieve_error error;

	(void)sieve_storage_get_last_error(storage, &error);
	doveadm_sieve_cmd_failed_error(ctx, error);
}

static const char *doveadm_sieve_cmd_get_setting
(void *context, const char *identifier)
{
	struct doveadm_sieve_cmd_context *ctx =
		(struct doveadm_sieve_cmd_context *) context;

	return mail_user_plugin_getenv(ctx->ctx.cur_mail_user, identifier);
}

static const struct sieve_callbacks sieve_callbacks = {
	NULL,
	doveadm_sieve_cmd_get_setting
};

static bool doveadm_sieve_cmd_parse_arg
(struct doveadm_mail_cmd_context *_ctx ATTR_UNUSED,
	int c ATTR_UNUSED)
{
	return FALSE;
}

void doveadm_sieve_cmd_scriptnames_check(const char *const args[])
{
	unsigned int i;

	for (i = 0; args[i] != NULL; i++) {
		if (!uni_utf8_str_is_valid(args[i])) {
			i_fatal_status(EX_DATAERR,
				"Sieve script name not valid UTF-8: %s", args[i]);
		}
		if ( !sieve_script_name_is_valid(args[i]) ) {
			i_fatal_status(EX_DATAERR,
				"Sieve script name not valid: %s", args[i]);
		}
	}
}

static int
doveadm_sieve_cmd_run
(struct doveadm_mail_cmd_context *_ctx,
	struct mail_user *user)
{
	struct doveadm_sieve_cmd_context *ctx =
		(struct doveadm_sieve_cmd_context *)_ctx;
	struct sieve_environment svenv;
	enum sieve_error error;
	int ret;

	memset((void*)&svenv, 0, sizeof(svenv));
	svenv.username = user->username;
	(void)mail_user_get_home(user, &svenv.home_dir);
	svenv.base_dir = user->set->base_dir;
	svenv.flags = SIEVE_FLAG_HOME_RELATIVE;

	ctx->svinst = sieve_init
		(&svenv, &sieve_callbacks, (void *)ctx, user->mail_debug);

	ctx->storage = sieve_storage_create_main
		(ctx->svinst, user, SIEVE_STORAGE_FLAG_READWRITE, &error);
	if ( ctx->storage == NULL ) {
		switch ( error ) {
		case SIEVE_ERROR_NOT_POSSIBLE:
			error = SIEVE_ERROR_NOT_FOUND;
			i_error("Failed to open Sieve storage: "
				"Sieve is disabled for this user");
			break;
		case SIEVE_ERROR_NOT_FOUND:
			i_error("Failed to open Sieve storage: "
				"User cannot manage personal Sieve scripts.");
			break;
		default:
			i_error("Failed to open Sieve storage.");
		}
		doveadm_sieve_cmd_failed_error(ctx, error);
		ret =  -1;

	} else {
		i_assert( ctx->v.run != NULL );
		ret = ctx->v.run(ctx);
		sieve_storage_unref(&ctx->storage);
	}

	sieve_deinit(&ctx->svinst);
	return ret;
}

struct doveadm_sieve_cmd_context *
doveadm_sieve_cmd_alloc_size(size_t size)
{
	struct doveadm_sieve_cmd_context *ctx;

	ctx = (struct doveadm_sieve_cmd_context *)
		doveadm_mail_cmd_alloc_size(size);
	ctx->ctx.getopt_args = "s";
	ctx->ctx.v.parse_arg = doveadm_sieve_cmd_parse_arg;
	ctx->ctx.v.run = doveadm_sieve_cmd_run;
	return ctx;
}

static struct doveadm_cmd_ver2 *doveadm_sieve_commands[] = {
	&doveadm_sieve_cmd_list,
	&doveadm_sieve_cmd_get,
	&doveadm_sieve_cmd_put,
	&doveadm_sieve_cmd_delete,
	&doveadm_sieve_cmd_activate,
	&doveadm_sieve_cmd_deactivate,
	&doveadm_sieve_cmd_rename
};

void doveadm_sieve_cmds_init(void)
{
	unsigned int i;

	for (i = 0; i < N_ELEMENTS(doveadm_sieve_commands); i++)
		doveadm_cmd_register_ver2(doveadm_sieve_commands[i]);
}