diff options
Diffstat (limited to 'sway/commands.c')
-rw-r--r-- | sway/commands.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/sway/commands.c b/sway/commands.c index 5fdcdbb6..17638129 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -7,6 +7,8 @@ | |||
7 | #include <stdio.h> | 7 | #include <stdio.h> |
8 | #include <json-c/json.h> | 8 | #include <json-c/json.h> |
9 | #include "sway/commands.h" | 9 | #include "sway/commands.h" |
10 | #include "sway/config.h" | ||
11 | #include "sway/security.h" | ||
10 | #include "stringop.h" | 12 | #include "stringop.h" |
11 | #include "log.h" | 13 | #include "log.h" |
12 | 14 | ||
@@ -200,6 +202,136 @@ cleanup: | |||
200 | return results; | 202 | return results; |
201 | } | 203 | } |
202 | 204 | ||
205 | // this is like handle_command above, except: | ||
206 | // 1) it ignores empty commands (empty lines) | ||
207 | // 2) it does variable substitution | ||
208 | // 3) it doesn't split commands (because the multiple commands are supposed to | ||
209 | // be chained together) | ||
210 | // 4) handle_command handles all state internally while config_command has some | ||
211 | // state handled outside (notably the block mode, in read_config) | ||
212 | struct cmd_results *config_command(char *exec, enum cmd_status block) { | ||
213 | struct cmd_results *results = NULL; | ||
214 | int argc; | ||
215 | char **argv = split_args(exec, &argc); | ||
216 | if (!argc) { | ||
217 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
218 | goto cleanup; | ||
219 | } | ||
220 | |||
221 | sway_log(L_INFO, "handling config command '%s'", exec); | ||
222 | // Endblock | ||
223 | if (**argv == '}') { | ||
224 | results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); | ||
225 | goto cleanup; | ||
226 | } | ||
227 | struct cmd_handler *handler = find_handler(argv[0], block); | ||
228 | if (!handler) { | ||
229 | char *input = argv[0] ? argv[0] : "(empty)"; | ||
230 | results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); | ||
231 | goto cleanup; | ||
232 | } | ||
233 | int i; | ||
234 | // Var replacement, for all but first argument of set | ||
235 | // TODO commands | ||
236 | for (i = /*handler->handle == cmd_set ? 2 :*/ 1; i < argc; ++i) { | ||
237 | argv[i] = do_var_replacement(argv[i]); | ||
238 | unescape_string(argv[i]); | ||
239 | } | ||
240 | /* Strip quotes for first argument. | ||
241 | * TODO This part needs to be handled much better */ | ||
242 | if (argc>1 && (*argv[1] == '\"' || *argv[1] == '\'')) { | ||
243 | strip_quotes(argv[1]); | ||
244 | } | ||
245 | if (handler->handle) { | ||
246 | results = handler->handle(argc-1, argv+1); | ||
247 | } else { | ||
248 | results = cmd_results_new(CMD_INVALID, argv[0], "This command is shimmed, but unimplemented"); | ||
249 | } | ||
250 | |||
251 | cleanup: | ||
252 | free_argv(argc, argv); | ||
253 | return results; | ||
254 | } | ||
255 | |||
256 | struct cmd_results *config_commands_command(char *exec) { | ||
257 | struct cmd_results *results = NULL; | ||
258 | int argc; | ||
259 | char **argv = split_args(exec, &argc); | ||
260 | if (!argc) { | ||
261 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
262 | goto cleanup; | ||
263 | } | ||
264 | |||
265 | // Find handler for the command this is setting a policy for | ||
266 | char *cmd = argv[0]; | ||
267 | |||
268 | if (strcmp(cmd, "}") == 0) { | ||
269 | results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); | ||
270 | goto cleanup; | ||
271 | } | ||
272 | |||
273 | struct cmd_handler *handler = find_handler(cmd, CMD_BLOCK_END); | ||
274 | if (!handler && strcmp(cmd, "*") != 0) { | ||
275 | char *input = cmd ? cmd : "(empty)"; | ||
276 | results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command"); | ||
277 | goto cleanup; | ||
278 | } | ||
279 | |||
280 | enum command_context context = 0; | ||
281 | |||
282 | struct { | ||
283 | char *name; | ||
284 | enum command_context context; | ||
285 | } context_names[] = { | ||
286 | { "config", CONTEXT_CONFIG }, | ||
287 | { "binding", CONTEXT_BINDING }, | ||
288 | { "ipc", CONTEXT_IPC }, | ||
289 | { "criteria", CONTEXT_CRITERIA }, | ||
290 | { "all", CONTEXT_ALL }, | ||
291 | }; | ||
292 | |||
293 | for (int i = 1; i < argc; ++i) { | ||
294 | size_t j; | ||
295 | for (j = 0; j < sizeof(context_names) / sizeof(context_names[0]); ++j) { | ||
296 | if (strcmp(context_names[j].name, argv[i]) == 0) { | ||
297 | break; | ||
298 | } | ||
299 | } | ||
300 | if (j == sizeof(context_names) / sizeof(context_names[0])) { | ||
301 | results = cmd_results_new(CMD_INVALID, cmd, | ||
302 | "Invalid command context %s", argv[i]); | ||
303 | goto cleanup; | ||
304 | } | ||
305 | context |= context_names[j].context; | ||
306 | } | ||
307 | |||
308 | struct command_policy *policy = NULL; | ||
309 | for (int i = 0; i < config->command_policies->length; ++i) { | ||
310 | struct command_policy *p = config->command_policies->items[i]; | ||
311 | if (strcmp(p->command, cmd) == 0) { | ||
312 | policy = p; | ||
313 | break; | ||
314 | } | ||
315 | } | ||
316 | if (!policy) { | ||
317 | policy = alloc_command_policy(cmd); | ||
318 | sway_assert(policy, "Unable to allocate security policy"); | ||
319 | if (policy) { | ||
320 | list_add(config->command_policies, policy); | ||
321 | } | ||
322 | } | ||
323 | policy->context = context; | ||
324 | |||
325 | sway_log(L_INFO, "Set command policy for %s to %d", | ||
326 | policy->command, policy->context); | ||
327 | |||
328 | results = cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
329 | |||
330 | cleanup: | ||
331 | free_argv(argc, argv); | ||
332 | return results; | ||
333 | } | ||
334 | |||
203 | struct cmd_results *cmd_results_new(enum cmd_status status, | 335 | struct cmd_results *cmd_results_new(enum cmd_status status, |
204 | const char *input, const char *format, ...) { | 336 | const char *input, const char *format, ...) { |
205 | struct cmd_results *results = malloc(sizeof(struct cmd_results)); | 337 | struct cmd_results *results = malloc(sizeof(struct cmd_results)); |