/* * trigger-command.c - trigger command * * Copyright (C) 2014 Sébastien Helleu * * This file is part of WeeChat, the extensible chat client. * * WeeChat is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * WeeChat is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with WeeChat. If not, see . */ #include #include #include #include "../weechat-plugin.h" #include "trigger.h" #include "trigger-buffer.h" #include "trigger-config.h" /* * Displays the status of triggers (global status). */ void trigger_command_display_status () { weechat_printf_tags (NULL, "no_trigger", (trigger_enabled) ? _("Triggers enabled") : _("Triggers disabled")); } /* * Displays one trigger (internal function, must not be called directly). */ void trigger_command_display_trigger_internal (const char *name, int enabled, const char *hook, const char *arguments, const char *conditions, int hooks_count, int hook_count_cb, int hook_count_cmd, int regex_count, struct t_trigger_regex *regex, int commands_count, char **commands, int return_code, int verbose) { char str_conditions[64], str_regex[64], str_command[64], str_rc[64]; char spaces[256]; int i, length; if (verbose >= 1) { weechat_printf_tags ( NULL, "no_trigger", " %s%s%s: %s%s%s%s%s%s%s", (enabled) ? weechat_color (weechat_config_string (trigger_config_color_trigger)) : weechat_color (weechat_config_string (trigger_config_color_trigger_disabled)), name, weechat_color ("reset"), hook, weechat_color ("chat_delimiters"), (arguments && arguments[0]) ? "(" : "", weechat_color ("reset"), arguments, weechat_color ("chat_delimiters"), (arguments && arguments[0]) ? ")" : ""); length = weechat_strlen_screen (name) + 3; if (length >= (int)sizeof (spaces)) length = sizeof (spaces) - 1; memset (spaces, ' ', length); spaces[length] = '\0'; if (verbose >= 2) { weechat_printf_tags (NULL, "no_trigger", "%s hooks: %d", spaces, hooks_count); weechat_printf_tags (NULL, "no_trigger", "%s callback: %d", spaces, hook_count_cb); weechat_printf_tags (NULL, "no_trigger", "%s commands: %d", spaces, hook_count_cmd); } if (conditions && conditions[0]) { weechat_printf_tags (NULL, "no_trigger", "%s %s=? %s\"%s%s%s\"", spaces, weechat_color (weechat_config_string (trigger_config_color_flag_conditions)), weechat_color ("chat_delimiters"), weechat_color ("reset"), conditions, weechat_color ("chat_delimiters")); } for (i = 0; i < regex_count; i++) { weechat_printf_tags (NULL, "no_trigger", "%s %s~%d %s\"%s%s%s\" --> " "\"%s%s%s\"%s%s%s%s", spaces, weechat_color (weechat_config_string (trigger_config_color_flag_regex)), i + 1, weechat_color ("chat_delimiters"), weechat_color (weechat_config_string (trigger_config_color_regex)), regex[i].str_regex, weechat_color ("chat_delimiters"), weechat_color (weechat_config_string (trigger_config_color_replace)), regex[i].replace, weechat_color ("chat_delimiters"), weechat_color ("reset"), (regex[i].variable) ? " (" : "", (regex[i].variable) ? regex[i].variable : "", (regex[i].variable) ? ")" : ""); } if (commands) { for (i = 0; commands[i]; i++) { weechat_printf_tags (NULL, "no_trigger", "%s %s/%d %s\"%s%s%s\"", spaces, weechat_color (weechat_config_string (trigger_config_color_flag_command)), i + 1, weechat_color ("chat_delimiters"), weechat_color ("reset"), commands[i], weechat_color ("chat_delimiters")); } } if ((return_code >= 0) && (return_code != TRIGGER_RC_OK)) { weechat_printf_tags (NULL, "no_trigger", "%s %s=> %s%s", spaces, weechat_color (weechat_config_string (trigger_config_color_flag_return_code)), weechat_color ("reset"), trigger_return_code_string[return_code]); } } else { str_conditions[0] ='\0'; str_regex[0] = '\0'; str_command[0] = '\0'; str_rc[0] = '\0'; if (conditions && conditions[0]) { snprintf (str_conditions, sizeof (str_conditions), " %s=?%s", weechat_color (weechat_config_string (trigger_config_color_flag_conditions)), weechat_color ("reset")); } if (regex_count > 0) { snprintf (str_regex, sizeof (str_regex), " %s~%d%s", weechat_color (weechat_config_string (trigger_config_color_flag_regex)), regex_count, weechat_color ("reset")); } if (commands_count > 0) { snprintf (str_command, sizeof (str_command), " %s/%d%s", weechat_color (weechat_config_string (trigger_config_color_flag_command)), commands_count, weechat_color ("reset")); } if ((return_code >= 0) && (return_code != TRIGGER_RC_OK)) { snprintf (str_rc, sizeof (str_rc), " %s=>%s", weechat_color (weechat_config_string (trigger_config_color_flag_return_code)), weechat_color ("reset")); } weechat_printf_tags ( NULL, "no_trigger", " %s%s%s: %s%s%s%s%s%s%s%s%s%s%s%s", (enabled) ? weechat_color (weechat_config_string (trigger_config_color_trigger)) : weechat_color (weechat_config_string (trigger_config_color_trigger_disabled)), name, weechat_color ("reset"), hook, weechat_color ("chat_delimiters"), (arguments && arguments[0]) ? "(" : "", weechat_color ("reset"), arguments, weechat_color ("chat_delimiters"), (arguments && arguments[0]) ? ")" : "", weechat_color ("reset"), str_conditions, str_regex, str_command, str_rc); } } /* * Displays one trigger. */ void trigger_command_display_trigger (struct t_trigger *trigger, int verbose) { trigger_command_display_trigger_internal ( trigger->name, weechat_config_boolean (trigger->options[TRIGGER_OPTION_ENABLED]), weechat_config_string (trigger->options[TRIGGER_OPTION_HOOK]), weechat_config_string (trigger->options[TRIGGER_OPTION_ARGUMENTS]), weechat_config_string (trigger->options[TRIGGER_OPTION_CONDITIONS]), trigger->hooks_count, trigger->hook_count_cb, trigger->hook_count_cmd, trigger->regex_count, trigger->regex, trigger->commands_count, trigger->commands, weechat_config_integer (trigger->options[TRIGGER_OPTION_RETURN_CODE]), verbose); } /* * Displays a list of triggers. */ void trigger_command_list (const char *message, int verbose) { struct t_trigger *ptr_trigger; weechat_printf_tags (NULL, "no_trigger", ""); trigger_command_display_status (); if (!triggers) { weechat_printf_tags (NULL, "no_trigger", _("No trigger defined")); return; } weechat_printf_tags (NULL, "no_trigger", message); for (ptr_trigger = triggers; ptr_trigger; ptr_trigger = ptr_trigger->next_trigger) { trigger_command_display_trigger (ptr_trigger, verbose); } } /* * Displays a list of default triggers. */ void trigger_command_list_default (int verbose) { int i, regex_count, commands_count; struct t_trigger_regex *regex; char **commands; regex_count = 0; regex = NULL; commands_count = 0; commands = NULL; weechat_printf_tags (NULL, "no_trigger", ""); weechat_printf_tags (NULL, "no_trigger", _("List of default triggers:")); for (i = 0; trigger_config_default_list[i][0]; i++) { if (trigger_regex_split (trigger_config_default_list[i][5], ®ex_count, ®ex) < 0) continue; trigger_split_command (trigger_config_default_list[i][6], &commands_count, &commands); trigger_command_display_trigger_internal ( trigger_config_default_list[i][0], weechat_config_string_to_boolean (trigger_config_default_list[i][1]), trigger_config_default_list[i][2], trigger_config_default_list[i][3], trigger_config_default_list[i][4], 0, 0, 0, regex_count, regex, commands_count, commands, trigger_search_return_code (trigger_config_default_list[i][7]), verbose); } trigger_regex_free (®ex_count, ®ex); if (commands) weechat_string_free_split (commands); } /* * Set "enabled" value in a trigger. * * Argument "enable" can be: * -1: toggle trigger * 0: disable trigger * 1: enable trigger * 2: restart trigger (recreate hook(s)) */ void trigger_command_set_enabled (struct t_trigger *trigger, int enable, int display_error) { if (enable == 2) { if (weechat_config_boolean (trigger->options[TRIGGER_OPTION_ENABLED])) { trigger_unhook (trigger); trigger_hook (trigger); weechat_printf_tags (NULL, "no_trigger", _("Trigger \"%s\" restarted"), trigger->name); } else if (display_error) { weechat_printf_tags (NULL, "no_trigger", _("%sError: a disabled trigger can not be " "restarted"), weechat_prefix ("error")); } } else { if (enable < 0) { enable = weechat_config_boolean (trigger->options[TRIGGER_OPTION_ENABLED]) ? 0 : 1; } weechat_config_option_set (trigger->options[TRIGGER_OPTION_ENABLED], (enable) ? "on" : "off", 1); weechat_printf_tags (NULL, "no_trigger", (enable) ? _("Trigger \"%s\" enabled") : _("Trigger \"%s\" disabled"), trigger->name); } } /* * Renames a trigger and displays error if the rename is not possible. * * This function is called by commands: * /trigger set OLD name NEW * /trigger rename OLD NEW */ void trigger_command_rename (struct t_trigger *trigger, const char *new_name) { char *name, *name2; name = strdup (trigger->name); name2 = weechat_string_remove_quotes (new_name, "'\""); if (name && name2) { /* check that new name is valid */ if (!trigger_name_valid (name2)) { weechat_printf_tags (NULL, "no_trigger", _("%sError: invalid name for trigger"), weechat_prefix ("error")); goto end; } /* check that no trigger already exists with the new name */ if (trigger_search (name2)) { weechat_printf_tags (NULL, "no_trigger", _("%sError: trigger \"%s\" already " "exists"), weechat_prefix ("error"), name2); goto end; } /* rename the trigger */ if (trigger_rename (trigger, name2)) { weechat_printf_tags (NULL, "no_trigger", _("Trigger \"%s\" renamed to \"%s\""), name, trigger->name); } else { weechat_printf_tags (NULL, "no_trigger", _("%sError: failed to rename trigger " "\"%s\""), weechat_prefix ("error"), name); } } end: if (name) free (name); if (name2) free (name2); } /* * Callback for command "/trigger": manage triggers. */ int trigger_command_trigger (void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { struct t_trigger *ptr_trigger, *ptr_trigger2; struct t_trigger_regex *regex; char *value, **sargv, **items, input[1024], str_pos[16]; int rc, i, type, count, index_option, enable, sargc, num_items, add_rc; int regex_count, regex_rc; /* make C compiler happy */ (void) data; rc = WEECHAT_RC_OK; sargv = NULL; /* list all triggers */ if ((argc == 1) || ((argc == 2) && (weechat_strcasecmp (argv[1], "list") == 0))) { trigger_command_list (_("List of triggers:"), 0); goto end; } /* full list of all triggers */ if ((argc == 2) && (weechat_strcasecmp (argv[1], "listfull") == 0)) { trigger_command_list (_("List of triggers:"), 1); goto end; } /* list of default triggers */ if ((argc == 2) && (weechat_strcasecmp (argv[1], "listdefault") == 0)) { trigger_command_list_default (1); goto end; } /* add a trigger */ if ((weechat_strcasecmp (argv[1], "add") == 0) || (weechat_strcasecmp (argv[1], "addoff") == 0) || (weechat_strcasecmp (argv[1], "addreplace") == 0)) { sargv = weechat_string_split_shell (argv_eol[2], &sargc); if (!sargv || (sargc < 2)) goto error; if (!trigger_name_valid (sargv[0])) { weechat_printf_tags (NULL, "no_trigger", _("%sError: invalid name for trigger"), weechat_prefix ("error")); goto end; } type = trigger_search_hook_type (sargv[1]); if (type < 0) { weechat_printf_tags (NULL, "no_trigger", _("%sError: invalid hook type \"%s\""), weechat_prefix ("error"), sargv[1]); goto end; } if ((sargc > 4) && sargv[4][0]) { regex_count = 0; regex = NULL; regex_rc = trigger_regex_split (sargv[4], ®ex_count, ®ex); trigger_regex_free (®ex_count, ®ex); switch (regex_rc) { case 0: /* OK */ break; case -1: /* format error */ weechat_printf (NULL, _("%sError: invalid format for regular " "expression"), weechat_prefix ("error")); goto end; break; case -2: /* regex compilation error */ weechat_printf (NULL, _("%sError: invalid regular expression " "(compilation failed)"), weechat_prefix ("error")); goto end; break; case -3: /* memory error */ weechat_printf (NULL, _("%s%s: not enough memory"), weechat_prefix ("error"), TRIGGER_PLUGIN_NAME); goto end; break; } } if ((sargc > 6) && sargv[6][0] && (trigger_search_return_code (sargv[6]) < 0)) { weechat_printf_tags (NULL, "no_trigger", _("%sError: invalid return code \"%s\""), weechat_prefix ("error"), sargv[6]); goto end; } ptr_trigger = trigger_search (sargv[0]); if (ptr_trigger) { if (weechat_strcasecmp (argv[1], "addreplace") == 0) { if (ptr_trigger) trigger_free (ptr_trigger); } else { weechat_printf_tags (NULL, "no_trigger", _("%sError: trigger \"%s\" already exists " "(choose another name or use option " "\"addreplace\" to overwrite it)"), weechat_prefix ("error"), sargv[0]); goto end; } } ptr_trigger = trigger_alloc (sargv[0]); if (!ptr_trigger) { weechat_printf_tags (NULL, "no_trigger", _("%sError: failed to create trigger \"%s\""), weechat_prefix ("error"), sargv[0]); goto end; } ptr_trigger = trigger_new ( sargv[0], /* name */ (weechat_strcasecmp (argv[1], "addoff") == 0) ? "off" : "on", sargv[1], /* hook */ (sargc > 2) ? sargv[2] : "", /* arguments */ (sargc > 3) ? sargv[3] : "", /* conditions */ (sargc > 4) ? sargv[4] : "", /* regex */ (sargc > 5) ? sargv[5] : "", /* command */ (sargc > 6) ? sargv[6] : ""); /* return code */ if (ptr_trigger) { weechat_printf_tags (NULL, "no_trigger", _("Trigger \"%s\" created"), sargv[0]); } else { weechat_printf_tags (NULL, "no_trigger", _("%sError: failed to create trigger \"%s\""), weechat_prefix ("error"), sargv[0]); } goto end; } /* add trigger command in input (to help trigger creation) */ if (weechat_strcasecmp (argv[1], "addinput") == 0) { type = TRIGGER_HOOK_SIGNAL; if (argc >= 3) { type = trigger_search_hook_type (argv[2]); if (type < 0) { weechat_printf_tags (NULL, "no_trigger", _("%sError: invalid hook type \"%s\""), weechat_prefix ("error"), argv[2]); goto end; } } items = weechat_string_split (trigger_hook_default_rc[type], ",", 0, 0, &num_items); snprintf (input, sizeof (input), "/trigger add name %s \"%s\" \"%s\" \"%s\" \"%s\"%s%s%s", trigger_hook_type_string[type], trigger_hook_default_arguments[type], TRIGGER_HOOK_DEFAULT_CONDITIONS, TRIGGER_HOOK_DEFAULT_REGEX, TRIGGER_HOOK_DEFAULT_COMMAND, (items && (num_items > 0)) ? " \"" : "", (items && (num_items > 0)) ? items[0] : "", (items && (num_items > 0)) ? "\"" : ""); weechat_buffer_set (buffer, "input", input); weechat_buffer_set (buffer, "input_pos", "13"); goto end; } /* * get command to create a trigger, and according to option: * - input: put the command in input * - output: send the command to the buffer * - recreate: same as input, but the trigger is first deleted */ if ((weechat_strcasecmp (argv[1], "input") == 0) || (weechat_strcasecmp (argv[1], "output") == 0) || (weechat_strcasecmp (argv[1], "recreate") == 0)) { if (argc < 3) goto error; ptr_trigger = trigger_search (argv[2]); if (!ptr_trigger) { weechat_printf_tags (NULL, "no_trigger", _("%sError: trigger \"%s\" not found"), weechat_prefix ("error"), argv[2]); goto end; } add_rc = trigger_hook_default_rc[weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_HOOK])][0]; snprintf (input, sizeof (input), "//trigger %s %s %s \"%s\" \"%s\" \"%s\" \"%s\"%s%s%s", (weechat_strcasecmp (argv[1], "recreate") == 0) ? "addreplace" : "add", ptr_trigger->name, weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_HOOK]), weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_ARGUMENTS]), weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_CONDITIONS]), weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_REGEX]), weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_COMMAND]), (add_rc) ? " \"" : "", (add_rc) ? weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_RETURN_CODE]) : "", (add_rc) ? "\"" : ""); if (weechat_strcasecmp (argv[1], "output") == 0) { weechat_command (buffer, input); } else { weechat_buffer_set (buffer, "input", input + 1); snprintf (str_pos, sizeof (str_pos), "%d", weechat_utf8_strlen (input + 1)); weechat_buffer_set (buffer, "input_pos", str_pos); } goto end; } /* set option in a trigger */ if (weechat_strcasecmp (argv[1], "set") == 0) { if (argc < 5) goto error; ptr_trigger = trigger_search (argv[2]); if (!ptr_trigger) { weechat_printf_tags (NULL, "no_trigger", _("%sError: trigger \"%s\" not found"), weechat_prefix ("error"), argv[2]); goto end; } if (weechat_strcasecmp (argv[3], "name") == 0) { trigger_command_rename (ptr_trigger, argv[4]); goto end; } value = weechat_string_remove_quotes (argv_eol[4], "'\""); if (value) { index_option = trigger_search_option (argv[3]); if (index_option >= 0) { weechat_config_option_set (ptr_trigger->options[index_option], value, 1); weechat_printf_tags (NULL, "no_trigger", _("Trigger \"%s\" updated"), ptr_trigger->name); } else { weechat_printf_tags (NULL, "no_trigger", _("%sError: trigger option \"%s\" not " "found"), weechat_prefix ("error"), argv[3]); } free (value); } goto end; } /* rename a trigger */ if (weechat_strcasecmp (argv[1], "rename") == 0) { if (argc < 4) goto error; ptr_trigger = trigger_search (argv[2]); if (!ptr_trigger) { weechat_printf_tags (NULL, "no_trigger", _("%sError: trigger \"%s\" not found"), weechat_prefix ("error"), argv[2]); goto end; } trigger_command_rename (ptr_trigger, argv[3]); goto end; } /* copy a trigger */ if (weechat_strcasecmp (argv[1], "copy") == 0) { if (argc < 4) goto error; ptr_trigger = trigger_search (argv[2]); if (!ptr_trigger) { weechat_printf_tags (NULL, "no_trigger", _("%sError: trigger \"%s\" not found"), weechat_prefix ("error"), argv[2]); goto end; } /* check that new name is valid */ if (!trigger_name_valid (argv[3])) { weechat_printf_tags (NULL, "no_trigger", _("%sError: invalid name for trigger"), weechat_prefix ("error")); goto end; } /* check that no trigger already exists with the new name */ if (trigger_search (argv[3])) { weechat_printf_tags (NULL, "no_trigger", _("%sError: trigger \"%s\" already " "exists"), weechat_prefix ("error"), argv[3]); goto end; } /* copy the trigger */ ptr_trigger2 = trigger_copy (ptr_trigger, argv[3]); if (ptr_trigger2) { weechat_printf_tags (NULL, "no_trigger", _("Trigger \"%s\" copied to \"%s\""), ptr_trigger->name, ptr_trigger2->name); } else { weechat_printf_tags (NULL, "no_trigger", _("%sError: failed to copy trigger " "\"%s\""), weechat_prefix ("error"), ptr_trigger->name); } goto end; } /* enable/disable/toggle/restart trigger(s) */ if ((weechat_strcasecmp (argv[1], "enable") == 0) || (weechat_strcasecmp (argv[1], "disable") == 0) || (weechat_strcasecmp (argv[1], "toggle") == 0) || (weechat_strcasecmp (argv[1], "restart") == 0)) { if (argc < 3) { if (weechat_strcasecmp (argv[1], "restart") == 0) goto error; if (weechat_strcasecmp (argv[1], "enable") == 0) weechat_config_option_set (trigger_config_look_enabled, "1", 1); else if (weechat_strcasecmp (argv[1], "disable") == 0) weechat_config_option_set (trigger_config_look_enabled, "0", 1); else if (weechat_strcasecmp (argv[1], "toggle") == 0) { weechat_config_option_set (trigger_config_look_enabled, (trigger_enabled) ? "0" : "1", 1); } trigger_command_display_status (); goto end; } enable = -1; if (weechat_strcasecmp (argv[1], "enable") == 0) enable = 1; else if (weechat_strcasecmp (argv[1], "disable") == 0) enable = 0; else if (weechat_strcasecmp (argv[1], "restart") == 0) enable = 2; if (weechat_strcasecmp (argv[2], "-all") == 0) { for (ptr_trigger = triggers; ptr_trigger; ptr_trigger = ptr_trigger->next_trigger) { trigger_command_set_enabled (ptr_trigger, enable, 0); } } else { for (i = 2; i < argc; i++) { ptr_trigger = trigger_search (argv[i]); if (ptr_trigger) trigger_command_set_enabled (ptr_trigger, enable, 1); else { weechat_printf_tags (NULL, "no_trigger", _("%sTrigger \"%s\" not found"), weechat_prefix ("error"), argv[i]); } } } goto end; } /* delete trigger(s) */ if (weechat_strcasecmp (argv[1], "del") == 0) { if (argc < 3) goto error; if (weechat_strcasecmp (argv[2], "-all") == 0) { count = triggers_count; trigger_free_all (); if (count > 0) weechat_printf_tags (NULL, "no_trigger", _("%d triggers removed"), count); } else { for (i = 2; i < argc; i++) { ptr_trigger = trigger_search (argv[i]); if (ptr_trigger) { trigger_free (ptr_trigger); weechat_printf_tags (NULL, "no_trigger", _("Trigger \"%s\" removed"), argv[i]); } else { weechat_printf_tags (NULL, "no_trigger", _("%sTrigger \"%s\" not found"), weechat_prefix ("error"), argv[i]); } } } goto end; } /* show detailed info on a trigger */ if (weechat_strcasecmp (argv[1], "show") == 0) { if (argc < 3) goto error; ptr_trigger = trigger_search (argv[2]); if (!ptr_trigger) { weechat_printf_tags (NULL, "no_trigger", _("%sError: trigger \"%s\" not found"), weechat_prefix ("error"), argv[2]); goto end; } weechat_printf_tags (NULL, "no_trigger", ""); weechat_printf_tags (NULL, "no_trigger", _("Trigger:")); trigger_command_display_trigger (ptr_trigger, 2); goto end; } /* restore default triggers */ if (weechat_strcasecmp (argv[1], "default") == 0) { if ((argc >= 3) && (weechat_strcasecmp (argv[2], "-yes") == 0)) { trigger_free_all (); trigger_create_default (); trigger_command_list (_("Default triggers restored:"), 0); } else { weechat_printf (NULL, _("%sError: \"-yes\" argument is required for " "restoring default triggers (security reason)"), weechat_prefix ("error")); } goto end; } /* open the trigger monitor buffer */ if (weechat_strcasecmp (argv[1], "monitor") == 0) { trigger_buffer_open (1); goto end; } error: rc = WEECHAT_RC_ERROR; end: if (sargv) weechat_string_free_split (sargv); return rc; } /* * Hooks trigger commands. */ void trigger_command_init () { weechat_hook_command ( "trigger", N_("manage triggers, the Swiss Army knife for WeeChat"), N_("list|listfull|listdefault" " || add|addoff|addreplace [\"\" " "[\"\" [\"\" [\"\" " "[\"\"]]]]]" " || addinput []" " || input|output|recreate " " || set