summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--ChangeLog.asciidoc1
-rw-r--r--configure.ac19
-rw-r--r--debian/weechat-plugins.install1
-rw-r--r--doc/de/weechat_user.de.txt4
-rw-r--r--doc/docgen.py1
-rw-r--r--doc/en/weechat_plugin_api.en.txt32
-rw-r--r--doc/en/weechat_user.en.txt4
-rw-r--r--doc/fr/weechat_plugin_api.fr.txt37
-rw-r--r--doc/fr/weechat_user.fr.txt4
-rw-r--r--doc/it/weechat_plugin_api.it.txt36
-rw-r--r--doc/it/weechat_user.it.txt4
-rw-r--r--doc/ja/weechat_plugin_api.ja.txt36
-rw-r--r--doc/ja/weechat_user.ja.txt4
-rw-r--r--doc/pl/weechat_user.pl.txt4
-rw-r--r--po/POTFILES.in10
-rw-r--r--po/srcfiles.cmake10
-rw-r--r--src/core/wee-command.c68
-rw-r--r--src/core/wee-hook.c14
-rw-r--r--src/core/wee-string.c43
-rw-r--r--src/core/wee-string.h4
-rw-r--r--src/gui/curses/gui-curses-color.c17
-rw-r--r--src/gui/curses/gui-curses.h1
-rw-r--r--src/gui/gui-color.c380
-rw-r--r--src/gui/gui-color.h12
-rw-r--r--src/plugins/CMakeLists.txt4
-rw-r--r--src/plugins/Makefile.am12
-rw-r--r--src/plugins/exec/CMakeLists.txt30
-rw-r--r--src/plugins/exec/Makefile.am40
-rw-r--r--src/plugins/exec/exec-buffer.c146
-rw-r--r--src/plugins/exec/exec-buffer.h27
-rw-r--r--src/plugins/exec/exec-command.c753
-rw-r--r--src/plugins/exec/exec-command.h46
-rw-r--r--src/plugins/exec/exec-completion.c73
-rw-r--r--src/plugins/exec/exec-completion.h25
-rw-r--r--src/plugins/exec/exec-config.c191
-rw-r--r--src/plugins/exec/exec-config.h42
-rw-r--r--src/plugins/exec/exec.c587
-rw-r--r--src/plugins/exec/exec.h79
-rw-r--r--src/plugins/irc/irc-color.c408
-rw-r--r--src/plugins/irc/irc-color.h11
-rw-r--r--src/plugins/irc/irc.c3
-rw-r--r--src/plugins/plugin-api.c69
-rw-r--r--src/plugins/trigger/trigger-callback.c3
-rw-r--r--src/plugins/weechat-plugin.h12
-rw-r--r--weechat.cygport.in1
46 files changed, 3223 insertions, 86 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b1301cc82..da61424a5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -71,6 +71,7 @@ OPTION(ENABLE_ALIAS "Enable Alias plugin" ON)
OPTION(ENABLE_ASPELL "Enable Aspell plugin" ON)
OPTION(ENABLE_ENCHANT "Enable Enchant lib for Aspell plugin" OFF)
OPTION(ENABLE_CHARSET "Enable Charset plugin" ON)
+OPTION(ENABLE_EXEC "Enable Exec plugin" ON)
OPTION(ENABLE_FIFO "Enable FIFO plugin" ON)
OPTION(ENABLE_IRC "Enable IRC plugin" ON)
OPTION(ENABLE_LOGGER "Enable Logger plugin" ON)
diff --git a/ChangeLog.asciidoc b/ChangeLog.asciidoc
index 9dade5ba7..9509860af 100644
--- a/ChangeLog.asciidoc
+++ b/ChangeLog.asciidoc
@@ -15,6 +15,7 @@ http://weechat.org/files/releasenotes/ReleaseNotes-devel.html[release notes]
== Version 0.4.4 (under dev)
+* core: add missing \0 at the end of stderr buffer in hook_process
* core: fix highlight problem with "(?-i)" and upper case letters in option
weechat.look.highlight (closes #24)
* core: use glibtoolize on Mac OS X (autotools) (closes #22)
diff --git a/configure.ac b/configure.ac
index 953e6dc63..414e82052 100644
--- a/configure.ac
+++ b/configure.ac
@@ -104,6 +104,7 @@ AH_VERBATIM([HAVE_ASPELL_VERSION_STRING], [#undef HAVE_ASPELL_VERSION_STRING])
AH_VERBATIM([PLUGIN_ALIAS], [#undef PLUGIN_ALIAS])
AH_VERBATIM([PLUGIN_ASPELL], [#undef PLUGIN_ASPELL])
AH_VERBATIM([PLUGIN_CHARSET], [#undef PLUGIN_CHARSET])
+AH_VERBATIM([PLUGIN_EXEC], [#undef PLUGIN_EXEC])
AH_VERBATIM([PLUGIN_FIFO], [#undef PLUGIN_FIFO])
AH_VERBATIM([PLUGIN_IRC], [#undef PLUGIN_IRC])
AH_VERBATIM([PLUGIN_LOGGER], [#undef PLUGIN_LOGGER])
@@ -131,6 +132,7 @@ AC_ARG_ENABLE(alias, [ --disable-alias turn off Alias plugin (de
AC_ARG_ENABLE(aspell, [ --disable-aspell turn off Aspell plugin (default=compiled)],enable_aspell=$enableval,enable_aspell=yes)
AC_ARG_ENABLE(enchant, [ --enable-enchant turn on Enchant lib for Aspell plugin (default=off)],enable_enchant=$enableval,enable_enchant=no)
AC_ARG_ENABLE(charset, [ --disable-charset turn off Charset plugin (default=compiled if found)],enable_charset=$enableval,enable_charset=yes)
+AC_ARG_ENABLE(exec, [ --disable-exec turn off Exec plugin (default=compiled)],enable_exec=$enableval,enable_exec=yes)
AC_ARG_ENABLE(fifo, [ --disable-fifo turn off Fifo plugin (default=compiled)],enable_fifo=$enableval,enable_fifo=yes)
AC_ARG_ENABLE(irc, [ --disable-irc turn off IRC plugin (default=compiled)],enable_irc=$enableval,enable_irc=yes)
AC_ARG_ENABLE(logger, [ --disable-logger turn off Logger plugin (default=compiled)],enable_logger=$enableval,enable_logger=yes)
@@ -358,6 +360,18 @@ else
not_asked="$not_asked charset"
fi
+# ---------------------------------- exec --------------------------------------
+
+if test "x$enable_exec" = "xyes" ; then
+ EXEC_CFLAGS=""
+ EXEC_LFLAGS=""
+ AC_SUBST(EXEC_CFLAGS)
+ AC_SUBST(EXEC_LFLAGS)
+ AC_DEFINE(PLUGIN_EXEC)
+else
+ not_asked="$not_asked exec"
+fi
+
# ---------------------------------- fifo --------------------------------------
if test "x$enable_fifo" = "xyes" ; then
@@ -1117,6 +1131,7 @@ AM_CONDITIONAL(GUI_NCURSES, test "$enable_ncurses" = "yes")
AM_CONDITIONAL(PLUGIN_ALIAS, test "$enable_alias" = "yes")
AM_CONDITIONAL(PLUGIN_ASPELL, test "$enable_aspell" = "yes")
AM_CONDITIONAL(PLUGIN_CHARSET, test "$enable_charset" = "yes")
+AM_CONDITIONAL(PLUGIN_EXEC, test "$enable_exec" = "yes")
AM_CONDITIONAL(PLUGIN_FIFO, test "$enable_fifo" = "yes")
AM_CONDITIONAL(PLUGIN_IRC, test "$enable_irc" = "yes")
AM_CONDITIONAL(PLUGIN_LOGGER, test "$enable_logger" = "yes")
@@ -1149,6 +1164,7 @@ AC_OUTPUT([Makefile
src/plugins/alias/Makefile
src/plugins/aspell/Makefile
src/plugins/charset/Makefile
+ src/plugins/exec/Makefile
src/plugins/fifo/Makefile
src/plugins/irc/Makefile
src/plugins/logger/Makefile
@@ -1192,6 +1208,9 @@ fi
if test "x$enable_charset" = "xyes"; then
listplugins="$listplugins charset"
fi
+if test "x$enable_exec" = "xyes"; then
+ listplugins="$listplugins exec"
+fi
if test "x$enable_fifo" = "xyes"; then
listplugins="$listplugins fifo"
fi
diff --git a/debian/weechat-plugins.install b/debian/weechat-plugins.install
index ef09e1747..ff345a770 100644
--- a/debian/weechat-plugins.install
+++ b/debian/weechat-plugins.install
@@ -1,4 +1,5 @@
usr/lib/weechat/plugins/aspell.so
+usr/lib/weechat/plugins/exec.so
usr/lib/weechat/plugins/fifo.so
usr/lib/weechat/plugins/guile.so
usr/lib/weechat/plugins/perl.so
diff --git a/doc/de/weechat_user.de.txt b/doc/de/weechat_user.de.txt
index 50444c52e..7e44f280d 100644
--- a/doc/de/weechat_user.de.txt
+++ b/doc/de/weechat_user.de.txt
@@ -1395,8 +1395,8 @@ Farbtabelle für key[ctrl-c,c]:
| 11 | hell türkis | lightcyan
| 12 | hellblau | lightblue
| 13 | hell magenta | lightmagenta
-| 14 | grau | gray
-| 15 | hellgrau | white
+| 14 | grau | darkgray
+| 15 | hellgrau | gray
|===
Beispiel: Im Buffer wird "Hallo an alle!" ausgegeben. Dabei wird "Hallo" in fett und hellblau
diff --git a/doc/docgen.py b/doc/docgen.py
index bafa2dbed..2ebfd3b43 100644
--- a/doc/docgen.py
+++ b/doc/docgen.py
@@ -88,6 +88,7 @@ plugin_list = {
'alias': '',
'aspell': 'o',
'charset': 'o',
+ 'exec': 'o',
'fifo': 'o',
'irc': 'co',
'logger': 'o',
diff --git a/doc/en/weechat_plugin_api.en.txt b/doc/en/weechat_plugin_api.en.txt
index 91631663d..9812abc2e 100644
--- a/doc/en/weechat_plugin_api.en.txt
+++ b/doc/en/weechat_plugin_api.en.txt
@@ -1268,14 +1268,17 @@ This function is not available in scripting API.
_WeeChat ≥ 0.4.4._
-Replace text in a string using a regular expression and replacement text.
+Replace text in a string using a regular expression, replacement text and
+optional callback.
Prototype:
[source,C]
----
char *weechat_string_replace_regex (const char *string, void *regex,
- const char *replace, const char reference_char);
+ const char *replace, const char reference_char,
+ char *(*callback)(void *data, const char *text),
+ void *callback_data);
----
Arguments:
@@ -1291,6 +1294,13 @@ Arguments:
** `$.*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 '$')
+* 'callback': an optional callback called for each reference in 'replace'
+ (except for matches replaced by a char); the callback must return:
+** newly allocated string: it is used as replacement text (it is freed after
+ use)
+** NULL: the text received in callback is used as replacement text (without
+ changes)
+* 'callback_data': pointer given to callback when it is called
Return value:
@@ -1307,7 +1317,7 @@ 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", '$');
+ "$3/$2/$1", '$', NULL, NULL);
/* string == "date: 14/02/2014" */
if (string)
free (string);
@@ -9122,12 +9132,18 @@ List of modifiers used by WeeChat and plugins:
| irc_color_decode |
"1" to keep colors, "0" to remove colors |
Any string |
- String with WeeChat color codes, or without color
+ String with IRC colors converted to WeeChat colors (or IRC colors removed)
| irc_color_encode |
"1" to keep colors, "0" to remove colors |
Any string |
- String with IRC color codes, or without color
+ String with IRC colors (or IRC colors removed)
+
+| irc_color_decode_ansi +
+ _(WeeChat ≥ 0.4.4)_ |
+ "1" to keep colors, "0" to remove colors |
+ Any string |
+ String with ANSI colors converted to IRC colors (or ANSI colors removed)
| irc_command_auth +
_(WeeChat ≥ 0.4.1)_ |
@@ -9165,6 +9181,12 @@ List of modifiers used by WeeChat and plugins:
fit in 512 bytes) |
New content of message
+| color_decode_ansi +
+ _(WeeChat ≥ 0.4.4)_ |
+ "1" to keep colors, "0" to remove colors |
+ Any string |
+ String with ANSI colors converted to WeeChat colors (or ANSI colors removed)
+
| bar_condition_yyy ^(2)^ |
String with window pointer ("0x123..") |
Empty string |
diff --git a/doc/en/weechat_user.en.txt b/doc/en/weechat_user.en.txt
index 792353adf..0bbbd9cc4 100644
--- a/doc/en/weechat_user.en.txt
+++ b/doc/en/weechat_user.en.txt
@@ -1377,8 +1377,8 @@ Color codes for key[ctrl-c,c] are:
| 11 | light cyan | lightcyan
| 12 | light blue | lightblue
| 13 | light magenta | lightmagenta
-| 14 | gray | gray
-| 15 | light gray | white
+| 14 | gray | darkgray
+| 15 | light gray | gray
|===
Example: display of "hello everybody!" with "hello" in light blue bold and
diff --git a/doc/fr/weechat_plugin_api.fr.txt b/doc/fr/weechat_plugin_api.fr.txt
index 60cca1461..b8b334994 100644
--- a/doc/fr/weechat_plugin_api.fr.txt
+++ b/doc/fr/weechat_plugin_api.fr.txt
@@ -1286,15 +1286,17 @@ Cette fonction n'est pas disponible dans l'API script.
_WeeChat ≥ 0.4.4._
-Remplacer du texte dans une chaîne en utilisant une expression régulière et du
-texte de remplacement.
+Remplacer du texte dans une chaîne en utilisant une expression régulière, du
+texte de remplacement et un "callback" optionnel.
Prototype :
[source,C]
----
char *weechat_string_replace_regex (const char *string, void *regex,
- const char *replace, const char reference_char);
+ const char *replace, const char reference_char,
+ char *(*callback)(void *data, const char *text),
+ void *callback_data);
----
Paramètres :
@@ -1314,6 +1316,14 @@ Paramètres :
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 '$')
+* 'callback' : un "callback" optionnel appelé pour chaque référence dans
+ 'replace' (sauf pour les correspondances remplacées par un caractère); le
+ "callback" doit retourner :
+** une chaîne nouvellement allouée : elle est utilisée en texte de remplacement
+ (elle est libérée après utilisation)
+** NULL : le texte reçu dans le "callback" est utilisé comme texte de
+ remplacement (sans changement)
+* 'callback_data' : pointeur donné au "callback" lorsqu'il est appelé
Valeur de retour :
@@ -1330,7 +1340,7 @@ 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", '$');
+ "$3/$2/$1", '$', NULL, NULL);
/* string == "date: 14/02/2014" */
if (string)
free (string);
@@ -9290,12 +9300,20 @@ Liste des modificateurs utilisés par WeeChat et les extensions :
| irc_color_decode |
"1" pour garder les couleurs, "0" pour les supprimer |
Toute chaîne |
- Chaîne avec des codes couleur WeeChat, ou sans couleur
+ Chaîne avec les couleurs IRC converties en couleurs WeeChat (ou avec les
+ couleurs IRC supprimées)
| irc_color_encode |
"1" pour garder les couleurs, "0" pour les supprimer |
Toute chaîne |
- Chaîne avec des codes couleur IRC, ou sans couleur
+ Chaîne avec les couleurs IRC (ou avec les couleurs IRC supprimées)
+
+| irc_color_decode_ansi +
+ _(WeeChat ≥ 0.4.4)_ |
+ "1" pour garder les couleurs, "0" pour les supprimer |
+ Toute chaîne |
+ Chaîne avec les couleurs ANSI converties en couleurs IRC (ou avec les couleurs
+ ANSI supprimées)
| irc_command_auth +
_(WeeChat ≥ 0.4.1)_ |
@@ -9333,6 +9351,13 @@ Liste des modificateurs utilisés par WeeChat et les extensions :
automatique pour tenir dans les 512 octets) |
Nouveau contenu du message
+| color_decode_ansi +
+ _(WeeChat ≥ 0.4.4)_ |
+ "1" pour garder les couleurs, "0" pour les supprimer |
+ Toute chaîne |
+ Chaîne avec les couleurs ANSI converties en couleurs WeeChat (ou avec les
+ couleurs ANSI supprimées)
+
| bar_condition_yyy ^(2)^ |
Chaîne avec un pointeur vers la fenêtre ("0x123..") |
Chaîne vide |
diff --git a/doc/fr/weechat_user.fr.txt b/doc/fr/weechat_user.fr.txt
index a7738e4a9..dc30ebe2a 100644
--- a/doc/fr/weechat_user.fr.txt
+++ b/doc/fr/weechat_user.fr.txt
@@ -1417,8 +1417,8 @@ Les codes couleur pour key[ctrl-c,c] sont :
| 11 | cyan clair | lightcyan
| 12 | bleu clair | lightblue
| 13 | violet clair | lightmagenta
-| 14 | gris | gray
-| 15 | gris clair | white
+| 14 | gris | darkgray
+| 15 | gris clair | gray
|===
Exemple : affichage de "bonjour tout le monde !" avec "bonjour" en bleu clair
diff --git a/doc/it/weechat_plugin_api.it.txt b/doc/it/weechat_plugin_api.it.txt
index 62ae887e6..1ce753ae0 100644
--- a/doc/it/weechat_plugin_api.it.txt
+++ b/doc/it/weechat_plugin_api.it.txt
@@ -1302,14 +1302,17 @@ Questa funzione non è disponibile nelle API per lo scripting.
_WeeChat ≥ 0.4.4._
// TRANSLATION MISSING
-Replace text in a string using a regular expression and replacement text.
+Replace text in a string using a regular expression, replacement text and
+optional callback.
Prototipo:
[source,C]
----
char *weechat_string_replace_regex (const char *string, void *regex,
- const char *replace, const char reference_char);
+ const char *replace, const char reference_char,
+ char *(*callback)(void *data, const char *text),
+ void *callback_data);
----
Argomenti:
@@ -1326,6 +1329,13 @@ Argomenti:
** `$.*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 '$')
+* 'callback': an optional callback called for each reference in 'replace'
+ (except for matches replaced by a char); the callback must return:
+** newly allocated string: it is used as replacement text (it is freed after
+ use)
+** NULL: the text received in callback is used as replacement text (without
+ changes)
+* 'callback_data': pointer given to callback when it is called
Valore restituito:
@@ -1343,7 +1353,7 @@ 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", '$');
+ "$3/$2/$1", '$', NULL, NULL);
/* string == "date: 14/02/2014" */
if (string)
free (string);
@@ -9346,15 +9356,24 @@ List of modifiers used by WeeChat and plugins:
Qualsiasi stringa |
Stringa codificata da UTF-8 al set caratteri trovato per il plugin/buffer
+// TRANSLATION MISSING
| irc_color_decode |
"1" per mantenere i colori, "0" per rimuovere i colori |
Qualsiasi stringa |
- Stringa con i codici colori di Weechat, o senza colore
+ String with IRC colors converted to WeeChat colors (or IRC colors removed)
+// TRANSLATION MISSING
| irc_color_encode |
"1" per mantenere i colori, "0" per rimuovere i colori |
Qualsiasi stringa |
- Stringa con i codici colori IRC, o senza colore
+ String with IRC colors (or IRC colors removed)
+
+// TRANSLATION MISSING
+| irc_color_decode_ansi +
+ _(WeeChat ≥ 0.4.4)_ |
+ "1" per mantenere i colori, "0" per rimuovere i colori |
+ Qualsiasi stringa |
+ String with ANSI colors converted to IRC colors (or ANSI colors removed)
// TRANSLATION MISSING
| irc_command_auth +
@@ -9392,6 +9411,13 @@ List of modifiers used by WeeChat and plugins:
Contenuto del messaggio che sta per essere inviato al server IRC (dopo la divisione automatica da adattare in 512 byte) |
Nuovo contenuto del messaggio
+// TRANSLATION MISSING
+| color_decode_ansi +
+ _(WeeChat ≥ 0.4.4)_ |
+ "1" per mantenere i colori, "0" per rimuovere i colori |
+ Qualsiasi stringa |
+ String with ANSI colors converted to WeeChat colors (or ANSI colors removed)
+
| bar_condition_yyy ^(2)^ |
Stringa con puntatore alla finestra ("0x123..") |
Stringa vuota |
diff --git a/doc/it/weechat_user.it.txt b/doc/it/weechat_user.it.txt
index d6fcf6c1e..9ba076a81 100644
--- a/doc/it/weechat_user.it.txt
+++ b/doc/it/weechat_user.it.txt
@@ -1429,8 +1429,8 @@ I codici colore per key[ctrl-c,c] sono:
| 11 | azzurro chiaro | lightcyan
| 12 | blu chiaro | lightblue
| 13 | rosa chiaro | lightmagenta
-| 14 | grigio | gray
-| 15 | grigio chiaro | white
+| 14 | grigio | darkgray
+| 15 | grigio chiaro | gray
|===
Esempio: visualizza "ciao a tutti!" con "ciao" scritto in blu chiaro grassetto
diff --git a/doc/ja/weechat_plugin_api.ja.txt b/doc/ja/weechat_plugin_api.ja.txt
index 42032beef..b610b8fe9 100644
--- a/doc/ja/weechat_plugin_api.ja.txt
+++ b/doc/ja/weechat_plugin_api.ja.txt
@@ -1269,14 +1269,17 @@ free (str);
_WeeChat バージョン 0.4.4 以上で利用可。_
// TRANSLATION MISSING
-Replace text in a string using a regular expression and replacement text.
+Replace text in a string using a regular expression, replacement text and
+optional callback.
プロトタイプ:
[source,C]
----
char *weechat_string_replace_regex (const char *string, void *regex,
- const char *replace, const char reference_char);
+ const char *replace, const char reference_char,
+ char *(*callback)(void *data, const char *text),
+ void *callback_data);
----
引数:
@@ -1293,6 +1296,13 @@ char *weechat_string_replace_regex (const char *string, void *regex,
** `$.*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 '$')
+* 'callback': an optional callback called for each reference in 'replace'
+ (except for matches replaced by a char); the callback must return:
+** newly allocated string: it is used as replacement text (it is freed after
+ use)
+** NULL: the text received in callback is used as replacement text (without
+ changes)
+* 'callback_data': pointer given to callback when it is called
戻り値:
@@ -1310,7 +1320,7 @@ 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", '$');
+ "$3/$2/$1", '$', NULL, NULL);
/* string == "date: 14/02/2014" */
if (string)
free (string);
@@ -9138,15 +9148,24 @@ WeeChat とプラグインが使う修飾子のリスト:
任意の文字列 |
UTF-8 からプラグインおよびバッファの文字セットにエンコードされた文字列
+// TRANSLATION MISSING
| irc_color_decode |
色を保持する場合は "1"、削除する場合は "0" |
任意の文字列 |
- WeeChat 色コードを含む文字列および含まない文字列
+ String with IRC colors converted to WeeChat colors (or IRC colors removed)
+// TRANSLATION MISSING
| irc_color_encode |
色を保持する場合は "1"、削除する場合は "0" |
任意の文字列 |
- IRC 色コードを含む文字列および含まない文字列
+ String with IRC colors (or IRC colors removed)
+
+// TRANSLATION MISSING
+| irc_color_decode_ansi +
+ _(WeeChat バージョン 0.4.4 以上で利用可)_ |
+ 色を保持する場合は "1"、削除する場合は "0" |
+ 任意の文字列 |
+ String with ANSI colors converted to IRC colors (or ANSI colors removed)
| irc_command_auth +
_(WeeChat バージョン 0.4.1 以上で利用可)_ |
@@ -9182,6 +9201,13 @@ WeeChat とプラグインが使う修飾子のリスト:
IRC サーバに送信するメッセージの内容 (512 バイトを超えないように自動分割した後) |
メッセージの新しい内容
+// TRANSLATION MISSING
+| color_decode_ansi +
+ _(WeeChat バージョン 0.4.4 以上で利用可)_ |
+ 色を保持する場合は "1"、削除する場合は "0" |
+ 任意の文字列 |
+ String with ANSI colors converted to WeeChat colors (or ANSI colors removed)
+
| bar_condition_yyy ^(2)^ |
ウィンドウへのポインタの文字列 ("0x123..") |
空文字列 |
diff --git a/doc/ja/weechat_user.ja.txt b/doc/ja/weechat_user.ja.txt
index 383a11649..469fd2946 100644
--- a/doc/ja/weechat_user.ja.txt
+++ b/doc/ja/weechat_user.ja.txt
@@ -1379,8 +1379,8 @@ key[ctrl-c,c] 用の色コード:
| 11 | 明るい青緑色 | lightcyan
| 12 | 明るい青 | lightblue
| 13 | 明るい赤紫色 | lightmagenta
-| 14 | 灰色 | gray
-| 15 | 明るい灰色 | white
+| 14 | 灰色 | darkgray
+| 15 | 明るい灰色 | gray
|===
例: "こんにちは皆さん!" の "こんにちは" を太字の明るい青、"皆さん"
diff --git a/doc/pl/weechat_user.pl.txt b/doc/pl/weechat_user.pl.txt
index de5ab9260..606fcf9d5 100644
--- a/doc/pl/weechat_user.pl.txt
+++ b/doc/pl/weechat_user.pl.txt
@@ -1387,8 +1387,8 @@ Kody kolorów dla key[ctrl-c,c]:
| 11 | light cyan | lightcyan
| 12 | light blue | lightblue
| 13 | light magenta | lightmagenta
-| 14 | gray | gray
-| 15 | light gray | white
+| 14 | gray | darkgray
+| 15 | light gray | gray
|===
Przykład: wyświetlenie "hello everybody!" z pogrubionym jasno niebieskim "hello"
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 82aec229f..d0dadead2 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -113,6 +113,16 @@
./src/plugins/aspell/weechat-aspell-speller.c
./src/plugins/aspell/weechat-aspell-speller.h
./src/plugins/charset/charset.c
+./src/plugins/exec/exec.c
+./src/plugins/exec/exec-buffer.c
+./src/plugins/exec/exec-buffer.h
+./src/plugins/exec/exec-command.c
+./src/plugins/exec/exec-command.h
+./src/plugins/exec/exec-completion.c
+./src/plugins/exec/exec-completion.h
+./src/plugins/exec/exec-config.c
+./src/plugins/exec/exec-config.h
+./src/plugins/exec/exec.h
./src/plugins/fifo/fifo.c
./src/plugins/fifo/fifo.h
./src/plugins/fifo/fifo-info.c
diff --git a/po/srcfiles.cmake b/po/srcfiles.cmake
index b51385503..886397caa 100644
--- a/po/srcfiles.cmake
+++ b/po/srcfiles.cmake
@@ -114,6 +114,16 @@ SET(WEECHAT_SOURCES
./src/plugins/aspell/weechat-aspell-speller.c
./src/plugins/aspell/weechat-aspell-speller.h
./src/plugins/charset/charset.c
+./src/plugins/exec/exec.c
+./src/plugins/exec/exec-buffer.c
+./src/plugins/exec/exec-buffer.h
+./src/plugins/exec/exec-command.c
+./src/plugins/exec/exec-command.h
+./src/plugins/exec/exec-completion.c
+./src/plugins/exec/exec-completion.h
+./src/plugins/exec/exec-config.c
+./src/plugins/exec/exec-config.h
+./src/plugins/exec/exec.h
./src/plugins/fifo/fifo.c
./src/plugins/fifo/fifo.h
./src/plugins/fifo/fifo-info.c
diff --git a/src/core/wee-command.c b/src/core/wee-command.c
index e29d4cd03..2faf34276 100644
--- a/src/core/wee-command.c
+++ b/src/core/wee-command.c
@@ -1157,7 +1157,8 @@ COMMAND_CALLBACK(color)
{
char *str_alias, *str_rgb, *pos, *error;
char str_color[1024], str_command[1024];
- long number;
+ long number, limit;
+ unsigned int rgb;
int i;
struct t_gui_color_palette *color_palette;
@@ -1302,6 +1303,46 @@ COMMAND_CALLBACK(color)
return WEECHAT_RC_OK;
}
+ /* convert terminal color to RGB color */
+ if (string_strcasecmp (argv[1], "term2rgb") == 0)
+ {
+ if (argc < 3)
+ return WEECHAT_RC_ERROR;
+ error = NULL;
+ number = strtol (argv[2], &error, 10);
+ if (!error || error[0] || (number < 0) || (number > 255))
+ return WEECHAT_RC_ERROR;
+ gui_chat_printf (NULL,
+ "%ld -> #%06x",
+ number,
+ gui_color_convert_term_to_rgb (number));
+ return WEECHAT_RC_OK;
+ }
+
+ /* convert RGB color to terminal color */
+ if (string_strcasecmp (argv[1], "rgb2term") == 0)
+ {
+ if (argc < 3)
+ return WEECHAT_RC_ERROR;
+ if (sscanf ((argv[2][0] == '#') ? argv[2] + 1 : argv[2], "%x", &rgb) != 1)
+ return WEECHAT_RC_ERROR;
+ if (rgb > 0xFFFFFF)
+ return WEECHAT_RC_ERROR;
+ limit = 256;
+ if (argc > 3)
+ {
+ error = NULL;
+ limit = strtol (argv[3], &error, 10);
+ if (!error || error[0] || (limit < 1) || (limit > 256))
+ return WEECHAT_RC_ERROR;
+ }
+ gui_chat_printf (NULL,
+ "#%06x -> %d",
+ rgb,
+ gui_color_convert_rgb_to_term (rgb, limit));
+ return WEECHAT_RC_OK;
+ }
+
return WEECHAT_RC_ERROR;
}
@@ -6612,16 +6653,25 @@ command_init ()
hook_command (
NULL, "color",
N_("define color aliases and display palette of colors"),
- N_("alias <color> <name> || unalias <color> || reset || -o"),
- N_(" alias: add an alias for a color\n"
- "unalias: delete an alias\n"
- " color: color number (greater than or equal to 0, max depends on "
+ N_("alias <color> <name>"
+ " || unalias <color>"
+ " || reset"
+ " || term2rgb <color>"
+ " || rgb2term <rgb> [<limit>]"
+ " || -o"),
+ N_(" alias: add an alias for a color\n"
+ " unalias: delete an alias\n"
+ " color: color number (greater than or equal to 0, max depends on "
"terminal, commonly 63 or 255)\n"
- " name: alias name for color (for example: \"orange\")\n"
- " reset: reset all color pairs (required when no more color pairs "
+ " name: alias name for color (for example: \"orange\")\n"
+ " reset: reset all color pairs (required when no more color pairs "
"are available if automatic reset is disabled, see option "
"weechat.look.color_pairs_auto_reset)\n"
- " -o: send terminal/colors info to current buffer as input\n"
+ "term2rgb: convert a terminal color (0-255) to RGB color\n"
+ "rgb2term: convert a RGB color to terminal color (0-255)\n"
+ " limit: number of colors to use in terminal table (starting from "
+ "0); default is 256\n"
+ " -o: send terminal/colors info to current buffer as input\n"
"\n"
"Without argument, this command displays colors in a new buffer.\n"
"\n"
@@ -6633,6 +6683,8 @@ command_init ()
"alias %(palette_colors)"
" || unalias %(palette_colors)"
" || reset"
+ " || term2rgb"
+ " || rgb2term"
" || -o",
&command_color, NULL);
/*
diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c
index 415879530..0334464f3 100644
--- a/src/core/wee-hook.c
+++ b/src/core/wee-hook.c
@@ -1607,15 +1607,15 @@ hook_process_child (struct t_hook *hook_process)
void
hook_process_send_buffers (struct t_hook *hook_process, int callback_rc)
{
- int i, size;
+ int size;
/* add '\0' at end of stdout and stderr */
- for (i = 0; i < 2; i++)
- {
- size = HOOK_PROCESS(hook_process, buffer_size[i]);
- if (size > 0)
- HOOK_PROCESS(hook_process, buffer[i])[size] = '\0';
- }
+ size = HOOK_PROCESS(hook_process, buffer_size[HOOK_PROCESS_STDOUT]);
+ if (size > 0)
+ HOOK_PROCESS(hook_process, buffer[HOOK_PROCESS_STDOUT])[size] = '\0';
+ size = HOOK_PROCESS(hook_process, buffer_size[HOOK_PROCESS_STDERR]);
+ if (size > 0)
+ HOOK_PROCESS(hook_process, buffer[HOOK_PROCESS_STDERR])[size] = '\0';
/* send buffers to callback */
(void) (HOOK_PROCESS(hook_process, callback))
diff --git a/src/core/wee-string.c b/src/core/wee-string.c
index ae8292290..e8f9ed589 100644
--- a/src/core/wee-string.c
+++ b/src/core/wee-string.c
@@ -1146,7 +1146,9 @@ string_replace (const char *string, const char *search, const char *replace)
char *
string_replace_regex_get_replace (const char *string, regmatch_t *regex_match,
int last_match, const char *replace,
- const char reference_char)
+ const char reference_char,
+ char *(*callback)(void *data, const char *text),
+ void *callback_data)
{
int length, length_current, length_add, match;
const char *ptr_replace, *ptr_add;
@@ -1200,8 +1202,26 @@ string_replace_regex_get_replace (const char *string, regmatch_t *regex_match,
}
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;
+ if (callback)
+ {
+ temp = string_strndup (string + regex_match[match].rm_so,
+ regex_match[match].rm_eo - regex_match[match].rm_so);
+ if (temp)
+ {
+ modified_replace = (*callback) (callback_data, temp);
+ if (modified_replace)
+ {
+ ptr_add = modified_replace;
+ length_add = strlen (modified_replace);
+ }
+ free (temp);
+ }
+ }
+ if (!ptr_add)
+ {
+ 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] == '.')
@@ -1300,6 +1320,11 @@ string_replace_regex_get_replace (const char *string, regmatch_t *regex_match,
* (the char '*' can be replaced by any char between space (32)
* and '~' (126))
*
+ * If the callback is not NULL, it is called for every reference to a match
+ * (except for matches replaced by a char).
+ * If not NULL, the string returned by the callback (which must have been newly
+ * allocated) is used and freed after use.
+ *
* Examples:
*
* string | regex | replace | result
@@ -1314,7 +1339,9 @@ string_replace_regex_get_replace (const char *string, regmatch_t *regex_match,
char *
string_replace_regex (const char *string, void *regex, const char *replace,
- const char reference_char)
+ const char reference_char,
+ char *(*callback)(void *data, const char *text),
+ void *callback_data)
{
char *result, *result2, *str_replace;
int length, length_replace, start_offset, i, rc, end, last_match;
@@ -1365,9 +1392,13 @@ string_replace_regex (const char *string, void *regex, const char *replace,
/* 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,
+ str_replace = string_replace_regex_get_replace (result,
+ regex_match,
last_match,
- replace, reference_char);
+ replace,
+ reference_char,
+ callback,
+ callback_data);
length_replace = (str_replace) ? strlen (str_replace) : 0;
length = regex_match[0].rm_so + length_replace +
diff --git a/src/core/wee-string.h b/src/core/wee-string.h
index 1ae8cb9b2..bf34cb2a3 100644
--- a/src/core/wee-string.h
+++ b/src/core/wee-string.h
@@ -59,7 +59,9 @@ extern int string_has_highlight_regex_compiled (const char *string,
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);
+ const char reference_char,
+ char *(*callback)(void *data, const char *text),
+ void *callback_data);
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,
diff --git a/src/gui/curses/gui-curses-color.c b/src/gui/curses/gui-curses-color.c
index 41ce2b54a..60291421b 100644
--- a/src/gui/curses/gui-curses-color.c
+++ b/src/gui/curses/gui-curses-color.c
@@ -1539,20 +1539,3 @@ gui_color_dump ()
}
}
}
-
-/*
- * Ends GUI colors.
- */
-
-void
-gui_color_end ()
-{
- int i;
-
- for (i = 0; i < GUI_COLOR_NUM_COLORS; i++)
- {
- gui_color_free (gui_color[i]);
- }
- gui_color_palette_free_structs ();
- gui_color_free_vars ();
-}
diff --git a/src/gui/curses/gui-curses.h b/src/gui/curses/gui-curses.h
index 35c4b9b20..7553e842f 100644
--- a/src/gui/curses/gui-curses.h
+++ b/src/gui/curses/gui-curses.h
@@ -86,7 +86,6 @@ extern int gui_color_get_pair (int fg, int bg);
extern int gui_color_weechat_get_pair (int weechat_color);
extern void gui_color_pre_init ();
extern void gui_color_init ();
-extern void gui_color_end ();
/* chat functions */
extern void gui_chat_calculate_line_diff (struct t_gui_window *window,
diff --git a/src/gui/gui-color.c b/src/gui/gui-color.c
index 13b4ea8ff..a851b15da 100644
--- a/src/gui/gui-color.c
+++ b/src/gui/gui-color.c
@@ -31,6 +31,7 @@
#include <signal.h>
#include <time.h>
#include <ctype.h>
+#include <limits.h>
#include "../core/weechat.h"
#include "../core/wee-config.h"
@@ -51,6 +52,65 @@ struct t_hashtable *gui_color_hash_palette_color = NULL;
struct t_hashtable *gui_color_hash_palette_alias = NULL;
struct t_weelist *gui_color_list_with_alias = NULL;
+/* terminal colors */
+int gui_color_term256[256] =
+{
+ 0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, /* 0-5 */
+ 0x008080, 0xc0c0c0, 0x808080, 0xff0000, 0x00ff00, 0xffff00, /* 6-11 */
+ 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff, 0x000000, 0x00005f, /* 12-17 */
+ 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, /* 18-23 */
+ 0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, /* 24-29 */
+ 0x008787, 0x0087af, 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, /* 30-35 */
+ 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, 0x00d700, 0x00d75f, /* 36-41 */
+ 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, /* 42-47 */
+ 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, /* 48-53 */
+ 0x5f0087, 0x5f00af, 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, /* 54-59 */
+ 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, 0x5f8700, 0x5f875f, /* 60-65 */
+ 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f, /* 66-71 */
+ 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, /* 72-77 */
+ 0x5fd787, 0x5fd7af, 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, /* 78-83 */
+ 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, 0x870000, 0x87005f, /* 84-89 */
+ 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, /* 90-95 */
+ 0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, /* 96-101 */
+ 0x878787, 0x8787af, 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, /* 102-107 */
+ 0x87af87, 0x87afaf, 0x87afd7, 0x87afff, 0x87d700, 0x87d75f, /* 108-113 */
+ 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f, /* 114-119 */
+ 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, /* 120-125 */
+ 0xaf0087, 0xaf00af, 0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, /* 126-131 */
+ 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, 0xaf8700, 0xaf875f, /* 132-137 */
+ 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f, /* 138-143 */
+ 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, /* 144-149 */
+ 0xafd787, 0xafd7af, 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, /* 150-155 */
+ 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, 0xd70000, 0xd7005f, /* 156-161 */
+ 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, /* 162-167 */
+ 0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, /* 168-173 */
+ 0xd78787, 0xd787af, 0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, /* 174-179 */
+ 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff, 0xd7d700, 0xd7d75f, /* 180-185 */
+ 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f, /* 186-191 */
+ 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, 0xff0000, 0xff005f, /* 192-197 */
+ 0xff0087, 0xff00af, 0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, /* 198-203 */
+ 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff, 0xff8700, 0xff875f, /* 204-209 */
+ 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f, /* 210-215 */
+ 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, 0xffd75f, /* 216-221 */
+ 0xffd787, 0xffd7af, 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, /* 222-227 */
+ 0xffff87, 0xffffaf, 0xffffd7, 0xffffff, 0x080808, 0x121212, /* 228-233 */
+ 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, /* 234-239 */
+ 0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, /* 240-245 */
+ 0x949494, 0x9e9e9e, 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, /* 246-251 */
+ 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee, /* 252-255 */
+};
+
+/* ANSI colors */
+regex_t *gui_color_regex_ansi = NULL;
+char *gui_color_ansi[16] =
+{
+ /* 0-7 */
+ "black", "red", "green", "brown", "blue", "magenta", "cyan", "gray",
+ /* 8-15 */
+ "darkgray", "lightred", "lightgreen", "yellow", "lightblue", "lightmagenta",
+ "lightcyan", "white",
+};
+
/*
* Searches for a color with configuration option name.
@@ -401,6 +461,68 @@ gui_color_get_custom (const char *color_name)
}
/*
+ * Converts a terminal color to its RGB value.
+ *
+ * Returns a RGB color as integer.
+ */
+
+int
+gui_color_convert_term_to_rgb (int color)
+{
+ if ((color < 0) || (color > 255))
+ return 0;
+
+ return gui_color_term256[color];
+}
+
+/*
+ * Converts a RGB color to the closest terminal color.
+ *
+ * Argument "limit" is the number of colors to check in the table of terminal
+ * colors (starting from 0). So for example 256 will return any of the 256
+ * colors, 16 will return a color between 0 and 15.
+ *
+ * Returns the closest terminal color (0-255).
+ */
+
+int
+gui_color_convert_rgb_to_term (int rgb, int limit)
+{
+ int i, r1, g1, b1, r2, g2, b2, diff, best_diff, best_color;
+
+ r1 = rgb >> 16;
+ g1 = (rgb >> 8) & 0xFF;
+ b1 = rgb & 0xFF;
+
+ best_diff = INT_MAX;
+ best_color = 0;
+
+ for (i = 0; i < limit; i++)
+ {
+ r2 = gui_color_term256[i] >> 16;
+ g2 = (gui_color_term256[i] >> 8) & 0xFF;
+ b2 = gui_color_term256[i] & 0xFF;
+
+ diff = ((r2 - r1) * (r2 - r1)) +
+ ((g2 - g1) * (g2 - g1)) +
+ ((b2 - b1) * (b2 - b1));
+
+ /* exact match! */
+ if (diff == 0)
+ return i;
+
+ if (diff < best_diff)
+ {
+ best_color = i;
+ best_diff = diff;
+ }
+ }
+
+ /* return the closest color */
+ return best_color;
+}
+
+/*
* Removes WeeChat color codes from a message.
*
* If replacement is not NULL and not empty, it is used to replace color codes
@@ -594,6 +716,240 @@ gui_color_decode (const char *string, const char *replacement)
}
/*
+ * Converts ANSI color codes to WeeChat colors (or removes them).
+ *
+ * This callback is called by gui_color_decode_ansi, it must not be called
+ * directly.
+ */
+
+char *
+gui_color_decode_ansi_cb (void *data, const char *text)
+{
+ unsigned long keep_colors;
+ char *text2, **items, *output, str_color[128];
+ int i, length, num_items, value;
+
+ keep_colors = (unsigned long)data;
+
+ /* if we don't keep colors of if text is empty, just return empty string */
+ if (!keep_colors || !text || !text[0])
+ return strdup ("");
+
+ /* only sequences ending with 'm' are used, the others are discarded */
+ length = strlen (text);
+ if (text[length - 1] != 'm')
+ return strdup ("");
+
+ /* sequence "\33[m" resets color */
+ if (length < 4)
+ return strdup (gui_color_get_custom ("reset"));
+
+ text2 = NULL;
+ items = NULL;
+ output = NULL;
+
+ /* extract text between "\33[" and "m" */
+ text2 = string_strndup (text + 2, length - 3);
+ if (!text2)
+ goto end;
+
+ items = string_split (text2, ";", 0, 0, &num_items);
+ if (!items)
+ goto end;
+
+ output = malloc ((32 * num_items) + 1);
+ if (!output)
+ goto end;
+ output[0] = '\0';
+
+ for (i = 0; i < num_items; i++)
+ {
+ value = atoi (items[i]);
+ switch (value)
+ {
+ case 0: /* reset */
+ strcat (output, gui_color_get_custom ("reset"));
+ break;
+ case 1: /* bold */
+ strcat (output, gui_color_get_custom ("bold"));
+ break;
+ case 2: /* remove bold */
+ case 21:
+ case 22:
+ strcat (output, gui_color_get_custom ("-bold"));
+ break;
+ case 3: /* italic */
+ strcat (output, gui_color_get_custom ("italic"));
+ break;
+ case 4: /* underline */
+ strcat (output, gui_color_get_custom ("underline"));
+ break;
+ case 23: /* remove italic */
+ strcat (output, gui_color_get_custom ("-italic"));
+ break;
+ case 24: /* remove underline */
+ strcat (output, gui_color_get_custom ("-underline"));
+ break;
+ case 30: /* text color */
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ strcat (output,
+ gui_color_get_custom (gui_color_ansi[value - 30]));
+ break;
+ case 38: /* text color */
+ if (i + 1 < num_items)
+ {
+ switch (atoi (items[i + 1]))
+ {
+ case 2: /* RGB color */
+ if (i + 4 < num_items)
+ {
+ snprintf (str_color, sizeof (str_color),
+ "|%d",
+ gui_color_convert_rgb_to_term (
+ (atoi (items[i + 2]) << 16) |
+ (atoi (items[i + 3]) << 8) |
+ atoi (items[i + 4]),
+ 256));
+ strcat (output, gui_color_get_custom (str_color));
+ i += 4;
+ }
+ break;
+ case 5: /* terminal color (0-255) */
+ if (i + 2 < num_items)
+ {
+ snprintf (str_color, sizeof (str_color),
+ "|%d", atoi (items[i + 2]));
+ strcat (output, gui_color_get_custom (str_color));
+ i += 2;
+ }
+ break;
+ }
+ }
+ break;
+ case 39: /* default text color */
+ strcat (output, gui_color_get_custom ("default"));
+ break;
+ case 40: /* background color */
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ snprintf (str_color, sizeof (str_color),
+ "|,%s",
+ gui_color_ansi[value - 40]);
+ strcat (output, gui_color_get_custom (str_color));
+ break;
+ case 48: /* background color */
+ if (i + 1 < num_items)
+ {
+ switch (atoi (items[i + 1]))
+ {
+ case 2: /* RGB color */
+ if (i + 4 < num_items)
+ {
+ snprintf (str_color, sizeof (str_color),
+ "|,%d",
+ gui_color_convert_rgb_to_term (
+ (atoi (items[i + 2]) << 16) |
+ (atoi (items[i + 3]) << 8) |
+ atoi (items[i + 4]),
+ 256));
+ strcat (output, gui_color_get_custom (str_color));
+ i += 4;
+ }
+ break;
+ case 5: /* terminal color (0-255) */
+ if (i + 2 < num_items)
+ {
+ snprintf (str_color, sizeof (str_color),
+ "|,%d", atoi (items[i + 2]));
+ strcat (output, gui_color_get_custom (str_color));
+ i += 2;
+ }
+ break;
+ }
+ }
+ break;
+ case 49: /* default background color */
+ strcat (output, gui_color_get_custom (",default"));
+ break;
+ case 90: /* text color (bright) */
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ strcat (output,
+ gui_color_get_custom (gui_color_ansi[value - 90 + 8]));
+ break;
+ case 100: /* background color (bright) */
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ snprintf (str_color, sizeof (str_color),
+ "|,%s",
+ gui_color_ansi[value - 100 + 8]);
+ strcat (output, gui_color_get_custom (str_color));
+ break;
+ }
+ }
+
+end:
+ if (items)
+ string_free_split (items);
+ if (text2)
+ free (text2);
+
+ return (output) ? output : strdup ("");
+}
+
+/*
+ * Converts ANSI color codes to WeeChat colors (or removes them).
+ *
+ * Note: result must be freed after use.
+ */
+
+char *
+gui_color_decode_ansi (const char *string, int keep_colors)
+{
+ /* allocate/compile regex if needed (first call) */
+ if (!gui_color_regex_ansi)
+ {
+ gui_color_regex_ansi = malloc (sizeof (*gui_color_regex_ansi));
+ if (!gui_color_regex_ansi)
+ return NULL;
+ if (string_regcomp (gui_color_regex_ansi,
+ GUI_COLOR_REGEX_ANSI_DECODE,
+ REG_EXTENDED) != 0)
+ {
+ free (gui_color_regex_ansi);
+ gui_color_regex_ansi = NULL;
+ return NULL;
+ }
+ }
+
+ return string_replace_regex (string, gui_color_regex_ansi,
+ "$0", '$',
+ &gui_color_decode_ansi_cb,
+ (void *)((unsigned long)keep_colors));
+}
+
+/*
* Emphasizes a string or regular expression in a string (which can contain
* colors).
*
@@ -916,3 +1272,27 @@ gui_color_palette_free_structs ()
if (gui_color_list_with_alias)
weelist_free (gui_color_list_with_alias);
}
+
+/*
+ * Ends GUI colors.
+ */
+
+void
+gui_color_end ()
+{
+ int i;
+
+ for (i = 0; i < GUI_COLOR_NUM_COLORS; i++)
+ {
+ gui_color_free (gui_color[i]);
+ }
+ gui_color_palette_free_structs ();
+ gui_color_free_vars ();
+
+ if (gui_color_regex_ansi)
+ {
+ regfree (gui_color_regex_ansi);
+ free (gui_color_regex_ansi);
+ gui_color_regex_ansi = NULL;
+ }
+}
diff --git a/src/gui/gui-color.h b/src/gui/gui-color.h
index 598b22555..b19a500f7 100644
--- a/src/gui/gui-color.h
+++ b/src/gui/gui-color.h
@@ -138,6 +138,12 @@ enum t_gui_color_enum
#define GUI_COLOR_EXTENDED_MASK 0x00FFFFF
#define GUI_COLOR_EXTENDED_MAX 99999
+#define GUI_COLOR_REGEX_ANSI_DECODE \
+ "\33(" \
+ "([()].)|" \
+ "([<>])|" \
+ "(\\[[0-9;?]*[A-Za-z]))"
+
/* color structure */
struct t_gui_color
@@ -169,7 +175,10 @@ extern const char *gui_color_search_config (const char *color_name);
extern int gui_color_attr_get_flag (char c);
extern void gui_color_attr_build_string (int color, char *str_attr);
extern const char *gui_color_get_custom (const char *color_name);
+extern int gui_color_convert_term_to_rgb (int color);
+extern int gui_color_convert_rgb_to_term (int rgb, int limit);
extern char *gui_color_decode (const char *string, const char *replacement);
+extern char *gui_color_decode_ansi (const char *string, int keep_colors);
extern char *gui_color_emphasize (const char *string, const char *search,
int case_sensitive, regex_t *regex);
extern void gui_color_free (struct t_gui_color *color);
@@ -178,7 +187,7 @@ extern int gui_color_palette_get_alias (const char *alias);
extern struct t_gui_color_palette *gui_color_palette_get (int number);
extern void gui_color_palette_add (int number, const char *value);
extern void gui_color_palette_remove (int number);
-extern void gui_color_palette_free_structs ();
+extern void gui_color_end ();
/* color functions (GUI dependent) */
@@ -189,6 +198,7 @@ extern int gui_color_assign_by_diff (int *color, const char *color_name,
extern int gui_color_get_weechat_colors_number ();
extern int gui_color_get_term_colors ();
extern const char *gui_color_get_name (int num_color);
+extern void gui_color_free_vars ();
extern void gui_color_init_weechat ();
extern void gui_color_display_terminal_colors ();
extern void gui_color_info_term_colors (char *buffer, int size);
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index 5bfdb9444..1e5587454 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -72,6 +72,10 @@ IF(ENABLE_CHARSET)
ENDIF(ICONV_FOUND)
ENDIF(ENABLE_CHARSET)
+IF(ENABLE_EXEC)
+ ADD_SUBDIRECTORY( exec )
+ENDIF(ENABLE_EXEC)
+
IF(ENABLE_FIFO)
ADD_SUBDIRECTORY( fifo )
ENDIF(ENABLE_FIFO)
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index d546c026e..d42af9c74 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -51,6 +51,10 @@ if PLUGIN_CHARSET
charset_dir = charset
endif
+if PLUGIN_EXEC
+exec_dir = exec
+endif
+
if PLUGIN_FIFO
fifo_dir = fifo
endif
@@ -103,10 +107,10 @@ if PLUGIN_XFER
xfer_dir = xfer
endif
-SUBDIRS = . $(alias_dir) $(aspell_dir) $(charset_dir) $(fifo_dir) $(irc_dir) \
- $(logger_dir) $(relay_dir) $(script_dir) $(perl_dir) $(python_dir) \
- $(ruby_dir) $(lua_dir) $(tcl_dir) $(guile_dir) $(trigger_dir) \
- $(xfer_dir)
+SUBDIRS = . $(alias_dir) $(aspell_dir) $(charset_dir) $(exec_dir) $(fifo_dir) \
+ $(irc_dir) $(logger_dir) $(relay_dir) $(script_dir) $(perl_dir) \
+ $(python_dir) $(ruby_dir) $(lua_dir) $(tcl_dir) $(guile_dir) \
+ $(trigger_dir) $(xfer_dir)
EXTRA_DIST = CMakeLists.txt
diff --git a/src/plugins/exec/CMakeLists.txt b/src/plugins/exec/CMakeLists.txt
new file mode 100644
index 000000000..a5286eabd
--- /dev/null
+++ b/src/plugins/exec/CMakeLists.txt
@@ -0,0 +1,30 @@
+#
+# 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(exec MODULE
+exec.c exec.h
+exec-buffer.c exec-buffer.h
+exec-command.c exec-command.h
+exec-completion.c exec-completion.h
+exec-config.c exec-config.h)
+SET_TARGET_PROPERTIES(exec PROPERTIES PREFIX "")
+
+TARGET_LINK_LIBRARIES(exec)
+
+INSTALL(TARGETS exec LIBRARY DESTINATION ${LIBDIR}/plugins)
diff --git a/src/plugins/exec/Makefile.am b/src/plugins/exec/Makefile.am
new file mode 100644
index 000000000..cad543311
--- /dev/null
+++ b/src/plugins/exec/Makefile.am
@@ -0,0 +1,40 @@
+#
+# 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\" $(EXEC_CFLAGS)
+
+libdir = ${weechat_libdir}/plugins
+
+lib_LTLIBRARIES = exec.la
+
+exec_la_SOURCES = exec.c \
+ exec.h \
+ exec-buffer.c \
+ exec-buffer.h \
+ exec-command.c \
+ exec-command.h \
+ exec-completion.c \
+ exec-completion.h \
+ exec-config.c \
+ exec-config.h
+
+exec_la_LDFLAGS = -module -no-undefined
+exec_la_LIBADD = $(EXEC_LFLAGS)
+
+EXTRA_DIST = CMakeLists.txt
diff --git a/src/plugins/exec/exec-buffer.c b/src/plugins/exec/exec-buffer.c
new file mode 100644
index 000000000..1a4019fde
--- /dev/null
+++ b/src/plugins/exec/exec-buffer.c
@@ -0,0 +1,146 @@
+/*
+ * exec-buffer.c - buffers with output of 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 "exec.h"
+#include "exec-buffer.h"
+#include "exec-command.h"
+#include "exec-config.h"
+
+
+/*
+ * Callback for user data in an exec buffer.
+ */
+
+int
+exec_buffer_input_cb (void *data, struct t_gui_buffer *buffer,
+ const char *input_data)
+{
+ char **argv, **argv_eol;
+ int argc;
+
+ /* make C compiler happy */
+ (void) data;
+
+ /* close buffer */
+ if (strcmp (input_data, "q") == 0)
+ {
+ weechat_buffer_close (buffer);
+ return WEECHAT_RC_OK;
+ }
+
+ argv = weechat_string_split (input_data, " ", 0, 0, &argc);
+ argv_eol = weechat_string_split (input_data, " ", 1, 0, NULL);
+
+ if (argv && argv_eol)
+ exec_command_run (buffer, argc, argv, argv_eol, 0);
+
+ if (argv)
+ weechat_string_free_split (argv);
+ if (argv_eol)
+ weechat_string_free_split (argv_eol);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Callback called when an exec buffer is closed.
+ */
+
+int
+exec_buffer_close_cb (void *data, struct t_gui_buffer *buffer)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) buffer;
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Restore buffer callbacks (input and close) for buffers created by exec
+ * plugin.
+ */
+
+void
+exec_buffer_set_callbacks ()
+{
+ struct t_infolist *ptr_infolist;
+ struct t_gui_buffer *ptr_buffer;
+ const char *plugin_name;
+
+ ptr_infolist = weechat_infolist_get ("buffer", NULL, "");
+ if (ptr_infolist)
+ {
+ while (weechat_infolist_next (ptr_infolist))
+ {
+ ptr_buffer = weechat_infolist_pointer (ptr_infolist, "pointer");
+ plugin_name = weechat_infolist_string (ptr_infolist, "plugin_name");
+ if (ptr_buffer && plugin_name
+ && (strcmp (plugin_name, EXEC_PLUGIN_NAME) == 0))
+ {
+ weechat_buffer_set_pointer (ptr_buffer, "close_callback",
+ &exec_buffer_close_cb);
+ weechat_buffer_set_pointer (ptr_buffer, "input_callback",
+ &exec_buffer_input_cb);
+ }
+ }
+ weechat_infolist_free (ptr_infolist);
+ }
+}
+
+/*
+ * Creates a new exec buffer for a command.
+ */
+
+struct t_gui_buffer *
+exec_buffer_new (const char *name, int switch_to_buffer)
+{
+ struct t_gui_buffer *new_buffer;
+
+ new_buffer = weechat_buffer_search (EXEC_PLUGIN_NAME, name);
+ if (new_buffer)
+ goto end;
+
+ new_buffer = weechat_buffer_new (name,
+ &exec_buffer_input_cb, NULL,
+ &exec_buffer_close_cb, NULL);
+
+ /* failed to create buffer ? then return */
+ if (!new_buffer)
+ return NULL;
+
+ weechat_buffer_set (new_buffer, "title", _("Executed commands"));
+ weechat_buffer_set (new_buffer, "localvar_set_type", "exec");
+ weechat_buffer_set (new_buffer, "localvar_set_no_log", "1");
+ weechat_buffer_set (new_buffer, "time_for_each_line", "0");
+ weechat_buffer_set (new_buffer, "input_get_unknown_commands", "0");
+
+end:
+ if (switch_to_buffer)
+ weechat_buffer_set (new_buffer, "display", "1");
+
+ return new_buffer;
+}
diff --git a/src/plugins/exec/exec-buffer.h b/src/plugins/exec/exec-buffer.h
new file mode 100644
index 000000000..42e519888
--- /dev/null
+++ b/src/plugins/exec/exec-buffer.h
@@ -0,0 +1,27 @@
+/*
+ * 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_EXEC_BUFFER_H
+#define __WEECHAT_EXEC_BUFFER_H 1
+
+extern void exec_buffer_set_callbacks ();
+extern struct t_gui_buffer *exec_buffer_new (const char *name,
+ int switch_to_buffer);
+
+#endif /* __WEECHAT_EXEC_BUFFER_H */
diff --git a/src/plugins/exec/exec-command.c b/src/plugins/exec/exec-command.c
new file mode 100644
index 000000000..09230c195
--- /dev/null
+++ b/src/plugins/exec/exec-command.c
@@ -0,0 +1,753 @@
+/*
+ * exec-command.c - exec 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 <time.h>
+
+#include "../weechat-plugin.h"
+#include "exec.h"
+#include "exec-buffer.h"
+#include "exec-command.h"
+#include "exec-config.h"
+
+
+/*
+ * Displays a list of executed commands.
+ */
+
+void
+exec_command_list ()
+{
+ struct t_exec_cmd *ptr_exec_cmd;
+ char str_elapsed[32], str_time1[256], str_time2[256];
+ time_t elapsed_time;
+ struct tm *local_time;
+
+ weechat_printf (NULL, "");
+
+ if (!exec_cmds)
+ {
+ weechat_printf (NULL, _("No command is running"));
+ return;
+ }
+
+ weechat_printf (NULL, _("Commands:"));
+
+ for (ptr_exec_cmd = exec_cmds; ptr_exec_cmd;
+ ptr_exec_cmd = ptr_exec_cmd->next_cmd)
+ {
+ elapsed_time = (ptr_exec_cmd->end_time == 0) ?
+ time (NULL) - ptr_exec_cmd->start_time :
+ ptr_exec_cmd->end_time - ptr_exec_cmd->start_time;
+ if (elapsed_time >= 3600)
+ {
+ snprintf (str_elapsed, sizeof (str_elapsed),
+ /* TRANSLATORS: format: hours + minutes, for example: 3h59 */
+ _("%dh%02d"),
+ elapsed_time / 3600,
+ elapsed_time % 3600);
+ }
+ else if (elapsed_time >= 60)
+ {
+ snprintf (str_elapsed, sizeof (str_elapsed),
+ /* TRANSLATORS: format: minutes + seconds, for example: 3m59 */
+ _("%dm%02d"),
+ elapsed_time / 60,
+ elapsed_time % 60);
+ }
+ else
+ {
+ snprintf (str_elapsed, sizeof (str_elapsed),
+ /* TRANSLATORS: format: seconds, for example: 59s */
+ _("%ds"),
+ elapsed_time);
+ }
+ if (ptr_exec_cmd->end_time == 0)
+ {
+ /* running command */
+ weechat_printf (NULL,
+ /* TRANSLATORS: %s before "ago" is elapsed time, for example: "3m59" */
+ _(" %s%s%s %d%s%s%s: %s\"%s%s%s\"%s (pid: %d, "
+ "started %s ago)"),
+ weechat_color (weechat_config_string (exec_config_color_flag_running)),
+ ">>",
+ weechat_color ("reset"),
+ ptr_exec_cmd->number,
+ (ptr_exec_cmd->name) ? " (" : "",
+ (ptr_exec_cmd->name) ? ptr_exec_cmd->name : "",
+ (ptr_exec_cmd->name) ? ")" : "",
+ weechat_color ("chat_delimiters"),
+ weechat_color ("reset"),
+ ptr_exec_cmd->command,
+ weechat_color ("chat_delimiters"),
+ weechat_color ("reset"),
+ ptr_exec_cmd->pid,
+ str_elapsed);
+ }
+ else
+ {
+ /* process has ended */
+ local_time = localtime (&ptr_exec_cmd->start_time);
+ strftime (str_time1, sizeof (str_time1),
+ "%Y-%m-%d %H:%M:%S", local_time);
+ local_time = localtime (&ptr_exec_cmd->end_time);
+ strftime (str_time2, sizeof (str_time2),
+ "%Y-%m-%d %H:%M:%S", local_time);
+ weechat_printf (NULL,
+ " %s%s%s %d%s%s%s: %s\"%s%s%s\"%s (%s -> %s, %s)",
+ weechat_color (weechat_config_string (exec_config_color_flag_finished)),
+ "[]",
+ weechat_color ("reset"),
+ ptr_exec_cmd->number,
+ (ptr_exec_cmd->name) ? " (" : "",
+ (ptr_exec_cmd->name) ? ptr_exec_cmd->name : "",
+ (ptr_exec_cmd->name) ? ")" : "",
+ weechat_color ("chat_delimiters"),
+ weechat_color ("reset"),
+ ptr_exec_cmd->command,
+ weechat_color ("chat_delimiters"),
+ weechat_color ("reset"),
+ str_time1,
+ str_time2,
+ str_elapsed);
+ }
+ }
+}
+
+/*
+ * Searches a running command by id, and displays an error if command is not
+ * found or not running any more.
+ *
+ * Returns the command found, or NULL if not found or not running.
+ */
+
+struct t_exec_cmd *
+exec_command_search_running_id (const char *id)
+{
+ struct t_exec_cmd *ptr_exec_cmd;
+
+ ptr_exec_cmd = exec_search_by_id (id);
+ if (!ptr_exec_cmd)
+ {
+ weechat_printf (NULL, _("%s%s: command id \"%s\" not found"),
+ weechat_prefix ("error"), EXEC_PLUGIN_NAME, id);
+ return NULL;
+ }
+
+ if (!ptr_exec_cmd->hook)
+ {
+ weechat_printf (NULL,
+ _("%s%s: command with id \"%s\" is not running any "
+ "more"),
+ weechat_prefix ("error"), EXEC_PLUGIN_NAME, id);
+ return NULL;
+ }
+
+ return ptr_exec_cmd;
+}
+
+/*
+ * Parse command options.
+ *
+ * Returns:
+ * 1: options parsed successfully
+ * 0: error parsing options
+ */
+
+int
+exec_command_parse_options (struct t_exec_cmd_options *cmd_options,
+ int argc, char **argv, int start_arg,
+ int set_command_index)
+{
+ int i;
+ char *error;
+
+ for (i = start_arg; i < argc; i++)
+ {
+ if (weechat_strcasecmp (argv[i], "-sh") == 0)
+ {
+ cmd_options->use_shell = 1;
+ }
+ else if (weechat_strcasecmp (argv[i], "-nosh") == 0)
+ {
+ cmd_options->use_shell = 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-bg") == 0)
+ {
+ cmd_options->detached = 1;
+ }
+ else if (weechat_strcasecmp (argv[i], "-nobg") == 0)
+ {
+ cmd_options->detached = 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-stdin") == 0)
+ {
+ cmd_options->pipe_stdin = 1;
+ }
+ else if (weechat_strcasecmp (argv[i], "-nostdin") == 0)
+ {
+ cmd_options->pipe_stdin = 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-buffer") == 0)
+ {
+ if (i + 1 >= argc)
+ return 0;
+ i++;
+ cmd_options->ptr_buffer_name = argv[i];
+ cmd_options->ptr_buffer = weechat_buffer_search ("==", argv[i]);
+ if (cmd_options->ptr_buffer
+ && (weechat_buffer_get_integer (cmd_options->ptr_buffer, "type") != 0))
+ {
+ /* only a buffer with formatted content is allowed */
+ return 0;
+ }
+ if (!cmd_options->ptr_buffer)
+ cmd_options->new_buffer = 1;
+ }
+ else if (weechat_strcasecmp (argv[i], "-l") == 0)
+ {
+ cmd_options->output_to_buffer = 0;
+ cmd_options->new_buffer = 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-o") == 0)
+ {
+ cmd_options->output_to_buffer = 1;
+ cmd_options->new_buffer = 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-n") == 0)
+ {
+ cmd_options->output_to_buffer = 0;
+ cmd_options->new_buffer = 1;
+ }
+ else if (weechat_strcasecmp (argv[i], "-sw") == 0)
+ {
+ cmd_options->switch_to_buffer = 1;
+ }
+ else if (weechat_strcasecmp (argv[i], "-nosw") == 0)
+ {
+ cmd_options->switch_to_buffer = 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-ln") == 0)
+ {
+ cmd_options->line_numbers = 1;
+ }
+ else if (weechat_strcasecmp (argv[i], "-noln") == 0)
+ {
+ cmd_options->line_numbers = 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-color") == 0)
+ {
+ if (i + 1 >= argc)
+ return 0;
+ i++;
+ cmd_options->color = exec_search_color (argv[i]);
+ if (cmd_options->color < 0)
+ return 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-rc") == 0)
+ {
+ cmd_options->display_rc = 1;
+ }
+ else if (weechat_strcasecmp (argv[i], "-norc") == 0)
+ {
+ cmd_options->display_rc = 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-timeout") == 0)
+ {
+ if (i + 1 >= argc)
+ return 0;
+ i++;
+ error = NULL;
+ cmd_options->timeout = strtol (argv[i], &error, 10);
+ if (!error || error[0])
+ return 0;
+ }
+ else if (weechat_strcasecmp (argv[i], "-name") == 0)
+ {
+ if (i + 1 >= argc)
+ return 0;
+ i++;
+ cmd_options->ptr_command_name = argv[i];
+ }
+ else
+ {
+ if (set_command_index)
+ {
+ cmd_options->command_index = i;
+ break;
+ }
+ else
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Runs a command.
+ *
+ * Returns:
+ * WEECHAT_RC_OK: command run successfully
+ * WEECHAT_RC_ERROR: error running command
+ */
+
+int
+exec_command_run (struct t_gui_buffer *buffer,
+ int argc, char **argv, char **argv_eol, int start_arg)
+{
+ char str_buffer[512];
+ struct t_exec_cmd *new_exec_cmd;
+ struct t_exec_cmd_options cmd_options;
+ struct t_hashtable *process_options;
+ struct t_infolist *ptr_infolist;
+ struct t_gui_buffer *new_buffer;
+
+ /* parse command options */
+ cmd_options.command_index = -1;
+ cmd_options.use_shell = 1;
+ cmd_options.detached = 0;
+ cmd_options.pipe_stdin = 0;
+ cmd_options.timeout = 0;
+ cmd_options.ptr_buffer_name = NULL;
+ cmd_options.ptr_buffer = buffer;
+ cmd_options.output_to_buffer = 0;
+ cmd_options.new_buffer = 0;
+ cmd_options.switch_to_buffer = 1;
+ cmd_options.line_numbers = -1;
+ cmd_options.color = EXEC_COLOR_DECODE;
+ cmd_options.display_rc = 1;
+ cmd_options.ptr_command_name = NULL;
+
+ /* parse default options */
+ if (!exec_command_parse_options (&cmd_options,
+ exec_config_cmd_num_options,
+ exec_config_cmd_options,
+ 0, 0))
+ {
+ weechat_printf (NULL,
+ _("%s%s: invalid options in option "
+ "exec.command.default_options"),
+ weechat_prefix ("error"), EXEC_PLUGIN_NAME);
+ return WEECHAT_RC_ERROR;
+ }
+ if (!exec_command_parse_options (&cmd_options, argc, argv, start_arg, 1))
+ return WEECHAT_RC_ERROR;
+
+ /* options "-bg" and "-o"/"-n" are incompatible */
+ if (cmd_options.detached
+ && (cmd_options.output_to_buffer || cmd_options.new_buffer))
+ return WEECHAT_RC_ERROR;
+
+ /* command not found? */
+ if (cmd_options.command_index < 0)
+ return WEECHAT_RC_ERROR;
+
+ new_exec_cmd = exec_add ();
+ if (!new_exec_cmd)
+ return WEECHAT_RC_ERROR;
+
+ /* create hashtable for weechat_hook_process_hashtable() */
+ process_options = weechat_hashtable_new (32,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL,
+ NULL);
+ if (!process_options)
+ {
+ exec_free (new_exec_cmd);
+ return WEECHAT_RC_ERROR;
+ }
+ /* automatically disable shell if we are downloading an URL */
+ if (strncmp (argv_eol[cmd_options.command_index], "url:", 4) == 0)
+ cmd_options.use_shell = 0;
+ if (cmd_options.use_shell)
+ {
+ /* command will be: sh -c "command arguments..." */
+ weechat_hashtable_set (process_options, "arg1", "-c");
+ weechat_hashtable_set (process_options, "arg2",
+ argv_eol[cmd_options.command_index]);
+ }
+ if (cmd_options.pipe_stdin)
+ weechat_hashtable_set (process_options, "stdin", "1");
+ if (cmd_options.detached)
+ weechat_hashtable_set (process_options, "detached", "1");
+
+ /* set variables in new command (before running the command) */
+ new_exec_cmd->name = (cmd_options.ptr_command_name) ?
+ strdup (cmd_options.ptr_command_name) : NULL;
+ new_exec_cmd->command = strdup (argv_eol[cmd_options.command_index]);
+ new_exec_cmd->detached = cmd_options.detached;
+ if (cmd_options.ptr_buffer_name && !cmd_options.ptr_buffer)
+ {
+ /* output in a new buffer using given name */
+ new_exec_cmd->output_to_buffer = 0;
+ snprintf (str_buffer, sizeof (str_buffer),
+ "exec.%s", cmd_options.ptr_buffer_name);
+ new_buffer = exec_buffer_new (str_buffer, cmd_options.switch_to_buffer);
+ if (new_buffer)
+ {
+ new_exec_cmd->buffer_full_name =
+ strdup (weechat_buffer_get_string (new_buffer, "full_name"));
+ }
+ }
+ else if (cmd_options.new_buffer)
+ {
+ /* output in a new buffer using automatic name */
+ if (new_exec_cmd->name)
+ {
+ snprintf (str_buffer, sizeof (str_buffer),
+ "exec.%s", new_exec_cmd->name);
+ }
+ else
+ {
+ snprintf (str_buffer, sizeof (str_buffer),
+ "exec.%d", new_exec_cmd->number);
+ }
+ new_buffer = exec_buffer_new (str_buffer, cmd_options.switch_to_buffer);
+ if (new_buffer)
+ {
+ new_exec_cmd->buffer_full_name =
+ strdup (weechat_buffer_get_string (new_buffer, "full_name"));
+ }
+ }
+ else if (cmd_options.ptr_buffer)
+ {
+ new_exec_cmd->buffer_full_name =
+ strdup (weechat_buffer_get_string (cmd_options.ptr_buffer,
+ "full_name"));
+ if (cmd_options.switch_to_buffer)
+ weechat_buffer_set (cmd_options.ptr_buffer, "display", "1");
+ }
+ if (cmd_options.ptr_buffer
+ && (strcmp (weechat_buffer_get_string (cmd_options.ptr_buffer, "plugin"),
+ EXEC_PLUGIN_NAME) == 0))
+ {
+ cmd_options.output_to_buffer = 0;
+ cmd_options.new_buffer = 1;
+ }
+ new_exec_cmd->output_to_buffer = cmd_options.output_to_buffer;
+ new_exec_cmd->line_numbers = (cmd_options.line_numbers < 0) ?
+ cmd_options.new_buffer : cmd_options.line_numbers;
+ new_exec_cmd->color = cmd_options.color;
+ new_exec_cmd->display_rc = cmd_options.display_rc;
+
+ /* execute the command */
+ if (weechat_exec_plugin->debug >= 1)
+ {
+ weechat_printf (NULL, "%s: executing command: \"%s%s%s\"",
+ EXEC_PLUGIN_NAME,
+ (cmd_options.use_shell) ? "" : "sh -c '",
+ argv_eol[cmd_options.command_index],
+ (cmd_options.use_shell) ? "" : "'");
+ }
+ new_exec_cmd->hook = weechat_hook_process_hashtable (
+ (cmd_options.use_shell) ? "sh" : argv_eol[cmd_options.command_index],
+ process_options,
+ cmd_options.timeout * 1000,
+ &exec_process_cb,
+ new_exec_cmd);
+
+ if (new_exec_cmd->hook)
+ {
+ /* get PID of command */
+ ptr_infolist = weechat_infolist_get ("hook", new_exec_cmd->hook, NULL);
+ if (ptr_infolist)
+ {
+ if (weechat_infolist_next (ptr_infolist))
+ {
+ new_exec_cmd->pid = weechat_infolist_integer (ptr_infolist,
+ "child_pid");
+ }
+ weechat_infolist_free (ptr_infolist);
+ }
+ }
+ else
+ {
+ exec_free (new_exec_cmd);
+ weechat_printf (NULL,
+ _("%s%s: failed to run command \"%s\""),
+ weechat_prefix ("error"), EXEC_PLUGIN_NAME,
+ argv_eol[cmd_options.command_index]);
+ }
+
+ weechat_hashtable_free (process_options);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Callback for command "/exec": manage executed commands.
+ */
+
+int
+exec_command_exec (void *data, struct t_gui_buffer *buffer, int argc,
+ char **argv, char **argv_eol)
+{
+ int i, length, count;
+ char *text;
+ struct t_exec_cmd *ptr_exec_cmd, *ptr_next_exec_cmd;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) buffer;
+
+ /* list running commands */
+ if ((argc == 1)
+ || ((argc == 2) && (weechat_strcasecmp (argv[1], "-list") == 0)))
+ {
+ exec_command_list ();
+ return WEECHAT_RC_OK;
+ }
+
+ /* send text to a running process */
+ if (weechat_strcasecmp (argv[1], "-in") == 0)
+ {
+ if (argc < 4)
+ return WEECHAT_RC_ERROR;
+ ptr_exec_cmd = exec_command_search_running_id (argv[2]);
+ if (ptr_exec_cmd && ptr_exec_cmd->hook)
+ {
+ length = strlen (argv_eol[3]) + 1 + 1;
+ text = malloc (length);
+ if (text)
+ {
+ snprintf (text, length, "%s\n", argv_eol[3]);
+ weechat_hook_set (ptr_exec_cmd->hook, "stdin", text);
+ free (text);
+ }
+ }
+ return WEECHAT_RC_OK;
+ }
+
+ /* send text to a running process (if given), then close stdin */
+ if (weechat_strcasecmp (argv[1], "-inclose") == 0)
+ {
+ if (argc < 3)
+ return WEECHAT_RC_ERROR;
+ ptr_exec_cmd = exec_command_search_running_id (argv[2]);
+ if (ptr_exec_cmd && ptr_exec_cmd->hook)
+ {
+ if (argc > 3)
+ {
+ length = strlen (argv_eol[3]) + 1 + 1;
+ text = malloc (length);
+ if (text)
+ {
+ snprintf (text, length, "%s\n", argv_eol[3]);
+ weechat_hook_set (ptr_exec_cmd->hook, "stdin", text);
+ free (text);
+ }
+ }
+ weechat_hook_set (ptr_exec_cmd->hook, "stdin_close", "1");
+ }
+ return WEECHAT_RC_OK;
+ }
+
+ /* send a signal to a running process */
+ if (weechat_strcasecmp (argv[1], "-signal") == 0)
+ {
+ if (argc < 4)
+ return WEECHAT_RC_ERROR;
+ ptr_exec_cmd = exec_command_search_running_id (argv[2]);
+ if (ptr_exec_cmd)
+ weechat_hook_set (ptr_exec_cmd->hook, "signal", argv[3]);
+ return WEECHAT_RC_OK;
+ }
+
+ /* send a KILL signal to a running process */
+ if (weechat_strcasecmp (argv[1], "-kill") == 0)
+ {
+ if (argc < 3)
+ return WEECHAT_RC_ERROR;
+ ptr_exec_cmd = exec_command_search_running_id (argv[2]);
+ if (ptr_exec_cmd)
+ weechat_hook_set (ptr_exec_cmd->hook, "signal", "kill");
+ return WEECHAT_RC_OK;
+ }
+
+ /* send a KILL signal to all running processes */
+ if (weechat_strcasecmp (argv[1], "-killall") == 0)
+ {
+ for (ptr_exec_cmd = exec_cmds; ptr_exec_cmd;
+ ptr_exec_cmd = ptr_exec_cmd->next_cmd)
+ {
+ if (ptr_exec_cmd->hook)
+ {
+ weechat_hook_set (ptr_exec_cmd->hook, "signal", "kill");
+ }
+ }
+ return WEECHAT_RC_OK;
+ }
+
+ /* set a hook property */
+ if (weechat_strcasecmp (argv[1], "-set") == 0)
+ {
+ if (argc < 5)
+ return WEECHAT_RC_ERROR;
+ ptr_exec_cmd = exec_command_search_running_id (argv[2]);
+ if (ptr_exec_cmd)
+ weechat_hook_set (ptr_exec_cmd->hook, argv[3], argv_eol[4]);
+ return WEECHAT_RC_OK;
+ }
+
+ /* delete terminated command(s) */
+ if (weechat_strcasecmp (argv[1], "-del") == 0)
+ {
+ if (argc < 3)
+ return WEECHAT_RC_ERROR;
+ if (weechat_strcasecmp (argv[2], "-all") == 0)
+ {
+ count = 0;
+ ptr_exec_cmd = exec_cmds;
+ while (ptr_exec_cmd)
+ {
+ ptr_next_exec_cmd = ptr_exec_cmd->next_cmd;
+ if (!ptr_exec_cmd->hook)
+ {
+ exec_free (ptr_exec_cmd);
+ count++;
+ }
+ ptr_exec_cmd = ptr_next_exec_cmd;
+ }
+ weechat_printf (NULL, _("%d commands removed"), count);
+ }
+ else
+ {
+ for (i = 2; i < argc; i++)
+ {
+ ptr_exec_cmd = exec_search_by_id (argv[i]);
+ if (ptr_exec_cmd)
+ {
+ if (ptr_exec_cmd->hook)
+ {
+ weechat_printf (NULL,
+ _("%s%s: command with id \"%s\" is still "
+ "running"),
+ weechat_prefix ("error"), EXEC_PLUGIN_NAME,
+ argv[i]);
+ }
+ else
+ {
+ exec_free (ptr_exec_cmd);
+ weechat_printf (NULL,
+ _("Command \"%s\" removed"), argv[i]);
+ }
+ }
+ else
+ {
+ weechat_printf (NULL,
+ _("%s%s: command id \"%s\" not found"),
+ weechat_prefix ("error"), EXEC_PLUGIN_NAME,
+ argv[i]);
+ }
+ }
+ }
+ return WEECHAT_RC_OK;
+ }
+
+ return exec_command_run (buffer, argc, argv, argv_eol, 1);
+}
+
+/*
+ * Hooks exec commands.
+ */
+
+void
+exec_command_init ()
+{
+ weechat_hook_command (
+ "exec",
+ N_("execute external commands"),
+ N_("-list"
+ " || [-sh|-nosh] [-bg|-nobg] [-stdin|-nostdin] [-buffer <name>] "
+ "[-l|-o|-n] |-sw|-nosw] [-ln|-noln] [-color off|decode|strip] "
+ "[-rc|-norc] [-timeout <timeout>] [-name <name>] <command>"
+ " || -in <id> <text>"
+ " || -inclose <id> [<text>]"
+ " || -signal <id> <signal>"
+ " || -kill <id>"
+ " || -killall"
+ " || -set <id> <property> <value>"
+ " || -del <id>|-all [<id>...]"),
+ N_(" -list: list commands\n"
+ " -sh: use the shell to execute the command (default)\n"
+ " -nosh: do not use the shell to execute the command (required if "
+ "the command has some unsafe data, for example the content of a "
+ "message from another user)\n"
+ " -bg: run process in background: do not display process output "
+ "neither return code (not compatible with option -o/-n)\n"
+ " -nobg: catch process output and display return code (default)\n"
+ " -stdin: create a pipe for sending data to the process (with "
+ "/exec -in)\n"
+ "-nostdin: do not create a pipe for stdin (default)\n"
+ " -buffer: display/send output of command on this buffer (if the "
+ "buffer is not found, a new buffer with name \"exec.exec.xxx\" is "
+ "created)\n"
+ " -l: display locally output of command on buffer (default)\n"
+ " -o: send output of command to the buffer "
+ "(not compatible with option -bg)\n"
+ " -n: display output of command in a new buffer (not compatible "
+ "with -bg)\n"
+ " -sw: switch to the output buffer (default)\n"
+ " -nosw: don't switch to the output buffer\n"
+ " -ln: display line numbers (default in new buffer only)\n"
+ " -noln: don't display line numbers\n"
+ " -color: action on ANSI colors in output:\n"
+ " off: keep ANSI codes as-is\n"
+ " decode: convert ANSI colors to WeeChat/IRC (default)\n"
+ " strip: remove ANSI colors\n"
+ " -rc: display return code (default)\n"
+ " -norc: don't display return code\n"
+ "-timeout: set a timeout for the command (in seconds)\n"
+ " -name: set a name for the command (to name it later with /exec)\n"
+ " command: the command to execute; if beginning with \"url:\", the "
+ "shell is disabled and the content of URL is downloaded and sent as "
+ "output\n"
+ " id: command identifier: either its number or name (if set "
+ "with \"-name xxx\")\n"
+ " -in: send text on standard input of process\n"
+ "-inclose: same a -in, but stdin is closed after (and text is "
+ "optional: without text, the stdin is just closed)\n"
+ " -signal: send a signal to the process; the signal can be an integer "
+ "or one of these names: hup, int, quit, kill, term, usr1, usr2\n"
+ " -kill: alias of \"-signal <id> kill\"\n"
+ "-killall: kill all running processes\n"
+ " -set: set a hook property (see function hook_set in plugin API "
+ "reference)\n"
+ "property: hook property\n"
+ " value: new value for hook property\n"
+ " -del: delete a terminated command\n"
+ " -all: delete all terminated commands\n"
+ "\n"
+ "Default options can be set in the option "
+ "exec.command.default_options."),
+ "-list"
+ " || -sh|-nosh|-bg|-nobg|-stdin|-nostdin|-buffer|-l|-o|-n|-sw|-nosw|"
+ "-ln|-noln|-color|-timeout|-name|%*"
+ " || -in|-inclose|-signal|-kill %(exec_commands_ids)"
+ " || -killall"
+ " || -set %(exec_commands_ids) stdin|stdin_close|signal"
+ " || -del %(exec_commands_ids)|-all %(exec_commands_ids)|%*",
+ &exec_command_exec, NULL);
+}
diff --git a/src/plugins/exec/exec-command.h b/src/plugins/exec/exec-command.h
new file mode 100644
index 000000000..252350ea1
--- /dev/null
+++ b/src/plugins/exec/exec-command.h
@@ -0,0 +1,46 @@
+/*
+ * 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_EXEC_COMMAND_H
+#define __WEECHAT_EXEC_COMMAND_H 1
+
+struct t_exec_cmd_options
+{
+ int command_index; /* index of command in arguments */
+ int use_shell; /* 1 to use shell (sh -c "command") */
+ int detached; /* 1 if detached (no output) */
+ int pipe_stdin; /* 1 to create a pipe for stdin */
+ int timeout; /* timeout (in seconds) */
+ const char *ptr_buffer_name; /* name of buffer */
+ struct t_gui_buffer *ptr_buffer; /* pointer to buffer */
+ int output_to_buffer; /* 1 if output is sent to buffer */
+ int new_buffer; /* output in a new buffer */
+ int switch_to_buffer; /* switch to the output buffer */
+ int line_numbers; /* 1 to display line numbers */
+ int color; /* what to do with ANSI colors */
+ int display_rc; /* 1 to display return code */
+ const char *ptr_command_name; /* name of command */
+};
+
+extern int exec_command_run (struct t_gui_buffer *buffer,
+ int argc, char **argv, char **argv_eol,
+ int start_arg);
+extern void exec_command_init ();
+
+#endif /* __WEECHAT_EXEC_COMMAND_H */
diff --git a/src/plugins/exec/exec-completion.c b/src/plugins/exec/exec-completion.c
new file mode 100644
index 000000000..80333279e
--- /dev/null
+++ b/src/plugins/exec/exec-completion.c
@@ -0,0 +1,73 @@
+/*
+ * exec-completion.c - completion for exec 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 "exec.h"
+
+
+/*
+ * Adds executed commands ids to completion list.
+ */
+
+int
+exec_completion_commands_ids_cb (void *data, const char *completion_item,
+ struct t_gui_buffer *buffer,
+ struct t_gui_completion *completion)
+{
+ struct t_exec_cmd *ptr_exec_cmd;
+ char str_number[32];
+
+ /* make C compiler happy */
+ (void) data;
+ (void) completion_item;
+ (void) buffer;
+
+ for (ptr_exec_cmd = exec_cmds; ptr_exec_cmd;
+ ptr_exec_cmd = ptr_exec_cmd->next_cmd)
+ {
+ snprintf (str_number, sizeof (str_number), "%d", ptr_exec_cmd->number);
+ weechat_hook_completion_list_add (completion, str_number,
+ 0, WEECHAT_LIST_POS_SORT);
+ if (ptr_exec_cmd->name)
+ {
+ weechat_hook_completion_list_add (completion, ptr_exec_cmd->name,
+ 0, WEECHAT_LIST_POS_SORT);
+ }
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Hooks completions.
+ */
+
+void
+exec_completion_init ()
+{
+ weechat_hook_completion ("exec_commands_ids",
+ N_("ids (numbers and names) of executed commands"),
+ &exec_completion_commands_ids_cb, NULL);
+}
diff --git a/src/plugins/exec/exec-completion.h b/src/plugins/exec/exec-completion.h
new file mode 100644
index 000000000..a01bb03cf
--- /dev/null
+++ b/src/plugins/exec/exec-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_EXEC_COMPLETION_H
+#define __WEECHAT_EXEC_COMPLETION_H 1
+
+extern void exec_completion_init ();
+
+#endif /* __WEECHAT_EXEC_COMPLETION_H */
diff --git a/src/plugins/exec/exec-config.c b/src/plugins/exec/exec-config.c
new file mode 100644
index 000000000..05ecc027e
--- /dev/null
+++ b/src/plugins/exec/exec-config.c
@@ -0,0 +1,191 @@
+/*
+ * exec-config.c - exec configuration options (file exec.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 "exec.h"
+#include "exec-config.h"
+
+
+struct t_config_file *exec_config_file = NULL;
+
+/* exec config, command section */
+
+struct t_config_option *exec_config_command_default_options;
+struct t_config_option *exec_config_command_purge_delay;
+
+/* exec config, color section */
+
+struct t_config_option *exec_config_color_flag_running;
+struct t_config_option *exec_config_color_flag_finished;
+
+char **exec_config_cmd_options = NULL;
+int exec_config_cmd_num_options = 0;
+
+
+/*
+ * Callback for changes on option "exec.command.default_options".
+ */
+
+void
+exec_config_change_command_default_options (void *data,
+ struct t_config_option *option)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) option;
+
+ if (exec_config_cmd_options)
+ weechat_string_free_split (exec_config_cmd_options);
+
+ exec_config_cmd_options = weechat_string_split (
+ weechat_config_string (exec_config_command_default_options),
+ " ", 0, 0, &exec_config_cmd_num_options);
+}
+
+/*
+ * Reloads exec configuration file.
+ */
+
+int
+exec_config_reload_cb (void *data, struct t_config_file *config_file)
+{
+ /* make C compiler happy */
+ (void) data;
+
+ return weechat_config_reload (config_file);
+}
+
+/*
+ * Initializes exec configuration file.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+exec_config_init ()
+{
+ struct t_config_section *ptr_section;
+
+ exec_config_file = weechat_config_new (EXEC_CONFIG_NAME,
+ &exec_config_reload_cb, NULL);
+ if (!exec_config_file)
+ return 0;
+
+ /* command */
+ ptr_section = weechat_config_new_section (exec_config_file, "command",
+ 0, 0,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ if (!ptr_section)
+ {
+ weechat_config_free (exec_config_file);
+ return 0;
+ }
+
+ exec_config_command_default_options = weechat_config_new_option (
+ exec_config_file, ptr_section,
+ "default_options", "string",
+ N_("default options for command /exec (see /help exec); example: "
+ "\"-nosh -bg\" to run all commands in background (no output), and "
+ "without using the shell"),
+ NULL, 0, 0, "", NULL, 0, NULL, NULL,
+ &exec_config_change_command_default_options, NULL, NULL, NULL);
+ exec_config_command_purge_delay = weechat_config_new_option (
+ exec_config_file, ptr_section,
+ "purge_delay", "integer",
+ N_("delay for purging finished commands (in seconds, 0 = purge "
+ "commands immediately, -1 = never purge)"),
+ NULL, -1, 36000 * 24 * 30, "0", NULL, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ /* color */
+ ptr_section = weechat_config_new_section (exec_config_file, "color",
+ 0, 0,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ if (!ptr_section)
+ {
+ weechat_config_free (exec_config_file);
+ return 0;
+ }
+
+ exec_config_color_flag_running = weechat_config_new_option (
+ exec_config_file, ptr_section,
+ "flag_running", "color",
+ N_("text color for a running command flag (in exec buffer and "
+ "/exec -list)"),
+ NULL, 0, 0, "lightgreen", NULL, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ exec_config_color_flag_finished = weechat_config_new_option (
+ exec_config_file, ptr_section,
+ "flag_finished", "color",
+ N_("text color for a finished command flag (in exec buffer and "
+ "/exec -list)"),
+ NULL, 0, 0, "lightred", NULL, 0,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ return 1;
+}
+
+/*
+ * Reads exec configuration file.
+ */
+
+int
+exec_config_read ()
+{
+ return weechat_config_read (exec_config_file);
+}
+
+/*
+ * Writes exec configuration file.
+ */
+
+int
+exec_config_write ()
+{
+ return weechat_config_write (exec_config_file);
+}
+
+/*
+ * Frees exec configuration.
+ */
+
+void
+exec_config_free ()
+{
+ weechat_config_free (exec_config_file);
+
+ if (exec_config_cmd_options)
+ {
+ weechat_string_free_split (exec_config_cmd_options);
+ exec_config_cmd_options = NULL;
+ exec_config_cmd_num_options = 0;
+ }
+}
diff --git a/src/plugins/exec/exec-config.h b/src/plugins/exec/exec-config.h
new file mode 100644
index 000000000..9963fd092
--- /dev/null
+++ b/src/plugins/exec/exec-config.h
@@ -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/>.
+ */
+
+#ifndef __WEECHAT_EXEC_CONFIG_H
+#define __WEECHAT_EXEC_CONFIG_H 1
+
+#define EXEC_CONFIG_NAME "exec"
+#define EXEC_CONFIG_SECTION_EXEC "exec"
+
+extern struct t_config_file *exec_config_file;
+
+extern struct t_config_option *exec_config_command_default_options;
+extern struct t_config_option *exec_config_command_purge_delay;
+
+extern struct t_config_option *exec_config_color_flag_running;
+extern struct t_config_option *exec_config_color_flag_finished;
+
+extern char **exec_config_cmd_options;
+extern int exec_config_cmd_num_options;
+
+extern int exec_config_init ();
+extern int exec_config_read ();
+extern int exec_config_write ();
+extern void exec_config_free ();
+
+#endif /* __WEECHAT_EXEC_CONFIG_H */
diff --git a/src/plugins/exec/exec.c b/src/plugins/exec/exec.c
new file mode 100644
index 000000000..a8184d680
--- /dev/null
+++ b/src/plugins/exec/exec.c
@@ -0,0 +1,587 @@
+/*
+ * exec.c - execution of external commands in 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 <time.h>
+
+#include "../weechat-plugin.h"
+#include "exec.h"
+#include "exec-buffer.h"
+#include "exec-command.h"
+#include "exec-completion.h"
+#include "exec-config.h"
+
+
+WEECHAT_PLUGIN_NAME(EXEC_PLUGIN_NAME);
+WEECHAT_PLUGIN_DESCRIPTION(N_("Execution of external commands in WeeChat"));
+WEECHAT_PLUGIN_AUTHOR("Sébastien Helleu <flashcode@flashtux.org>");
+WEECHAT_PLUGIN_VERSION(WEECHAT_VERSION);
+WEECHAT_PLUGIN_LICENSE(WEECHAT_LICENSE);
+
+struct t_weechat_plugin *weechat_exec_plugin = NULL;
+
+struct t_exec_cmd *exec_cmds = NULL; /* first executed command */
+struct t_exec_cmd *last_exec_cmd = NULL; /* last executed command */
+int exec_cmds_count = 0; /* number of executed commands */
+
+char *exec_color_string[EXEC_NUM_COLORS] =
+{ "off", "decode", "strip" };
+
+
+/*
+ * Searches for a color action name.
+ *
+ * Returns index of color in enum t_exec_color, -1 if not found.
+ */
+
+int
+exec_search_color (const char *color)
+{
+ int i;
+
+ if (!color)
+ return -1;
+
+ for (i = 0; i < EXEC_NUM_COLORS; i++)
+ {
+ if (weechat_strcasecmp (exec_color_string[i], color) == 0)
+ return i;
+ }
+
+ /* color not found */
+ return -1;
+}
+
+/*
+ * Searches for an executed command by id, which can be a number or a name.
+ *
+ * Returns pointer to executed command found, NULL if not found.
+ */
+
+struct t_exec_cmd *
+exec_search_by_id (const char *id)
+{
+ struct t_exec_cmd* ptr_exec_cmd;
+ char *error;
+ long number;
+
+ error = NULL;
+ number = strtol (id, &error, 10);
+ if (!error || error[0])
+ number = -1;
+
+ for (ptr_exec_cmd = exec_cmds; ptr_exec_cmd;
+ ptr_exec_cmd = ptr_exec_cmd->next_cmd)
+ {
+ /* check if number is matching */
+ if ((number >= 0) && (ptr_exec_cmd->number == (int)number))
+ return ptr_exec_cmd;
+
+ /* check if name is matching */
+ if (ptr_exec_cmd->name && (strcmp (ptr_exec_cmd->name, id) == 0))
+ return ptr_exec_cmd;
+ }
+
+ /* executed command not found */
+ return NULL;
+}
+
+/*
+ * Adds a command in list of executed commands.
+ */
+
+struct t_exec_cmd *
+exec_add ()
+{
+ struct t_exec_cmd *new_exec_cmd, *ptr_exec_cmd;
+ int number;
+
+ /* find first available number */
+ number = (last_exec_cmd) ? last_exec_cmd->number + 1 : 0;
+ for (ptr_exec_cmd = exec_cmds; ptr_exec_cmd;
+ ptr_exec_cmd = ptr_exec_cmd->next_cmd)
+ {
+ if (ptr_exec_cmd->prev_cmd
+ && (ptr_exec_cmd->number > ptr_exec_cmd->prev_cmd->number + 1))
+ {
+ number = ptr_exec_cmd->prev_cmd->number + 1;
+ break;
+ }
+ }
+
+ new_exec_cmd = malloc (sizeof (*new_exec_cmd));
+ if (!new_exec_cmd)
+ return NULL;
+
+ new_exec_cmd->prev_cmd = last_exec_cmd;
+ new_exec_cmd->next_cmd = NULL;
+ if (!exec_cmds)
+ exec_cmds = new_exec_cmd;
+ else
+ last_exec_cmd->next_cmd = new_exec_cmd;
+ last_exec_cmd = new_exec_cmd;
+
+ new_exec_cmd->number = number;
+ new_exec_cmd->name = NULL;
+ new_exec_cmd->hook = NULL;
+ new_exec_cmd->command = NULL;
+ new_exec_cmd->pid = 0;
+ new_exec_cmd->detached = 0;
+ new_exec_cmd->start_time = time (NULL);
+ new_exec_cmd->end_time = 0;
+ new_exec_cmd->output_to_buffer = 0;
+ new_exec_cmd->buffer_full_name = NULL;
+ new_exec_cmd->line_numbers = 0;
+ new_exec_cmd->display_rc = 0;
+ new_exec_cmd->stdout_size = 0;
+ new_exec_cmd->stdout = NULL;
+ new_exec_cmd->stderr_size = 0;
+ new_exec_cmd->stderr = NULL;
+ new_exec_cmd->return_code = -1;
+
+ exec_cmds_count++;
+
+ return new_exec_cmd;
+}
+
+/*
+ * Timer callback to delete a command.
+ */
+
+int
+exec_timer_delete_cb (void *data, int remaining_calls)
+{
+ struct t_exec_cmd *exec_cmd, *ptr_exec_cmd;
+
+ /* make C compiler happy */
+ (void) remaining_calls;
+
+ exec_cmd = (struct t_exec_cmd *)data;
+ if (!exec_cmd)
+ return WEECHAT_RC_OK;
+
+ for (ptr_exec_cmd = exec_cmds; ptr_exec_cmd;
+ ptr_exec_cmd = ptr_exec_cmd->next_cmd)
+ {
+ if (ptr_exec_cmd == exec_cmd)
+ {
+ exec_free (ptr_exec_cmd);
+ break;
+ }
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Concatenates some text to stdout/stderr of a command.
+ */
+
+void
+exec_command_concat_output (int *size, char **output, const char *text)
+{
+ int length, new_size;
+ char *new_output;
+
+ length = strlen (text);
+ new_size = *size + length;
+ new_output = realloc (*output, new_size + 1);
+ if (!new_output)
+ return;
+
+ *output = new_output;
+ memcpy (*output + *size, text, length + 1);
+ *size = new_size;
+}
+
+/*
+ * Displays output of a command.
+ */
+
+void
+exec_command_display_output (struct t_exec_cmd *exec_cmd,
+ struct t_gui_buffer *buffer, int stdout)
+{
+ char *ptr_output, *ptr_line, *line, *line2, *pos;
+ char str_number[32], str_tags[1024];
+ int line_nb, length;
+
+ ptr_output = (stdout) ? exec_cmd->stdout : exec_cmd->stderr;
+ if (!ptr_output)
+ return;
+
+ /*
+ * if output is sent to the buffer, the buffer must exist
+ * (we don't send output by default to core buffer)
+ */
+ if (exec_cmd->output_to_buffer && !buffer)
+ return;
+
+ ptr_line = ptr_output;
+ line_nb = 1;
+ while (ptr_line)
+ {
+ /* ignore last empty line */
+ if (!ptr_line[0])
+ break;
+
+ /* search end of line */
+ pos = strchr (ptr_line, '\n');
+ line = (pos) ?
+ weechat_strndup (ptr_line, pos - ptr_line) : strdup (ptr_line);
+ if (!line)
+ break;
+
+ if (exec_cmd->color != EXEC_COLOR_OFF)
+ {
+ line2 = weechat_hook_modifier_exec (
+ (exec_cmd->output_to_buffer) ?
+ "irc_color_decode_ansi" : "color_decode_ansi",
+ (exec_cmd->color == EXEC_COLOR_DECODE) ? "1" : "0",
+ line);
+ free (line);
+ if (!line2)
+ break;
+ line = line2;
+ }
+
+ if (exec_cmd->output_to_buffer)
+ {
+ if (exec_cmd->line_numbers)
+ {
+ length = 32 + strlen (line) + 1;
+ line2 = malloc (length);
+ if (line2)
+ {
+ snprintf (line2, length, "%d. %s", line_nb, line);
+ weechat_command (buffer, line2);
+ free (line2);
+ }
+ }
+ else
+ weechat_command (buffer, (line[0]) ? line : " ");
+ }
+ else
+ {
+
+ snprintf (str_number, sizeof (str_number), "%d", exec_cmd->number);
+ snprintf (str_tags, sizeof (str_tags),
+ "exec_%s,exec_cmd_%s",
+ (stdout) ? "stdout" : "stderr",
+ (exec_cmd->name) ? exec_cmd->name : str_number);
+ snprintf (str_number, sizeof (str_number), "%d\t", line_nb);
+ weechat_printf_tags (buffer, str_tags,
+ "%s%s",
+ (exec_cmd->line_numbers) ? str_number : " \t",
+ line);
+ }
+
+ free (line);
+ line_nb++;
+ ptr_line = (pos) ? pos + 1 : NULL;
+ }
+}
+
+/*
+ * Ends a command.
+ */
+
+void
+exec_end_command (struct t_exec_cmd *exec_cmd, int return_code)
+{
+ struct t_gui_buffer *ptr_buffer;
+
+ ptr_buffer = weechat_buffer_search ("==", exec_cmd->buffer_full_name);
+
+ /* display stdout/stderr (if output to buffer, the buffer must exist) */
+ exec_command_display_output (exec_cmd, ptr_buffer, 1);
+ exec_command_display_output (exec_cmd, ptr_buffer, 0);
+
+ /*
+ * display return code (only if command is not detached and if output is
+ * NOT sent to buffer)
+ */
+ if (!exec_cmd->detached && !exec_cmd->output_to_buffer
+ && exec_cmd->display_rc)
+ {
+ if (return_code >= 0)
+ {
+ weechat_printf_tags (ptr_buffer, "exec_rc",
+ _("%s: end of command %d (\"%s\"), "
+ "return code: %d"),
+ EXEC_PLUGIN_NAME, exec_cmd->number,
+ exec_cmd->command, return_code);
+ }
+ else
+ {
+ weechat_printf_tags (ptr_buffer, "exec_rc",
+ _("%s: unexpected end of command %d "
+ "(\"%s\")"),
+ EXEC_PLUGIN_NAME, exec_cmd->number,
+ exec_cmd->command);
+ }
+ }
+
+ /* (re)set some variables after the end of command */
+ exec_cmd->hook = NULL;
+ exec_cmd->pid = 0;
+ exec_cmd->end_time = time (NULL);
+ exec_cmd->return_code = return_code;
+
+ /* schedule a timer to remove the executed command */
+ if (weechat_config_integer (exec_config_command_purge_delay) >= 0)
+ {
+ weechat_hook_timer (1 + (1000 * weechat_config_integer (exec_config_command_purge_delay)),
+ 0, 1,
+ &exec_timer_delete_cb, exec_cmd);
+ }
+}
+
+/*
+ * Callback for hook process.
+ */
+
+int
+exec_process_cb (void *data, const char *command, int return_code,
+ const char *out, const char *err)
+{
+ struct t_exec_cmd *ptr_exec_cmd;
+
+ /* make C compiler happy */
+ (void) command;
+
+ ptr_exec_cmd = (struct t_exec_cmd *)data;
+ if (!ptr_exec_cmd)
+ return WEECHAT_RC_ERROR;
+
+ if (weechat_exec_plugin->debug >= 2)
+ {
+ weechat_printf (NULL,
+ "%s: process_cb: command=\"%s\", rc=%d, "
+ "out: %d bytes, err: %d bytes",
+ EXEC_PLUGIN_NAME,
+ ptr_exec_cmd->command,
+ return_code,
+ (out) ? strlen (out) : 0,
+ (err) ? strlen (err) : 0);
+ }
+
+ if (return_code == WEECHAT_HOOK_PROCESS_ERROR)
+ {
+ exec_end_command (ptr_exec_cmd, -1);
+ return WEECHAT_RC_OK;
+ }
+
+ if (out)
+ {
+ exec_command_concat_output (&ptr_exec_cmd->stdout_size,
+ &ptr_exec_cmd->stdout,
+ out);
+ }
+ if (err)
+ {
+ exec_command_concat_output (&ptr_exec_cmd->stderr_size,
+ &ptr_exec_cmd->stderr,
+ err);
+ }
+
+ if (return_code >= 0)
+ exec_end_command (ptr_exec_cmd, return_code);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Deletes a command.
+ */
+
+void
+exec_free (struct t_exec_cmd *exec_cmd)
+{
+ if (!exec_cmd)
+ return;
+
+ /* remove command from commands list */
+ if (exec_cmd->prev_cmd)
+ (exec_cmd->prev_cmd)->next_cmd = exec_cmd->next_cmd;
+ if (exec_cmd->next_cmd)
+ (exec_cmd->next_cmd)->prev_cmd = exec_cmd->prev_cmd;
+ if (exec_cmds == exec_cmd)
+ exec_cmds = exec_cmd->next_cmd;
+ if (last_exec_cmd == exec_cmd)
+ last_exec_cmd = exec_cmd->prev_cmd;
+
+ /* free data */
+ if (exec_cmd->hook)
+ weechat_unhook (exec_cmd->hook);
+ if (exec_cmd->name)
+ free (exec_cmd->name);
+ if (exec_cmd->command)
+ free (exec_cmd->command);
+ if (exec_cmd->buffer_full_name)
+ free (exec_cmd->buffer_full_name);
+ if (exec_cmd->stdout)
+ free (exec_cmd->stdout);
+ if (exec_cmd->stderr)
+ free (exec_cmd->stderr);
+
+ free (exec_cmd);
+
+ exec_cmds_count--;
+}
+
+/*
+ * Deletes all commands.
+ */
+
+void
+exec_free_all ()
+{
+ while (exec_cmds)
+ {
+ exec_free (exec_cmds);
+ }
+}
+
+/*
+ * Prints exec infos in WeeChat log file (usually for crash dump).
+ */
+
+void
+exec_print_log ()
+{
+ struct t_exec_cmd *ptr_exec_cmd;
+
+ for (ptr_exec_cmd = exec_cmds; ptr_exec_cmd;
+ ptr_exec_cmd = ptr_exec_cmd->next_cmd)
+ {
+ weechat_log_printf ("");
+ weechat_log_printf ("[exec command (addr:0x%lx)]", ptr_exec_cmd);
+ weechat_log_printf (" number. . . . . . . . . : %d", ptr_exec_cmd->number);
+ weechat_log_printf (" name. . . . . . . . . . : '%s'", ptr_exec_cmd->name);
+ weechat_log_printf (" hook. . . . . . . . . . : 0x%lx", ptr_exec_cmd->hook);
+ weechat_log_printf (" command . . . . . . . . : '%s'", ptr_exec_cmd->command);
+ weechat_log_printf (" pid . . . . . . . . . . : %d", ptr_exec_cmd->pid);
+ weechat_log_printf (" detached. . . . . . . . : %d", ptr_exec_cmd->detached);
+ weechat_log_printf (" start_time. . . . . . . : %ld", ptr_exec_cmd->start_time);
+ weechat_log_printf (" end_time. . . . . . . . : %ld", ptr_exec_cmd->end_time);
+ weechat_log_printf (" output_to_buffer. . . . : %d", ptr_exec_cmd->output_to_buffer);
+ weechat_log_printf (" buffer_full_name. . . . : '%s'", ptr_exec_cmd->buffer_full_name);
+ weechat_log_printf (" line_numbers. . . . . . : %d", ptr_exec_cmd->line_numbers);
+ weechat_log_printf (" display_rc. . . . . . . : %d", ptr_exec_cmd->display_rc);
+ weechat_log_printf (" stdout_size . . . . . . : %d", ptr_exec_cmd->stdout_size);
+ weechat_log_printf (" stdout. . . . . . . . . : '%s'", ptr_exec_cmd->stdout);
+ weechat_log_printf (" stderr_size . . . . . . : %d", ptr_exec_cmd->stderr_size);
+ weechat_log_printf (" stderr. . . . . . . . . : '%s'", ptr_exec_cmd->stderr);
+ weechat_log_printf (" return_code . . . . . . : %d", ptr_exec_cmd->return_code);
+ weechat_log_printf (" prev_cmd. . . . . . . . : 0x%lx", ptr_exec_cmd->prev_cmd);
+ weechat_log_printf (" next_cmd. . . . . . . . : 0x%lx", ptr_exec_cmd->next_cmd);
+ }
+}
+
+/*
+ * Callback for signal "debug_dump".
+ */
+
+int
+exec_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, EXEC_PLUGIN_NAME) == 0))
+ {
+ weechat_log_printf ("");
+ weechat_log_printf ("***** \"%s\" plugin dump *****",
+ weechat_plugin->name);
+
+ exec_print_log ();
+
+ weechat_log_printf ("");
+ weechat_log_printf ("***** End of \"%s\" plugin dump *****",
+ weechat_plugin->name);
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Initializes exec plugin.
+ */
+
+int
+weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[])
+{
+ int i, upgrading;
+
+ weechat_plugin = plugin;
+
+ exec_command_init ();
+
+ if (!exec_config_init ())
+ return WEECHAT_RC_ERROR;
+
+ exec_config_read ();
+
+ /* hook some signals */
+ weechat_hook_signal ("debug_dump", &exec_debug_dump_cb, NULL);
+
+ /* hook completions */
+ exec_completion_init ();
+
+ /* look at arguments */
+ upgrading = 0;
+ for (i = 0; i < argc; i++)
+ {
+ if (weechat_strcasecmp (argv[i], "--upgrade") == 0)
+ {
+ upgrading = 1;
+ }
+ }
+
+ if (upgrading)
+ exec_buffer_set_callbacks ();
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Ends exec plugin.
+ */
+
+int
+weechat_plugin_end (struct t_weechat_plugin *plugin)
+{
+ /* make C compiler happy */
+ (void) plugin;
+
+ exec_config_write ();
+ exec_free_all ();
+ exec_config_free ();
+
+ return WEECHAT_RC_OK;
+}
diff --git a/src/plugins/exec/exec.h b/src/plugins/exec/exec.h
new file mode 100644
index 000000000..9958ed7a3
--- /dev/null
+++ b/src/plugins/exec/exec.h
@@ -0,0 +1,79 @@
+/*
+ * 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_EXEC_H
+#define __WEECHAT_EXEC_H 1
+
+#include <time.h>
+
+#define weechat_plugin weechat_exec_plugin
+#define EXEC_PLUGIN_NAME "exec"
+
+enum t_exec_color {
+ EXEC_COLOR_OFF = 0,
+ EXEC_COLOR_DECODE,
+ EXEC_COLOR_STRIP,
+ /* number of color actions */
+ EXEC_NUM_COLORS,
+};
+
+struct t_exec_cmd
+{
+ /* command/process */
+ int number; /* command number */
+ char *name; /* name of command */
+ struct t_hook *hook; /* pointer to process hook */
+ char *command; /* command (with arguments) */
+ pid_t pid; /* process id */
+ int detached; /* 1 if command is detached */
+ time_t start_time; /* start time */
+ time_t end_time; /* end time */
+
+ /* display */
+ int output_to_buffer; /* 1 if output is sent to buffer */
+ char *buffer_full_name; /* buffer where output is displayed */
+ int line_numbers; /* 1 if lines numbers are displayed */
+ int color; /* what to do with ANSI colors */
+ int display_rc; /* 1 if return code is displayed */
+
+ /* command output */
+ int stdout_size; /* number of bytes in stdout */
+ char *stdout; /* stdout of command */
+ int stderr_size; /* number of bytes in stderr */
+ char *stderr; /* stderr of command */
+ int return_code; /* command return code */
+
+ struct t_exec_cmd *prev_cmd; /* link to previous command */
+ struct t_exec_cmd *next_cmd; /* link to next command */
+};
+
+extern struct t_weechat_plugin *weechat_exec_plugin;
+extern struct t_exec_cmd *exec_cmds;
+extern struct t_exec_cmd *last_exec_cmd;
+extern int exec_cmds_count;
+
+extern int exec_search_color (const char *color);
+extern struct t_exec_cmd *exec_search_by_id (const char *id);
+extern struct t_exec_cmd *exec_add ();
+extern int exec_process_cb (void *data, const char *command, int return_code,
+ const char *out, const char *err);
+extern void exec_free (struct t_exec_cmd *exec_cmd);
+extern void exec_free_all ();
+
+#endif /* __WEECHAT_EXEC_H */
diff --git a/src/plugins/irc/irc-color.c b/src/plugins/irc/irc-color.c
index 69b0381eb..6c0713aec 100644
--- a/src/plugins/irc/irc-color.c
+++ b/src/plugins/irc/irc-color.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <string.h>
#include <ctype.h>
+#include <regex.h>
#include "../weechat-plugin.h"
#include "irc.h"
@@ -45,9 +46,29 @@ char *irc_color_to_weechat[IRC_NUM_COLORS] =
/* 11 */ "lightcyan",
/* 12 */ "lightblue",
/* 13 */ "lightmagenta",
- /* 14 */ "gray",
- /* 15 */ "white"
+ /* 14 */ "darkgray",
+ /* 15 */ "gray"
};
+char irc_color_term2irc[IRC_COLOR_TERM2IRC_NUM_COLORS] =
+{ /* term > IRC */
+ 1, /* 0 1 (black) */
+ 5, /* 1 5 (red) */
+ 3, /* 2 3 (green) */
+ 7, /* 3 7 (brown) */
+ 2, /* 4 2 (blue) */
+ 6, /* 5 6 (magenta) */
+ 10, /* 6 10 (cyan) */
+ 15, /* 7 15 (gray) */
+ 14, /* 8 14 (darkgray) */
+ 4, /* 9 4 (lightred) */
+ 9, /* 10 9 (lightgreen) */
+ 8, /* 11 8 (yellow) */
+ 12, /* 12 12 (lightblue) */
+ 13, /* 13 13 (lightmagenta) */
+ 11, /* 14 11 (lightcyan) */
+ 0, /* 15 0 (white) */
+};
+regex_t *irc_color_regex_ansi = NULL;
/*
@@ -362,6 +383,371 @@ irc_color_encode (const char *string, int keep_colors)
}
/*
+ * Converts a RGB color to IRC color.
+ *
+ * Returns a IRC color number (between 0 and 15), -1 if error.
+ */
+
+int
+irc_color_convert_rgb2irc (int rgb)
+{
+ char str_color[64], *error;
+ const char *info_color;
+ long number;
+
+ snprintf (str_color, sizeof (str_color),
+ "%d,%d",
+ rgb,
+ IRC_COLOR_TERM2IRC_NUM_COLORS);
+
+ info_color = weechat_info_get ("color_rgb2term", str_color);
+ if (!info_color || !info_color[0])
+ return -1;
+
+ error = NULL;
+ number = strtol (info_color, &error, 10);
+ if (!error || error[0]
+ || (number < 0) || (number >= IRC_COLOR_TERM2IRC_NUM_COLORS))
+ {
+ return -1;
+ }
+
+ return irc_color_term2irc[number];
+}
+
+/*
+ * Converts a terminal color to IRC color.
+ *
+ * Returns a IRC color number (between 0 and 15), -1 if error.
+ */
+
+int
+irc_color_convert_term2irc (int color)
+{
+ char str_color[64], *error;
+ const char *info_color;
+ long number;
+
+ snprintf (str_color, sizeof (str_color), "%d", color);
+
+ info_color = weechat_info_get ("color_term2rgb", str_color);
+ if (!info_color || !info_color[0])
+ return -1;
+
+ error = NULL;
+ number = strtol (info_color, &error, 10);
+ if (!error || error[0] || (number < 0) || (number > 0xFFFFFF))
+ return -1;
+
+ return irc_color_convert_rgb2irc (number);
+}
+
+/*
+ * Replaces ANSI colors by IRC colors (or removes them).
+ *
+ * This callback is called by irc_color_decode_ansi, it must not be called
+ * directly.
+ */
+
+char *
+irc_color_decode_ansi_cb (void *data, const char *text)
+{
+ struct t_irc_color_ansi_state *ansi_state;
+ char *text2, **items, *output, str_color[128];
+ int i, length, num_items, value, color;
+
+ ansi_state = (struct t_irc_color_ansi_state *)data;
+
+ /* if we don't keep colors of if text is empty, just return empty string */
+ if (!ansi_state->keep_colors || !text || !text[0])
+ return strdup ("");
+
+ /* only sequences ending with 'm' are used, the others are discarded */
+ length = strlen (text);
+ if (text[length - 1] != 'm')
+ return strdup ("");
+
+ /* sequence "\33[m" resets color */
+ if (length < 4)
+ return strdup (weechat_color ("reset"));
+
+ text2 = NULL;
+ items = NULL;
+ output = NULL;
+
+ /* extract text between "\33[" and "m" */
+ text2 = weechat_strndup (text + 2, length - 3);
+ if (!text2)
+ goto end;
+
+ items = weechat_string_split (text2, ";", 0, 0, &num_items);
+ if (!items)
+ goto end;
+
+ output = malloc ((32 * num_items) + 1);
+ if (!output)
+ goto end;
+ output[0] = '\0';
+
+ for (i = 0; i < num_items; i++)
+ {
+ value = atoi (items[i]);
+ switch (value)
+ {
+ case 0: /* reset */
+ strcat (output, IRC_COLOR_RESET_STR);
+ ansi_state->bold = 0;
+ ansi_state->underline = 0;
+ ansi_state->italic = 0;
+ break;
+ case 1: /* bold */
+ if (!ansi_state->bold)
+ {
+ strcat (output, IRC_COLOR_BOLD_STR);
+ ansi_state->bold = 1;
+ }
+ break;
+ case 2: /* remove bold */
+ case 21:
+ case 22:
+ if (ansi_state->bold)
+ {
+ strcat (output, IRC_COLOR_BOLD_STR);
+ ansi_state->bold = 0;
+ }
+ break;
+ case 3: /* italic */
+ if (!ansi_state->italic)
+ {
+ strcat (output, IRC_COLOR_ITALIC_STR);
+ ansi_state->italic = 1;
+ }
+ break;
+ case 4: /* underline */
+ if (!ansi_state->underline)
+ {
+ strcat (output, IRC_COLOR_UNDERLINE_STR);
+ ansi_state->underline = 1;
+ }
+ break;
+ case 23: /* remove italic */
+ if (ansi_state->italic)
+ {
+ strcat (output, IRC_COLOR_ITALIC_STR);
+ ansi_state->italic = 0;
+ }
+ break;
+ case 24: /* remove underline */
+ if (ansi_state->underline)
+ {
+ strcat (output, IRC_COLOR_UNDERLINE_STR);
+ ansi_state->underline = 0;
+ }
+ break;
+ case 30: /* text color */
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ snprintf (str_color, sizeof (str_color),
+ "%c%02d",
+ IRC_COLOR_COLOR_CHAR,
+ irc_color_term2irc[value - 30]);
+ strcat (output, str_color);
+ break;
+ case 38: /* text color */
+ if (i + 1 < num_items)
+ {
+ switch (atoi (items[i + 1]))
+ {
+ case 2: /* RGB color */
+ if (i + 4 < num_items)
+ {
+ color = irc_color_convert_rgb2irc (
+ (atoi (items[i + 2]) << 16) |
+ (atoi (items[i + 3]) << 8) |
+ atoi (items[i + 4]));
+ if (color >= 0)
+ {
+ snprintf (str_color, sizeof (str_color),
+ "%c%02d",
+ IRC_COLOR_COLOR_CHAR,
+ color);
+ strcat (output, str_color);
+ }
+ i += 4;
+ }
+ break;
+ case 5: /* terminal color (0-255) */
+ if (i + 2 < num_items)
+ {
+ color = irc_color_convert_term2irc (atoi (items[i + 2]));
+ if (color >= 0)
+ {
+ snprintf (str_color, sizeof (str_color),
+ "%c%02d",
+ IRC_COLOR_COLOR_CHAR,
+ color);
+ strcat (output, str_color);
+ }
+ i += 2;
+ }
+ break;
+ }
+ }
+ break;
+ case 39: /* default text color */
+ snprintf (str_color, sizeof (str_color),
+ "%c15",
+ IRC_COLOR_COLOR_CHAR);
+ strcat (output, str_color);
+ break;
+ case 40: /* background color */
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ snprintf (str_color, sizeof (str_color),
+ "%c,%02d",
+ IRC_COLOR_COLOR_CHAR,
+ irc_color_term2irc[value - 40]);
+ strcat (output, str_color);
+ break;
+ case 48: /* background color */
+ if (i + 1 < num_items)
+ {
+ switch (atoi (items[i + 1]))
+ {
+ case 2: /* RGB color */
+ if (i + 4 < num_items)
+ {
+ color = irc_color_convert_rgb2irc (
+ (atoi (items[i + 2]) << 16) |
+ (atoi (items[i + 3]) << 8) |
+ atoi (items[i + 4]));
+ if (color >= 0)
+ {
+ snprintf (str_color, sizeof (str_color),
+ "%c,%02d",
+ IRC_COLOR_COLOR_CHAR,
+ color);
+ strcat (output, str_color);
+ }
+ i += 4;
+ }
+ break;
+ case 5: /* terminal color (0-255) */
+ if (i + 2 < num_items)
+ {
+ color = irc_color_convert_term2irc (atoi (items[i + 2]));
+ if (color >= 0)
+ {
+ snprintf (str_color, sizeof (str_color),
+ "%c,%02d",
+ IRC_COLOR_COLOR_CHAR,
+ color);
+ strcat (output, str_color);
+ }
+ i += 2;
+ }
+ break;
+ }
+ }
+ break;
+ case 49: /* default background color */
+ snprintf (str_color, sizeof (str_color),
+ "%c,01",
+ IRC_COLOR_COLOR_CHAR);
+ strcat (output, str_color);
+ break;
+ case 90: /* text color (bright) */
+ case 91:
+ case 92:
+ case 93:
+ case 94:
+ case 95:
+ case 96:
+ case 97:
+ snprintf (str_color, sizeof (str_color),
+ "%c%02d",
+ IRC_COLOR_COLOR_CHAR,
+ irc_color_term2irc[value - 90 + 8]);
+ strcat (output, str_color);
+ break;
+ case 100: /* background color (bright) */
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 106:
+ case 107:
+ snprintf (str_color, sizeof (str_color),
+ "%c,%02d",
+ IRC_COLOR_COLOR_CHAR,
+ irc_color_term2irc[value - 100 + 8]);
+ strcat (output, str_color);
+ break;
+ }
+ }
+
+end:
+ if (items)
+ weechat_string_free_split (items);
+ if (text2)
+ free (text2);
+
+ return (output) ? output : strdup ("");
+}
+
+/*
+ * Replaces ANSI colors by IRC colors.
+ *
+ * If keep_colors == 0: removes any color/style in message otherwise keeps
+ * colors.
+ *
+ * Note: result must be freed after use.
+ */
+
+char *
+irc_color_decode_ansi (const char *string, int keep_colors)
+{
+ struct t_irc_color_ansi_state ansi_state;
+
+ /* allocate/compile regex if needed (first call) */
+ if (!irc_color_regex_ansi)
+ {
+ irc_color_regex_ansi = malloc (sizeof (*irc_color_regex_ansi));
+ if (!irc_color_regex_ansi)
+ return NULL;
+ if (weechat_string_regcomp (irc_color_regex_ansi,
+ weechat_info_get ("color_ansi_regex", NULL),
+ REG_EXTENDED) != 0)
+ {
+ free (irc_color_regex_ansi);
+ irc_color_regex_ansi = NULL;
+ return NULL;
+ }
+ }
+
+ ansi_state.keep_colors = keep_colors;
+ ansi_state.bold = 0;
+ ansi_state.underline = 0;
+ ansi_state.italic = 0;
+
+ return weechat_string_replace_regex (string, irc_color_regex_ansi,
+ "$0", '$',
+ &irc_color_decode_ansi_cb,
+ &ansi_state);
+}
+
+/*
* Callback for modifiers "irc_color_decode" and "irc_color_encode".
*
* This modifier can be used by other plugins to decode/encode IRC colors in
@@ -385,6 +771,9 @@ irc_color_modifier_cb (void *data, const char *modifier,
if (strcmp (modifier, "irc_color_encode") == 0)
return irc_color_encode (string, keep_colors);
+ if (strcmp (modifier, "irc_color_decode_ansi") == 0)
+ return irc_color_decode_ansi (string, keep_colors);
+
/* unknown modifier */
return NULL;
}
@@ -403,3 +792,18 @@ irc_color_for_tags (const char *color)
return weechat_string_replace (color, ",", ":");
}
+
+/*
+ * Ends IRC colors.
+ */
+
+void
+irc_color_end ()
+{
+ if (irc_color_regex_ansi)
+ {
+ regfree (irc_color_regex_ansi);
+ free (irc_color_regex_ansi);
+ irc_color_regex_ansi = NULL;
+ }
+}
diff --git a/src/plugins/irc/irc-color.h b/src/plugins/irc/irc-color.h
index 0224bd11d..5136d7690 100644
--- a/src/plugins/irc/irc-color.h
+++ b/src/plugins/irc/irc-color.h
@@ -59,6 +59,8 @@
#define IRC_COLOR_UNDERLINE_CHAR '\x1F' /* underlined text */
#define IRC_COLOR_UNDERLINE_STR "\x1F" /* [1F]...[1F] */
+#define IRC_COLOR_TERM2IRC_NUM_COLORS 16
+
/* macros for WeeChat core and IRC colors */
#define IRC_COLOR_BAR_FG weechat_color("bar_fg")
@@ -92,11 +94,20 @@
#define IRC_COLOR_ITEM_LAG_COUNTING weechat_color(weechat_config_string(irc_config_color_item_lag_counting))
#define IRC_COLOR_ITEM_LAG_FINISHED weechat_color(weechat_config_string(irc_config_color_item_lag_finished))
+struct t_irc_color_ansi_state
+{
+ char keep_colors;
+ char bold;
+ char underline;
+ char italic;
+};
+
extern char *irc_color_decode (const char *string, int keep_colors);
extern char *irc_color_encode (const char *string, int keep_colors);
extern char *irc_color_modifier_cb (void *data, const char *modifier,
const char *modifier_data,
const char *string);
extern char *irc_color_for_tags (const char *color);
+extern void irc_color_end ();
#endif /* __WEECHAT_IRC_COLOR_H */
diff --git a/src/plugins/irc/irc.c b/src/plugins/irc/irc.c
index 2b341b99f..6c807ddaf 100644
--- a/src/plugins/irc/irc.c
+++ b/src/plugins/irc/irc.c
@@ -189,6 +189,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[])
/* modifiers */
weechat_hook_modifier ("irc_color_decode", &irc_color_modifier_cb, NULL);
weechat_hook_modifier ("irc_color_encode", &irc_color_modifier_cb, NULL);
+ weechat_hook_modifier ("irc_color_decode_ansi", &irc_color_modifier_cb, NULL);
/* hook completions */
irc_completion_init ();
@@ -281,5 +282,7 @@ weechat_plugin_end (struct t_weechat_plugin *plugin)
irc_redirect_end ();
+ irc_color_end ();
+
return WEECHAT_RC_OK;
}
diff --git a/src/plugins/plugin-api.c b/src/plugins/plugin-api.c
index 8a1c4dfb7..5dd4a983a 100644
--- a/src/plugins/plugin-api.c
+++ b/src/plugins/plugin-api.c
@@ -278,6 +278,25 @@ plugin_api_command (struct t_weechat_plugin *plugin,
}
/*
+ * Modifier to decode ANSI colors.
+ */
+
+char *
+plugin_api_modifier_color_decode_ansi (void *data,
+ const char *modifier,
+ const char *modifier_data,
+ const char *string)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) modifier;
+
+ return gui_color_decode_ansi (string,
+ (modifier_data && (strcmp (modifier_data, "1") == 0)) ?
+ 1: 0);
+}
+
+/*
* Gets info about WeeChat.
*/
@@ -288,10 +307,11 @@ plugin_api_info_get_internal (void *data, const char *info_name,
time_t inactivity;
static char value[32], version_number[32] = { '\0' };
static char weechat_dir_absolute_path[PATH_MAX] = { '\0' };
+ int rgb, limit;
+ char *pos, *color;
/* make C compiler happy */
(void) data;
- (void) arguments;
if (!info_name)
return NULL;
@@ -397,6 +417,43 @@ plugin_api_info_get_internal (void *data, const char *info_name,
snprintf (value, sizeof (value), "%d", gui_window_get_height ());
return value;
}
+ else if (string_strcasecmp (info_name, "color_ansi_regex") == 0)
+ {
+ return GUI_COLOR_REGEX_ANSI_DECODE;
+ }
+ else if (string_strcasecmp (info_name, "color_term2rgb") == 0)
+ {
+ if (arguments && arguments[0])
+ {
+ snprintf (value, sizeof (value),
+ "%d",
+ gui_color_convert_term_to_rgb (atoi (arguments)));
+ return value;
+ }
+ }
+ else if (string_strcasecmp (info_name, "color_rgb2term") == 0)
+ {
+ if (arguments && arguments[0])
+ {
+ limit = 256;
+ pos = strchr (arguments, ',');
+ if (pos)
+ {
+ color = string_strndup (arguments, pos - arguments);
+ if (!color)
+ return NULL;
+ rgb = atoi (color);
+ limit = atoi (pos + 1);
+ free (color);
+ }
+ else
+ rgb = atoi (arguments);
+ snprintf (value, sizeof (value),
+ "%d",
+ gui_color_convert_rgb_to_term (rgb, limit));
+ return value;
+ }
+ }
/* info not found */
return NULL;
@@ -1097,6 +1154,10 @@ plugin_api_infolist_free (struct t_infolist *infolist)
void
plugin_api_init ()
{
+ /* WeeChat core modifiers */
+ hook_modifier (NULL, "color_decode_ansi",
+ &plugin_api_modifier_color_decode_ansi, NULL);
+
/* WeeChat core info hooks */
hook_info (NULL, "version", N_("WeeChat version"), NULL,
&plugin_api_info_get_internal, NULL);
@@ -1141,6 +1202,12 @@ plugin_api_init ()
&plugin_api_info_get_internal, NULL);
hook_info (NULL, "term_height", N_("height of terminal"), NULL,
&plugin_api_info_get_internal, NULL);
+ hook_info (NULL, "color_ansi_regex", N_("regular expression to match ANSI escape codes"), NULL,
+ &plugin_api_info_get_internal, NULL);
+ hook_info (NULL, "color_term2rgb", N_("terminal color (0-255) converted to RGB color"), NULL,
+ &plugin_api_info_get_internal, NULL);
+ hook_info (NULL, "color_rgb2term", N_("RGB color converted to terminal color (0-255)"), NULL,
+ &plugin_api_info_get_internal, NULL);
/* WeeChat core infolist hooks */
hook_infolist (NULL, "bar", N_("list of bars"),
diff --git a/src/plugins/trigger/trigger-callback.c b/src/plugins/trigger/trigger-callback.c
index d9d82101e..00a941b20 100644
--- a/src/plugins/trigger/trigger-callback.c
+++ b/src/plugins/trigger/trigger-callback.c
@@ -213,7 +213,8 @@ trigger_callback_replace_regex (struct t_trigger *trigger,
value = weechat_string_replace_regex (ptr_value,
trigger->regex[i].regex,
replace_eval,
- '$');
+ '$',
+ NULL, NULL);
if (value)
{
/* display debug info on trigger buffer */
diff --git a/src/plugins/weechat-plugin.h b/src/plugins/weechat-plugin.h
index cea485f7b..9f3d219d0 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 "20140304-01"
+#define WEECHAT_PLUGIN_API_VERSION "20140313-01"
/* macros for defining plugin infos */
#define WEECHAT_PLUGIN_NAME(__name) \
@@ -250,7 +250,9 @@ struct t_weechat_plugin
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);
+ const char reference_char,
+ char *(*callback)(void *data, const char *text),
+ void *callback_data);
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);
@@ -1017,9 +1019,11 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin);
#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) \
+ __reference_char, __callback, \
+ __callback_data) \
weechat_plugin->string_replace_regex(__string, __regex, __replace, \
- __reference_char)
+ __reference_char, __callback, \
+ __callback_data)
#define weechat_string_split(__string, __separator, __eol, __max, \
__num_items) \
weechat_plugin->string_split(__string, __separator, __eol, \
diff --git a/weechat.cygport.in b/weechat.cygport.in
index f903d758b..3182f61b8 100644
--- a/weechat.cygport.in
+++ b/weechat.cygport.in
@@ -87,6 +87,7 @@ weechat_CONTENTS="
usr/lib/weechat/plugins/alias.dll
usr/lib/weechat/plugins/aspell.dll
usr/lib/weechat/plugins/charset.dll
+ usr/lib/weechat/plugins/exec.dll
usr/lib/weechat/plugins/fifo.dll
usr/lib/weechat/plugins/irc.dll
usr/lib/weechat/plugins/logger.dll