summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--configure.ac19
-rw-r--r--debian/weechat-plugins.install1
-rw-r--r--doc/de/weechat.1.de.txt3
-rw-r--r--doc/docgen.py16
-rw-r--r--doc/en/weechat.1.en.txt3
-rw-r--r--doc/en/weechat_dev.en.txt8
-rw-r--r--doc/en/weechat_plugin_api.en.txt252
-rw-r--r--doc/fr/weechat.1.fr.txt3
-rw-r--r--doc/fr/weechat_dev.fr.txt8
-rw-r--r--doc/fr/weechat_plugin_api.fr.txt270
-rw-r--r--doc/it/weechat.1.it.txt3
-rw-r--r--doc/it/weechat_plugin_api.it.txt262
-rw-r--r--doc/ja/weechat.1.ja.txt3
-rw-r--r--doc/ja/weechat_dev.ja.txt10
-rw-r--r--doc/ja/weechat_plugin_api.ja.txt259
-rw-r--r--doc/pl/weechat.1.pl.txt3
-rw-r--r--po/POTFILES.in72
-rw-r--r--po/srcfiles.cmake84
-rw-r--r--src/core/wee-command.c33
-rw-r--r--src/core/wee-config.c207
-rw-r--r--src/core/wee-hook.c7
-rw-r--r--src/core/wee-proxy.c157
-rw-r--r--src/core/wee-string.c405
-rw-r--r--src/core/wee-string.h5
-rw-r--r--src/gui/gui-bar.c433
-rw-r--r--src/gui/gui-completion.c23
-rw-r--r--src/plugins/CMakeLists.txt12
-rw-r--r--src/plugins/Makefile.am16
-rw-r--r--src/plugins/plugin.c4
-rw-r--r--src/plugins/trigger/CMakeLists.txt31
-rw-r--r--src/plugins/trigger/Makefile.am42
-rw-r--r--src/plugins/trigger/trigger-buffer.c220
-rw-r--r--src/plugins/trigger/trigger-buffer.h34
-rw-r--r--src/plugins/trigger/trigger-callback.c913
-rw-r--r--src/plugins/trigger/trigger-callback.h94
-rw-r--r--src/plugins/trigger/trigger-command.c990
-rw-r--r--src/plugins/trigger/trigger-command.h25
-rw-r--r--src/plugins/trigger/trigger-completion.c392
-rw-r--r--src/plugins/trigger/trigger-completion.h25
-rw-r--r--src/plugins/trigger/trigger-config.c692
-rw-r--r--src/plugins/trigger/trigger-config.h51
-rw-r--r--src/plugins/trigger/trigger.c1217
-rw-r--r--src/plugins/trigger/trigger.h161
-rw-r--r--src/plugins/weechat-plugin.h18
-rw-r--r--weechat.cygport.in1
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],
+ &regex_count,
+ &regex);
+ 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 (&regex_count, &regex);
+ 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/