1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2  */
3 
4 #include "lib.h"
5 #include "str.h"
6 
7 #include "sieve.h"
8 #include "sieve-script.h"
9 #include "sieve-storage.h"
10 
11 #include "managesieve-common.h"
12 #include "managesieve-commands.h"
13 
14 static void
cmd_setactive_activate(struct client_command_context * cmd,const char * scriptname)15 cmd_setactive_activate(struct client_command_context *cmd,
16 		       const char *scriptname)
17 {
18 	struct client *client = cmd->client;
19 	struct sieve_storage *storage = client->storage;
20 	struct sieve_script *script;
21 	string_t *errors = NULL;
22 	const char *errormsg = NULL;
23 	unsigned int warning_count = 0, error_count = 0;
24 	bool success = TRUE;
25 	int ret;
26 
27 	event_add_str(cmd->event, "script_name", scriptname);
28 
29 	script = sieve_storage_open_script(storage, scriptname, NULL);
30 	if (script == NULL) {
31 		client_command_storage_error(
32 			cmd, "Failed to open script `%s' for activation",
33 			scriptname);
34 		return;
35 	}
36 
37 	if (sieve_script_is_active(script) <= 0) T_BEGIN {
38 		/* Script is first being activated; compile it again without the
39 		   UPLOAD flag. */
40 		struct sieve_error_handler *ehandler;
41 		enum sieve_compile_flags cpflags =
42 			SIEVE_COMPILE_FLAG_NOGLOBAL |
43 			SIEVE_COMPILE_FLAG_ACTIVATED;
44 		struct sieve_binary *sbin;
45 		enum sieve_error error;
46 
47 		/* Prepare error handler */
48 		errors = str_new(default_pool, 1024);
49 		ehandler = sieve_strbuf_ehandler_create(
50 			client->svinst, errors, TRUE,
51 			client->set->managesieve_max_compile_errors);
52 
53 		/* Compile */
54 		sbin = sieve_compile_script(script, ehandler, cpflags, &error);
55 		if (sbin == NULL) {
56 			if (error != SIEVE_ERROR_NOT_VALID) {
57 				errormsg = sieve_script_get_last_error(
58 					script, &error);
59 				if (error == SIEVE_ERROR_NONE)
60 					errormsg = NULL;
61 			}
62 			success = FALSE;
63 		} else {
64 			sieve_close(&sbin);
65 		}
66 
67 		warning_count = sieve_get_warnings(ehandler);
68 		error_count = sieve_get_errors(ehandler);
69 		sieve_error_handler_unref(&ehandler);
70 	} T_END;
71 
72 	/* Activate only when script is valid (or already active) */
73 	if (success) {
74 		/* Refresh activation no matter what; this can also
75 		   resolve some erroneous situations. */
76 		ret = sieve_script_activate(script, (time_t)-1);
77 		if (ret < 0) {
78 			client_command_storage_error(
79 				cmd, "Failed to activate script `%s'",
80 				scriptname);
81 		} else {
82 			struct event_passthrough *e =
83 				client_command_create_finish_event(cmd)->
84 				add_int("compile_warnings", warning_count);
85 			e_debug(e->event(), "Activated script `%s' "
86 				" (%u warnings%s)",
87 				scriptname, warning_count,
88 				(ret == 0 ? ", redundant" : ""));
89 
90 			if (warning_count > 0) {
91 				client_send_okresp(
92 					client, "WARNINGS",
93 					str_c(errors));
94 			} else {
95 				client_send_ok(client,
96 					(ret > 0 ?
97 					 "Setactive completed." :
98 					 "Script is already active."));
99 			}
100 		}
101 	} else if (errormsg == NULL) {
102 		struct event_passthrough *e =
103 			client_command_create_finish_event(cmd)->
104 			add_str("error", "Compilation failed")->
105 			add_int("compile_errors", error_count)->
106 			add_int("compile_warnings", warning_count);
107 		e_debug(e->event(), "Failed to activate script `%s': "
108 			"Compilation failed (%u errors, %u warnings)",
109 			scriptname, error_count, warning_count);
110 
111 		client_send_no(client, str_c(errors));
112 	} else {
113 		struct event_passthrough *e =
114 			client_command_create_finish_event(cmd)->
115 			add_str("error", errormsg);
116 		e_debug(e->event(), "Failed to activate script `%s': %s",
117 			scriptname, errormsg);
118 
119 		client_send_no(client, errormsg);
120 	}
121 
122 	if (errors != NULL)
123 		str_free(&errors);
124 	sieve_script_unref(&script);
125 }
126 
127 static void
cmd_setactive_deactivate(struct client_command_context * cmd)128 cmd_setactive_deactivate(struct client_command_context *cmd)
129 {
130 	struct client *client = cmd->client;
131 	struct sieve_storage *storage = client->storage;
132 	int ret;
133 
134 	ret = sieve_storage_deactivate(storage, (time_t)-1);
135 	if (ret < 0) {
136 		client_command_storage_error(
137 			cmd, "Failed to deactivate script");
138 		return;
139 	}
140 
141 	struct event_passthrough *e =
142 		client_command_create_finish_event(cmd);
143 	e_debug(e->event(), "Deactivated script");
144 
145 	client_send_ok(client, (ret > 0 ?
146 				"Active script is now deactivated." :
147 				"No scripts currently active."));
148 }
149 
cmd_setactive(struct client_command_context * cmd)150 bool cmd_setactive(struct client_command_context *cmd)
151 {
152 	const char *scriptname;
153 
154 	/* <scriptname> */
155 	if (!client_read_string_args(cmd, TRUE, 1, &scriptname))
156 		return FALSE;
157 
158 	/* Activate, or deactivate */
159 	if (*scriptname != '\0')
160 		cmd_setactive_activate(cmd, scriptname);
161 	else
162 		cmd_setactive_deactivate(cmd);
163 
164 	return TRUE;
165 }
166