diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2014-02-21 15:36:14 +0100 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2014-02-21 15:36:14 +0100 |
commit | f907ea17d51d0446987970ab42b225054c99b12c (patch) | |
tree | 682e13d516f36522639433b49d481939c1b33c4f | |
parent | 30191871781575436492eb8ce29c2db660450997 (diff) | |
parent | d6e7c9fda6e6ae4528044c223ab37885adbde90a (diff) | |
download | weechat-f907ea17d51d0446987970ab42b225054c99b12c.zip |
Merge branch 'trigger'
46 files changed, 6748 insertions, 740 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d2fa082b8..ac7693253 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,6 +85,7 @@ OPTION(ENABLE_RUBY "Enable Ruby scripting language" ON) OPTION(ENABLE_LUA "Enable Lua scripting language" ON) OPTION(ENABLE_TCL "Enable Tcl scripting language" ON) OPTION(ENABLE_GUILE "Enable Scheme (guile) scripting language" ON) +OPTION(ENABLE_TRIGGER "Enable Trigger plugin" ON) OPTION(ENABLE_XFER "Enable Xfer plugin" ON) OPTION(ENABLE_MAN "Enable build of man page" OFF) OPTION(ENABLE_DOC "Enable build of documentation" OFF) diff --git a/configure.ac b/configure.ac index d851eaa82..c3b7cfdb5 100644 --- a/configure.ac +++ b/configure.ac @@ -116,6 +116,7 @@ AH_VERBATIM([PLUGIN_RUBY], [#undef PLUGIN_RUBY]) AH_VERBATIM([PLUGIN_LUA], [#undef PLUGIN_LUA]) AH_VERBATIM([PLUGIN_TCL], [#undef PLUGIN_TCL]) AH_VERBATIM([PLUGIN_GUILE], [#undef PLUGIN_GUILE]) +AH_VERBATIM([PLUGIN_TRIGGER], [#undef PLUGIN_TRIGGER]) AH_VERBATIM([PLUGIN_XFER], [#undef PLUGIN_XFER]) AH_VERBATIM([MAN], [#undef MAN]) AH_VERBATIM([DOC], [#undef DOC]) @@ -145,6 +146,7 @@ AC_ARG_ENABLE(ruby, [ --disable-ruby turn off Ruby script plug AC_ARG_ENABLE(lua, [ --disable-lua turn off Lua script plugin (default=compiled if found)],enable_lua=$enableval,enable_lua=yes) AC_ARG_ENABLE(tcl, [ --disable-tcl turn off Tcl script plugin (default=compiled if found)],enable_tcl=$enableval,enable_tcl=yes) AC_ARG_ENABLE(guile, [ --disable-guile turn off Guile (scheme) script plugin (default=compiled if found)],enable_guile=$enableval,enable_guile=yes) +AC_ARG_ENABLE(trigger, [ --disable-trigger turn off Trigger plugin (default=compiled)],enable_trigger=$enableval,enable_trigger=yes) AC_ARG_ENABLE(xfer, [ --disable-xfer turn off Xfer (file transfer) plugin (default=compiled if found)],enable_xfer=$enableval,enable_xfer=yes) AC_ARG_WITH(lua-inc, [ --with-lua-inc=DIR, lua include files are in DIR (default=autodetect)],lua_inc=$withval,lua_inc='') AC_ARG_WITH(lua-lib, [ --with-lua-lib=DIR, lua library files are in DIR (default=autodetect)],lua_lib=$withval,lua_lib='') @@ -800,6 +802,18 @@ if test "x$enable_guile" = "xyes" ; then AC_DEFINE(PLUGIN_GUILE) fi +# --------------------------------- trigger ------------------------------------ + +if test "x$enable_trigger" = "xyes" ; then + TRIGGER_CFLAGS="" + TRIGGER_LFLAGS="" + AC_SUBST(TRIGGER_CFLAGS) + AC_SUBST(TRIGGER_LFLAGS) + AC_DEFINE(PLUGIN_TRIGGER) +else + not_asked="$not_asked trigger" +fi + # ---------------------------------- xfer -------------------------------------- if test "x$enable_xfer" = "xyes" ; then @@ -1125,6 +1139,7 @@ AM_CONDITIONAL(PLUGIN_RUBY, test "$enable_ruby" = "yes") AM_CONDITIONAL(PLUGIN_LUA, test "$enable_lua" = "yes") AM_CONDITIONAL(PLUGIN_TCL, test "$enable_tcl" = "yes") AM_CONDITIONAL(PLUGIN_GUILE, test "$enable_guile" = "yes") +AM_CONDITIONAL(PLUGIN_TRIGGER, test "$enable_trigger" = "yes") AM_CONDITIONAL(PLUGIN_XFER, test "$enable_xfer" = "yes") AM_CONDITIONAL(MAN, test "$enable_man" = "yes") AM_CONDITIONAL(DOC, test "$enable_doc" = "yes") @@ -1157,6 +1172,7 @@ AC_OUTPUT([Makefile src/plugins/lua/Makefile src/plugins/tcl/Makefile src/plugins/guile/Makefile + src/plugins/trigger/Makefile src/plugins/xfer/Makefile src/gui/Makefile src/gui/curses/Makefile @@ -1224,6 +1240,9 @@ fi if test "x$enable_guile" = "xyes"; then listplugins="$listplugins guile($GUILE_VERSION)" fi +if test "x$enable_trigger" = "xyes"; then + listplugins="$listplugins trigger" +fi if test "x$enable_xfer" = "xyes"; then listplugins="$listplugins xfer" fi diff --git a/debian/weechat-plugins.install b/debian/weechat-plugins.install index 4ca5c7436..9b0696cfc 100644 --- a/debian/weechat-plugins.install +++ b/debian/weechat-plugins.install @@ -9,3 +9,4 @@ usr/lib/weechat/plugins/tcl.so usr/lib/weechat/plugins/script.so usr/lib/weechat/plugins/relay.so usr/lib/weechat/plugins/rmodifier.so +usr/lib/weechat/plugins/trigger.so diff --git a/doc/de/weechat.1.de.txt b/doc/de/weechat.1.de.txt index f868a87f7..86e68946f 100644 --- a/doc/de/weechat.1.de.txt +++ b/doc/de/weechat.1.de.txt @@ -77,6 +77,9 @@ $HOME/.weechat/rmodifier.conf:: $HOME/.weechat/script.conf:: Konfigurationsdatei für 'script' Erweiterung +$HOME/.weechat/trigger.conf:: + Konfigurationsdatei für 'trigger' Erweiterung + $HOME/.weechat/xfer.conf:: Konfigurationsdatei für 'xfer' Erweiterung diff --git a/doc/docgen.py b/doc/docgen.py index d59dd19d7..f671a4300 100644 --- a/doc/docgen.py +++ b/doc/docgen.py @@ -87,20 +87,21 @@ plugin_list = { 'weechat': 'co', 'alias': '', 'aspell': 'o', - 'charset': 'co', - 'fifo': 'co', + 'charset': 'o', + 'fifo': 'o', 'irc': 'co', - 'logger': 'co', - 'relay': 'co', - 'rmodifier': 'co', - 'script': 'co', + 'logger': 'o', + 'relay': 'o', + 'rmodifier': 'o', + 'script': 'o', 'perl': '', 'python': '', 'ruby': '', 'lua': '', 'tcl': '', 'guile': '', - 'xfer': 'co', + 'trigger': 'o', + 'xfer': 'o', } # options to ignore @@ -118,6 +119,7 @@ ignore_options = ( 'logger\.mask\..*', 'relay\.port\..*', 'rmodifier\.modifier\..*', + 'trigger\.trigger\..*', 'weechat\.palette\..*', 'weechat\.proxy\..*', 'weechat\.bar\..*', diff --git a/doc/en/weechat.1.en.txt b/doc/en/weechat.1.en.txt index 826488516..2f0460012 100644 --- a/doc/en/weechat.1.en.txt +++ b/doc/en/weechat.1.en.txt @@ -76,6 +76,9 @@ $HOME/.weechat/rmodifier.conf:: $HOME/.weechat/script.conf:: configuration file for 'script' plugin +$HOME/.weechat/trigger.conf:: + configuration file for 'trigger' plugin + $HOME/.weechat/xfer.conf:: configuration file for 'xfer' plugin diff --git a/doc/en/weechat_dev.en.txt b/doc/en/weechat_dev.en.txt index d864d65b8..2f31568b5 100644 --- a/doc/en/weechat_dev.en.txt +++ b/doc/en/weechat_dev.en.txt @@ -66,6 +66,7 @@ The main WeeChat directories are: | lua/ | Lua scripting API | tcl/ | Tcl scripting API | guile/ | Guile (scheme) scripting API +| trigger/ | Trigger plugin | xfer/ | Xfer plugin (IRC DCC file/chat) | doc/ | Documentation | po/ | Translations files (gettext) @@ -260,6 +261,13 @@ WeeChat "core" is located in following directories: | tcl/ | Tcl plugin | weechat-tcl.c | Main tcl functions (load/unload scripts, execute tcl code) | weechat-tcl-api.c | Tcl scripting API functions +| trigger/ | Trigger plugin +| trigger.c | Main trigger functions +| trigger-buffer.c | Trigger buffer +| trigger-callback.c | Trigger callbacks +| trigger-command.c | Trigger commands +| trigger-completion.c | Trigger completions +| trigger-config.c | Trigger config options (file trigger.conf) | xfer/ | Xfer plugin (IRC DCC file/chat) | xfer.c | Main xfer functions | xfer-buffer.c | Xfer buffer diff --git a/doc/en/weechat_plugin_api.en.txt b/doc/en/weechat_plugin_api.en.txt index 02aa46692..c8a06524c 100644 --- a/doc/en/weechat_plugin_api.en.txt +++ b/doc/en/weechat_plugin_api.en.txt @@ -854,41 +854,6 @@ match3 = weechat.string_match("abcdef", "*def", 0) # 1 match4 = weechat.string_match("abcdef", "*de*", 0) # 1 ---- -==== weechat_string_replace - -Replace all occurrences of a string by another string. - -Prototype: - -[source,C] ----- -char *weechat_string_replace (const char *string, const char *search, - const char *replace); ----- - -Arguments: - -* 'string': string -* 'search': string to replace -* 'replace': replacement for string 'search' - -Return value: - -* string with 'search' replaced by 'replace' (must be freed by calling "free" - after use) - -C example: - -[source,C] ----- -char *str = weechat_string_replace ("test", "s", "x"); /* result: "text" */ -/* ... */ -free (str); ----- - -[NOTE] -This function is not available in scripting API. - ==== weechat_string_expand_home _WeeChat ≥ 0.3.3._ @@ -995,6 +960,56 @@ free (str); [NOTE] This function is not available in scripting API. +==== weechat_string_convert_escaped_chars + +_WeeChat ≥ 0.4.4._ + +Convert escaped chars to their value: + +* `\"`: double quote +* `\\`: backslash +* `\a`: alert (BEL) +* `\b`: backspace +* `\e`: escape +* `\f`: form feed +* `\n`: new line +* `\r`: carriage return +* `\t`: horizontal tab +* `\v`: vertical tab +* `\0ooo`: char as octal value (ooo is 0 to 3 digits) +* `\xhh`: char as hexadecimal value (hh is 1 to 2 digits) +* `\uhhhh`: unicode char as hexadecimal value (hhhh is 1 to 4 digits) +* `\Uhhhhhhhh`: unicode char as hexadecimal value (hhhhhhhh is 1 to 8 digits) + +Prototype: + +[source,C] +---- +char *weechat_string_convert_escaped_chars (const char *string); +---- + +Arguments: + +* 'string': string + +Return value: + +* string with escaped chars replaced by their value (must be freed by calling + "free" after use) + +C example: + +[source,C] +---- +char *str = weechat_string_convert_escaped_chars ("snowman: \\u2603"); +/* str == "snowman: ☃" */ +/* ... */ +free (str); +---- + +[NOTE] +This function is not available in scripting API. + ==== weechat_string_mask_to_regex Return a regex, built with a mask, where only special char is "`*`". All other @@ -1214,6 +1229,95 @@ highlight = weechat.string_has_highlight_regex(string, regex) highlight = weechat.string_has_highlight_regex("my test string", "test|word2") # 1 ---- +==== weechat_string_replace + +Replace all occurrences of a string by another string. + +Prototype: + +[source,C] +---- +char *weechat_string_replace (const char *string, const char *search, + const char *replace); +---- + +Arguments: + +* 'string': string +* 'search': string to replace +* 'replace': replacement for string 'search' + +Return value: + +* string with 'search' replaced by 'replace' (must be freed by calling "free" + after use) + +C example: + +[source,C] +---- +char *str = weechat_string_replace ("test", "s", "x"); /* result: "text" */ +/* ... */ +free (str); +---- + +[NOTE] +This function is not available in scripting API. + +==== weechat_string_replace_regex + +_WeeChat ≥ 0.4.4._ + +Replace text in a string using a regular expression and replacement text. + +Prototype: + +[source,C] +---- +char *weechat_string_replace_regex (const char *string, void *regex, + const char *replace, const char reference_char); +---- + +Arguments: + +* 'string': string +* 'regex': pointer to a regular expression ('regex_t' structure) compiled with + WeeChat function <<_weechat_string_regcomp,weechat_string_regcomp>> or regcomp + (see `man regcomp`) +* 'replace': replacement text, where following references are allowed: +** `$0` to `$99`: match 0 to 99 in regular expression (0 is the whole match, + 1 to 99 are groups captured between parentheses) +** `$+`: the last match (with highest number) +** `$.*N`: match `N` (can be `+` or `0` to `99`), with all chars replaced by `*` + (the `*` char can be any char between space (32) and `~` (126)) +* 'reference_char': the char used for reference to match (commonly '$') + +Return value: + +* string with text replaced, NULL if problem (must be freed by calling "free" + after use) + +C example: + +[source,C] +---- +regex_t my_regex; +char *string; +if (weechat_string_regcomp (&my_regex, "([0-9]{4})-([0-9]{2})-([0-9]{2})", + REG_EXTENDED) == 0) +{ + string = weechat_string_replace_regex ("date: 2014-02-14", &my_regex, + "$3/$2/$1", '$'); + /* string == "date: 14/02/2014" */ + if (string) + free (string); + regfree (&my_regex); +} +---- + +[NOTE] +This function is not available in scripting API. + ==== weechat_string_split Split a string according to one or more delimiter(s). @@ -1244,7 +1348,7 @@ Return value: * array of strings, NULL if problem (must be freed by calling <<_weechat_string_free_split,weechat_string_free_split>> after use) -C examples: +C example: [source,C] ---- @@ -1272,6 +1376,51 @@ weechat_string_free_split (argv); [NOTE] This function is not available in scripting API. +==== weechat_string_split_shell + +_WeeChat ≥ 0.4.4._ + +Split a string like the shell does for a command with arguments. + +This function is a C conversion of Python class "shlex" (file: Lib/shlex.py in +Python repository), see: http://docs.python.org/3/library/shlex.html. + +Prototype: + +[source,C] +---- +char **weechat_string_split_shell (const char *string, int *num_items); +---- + +Arguments: + +* 'string': string to split +* 'num_items': pointer to int which will contain number of items created + +Return value: + +* array of strings, NULL if problem (must be freed by calling + <<_weechat_string_free_split,weechat_string_free_split>> after use) + +C example: + +[source,C] +---- +char **argv; +int argc; +argv = weechat_string_split_shell ("test 'first arg' \"second arg\"", &argc); +/* result: argv[0] == "test" + argv[1] == "first arg" + argv[2] == "second arg" + argv[3] == NULL + argc == 3 +*/ +weechat_string_free_split (argv); +---- + +[NOTE] +This function is not available in scripting API. + ==== weechat_string_free_split Free memory used by a split string. @@ -3480,6 +3629,37 @@ weechat_hashtable_map_string (hashtable, &map_cb, NULL); [NOTE] This function is not available in scripting API. +==== weechat_hashtable_dup + +_WeeChat ≥ 0.4.4._ + +Duplicate a hashtable. + +Prototype: + +[source,C] +---- +struct t_hashtable *hashtable_dup (struct t_hashtable *hashtable); +---- + +Arguments: + +* 'hashtable': hashtable pointer + +Return value: + +* duplicated hashtable + +C example: + +[source,C] +---- +struct t_hashtable *new_hashtable = weechat_hashtable_dup (hashtable); +---- + +[NOTE] +This function is not available in scripting API. + ==== weechat_hashtable_get_integer _WeeChat ≥ 0.3.3._ diff --git a/doc/fr/weechat.1.fr.txt b/doc/fr/weechat.1.fr.txt index 97d2f7cd5..72c04eb26 100644 --- a/doc/fr/weechat.1.fr.txt +++ b/doc/fr/weechat.1.fr.txt @@ -78,6 +78,9 @@ $HOME/.weechat/rmodifier.conf:: $HOME/.weechat/script.conf:: fichier de configuration pour l'extension 'script' +$HOME/.weechat/trigger.conf:: + fichier de configuration pour l'extension 'trigger' + $HOME/.weechat/xfer.conf:: fichier de configuration pour l'extension 'xfer' diff --git a/doc/fr/weechat_dev.fr.txt b/doc/fr/weechat_dev.fr.txt index 887314447..421b164a9 100644 --- a/doc/fr/weechat_dev.fr.txt +++ b/doc/fr/weechat_dev.fr.txt @@ -67,6 +67,7 @@ Les répertoires principaux de WeeChat sont : | lua/ | API script Lua | tcl/ | API script Tcl | guile/ | API script Guile (scheme) +| trigger/ | Extension Trigger | xfer/ | Extension Xfer (IRC DCC fichier/discussion) | doc/ | Documentation | po/ | Fichiers de traductions (gettext) @@ -261,6 +262,13 @@ Le cœur de WeeChat est situé dans les répertoires suivants : | tcl/ | Extension Tcl | weechat-tcl.c | Fonctions principales pour Tcl (chargement/déchargement des scripts, exécution de code Tcl) | weechat-tcl-api.c | Fonctions de l'API script Tcl +| trigger/ | Extension Trigger +| trigger.c | Fonctions principales de Trigger +| trigger-buffer.c | Tampon Trigger +| trigger-callback.c | Callbacks de Trigger +| trigger-command.c | Commandes pour Trigger +| trigger-completion.c | Complétions pour Trigger +| trigger-config.c | Options de configuration pour Trigger (fichier trigger.conf) | xfer/ | Extension Xfer (IRC DCC fichier/discussion) | xfer.c | Fonctions principales de Xfer | xfer-buffer.c | Tampon Xfer diff --git a/doc/fr/weechat_plugin_api.fr.txt b/doc/fr/weechat_plugin_api.fr.txt index 596b82924..79cef0b85 100644 --- a/doc/fr/weechat_plugin_api.fr.txt +++ b/doc/fr/weechat_plugin_api.fr.txt @@ -863,41 +863,6 @@ match3 = weechat.string_match("abcdef", "*def", 0) # 1 match4 = weechat.string_match("abcdef", "*de*", 0) # 1 ---- -==== weechat_string_replace - -Remplacer toutes les occurrences d'une chaîne par une autre chaîne. - -Prototype : - -[source,C] ----- -char *weechat_string_replace (const char *string, const char *search, - const char *replace); ----- - -Paramètres : - -* 'string' : chaîne -* 'search' : chaîne à remplacer -* 'replace' : remplacement pour la chaîne 'search' - -Valeur de retour : - -* chaîne avec 'search' remplacée par 'replace' (doit être supprimée par un appel - à "free" après utilisation) - -Exemple en C : - -[source,C] ----- -char *str = weechat_string_replace ("test, test", "s", "x"); /* résultat : "text" */ -/* ... */ -free (str); ----- - -[NOTE] -Cette fonction n'est pas disponible dans l'API script. - ==== weechat_string_expand_home _WeeChat ≥ 0.3.3._ @@ -1005,6 +970,58 @@ free (str); [NOTE] Cette fonction n'est pas disponible dans l'API script. +==== weechat_string_convert_escaped_chars + +_WeeChat ≥ 0.4.4._ + +Convertir les caractères échappés par leur valeur : + +* `\"` : double guillemet droit +* `\\` : barre oblique inversée +* `\a` : alerte (BEL) +* `\b` : retour arrière +* `\e` : échappement +* `\f` : saut de page +* `\n` : nouvelle ligne +* `\r` : retour chariot +* `\t` : tabulation horizontale +* `\v` : tabulation verticale +* `\0ooo` : caractère sous forme de valeur octale (ooo a 0 à 3 chiffres) +* `\xhh` : caractère sous forme de valeur hexadécimale (hh a 1 à 2 chiffres) +* `\uhhhh` : caractère unicode sous forme de valeur hexadécimale (hhhh a 1 à 4 + chiffres) +* `\Uhhhhhhhh` : caractère unicode sous forme de valeur hexadécimale (hhhhhhhh + a 1 à 8 chiffres) + +Prototype : + +[source,C] +---- +char *weechat_string_convert_escaped_chars (const char *string); +---- + +Paramètres : + +* 'string' : chaîne + +Valeur de retour : + +* chaîne avec les caractères échappés remplacés par leur valeur (doit être + supprimée par un appel à "free" après utilisation) + +Exemple en C : + +[source,C] +---- +char *str = weechat_string_convert_escaped_chars ("snowman: \\u2603"); +/* str == "snowman: ☃" */ +/* ... */ +free (str); +---- + +[NOTE] +Cette fonction n'est pas disponible dans l'API script. + ==== weechat_string_mask_to_regex Retourner une expression régulière ("regex"), construite avec un masque où le @@ -1230,6 +1247,100 @@ highlight = weechat.string_has_highlight_regex(string, regex) highlight = weechat.string_has_highlight_regex("my test string", "test|word2") # 1 ---- +==== weechat_string_replace + +Remplacer toutes les occurrences d'une chaîne par une autre chaîne. + +Prototype : + +[source,C] +---- +char *weechat_string_replace (const char *string, const char *search, + const char *replace); +---- + +Paramètres : + +* 'string' : chaîne +* 'search' : chaîne à remplacer +* 'replace' : remplacement pour la chaîne 'search' + +Valeur de retour : + +* chaîne avec 'search' remplacée par 'replace' (doit être supprimée par un appel + à "free" après utilisation) + +Exemple en C : + +[source,C] +---- +char *str = weechat_string_replace ("test, test", "s", "x"); /* résultat : "text" */ +/* ... */ +free (str); +---- + +[NOTE] +Cette fonction n'est pas disponible dans l'API script. + +==== weechat_string_replace_regex + +_WeeChat ≥ 0.4.4._ + +Remplacer du texte dans une chaîne en utilisant une expression régulière et du +texte de remplacement. + +Prototype : + +[source,C] +---- +char *weechat_string_replace_regex (const char *string, void *regex, + const char *replace, const char reference_char); +---- + +Paramètres : + +* 'string' : chaîne +* 'regex' : pointeur vers une expression régulière (structure 'regex_t') + compilée avec la fonction WeeChat + <<_weechat_string_regcomp,weechat_string_regcomp>> ou regcomp (voir + `man regcomp`) +* 'replace' : texte de remplacement, où les références suivantes sont + autorisées : +** `$0` à `$99` : correspondance 0 à 99 dans l'expression régulière (0 est la + correspondance entière, 1 à 99 sont les groupes capturés entre parenthèses) +** `$+` : la dernière correspondance (avec le numéro le plus élevé) +** `$.*N` : correspondance `N` (peut être `+` ou de `0` à `99`), avec tous les + caractères remplacés par `*` (le caractère `*` peut être n'importe quel + caractère entre l'espace (32) et `~` (126)) +* 'reference_char' : le caractère utilisé pour les références aux + correspondances (en général '$') + +Valeur de retour : + +* chaîne avec le texte remplacé, NULL en cas de problème (doit être supprimée + par un appel à "free" après utilisation) + +Exemple en C : + +[source,C] +---- +regex_t my_regex; +char *string; +if (weechat_string_regcomp (&my_regex, "([0-9]{4})-([0-9]{2})-([0-9]{2})", + REG_EXTENDED) == 0) +{ + string = weechat_string_replace_regex ("date: 2014-02-14", &my_regex, + "$3/$2/$1", '$'); + /* string == "date: 14/02/2014" */ + if (string) + free (string); + regfree (&my_regex); +} +---- + +[NOTE] +Cette fonction n'est pas disponible dans l'API script. + ==== weechat_string_split Découper une chaîne à l'aide de délimiteur(s). @@ -1291,6 +1402,54 @@ weechat_string_free_split (argv); [NOTE] Cette fonction n'est pas disponible dans l'API script. +==== weechat_string_split_shell + +_WeeChat ≥ 0.4.4._ + +Découper une chaîne comme le shell le fait pour une commande avec ses +paramètres. + +Cette fonction est une conversion en C de la classe Python "shlex" (fichier : +Lib/shlex.py dans le dépôt Python), voir : +http://docs.python.org/3/library/shlex.html. + +Prototype : + +[source,C] +---- +char **weechat_string_split_shell (const char *string, int *num_items); +---- + +Paramètres : + +* 'string' : chaîne à découper +* 'num_items' : pointeur vers un entier qui contiendra le nombre de chaînes + créées + +Valeur de retour : + +* tableau de chaînes, NULL en cas de problème (doit être supprimé par un appel à + <<_weechat_string_free_split,weechat_string_free_split>> après utilisation) + +Exemple en C : + +[source,C] +---- +char **argv; +int argc; +argv = weechat_string_split_shell ("test 'first arg' \"second arg\"", &argc); +/* résultat: argv[0] == "test" + argv[1] == "first arg" + argv[2] == "second arg" + argv[3] == NULL + argc == 3 +*/ +weechat_string_free_split (argv); +---- + +[NOTE] +Cette fonction n'est pas disponible dans l'API script. + ==== weechat_string_free_split Supprimer une chaîne découpée. @@ -3381,7 +3540,7 @@ Paramètres : * 'hashtable' : pointeur vers la table de hachage * 'key' : pointeur vers la clé -Valeur en retour : +Valeur de retour : * valeur pour la clé, NULL si la clé n'est pas trouvée @@ -3413,7 +3572,7 @@ Paramètres : * 'hashtable' : pointeur vers la table de hachage * 'key' : pointeur vers la clé -Valeur en retour : +Valeur de retour : * 1 si la clé est dans la table de hachage, 0 si la clé n'est pas dans la table de hachage @@ -3524,6 +3683,37 @@ weechat_hashtable_map_string (hashtable, &map_cb, NULL); [NOTE] Cette fonction n'est pas disponible dans l'API script. +==== weechat_hashtable_dup + +_WeeChat ≥ 0.4.4._ + +Dupliquer une table de hachage. + +Prototype : + +[source,C] +---- +struct t_hashtable *hashtable_dup (struct t_hashtable *hashtable); +---- + +Paramètres : + +* 'hashtable' : pointeur vers la table de hachage + +Valeur de retour : + +* table de hachage dupliquée + +Exemple en C : + +[source,C] +---- +struct t_hashtable *new_hashtable = weechat_hashtable_dup (hashtable); +---- + +[NOTE] +Cette fonction n'est pas disponible dans l'API script. + ==== weechat_hashtable_get_integer _WeeChat ≥ 0.3.3._ @@ -3545,7 +3735,7 @@ Paramètres : ** 'size' : taille du tableau interne "htable" dans la table de hachage ** 'items_count' : nombre d'éléments dans la table de hachage -Valeur en retour : +Valeur de retour : * valeur de la propriété sous forme d'entier @@ -3600,7 +3790,7 @@ Paramètres : ** 'keys_values_sorted' : chaîne avec la liste des clés et valeurs (triée sur les clés) (format : "clé1:valeur1,clé2:valeur2,clé3:valeur3") -Valeur en retour : +Valeur de retour : * valeur de la propriété sous forme de chaîne @@ -3678,7 +3868,7 @@ Paramètres : * 'infolist_item' : pointeur vers l'objet de l'infolist * 'prefix' : chaîne utilisée comme préfixe pour les noms dans l'infolist -Valeur en retour : +Valeur de retour : * 1 si ok, 0 en cas d'erreur diff --git a/doc/it/weechat.1.it.txt b/doc/it/weechat.1.it.txt index 37c0c1561..0d2c8e107 100644 --- a/doc/it/weechat.1.it.txt +++ b/doc/it/weechat.1.it.txt @@ -77,6 +77,9 @@ $HOME/.weechat/rmodifier.conf:: $HOME/.weechat/script.conf:: configuration file for 'script' plugin +$HOME/.weechat/trigger.conf:: + configuration file for 'trigger' plugin + $HOME/.weechat/xfer.conf:: configuration file for 'xfer' plugin diff --git a/doc/it/weechat_plugin_api.it.txt b/doc/it/weechat_plugin_api.it.txt index 840a81049..bc560e3e2 100644 --- a/doc/it/weechat_plugin_api.it.txt +++ b/doc/it/weechat_plugin_api.it.txt @@ -871,41 +871,6 @@ match3 = weechat.string_match("abcdef", "*def", 0) # 1 match4 = weechat.string_match("abcdef", "*de*", 0) # 1 ---- -==== weechat_string_replace - -Sostituisce tutte le ricorrenze di una stringa con un'altra. - -Prototipo: - -[source,C] ----- -char *weechat_string_replace (const char *string, const char *search, - const char *replace); ----- - -Argomenti: - -* 'string': stringa -* 'search': stringa da sostituire -* 'replace': sostituzione per la stringa 'search' - -Valore restituito: - -* la stringa dopo 'search' sostituita da 'replace' (deve essere liberata - chiamando "free" dopo l'uso) - -Esempio in C: - -[source,C] ----- -char *str = weechat_string_replace ("test", "s", "x"); /* result: "text" */ -/* ... */ -free (str); ----- - -[NOTE] -Questa funzione non è disponibile nelle API per lo scripting. - ==== weechat_string_expand_home _WeeChat ≥ 0.3.3._ @@ -1012,6 +977,58 @@ free (str); [NOTE] Questa funzione non è disponibile nelle API per lo scripting. +==== weechat_string_convert_escaped_chars + +_WeeChat ≥ 0.4.4._ + +// TRANSLATION MISSING +Convert escaped chars to their value: + +* `\"`: double quote +* `\\`: backslash +* `\a`: alert (BEL) +* `\b`: backspace +* `\e`: escape +* `\f`: form feed +* `\n`: new line +* `\r`: carriage return +* `\t`: horizontal tab +* `\v`: vertical tab +* `\0ooo`: char as octal value (ooo is 0 to 3 digits) +* `\xhh`: char as hexadecimal value (hh is 1 to 2 digits) +* `\uhhhh`: unicode char as hexadecimal value (hhhh is 1 to 4 digits) +* `\Uhhhhhhhh`: unicode char as hexadecimal value (hhhhhhhh is 1 to 8 digits) + +Prototipo: + +[source,C] +---- +char *weechat_string_convert_escaped_chars (const char *string); +---- + +Argomenti: + +* 'string': stringa + +Valore restituito: + +// TRANSLATION MISSING +* string with escaped chars replaced by their value (deve essere liberata + chiamando "free" dopo l'uso) + +Esempio in C: + +[source,C] +---- +char *str = weechat_string_convert_escaped_chars ("snowman: \\u2603"); +/* str == "snowman: ☃" */ +/* ... */ +free (str); +---- + +[NOTE] +Questa funzione non è disponibile nelle API per lo scripting. + ==== weechat_string_mask_to_regex Restituisce una espressione regolare con una mask, dove l'unico carattere @@ -1245,6 +1262,98 @@ highlight = weechat.string_has_highlight_regex(string, regex) highlight = weechat.string_has_highlight_regex("my test string", "test|word2") # 1 ---- +==== weechat_string_replace + +Sostituisce tutte le ricorrenze di una stringa con un'altra. + +Prototipo: + +[source,C] +---- +char *weechat_string_replace (const char *string, const char *search, + const char *replace); +---- + +Argomenti: + +* 'string': stringa +* 'search': stringa da sostituire +* 'replace': sostituzione per la stringa 'search' + +Valore restituito: + +* la stringa dopo 'search' sostituita da 'replace' (deve essere liberata + chiamando "free" dopo l'uso) + +Esempio in C: + +[source,C] +---- +char *str = weechat_string_replace ("test", "s", "x"); /* result: "text" */ +/* ... */ +free (str); +---- + +[NOTE] +Questa funzione non è disponibile nelle API per lo scripting. + +==== weechat_string_replace_regex + +_WeeChat ≥ 0.4.4._ + +// TRANSLATION MISSING +Replace text in a string using a regular expression and replacement text. + +Prototipo: + +[source,C] +---- +char *weechat_string_replace_regex (const char *string, void *regex, + const char *replace, const char reference_char); +---- + +Argomenti: + +// TRANSLATION MISSING +* 'string': string +* 'regex': pointer to a regular expression ('regex_t' structure) compiled with + WeeChat function <<_weechat_string_regcomp,weechat_string_regcomp>> or regcomp + (see `man regcomp`) +* 'replace': replacement text, where following references are allowed: +** `$0` to `$99`: match 0 to 99 in regular expression (0 is the whole match, + 1 to 99 are groups captured between parentheses) +** `$+`: the last match (with highest number) +** `$.*N`: match `N` (can be `+` or `0` to `99`), with all chars replaced by `*` + (the `*` char can be any char between space (32) and `~` (126)) +* 'reference_char': the char used for reference to match (commonly '$') + +Valore restituito: + +// TRANSLATION MISSING +* string with text replaced, NULL if problem (must be freed by calling "free" + after use) + +Esempio in C: + +[source,C] +---- +regex_t my_regex; +char *string; +if (weechat_string_regcomp (&my_regex, "([0-9]{4})-([0-9]{2})-([0-9]{2})", + REG_EXTENDED) == 0) +{ + string = weechat_string_replace_regex ("date: 2014-02-14", &my_regex, + "$3/$2/$1", '$'); + /* string == "date: 14/02/2014" */ + if (string) + free (string); + regfree (&my_regex); +} +---- + +[NOTE] +Questa funzione non è disponibile nelle API per lo scripting. + ==== weechat_string_split Divide una stringa in base a uno o più delimitatori. @@ -1301,6 +1410,56 @@ argv = weechat_string_split ("abc de fghi", " ", 1, 0, &argc); weechat_string_free_split (argv); ---- +[NOTE] +Questa funzione non è disponibile nelle API per lo scripting. + +==== weechat_string_split_shell + +_WeeChat ≥ 0.4.4._ + +// TRANSLATION MISSING +Split a string like the shell does for a command with arguments. + +// TRANSLATION MISSING +This function is a C conversion of Python class "shlex" (file: Lib/shlex.py in +Python repository), see: http://docs.python.org/3/library/shlex.html. + +Prototipo: + +[source,C] +---- +char **weechat_string_split_shell (const char *string, int *num_items); +---- + +Argomenti: + +* 'string': stringa da dividere +* 'num_items': puntatore ad int che conterrà il numero di elementi creati + +Valore restituito: + +* array di stringhe, NULL se si verifica un problema (deve essere liberata chiamando + <<_weechat_string_free_split,weechat_string_free_split>> dopo l'uso) + +Esempio in C: + +[source,C] +---- +char **argv; +int argc; +argv = weechat_string_split_shell ("test 'first arg' \"second arg\"", &argc); +/* result: argv[0] == "test" + argv[1] == "first arg" + argv[2] == "second arg" + argv[3] == NULL + argc == 3 +*/ +weechat_string_free_split (argv); +---- + +[NOTE] +Questa funzione non è disponibile nelle API per lo scripting. + ==== weechat_string_free_split Libera la memoria usata per la divisione di una stringa. @@ -3535,6 +3694,39 @@ weechat_hashtable_map_string (hashtable, &map_cb, NULL); [NOTE] Questa funzione non è disponibile nelle API per lo scripting. +==== weechat_hashtable_dup + +_WeeChat ≥ 0.4.4._ + +// TRANSLATION MISSING +Duplicate a hashtable. + +Prototipo: + +[source,C] +---- +struct t_hashtable *hashtable_dup (struct t_hashtable *hashtable); +---- + +Argomenti: + +* 'hashtable': puntatore alla tabella hash + +Valore restituito: + +// TRANSLATION MISSING +* duplicated hashtable + +Esempio in C: + +[source,C] +---- +struct t_hashtable *new_hashtable = weechat_hashtable_dup (hashtable); +---- + +[NOTE] +Questa funzione non è disponibile nelle API per lo scripting. + ==== weechat_hashtable_get_integer _WeeChat ≥ 0.3.3._ diff --git a/doc/ja/weechat.1.ja.txt b/doc/ja/weechat.1.ja.txt index 3262fb3bc..bf58b144c 100644 --- a/doc/ja/weechat.1.ja.txt +++ b/doc/ja/weechat.1.ja.txt @@ -75,6 +75,9 @@ $HOME/.weechat/rmodifier.conf:: $HOME/.weechat/script.conf:: 'script' プラグイン用の設定ファイル +$HOME/.weechat/trigger.conf:: + 'trigger' プラグイン用の設定ファイル + $HOME/.weechat/xfer.conf:: 'xfer' プラグイン用の設定ファイル diff --git a/doc/ja/weechat_dev.ja.txt b/doc/ja/weechat_dev.ja.txt index ef6b02932..d587eebb3 100644 --- a/doc/ja/weechat_dev.ja.txt +++ b/doc/ja/weechat_dev.ja.txt @@ -66,6 +66,8 @@ WeeChat の主要なリポジトリは 2 つあります: | lua/ | lua スクリプト用 API | tcl/ | tcl スクリプト用 API | guile/ | guile (scheme) スクリプト用 API +// TRANSLATION MISSING +| trigger/ | Trigger plugin | xfer/ | xfer (IRC DCC ファイル/チャット) | doc/ | 文書 | po/ | 翻訳ファイル (gettext) @@ -260,6 +262,14 @@ WeeChat "core" は以下のディレクトリに配置されています: | tcl/ | tcl プラグイン | weechat-tcl.c | tcl の主要関数 (スクリプトのロード/アンロード、tcl コードの実行) | weechat-tcl-api.c | tcl スクリプト作成 API 関数 +// TRANSLATION MISSING +| trigger/ | Trigger plugin +| trigger.c | Main trigger functions +| trigger-buffer.c | Trigger buffer +| trigger-callback.c | Trigger callbacks +| trigger-command.c | Trigger commands +| trigger-completion.c | Trigger completions +| trigger-config.c | Trigger config options (file trigger.conf) | xfer/ | xfer プラグイン (IRC DCC ファイル/チャット) | xfer.c | xfer の主要関数 | xfer-buffer.c | xfer バッファ diff --git a/doc/ja/weechat_plugin_api.ja.txt b/doc/ja/weechat_plugin_api.ja.txt index 7ee834c59..773c94a84 100644 --- a/doc/ja/weechat_plugin_api.ja.txt +++ b/doc/ja/weechat_plugin_api.ja.txt @@ -853,41 +853,6 @@ match3 = weechat.string_match("abcdef", "*def", 0) # 1 match4 = weechat.string_match("abcdef", "*de*", 0) # 1 ---- -==== weechat_string_replace - -マッチした全ての文字列を別の文字列で置換。 - -プロトタイプ: - -[source,C] ----- -char *weechat_string_replace (const char *string, const char *search, - const char *replace); ----- - -引数: - -* 'string': 文字列 -* 'search': マッチさせる文字列 -* 'replace': 'search' を置き換える文字列 - -戻り値: - -* 'search' を 'replace' で置き換えた文字列 - (使用後には必ず "free" を呼び出して領域を開放してください) - -C 言語での使用例: - -[source,C] ----- -char *str = weechat_string_replace ("test", "s", "x"); /* result: "text" */ -/* ... */ -free (str); ----- - -[NOTE] -スクリプト API ではこの関数を利用できません。 - ==== weechat_string_expand_home _WeeChat バージョン 0.3.3 以上で利用可。_ @@ -994,6 +959,58 @@ free (str); [NOTE] スクリプト API ではこの関数を利用できません。 +==== weechat_string_convert_escaped_chars + +_WeeChat バージョン 0.4.4 以上で利用可。_ + +// TRANSLATION MISSING +Convert escaped chars to their value: + +* `\"`: double quote +* `\\`: backslash +* `\a`: alert (BEL) +* `\b`: backspace +* `\e`: escape +* `\f`: form feed +* `\n`: new line +* `\r`: carriage return +* `\t`: horizontal tab +* `\v`: vertical tab +* `\0ooo`: char as octal value (ooo is 0 to 3 digits) +* `\xhh`: char as hexadecimal value (hh is 1 to 2 digits) +* `\uhhhh`: unicode char as hexadecimal value (hhhh is 1 to 4 digits) +* `\Uhhhhhhhh`: unicode char as hexadecimal value (hhhhhhhh is 1 to 8 digits) + +プロトタイプ: + +[source,C] +---- +char *weechat_string_convert_escaped_chars (const char *string); +---- + +引数: + +* 'string': 文字列 + +戻り値: + +// TRANSLATION MISSING +* string with escaped chars replaced by their value + (使用後には必ず "free" を呼び出して領域を開放してください) + +C 言語での使用例: + +[source,C] +---- +char *str = weechat_string_convert_escaped_chars ("snowman: \\u2603"); +/* str == "snowman: ☃" */ +/* ... */ +free (str); +---- + +[NOTE] +スクリプト API ではこの関数を利用できません。 + ==== weechat_string_mask_to_regex マスクから正規表現を作りこれを返す、マスク用の特殊文字は @@ -1212,6 +1229,98 @@ highlight = weechat.string_has_highlight_regex(string, regex) highlight = weechat.string_has_highlight_regex("my test string", "test|word2") # 1 ---- +==== weechat_string_replace + +マッチした全ての文字列を別の文字列で置換。 + +プロトタイプ: + +[source,C] +---- +char *weechat_string_replace (const char *string, const char *search, + const char *replace); +---- + +引数: + +* 'string': 文字列 +* 'search': マッチさせる文字列 +* 'replace': 'search' を置き換える文字列 + +戻り値: + +* 'search' を 'replace' で置き換えた文字列 + (使用後には必ず "free" を呼び出して領域を開放してください) + +C 言語での使用例: + +[source,C] +---- +char *str = weechat_string_replace ("test", "s", "x"); /* result: "text" */ +/* ... */ +free (str); +---- + +[NOTE] +スクリプト API ではこの関数を利用できません。 + +==== weechat_string_replace_regex + +_WeeChat バージョン 0.4.4 以上で利用可。_ + +// TRANSLATION MISSING +Replace text in a string using a regular expression and replacement text. + +プロトタイプ: + +[source,C] +---- +char *weechat_string_replace_regex (const char *string, void *regex, + const char *replace, const char reference_char); +---- + +引数: + +// TRANSLATION MISSING +* 'string': string +* 'regex': pointer to a regular expression ('regex_t' structure) compiled with + WeeChat function <<_weechat_string_regcomp,weechat_string_regcomp>> or regcomp + (see `man regcomp`) +* 'replace': replacement text, where following references are allowed: +** `$0` to `$99`: match 0 to 99 in regular expression (0 is the whole match, + 1 to 99 are groups captured between parentheses) +** `$+`: the last match (with highest number) +** `$.*N`: match `N` (can be `+` or `0` to `99`), with all chars replaced by `*` + (the `*` char can be any char between space (32) and `~` (126)) +* 'reference_char': the char used for reference to match (commonly '$') + +戻り値: + +// TRANSLATION MISSING +* string with text replaced, NULL if problem (must be freed by calling "free" + after use) + +C 言語での使用例: + +[source,C] +---- +regex_t my_regex; +char *string; +if (weechat_string_regcomp (&my_regex, "([0-9]{4})-([0-9]{2})-([0-9]{2})", + REG_EXTENDED) == 0) +{ + string = weechat_string_replace_regex ("date: 2014-02-14", &my_regex, + "$3/$2/$1", '$'); + /* string == "date: 14/02/2014" */ + if (string) + free (string); + regfree (&my_regex); +} +---- + +[NOTE] +スクリプト API ではこの関数を利用できません。 + ==== weechat_string_split 1 つ以上の区切り文字に従って文字列を分割。 @@ -1270,6 +1379,53 @@ weechat_string_free_split (argv); [NOTE] スクリプト API ではこの関数を利用できません。 +==== weechat_string_split_shell + +_WeeChat バージョン 0.4.4 以上で利用可。_ + +// TRANSLATION MISSING +Split a string like the shell does for a command with arguments. + +// TRANSLATION MISSING +This function is a C conversion of Python class "shlex" (file: Lib/shlex.py in +Python repository), see: http://docs.python.org/3/library/shlex.html. + +プロトタイプ: + +[source,C] +---- +char **weechat_string_split_shell (const char *string, int *num_items); +---- + +引数: + +* 'string': 分割する文字列 +* 'num_items': 分割回数を返す整数型変数へのポインタ + +戻り値: + +* 文字列の配列、分割に失敗した場合は NULL (使用後には必ず + <<_weechat_string_free_split,weechat_string_free_split>> を呼び出して領域を開放してください) + +C 言語での使用例: + +[source,C] +---- +char **argv; +int argc; +argv = weechat_string_split_shell ("test 'first arg' \"second arg\"", &argc); +/* result: argv[0] == "test" + argv[1] == "first arg" + argv[2] == "second arg" + argv[3] == NULL + argc == 3 +*/ +weechat_string_free_split (argv); +---- + +[NOTE] +スクリプト API ではこの関数を利用できません。 + ==== weechat_string_free_split 文字列分割に使用したメモリを開放。 @@ -3477,6 +3633,39 @@ weechat_hashtable_map_string (hashtable, &map_cb, NULL); [NOTE] スクリプト API ではこの関数を利用できません。 +==== weechat_hashtable_dup + +_WeeChat バージョン 0.4.4 以上で利用可。_ + +// TRANSLATION MISSING +Duplicate a hashtable. + +プロトタイプ: + +[source,C] +---- +struct t_hashtable *hashtable_dup (struct t_hashtable *hashtable); +---- + +引数: + +* 'hashtable': ハッシュテーブルへのポインタ + +戻り値: + +// TRANSLATION MISSING +* duplicated hashtable + +C 言語での使用例: + +[source,C] +---- +struct t_hashtable *new_hashtable = weechat_hashtable_dup (hashtable); +---- + +[NOTE] +スクリプト API ではこの関数を利用できません。 + ==== weechat_hashtable_get_integer _WeeChat バージョン 0.3.3 以上で利用可。_ diff --git a/doc/pl/weechat.1.pl.txt b/doc/pl/weechat.1.pl.txt index 59e47c8c3..63fa8f553 100644 --- a/doc/pl/weechat.1.pl.txt +++ b/doc/pl/weechat.1.pl.txt @@ -76,6 +76,9 @@ $HOME/.weechat/rmodifier.conf:: $HOME/.weechat/script.conf:: plik konfiguracyjny wtyczki 'script' +$HOME/.weechat/trigger.conf:: + plik konfiguracyjny wtyczki 'trigger' + $HOME/.weechat/xfer.conf:: plik konfiguracyjny wtyczki 'xfer' diff --git a/po/POTFILES.in b/po/POTFILES.in index 7ef0678f8..ab669ac08 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,3 +1,4 @@ +./doc/docgen.py ./src/core/wee-backtrace.c ./src/core/wee-backtrace.h ./src/core/weechat.c @@ -33,9 +34,9 @@ ./src/core/wee-string.c ./src/core/wee-string.h ./src/core/wee-upgrade.c -./src/core/wee-upgrade.h ./src/core/wee-upgrade-file.c ./src/core/wee-upgrade-file.h +./src/core/wee-upgrade.h ./src/core/wee-url.c ./src/core/wee-url.h ./src/core/wee-utf8.c @@ -64,12 +65,10 @@ ./src/gui/gui-chat.h ./src/gui/gui-color.c ./src/gui/gui-color.h -./src/gui/gui-cursor.c -./src/gui/gui-cursor.h -./src/gui/gui-mouse.c -./src/gui/gui-mouse.h ./src/gui/gui-completion.c ./src/gui/gui-completion.h +./src/gui/gui-cursor.c +./src/gui/gui-cursor.h ./src/gui/gui-filter.c ./src/gui/gui-filter.h ./src/gui/gui-focus.c @@ -87,26 +86,28 @@ ./src/gui/gui-line.c ./src/gui/gui-line.h ./src/gui/gui-main.h +./src/gui/gui-mouse.c +./src/gui/gui-mouse.h ./src/gui/gui-nicklist.c ./src/gui/gui-nicklist.h ./src/gui/gui-window.c ./src/gui/gui-window.h ./src/plugins/alias/alias.c -./src/plugins/alias/alias.h ./src/plugins/alias/alias-config.c ./src/plugins/alias/alias-config.h +./src/plugins/alias/alias.h ./src/plugins/alias/alias-info.c ./src/plugins/alias/alias-info.h -./src/plugins/aspell/weechat-aspell.c -./src/plugins/aspell/weechat-aspell.h ./src/plugins/aspell/weechat-aspell-bar-item.c ./src/plugins/aspell/weechat-aspell-bar-item.h +./src/plugins/aspell/weechat-aspell.c ./src/plugins/aspell/weechat-aspell-command.c ./src/plugins/aspell/weechat-aspell-command.h ./src/plugins/aspell/weechat-aspell-completion.c ./src/plugins/aspell/weechat-aspell-completion.h ./src/plugins/aspell/weechat-aspell-config.c ./src/plugins/aspell/weechat-aspell-config.h +./src/plugins/aspell/weechat-aspell.h ./src/plugins/aspell/weechat-aspell-info.c ./src/plugins/aspell/weechat-aspell-info.h ./src/plugins/aspell/weechat-aspell-speller.c @@ -166,12 +167,12 @@ ./src/plugins/irc/irc-sasl.h ./src/plugins/irc/irc-server.c ./src/plugins/irc/irc-server.h -./src/plugins/logger/logger.c -./src/plugins/logger/logger.h ./src/plugins/logger/logger-buffer.c ./src/plugins/logger/logger-buffer.h +./src/plugins/logger/logger.c ./src/plugins/logger/logger-config.c ./src/plugins/logger/logger-config.h +./src/plugins/logger/logger.h ./src/plugins/logger/logger-info.c ./src/plugins/logger/logger-info.h ./src/plugins/logger/logger-tail.c @@ -180,12 +181,28 @@ ./src/plugins/lua/weechat-lua-api.h ./src/plugins/lua/weechat-lua.c ./src/plugins/lua/weechat-lua.h +./src/plugins/perl/weechat-perl-api.c +./src/plugins/perl/weechat-perl-api.h +./src/plugins/perl/weechat-perl.c +./src/plugins/perl/weechat-perl.h ./src/plugins/plugin-api.c ./src/plugins/plugin-api.h ./src/plugins/plugin.c ./src/plugins/plugin-config.c ./src/plugins/plugin-config.h ./src/plugins/plugin.h +./src/plugins/plugin-script-api.c +./src/plugins/plugin-script-api.h +./src/plugins/plugin-script.c +./src/plugins/plugin-script-callback.c +./src/plugins/plugin-script-callback.h +./src/plugins/plugin-script.h +./src/plugins/python/weechat-python-api.c +./src/plugins/python/weechat-python-api.h +./src/plugins/python/weechat-python.c +./src/plugins/python/weechat-python.h +./src/plugins/relay/irc/relay-irc.c +./src/plugins/relay/irc/relay-irc.h ./src/plugins/relay/relay-buffer.c ./src/plugins/relay/relay-buffer.h ./src/plugins/relay/relay.c @@ -210,8 +227,6 @@ ./src/plugins/relay/relay-upgrade.h ./src/plugins/relay/relay-websocket.c ./src/plugins/relay/relay-websocket.h -./src/plugins/relay/irc/relay-irc.c -./src/plugins/relay/irc/relay-irc.h ./src/plugins/relay/weechat/relay-weechat.c ./src/plugins/relay/weechat/relay-weechat.h ./src/plugins/relay/weechat/relay-weechat-msg.c @@ -232,36 +247,22 @@ ./src/plugins/rmodifier/rmodifier.h ./src/plugins/rmodifier/rmodifier-info.c ./src/plugins/rmodifier/rmodifier-info.h -./src/plugins/perl/weechat-perl-api.c -./src/plugins/perl/weechat-perl-api.h -./src/plugins/perl/weechat-perl.c -./src/plugins/perl/weechat-perl.h -./src/plugins/plugin-script.c -./src/plugins/plugin-script.h -./src/plugins/plugin-script-api.c -./src/plugins/plugin-script-api.h -./src/plugins/plugin-script-callback.c -./src/plugins/plugin-script-callback.h -./src/plugins/python/weechat-python-api.c -./src/plugins/python/weechat-python-api.h -./src/plugins/python/weechat-python.c -./src/plugins/python/weechat-python.h ./src/plugins/ruby/weechat-ruby-api.c ./src/plugins/ruby/weechat-ruby-api.h ./src/plugins/ruby/weechat-ruby.c ./src/plugins/ruby/weechat-ruby.h -./src/plugins/script/script.c -./src/plugins/script/script.h ./src/plugins/script/script-action.c ./src/plugins/script/script-action.h ./src/plugins/script/script-buffer.c ./src/plugins/script/script-buffer.h +./src/plugins/script/script.c ./src/plugins/script/script-command.c ./src/plugins/script/script-command.h ./src/plugins/script/script-completion.c ./src/plugins/script/script-completion.h ./src/plugins/script/script-config.c ./src/plugins/script/script-config.h +./src/plugins/script/script.h ./src/plugins/script/script-info.c ./src/plugins/script/script-info.h ./src/plugins/script/script-repo.c @@ -270,6 +271,18 @@ ./src/plugins/tcl/weechat-tcl-api.h ./src/plugins/tcl/weechat-tcl.c ./src/plugins/tcl/weechat-tcl.h +./src/plugins/trigger/trigger.c +./src/plugins/trigger/trigger-buffer.c +./src/plugins/trigger/trigger-buffer.h +./src/plugins/trigger/trigger-callback.c +./src/plugins/trigger/trigger-callback.h +./src/plugins/trigger/trigger-command.c +./src/plugins/trigger/trigger-command.h +./src/plugins/trigger/trigger-completion.c +./src/plugins/trigger/trigger-completion.h +./src/plugins/trigger/trigger-config.c +./src/plugins/trigger/trigger-config.h +./src/plugins/trigger/trigger.h ./src/plugins/weechat-plugin.h ./src/plugins/xfer/xfer-buffer.c ./src/plugins/xfer/xfer-buffer.h @@ -286,11 +299,10 @@ ./src/plugins/xfer/xfer-dcc.h ./src/plugins/xfer/xfer-file.c ./src/plugins/xfer/xfer-file.h +./src/plugins/xfer/xfer.h ./src/plugins/xfer/xfer-info.c ./src/plugins/xfer/xfer-info.h -./src/plugins/xfer/xfer.h ./src/plugins/xfer/xfer-network.c ./src/plugins/xfer/xfer-network.h ./src/plugins/xfer/xfer-upgrade.c ./src/plugins/xfer/xfer-upgrade.h -./doc/docgen.py diff --git a/po/srcfiles.cmake b/po/srcfiles.cmake index d4af8b1ac..de4d5c2f9 100644 --- a/po/srcfiles.cmake +++ b/po/srcfiles.cmake @@ -1,4 +1,5 @@ SET(WEECHAT_SOURCES +./doc/docgen.py ./src/core/wee-backtrace.c ./src/core/wee-backtrace.h ./src/core/weechat.c @@ -34,9 +35,9 @@ SET(WEECHAT_SOURCES ./src/core/wee-string.c ./src/core/wee-string.h ./src/core/wee-upgrade.c -./src/core/wee-upgrade.h ./src/core/wee-upgrade-file.c ./src/core/wee-upgrade-file.h +./src/core/wee-upgrade.h ./src/core/wee-url.c ./src/core/wee-url.h ./src/core/wee-utf8.c @@ -65,10 +66,10 @@ SET(WEECHAT_SOURCES ./src/gui/gui-chat.h ./src/gui/gui-color.c ./src/gui/gui-color.h -./src/gui/gui-cursor.c -./src/gui/gui-cursor.h ./src/gui/gui-completion.c ./src/gui/gui-completion.h +./src/gui/gui-cursor.c +./src/gui/gui-cursor.h ./src/gui/gui-filter.c ./src/gui/gui-filter.h ./src/gui/gui-focus.c @@ -93,21 +94,21 @@ SET(WEECHAT_SOURCES ./src/gui/gui-window.c ./src/gui/gui-window.h ./src/plugins/alias/alias.c -./src/plugins/alias/alias.h ./src/plugins/alias/alias-config.c ./src/plugins/alias/alias-config.h +./src/plugins/alias/alias.h ./src/plugins/alias/alias-info.c ./src/plugins/alias/alias-info.h -./src/plugins/aspell/weechat-aspell.c -./src/plugins/aspell/weechat-aspell.h ./src/plugins/aspell/weechat-aspell-bar-item.c ./src/plugins/aspell/weechat-aspell-bar-item.h +./src/plugins/aspell/weechat-aspell.c ./src/plugins/aspell/weechat-aspell-command.c ./src/plugins/aspell/weechat-aspell-command.h ./src/plugins/aspell/weechat-aspell-completion.c ./src/plugins/aspell/weechat-aspell-completion.h ./src/plugins/aspell/weechat-aspell-config.c ./src/plugins/aspell/weechat-aspell-config.h +./src/plugins/aspell/weechat-aspell.h ./src/plugins/aspell/weechat-aspell-info.c ./src/plugins/aspell/weechat-aspell-info.h ./src/plugins/aspell/weechat-aspell-speller.c @@ -117,6 +118,10 @@ SET(WEECHAT_SOURCES ./src/plugins/fifo/fifo.h ./src/plugins/fifo/fifo-info.c ./src/plugins/fifo/fifo-info.h +./src/plugins/guile/weechat-guile-api.c +./src/plugins/guile/weechat-guile-api.h +./src/plugins/guile/weechat-guile.c +./src/plugins/guile/weechat-guile.h ./src/plugins/irc/irc-bar-item.c ./src/plugins/irc/irc-bar-item.h ./src/plugins/irc/irc-buffer.c @@ -163,22 +168,42 @@ SET(WEECHAT_SOURCES ./src/plugins/irc/irc-sasl.h ./src/plugins/irc/irc-server.c ./src/plugins/irc/irc-server.h -./src/plugins/logger/logger.c -./src/plugins/logger/logger.h ./src/plugins/logger/logger-buffer.c ./src/plugins/logger/logger-buffer.h +./src/plugins/logger/logger.c ./src/plugins/logger/logger-config.c ./src/plugins/logger/logger-config.h +./src/plugins/logger/logger.h ./src/plugins/logger/logger-info.c ./src/plugins/logger/logger-info.h ./src/plugins/logger/logger-tail.c ./src/plugins/logger/logger-tail.h +./src/plugins/lua/weechat-lua-api.c +./src/plugins/lua/weechat-lua-api.h +./src/plugins/lua/weechat-lua.c +./src/plugins/lua/weechat-lua.h +./src/plugins/perl/weechat-perl-api.c +./src/plugins/perl/weechat-perl-api.h +./src/plugins/perl/weechat-perl.c +./src/plugins/perl/weechat-perl.h ./src/plugins/plugin-api.c ./src/plugins/plugin-api.h ./src/plugins/plugin.c ./src/plugins/plugin-config.c ./src/plugins/plugin-config.h ./src/plugins/plugin.h +./src/plugins/plugin-script-api.c +./src/plugins/plugin-script-api.h +./src/plugins/plugin-script.c +./src/plugins/plugin-script-callback.c +./src/plugins/plugin-script-callback.h +./src/plugins/plugin-script.h +./src/plugins/python/weechat-python-api.c +./src/plugins/python/weechat-python-api.h +./src/plugins/python/weechat-python.c +./src/plugins/python/weechat-python.h +./src/plugins/relay/irc/relay-irc.c +./src/plugins/relay/irc/relay-irc.h ./src/plugins/relay/relay-buffer.c ./src/plugins/relay/relay-buffer.h ./src/plugins/relay/relay.c @@ -203,8 +228,6 @@ SET(WEECHAT_SOURCES ./src/plugins/relay/relay-upgrade.h ./src/plugins/relay/relay-websocket.c ./src/plugins/relay/relay-websocket.h -./src/plugins/relay/irc/relay-irc.c -./src/plugins/relay/irc/relay-irc.h ./src/plugins/relay/weechat/relay-weechat.c ./src/plugins/relay/weechat/relay-weechat.h ./src/plugins/relay/weechat/relay-weechat-msg.c @@ -225,44 +248,22 @@ SET(WEECHAT_SOURCES ./src/plugins/rmodifier/rmodifier.h ./src/plugins/rmodifier/rmodifier-info.c ./src/plugins/rmodifier/rmodifier-info.h -./src/plugins/guile/weechat-guile-api.c -./src/plugins/guile/weechat-guile-api.h -./src/plugins/guile/weechat-guile.c -./src/plugins/guile/weechat-guile.h -./src/plugins/lua/weechat-lua-api.c -./src/plugins/lua/weechat-lua-api.h -./src/plugins/lua/weechat-lua.c -./src/plugins/lua/weechat-lua.h -./src/plugins/perl/weechat-perl-api.c -./src/plugins/perl/weechat-perl-api.h -./src/plugins/perl/weechat-perl.c -./src/plugins/perl/weechat-perl.h -./src/plugins/plugin-script.c -./src/plugins/plugin-script.h -./src/plugins/plugin-script-api.c -./src/plugins/plugin-script-api.h -./src/plugins/plugin-script-callback.c -./src/plugins/plugin-script-callback.h -./src/plugins/python/weechat-python-api.c -./src/plugins/python/weechat-python-api.h -./src/plugins/python/weechat-python.c -./src/plugins/python/weechat-python.h ./src/plugins/ruby/weechat-ruby-api.c ./src/plugins/ruby/weechat-ruby-api.h ./src/plugins/ruby/weechat-ruby.c ./src/plugins/ruby/weechat-ruby.h -./src/plugins/script/script.c -./src/plugins/script/script.h ./src/plugins/script/script-action.c ./src/plugins/script/script-action.h ./src/plugins/script/script-buffer.c ./src/plugins/script/script-buffer.h +./src/plugins/script/script.c ./src/plugins/script/script-command.c ./src/plugins/script/script-command.h ./src/plugins/script/script-completion.c ./src/plugins/script/script-completion.h ./src/plugins/script/script-config.c ./src/plugins/script/script-config.h +./src/plugins/script/script.h ./src/plugins/script/script-info.c ./src/plugins/script/script-info.h ./src/plugins/script/script-repo.c @@ -271,6 +272,18 @@ SET(WEECHAT_SOURCES ./src/plugins/tcl/weechat-tcl-api.h ./src/plugins/tcl/weechat-tcl.c ./src/plugins/tcl/weechat-tcl.h +./src/plugins/trigger/trigger.c +./src/plugins/trigger/trigger-buffer.c +./src/plugins/trigger/trigger-buffer.h +./src/plugins/trigger/trigger-callback.c +./src/plugins/trigger/trigger-callback.h +./src/plugins/trigger/trigger-command.c +./src/plugins/trigger/trigger-command.h +./src/plugins/trigger/trigger-completion.c +./src/plugins/trigger/trigger-completion.h +./src/plugins/trigger/trigger-config.c +./src/plugins/trigger/trigger-config.h +./src/plugins/trigger/trigger.h ./src/plugins/weechat-plugin.h ./src/plugins/xfer/xfer-buffer.c ./src/plugins/xfer/xfer-buffer.h @@ -287,12 +300,11 @@ SET(WEECHAT_SOURCES ./src/plugins/xfer/xfer-dcc.h ./src/plugins/xfer/xfer-file.c ./src/plugins/xfer/xfer-file.h +./src/plugins/xfer/xfer.h ./src/plugins/xfer/xfer-info.c ./src/plugins/xfer/xfer-info.h -./src/plugins/xfer/xfer.h ./src/plugins/xfer/xfer-network.c ./src/plugins/xfer/xfer-network.h ./src/plugins/xfer/xfer-upgrade.c ./src/plugins/xfer/xfer-upgrade.h -./doc/docgen.py ) diff --git a/src/core/wee-command.c b/src/core/wee-command.c index 06374015b..a6ea87d44 100644 --- a/src/core/wee-command.c +++ b/src/core/wee-command.c @@ -5043,13 +5043,14 @@ command_set_display_section (struct t_config_file *config_file, struct t_config_section *section) { gui_chat_printf (NULL, ""); - gui_chat_printf (NULL, "%s[%s%s%s]%s (%s)", - GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), - GUI_COLOR(GUI_COLOR_CHAT_BUFFER), - section->name, - GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), - GUI_COLOR(GUI_COLOR_CHAT), - config_file->filename); + gui_chat_printf_date_tags (NULL, 0, "no_trigger", + "%s[%s%s%s]%s (%s)", + GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), + GUI_COLOR(GUI_COLOR_CHAT_BUFFER), + section->name, + GUI_COLOR(GUI_COLOR_CHAT_DELIMITERS), + GUI_COLOR(GUI_COLOR_CHAT), + config_file->filename); } /* @@ -5086,7 +5087,8 @@ command_set_display_option (struct t_config_option *option, (CONFIG_BOOLEAN_DEFAULT(option)) ? "on" : "off"); display_default = str_default; } - gui_chat_printf_date_tags (NULL, 0, GUI_CHAT_TAG_NO_HIGHLIGHT, + gui_chat_printf_date_tags (NULL, 0, + "no_trigger," GUI_CHAT_TAG_NO_HIGHLIGHT, "%s%s.%s.%s%s = %s%s%s%s%s%s%s%s%s%s", (message) ? message : " ", option->config_file->name, @@ -5121,7 +5123,8 @@ command_set_display_option (struct t_config_option *option, } if (option->string_values) { - gui_chat_printf_date_tags (NULL, 0, GUI_CHAT_TAG_NO_HIGHLIGHT, + gui_chat_printf_date_tags (NULL, 0, + "no_trigger," GUI_CHAT_TAG_NO_HIGHLIGHT, "%s%s.%s.%s%s = %s%s%s%s%s%s%s%s%s%s", (message) ? message : " ", option->config_file->name, @@ -5141,7 +5144,8 @@ command_set_display_option (struct t_config_option *option, } else { - gui_chat_printf_date_tags (NULL, 0, GUI_CHAT_TAG_NO_HIGHLIGHT, + gui_chat_printf_date_tags (NULL, 0, + "no_trigger," GUI_CHAT_TAG_NO_HIGHLIGHT, "%s%s.%s.%s%s = %s%d%s%s%s%s%s%s%s%s", (message) ? message : " ", option->config_file->name, @@ -5166,7 +5170,8 @@ command_set_display_option (struct t_config_option *option, { display_default = CONFIG_STRING_DEFAULT(option); } - gui_chat_printf_date_tags (NULL, 0, GUI_CHAT_TAG_NO_HIGHLIGHT, + gui_chat_printf_date_tags (NULL, 0, + "no_trigger," GUI_CHAT_TAG_NO_HIGHLIGHT, "%s%s.%s.%s%s = \"%s%s%s\"%s%s%s%s%s%s%s%s%s%s%s", (message) ? message : " ", option->config_file->name, @@ -5199,7 +5204,8 @@ command_set_display_option (struct t_config_option *option, } } color_name = gui_color_get_name (CONFIG_COLOR(option)); - gui_chat_printf_date_tags (NULL, 0, GUI_CHAT_TAG_NO_HIGHLIGHT, + gui_chat_printf_date_tags (NULL, 0, + "no_trigger," GUI_CHAT_TAG_NO_HIGHLIGHT, "%s%s.%s.%s%s = %s%s%s%s%s%s%s%s%s%s", (message) ? message : " ", option->config_file->name, @@ -5224,7 +5230,8 @@ command_set_display_option (struct t_config_option *option, } else { - gui_chat_printf_date_tags (NULL, 0, GUI_CHAT_TAG_NO_HIGHLIGHT, + gui_chat_printf_date_tags (NULL, 0, + "no_trigger," GUI_CHAT_TAG_NO_HIGHLIGHT, "%s%s.%s.%s", (message) ? message : " ", option->config_file->name, diff --git a/src/core/wee-config.c b/src/core/wee-config.c index 73f435694..c7187d980 100644 --- a/src/core/wee-config.c +++ b/src/core/wee-config.c @@ -1311,66 +1311,64 @@ config_weechat_proxy_read_cb (void *data, struct t_config_file *config_file, /* make C compiler happy */ (void) data; (void) config_file; - (void) section; - if (option_name) + if (!option_name) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + pos_option = strchr (option_name, '.'); + if (!pos_option) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + proxy_name = string_strndup (option_name, pos_option - option_name); + if (!proxy_name) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + pos_option++; + + /* search temporary proxy */ + for (ptr_temp_proxy = weechat_temp_proxies; ptr_temp_proxy; + ptr_temp_proxy = ptr_temp_proxy->next_proxy) + { + if (strcmp (ptr_temp_proxy->name, proxy_name) == 0) + break; + } + if (!ptr_temp_proxy) { - pos_option = strchr (option_name, '.'); - if (pos_option) + /* create new temporary proxy */ + ptr_temp_proxy = proxy_alloc (proxy_name); + if (ptr_temp_proxy) { - proxy_name = string_strndup (option_name, pos_option - option_name); - if (proxy_name) - { - pos_option++; - for (ptr_temp_proxy = weechat_temp_proxies; ptr_temp_proxy; - ptr_temp_proxy = ptr_temp_proxy->next_proxy) - { - if (strcmp (ptr_temp_proxy->name, proxy_name) == 0) - break; - } - if (!ptr_temp_proxy) - { - /* create new temp proxy */ - ptr_temp_proxy = proxy_alloc (proxy_name); - if (ptr_temp_proxy) - { - /* add new temp proxy at end of queue */ - ptr_temp_proxy->prev_proxy = last_weechat_temp_proxy; - ptr_temp_proxy->next_proxy = NULL; - - if (!weechat_temp_proxies) - weechat_temp_proxies = ptr_temp_proxy; - else - last_weechat_temp_proxy->next_proxy = ptr_temp_proxy; - last_weechat_temp_proxy = ptr_temp_proxy; - } - } - - if (ptr_temp_proxy) - { - index_option = proxy_search_option (pos_option); - if (index_option >= 0) - { - proxy_create_option_temp (ptr_temp_proxy, index_option, - value); - } - else - { - gui_chat_printf (NULL, - _("%sWarning: unknown option for " - "section \"%s\": %s (value: \"%s\")"), - gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], - section->name, - option_name, - value); - } - } + /* add new proxy at the end */ + ptr_temp_proxy->prev_proxy = last_weechat_temp_proxy; + ptr_temp_proxy->next_proxy = NULL; + if (!weechat_temp_proxies) + weechat_temp_proxies = ptr_temp_proxy; + else + last_weechat_temp_proxy->next_proxy = ptr_temp_proxy; + last_weechat_temp_proxy = ptr_temp_proxy; + } + } - free (proxy_name); - } + if (ptr_temp_proxy) + { + index_option = proxy_search_option (pos_option); + if (index_option >= 0) + { + proxy_create_option_temp (ptr_temp_proxy, index_option, + value); + } + else + { + gui_chat_printf (NULL, + _("%sWarning: unknown option for section \"%s\": " + "%s (value: \"%s\")"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + section->name, option_name, value); } } + free (proxy_name); + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; } @@ -1392,64 +1390,63 @@ config_weechat_bar_read_cb (void *data, struct t_config_file *config_file, (void) config_file; (void) section; - if (option_name) + if (!option_name) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + pos_option = strchr (option_name, '.'); + if (!pos_option) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + bar_name = string_strndup (option_name, pos_option - option_name); + if (!bar_name) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + pos_option++; + + /* search temporary bar */ + for (ptr_temp_bar = gui_temp_bars; ptr_temp_bar; + ptr_temp_bar = ptr_temp_bar->next_bar) + { + if (strcmp (ptr_temp_bar->name, bar_name) == 0) + break; + } + if (!ptr_temp_bar) { - pos_option = strchr (option_name, '.'); - if (pos_option) + /* create new temporary bar */ + ptr_temp_bar = gui_bar_alloc (bar_name); + if (ptr_temp_bar) { - bar_name = string_strndup (option_name, pos_option - option_name); - if (bar_name) - { - pos_option++; - for (ptr_temp_bar = gui_temp_bars; ptr_temp_bar; - ptr_temp_bar = ptr_temp_bar->next_bar) - { - if (strcmp (ptr_temp_bar->name, bar_name) == 0) - break; - } - if (!ptr_temp_bar) - { - /* create new temp bar */ - ptr_temp_bar = gui_bar_alloc (bar_name); - if (ptr_temp_bar) - { - /* add new temp bar at end of queue */ - ptr_temp_bar->prev_bar = last_gui_temp_bar; - ptr_temp_bar->next_bar = NULL; - - if (!gui_temp_bars) - gui_temp_bars = ptr_temp_bar; - else - last_gui_temp_bar->next_bar = ptr_temp_bar; - last_gui_temp_bar = ptr_temp_bar; - } - } - - if (ptr_temp_bar) - { - index_option = gui_bar_search_option (pos_option); - if (index_option >= 0) - { - gui_bar_create_option_temp (ptr_temp_bar, index_option, - value); - } - else - { - gui_chat_printf (NULL, - _("%sWarning: unknown option for " - "section \"%s\": %s (value: \"%s\")"), - gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], - section->name, - option_name, - value); - } - } + /* add new bar at the end */ + ptr_temp_bar->prev_bar = last_gui_temp_bar; + ptr_temp_bar->next_bar = NULL; + if (!gui_temp_bars) + gui_temp_bars = ptr_temp_bar; + else + last_gui_temp_bar->next_bar = ptr_temp_bar; + last_gui_temp_bar = ptr_temp_bar; + } + } - free (bar_name); - } + if (ptr_temp_bar) + { + index_option = gui_bar_search_option (pos_option); + if (index_option >= 0) + { + gui_bar_create_option_temp (ptr_temp_bar, index_option, + value); + } + else + { + gui_chat_printf (NULL, + _("%sWarning: unknown option for section \"%s\": " + "%s (value: \"%s\")"), + gui_chat_prefix[GUI_CHAT_PREFIX_ERROR], + section->name, option_name, value); } } + free (bar_name); + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; } diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c index 64ee97f75..04c2affef 100644 --- a/src/core/wee-hook.c +++ b/src/core/wee-hook.c @@ -482,7 +482,7 @@ hook_command_build_completion (struct t_hook_command *hook_command) { /* * build static part of template: it's first argument(s) which does not - * contain "%" or "|" + * contain "%" */ last_space = NULL; ptr_template = hook_command->cplt_templates[i]; @@ -493,7 +493,7 @@ hook_command_build_completion (struct t_hook_command *hook_command) last_space = ptr_template; break; } - else if ((ptr_template[0] == '%') || (ptr_template[0] == '|')) + else if (ptr_template[0] == '%') break; ptr_template = utf8_next_char (ptr_template); } @@ -1542,7 +1542,8 @@ hook_process_child (struct t_hook *hook_process) * if no arguments were found in hashtable, make an automatic split * of command, like the shell does */ - exec_args = string_split_shell (HOOK_PROCESS(hook_process, command)); + exec_args = string_split_shell (HOOK_PROCESS(hook_process, command), + NULL); } if (exec_args) diff --git a/src/core/wee-proxy.c b/src/core/wee-proxy.c index 7fc81ccf8..08b6190a4 100644 --- a/src/core/wee-proxy.c +++ b/src/core/wee-proxy.c @@ -294,69 +294,70 @@ proxy_create_option (const char *proxy_name, int index_option, length = strlen (proxy_name) + 1 + strlen (proxy_option_string[index_option]) + 1; option_name = malloc (length); - if (option_name) - { - snprintf (option_name, length, "%s.%s", - proxy_name, proxy_option_string[index_option]); + if (!option_name) + return NULL; - switch (index_option) - { - case PROXY_OPTION_TYPE: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_proxy, - option_name, "integer", - N_("proxy type (http (default), socks4, socks5)"), - "http|socks4|socks5", 0, 0, value, NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL); - break; - case PROXY_OPTION_IPV6: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_proxy, - option_name, "boolean", - N_("connect to proxy using ipv6"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL); - break; - case PROXY_OPTION_ADDRESS: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_proxy, - option_name, "string", - N_("proxy server address (IP or hostname)"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL); - break; - case PROXY_OPTION_PORT: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_proxy, - option_name, "integer", - N_("port for connecting to proxy server"), - NULL, 0, 65535, value, NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL); - break; - case PROXY_OPTION_USERNAME: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_proxy, - option_name, "string", - N_("username for proxy server " - "(note: content is evaluated, see /help eval)"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL); - break; - case PROXY_OPTION_PASSWORD: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_proxy, - option_name, "string", - N_("password for proxy server " - "(note: content is evaluated, see /help eval)"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, NULL, NULL, NULL, NULL); - break; - case PROXY_NUM_OPTIONS: - break; - } - free (option_name); + snprintf (option_name, length, "%s.%s", + proxy_name, proxy_option_string[index_option]); + + switch (index_option) + { + case PROXY_OPTION_TYPE: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_proxy, + option_name, "integer", + N_("proxy type (http (default), socks4, socks5)"), + "http|socks4|socks5", 0, 0, value, NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + case PROXY_OPTION_IPV6: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_proxy, + option_name, "boolean", + N_("connect to proxy using ipv6"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + case PROXY_OPTION_ADDRESS: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_proxy, + option_name, "string", + N_("proxy server address (IP or hostname)"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + case PROXY_OPTION_PORT: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_proxy, + option_name, "integer", + N_("port for connecting to proxy server"), + NULL, 0, 65535, value, NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + case PROXY_OPTION_USERNAME: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_proxy, + option_name, "string", + N_("username for proxy server " + "(note: content is evaluated, see /help eval)"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + case PROXY_OPTION_PASSWORD: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_proxy, + option_name, "string", + N_("password for proxy server " + "(note: content is evaluated, see /help eval)"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + case PROXY_NUM_OPTIONS: + break; } + free (option_name); + return ptr_option; } @@ -423,24 +424,24 @@ proxy_new_with_options (const char *name, /* create proxy */ new_proxy = proxy_alloc (name); - if (new_proxy) - { - new_proxy->options[PROXY_OPTION_TYPE] = type; - new_proxy->options[PROXY_OPTION_IPV6] = ipv6; - new_proxy->options[PROXY_OPTION_ADDRESS] = address; - new_proxy->options[PROXY_OPTION_PORT] = port; - new_proxy->options[PROXY_OPTION_USERNAME] = username; - new_proxy->options[PROXY_OPTION_PASSWORD] = password; - - /* add proxy to proxies list */ - new_proxy->prev_proxy = last_weechat_proxy; - if (weechat_proxies) - last_weechat_proxy->next_proxy = new_proxy; - else - weechat_proxies = new_proxy; - last_weechat_proxy = new_proxy; - new_proxy->next_proxy = NULL; - } + if (!new_proxy) + return NULL; + + new_proxy->options[PROXY_OPTION_TYPE] = type; + new_proxy->options[PROXY_OPTION_IPV6] = ipv6; + new_proxy->options[PROXY_OPTION_ADDRESS] = address; + new_proxy->options[PROXY_OPTION_PORT] = port; + new_proxy->options[PROXY_OPTION_USERNAME] = username; + new_proxy->options[PROXY_OPTION_PASSWORD] = password; + + /* add proxy to proxies list */ + new_proxy->prev_proxy = last_weechat_proxy; + if (weechat_proxies) + last_weechat_proxy->next_proxy = new_proxy; + else + weechat_proxies = new_proxy; + last_weechat_proxy = new_proxy; + new_proxy->next_proxy = NULL; return new_proxy; } diff --git a/src/core/wee-string.c b/src/core/wee-string.c index ab29d9632..08fb4c7e1 100644 --- a/src/core/wee-string.c +++ b/src/core/wee-string.c @@ -449,64 +449,6 @@ string_match (const char *string, const char *mask, int case_sensitive) } /* - * Replaces a string by new one in a string. - * - * Note: result must be freed after use. - */ - -char * -string_replace (const char *string, const char *search, const char *replace) -{ - const char *pos; - char *new_string; - int length1, length2, length_new, count; - - if (!string || !search || !replace) - return NULL; - - length1 = strlen (search); - length2 = strlen (replace); - - /* count number of strings to replace */ - count = 0; - pos = string; - while (pos && pos[0] && (pos = strstr (pos, search))) - { - count++; - pos += length1; - } - - /* easy: no string to replace! */ - if (count == 0) - return strdup (string); - - /* compute needed memory for new string */ - length_new = strlen (string) - (count * length1) + (count * length2) + 1; - - /* allocate new string */ - new_string = malloc (length_new); - if (!new_string) - return strdup (string); - - /* replace all occurrences */ - new_string[0] = '\0'; - while (string && string[0]) - { - pos = strstr (string, search); - if (pos) - { - strncat (new_string, string, pos - string); - strcat (new_string, replace); - pos += length1; - } - else - strcat (new_string, string); - string = pos; - } - return new_string; -} - -/* * Expands home in a path. * * Example: "~/file.txt" => "/home/xxx/file.txt" @@ -1145,6 +1087,331 @@ string_has_highlight_regex (const char *string, const char *regex) } /* + * Replaces a string by new one in a string. + * + * Note: result must be freed after use. + */ + +char * +string_replace (const char *string, const char *search, const char *replace) +{ + const char *pos; + char *new_string; + int length1, length2, length_new, count; + + if (!string || !search || !replace) + return NULL; + + length1 = strlen (search); + length2 = strlen (replace); + + /* count number of strings to replace */ + count = 0; + pos = string; + while (pos && pos[0] && (pos = strstr (pos, search))) + { + count++; + pos += length1; + } + + /* easy: no string to replace! */ + if (count == 0) + return strdup (string); + + /* compute needed memory for new string */ + length_new = strlen (string) - (count * length1) + (count * length2) + 1; + + /* allocate new string */ + new_string = malloc (length_new); + if (!new_string) + return strdup (string); + + /* replace all occurrences */ + new_string[0] = '\0'; + while (string && string[0]) + { + pos = strstr (string, search); + if (pos) + { + strncat (new_string, string, pos - string); + strcat (new_string, replace); + pos += length1; + } + else + strcat (new_string, string); + string = pos; + } + return new_string; +} + +/* + * Get replacement string for a regex, using array of "match" + * (for more info, see function "string_replace_regex"). + * + * Note: result must be freed after use. + */ + +char * +string_replace_regex_get_replace (const char *string, regmatch_t *regex_match, + int last_match, const char *replace, + const char reference_char) +{ + int length, length_current, length_add, match; + const char *ptr_replace, *ptr_add; + char *result, *result2, *modified_replace, *temp, char_replace; + + /* default length is length*2, it will grow later if needed */ + length = (strlen (string) * 2); + result = malloc (length + 1); + if (!result) + return NULL; + + result[0] = '\0'; + length_current = 0; + ptr_replace = replace; + while (ptr_replace && ptr_replace[0]) + { + ptr_add = NULL; + length_add = 0; + modified_replace = NULL; + + if ((ptr_replace[0] == '\\') && (ptr_replace[1] == reference_char)) + { + /* escaped reference char */ + ptr_add = ptr_replace + 1; + length_add = 1; + ptr_replace += 2; + } + else if (ptr_replace[0] == reference_char) + { + if ((ptr_replace[1] == '+') || isdigit ((unsigned char)ptr_replace[1])) + { + if (ptr_replace[1] == '+') + { + /* reference to last match */ + match = last_match; + ptr_replace += 2; + } + else + { + /* reference to match 0 .. 99 */ + if (isdigit ((unsigned char)ptr_replace[2])) + { + match = ((ptr_replace[1] - '0') * 10) + (ptr_replace[2] - '0'); + ptr_replace += 3; + } + else + { + match = ptr_replace[1] - '0'; + ptr_replace += 2; + } + } + if (regex_match[match].rm_so >= 0) + { + ptr_add = string + regex_match[match].rm_so; + length_add = regex_match[match].rm_eo - regex_match[match].rm_so; + } + } + else if ((ptr_replace[1] == '.') + && (ptr_replace[2] >= 32) && (ptr_replace[2] <= 126) + && ((ptr_replace[3] == '+') || isdigit ((unsigned char)ptr_replace[3]))) + { + char_replace = ptr_replace[2]; + if (ptr_replace[3] == '+') + { + /* reference to last match */ + match = last_match; + ptr_replace += 4; + } + else + { + /* reference to match 0 .. 99 */ + if (isdigit ((unsigned char)ptr_replace[4])) + { + match = ((ptr_replace[3] - '0') * 10) + (ptr_replace[4] - '0'); + ptr_replace += 5; + } + else + { + match = ptr_replace[3] - '0'; + ptr_replace += 4; + } + } + if (regex_match[match].rm_so >= 0) + { + temp = string_strndup (string + regex_match[match].rm_so, + regex_match[match].rm_eo - regex_match[match].rm_so); + if (temp) + { + length_add = utf8_strlen (temp); + modified_replace = malloc (length_add + 1); + if (modified_replace) + { + memset (modified_replace, char_replace, length_add); + modified_replace[length_add] = '\0'; + ptr_add = modified_replace; + } + free (temp); + } + } + } + else + { + /* just ignore the reference char */ + ptr_replace++; + } + } + else + { + ptr_add = ptr_replace; + length_add = utf8_char_size (ptr_replace); + ptr_replace += length_add; + } + + if (ptr_add) + { + if (length_current + length_add > length) + { + length = (length * 2 >= length_current + length_add) ? + length * 2 : length_current + length_add; + result2 = realloc (result, length + 1); + if (!result2) + { + if (modified_replace) + free (modified_replace); + free (result); + return NULL; + } + result = result2; + } + memcpy (result + length_current, ptr_add, length_add); + length_current += length_add; + result[length_current] = '\0'; + } + if (modified_replace) + free (modified_replace); + } + + return result; +} + +/* + * Replaces text in a string using a regular expression and replacement text. + * + * The argument "regex" is a pointer to a regex compiled with WeeChat function + * string_regcomp (or function regcomp). + * + * The argument "replace" can contain references to matches: + * $0 .. $99 match 0 to 99 (0 is whole match, 1 .. 99 are groups captured) + * $+ the last match (with highest number) + * $.*N match N (can be '+' or 0 to 99), with all chars replaced by '*' + * (the char '*' can be replaced by any char between space (32) + * and '~' (126)) + * + * Examples: + * + * string | regex | replace | result + * ----------+---------------+-----------+------------- + * test foo | test | Z | Z foo + * test foo | ^(test +)(.*) | $2 | foo + * test foo | ^(test +)(.*) | $1 / $.*2 | test / *** + * test foo | ^(test +)(.*) | $.%+ | %%% + * + * Note: result must be freed after use. + */ + +char * +string_replace_regex (const char *string, void *regex, const char *replace, + const char reference_char) +{ + char *result, *result2, *str_replace; + int length, length_replace, start_offset, i, rc, end, last_match; + regmatch_t regex_match[100]; + + if (!string) + return NULL; + + length = strlen (string) + 1; + result = malloc (length); + if (!result) + return NULL; + snprintf (result, length, "%s", string); + + start_offset = 0; + while (result && result[start_offset]) + { + for (i = 0; i < 100; i++) + { + regex_match[i].rm_so = -1; + } + + rc = regexec ((regex_t *)regex, result + start_offset, 100, regex_match, + 0); + /* + * no match found: exit the loop (if rm_eo == 0, it is an empty match + * at beginning of string: we consider there is no match, to prevent an + * infinite loop) + */ + if ((rc != 0) + || (regex_match[0].rm_so < 0) || (regex_match[0].rm_eo <= 0)) + { + break; + } + + /* adjust the start/end offsets */ + last_match = 0; + for (i = 0; i < 100; i++) + { + if (regex_match[i].rm_so >= 0) + { + last_match = i; + regex_match[i].rm_so += start_offset; + regex_match[i].rm_eo += start_offset; + } + } + + /* check if the regex matched the end of string */ + end = !result[regex_match[0].rm_eo]; + + str_replace = string_replace_regex_get_replace (result, regex_match, + last_match, + replace, reference_char); + length_replace = (str_replace) ? strlen (str_replace) : 0; + + length = regex_match[0].rm_so + length_replace + + strlen (result + regex_match[0].rm_eo) + 1; + result2 = malloc (length); + if (!result2) + { + free (result); + return NULL; + } + result2[0] = '\0'; + if (regex_match[0].rm_so > 0) + { + memcpy (result2, result, regex_match[0].rm_so); + result2[regex_match[0].rm_so] = '\0'; + } + if (str_replace) + strcat (result2, str_replace); + strcat (result2, result + regex_match[0].rm_eo); + + free (result); + result = result2; + + if (str_replace) + free (str_replace); + + if (end) + break; + + start_offset = regex_match[0].rm_so + length_replace; + } + + return result; +} + +/* * Splits a string according to separators. * * This function must not be called directly (call string_split or @@ -1172,7 +1439,7 @@ string_split_internal (const char *string, const char *separators, int keep_eol, char *ptr, *ptr1, *ptr2; const char *str_shared; - if (num_items != NULL) + if (num_items) *num_items = 0; if (!string || !string[0] || !separators || !separators[0]) @@ -1187,7 +1454,7 @@ string_split_internal (const char *string, const char *separators, int keep_eol, i = 1; while ((ptr = strpbrk (ptr, separators))) { - while (ptr[0] && (strchr (separators, ptr[0]) != NULL)) + while (ptr[0] && strchr (separators, ptr[0])) { ptr++; } @@ -1206,7 +1473,7 @@ string_split_internal (const char *string, const char *separators, int keep_eol, for (i = 0; i < n_items; i++) { - while (ptr1[0] && (strchr (separators, ptr1[0]) != NULL)) + while (ptr1[0] && strchr (separators, ptr1[0])) { ptr1++; } @@ -1307,7 +1574,7 @@ string_split_internal (const char *string, const char *separators, int keep_eol, } array[i] = NULL; - if (num_items != NULL) + if (num_items) *num_items = i; free (string2); @@ -1347,8 +1614,8 @@ string_split_shared (const char *string, const char *separators, int keep_eol, /* * Splits a string like the shell does for a command with arguments. * - * This function is a C conversion of python class "shlex" - * (file: Lib/shlex.py in python repository) + * This function is a C conversion of Python class "shlex" + * (file: Lib/shlex.py in Python repository) * Doc: http://docs.python.org/3/library/shlex.html * * Copyrights in shlex.py: @@ -1362,12 +1629,15 @@ string_split_shared (const char *string, const char *separators, int keep_eol, */ char ** -string_split_shell (const char *string) +string_split_shell (const char *string, int *num_items) { int temp_len, num_args, add_char_to_temp, add_temp_to_args, quoted; char *string2, *temp, **args, **args2, state, escapedstate; char *ptr_string, *ptr_next, saved_char; + if (num_items) + *num_items = 0; + if (!string) return NULL; @@ -1533,6 +1803,9 @@ string_split_shell (const char *string) free (string2); free (temp); + if (num_items) + *num_items = num_args; + return args; } @@ -1630,7 +1903,7 @@ string_split_command (const char *command, char separator) nb_substr = 1; ptr = command; - while ( (p = strchr(ptr, separator)) != NULL) + while ((p = strchr(ptr, separator)) != NULL) { nb_substr++; ptr = ++p; diff --git a/src/core/wee-string.h b/src/core/wee-string.h index 9a7c5d76b..1ae8cb9b2 100644 --- a/src/core/wee-string.h +++ b/src/core/wee-string.h @@ -57,12 +57,15 @@ extern int string_has_highlight (const char *string, extern int string_has_highlight_regex_compiled (const char *string, regex_t *regex); extern int string_has_highlight_regex (const char *string, const char *regex); +extern char *string_replace_regex (const char *string, void *regex, + const char *replace, + const char reference_char); extern char **string_split (const char *string, const char *separators, int keep_eol, int num_items_max, int *num_items); extern char **string_split_shared (const char *string, const char *separators, int keep_eol, int num_items_max, int *num_items); -extern char **string_split_shell (const char *string); +extern char **string_split_shell (const char *string, int *num_items); extern void string_free_split (char **split_string); extern void string_free_split_shared (char **split_string); extern char *string_build_with_split_string (const char **split_string, diff --git a/src/gui/gui-bar.c b/src/gui/gui-bar.c index 4a48124c8..2d255ba8c 100644 --- a/src/gui/gui-bar.c +++ b/src/gui/gui-bar.c @@ -1368,157 +1368,157 @@ gui_bar_create_option (const char *bar_name, int index_option, const char *value length = strlen (bar_name) + 1 + strlen (gui_bar_option_string[index_option]) + 1; option_name = malloc (length); - if (option_name) - { - snprintf (option_name, length, "%s.%s", - bar_name, gui_bar_option_string[index_option]); + if (!option_name) + return NULL; - switch (index_option) - { - case GUI_BAR_OPTION_HIDDEN: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "boolean", - N_("true if bar is hidden, false if it is displayed"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, &gui_bar_config_change_hidden, NULL, NULL, NULL); - break; - case GUI_BAR_OPTION_PRIORITY: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "integer", - N_("bar priority (high number means bar displayed first)"), - NULL, 0, INT_MAX, value, NULL, 0, - NULL, NULL, &gui_bar_config_change_priority, NULL, NULL, NULL); - break; - case GUI_BAR_OPTION_TYPE: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "integer", - N_("bar type (root, window, window_active, window_inactive)"), - "root|window|window_active|window_inactive", 0, 0, value, NULL, 0, - &gui_bar_config_check_type, NULL, NULL, NULL, NULL, NULL); - break; - case GUI_BAR_OPTION_CONDITIONS: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "string", - N_("condition(s) for displaying bar (for bars of type " - "\"window\"): a simple condition: \"active\", " - "\"inactive\", \"nicklist\" (window must be active/" - "inactive, buffer must have a nicklist), or an " - "expression with condition(s) (see /help eval), like: " - "\"${nicklist} && ${window.win_width} > 100\" " - "(local variables for expression are ${active}, " - "${inactive} and ${nicklist})"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, &gui_bar_config_change_conditions, NULL, NULL, NULL); - break; - case GUI_BAR_OPTION_POSITION: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "integer", - N_("bar position (bottom, top, left, right)"), - "bottom|top|left|right", 0, 0, value, NULL, 0, - NULL, NULL, &gui_bar_config_change_position, NULL, NULL, NULL); - break; - case GUI_BAR_OPTION_FILLING_TOP_BOTTOM: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "integer", - N_("bar filling direction (\"horizontal\" (from left to " - "right) or \"vertical\" (from top to bottom)) when bar " - "position is top or bottom"), - "horizontal|vertical|columns_horizontal|columns_vertical", - 0, 0, value, NULL, 0, - NULL, NULL, &gui_bar_config_change_filling, NULL, NULL, NULL); - break; - case GUI_BAR_OPTION_FILLING_LEFT_RIGHT: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "integer", - N_("bar filling direction (\"horizontal\" (from left to " - "right) or \"vertical\" (from top to bottom)) when bar " - "position is left or right"), - "horizontal|vertical|columns_horizontal|columns_vertical", - 0, 0, value, NULL, 0, - NULL, NULL, &gui_bar_config_change_filling, NULL, NULL, NULL); - break; - case GUI_BAR_OPTION_SIZE: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "integer", - N_("bar size in chars (0 = auto size)"), - NULL, 0, INT_MAX, value, NULL, 0, - &gui_bar_config_check_size, NULL, - &gui_bar_config_change_size, NULL, - NULL, NULL); - break; - case GUI_BAR_OPTION_SIZE_MAX: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "integer", - N_("max bar size in chars (0 = no limit)"), - NULL, 0, INT_MAX, value, NULL, 0, - NULL, NULL, - &gui_bar_config_change_size_max, NULL, - NULL, NULL); - break; - case GUI_BAR_OPTION_COLOR_FG: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "color", - N_("default text color for bar"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, - &gui_bar_config_change_color, NULL, - NULL, NULL); - break; - case GUI_BAR_OPTION_COLOR_DELIM: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "color", - N_("default delimiter color for bar"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, - &gui_bar_config_change_color, NULL, - NULL, NULL); - break; - case GUI_BAR_OPTION_COLOR_BG: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "color", - N_("default background color for bar"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, - &gui_bar_config_change_color, NULL, - NULL, NULL); - break; - case GUI_BAR_OPTION_SEPARATOR: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "boolean", - N_("separator line between bar and other bars/windows"), - NULL, 0, 0, value, NULL, 0, - NULL, NULL, &gui_bar_config_change_separator, NULL, NULL, NULL); - break; - case GUI_BAR_OPTION_ITEMS: - ptr_option = config_file_new_option ( - weechat_config_file, weechat_config_section_bar, - option_name, "string", - N_("items of bar, they can be separated by comma (space " - "between items) or \"+\" (glued items); special syntax " - "\"@buffer:item\" can be used to force buffer used when " - "displaying the bar item"), - NULL, 0, 0, gui_bar_default_items (bar_name), value, 0, - NULL, NULL, &gui_bar_config_change_items, NULL, NULL, NULL); - break; - case GUI_BAR_NUM_OPTIONS: - break; - } - free (option_name); + snprintf (option_name, length, "%s.%s", + bar_name, gui_bar_option_string[index_option]); + + switch (index_option) + { + case GUI_BAR_OPTION_HIDDEN: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "boolean", + N_("true if bar is hidden, false if it is displayed"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, &gui_bar_config_change_hidden, NULL, NULL, NULL); + break; + case GUI_BAR_OPTION_PRIORITY: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "integer", + N_("bar priority (high number means bar displayed first)"), + NULL, 0, INT_MAX, value, NULL, 0, + NULL, NULL, &gui_bar_config_change_priority, NULL, NULL, NULL); + break; + case GUI_BAR_OPTION_TYPE: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "integer", + N_("bar type (root, window, window_active, window_inactive)"), + "root|window|window_active|window_inactive", 0, 0, value, NULL, 0, + &gui_bar_config_check_type, NULL, NULL, NULL, NULL, NULL); + break; + case GUI_BAR_OPTION_CONDITIONS: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "string", + N_("condition(s) for displaying bar (for bars of type " + "\"window\"): a simple condition: \"active\", \"inactive\", " + "\"nicklist\" (window must be active/inactive, buffer must " + "have a nicklist), or an expression with condition(s) (see " + "/help eval), like: \"${nicklist} && ${window.win_width} > " + "100\" (local variables for expression are ${active}, " + "${inactive} and ${nicklist})"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, &gui_bar_config_change_conditions, NULL, NULL, NULL); + break; + case GUI_BAR_OPTION_POSITION: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "integer", + N_("bar position (bottom, top, left, right)"), + "bottom|top|left|right", 0, 0, value, NULL, 0, + NULL, NULL, &gui_bar_config_change_position, NULL, NULL, NULL); + break; + case GUI_BAR_OPTION_FILLING_TOP_BOTTOM: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "integer", + N_("bar filling direction (\"horizontal\" (from left to right) " + "or \"vertical\" (from top to bottom)) when bar position is " + "top or bottom"), + "horizontal|vertical|columns_horizontal|columns_vertical", + 0, 0, value, NULL, 0, + NULL, NULL, &gui_bar_config_change_filling, NULL, NULL, NULL); + break; + case GUI_BAR_OPTION_FILLING_LEFT_RIGHT: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "integer", + N_("bar filling direction (\"horizontal\" (from left to right) " + "or \"vertical\" (from top to bottom)) when bar position is " + "left or right"), + "horizontal|vertical|columns_horizontal|columns_vertical", + 0, 0, value, NULL, 0, + NULL, NULL, &gui_bar_config_change_filling, NULL, NULL, NULL); + break; + case GUI_BAR_OPTION_SIZE: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "integer", + N_("bar size in chars (0 = auto size)"), + NULL, 0, INT_MAX, value, NULL, 0, + &gui_bar_config_check_size, NULL, + &gui_bar_config_change_size, NULL, + NULL, NULL); + break; + case GUI_BAR_OPTION_SIZE_MAX: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "integer", + N_("max bar size in chars (0 = no limit)"), + NULL, 0, INT_MAX, value, NULL, 0, + NULL, NULL, + &gui_bar_config_change_size_max, NULL, + NULL, NULL); + break; + case GUI_BAR_OPTION_COLOR_FG: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "color", + N_("default text color for bar"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, + &gui_bar_config_change_color, NULL, + NULL, NULL); + break; + case GUI_BAR_OPTION_COLOR_DELIM: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "color", + N_("default delimiter color for bar"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, + &gui_bar_config_change_color, NULL, + NULL, NULL); + break; + case GUI_BAR_OPTION_COLOR_BG: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "color", + N_("default background color for bar"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, + &gui_bar_config_change_color, NULL, + NULL, NULL); + break; + case GUI_BAR_OPTION_SEPARATOR: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "boolean", + N_("separator line between bar and other bars/windows"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, &gui_bar_config_change_separator, NULL, NULL, NULL); + break; + case GUI_BAR_OPTION_ITEMS: + ptr_option = config_file_new_option ( + weechat_config_file, weechat_config_section_bar, + option_name, "string", + N_("items of bar, they can be separated by comma (space " + "between items) or \"+\" (glued items); special syntax " + "\"@buffer:item\" can be used to force buffer used when " + "displaying the bar item"), + NULL, 0, 0, gui_bar_default_items (bar_name), value, 0, + NULL, NULL, &gui_bar_config_change_items, NULL, NULL, NULL); + break; + case GUI_BAR_NUM_OPTIONS: + break; } + free (option_name); + return ptr_option; } @@ -1535,53 +1535,10 @@ gui_bar_create_option_temp (struct t_gui_bar *temp_bar, int index_option, new_option = gui_bar_create_option (temp_bar->name, index_option, value); - if (new_option) + if (new_option + && (index_option >= 0) && (index_option < GUI_BAR_NUM_OPTIONS)) { - switch (index_option) - { - case GUI_BAR_OPTION_HIDDEN: - temp_bar->options[GUI_BAR_OPTION_HIDDEN] = new_option; - break; - case GUI_BAR_OPTION_PRIORITY: - temp_bar->options[GUI_BAR_OPTION_PRIORITY] = new_option; - break; - case GUI_BAR_OPTION_TYPE: - temp_bar->options[GUI_BAR_OPTION_TYPE] = new_option; - break; - case GUI_BAR_OPTION_CONDITIONS: - temp_bar->options[GUI_BAR_OPTION_CONDITIONS] = new_option; - break; - case GUI_BAR_OPTION_POSITION: - temp_bar->options[GUI_BAR_OPTION_POSITION] = new_option; - break; - case GUI_BAR_OPTION_FILLING_TOP_BOTTOM: - temp_bar->options[GUI_BAR_OPTION_FILLING_TOP_BOTTOM] = new_option; - break; - case GUI_BAR_OPTION_FILLING_LEFT_RIGHT: - temp_bar->options[GUI_BAR_OPTION_FILLING_LEFT_RIGHT] = new_option; - break; - case GUI_BAR_OPTION_SIZE: - temp_bar->options[GUI_BAR_OPTION_SIZE] = new_option; - break; - case GUI_BAR_OPTION_SIZE_MAX: - temp_bar->options[GUI_BAR_OPTION_SIZE_MAX] = new_option; - break; - case GUI_BAR_OPTION_COLOR_FG: - temp_bar->options[GUI_BAR_OPTION_COLOR_FG] = new_option; - break; - case GUI_BAR_OPTION_COLOR_DELIM: - temp_bar->options[GUI_BAR_OPTION_COLOR_DELIM] = new_option; - break; - case GUI_BAR_OPTION_COLOR_BG: - temp_bar->options[GUI_BAR_OPTION_COLOR_BG] = new_option; - break; - case GUI_BAR_OPTION_SEPARATOR: - temp_bar->options[GUI_BAR_OPTION_SEPARATOR] = new_option; - break; - case GUI_BAR_OPTION_ITEMS: - temp_bar->options[GUI_BAR_OPTION_ITEMS] = new_option; - break; - } + temp_bar->options[index_option] = new_option; } } @@ -1648,51 +1605,51 @@ gui_bar_new_with_options (const char *name, /* create bar */ new_bar = gui_bar_alloc (name); - if (new_bar) - { - new_bar->options[GUI_BAR_OPTION_HIDDEN] = hidden; - new_bar->options[GUI_BAR_OPTION_PRIORITY] = priority; - new_bar->options[GUI_BAR_OPTION_TYPE] = type; - new_bar->options[GUI_BAR_OPTION_CONDITIONS] = conditions; - new_bar->options[GUI_BAR_OPTION_POSITION] = position; - new_bar->options[GUI_BAR_OPTION_FILLING_TOP_BOTTOM] = filling_top_bottom; - new_bar->options[GUI_BAR_OPTION_FILLING_LEFT_RIGHT] = filling_left_right; - new_bar->options[GUI_BAR_OPTION_SIZE] = size; - new_bar->options[GUI_BAR_OPTION_SIZE_MAX] = size_max; - new_bar->options[GUI_BAR_OPTION_COLOR_FG] = color_fg; - new_bar->options[GUI_BAR_OPTION_COLOR_DELIM] = color_delim; - new_bar->options[GUI_BAR_OPTION_COLOR_BG] = color_bg; - new_bar->options[GUI_BAR_OPTION_SEPARATOR] = separator; - new_bar->options[GUI_BAR_OPTION_ITEMS] = items; - new_bar->items_count = 0; - new_bar->items_subcount = NULL; - new_bar->items_array = NULL; - new_bar->items_buffer = NULL; - new_bar->items_prefix = NULL; - new_bar->items_name = NULL; - new_bar->items_suffix = NULL; - gui_bar_set_items_array (new_bar, CONFIG_STRING(items)); - new_bar->bar_window = NULL; - new_bar->bar_refresh_needed = 1; - - /* add bar to bars list */ - gui_bar_insert (new_bar); + if (!new_bar) + return NULL; - /* add window bar */ - if (CONFIG_INTEGER(new_bar->options[GUI_BAR_OPTION_TYPE]) == GUI_BAR_TYPE_ROOT) - { - /* create only one window for bar */ - gui_bar_window_new (new_bar, NULL); - gui_window_ask_refresh (1); - } - else + new_bar->options[GUI_BAR_OPTION_HIDDEN] = hidden; + new_bar->options[GUI_BAR_OPTION_PRIORITY] = priority; + new_bar->options[GUI_BAR_OPTION_TYPE] = type; + new_bar->options[GUI_BAR_OPTION_CONDITIONS] = conditions; + new_bar->options[GUI_BAR_OPTION_POSITION] = position; + new_bar->options[GUI_BAR_OPTION_FILLING_TOP_BOTTOM] = filling_top_bottom; + new_bar->options[GUI_BAR_OPTION_FILLING_LEFT_RIGHT] = filling_left_right; + new_bar->options[GUI_BAR_OPTION_SIZE] = size; + new_bar->options[GUI_BAR_OPTION_SIZE_MAX] = size_max; + new_bar->options[GUI_BAR_OPTION_COLOR_FG] = color_fg; + new_bar->options[GUI_BAR_OPTION_COLOR_DELIM] = color_delim; + new_bar->options[GUI_BAR_OPTION_COLOR_BG] = color_bg; + new_bar->options[GUI_BAR_OPTION_SEPARATOR] = separator; + new_bar->options[GUI_BAR_OPTION_ITEMS] = items; + new_bar->items_count = 0; + new_bar->items_subcount = NULL; + new_bar->items_array = NULL; + new_bar->items_buffer = NULL; + new_bar->items_prefix = NULL; + new_bar->items_name = NULL; + new_bar->items_suffix = NULL; + gui_bar_set_items_array (new_bar, CONFIG_STRING(items)); + new_bar->bar_window = NULL; + new_bar->bar_refresh_needed = 1; + + /* add bar to bars list */ + gui_bar_insert (new_bar); + + /* add window bar */ + if (CONFIG_INTEGER(new_bar->options[GUI_BAR_OPTION_TYPE]) == GUI_BAR_TYPE_ROOT) + { + /* create only one window for bar */ + gui_bar_window_new (new_bar, NULL); + gui_window_ask_refresh (1); + } + else + { + /* create bar window for all opened windows */ + for (ptr_win = gui_windows; ptr_win; + ptr_win = ptr_win->next_window) { - /* create bar window for all opened windows */ - for (ptr_win = gui_windows; ptr_win; - ptr_win = ptr_win->next_window) - { - gui_bar_window_new (new_bar, ptr_win); - } + gui_bar_window_new (new_bar, ptr_win); } } @@ -1867,7 +1824,7 @@ gui_bar_use_temp_bars () } } - /* free all temp bars */ + /* free all temporary bars */ while (gui_temp_bars) { next_temp_bar = gui_temp_bars->next_bar; diff --git a/src/gui/gui-completion.c b/src/gui/gui-completion.c index 18b51ccb3..c97192ed1 100644 --- a/src/gui/gui-completion.c +++ b/src/gui/gui-completion.c @@ -478,7 +478,8 @@ int gui_completion_get_matching_template (struct t_gui_completion *completion, struct t_hook *hook_command) { - int i, length, fallback; + int i, j, length, fallback, num_items; + char **items; /* without at least one argument, we can't find matching template! */ if (completion->base_command_arg_index <= 1) @@ -488,13 +489,23 @@ gui_completion_get_matching_template (struct t_gui_completion *completion, for (i = 0; i < HOOK_COMMAND(hook_command, cplt_num_templates); i++) { - length = strlen (HOOK_COMMAND(hook_command, cplt_templates_static)[i]); - if ((strncmp (HOOK_COMMAND(hook_command, cplt_templates_static)[i], - completion->args, length) == 0) - && (completion->args[length] == ' ')) + items = string_split (HOOK_COMMAND(hook_command, cplt_templates_static)[i], + "|", 0, 0, &num_items); + if (items) { - return i; + for (j = 0; j < num_items; j++) + { + length = strlen (items[j]); + if ((strncmp (items[j], completion->args, length) == 0) + && (completion->args[length] == ' ')) + { + string_free_split (items); + return i; + } + } + string_free_split (items); } + /* * try to find a fallback template if we don't find any matching * template, for example with these templates (command /set): diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 3e6ac0e26..41a03412a 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -96,10 +96,6 @@ IF(ENABLE_SCRIPT) ADD_SUBDIRECTORY( script ) ENDIF(ENABLE_SCRIPT) -IF(ENABLE_XFER) - ADD_SUBDIRECTORY( xfer ) -ENDIF(ENABLE_XFER) - IF(ENABLE_SCRIPTS AND ENABLE_PERL) FIND_PACKAGE(Perl) IF(PERL_FOUND) @@ -142,4 +138,12 @@ IF(ENABLE_SCRIPTS AND ENABLE_GUILE) ENDIF(GUILE_FOUND) ENDIF(ENABLE_SCRIPTS AND ENABLE_GUILE) +IF(ENABLE_TRIGGER) + ADD_SUBDIRECTORY( trigger ) +ENDIF(ENABLE_TRIGGER) + +IF(ENABLE_XFER) + ADD_SUBDIRECTORY( xfer ) +ENDIF(ENABLE_XFER) + INSTALL(FILES weechat-plugin.h DESTINATION ${INCLUDEDIR}) diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 16c0e35ac..bfddd6274 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -75,10 +75,6 @@ if PLUGIN_SCRIPT script_dir = script endif -if PLUGIN_XFER -xfer_dir = xfer -endif - if PLUGIN_PERL perl_dir = perl endif @@ -103,10 +99,18 @@ if PLUGIN_GUILE guile_dir = guile endif +if PLUGIN_TRIGGER +trigger_dir = trigger +endif + +if PLUGIN_XFER +xfer_dir = xfer +endif + SUBDIRS = . $(alias_dir) $(aspell_dir) $(charset_dir) $(fifo_dir) $(irc_dir) \ - $(logger_dir) $(relay_dir) $(rmodifier_dir) $(script_dir) $(xfer_dir) \ + $(logger_dir) $(relay_dir) $(rmodifier_dir) $(script_dir) \ $(perl_dir) $(python_dir) $(ruby_dir) $(lua_dir) $(tcl_dir) \ - $(guile_dir) + $(guile_dir) $(trigger_dir) $(xfer_dir) EXTRA_DIST = CMakeLists.txt diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c index 2cdfbfbbe..f910c8fdc 100644 --- a/src/plugins/plugin.c +++ b/src/plugins/plugin.c @@ -516,12 +516,15 @@ plugin_load (const char *filename, int argc, char **argv) new_plugin->string_expand_home = &string_expand_home; new_plugin->string_remove_quotes = &string_remove_quotes; new_plugin->string_strip = &string_strip; + new_plugin->string_convert_escaped_chars = &string_convert_escaped_chars; new_plugin->string_mask_to_regex = &string_mask_to_regex; new_plugin->string_regex_flags = &string_regex_flags; new_plugin->string_regcomp = &string_regcomp; new_plugin->string_has_highlight = &string_has_highlight; new_plugin->string_has_highlight_regex = &string_has_highlight_regex; + new_plugin->string_replace_regex = &string_replace_regex; new_plugin->string_split = &string_split; + new_plugin->string_split_shell = &string_split_shell; new_plugin->string_free_split = &string_free_split; new_plugin->string_build_with_split_string = &string_build_with_split_string; new_plugin->string_split_command = &string_split_command; @@ -587,6 +590,7 @@ plugin_load (const char *filename, int argc, char **argv) new_plugin->hashtable_has_key = &hashtable_has_key; new_plugin->hashtable_map = &hashtable_map; new_plugin->hashtable_map_string = &hashtable_map_string; + new_plugin->hashtable_dup = &hashtable_dup; new_plugin->hashtable_get_integer = &hashtable_get_integer; new_plugin->hashtable_get_string = &hashtable_get_string; new_plugin->hashtable_set_pointer = &hashtable_set_pointer; diff --git a/src/plugins/trigger/CMakeLists.txt b/src/plugins/trigger/CMakeLists.txt new file mode 100644 index 000000000..59d8e1c00 --- /dev/null +++ b/src/plugins/trigger/CMakeLists.txt @@ -0,0 +1,31 @@ +# +# Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +ADD_LIBRARY(trigger MODULE +trigger.c trigger.h +trigger-buffer.c trigger-buffer.h +trigger-callback.c trigger-callback.h +trigger-command.c trigger-command.h +trigger-completion.c trigger-completion.h +trigger-config.c trigger-config.h) +SET_TARGET_PROPERTIES(trigger PROPERTIES PREFIX "") + +TARGET_LINK_LIBRARIES(trigger) + +INSTALL(TARGETS trigger LIBRARY DESTINATION ${LIBDIR}/plugins) diff --git a/src/plugins/trigger/Makefile.am b/src/plugins/trigger/Makefile.am new file mode 100644 index 000000000..2486c0359 --- /dev/null +++ b/src/plugins/trigger/Makefile.am @@ -0,0 +1,42 @@ +# +# Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +AM_CPPFLAGS = -DLOCALEDIR=\"$(datadir)/locale\" $(TRIGGER_CFLAGS) + +libdir = ${weechat_libdir}/plugins + +lib_LTLIBRARIES = trigger.la + +trigger_la_SOURCES = trigger.c \ + trigger.h \ + trigger-buffer.c \ + trigger-buffer.h \ + trigger-callback.c \ + trigger-callback.h \ + trigger-command.c \ + trigger-command.h \ + trigger-completion.c \ + trigger-completion.h \ + trigger-config.c \ + trigger-config.h + +trigger_la_LDFLAGS = -module -no-undefined +trigger_la_LIBADD = $(TRIGGER_LFLAGS) + +EXTRA_DIST = CMakeLists.txt diff --git a/src/plugins/trigger/trigger-buffer.c b/src/plugins/trigger/trigger-buffer.c new file mode 100644 index 000000000..b9a3f20ec --- /dev/null +++ b/src/plugins/trigger/trigger-buffer.c @@ -0,0 +1,220 @@ +/* + * trigger-buffer.c - debug buffer for triggers + * + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "trigger.h" +#include "trigger-buffer.h" +#include "trigger-config.h" + + +struct t_gui_buffer *trigger_buffer = NULL; + + +/* + * Callback called for each entry in hashtable. + */ + +void +trigger_buffer_hashtable_map_cb (void *data, + struct t_hashtable *hashtable, + const void *key, const void *value) +{ + const char *value_type; + char *value_no_color; + + /* make C compiler happy */ + (void) data; + (void) hashtable; + + value_type = weechat_hashtable_get_string (hashtable, "type_values"); + if (!value_type) + return; + + if (strcmp (value_type, "string") == 0) + { + value_no_color = (weechat_config_boolean (trigger_config_look_monitor_strip_colors)) ? + weechat_string_remove_color ((const char *)value, NULL) : NULL; + weechat_printf_tags (trigger_buffer, "no_trigger", + "\t %s: %s\"%s%s%s\"", + (char *)key, + weechat_color ("chat_delimiters"), + weechat_color ("reset"), + (value_no_color) ? value_no_color : (const char *)value, + weechat_color ("chat_delimiters")); + if (value_no_color) + free (value_no_color); + } + else if (strcmp (value_type, "pointer") == 0) + { + weechat_printf_tags (trigger_buffer, "no_trigger", + "\t %s: 0x%lx", + (char *)key, + value); + } +} + +/* + * Displays a hashtable on trigger buffer. + */ + +void +trigger_buffer_display_hashtable (const char *name, + struct t_hashtable *hashtable) +{ + if (!trigger_buffer) + return; + + weechat_printf_tags (trigger_buffer, "no_trigger", " %s:", name); + + weechat_hashtable_map (hashtable, &trigger_buffer_hashtable_map_cb, NULL); +} + +/* + * Displays a trigger in trigger buffer. + */ + +void +trigger_buffer_display_trigger (struct t_trigger *trigger, + struct t_gui_buffer *buffer, + struct t_hashtable *pointers, + struct t_hashtable *extra_vars) +{ + if (!trigger_buffer) + return; + + weechat_printf_tags (trigger_buffer, "no_trigger", + "%s\t%s%s %s(%s%s%s)", + trigger_hook_type_string[weechat_config_integer (trigger->options[TRIGGER_OPTION_HOOK])], + weechat_color (weechat_config_string (trigger_config_color_trigger)), + trigger->name, + weechat_color ("chat_delimiters"), + weechat_color ("reset"), + weechat_config_string (trigger->options[TRIGGER_OPTION_ARGUMENTS]), + weechat_color ("chat_delimiters")); + if (buffer) + { + weechat_printf_tags (trigger_buffer, "no_trigger", + "\t buffer: %s%s", + weechat_color ("chat_buffer"), + weechat_buffer_get_string (buffer, "full_name")); + } + if (pointers) + trigger_buffer_display_hashtable ("pointers", pointers); + if (extra_vars) + trigger_buffer_display_hashtable ("extra_vars", extra_vars); +} + +/* + * Callback for user data in trigger buffer. + */ + +int +trigger_buffer_input_cb (void *data, struct t_gui_buffer *buffer, + const char *input_data) +{ + /* make C compiler happy */ + (void) data; + + /* close buffer */ + if (strcmp (input_data, "q") == 0) + { + weechat_buffer_close (buffer); + return WEECHAT_RC_OK; + } + + return WEECHAT_RC_OK; +} + +/* + * Callback called when trigger buffer is closed. + */ + +int +trigger_buffer_close_cb (void *data, struct t_gui_buffer *buffer) +{ + /* make C compiler happy */ + (void) data; + (void) buffer; + + trigger_buffer = NULL; + + return WEECHAT_RC_OK; +} + +/* + * Restore buffer callbacks (input and close) for buffer created by trigger + * plugin. + */ + +void +trigger_buffer_set_callbacks () +{ + struct t_gui_buffer *ptr_buffer; + + ptr_buffer = weechat_buffer_search (TRIGGER_PLUGIN_NAME, + TRIGGER_BUFFER_NAME); + if (ptr_buffer) + { + trigger_buffer = ptr_buffer; + weechat_buffer_set_pointer (trigger_buffer, "close_callback", + &trigger_buffer_close_cb); + weechat_buffer_set_pointer (trigger_buffer, "input_callback", + &trigger_buffer_input_cb); + } +} + +/* + * Opens script buffer. + */ + +void +trigger_buffer_open (int switch_to_buffer) +{ + if (!trigger_buffer) + { + trigger_buffer = weechat_buffer_new (TRIGGER_BUFFER_NAME, + &trigger_buffer_input_cb, NULL, + &trigger_buffer_close_cb, NULL); + + /* failed to create buffer ? then return */ + if (!trigger_buffer) + return; + + weechat_buffer_set (trigger_buffer, "title", _("Trigger monitor")); + + if (!weechat_buffer_get_integer (trigger_buffer, "short_name_is_set")) + weechat_buffer_set (trigger_buffer, "short_name", TRIGGER_BUFFER_NAME); + weechat_buffer_set (trigger_buffer, "localvar_set_type", "debug"); + weechat_buffer_set (trigger_buffer, "localvar_set_server", TRIGGER_BUFFER_NAME); + weechat_buffer_set (trigger_buffer, "localvar_set_channel", TRIGGER_BUFFER_NAME); + weechat_buffer_set (trigger_buffer, "localvar_set_no_log", "1"); + + /* disable all highlights on this buffer */ + weechat_buffer_set (trigger_buffer, "highlight_words", "-"); + } + + if (switch_to_buffer) + weechat_buffer_set (trigger_buffer, "display", "1"); +} diff --git a/src/plugins/trigger/trigger-buffer.h b/src/plugins/trigger/trigger-buffer.h new file mode 100644 index 000000000..1c480191b --- /dev/null +++ b/src/plugins/trigger/trigger-buffer.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_TRIGGER_BUFFER_H +#define __WEECHAT_TRIGGER_BUFFER_H 1 + +#define TRIGGER_BUFFER_NAME "monitor" + +struct t_gui_buffer *trigger_buffer; + +extern void trigger_buffer_display_trigger (struct t_trigger *trigger, + struct t_gui_buffer *buffer, + struct t_hashtable *pointers, + struct t_hashtable *extra_vars); +extern void trigger_buffer_set_callbacks (); +extern void trigger_buffer_open (int switch_to_buffer); + +#endif /* __WEECHAT_TRIGGER_BUFFER_H */ diff --git a/src/plugins/trigger/trigger-callback.c b/src/plugins/trigger/trigger-callback.c new file mode 100644 index 000000000..a0bc08791 --- /dev/null +++ b/src/plugins/trigger/trigger-callback.c @@ -0,0 +1,913 @@ +/* + * trigger-callback.c - callbacks for triggers + * + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "../weechat-plugin.h" +#include "trigger.h" +#include "trigger-callback.h" +#include "trigger-buffer.h" + + +/* one hashtable by hook, used in callback to evaluate "conditions" */ +struct t_hashtable *trigger_callback_hashtable_options = NULL; + + +/* + * Parses an IRC message. + * + * Returns a hashtable with the parsed message, or NULL if error. + * + * Note: the hashtable must be freed after use. + */ + +struct t_hashtable * +trigger_callback_irc_message_parse (const char *irc_message, + const char *irc_server) +{ + struct t_hashtable *hashtable_in, *hashtable_out; + + hashtable_out = NULL; + + hashtable_in = weechat_hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + if (hashtable_in) + { + weechat_hashtable_set (hashtable_in, "message", irc_message); + weechat_hashtable_set (hashtable_in, "server", irc_server); + hashtable_out = weechat_info_get_hashtable ("irc_message_parse", + hashtable_in); + weechat_hashtable_free (hashtable_in); + } + + return hashtable_out; +} +/* + * Sets variables in "extra_vars" hashtable using tags from message. + * + * Returns: + * 0: tag "no_trigger" was in tags, callback must NOT be executed + * 1: no tag "no_trigger", callback can be executed + */ + +int +trigger_callback_set_tags (struct t_gui_buffer *buffer, + const char **tags, int tags_count, + struct t_hashtable *extra_vars) +{ + const char *localvar_type; + char str_temp[128]; + int i; + + snprintf (str_temp, sizeof (str_temp), "%d", tags_count); + weechat_hashtable_set (extra_vars, "tg_tags_count", str_temp); + localvar_type = (buffer) ? + weechat_buffer_get_string (buffer, "localvar_type") : NULL; + + for (i = 0; i < tags_count; i++) + { + if (strcmp (tags[i], "no_trigger") == 0) + { + return 0; + } + else if (strncmp (tags[i], "notify_", 7) == 0) + { + weechat_hashtable_set (extra_vars, "tg_tag_notify", tags[i] + 7); + if (strcmp (tags[i] + 7, "private") == 0) + { + snprintf (str_temp, sizeof (str_temp), "%d", + (localvar_type + && (strcmp (localvar_type, "private") == 0)) ? 1 : 0); + weechat_hashtable_set (extra_vars, "tg_msg_pv", str_temp); + } + } + else if (strncmp (tags[i], "nick_", 5) == 0) + { + weechat_hashtable_set (extra_vars, "tg_tag_nick", tags[i] + 5); + } + else if (strncmp (tags[i], "prefix_nick_", 12) == 0) + { + weechat_hashtable_set (extra_vars, "tg_tag_prefix_nick", + tags[i] + 12); + } + } + + return 1; +} + +/* + * Checks conditions for a trigger. + * + * Returns: + * 1: conditions are true (or no condition set in trigger) + * 0: conditions are false + */ + +int +trigger_callback_check_conditions (struct t_trigger *trigger, + struct t_hashtable *pointers, + struct t_hashtable *extra_vars) +{ + const char *conditions; + char *value; + int rc; + + conditions = weechat_config_string (trigger->options[TRIGGER_OPTION_CONDITIONS]); + if (!conditions || !conditions[0]) + return 1; + + value = weechat_string_eval_expression (conditions, + pointers, + extra_vars, + trigger_callback_hashtable_options); + rc = (value && (strcmp (value, "1") == 0)); + if (value) + free (value); + + return rc; +} + +/* + * Replaces text using one or more regex in the trigger. + */ + +void +trigger_callback_replace_regex (struct t_trigger *trigger, + struct t_hashtable *pointers, + struct t_hashtable *extra_vars) +{ + char *value, *replace_eval; + const char *ptr_key, *ptr_value; + int i; + + if (trigger->regex_count == 0) + return; + + for (i = 0; i < trigger->regex_count; i++) + { + /* if regex is not set (invalid), skip it */ + if (!trigger->regex[i].regex) + continue; + + ptr_key = (trigger->regex[i].variable) ? + trigger->regex[i].variable : + trigger_hook_regex_default_var[weechat_config_integer (trigger->options[TRIGGER_OPTION_HOOK])]; + if (!ptr_key || !ptr_key[0]) + { + if (trigger_buffer) + { + weechat_printf_tags (trigger_buffer, "no_trigger", + "\t regex %d: %s", + i + 1, _("no variable")); + } + continue; + } + + ptr_value = weechat_hashtable_get (extra_vars, ptr_key); + if (!ptr_value) + { + if (trigger_buffer) + { + weechat_printf_tags (trigger_buffer, "no_trigger", + "\t regex %d (%s): %s", + i + 1, ptr_key, _("empty variable")); + } + continue; + } + + replace_eval = weechat_string_eval_expression ( + trigger->regex[i].replace_escaped, + pointers, + extra_vars, + NULL); + if (replace_eval) + { + value = weechat_string_replace_regex (ptr_value, + trigger->regex[i].regex, + replace_eval, + '$'); + if (value) + { + /* display debug info on trigger buffer */ + if (trigger_buffer) + { + weechat_printf_tags (trigger_buffer, "no_trigger", + "\t regex %d %s(%s%s%s)%s: " + "%s\"%s%s%s\"", + i + 1, + weechat_color ("chat_delimiters"), + weechat_color ("reset"), + ptr_key, + weechat_color ("chat_delimiters"), + weechat_color ("reset"), + weechat_color ("chat_delimiters"), + weechat_color ("reset"), + value, + weechat_color ("chat_delimiters")); + } + weechat_hashtable_set (extra_vars, ptr_key, value); + free (value); + } + free (replace_eval); + } + } +} + +/* + * Executes the trigger command(s). + */ + +void +trigger_callback_run_command (struct t_trigger *trigger, + struct t_gui_buffer *buffer, + struct t_hashtable *pointers, + struct t_hashtable *extra_vars) +{ + char *command_eval; + int i; + + if (!trigger->commands) + return; + + if (!buffer) + { + buffer = weechat_buffer_search_main (); + if (!buffer) + return; + } + + for (i = 0; trigger->commands[i]; i++) + { + command_eval = weechat_string_eval_expression (trigger->commands[i], + pointers, extra_vars, + NULL); + if (command_eval) + { + /* display debug info on trigger buffer */ + if (trigger_buffer) + { + weechat_printf_tags (trigger_buffer, "no_trigger", + _("%s running command %s\"%s%s%s\"%s " + "on buffer %s%s%s"), + "\t", + weechat_color ("chat_delimiters"), + weechat_color ("reset"), + command_eval, + weechat_color ("chat_delimiters"), + weechat_color ("reset"), + weechat_color ("chat_buffer"), + weechat_buffer_get_string (buffer, + "full_name"), + weechat_color ("reset")); + } + weechat_command (buffer, command_eval); + trigger->hook_count_cmd++; + } + free (command_eval); + } +} + +/* + * Executes a trigger. + * + * Following actions are executed: + * 1. display debug info on trigger buffer + * 2. check conditions (if false, exit) + * 3. replace text with regex + * 4. execute command(s) + */ + +void +trigger_callback_execute (struct t_trigger *trigger, + struct t_gui_buffer *buffer, + struct t_hashtable *pointers, + struct t_hashtable *extra_vars) +{ + /* display debug info on trigger buffer */ + if (!trigger_buffer && (weechat_trigger_plugin->debug >= 1)) + trigger_buffer_open (0); + trigger_buffer_display_trigger (trigger, buffer, pointers, extra_vars); + + /* check conditions */ + if (trigger_callback_check_conditions (trigger, pointers, extra_vars)) + { + /* replace text with regex */ + trigger_callback_replace_regex (trigger, pointers, extra_vars); + + /* execute command(s) */ + trigger_callback_run_command (trigger, buffer, pointers, extra_vars); + } +} + +/* + * Callback for a signal hooked. + */ + +int +trigger_callback_signal_cb (void *data, const char *signal, + const char *type_data, void *signal_data) +{ + const char *ptr_signal_data; + char str_data[128], *irc_server; + const char *pos, *ptr_irc_message; + + TRIGGER_CALLBACK_CB_INIT(WEECHAT_RC_OK); + + /* split IRC message (if signal_data is an IRC message) */ + irc_server = NULL; + ptr_irc_message = NULL; + if (strcmp (type_data, WEECHAT_HOOK_SIGNAL_STRING) == 0) + { + if (strstr (signal, ",irc_in_") + || strstr (signal, ",irc_in2_") + || strstr (signal, ",irc_raw_in_") + || strstr (signal, ",irc_raw_in2_") + || strstr (signal, ",irc_out1_") + || strstr (signal, ",irc_out_")) + { + pos = strchr (signal, ','); + if (pos) + { + irc_server = weechat_strndup (signal, pos - signal); + ptr_irc_message = (const char *)signal_data; + } + } + else + { + pos = strstr (signal, ",irc_outtags_"); + if (pos) + { + irc_server = weechat_strndup (signal, pos - signal); + pos = strchr ((const char *)signal_data, ';'); + if (pos) + ptr_irc_message = pos + 1; + } + } + } + if (irc_server && ptr_irc_message) + { + extra_vars = trigger_callback_irc_message_parse (ptr_irc_message, + irc_server); + if (extra_vars) + weechat_hashtable_set (extra_vars, "server", irc_server); + } + if (irc_server) + free (irc_server); + + /* create hashtable (if not already created) */ + if (!extra_vars) + { + TRIGGER_CALLBACK_CB_NEW_EXTRA_VARS; + } + + /* add data in hashtable used for conditions/replace/command */ + weechat_hashtable_set (extra_vars, "tg_signal", signal); + if (strcmp (type_data, WEECHAT_HOOK_SIGNAL_STRING) == 0) + { + ptr_signal_data = (const char *)signal_data; + } + else if (strcmp (type_data, WEECHAT_HOOK_SIGNAL_INT) == 0) + { + snprintf (str_data, sizeof (str_data), + "%d", *((int *)signal_data)); + ptr_signal_data = str_data; + } + else if (strcmp (type_data, WEECHAT_HOOK_SIGNAL_POINTER) == 0) + { + str_data[0] = '\0'; + if (signal_data) + { + snprintf (str_data, sizeof (str_data), + "0x%lx", (long unsigned int)signal_data); + } + ptr_signal_data = str_data; + } + weechat_hashtable_set (extra_vars, "tg_signal_data", ptr_signal_data); + + /* execute the trigger (conditions, regex, command) */ + trigger_callback_execute (trigger, NULL, pointers, extra_vars); + +end: + TRIGGER_CALLBACK_CB_END(trigger_rc); +} + +/* + * Callback for a hsignal hooked. + */ + +int +trigger_callback_hsignal_cb (void *data, const char *signal, + struct t_hashtable *hashtable) +{ + const char *type_values; + + TRIGGER_CALLBACK_CB_INIT(WEECHAT_RC_OK); + + /* duplicate hashtable */ + if (hashtable + && (strcmp (weechat_hashtable_get_string (hashtable, "type_keys"), "string") == 0)) + { + type_values = weechat_hashtable_get_string (hashtable, "type_values"); + if (strcmp (type_values, "pointer") == 0) + { + pointers = weechat_hashtable_dup (hashtable); + if (!pointers) + goto end; + } + else if (strcmp (type_values, "pointer") == 0) + { + extra_vars = weechat_hashtable_dup (hashtable); + if (!extra_vars) + goto end; + } + } + + /* create hashtable (if not already created) */ + if (!extra_vars) + { + TRIGGER_CALLBACK_CB_NEW_EXTRA_VARS; + } + + /* add data in hashtable used for conditions/replace/command */ + weechat_hashtable_set (extra_vars, "tg_signal", signal); + + /* execute the trigger (conditions, regex, command) */ + trigger_callback_execute (trigger, NULL, pointers, extra_vars); + +end: + TRIGGER_CALLBACK_CB_END(trigger_rc); +} + +/* + * Callback for a modifier hooked. + */ + +char * +trigger_callback_modifier_cb (void *data, const char *modifier, + const char *modifier_data, const char *string) +{ + struct t_gui_buffer *buffer; + const char *ptr_string; + char *string_modified, *pos, *pos2, *plugin_name, *buffer_name; + char *buffer_full_name, *str_tags, **tags, *prefix, *string_no_color; + int length, num_tags; + + TRIGGER_CALLBACK_CB_INIT(NULL); + + buffer = NULL; + tags = NULL; + num_tags = 0; + string_no_color = NULL; + + /* split IRC message (if string is an IRC message) */ + if ((strncmp (modifier, "irc_in_", 7) == 0) + || (strncmp (modifier, "irc_in2_", 8) == 0) + || (strncmp (modifier, "irc_out1_", 9) == 0) + || (strncmp (modifier, "irc_out_", 8) == 0)) + { + extra_vars = trigger_callback_irc_message_parse (string, + modifier_data); + if (extra_vars) + weechat_hashtable_set (extra_vars, "server", modifier_data); + } + + TRIGGER_CALLBACK_CB_NEW_POINTERS; + if (!extra_vars) + { + TRIGGER_CALLBACK_CB_NEW_EXTRA_VARS; + } + + /* add data in hashtable used for conditions/replace/command */ + weechat_hashtable_set (extra_vars, "tg_modifier", modifier); + weechat_hashtable_set (extra_vars, "tg_modifier_data", modifier_data); + weechat_hashtable_set (extra_vars, "tg_string", string); + string_no_color = weechat_string_remove_color (string, NULL); + if (string_no_color) + { + weechat_hashtable_set (extra_vars, + "tg_string_nocolor", string_no_color); + } + + /* add special variables for a WeeChat message */ + if (strcmp (modifier, "weechat_print") == 0) + { + /* set "tg_prefix" and "tg_message" */ + pos = strchr (string, '\t'); + if (pos) + { + if (pos > string) + { + prefix = weechat_strndup (string, pos - string); + if (prefix) + { + weechat_hashtable_set (extra_vars, "tg_prefix", prefix); + free (prefix); + } + } + pos++; + if (pos[0] == '\t') + pos++; + weechat_hashtable_set (extra_vars, "tg_message", pos); + } + else + weechat_hashtable_set (extra_vars, "tg_message", string); + + /* set "tg_prefix_nocolor" and "tg_message_nocolor" */ + if (string_no_color) + { + pos = strchr (string_no_color, '\t'); + if (pos) + { + if (pos > string_no_color) + { + prefix = weechat_strndup (string_no_color, + pos - string_no_color); + if (prefix) + { + weechat_hashtable_set (extra_vars, + "tg_prefix_nocolor", prefix); + free (prefix); + } + } + pos++; + if (pos[0] == '\t') + pos++; + weechat_hashtable_set (extra_vars, "tg_message_nocolor", pos); + } + else + { + weechat_hashtable_set (extra_vars, + "tg_message_nocolor", string_no_color); + } + } + + /* + * extract buffer/tags from modifier data + * (format: "plugin;buffer_name;tags") + */ + pos = strchr (modifier_data, ';'); + if (pos) + { + plugin_name = weechat_strndup (modifier_data, pos - modifier_data); + if (plugin_name) + { + weechat_hashtable_set (extra_vars, "tg_plugin", plugin_name); + pos++; + pos2 = strchr (pos, ';'); + if (pos2) + { + buffer_name = weechat_strndup (pos, pos2 - pos); + if (buffer_name) + { + buffer = weechat_buffer_search (plugin_name, + buffer_name); + length = strlen (plugin_name) + 1 + strlen (buffer_name) + 1; + buffer_full_name = malloc (length); + if (buffer_full_name) + { + snprintf (buffer_full_name, length, + "%s.%s", plugin_name, buffer_name); + weechat_hashtable_set (extra_vars, "tg_buffer", + buffer_full_name); + free (buffer_full_name); + } + free (buffer_name); + } + pos2++; + if (pos2[0]) + { + tags = weechat_string_split (pos2, ",", 0, 0, &num_tags); + length = 1 + strlen (pos2) + 1 + 1; + str_tags = malloc (length); + if (str_tags) + { + snprintf (str_tags, length, ",%s,", pos2); + weechat_hashtable_set (extra_vars, "tg_tags", + str_tags); + free (str_tags); + } + } + } + free (plugin_name); + } + } + weechat_hashtable_set (pointers, "buffer", buffer); + } + + if (tags) + { + if (!trigger_callback_set_tags (buffer, (const char **)tags, num_tags, + extra_vars)) + { + goto end; + } + } + + /* execute the trigger (conditions, regex, command) */ + trigger_callback_execute (trigger, buffer, pointers, extra_vars); + +end: + ptr_string = weechat_hashtable_get (extra_vars, "tg_string"); + string_modified = (ptr_string && (strcmp (ptr_string, string) != 0)) ? + strdup (ptr_string) : NULL; + + if (tags) + weechat_string_free_split (tags); + if (string_no_color) + free (string_no_color); + + TRIGGER_CALLBACK_CB_END(string_modified); +} + +/* + * Callback for a print hooked. + */ + +int +trigger_callback_print_cb (void *data, struct t_gui_buffer *buffer, + time_t date, int tags_count, const char **tags, + int displayed, int highlight, const char *prefix, + const char *message) +{ + char *str_tags, *str_tags2, str_temp[128], *str_no_color; + int length; + struct tm *date_tmp; + + TRIGGER_CALLBACK_CB_INIT(WEECHAT_RC_OK); + + /* do nothing if the buffer does not match buffers defined in the trigger */ + if (trigger->hook_print_buffers + && !weechat_buffer_match_list (buffer, trigger->hook_print_buffers)) + goto end; + + TRIGGER_CALLBACK_CB_NEW_POINTERS; + TRIGGER_CALLBACK_CB_NEW_EXTRA_VARS; + + /* add data in hashtables used for conditions/replace/command */ + weechat_hashtable_set (pointers, "buffer", buffer); + date_tmp = localtime (&date); + if (date_tmp) + { + strftime (str_temp, sizeof (str_temp), "%Y-%m-%d %H:%M:%S", date_tmp); + weechat_hashtable_set (extra_vars, "tg_date", str_temp); + } + snprintf (str_temp, sizeof (str_temp), "%d", displayed); + weechat_hashtable_set (extra_vars, "tg_displayed", str_temp); + snprintf (str_temp, sizeof (str_temp), "%d", highlight); + weechat_hashtable_set (extra_vars, "tg_highlight", str_temp); + weechat_hashtable_set (extra_vars, "tg_prefix", prefix); + str_no_color = weechat_string_remove_color (prefix, NULL); + if (str_no_color) + { + weechat_hashtable_set (extra_vars, "tg_prefix_nocolor", str_no_color); + free (str_no_color); + } + weechat_hashtable_set (extra_vars, "tg_message", message); + str_no_color = weechat_string_remove_color (message, NULL); + if (str_no_color) + { + weechat_hashtable_set (extra_vars, "tg_message_nocolor", str_no_color); + free (str_no_color); + } + + str_tags = weechat_string_build_with_split_string (tags, ","); + if (str_tags) + { + /* build string with tags and commas around: ",tag1,tag2,tag3," */ + length = 1 + strlen (str_tags) + 1 + 1; + str_tags2 = malloc (length); + if (str_tags2) + { + snprintf (str_tags2, length, ",%s,", str_tags); + weechat_hashtable_set (extra_vars, "tg_tags", str_tags2); + free (str_tags2); + } + free (str_tags); + } + if (!trigger_callback_set_tags (buffer, tags, tags_count, extra_vars)) + goto end; + + /* execute the trigger (conditions, regex, command) */ + trigger_callback_execute (trigger, buffer, pointers, extra_vars); + +end: + TRIGGER_CALLBACK_CB_END(trigger_rc); +} + +/* + * Callback for a command hooked. + */ + +int +trigger_callback_command_cb (void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol) +{ + char str_name[32]; + int i; + + TRIGGER_CALLBACK_CB_INIT(WEECHAT_RC_OK); + + TRIGGER_CALLBACK_CB_NEW_POINTERS; + TRIGGER_CALLBACK_CB_NEW_EXTRA_VARS; + + /* add data in hashtables used for conditions/replace/command */ + weechat_hashtable_set (pointers, "buffer", buffer); + for (i = 0; i < argc; i++) + { + snprintf (str_name, sizeof (str_name), "tg_argv%d", i); + weechat_hashtable_set (extra_vars, str_name, argv[i]); + snprintf (str_name, sizeof (str_name), "tg_argv_eol%d", i); + weechat_hashtable_set (extra_vars, str_name, argv_eol[i]); + } + + /* execute the trigger (conditions, regex, command) */ + trigger_callback_execute (trigger, buffer, pointers, extra_vars); + +end: + TRIGGER_CALLBACK_CB_END(trigger_rc); +} + +/* + * Callback for a command_run hooked. + */ + +int +trigger_callback_command_run_cb (void *data, struct t_gui_buffer *buffer, + const char *command) +{ + TRIGGER_CALLBACK_CB_INIT(WEECHAT_RC_OK); + + TRIGGER_CALLBACK_CB_NEW_POINTERS; + TRIGGER_CALLBACK_CB_NEW_EXTRA_VARS; + + /* add data in hashtables used for conditions/replace/command */ + weechat_hashtable_set (pointers, "buffer", buffer); + weechat_hashtable_set (extra_vars, "tg_command", command); + + /* execute the trigger (conditions, regex, command) */ + trigger_callback_execute (trigger, buffer, pointers, extra_vars); + +end: + TRIGGER_CALLBACK_CB_END(trigger_rc); +} + +/* + * Callback for a timer hooked. + */ + +int +trigger_callback_timer_cb (void *data, int remaining_calls) +{ + char str_temp[128]; + int i; + time_t date; + struct tm *date_tmp; + + TRIGGER_CALLBACK_CB_INIT(WEECHAT_RC_OK); + + /* + * remove the hook if this is the last call to timer + * (because WeeChat will remove the hook after this call, so the pointer + * will become invalid) + */ + if ((remaining_calls == 0) && trigger->hooks) + { + for (i = 0; i < trigger->hooks_count; i++) + { + trigger->hooks[i] = NULL; + } + } + + TRIGGER_CALLBACK_CB_NEW_EXTRA_VARS; + + /* add data in hashtable used for conditions/replace/command */ + snprintf (str_temp, sizeof (str_temp), "%d", remaining_calls); + weechat_hashtable_set (extra_vars, "tg_remaining_calls", str_temp); + date = time (NULL); + date_tmp = localtime (&date); + if (date_tmp) + { + strftime (str_temp, sizeof (str_temp), "%Y-%m-%d %H:%M:%S", date_tmp); + weechat_hashtable_set (extra_vars, "tg_date", str_temp); + } + + /* execute the trigger (conditions, regex, command) */ + trigger_callback_execute (trigger, NULL, pointers, extra_vars); + +end: + TRIGGER_CALLBACK_CB_END(trigger_rc); +} + +/* + * Callback for a config hooked. + */ + +int +trigger_callback_config_cb (void *data, const char *option, const char *value) +{ + TRIGGER_CALLBACK_CB_INIT(WEECHAT_RC_OK); + + TRIGGER_CALLBACK_CB_NEW_EXTRA_VARS; + + /* add data in hashtable used for conditions/replace/command */ + weechat_hashtable_set (extra_vars, "tg_option", option); + weechat_hashtable_set (extra_vars, "tg_value", value); + + /* execute the trigger (conditions, regex, command) */ + trigger_callback_execute (trigger, NULL, pointers, extra_vars); + +end: + TRIGGER_CALLBACK_CB_END(trigger_rc); +} + +/* + * Callback for a focus hooked. + */ + +struct t_hashtable * +trigger_callback_focus_cb (void *data, struct t_hashtable *info) +{ + const char *ptr_value; + long unsigned int value; + int rc; + + TRIGGER_CALLBACK_CB_INIT(info); + + TRIGGER_CALLBACK_CB_NEW_POINTERS; + + /* add data in hashtables used for conditions/replace/command */ + ptr_value = weechat_hashtable_get (info, "_window"); + if (ptr_value && ptr_value[0] && (strncmp (ptr_value, "0x", 2) == 0)) + { + rc = sscanf (ptr_value + 2, "%lx", &value); + if ((rc != EOF) && (rc >= 1)) + weechat_hashtable_set (pointers, "window", (void *)value); + } + ptr_value = weechat_hashtable_get (info, "_buffer"); + if (ptr_value && ptr_value[0] && (strncmp (ptr_value, "0x", 2) == 0)) + { + rc = sscanf (ptr_value + 2, "%lx", &value); + if ((rc != EOF) && (rc >= 1)) + weechat_hashtable_set (pointers, "buffer", (void *)value); + } + + /* execute the trigger (conditions, regex, command) */ + trigger_callback_execute (trigger, NULL, pointers, info); + +end: + TRIGGER_CALLBACK_CB_END(info); +} + +/* + * Initializes trigger callback. + */ + +void +trigger_callback_init () +{ + trigger_callback_hashtable_options = weechat_hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + if (trigger_callback_hashtable_options) + { + weechat_hashtable_set (trigger_callback_hashtable_options, + "type", "condition"); + } +} + +/* + * Ends trigger callback. + */ + +void +trigger_callback_end () +{ + if (trigger_callback_hashtable_options) + weechat_hashtable_free (trigger_callback_hashtable_options); +} diff --git a/src/plugins/trigger/trigger-callback.h b/src/plugins/trigger/trigger-callback.h new file mode 100644 index 000000000..29ec9b9d9 --- /dev/null +++ b/src/plugins/trigger/trigger-callback.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_TRIGGER_CALLBACK_H +#define __WEECHAT_TRIGGER_CALLBACK_H 1 + +#define TRIGGER_CALLBACK_CB_INIT(__rc) \ + struct t_trigger *trigger; \ + struct t_hashtable *pointers, *extra_vars; \ + int trigger_rc; \ + pointers = NULL; \ + extra_vars = NULL; \ + (void) trigger_rc; \ + if (!trigger_enabled) \ + return __rc; \ + trigger = (struct t_trigger *)data; \ + if (!trigger || trigger->hook_running) \ + return __rc; \ + trigger->hook_count_cb++; \ + trigger->hook_running = 1; \ + trigger_rc = trigger_return_code[ \ + weechat_config_integer ( \ + trigger->options[TRIGGER_OPTION_RETURN_CODE])]; + +#define TRIGGER_CALLBACK_CB_NEW_POINTERS \ + pointers = weechat_hashtable_new ( \ + 32, \ + WEECHAT_HASHTABLE_STRING, \ + WEECHAT_HASHTABLE_POINTER, \ + NULL, \ + NULL); \ + if (!pointers) \ + goto end; + +#define TRIGGER_CALLBACK_CB_NEW_EXTRA_VARS \ + extra_vars = weechat_hashtable_new ( \ + 32, \ + WEECHAT_HASHTABLE_STRING, \ + WEECHAT_HASHTABLE_STRING, \ + NULL, \ + NULL); \ + if (!extra_vars) \ + goto end; + +#define TRIGGER_CALLBACK_CB_END(__rc) \ + if (pointers) \ + weechat_hashtable_free (pointers); \ + if (extra_vars) \ + weechat_hashtable_free (extra_vars); \ + trigger->hook_running = 0; \ + return __rc; + +extern int trigger_callback_signal_cb (void *data, const char *signal, + const char *type_data, void *signal_data); +extern int trigger_callback_hsignal_cb (void *data, const char *signal, + struct t_hashtable *hashtable); +extern char *trigger_callback_modifier_cb (void *data, const char *modifier, + const char *modifier_data, + const char *string); +extern int trigger_callback_print_cb (void *data, struct t_gui_buffer *buffer, + time_t date, int tags_count, + const char **tags, int displayed, + int highlight, const char *prefix, + const char *message); +extern int trigger_callback_command_cb (void *data, struct t_gui_buffer *buffer, + int argc, char **argv, char **argv_eol); +extern int trigger_callback_command_run_cb (void *data, + struct t_gui_buffer *buffer, + const char *command); +extern int trigger_callback_timer_cb (void *data, int remaining_calls); +extern int trigger_callback_config_cb (void *data, const char *option, + const char *value); +extern struct t_hashtable *trigger_callback_focus_cb (void *data, + struct t_hashtable *info); +extern void trigger_callback_init (); +extern void trigger_callback_end (); + +#endif /* __WEECHAT_TRIGGER_CALLBACK_H */ diff --git a/src/plugins/trigger/trigger-command.c b/src/plugins/trigger/trigger-command.c new file mode 100644 index 000000000..15e333446 --- /dev/null +++ b/src/plugins/trigger/trigger-command.c @@ -0,0 +1,990 @@ +/* + * trigger-command.c - trigger command + * + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#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++) + { + trigger_split_regex (trigger_config_default_list[i][0], + trigger_config_default_list[i][5], + ®ex_count, + ®ex); + 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_free_regex (®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; + char *value, **sargv, **items, input[1024], str_pos[16]; + int rc, i, type, count, index_option, enable, sargc, num_items, add_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 > 6) && (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 <name> <hook> [\"<arguments>\" " + "[\"<conditions>\" [\"<regex>\" [\"<command>\" " + "[\"<return_code>\"]]]]]" + " || addinput [<hook>]" + " || input|output|recreate <name>" + " || set <name> <option> <value>" + " || rename|copy <name> <new_name>" + " || enable|disable|toggle [<name>|-all [<name>...]]" + " || restart <name>|-all [<name>...]" + " || show <name>" + " || del <name>|-all [<name>...]" + " || default -yes" + " || monitor"), + N_(" list: list triggers (without argument, this list is displayed)\n" + " listfull: list triggers with detailed info for each trigger\n" + "listdefault: list default triggers\n" + " add: add a trigger\n" + " addoff: add a trigger (disabled)\n" + " addreplace: add or replace an existing trigger\n" + " name: name of trigger\n" + " hook: signal, hsignal, modifier, print, command, command_run, " + "timer, config, focus\n" + " arguments: arguments for the hook, depending on hook (separated " + "by semicolons):\n" + " signal: name(s) of signal (required)\n" + " hsignal: name(s) of hsignal (required)\n" + " modifier: name(s) of modifier (required)\n" + " print: buffer, tags, message, strip_colors\n" + " command: command (required), description, arguents, " + "description of arguments, completion\n" + " command_run: command (required)\n" + " timer: interval (required), align_second (required), " + "max_calls (required)\n" + " config: name of option (required)\n" + " focus: name(s) of area (required)\n" + " conditions: evaluated conditions for the trigger\n" + " regex: one or more regular expressions to replace strings " + "in variables\n" + " command: command to execute (many commands can be separated by " + "\";\"\n" + "return_code: return code in callback (ok (default), ok_eat, error)\n" + " addinput: set input with default arguments to create a trigger\n" + " input: set input with the command used to create the trigger\n" + " output: send the command to create the trigger on the buffer\n" + " recreate: same as input, with option \"addreplace\" instead of " + "\"add\"\n" + " set: set an option in a trigger\n" + " option: name of option: name, hook, arguments, conditions, " + "regex, command, return_code\n" + " (for help on option, you can do /help " + "trigger.trigger.<name>.<option>)\n" + " value: new value for the option\n" + " rename: rename a trigger\n" + " copy: copy a trigger\n" + " enable: enable trigger(s) (without arguments: enable triggers " + "globally)\n" + " disable: disable trigger(s) (without arguments: disable triggers " + "globally)\n" + " toggle: toggle trigger(s) (without arguments: toggle triggers " + "globally)\n" + " restart: restart trigger(s) (recreate the hooks)\n" + " show: show detailed info on a trigger (with some stats)\n" + " del: delete a trigger\n" + " -all: do action on all triggers\n" + " default: restore default triggers\n" + " monitor: open the trigger monitor buffer\n" + "\n" + "When a trigger callback is called, following actions are performed, " + "in this order:\n" + " 1. check conditions; if false, exit\n" + " 2. replace text using POSIX extended regular expression(s) (if " + "defined in trigger)\n" + " 3. execute command(s) (if defined in trigger)\n" + " 4. exit with a return code (except for modifiers)\n" + "\n" + "Examples (you can also look at default triggers with /trigger " + "listdefault):\n" + " add text attributes *bold*, _underline_ and /italic/ (only in " + "user messages):\n" + " /trigger add effects modifier weechat_print \"${tg_tag_nick}\" " + "\"==\\*(\\S+)\\*==*${color:bold}$1${color:-bold}*== " + "==_(\\S+)_==_${color:underline}$1${color:-underline}_== " + "==/(\\S+)/==/${color:italic}$1${color:-italic}/\"\n" + " hide nicklist bar on small terminals:\n" + " /trigger add resize_small signal signal_sigwinch " + "\"${info:term_width} < 100\" \"\" \"/bar hide nicklist\"\n" + " /trigger add resize_big signal signal_sigwinch " + "\"${info:term_width} >= 100\" \"\" \"/bar show nicklist\"\n" + " silently save config each hour:\n" + " /trigger add cfgsave timer 3600000;0;0 \"\" \"\" \"/mute /save\""), + "list|listfull|listdefault" + " || add|addoff|addreplace %(trigger_names) %(trigger_hooks) " + "%(trigger_hook_arguments) %(trigger_hook_conditions) " + "%(trigger_hook_regex) %(trigger_hook_command) %(trigger_hook_rc)" + " || addinput %(trigger_hooks)" + " || input|output|recreate %(trigger_names)" + " || set %(trigger_names) %(trigger_options)|name %(trigger_option_value)" + " || rename|copy %(trigger_names) %(trigger_names)" + " || enable|disable|toggle|restart|del %(trigger_names)|-all " + "%(trigger_names)|%*" + " || show %(trigger_names)" + " || default" + " || monitor", + &trigger_command_trigger, NULL); +} diff --git a/src/plugins/trigger/trigger-command.h b/src/plugins/trigger/trigger-command.h new file mode 100644 index 000000000..a2ad07f25 --- /dev/null +++ b/src/plugins/trigger/trigger-command.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_TRIGGER_COMMAND_H +#define __WEECHAT_TRIGGER_COMMAND_H 1 + +extern void trigger_command_init (); + +#endif /* __WEECHAT_TRIGGER_COMMAND_H */ diff --git a/src/plugins/trigger/trigger-completion.c b/src/plugins/trigger/trigger-completion.c new file mode 100644 index 000000000..aaa3ab8d5 --- /dev/null +++ b/src/plugins/trigger/trigger-completion.c @@ -0,0 +1,392 @@ +/* + * trigger-completion.c - completion for trigger commands + * + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "trigger.h" + + +/* + * Adds triggers to completion list. + */ + +int +trigger_completion_triggers_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_trigger *ptr_trigger; + + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + for (ptr_trigger = triggers; ptr_trigger; + ptr_trigger = ptr_trigger->next_trigger) + { + weechat_hook_completion_list_add (completion, ptr_trigger->name, + 0, WEECHAT_LIST_POS_SORT); + } + + return WEECHAT_RC_OK; +} + +/* + * Adds options for triggers to completion list. + */ + +int +trigger_completion_options_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + int i; + + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + weechat_hook_completion_list_add (completion, + trigger_option_string[i], + 0, WEECHAT_LIST_POS_SORT); + } + + return WEECHAT_RC_OK; +} + +/* + * Adds value of a trigger option to completion list. + */ + +int +trigger_completion_option_value_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + const char *args; + char **argv; + int argc, index_option; + struct t_trigger *ptr_trigger; + + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + args = weechat_hook_completion_get_string (completion, "args"); + if (!args) + return WEECHAT_RC_OK; + + argv = weechat_string_split (args, " ", 0, 0, &argc); + if (!argv) + return WEECHAT_RC_OK; + + if (argc >= 3) + { + ptr_trigger = trigger_search (argv[1]); + if (ptr_trigger) + { + if (weechat_strcasecmp (argv[2], "name") == 0) + { + weechat_hook_completion_list_add (completion, + ptr_trigger->name, + 0, + WEECHAT_LIST_POS_BEGINNING); + } + else + { + index_option = trigger_search_option (argv[2]); + if (index_option >= 0) + { + weechat_hook_completion_list_add (completion, + weechat_config_string (ptr_trigger->options[index_option]), + 0, + WEECHAT_LIST_POS_BEGINNING); + } + } + } + } + + weechat_string_free_split (argv); + + return WEECHAT_RC_OK; +} + +/* + * Adds hooks for triggers to completion list. + */ + +int +trigger_completion_hooks_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + int i; + + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + for (i = 0; i < TRIGGER_NUM_HOOK_TYPES; i++) + { + weechat_hook_completion_list_add (completion, + trigger_hook_type_string[i], + 0, WEECHAT_LIST_POS_END); + } + + return WEECHAT_RC_OK; +} + +/* + * Adds a word with quotes around to completion list. + */ + +void +trigger_completion_add_quoted_word (struct t_gui_completion *completion, + const char *word) +{ + char *temp; + int length; + + length = 1 + strlen (word) + 1 + 1; + temp = malloc (length); + if (!temp) + return; + + snprintf (temp, length, "\"%s\"", word); + weechat_hook_completion_list_add (completion, temp, 0, + WEECHAT_LIST_POS_END); + + free (temp); +} + +/* + * Adds a default string to completion list, depending on hook type. + * + * If split is not NULL, the default string found is split using this separator, + * and therefore many words can be added to completion list. + */ + +void +trigger_completion_add_default_for_hook (struct t_gui_completion *completion, + char *default_strings[], char *split) +{ + const char *args; + char **argv, **items; + int argc, num_items, type, i; + + args = weechat_hook_completion_get_string (completion, "args"); + if (!args) + return; + + argv = weechat_string_split (args, " ", 0, 0, &argc); + if (!argv) + return; + + if (argc >= 3) + { + type = trigger_search_hook_type (argv[2]); + if (type >= 0) + { + if (default_strings[type][0] && split && split[0]) + { + items = weechat_string_split (default_strings[type], split, + 0, 0, &num_items); + if (items) + { + for (i = 0; i < num_items; i++) + { + trigger_completion_add_quoted_word (completion, + items[i]); + } + weechat_string_free_split (items); + } + } + else + { + trigger_completion_add_quoted_word (completion, + default_strings[type]); + } + } + } + + weechat_string_free_split (argv); +} + +/* + * Adds default arguments for hook to completion list. + */ + +int +trigger_completion_hook_arguments_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + trigger_completion_add_default_for_hook (completion, + trigger_hook_default_arguments, + NULL); + weechat_hook_completion_list_add (completion, "\"\"", 0, + WEECHAT_LIST_POS_END); + + return WEECHAT_RC_OK; +} + +/* + * Adds default conditions for hook to completion list. + */ + +int +trigger_completion_hook_conditions_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + weechat_hook_completion_list_add (completion, + "\"" TRIGGER_HOOK_DEFAULT_CONDITIONS "\"", + 0, + WEECHAT_LIST_POS_END); + weechat_hook_completion_list_add (completion, "\"\"", 0, + WEECHAT_LIST_POS_END); + + return WEECHAT_RC_OK; +} + +/* + * Adds default regular expression for hook to completion list. + */ + +int +trigger_completion_hook_regex_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + weechat_hook_completion_list_add (completion, + "\"" TRIGGER_HOOK_DEFAULT_REGEX "\"", + 0, + WEECHAT_LIST_POS_END); + weechat_hook_completion_list_add (completion, "\"\"", 0, + WEECHAT_LIST_POS_END); + + return WEECHAT_RC_OK; +} + +/* + * Adds default command for hook to completion list. + */ + +int +trigger_completion_hook_command_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + weechat_hook_completion_list_add (completion, + "\"" TRIGGER_HOOK_DEFAULT_COMMAND "\"", + 0, + WEECHAT_LIST_POS_END); + weechat_hook_completion_list_add (completion, "\"\"", 0, + WEECHAT_LIST_POS_END); + + return WEECHAT_RC_OK; +} + +/* + * Adds default return code(s) for hook to completion list. + */ + +int +trigger_completion_hook_rc_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + trigger_completion_add_default_for_hook (completion, + trigger_hook_default_rc, + ","); + + return WEECHAT_RC_OK; +} + +/* + * Hooks completions. + */ + +void +trigger_completion_init () +{ + weechat_hook_completion ("trigger_names", + N_("triggers"), + &trigger_completion_triggers_cb, NULL); + weechat_hook_completion ("trigger_options", + N_("options for triggers"), + &trigger_completion_options_cb, NULL); + weechat_hook_completion ("trigger_option_value", + N_("value of a trigger option"), + &trigger_completion_option_value_cb, NULL); + weechat_hook_completion ("trigger_hooks", + N_("hooks for triggers"), + &trigger_completion_hooks_cb, NULL); + weechat_hook_completion ("trigger_hook_arguments", + N_("default arguments for a hook"), + &trigger_completion_hook_arguments_cb, NULL); + weechat_hook_completion ("trigger_hook_conditions", + N_("default conditions for a hook"), + &trigger_completion_hook_conditions_cb, NULL); + weechat_hook_completion ("trigger_hook_regex", + N_("default regular expression for a hook"), + &trigger_completion_hook_regex_cb, NULL); + weechat_hook_completion ("trigger_hook_command", + N_("default command for a hook"), + &trigger_completion_hook_command_cb, NULL); + weechat_hook_completion ("trigger_hook_rc", + N_("default return codes for hook callback"), + &trigger_completion_hook_rc_cb, NULL); +} diff --git a/src/plugins/trigger/trigger-completion.h b/src/plugins/trigger/trigger-completion.h new file mode 100644 index 000000000..17dcccf9c --- /dev/null +++ b/src/plugins/trigger/trigger-completion.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_TRIGGER_COMPLETION_H +#define __WEECHAT_TRIGGER_COMPLETION_H 1 + +extern void trigger_completion_init (); + +#endif /* __WEECHAT_TRIGGER_COMPLETION_H */ diff --git a/src/plugins/trigger/trigger-config.c b/src/plugins/trigger/trigger-config.c new file mode 100644 index 000000000..a9cfe7e09 --- /dev/null +++ b/src/plugins/trigger/trigger-config.c @@ -0,0 +1,692 @@ +/* + * trigger-config.c - trigger configuration options (file trigger.conf) + * + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "trigger.h" +#include "trigger-config.h" + + +struct t_config_file *trigger_config_file = NULL; +struct t_config_section *trigger_config_section_trigger = NULL; + +/* trigger config, look section */ + +struct t_config_option *trigger_config_look_enabled; +struct t_config_option *trigger_config_look_monitor_strip_colors; + +/* trigger config, color section */ + +struct t_config_option *trigger_config_color_flag_command; +struct t_config_option *trigger_config_color_flag_conditions; +struct t_config_option *trigger_config_color_flag_regex; +struct t_config_option *trigger_config_color_flag_return_code; +struct t_config_option *trigger_config_color_regex; +struct t_config_option *trigger_config_color_replace; +struct t_config_option *trigger_config_color_trigger; +struct t_config_option *trigger_config_color_trigger_disabled; + +char *trigger_config_default_list[][1 + TRIGGER_NUM_OPTIONS] = +{ + /* beep on highlight/private message */ + { "beep", "on", + "print", + "", + "${tg_highlight} || ${tg_msg_pv}", + "", + "/print -stderr \\a", + "ok" }, + /* hide passwords in commands */ + { "cmd_pass", "on", + "modifier", + "5000|input_text_display;5000|history_add;5000|irc_command_auth", + "", + "==^(" + "(/(msg|quote) +nickserv " + "+(id|identify|register|ghost \\S+|release \\S+|regain \\S+) +)|" + "/oper +\\S+ +|" + "/quote pass +|" + "/set +\\S*password\\S* +|" + "/secure +(passphrase|decrypt|set \\S+) +)" + "(.*)" + "==$1$.*+", + "", + "" }, + /* hide password in IRC auth message displayed */ + { "msg_auth", "on", + "modifier", + "5000|irc_message_auth", + "", + "==^(.*(id|identify|register|ghost \\S+|release \\S+) +)(.*)==$1$.*+", + "", + "" }, + /* hide server password in commands /server and /connect */ + { "server_pass", "on", + "modifier", + "5000|input_text_display;5000|history_add", + "", + "==^(/(server|connect) .*-(sasl_)?password=)(\\S+)(.*)==$1$.*4$5" + "", + "" }, + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, +}; + + +/* + * Callback for changes on option "trigger.look.enabled". + */ + +void +trigger_config_change_enabled (void *data, struct t_config_option *option) +{ + /* make C compiler happy */ + (void) data; + + trigger_enabled = weechat_config_boolean (option); +} + +/* + * Callback for changes on option "trigger.trigger.xxx.enabled". + */ + +void +trigger_config_change_trigger_enabled (void *data, + struct t_config_option *option) +{ + struct t_trigger *ptr_trigger; + + /* make C compiler happy */ + (void) data; + + ptr_trigger = trigger_search_with_option (option); + if (!ptr_trigger) + return; + + if (weechat_config_boolean (option)) + trigger_hook (ptr_trigger); + else + trigger_unhook (ptr_trigger); +} + +/* + * Callback for changes on option "trigger.trigger.xxx.hook". + */ + +void +trigger_config_change_trigger_hook (void *data, struct t_config_option *option) +{ + struct t_trigger *ptr_trigger; + + /* make C compiler happy */ + (void) data; + + ptr_trigger = trigger_search_with_option (option); + if (!ptr_trigger) + return; + + if (ptr_trigger->options[TRIGGER_OPTION_ARGUMENTS]) + trigger_hook (ptr_trigger); +} + +/* + * Callback for changes on option "trigger.trigger.xxx.arguments". + */ + +void +trigger_config_change_trigger_arguments (void *data, + struct t_config_option *option) +{ + struct t_trigger *ptr_trigger; + + /* make C compiler happy */ + (void) data; + + ptr_trigger = trigger_search_with_option (option); + if (!ptr_trigger) + return; + + if (ptr_trigger->options[TRIGGER_OPTION_HOOK]) + trigger_hook (ptr_trigger); +} + +/* + * Callback for changes on option "trigger.trigger.xxx.regex". + */ + +void +trigger_config_change_trigger_regex (void *data, struct t_config_option *option) +{ + struct t_trigger *ptr_trigger; + + /* make C compiler happy */ + (void) data; + + ptr_trigger = trigger_search_with_option (option); + if (!ptr_trigger) + return; + + trigger_split_regex (ptr_trigger->name, weechat_config_string (option), + &ptr_trigger->regex_count, &ptr_trigger->regex); +} + +/* + * Callback for changes on option "trigger.trigger.xxx.command". + */ + +void +trigger_config_change_trigger_command (void *data, + struct t_config_option *option) +{ + struct t_trigger *ptr_trigger; + + /* make C compiler happy */ + (void) data; + + ptr_trigger = trigger_search_with_option (option); + if (!ptr_trigger) + return; + + trigger_split_command (weechat_config_string (option), + &ptr_trigger->commands_count, + &ptr_trigger->commands); +} + +/* + * Creates an option for a trigger. + * + * Returns pointer to new option, NULL if error. + */ + +struct t_config_option * +trigger_config_create_trigger_option (const char *trigger_name, int index_option, + const char *value) +{ + struct t_config_option *ptr_option; + int length; + char *option_name; + + ptr_option = NULL; + + length = strlen (trigger_name) + 1 + + strlen (trigger_option_string[index_option]) + 1; + option_name = malloc (length); + if (!option_name) + return NULL; + + snprintf (option_name, length, "%s.%s", + trigger_name, trigger_option_string[index_option]); + + switch (index_option) + { + case TRIGGER_OPTION_ENABLED: + ptr_option = weechat_config_new_option ( + trigger_config_file, trigger_config_section_trigger, + option_name, "boolean", + N_("if disabled, the hooks are removed from trigger, so it is " + "not called any more"), + NULL, 0, 0, value, NULL, 0, NULL, NULL, + &trigger_config_change_trigger_enabled, NULL, NULL, NULL); + break; + case TRIGGER_OPTION_HOOK: + ptr_option = weechat_config_new_option ( + trigger_config_file, trigger_config_section_trigger, + option_name, "integer", + N_("type of hook used"), + trigger_hook_option_values, + 0, 0, value, NULL, 0, NULL, NULL, + &trigger_config_change_trigger_hook, NULL, NULL, NULL); + break; + case TRIGGER_OPTION_ARGUMENTS: + ptr_option = weechat_config_new_option ( + trigger_config_file, trigger_config_section_trigger, + option_name, "string", + N_("arguments for the hook (depend on the hook type, see /help " + "trigger)"), + NULL, 0, 0, value, NULL, 0, NULL, NULL, + &trigger_config_change_trigger_arguments, NULL, NULL, NULL); + break; + case TRIGGER_OPTION_CONDITIONS: + ptr_option = weechat_config_new_option ( + trigger_config_file, trigger_config_section_trigger, + option_name, "string", + N_("condition(s) for running the command (it is checked in " + "hook callback) (note: content is evaluated when trigger is " + "run, see /help eval)"), + NULL, 0, 0, value, NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + case TRIGGER_OPTION_REGEX: + ptr_option = weechat_config_new_option ( + trigger_config_file, trigger_config_section_trigger, + option_name, "string", + N_("replace text with a POSIX extended regular expression (it " + "is done only if conditions are OK, and before running the " + "command) (note: content is evaluated on trigger creation, " + "see /help eval); format is: \"/regex/replace/var\" (var " + "is the hashtable variable to replace, it is optional), " + "many regex can be separated by a space, for example: " + "\"/regex1/replace1/var1 /regex2/replace2/var2\"; the " + "separator \"/\" can be replaced by any char (one or more " + "identical chars), except '\\' and parentheses; matching " + "groups can be used in replace: $0 to $99, $+ for last " + "match and $.cN to replace all chars of group N by char c"), + NULL, 0, 0, value, NULL, 0, NULL, NULL, + &trigger_config_change_trigger_regex, NULL, NULL, NULL); + break; + case TRIGGER_OPTION_COMMAND: + ptr_option = weechat_config_new_option ( + trigger_config_file, trigger_config_section_trigger, + option_name, "string", + N_("command(s) to run if conditions are OK, after regex " + "replacements (many commands can be separated by semicolons)"), + NULL, 0, 0, value, NULL, 0, NULL, NULL, + &trigger_config_change_trigger_command, NULL, NULL, NULL); + break; + case TRIGGER_OPTION_RETURN_CODE: + ptr_option = weechat_config_new_option ( + trigger_config_file, trigger_config_section_trigger, + option_name, "integer", + N_("return code for hook callback (see plugin API reference to " + "know where ok_eat or error can be used efficiently)"), + "ok|ok_eat|error", 0, 0, value, NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + break; + case TRIGGER_NUM_OPTIONS: + break; + } + + free (option_name); + + return ptr_option; +} + +/* + * Creates option for a temporary trigger (when reading configuration file). + */ + +void +trigger_config_create_option_temp (struct t_trigger *temp_trigger, + int index_option, const char *value) +{ + struct t_config_option *new_option; + + new_option = trigger_config_create_trigger_option (temp_trigger->name, + index_option, value); + if (new_option + && (index_option >= 0) && (index_option < TRIGGER_NUM_OPTIONS)) + { + temp_trigger->options[index_option] = new_option; + } +} + +/* + * Uses temporary triggers (created by reading configuration file). + */ + +void +trigger_config_use_temp_triggers () +{ + struct t_trigger *ptr_temp_trigger, *next_temp_trigger; + int i, num_options_ok; + + for (ptr_temp_trigger = triggers_temp; ptr_temp_trigger; + ptr_temp_trigger = ptr_temp_trigger->next_trigger) + { + num_options_ok = 0; + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + if (!ptr_temp_trigger->options[i]) + { + ptr_temp_trigger->options[i] = + trigger_config_create_trigger_option (ptr_temp_trigger->name, + i, + trigger_option_default[i]); + } + if (ptr_temp_trigger->options[i]) + num_options_ok++; + } + + if (num_options_ok == TRIGGER_NUM_OPTIONS) + { + trigger_new_with_options (ptr_temp_trigger->name, + ptr_temp_trigger->options); + } + else + { + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + if (ptr_temp_trigger->options[i]) + { + weechat_config_option_free (ptr_temp_trigger->options[i]); + ptr_temp_trigger->options[i] = NULL; + } + } + } + } + + /* free all temporary triggers */ + while (triggers_temp) + { + next_temp_trigger = triggers_temp->next_trigger; + + if (triggers_temp->name) + free (triggers_temp->name); + free (triggers_temp); + + triggers_temp = next_temp_trigger; + } + last_trigger_temp = NULL; +} + +/* + * Reads a trigger option in trigger configuration file. + */ + +int +trigger_config_trigger_read_cb (void *data, struct t_config_file *config_file, + struct t_config_section *section, + const char *option_name, const char *value) +{ + char *pos_option, *trigger_name; + struct t_trigger *ptr_temp_trigger; + int index_option; + + /* make C compiler happy */ + (void) data; + (void) config_file; + (void) section; + + if (!option_name) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + pos_option = strchr (option_name, '.'); + if (!pos_option) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + trigger_name = weechat_strndup (option_name, pos_option - option_name); + if (!trigger_name) + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; + + pos_option++; + + /* search temporary trigger */ + for (ptr_temp_trigger = triggers_temp; ptr_temp_trigger; + ptr_temp_trigger = ptr_temp_trigger->next_trigger) + { + if (strcmp (ptr_temp_trigger->name, trigger_name) == 0) + break; + } + if (!ptr_temp_trigger) + { + /* create new temporary trigger */ + ptr_temp_trigger = trigger_alloc (trigger_name); + if (ptr_temp_trigger) + trigger_add (ptr_temp_trigger, &triggers_temp, &last_trigger_temp); + } + + if (ptr_temp_trigger) + { + index_option = trigger_search_option (pos_option); + if (index_option >= 0) + { + trigger_config_create_option_temp (ptr_temp_trigger, index_option, + value); + } + else + { + weechat_printf (NULL, + _("%sWarning: unknown option for section \"%s\": " + "%s (value: \"%s\")"), + weechat_prefix ("error"), + TRIGGER_CONFIG_SECTION_TRIGGER, + option_name, value); + } + } + + free (trigger_name); + + return WEECHAT_CONFIG_OPTION_SET_OK_SAME_VALUE; +} + +/* + * Writes default triggers in trigger configuration file. + */ + +int +trigger_config_trigger_write_default_cb (void *data, + struct t_config_file *config_file, + const char *section_name) +{ + int i, j, quotes; + char option_name[512]; + + /* make C compiler happy */ + (void) data; + + if (!weechat_config_write_line (config_file, section_name, NULL)) + return WEECHAT_CONFIG_WRITE_ERROR; + + for (i = 0; trigger_config_default_list[i][0]; i++) + { + for (j = 0; j < TRIGGER_NUM_OPTIONS; j++) + { + snprintf (option_name, sizeof (option_name), + "%s.%s", + trigger_config_default_list[i][0], + trigger_option_string[j]); + quotes = (j & (TRIGGER_OPTION_ARGUMENTS | TRIGGER_OPTION_CONDITIONS | + TRIGGER_OPTION_REGEX | TRIGGER_OPTION_COMMAND)); + if (!weechat_config_write_line (config_file, option_name, "%s%s%s", + (quotes) ? "\"" : "", + trigger_config_default_list[i][j + 1], + (quotes) ? "\"" : "")) + { + return WEECHAT_CONFIG_WRITE_ERROR; + } + } + } + + return WEECHAT_CONFIG_WRITE_OK; +} + +/* + * Reloads trigger configuration file. + */ + +int +trigger_config_reload_cb (void *data, struct t_config_file *config_file) +{ + int rc; + + /* make C compiler happy */ + (void) data; + + trigger_free_all (); + + rc = weechat_config_reload (config_file); + + trigger_config_use_temp_triggers (); + + return rc; +} + +/* + * Initializes trigger configuration file. + * + * Returns: + * 1: OK + * 0: error + */ + +int +trigger_config_init () +{ + struct t_config_section *ptr_section; + + trigger_config_file = weechat_config_new (TRIGGER_CONFIG_NAME, + &trigger_config_reload_cb, NULL); + if (!trigger_config_file) + return 0; + + /* look */ + ptr_section = weechat_config_new_section (trigger_config_file, "look", + 0, 0, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (trigger_config_file); + return 0; + } + + trigger_config_look_enabled = weechat_config_new_option ( + trigger_config_file, ptr_section, + "enabled", "boolean", + N_("enable trigger support"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, + &trigger_config_change_enabled, NULL, NULL, NULL); + trigger_config_look_monitor_strip_colors = weechat_config_new_option ( + trigger_config_file, ptr_section, + "monitor_strip_colors", "boolean", + N_("strip colors in hashtable values displayed on monitor buffer"), + NULL, 0, 0, "off", NULL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + + /* color */ + ptr_section = weechat_config_new_section (trigger_config_file, "color", + 0, 0, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (trigger_config_file); + return 0; + } + + trigger_config_color_flag_command = weechat_config_new_option ( + trigger_config_file, ptr_section, + "flag_command", "color", + N_("text color for command flag (in /trigger list)"), + NULL, 0, 0, "lightgreen", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + trigger_config_color_flag_conditions = weechat_config_new_option ( + trigger_config_file, ptr_section, + "flag_conditions", "color", + N_("text color for conditions flag (in /trigger list)"), + NULL, 0, 0, "yellow", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + trigger_config_color_flag_regex = weechat_config_new_option ( + trigger_config_file, ptr_section, + "flag_regex", "color", + N_("text color for regex flag (in /trigger list)"), + NULL, 0, 0, "lightcyan", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + trigger_config_color_flag_return_code = weechat_config_new_option ( + trigger_config_file, ptr_section, + "flag_return_code", "color", + N_("text color for return code flag (in /trigger list)"), + NULL, 0, 0, "lightmagenta", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + trigger_config_color_regex = weechat_config_new_option ( + trigger_config_file, ptr_section, + "regex", "color", + N_("text color for regular expressions"), + NULL, 0, 0, "white", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + trigger_config_color_replace = weechat_config_new_option ( + trigger_config_file, ptr_section, + "replace", "color", + N_("text color for replacement text (for regular expressions)"), + NULL, 0, 0, "cyan", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + trigger_config_color_trigger = weechat_config_new_option ( + trigger_config_file, ptr_section, + "trigger", "color", + N_("text color for trigger name"), + NULL, 0, 0, "green", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + trigger_config_color_trigger_disabled = weechat_config_new_option ( + trigger_config_file, ptr_section, + "trigger_disabled", "color", + N_("text color for disabled trigger name"), + NULL, 0, 0, "red", NULL, 0, + NULL, NULL, NULL, NULL, NULL, NULL); + + /* trigger */ + ptr_section = weechat_config_new_section (trigger_config_file, + TRIGGER_CONFIG_SECTION_TRIGGER, + 0, 0, + &trigger_config_trigger_read_cb, NULL, + NULL, NULL, + &trigger_config_trigger_write_default_cb, NULL, + NULL, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (trigger_config_file); + return 0; + } + + trigger_config_section_trigger = ptr_section; + + return 1; +} + +/* + * Reads trigger configuration file. + */ + +int +trigger_config_read () +{ + int rc; + + rc = weechat_config_read (trigger_config_file); + + trigger_config_use_temp_triggers (); + + return rc; +} + +/* + * Writes trigger configuration file. + */ + +int +trigger_config_write () +{ + return weechat_config_write (trigger_config_file); +} + +/* + * Frees trigger configuration. + */ + +void +trigger_config_free () +{ + weechat_config_free (trigger_config_file); +} diff --git a/src/plugins/trigger/trigger-config.h b/src/plugins/trigger/trigger-config.h new file mode 100644 index 000000000..6e0fc9df9 --- /dev/null +++ b/src/plugins/trigger/trigger-config.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_TRIGGER_CONFIG_H +#define __WEECHAT_TRIGGER_CONFIG_H 1 + +#define TRIGGER_CONFIG_NAME "trigger" +#define TRIGGER_CONFIG_SECTION_TRIGGER "trigger" + +extern struct t_config_file *trigger_config_file; +extern struct t_config_section *trigger_config_section_trigger; + +extern struct t_config_option *trigger_config_look_enabled; +extern struct t_config_option *trigger_config_look_monitor_strip_colors; + +extern struct t_config_option *trigger_config_color_flag_command; +extern struct t_config_option *trigger_config_color_flag_conditions; +extern struct t_config_option *trigger_config_color_flag_regex; +extern struct t_config_option *trigger_config_color_flag_return_code; +extern struct t_config_option *trigger_config_color_regex; +extern struct t_config_option *trigger_config_color_replace; +extern struct t_config_option *trigger_config_color_trigger; +extern struct t_config_option *trigger_config_color_trigger_disabled; + +extern char *trigger_config_default_list[][1 + TRIGGER_NUM_OPTIONS]; + +extern struct t_config_option *trigger_config_create_trigger_option (const char *trigger_name, + int index_option, + const char *value); +extern int trigger_config_init (); +extern int trigger_config_read (); +extern int trigger_config_write (); +extern void trigger_config_free (); + +#endif /* __WEECHAT_TRIGGER_CONFIG_H */ diff --git a/src/plugins/trigger/trigger.c b/src/plugins/trigger/trigger.c new file mode 100644 index 000000000..4a580469a --- /dev/null +++ b/src/plugins/trigger/trigger.c @@ -0,0 +1,1217 @@ +/* + * trigger.c - trigger plugin for WeeChat + * + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <regex.h> + +#include "../weechat-plugin.h" +#include "trigger.h" +#include "trigger-buffer.h" +#include "trigger-callback.h" +#include "trigger-command.h" +#include "trigger-completion.h" +#include "trigger-config.h" + + +WEECHAT_PLUGIN_NAME(TRIGGER_PLUGIN_NAME); +WEECHAT_PLUGIN_DESCRIPTION(N_("Run actions on events triggered by WeeChat/plugins")); +WEECHAT_PLUGIN_AUTHOR("Sébastien Helleu <flashcode@flashtux.org>"); +WEECHAT_PLUGIN_VERSION(WEECHAT_VERSION); +WEECHAT_PLUGIN_LICENSE(WEECHAT_LICENSE); + +struct t_weechat_plugin *weechat_trigger_plugin = NULL; + +char *trigger_option_string[TRIGGER_NUM_OPTIONS] = +{ "enabled", "hook", "arguments", "conditions", "regex", "command", + "return_code" }; +char *trigger_option_default[TRIGGER_NUM_OPTIONS] = +{ "on", "signal", "", "", "", "", "ok" }; + +char *trigger_hook_type_string[TRIGGER_NUM_HOOK_TYPES] = +{ "signal", "hsignal", "modifier", "print", "command", "command_run", "timer", + "config", "focus" }; +char *trigger_hook_option_values = + "signal|hsignal|modifier|print|command|command_run|timer|config|focus"; +char *trigger_hook_default_arguments[TRIGGER_NUM_HOOK_TYPES] = +{ "xxx", "xxx", "xxx", "", "cmd;desc;args;args_desc;%(buffers_names)", "/cmd", + "60000;0;0", "xxx", "chat" }; +char *trigger_hook_default_rc[TRIGGER_NUM_HOOK_TYPES] = +{ "ok,ok_eat,error", "ok,ok_eat,error", "", "ok,error", "ok,error", + "ok,ok_eat,error", "ok", "ok", "" }; + +char *trigger_hook_regex_default_var[TRIGGER_NUM_HOOK_TYPES] = +{ "tg_signal_data", "", "tg_string", "tg_message", "tg_argv_eol1", "tg_command", + "", "tg_value", "" }; + +char *trigger_return_code_string[TRIGGER_NUM_RETURN_CODES] = +{ "ok", "ok_eat", "error" }; +int trigger_return_code[TRIGGER_NUM_RETURN_CODES] = +{ WEECHAT_RC_OK, WEECHAT_RC_OK_EAT, WEECHAT_RC_ERROR }; + +struct t_trigger *triggers = NULL; /* first trigger */ +struct t_trigger *last_trigger = NULL; /* last trigger */ +int triggers_count = 0; /* number of triggers */ + +struct t_trigger *triggers_temp = NULL; /* first temporary trigger */ +struct t_trigger *last_trigger_temp = NULL; /* last temporary trigger */ + +int trigger_enabled = 1; /* 0 if triggers are disabled */ + + +/* + * Searches for a trigger option name. + * + * Returns index of option in enum t_trigger_option, -1 if not found. + */ + +int +trigger_search_option (const char *option_name) +{ + int i; + + if (!option_name) + return -1; + + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + if (weechat_strcasecmp (trigger_option_string[i], option_name) == 0) + return i; + } + + /* trigger option not found */ + return -1; +} + +/* + * Searches for trigger hook type. + * + * Returns index of hook type in enum t_trigger_hook_type, -1 if not found. + */ + +int +trigger_search_hook_type (const char *type) +{ + int i; + + for (i = 0; i < TRIGGER_NUM_HOOK_TYPES; i++) + { + if (weechat_strcasecmp (trigger_hook_type_string[i], type) == 0) + return i; + } + + /* hook type not found */ + return -1; +} + +/* + * Searches for trigger return code. + * + * Returns index of return code in enum t_trigger_return_code, -1 if not found. + */ + +int +trigger_search_return_code (const char *return_code) +{ + int i; + + for (i = 0; i < TRIGGER_NUM_RETURN_CODES; i++) + { + if (weechat_strcasecmp (trigger_return_code_string[i], return_code) == 0) + return i; + } + + /* return code not found */ + return -1; +} + +/* + * Searches for a trigger by name. + * + * Returns pointer to trigger found, NULL if not found. + */ + +struct t_trigger * +trigger_search (const char *name) +{ + struct t_trigger *ptr_trigger; + + if (!name || !name[0]) + return NULL; + + for (ptr_trigger = triggers; ptr_trigger; + ptr_trigger = ptr_trigger->next_trigger) + { + if (weechat_strcasecmp (ptr_trigger->name, name) == 0) + return ptr_trigger; + } + + /* trigger not found */ + return NULL; +} + +/* + * Searches for a trigger with a pointer to a trigger option. + * + * Returns pointer to trigger found, NULL if not found. + */ + +struct t_trigger * +trigger_search_with_option (struct t_config_option *option) +{ + const char *ptr_name; + char *pos_option; + struct t_trigger *ptr_trigger; + + ptr_name = weechat_hdata_string (weechat_hdata_get ("config_option"), + option, "name"); + if (!ptr_name) + return NULL; + + pos_option = strchr (ptr_name, '.'); + if (!pos_option) + return NULL; + + for (ptr_trigger = triggers; ptr_trigger; + ptr_trigger = ptr_trigger->next_trigger) + { + if (weechat_strncasecmp (ptr_trigger->name, ptr_name, pos_option - ptr_name) == 0) + break; + } + + return ptr_trigger; +} + +/* + * Unhooks things hooked in a trigger. + */ + +void +trigger_unhook (struct t_trigger *trigger) +{ + int i; + + if (trigger->hooks) + { + for (i = 0; i < trigger->hooks_count; i++) + { + if (trigger->hooks[i]) + weechat_unhook (trigger->hooks[i]); + } + free (trigger->hooks); + trigger->hooks = NULL; + trigger->hooks_count = 0; + } + trigger->hook_count_cb = 0; + trigger->hook_count_cmd = 0; + if (trigger->hook_print_buffers) + { + free (trigger->hook_print_buffers); + trigger->hook_print_buffers = NULL; + } +} + +/* + * Creates hook(s) in a trigger. + */ + +void +trigger_hook (struct t_trigger *trigger) +{ + char **argv, **argv_eol, *tags, *message, *error1, *error2, *error3; + int i, argc, strip_colors; + long interval, align_second, max_calls; + + trigger_unhook (trigger); + + argv = weechat_string_split (weechat_config_string (trigger->options[TRIGGER_OPTION_ARGUMENTS]), + ";", 0, 0, &argc); + argv_eol = weechat_string_split (weechat_config_string (trigger->options[TRIGGER_OPTION_ARGUMENTS]), + ";", 1, 0, NULL); + + switch (weechat_config_integer (trigger->options[TRIGGER_OPTION_HOOK])) + { + case TRIGGER_HOOK_SIGNAL: + if (argv && (argc >= 1)) + { + trigger->hooks = malloc (argc * sizeof (trigger->hooks[0])); + if (trigger->hooks) + { + trigger->hooks_count = argc; + for (i = 0; i < argc; i++) + { + trigger->hooks[i] = weechat_hook_signal ( + argv[i], + &trigger_callback_signal_cb, + trigger); + } + } + } + break; + case TRIGGER_HOOK_HSIGNAL: + if (argv && (argc >= 1)) + { + trigger->hooks = malloc (argc * sizeof (trigger->hooks[0])); + if (trigger->hooks) + { + trigger->hooks_count = argc; + for (i = 0; i < argc; i++) + { + trigger->hooks[i] = weechat_hook_hsignal ( + argv[i], + &trigger_callback_hsignal_cb, + trigger); + } + } + } + break; + case TRIGGER_HOOK_MODIFIER: + if (argv && (argc >= 1)) + { + trigger->hooks = malloc (argc * sizeof (trigger->hooks[0])); + if (trigger->hooks) + { + trigger->hooks_count = argc; + for (i = 0; i < argc; i++) + { + trigger->hooks[i] = weechat_hook_modifier ( + argv[i], + &trigger_callback_modifier_cb, + trigger); + } + } + } + break; + case TRIGGER_HOOK_PRINT: + tags = NULL; + message = NULL; + strip_colors = 0; + if (argv && (argc >= 1)) + { + if (strcmp (argv[0], "*") != 0) + trigger->hook_print_buffers = strdup (argv[0]); + if ((argc >= 2) && (strcmp (argv[1], "*") != 0)) + tags = argv[1]; + if ((argc >= 3) && (strcmp (argv[2], "*") != 0)) + message = argv[2]; + if (argc >= 4) + strip_colors = (strcmp (argv[3], "0") != 0) ? 1 : 0; + } + trigger->hooks = malloc (sizeof (trigger->hooks[0])); + if (trigger->hooks) + { + trigger->hooks_count = 1; + trigger->hooks[0] = weechat_hook_print ( + NULL, + tags, + message, + strip_colors, + &trigger_callback_print_cb, + trigger); + } + break; + case TRIGGER_HOOK_COMMAND: + if (argv && (argc >= 1)) + { + trigger->hooks = malloc (sizeof (trigger->hooks[0])); + if (trigger->hooks) + { + trigger->hooks_count = 1; + trigger->hooks[0] = weechat_hook_command ( + argv[0], /* command */ + (argc > 1) ? argv[1] : "", /* description */ + (argc > 2) ? argv[2] : "", /* arguments */ + (argc > 3) ? argv[3] : "", /* description of args */ + (argc > 4) ? argv[4] : "", /* completion */ + &trigger_callback_command_cb, + trigger); + } + } + break; + case TRIGGER_HOOK_COMMAND_RUN: + if (argv && (argc >= 1)) + { + trigger->hooks = malloc (argc * sizeof (trigger->hooks[0])); + if (trigger->hooks) + { + trigger->hooks_count = argc; + for (i = 0; i < argc; i++) + { + trigger->hooks[i] = weechat_hook_command_run ( + argv[i], + &trigger_callback_command_run_cb, + trigger); + } + } + } + break; + case TRIGGER_HOOK_TIMER: + if (argv && (argc >= 3)) + { + error1 = NULL; + error2 = NULL; + error3 = NULL; + interval = strtol (argv[0], &error1, 10); + align_second = strtol (argv[1], &error2, 10); + max_calls = strtol (argv[2], &error3, 10); + if (error1 && !error1[0] + && error2 && !error2[0] + && error3 && !error3[0] + && (interval > 0) + && (align_second >= 0) + && (max_calls >= 0)) + { + trigger->hooks = malloc (sizeof (trigger->hooks[0])); + if (trigger->hooks) + { + trigger->hooks_count = 1; + trigger->hooks[0] = weechat_hook_timer ( + interval, + (int)align_second, + (int)max_calls, + &trigger_callback_timer_cb, + trigger); + } + } + } + break; + case TRIGGER_HOOK_CONFIG: + if (argv && (argc >= 1)) + { + trigger->hooks = malloc (argc * sizeof (trigger->hooks[0])); + if (trigger->hooks) + { + trigger->hooks_count = argc; + for (i = 0; i < argc; i++) + { + trigger->hooks[i] = weechat_hook_config ( + argv[i], + &trigger_callback_config_cb, + trigger); + } + } + } + break; + case TRIGGER_HOOK_FOCUS: + if (argv && (argc >= 1)) + { + trigger->hooks = malloc (argc * sizeof (trigger->hooks[0])); + if (trigger->hooks) + { + trigger->hooks_count = argc; + for (i = 0; i < argc; i++) + { + trigger->hooks[i] = weechat_hook_focus ( + argv[i], + &trigger_callback_focus_cb, + trigger); + } + } + } + break; + } + + if (!trigger->hooks) + { + weechat_printf (NULL, + _("%sError: unable to create hook for trigger \"%s\" " + "(bad arguments)"), + weechat_prefix ("error"), trigger->name); + } + + if (argv) + weechat_string_free_split (argv); + if (argv_eol) + weechat_string_free_split (argv_eol); +} + +/* + * Frees all the regex in a trigger. + */ + +void +trigger_free_regex (int *regex_count, struct t_trigger_regex **regex) +{ + int i; + + if (*regex_count > 0) + { + for (i = 0; i < *regex_count; i++) + { + if ((*regex)[i].variable) + free ((*regex)[i].variable); + if ((*regex)[i].str_regex) + free ((*regex)[i].str_regex); + if ((*regex)[i].regex) + { + regfree ((*regex)[i].regex); + free ((*regex)[i].regex); + } + if ((*regex)[i].replace) + free ((*regex)[i].replace); + if ((*regex)[i].replace_escaped) + free ((*regex)[i].replace_escaped); + } + free (*regex); + *regex = NULL; + *regex_count = 0; + } +} + +/* + * Splits the regex in structures, with regex and replacement text. + */ + +void +trigger_split_regex (const char *trigger_name, const char *str_regex, + int *regex_count, struct t_trigger_regex **regex) +{ + const char *ptr_regex, *pos, *pos_replace, *pos_replace_end; + const char *pos_next_regex; + char *delimiter; + int index, length_delimiter; + struct t_trigger_regex *new_regex; + + delimiter = NULL; + + if (!regex_count || !regex) + goto end; + + /* remove any existing regex */ + trigger_free_regex (regex_count, regex); + + if (!str_regex || !str_regex[0]) + goto end; + + /* min 3 chars, for example: "/a/" */ + if (strlen (str_regex) < 3) + goto format_error; + + /* parse regular expressions in the option */ + ptr_regex = str_regex; + while (ptr_regex && ptr_regex[0]) + { + if (delimiter) + { + free (delimiter); + delimiter = NULL; + } + + /* search the delimiter (which can be more than one char) */ + pos = weechat_utf8_next_char (ptr_regex); + while (pos[0] && (weechat_utf8_charcmp (ptr_regex, pos) == 0)) + { + pos = weechat_utf8_next_char (pos); + } + if (!pos[0]) + goto format_error; + delimiter = weechat_strndup (ptr_regex, pos - ptr_regex); + if (!delimiter) + goto memory_error; + if ((strcmp (delimiter, "\\") == 0) || (strcmp (delimiter, "(") == 0)) + goto format_error; + + length_delimiter = strlen (delimiter); + + ptr_regex = pos; + if (!ptr_regex[0]) + goto format_error; + + /* search the start of replacement string */ + pos_replace = strstr (ptr_regex, delimiter); + if (!pos_replace) + goto format_error; + + /* search the end of replacement string */ + pos_replace_end = strstr (pos_replace + length_delimiter, delimiter); + + new_regex = realloc (*regex, + (*regex_count + 1) * sizeof ((*regex)[0])); + if (!new_regex) + goto memory_error; + + *regex = new_regex; + (*regex_count)++; + index = *regex_count - 1; + + /* initialize new regex */ + (*regex)[index].variable = NULL; + (*regex)[index].str_regex = NULL; + (*regex)[index].regex = NULL; + (*regex)[index].replace = NULL; + (*regex)[index].replace_escaped = NULL; + + /* set string with regex */ + (*regex)[index].str_regex = weechat_strndup (ptr_regex, + pos_replace - ptr_regex); + if (!(*regex)[index].str_regex) + goto memory_error; + + /* set regex */ + (*regex)[index].regex = malloc (sizeof (*(*regex)[index].regex)); + if (!(*regex)[index].regex) + goto memory_error; + if (weechat_string_regcomp ((*regex)[index].regex, + (*regex)[index].str_regex, + REG_EXTENDED | REG_ICASE) != 0) + { + weechat_printf (NULL, + _("%s%s: error compiling regular expression \"%s\""), + weechat_prefix ("error"), TRIGGER_PLUGIN_NAME, + (*regex)[index].str_regex); + free ((*regex)[index].regex); + (*regex)[index].regex = NULL; + goto end; + } + + /* set replace and replace_eval */ + (*regex)[index].replace = (pos_replace_end) ? + weechat_strndup (pos_replace + length_delimiter, + pos_replace_end - pos_replace - length_delimiter) : + strdup (pos_replace + length_delimiter); + if (!(*regex)[index].replace) + goto memory_error; + (*regex)[index].replace_escaped = + weechat_string_convert_escaped_chars ((*regex)[index].replace); + if (!(*regex)[index].replace_escaped) + goto memory_error; + + if (!pos_replace_end) + break; + + /* set variable (optional) */ + ptr_regex = pos_replace_end + length_delimiter; + if (!ptr_regex[0]) + break; + if (ptr_regex[0] == ' ') + pos_next_regex = ptr_regex; + else + { + pos_next_regex = strchr (ptr_regex, ' '); + (*regex)[index].variable = (pos_next_regex) ? + weechat_strndup (ptr_regex, pos_next_regex - ptr_regex) : + strdup (ptr_regex); + if (!(*regex)[index].variable) + goto memory_error; + } + if (!pos_next_regex) + break; + + /* skip spaces before next regex */ + ptr_regex = pos_next_regex + 1; + while (ptr_regex[0] == ' ') + { + ptr_regex++; + } + } + + goto end; + +format_error: + weechat_printf (NULL, + _("%s%s: invalid value for option \"regex\", " + "see /help trigger.trigger.%s.regex"), + weechat_prefix ("error"), TRIGGER_PLUGIN_NAME, + trigger_name); + trigger_free_regex (regex_count, regex); + goto end; + +memory_error: + weechat_printf (NULL, + _("%s%s: not enough memory"), + weechat_prefix ("error"), TRIGGER_PLUGIN_NAME); + trigger_free_regex (regex_count, regex); + goto end; + +end: + if (delimiter) + free (delimiter); +} + +/* + * Splits command of a trigger. + */ + +void +trigger_split_command (const char *command, + int *commands_count, char ***commands) +{ + int i; + + if (!commands_count || !commands) + return; + + if (*commands) + { + weechat_string_free_split (*commands); + *commands = NULL; + } + *commands_count = 0; + + if (command && command[0]) + { + *commands = weechat_string_split_command (command, ';'); + if (*commands) + { + for (i = 0; (*commands)[i]; i++) + { + } + *commands_count = i; + } + } +} + +/* + * Checks if a trigger name is valid: it must not start with "-" and not have + * any spaces. + * + * Returns: + * 1: name is valid + * 0: name is invalid + */ + +int +trigger_name_valid (const char *name) +{ + if (!name || !name[0] || (name[0] == '-')) + return 0; + + /* no spaces allowed */ + if (strchr (name, ' ')) + return 0; + + /* name is valid */ + return 1; +} + +/* + * Allocates and initializes new trigger structure. + * + * Returns pointer to new trigger, NULL if error. + */ + +struct t_trigger * +trigger_alloc (const char *name) +{ + struct t_trigger *new_trigger; + int i; + + if (!trigger_name_valid (name)) + return NULL; + + if (trigger_search (name)) + return NULL; + + new_trigger = malloc (sizeof (*new_trigger)); + if (!new_trigger) + return NULL; + + new_trigger->name = strdup (name); + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + new_trigger->options[i] = NULL; + } + new_trigger->hooks_count = 0; + new_trigger->hooks = NULL; + new_trigger->hook_count_cb = 0; + new_trigger->hook_count_cmd = 0; + new_trigger->hook_running = 0; + new_trigger->hook_print_buffers = NULL; + new_trigger->regex_count = 0; + new_trigger->regex = NULL; + new_trigger->commands_count = 0; + new_trigger->commands = NULL; + new_trigger->prev_trigger = NULL; + new_trigger->next_trigger = NULL; + + return new_trigger; +} + +/* + * Searches for position of trigger in list (to keep triggers sorted by name). + */ + +struct t_trigger * +trigger_find_pos (struct t_trigger *trigger, struct t_trigger *list_triggers) +{ + struct t_trigger *ptr_trigger; + + for (ptr_trigger = list_triggers; ptr_trigger; + ptr_trigger = ptr_trigger->next_trigger) + { + if (weechat_strcasecmp (trigger->name, ptr_trigger->name) < 0) + return ptr_trigger; + } + + /* position not found */ + return NULL; +} + +/* + * Adds a trigger in a linked list. + */ + +void +trigger_add (struct t_trigger *trigger, + struct t_trigger **list_triggers, + struct t_trigger **last_list_trigger) +{ + struct t_trigger *pos_trigger; + + pos_trigger = trigger_find_pos (trigger, *list_triggers); + if (pos_trigger) + { + /* add trigger before "pos_trigger" */ + trigger->prev_trigger = pos_trigger->prev_trigger; + trigger->next_trigger = pos_trigger; + if (pos_trigger->prev_trigger) + (pos_trigger->prev_trigger)->next_trigger = trigger; + else + *list_triggers = trigger; + pos_trigger->prev_trigger = trigger; + } + else + { + /* add trigger to end of list */ + trigger->prev_trigger = *last_list_trigger; + trigger->next_trigger = NULL; + if (!*list_triggers) + *list_triggers = trigger; + else + (*last_list_trigger)->next_trigger = trigger; + *last_list_trigger = trigger; + } +} + +/* + * Creates a new trigger with options. + * + * Returns pointer to new trigger, NULL if error. + */ + +struct t_trigger * +trigger_new_with_options (const char *name, struct t_config_option **options) +{ + struct t_trigger *new_trigger; + int i; + + new_trigger = trigger_alloc (name); + if (!new_trigger) + return NULL; + + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + new_trigger->options[i] = options[i]; + } + trigger_add (new_trigger, &triggers, &last_trigger); + triggers_count++; + + trigger_split_regex (new_trigger->name, + weechat_config_string (new_trigger->options[TRIGGER_OPTION_REGEX]), + &new_trigger->regex_count, + &new_trigger->regex); + trigger_split_command (weechat_config_string (new_trigger->options[TRIGGER_OPTION_COMMAND]), + &new_trigger->commands_count, + &new_trigger->commands); + + if (weechat_config_boolean (new_trigger->options[TRIGGER_OPTION_ENABLED])) + trigger_hook (new_trigger); + + return new_trigger; +} + +/* + * Creates a new trigger. + * + * Returns pointer to new trigger, NULL if error. + */ + +struct t_trigger * +trigger_new (const char *name, const char *enabled, const char *hook, + const char *arguments, const char *conditions, const char *regex, + const char *command, const char *return_code) +{ + struct t_config_option *option[TRIGGER_NUM_OPTIONS]; + const char *value[TRIGGER_NUM_OPTIONS]; + struct t_trigger *new_trigger; + int i; + + /* look for type */ + if (trigger_search_hook_type (hook) < 0) + return NULL; + + /* look for return code */ + if (return_code && return_code[0] + && (trigger_search_return_code (return_code) < 0)) + { + return NULL; + } + + value[TRIGGER_OPTION_ENABLED] = enabled; + value[TRIGGER_OPTION_HOOK] = hook; + value[TRIGGER_OPTION_ARGUMENTS] = arguments; + value[TRIGGER_OPTION_CONDITIONS] = conditions; + value[TRIGGER_OPTION_REGEX] = regex; + value[TRIGGER_OPTION_COMMAND] = command; + value[TRIGGER_OPTION_RETURN_CODE] = return_code; + + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + option[i] = trigger_config_create_trigger_option (name, i, value[i]); + } + + new_trigger = trigger_new_with_options (name, option); + if (!new_trigger) + { + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + weechat_config_option_free (option[i]); + } + } + + return new_trigger; +} + +/* + * Creates default triggers. + */ + +void +trigger_create_default () +{ + int i; + + for (i = 0; trigger_config_default_list[i][0]; i++) + { + trigger_new (trigger_config_default_list[i][0], /* name */ + trigger_config_default_list[i][1], /* enabled */ + trigger_config_default_list[i][2], /* hook */ + trigger_config_default_list[i][3], /* arguments */ + trigger_config_default_list[i][4], /* conditions */ + trigger_config_default_list[i][5], /* regex */ + trigger_config_default_list[i][6], /* command */ + trigger_config_default_list[i][7]); /* return code */ + } +} + +/* + * Renames a trigger. + * + * Returns: + * 1: OK + * 0: error (trigger not renamed) + */ + +int +trigger_rename (struct t_trigger *trigger, const char *name) +{ + int length, i; + char *option_name; + + if (!name || !name[0] || !trigger_name_valid (name) + || trigger_search (name)) + { + return 0; + } + + length = strlen (name) + 64; + option_name = malloc (length); + if (!option_name) + return 0; + + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + if (trigger->options[i]) + { + snprintf (option_name, length, + "%s.%s", + name, + trigger_option_string[i]); + weechat_config_option_rename (trigger->options[i], option_name); + } + } + + if (trigger->name) + free (trigger->name); + trigger->name = strdup (name); + + free (option_name); + + /* re-insert trigger in list (for sorting triggers by name) */ + if (trigger->prev_trigger) + (trigger->prev_trigger)->next_trigger = trigger->next_trigger; + else + triggers = trigger->next_trigger; + if (trigger->next_trigger) + (trigger->next_trigger)->prev_trigger = trigger->prev_trigger; + else + last_trigger = trigger->prev_trigger; + trigger_add (trigger, &triggers, &last_trigger); + + return 1; +} + +/* + * Copies a trigger. + * + * Returns a pointer to the new trigger, NULL if error. + */ + +struct t_trigger * +trigger_copy (struct t_trigger *trigger, const char *name) +{ + if (!name || !name[0] || !trigger_name_valid (name) + || trigger_search (name)) + { + return NULL; + } + + return trigger_new ( + name, + weechat_config_string (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]), + weechat_config_string (trigger->options[TRIGGER_OPTION_REGEX]), + weechat_config_string (trigger->options[TRIGGER_OPTION_COMMAND]), + weechat_config_string (trigger->options[TRIGGER_OPTION_RETURN_CODE])); +} + +/* + * Deletes a trigger. + */ + +void +trigger_free (struct t_trigger *trigger) +{ + int i; + + if (!trigger) + return; + + /* remove trigger from triggers list */ + if (trigger->prev_trigger) + (trigger->prev_trigger)->next_trigger = trigger->next_trigger; + if (trigger->next_trigger) + (trigger->next_trigger)->prev_trigger = trigger->prev_trigger; + if (triggers == trigger) + triggers = trigger->next_trigger; + if (last_trigger == trigger) + last_trigger = trigger->prev_trigger; + + /* free data */ + trigger_unhook (trigger); + trigger_free_regex (&trigger->regex_count, &trigger->regex); + if (trigger->name) + free (trigger->name); + for (i = 0; i < TRIGGER_NUM_OPTIONS; i++) + { + if (trigger->options[i]) + weechat_config_option_free (trigger->options[i]); + } + if (trigger->commands) + weechat_string_free_split (trigger->commands); + + free (trigger); + + triggers_count--; +} + +/* + * Deletes all triggers. + */ + +void +trigger_free_all () +{ + while (triggers) + { + trigger_free (triggers); + } +} + +/* + * Prints trigger infos in WeeChat log file (usually for crash dump). + */ + +void +trigger_print_log () +{ + struct t_trigger *ptr_trigger; + int i; + + for (ptr_trigger = triggers; ptr_trigger; + ptr_trigger = ptr_trigger->next_trigger) + { + weechat_log_printf (""); + weechat_log_printf ("[trigger (addr:0x%lx)]", ptr_trigger); + weechat_log_printf (" name. . . . . . . . . . : '%s'", ptr_trigger->name); + weechat_log_printf (" enabled . . . . . . . . : %d", + weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_ENABLED])); + weechat_log_printf (" hook . . . . . . . . . : %d ('%s')", + weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_HOOK]), + trigger_hook_type_string[weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_HOOK])]); + weechat_log_printf (" arguments . . . . . . . : '%s'", + weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_ARGUMENTS])); + weechat_log_printf (" conditions. . . . . . . : '%s'", + weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_CONDITIONS])); + weechat_log_printf (" regex . . . . . . . . . : '%s'", + weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_REGEX])); + weechat_log_printf (" command . . . . . . . . : '%s'", + weechat_config_string (ptr_trigger->options[TRIGGER_OPTION_COMMAND])); + weechat_log_printf (" return_code . . . . . . : %d ('%s')", + weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_RETURN_CODE]), + trigger_return_code_string[weechat_config_integer (ptr_trigger->options[TRIGGER_OPTION_RETURN_CODE])]); + weechat_log_printf (" hooks_count . . . . . . : %d", ptr_trigger->hooks_count); + weechat_log_printf (" hooks . . . . . . . . . : 0x%lx", ptr_trigger->hooks); + for (i = 0; i < ptr_trigger->hooks_count; i++) + { + weechat_log_printf (" hooks[%03d]. . . . . . : 0x%lx", + i, ptr_trigger->hooks[i]); + } + weechat_log_printf (" hook_count_cb . . . . . : %lu", ptr_trigger->hook_count_cb); + weechat_log_printf (" hook_count_cmd. . . . . : %lu", ptr_trigger->hook_count_cmd); + weechat_log_printf (" hook_running. . . . . . : %d", ptr_trigger->hook_running); + weechat_log_printf (" hook_print_buffers. . . : '%s'", ptr_trigger->hook_print_buffers); + weechat_log_printf (" regex_count . . . . . . : %d", ptr_trigger->regex_count); + weechat_log_printf (" regex . . . . . . . . . : 0x%lx", ptr_trigger->regex); + for (i = 0; i < ptr_trigger->regex_count; i++) + { + weechat_log_printf (" regex[%03d].variable . . . : '%s'", + i, ptr_trigger->regex[i].variable); + weechat_log_printf (" regex[%03d].str_regex. . . : '%s'", + i, ptr_trigger->regex[i].str_regex); + weechat_log_printf (" regex[%03d].regex. . . . . : 0x%lx", + i, ptr_trigger->regex[i].regex); + weechat_log_printf (" regex[%03d].replace. . . . : '%s'", + i, ptr_trigger->regex[i].replace); + weechat_log_printf (" regex[%03d].replace_escaped: '%s'", + i, ptr_trigger->regex[i].replace_escaped); + } + weechat_log_printf (" commands_count. . . . . : %d", ptr_trigger->commands_count); + weechat_log_printf (" commands. . . . . . . . : 0x%lx", ptr_trigger->commands); + if (ptr_trigger->commands) + { + for (i = 0; ptr_trigger->commands[i]; i++) + { + weechat_log_printf (" commands[%03d] . . . . : '%s'", + i, ptr_trigger->commands[i]); + } + } + weechat_log_printf (" prev_trigger. . . . . . : 0x%lx", ptr_trigger->prev_trigger); + weechat_log_printf (" next_trigger. . . . . . : 0x%lx", ptr_trigger->next_trigger); + } +} + +/* + * Callback for signal "debug_dump". + */ + +int +trigger_debug_dump_cb (void *data, const char *signal, const char *type_data, + void *signal_data) +{ + /* make C compiler happy */ + (void) data; + (void) signal; + (void) type_data; + + if (!signal_data + || (weechat_strcasecmp ((char *)signal_data, TRIGGER_PLUGIN_NAME) == 0)) + { + weechat_log_printf (""); + weechat_log_printf ("***** \"%s\" plugin dump *****", + weechat_plugin->name); + + trigger_print_log (); + + weechat_log_printf (""); + weechat_log_printf ("***** End of \"%s\" plugin dump *****", + weechat_plugin->name); + } + + return WEECHAT_RC_OK; +} + +/* + * Initializes trigger plugin. + */ + +int +weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) +{ + int i, upgrading; + + /* make C compiler happy */ + (void) argc; + (void) argv; + + weechat_plugin = plugin; + + trigger_callback_init (); + + trigger_command_init (); + + if (!trigger_config_init ()) + return WEECHAT_RC_ERROR; + + trigger_config_read (); + + /* hook some signals */ + weechat_hook_signal ("debug_dump", &trigger_debug_dump_cb, NULL); + + /* hook completions */ + trigger_completion_init (); + + /* look at arguments */ + upgrading = 0; + for (i = 0; i < argc; i++) + { + if (weechat_strcasecmp (argv[i], "--upgrade") == 0) + { + upgrading = 1; + } + } + + if (upgrading) + trigger_buffer_set_callbacks (); + + return WEECHAT_RC_OK; +} + +/* + * Ends trigger plugin. + */ + +int +weechat_plugin_end (struct t_weechat_plugin *plugin) +{ + /* make C compiler happy */ + (void) plugin; + + trigger_config_write (); + trigger_free_all (); + trigger_config_free (); + trigger_callback_end (); + + return WEECHAT_RC_OK; +} diff --git a/src/plugins/trigger/trigger.h b/src/plugins/trigger/trigger.h new file mode 100644 index 000000000..4c5e251ea --- /dev/null +++ b/src/plugins/trigger/trigger.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2014 Sébastien Helleu <flashcode@flashtux.org> + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_TRIGGER_H +#define __WEECHAT_TRIGGER_H 1 + +#include <regex.h> + +#define weechat_plugin weechat_trigger_plugin +#define TRIGGER_PLUGIN_NAME "trigger" + +#define TRIGGER_HOOK_DEFAULT_CONDITIONS "${...}" +#define TRIGGER_HOOK_DEFAULT_REGEX "/abc/def" +#define TRIGGER_HOOK_DEFAULT_COMMAND "/cmd" + +enum t_trigger_option +{ + TRIGGER_OPTION_ENABLED = 0, /* true if trigger is enabled */ + TRIGGER_OPTION_HOOK, /* hook (signal, modifier, ...) */ + TRIGGER_OPTION_ARGUMENTS, /* arguments for hook */ + TRIGGER_OPTION_CONDITIONS, /* conditions for trigger */ + TRIGGER_OPTION_REGEX, /* replace text with 1 or more regex */ + TRIGGER_OPTION_COMMAND, /* command run if conditions are OK */ + TRIGGER_OPTION_RETURN_CODE, /* return code for hook callback */ + /* number of trigger options */ + TRIGGER_NUM_OPTIONS, +}; + +enum t_trigger_hook_type +{ + TRIGGER_HOOK_SIGNAL = 0, + TRIGGER_HOOK_HSIGNAL, + TRIGGER_HOOK_MODIFIER, + TRIGGER_HOOK_PRINT, + TRIGGER_HOOK_COMMAND, + TRIGGER_HOOK_COMMAND_RUN, + TRIGGER_HOOK_TIMER, + TRIGGER_HOOK_CONFIG, + TRIGGER_HOOK_FOCUS, + /* number of hook types */ + TRIGGER_NUM_HOOK_TYPES, +}; + +enum t_trigger_return_code +{ + TRIGGER_RC_OK = 0, + TRIGGER_RC_OK_EAT, + TRIGGER_RC_ERROR, + /* number of return codes */ + TRIGGER_NUM_RETURN_CODES, +}; + +struct t_trigger_regex +{ + char *variable; /* the hashtable key used */ + char *str_regex; /* regex to search for replacement */ + regex_t *regex; /* compiled regex */ + char *replace; /* replacement text */ + char *replace_escaped; /* repl. text (with chars escaped) */ +}; + +struct t_trigger +{ + /* user choices */ + char *name; /* trigger name */ + struct t_config_option *options[TRIGGER_NUM_OPTIONS]; + + /* internal vars */ + + /* hooks */ + int hooks_count; /* number of hooks */ + struct t_hook **hooks; /* array of hooks (signal, ...) */ + unsigned long hook_count_cb; /* number of calls made to callback */ + unsigned long hook_count_cmd; /* number of commands run in callback*/ + int hook_running; /* 1 if one hook callback is running */ + char *hook_print_buffers; /* buffers (for hook_print only) */ + + /* regular expressions with their replacement text */ + int regex_count; /* number of regex */ + struct t_trigger_regex *regex; /* array of regex */ + + /* commands */ + int commands_count; /* number of commands */ + char **commands; /* commands */ + + /* links to other triggers */ + struct t_trigger *prev_trigger; /* link to previous trigger */ + struct t_trigger *next_trigger; /* link to next trigger */ +}; + +extern struct t_weechat_plugin *weechat_trigger_plugin; +extern char *trigger_option_string[]; +extern char *trigger_option_default[]; +extern char *trigger_hook_type_string[]; +extern char *trigger_hook_option_values; +extern char *trigger_hook_default_arguments[]; +extern char *trigger_hook_default_rc[]; +extern char *trigger_hook_regex_default_var[]; +extern char *trigger_return_code_string[]; +extern int trigger_return_code[]; +extern struct t_trigger *triggers; +extern struct t_trigger *last_trigger; +extern int triggers_count; +extern struct t_trigger *triggers_temp; +extern struct t_trigger *last_trigger_temp; +extern int trigger_enabled; + +extern int trigger_search_option (const char *option_name); +extern int trigger_search_hook_type (const char *type); +extern int trigger_search_return_code (const char *return_code); +extern struct t_trigger *trigger_search (const char *name); +extern struct t_trigger *trigger_search_with_option (struct t_config_option *option); +extern void trigger_free_regex (int *regex_count, + struct t_trigger_regex **regex); +extern void trigger_split_regex (const char *trigger_name, + const char *str_regex, + int *regex_count, + struct t_trigger_regex **regex); +extern void trigger_split_command (const char *command, + int *commands_count, char ***commands); +extern void trigger_unhook (struct t_trigger *trigger); +extern void trigger_hook (struct t_trigger *trigger); +extern int trigger_name_valid (const char *name); +extern struct t_trigger *trigger_alloc (const char *name); +extern void trigger_add (struct t_trigger *trigger, + struct t_trigger **list_triggers, + struct t_trigger **last_list_trigger); +extern struct t_trigger *trigger_new_with_options (const char *name, + struct t_config_option **options); +extern struct t_trigger *trigger_new (const char *name, + const char *enabled, + const char *hook, + const char *arguments, + const char *conditions, + const char *replace, + const char *command, + const char *return_code); +extern void trigger_create_default (); +extern int trigger_rename (struct t_trigger *trigger, const char *name); +extern struct t_trigger *trigger_copy (struct t_trigger *trigger, + const char *name); +extern void trigger_free (struct t_trigger *trigger); +extern void trigger_free_all (); + +#endif /* __WEECHAT_TRIGGER_H */ diff --git a/src/plugins/weechat-plugin.h b/src/plugins/weechat-plugin.h index 38f1f964d..16ff1c56f 100644 --- a/src/plugins/weechat-plugin.h +++ b/src/plugins/weechat-plugin.h @@ -57,7 +57,7 @@ struct timeval; * please change the date with current one; for a second change at same * date, increment the 01, otherwise please keep 01. */ -#define WEECHAT_PLUGIN_API_VERSION "20140210-01" +#define WEECHAT_PLUGIN_API_VERSION "20140221-01" /* macros for defining plugin infos */ #define WEECHAT_PLUGIN_NAME(__name) \ @@ -240,6 +240,7 @@ struct t_weechat_plugin char *(*string_remove_quotes) (const char *string, const char *quotes); char *(*string_strip) (const char *string, int left, int right, const char *chars); + char *(*string_convert_escaped_chars) (const char *string); char *(*string_mask_to_regex) (const char *mask); const char *(*string_regex_flags) (const char *regex, int default_flags, int *flags); @@ -247,8 +248,12 @@ struct t_weechat_plugin int (*string_has_highlight) (const char *string, const char *highlight_words); int (*string_has_highlight_regex) (const char *string, const char *regex); + char *(*string_replace_regex) (const char *string, void *regex, + const char *replace, + const char reference_char); char **(*string_split) (const char *string, const char *separators, int keep_eol, int num_items_max, int *num_items); + char **(*string_split_shell) (const char *string, int *num_items); void (*string_free_split) (char **split_string); char *(*string_build_with_split_string) (const char **split_string, const char *separator); @@ -356,6 +361,7 @@ struct t_weechat_plugin const char *key, const char *value), void *callback_map_data); + struct t_hashtable *(*hashtable_dup) (struct t_hashtable *hashtable); int (*hashtable_get_integer) (struct t_hashtable *hashtable, const char *property); const char *(*hashtable_get_string) (struct t_hashtable *hashtable, @@ -997,6 +1003,8 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin); weechat_plugin->string_remove_quotes(__string, __quotes) #define weechat_string_strip(__string, __left, __right, __chars) \ weechat_plugin->string_strip(__string, __left, __right, __chars) +#define weechat_string_convert_escaped_chars(__string) \ + weechat_plugin->string_convert_escaped_chars(__string) #define weechat_string_mask_to_regex(__mask) \ weechat_plugin->string_mask_to_regex(__mask) #define weechat_string_regex_flags(__regex, __default_flags, __flags) \ @@ -1008,10 +1016,16 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin); weechat_plugin->string_has_highlight(__string, __highlight_words) #define weechat_string_has_highlight_regex(__string, __regex) \ weechat_plugin->string_has_highlight_regex(__string, __regex) +#define weechat_string_replace_regex(__string, __regex, __replace, \ + __reference_char) \ + weechat_plugin->string_replace_regex(__string, __regex, __replace, \ + __reference_char) #define weechat_string_split(__string, __separator, __eol, __max, \ __num_items) \ weechat_plugin->string_split(__string, __separator, __eol, \ __max, __num_items) +#define weechat_string_split_shell(__string, __num_items) \ + weechat_plugin->string_split_shell(__string, __num_items) #define weechat_string_free_split(__split_string) \ weechat_plugin->string_free_split(__split_string) #define weechat_string_build_with_split_string(__split_string, \ @@ -1155,6 +1169,8 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin); __cb_map_data) \ weechat_plugin->hashtable_map_string(__hashtable, __cb_map, \ __cb_map_data) +#define weechat_hashtable_dup(__hashtable) \ + weechat_plugin->hashtable_dup(__hashtable) #define weechat_hashtable_get_integer(__hashtable, __property) \ weechat_plugin->hashtable_get_integer(__hashtable, __property) #define weechat_hashtable_get_string(__hashtable, __property) \ diff --git a/weechat.cygport.in b/weechat.cygport.in index f4a4b3a0e..7b1175cec 100644 --- a/weechat.cygport.in +++ b/weechat.cygport.in @@ -93,6 +93,7 @@ weechat_CONTENTS=" usr/lib/weechat/plugins/relay.dll usr/lib/weechat/plugins/rmodifier.dll usr/lib/weechat/plugins/script.dll + usr/lib/weechat/plugins/trigger.dll usr/lib/weechat/plugins/xfer.dll usr/share/locale/ usr/share/icons/ |