From 97254780d655dd29b4093e52c6930aecaecca2eb Mon Sep 17 00:00:00 2001 From: Sebastien Helleu Date: Mon, 10 Mar 2014 14:26:23 +0100 Subject: [PATCH] exec: add exec plugin --- CMakeLists.txt | 1 + configure.ac | 19 ++ debian/weechat-plugins.install | 1 + doc/docgen.py | 1 + po/POTFILES.in | 8 + po/srcfiles.cmake | 8 + src/plugins/CMakeLists.txt | 4 + src/plugins/Makefile.am | 12 +- src/plugins/exec/CMakeLists.txt | 29 ++ src/plugins/exec/Makefile.am | 38 +++ src/plugins/exec/exec-command.c | 409 +++++++++++++++++++++++ src/plugins/exec/exec-command.h | 25 ++ src/plugins/exec/exec-completion.c | 73 +++++ src/plugins/exec/exec-completion.h | 25 ++ src/plugins/exec/exec-config.c | 151 +++++++++ src/plugins/exec/exec-config.h | 38 +++ src/plugins/exec/exec.c | 500 +++++++++++++++++++++++++++++ src/plugins/exec/exec.h | 67 ++++ weechat.cygport.in | 1 + 19 files changed, 1406 insertions(+), 4 deletions(-) create mode 100644 src/plugins/exec/CMakeLists.txt create mode 100644 src/plugins/exec/Makefile.am create mode 100644 src/plugins/exec/exec-command.c create mode 100644 src/plugins/exec/exec-command.h create mode 100644 src/plugins/exec/exec-completion.c create mode 100644 src/plugins/exec/exec-completion.h create mode 100644 src/plugins/exec/exec-config.c create mode 100644 src/plugins/exec/exec-config.h create mode 100644 src/plugins/exec/exec.c create mode 100644 src/plugins/exec/exec.h 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/configure.ac b/configure.ac index 2b466082f..8871cc21b 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/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/po/POTFILES.in b/po/POTFILES.in index 82aec229f..f3f120ee0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -113,6 +113,14 @@ ./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-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..2fce5d3d2 100644 --- a/po/srcfiles.cmake +++ b/po/srcfiles.cmake @@ -114,6 +114,14 @@ 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-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/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..bd86d831f --- /dev/null +++ b/src/plugins/exec/CMakeLists.txt @@ -0,0 +1,29 @@ +# +# Copyright (C) 2014 Sébastien Helleu +# +# This file is part of WeeChat, the extensible chat client. +# +# WeeChat is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# WeeChat is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with WeeChat. If not, see . +# + +ADD_LIBRARY(exec MODULE +exec.c exec.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..3fa30374f --- /dev/null +++ b/src/plugins/exec/Makefile.am @@ -0,0 +1,38 @@ +# +# Copyright (C) 2014 Sébastien Helleu +# +# This file is part of WeeChat, the extensible chat client. +# +# WeeChat is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# WeeChat is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with WeeChat. If not, see . +# + +AM_CPPFLAGS = -DLOCALEDIR=\"$(datadir)/locale\" $(EXEC_CFLAGS) + +libdir = ${weechat_libdir}/plugins + +lib_LTLIBRARIES = exec.la + +exec_la_SOURCES = exec.c \ + exec.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-command.c b/src/plugins/exec/exec-command.c new file mode 100644 index 000000000..0f07e02c6 --- /dev/null +++ b/src/plugins/exec/exec-command.c @@ -0,0 +1,409 @@ +/* + * exec-command.c - exec command + * + * Copyright (C) 2014 Sébastien Helleu + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see . + */ + +#include +#include +#include +#include + +#include "../weechat-plugin.h" +#include "exec.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; +} + +/* + * 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, command_index, use_shell, pipe_stdin, output_to_buffer, length; + long timeout; + char *error, *ptr_name, *text; + struct t_exec_cmd *ptr_exec_cmd, *new_exec_cmd; + struct t_hashtable *options_cmd; + struct t_infolist *ptr_infolist; + + /* 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->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 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) + { + /* TODO: send signal to the process */ + } + 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) + { + /* TODO: send KILL signal to the process */ + } + 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) + { + /* TODO: send KILL signal to the process */ + } + return WEECHAT_RC_OK; + } + + /* parse command options */ + command_index = -1; + use_shell = 1; + pipe_stdin = 0; + timeout = 0; + output_to_buffer = 0; + ptr_name = NULL; + + for (i = 1; i < argc; i++) + { + if (weechat_strcasecmp (argv[i], "-nosh") == 0) + { + use_shell = 0; + } + else if (weechat_strcasecmp (argv[i], "-stdin") == 0) + { + pipe_stdin = 1; + } + else if (weechat_strcasecmp (argv[i], "-o") == 0) + { + output_to_buffer = 1; + } + else if (weechat_strcasecmp (argv[i], "-timeout") == 0) + { + if (i + 1 >= argc) + return WEECHAT_RC_ERROR; + i++; + error = NULL; + timeout = strtol (argv[i], &error, 10); + if (!error || error[0]) + return WEECHAT_RC_ERROR; + } + else if (weechat_strcasecmp (argv[i], "-name") == 0) + { + if (i + 1 >= argc) + return WEECHAT_RC_ERROR; + i++; + ptr_name = argv[i]; + } + else + { + command_index = i; + break; + } + } + if (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() */ + options_cmd = weechat_hashtable_new (32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + if (!options_cmd) + { + exec_free (new_exec_cmd); + return WEECHAT_RC_ERROR; + } + + /* run the command in background */ + if (use_shell) + { + /* command will be: sh -c "command arguments..." */ + weechat_hashtable_set (options_cmd, "arg1", "-c"); + weechat_hashtable_set (options_cmd, "arg2", argv_eol[command_index]); + } + if (weechat_exec_plugin->debug >= 1) + { + weechat_printf (NULL, "%s: executing command: \"%s%s%s\"", + EXEC_PLUGIN_NAME, + (use_shell) ? "" : "sh -c '", + argv_eol[command_index], + (use_shell) ? "" : "'"); + } + if (pipe_stdin) + weechat_hashtable_set (options_cmd, "stdin", "1"); + new_exec_cmd->hook = weechat_hook_process_hashtable ( + (use_shell) ? "sh" : argv_eol[command_index], + options_cmd, + (int)(timeout * 1000), + &exec_process_cb, + new_exec_cmd); + + weechat_hashtable_free (options_cmd); + + if (!new_exec_cmd->hook) + { + exec_free (new_exec_cmd); + weechat_printf (NULL, + _("%s%s: failed to run command \"%s\""), + weechat_prefix ("error"), EXEC_PLUGIN_NAME, + argv_eol[command_index]); + return WEECHAT_RC_OK; + } + + new_exec_cmd->name = (ptr_name) ? strdup (ptr_name) : NULL; + new_exec_cmd->command = strdup (argv_eol[command_index]); + new_exec_cmd->buffer_plugin = strdup (weechat_buffer_get_string (buffer, + "plugin")); + new_exec_cmd->buffer_name = strdup (weechat_buffer_get_string (buffer, + "name")); + new_exec_cmd->output_to_buffer = output_to_buffer; + 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); + } + + return WEECHAT_RC_OK; +} + +/* + * Hooks exec commands. + */ + +void +exec_command_init () +{ + weechat_hook_command ( + "exec", + N_("execute external commands"), + N_("-list" + " || [-nosh] [-stdin] [-o] [-timeout ] [-name ] " + " || -in " + " || -signal " + " || -kill " + " || -killall"), + N_(" -list: list commands\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" + " -stdin: create a pipe for sending data to the process (with " + "/exec -in)\n" + " -o: send output of command to the current buffer\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\n" + " -in: send text on standard input of process\n" + " -signal: send a signal (integer or name) to the process (example: " + "kill, 9, ...)\n" + " -kill: alias of \"-signal 9\"\n" + "-killall: kill all running processes\n" + " number: command number"), + "-list" + " || -nosh|-stdin|-o|-timeout|-name|%*" + " || -in|-signal|-kill %(exec_commands_ids)" + " || -killall", + &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..312033c41 --- /dev/null +++ b/src/plugins/exec/exec-command.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2014 Sébastien Helleu + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see . + */ + +#ifndef __WEECHAT_EXEC_COMMAND_H +#define __WEECHAT_EXEC_COMMAND_H 1 + +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 + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see . + */ + +#include +#include +#include + +#include "../weechat-plugin.h" +#include "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 + * + * 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 . + */ + +#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..4c5cb1c69 --- /dev/null +++ b/src/plugins/exec/exec-config.c @@ -0,0 +1,151 @@ +/* + * exec-config.c - exec configuration options (file exec.conf) + * + * Copyright (C) 2014 Sébastien Helleu + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see . + */ + +#include +#include +#include + +#include "../weechat-plugin.h" +#include "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_purge_delay; + +/* exec config, color section */ + +struct t_config_option *exec_config_color_flag_running; +struct t_config_option *exec_config_color_flag_finished; + +/* + * 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_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); +} diff --git a/src/plugins/exec/exec-config.h b/src/plugins/exec/exec-config.h new file mode 100644 index 000000000..331f057de --- /dev/null +++ b/src/plugins/exec/exec-config.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 Sébastien Helleu + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see . + */ + +#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_purge_delay; + +extern struct t_config_option *exec_config_color_flag_running; +extern struct t_config_option *exec_config_color_flag_finished; + +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..bbdb33965 --- /dev/null +++ b/src/plugins/exec/exec.c @@ -0,0 +1,500 @@ +/* + * exec.c - execution of external commands in WeeChat + * + * Copyright (C) 2014 Sébastien Helleu + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see . + */ + +#include +#include +#include +#include + +#include "../weechat-plugin.h" +#include "exec.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 "); +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 */ + + +/* + * 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->start_time = time (NULL); + new_exec_cmd->end_time = 0; + new_exec_cmd->buffer_plugin = NULL; + new_exec_cmd->buffer_name = NULL; + new_exec_cmd->output_to_buffer = 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, **lines, str_number[32], str_tags[1024]; + int i, num_lines; + + 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; + + lines = weechat_string_split (ptr_output, "\n", 0, 0, &num_lines); + if (!lines) + return; + + for (i = 0; i < num_lines; i++) + { + if (exec_cmd->output_to_buffer) + weechat_command (buffer, lines[i]); + 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); + weechat_printf_tags (buffer, str_tags, + "%s%s", + (stdout) ? " \t" : weechat_prefix ("error"), + lines[i]); + } + } + + weechat_string_free_split (lines); +} + +/* + * 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_plugin, + exec_cmd->buffer_name); + + /* display return code (only if output is NOT sent to buffer) */ + if (!exec_cmd->output_to_buffer) + { + weechat_printf (ptr_buffer, ""); + if (return_code >= 0) + { + weechat_printf (ptr_buffer, "%s: end of command \"%s\" (rc=%d)", + EXEC_PLUGIN_NAME, exec_cmd->command, + return_code); + } + else + { + weechat_printf (ptr_buffer, + _("%s%s: unexpected end of command \"%s\""), + weechat_prefix ("error"), EXEC_PLUGIN_NAME, + exec_cmd->command); + } + } + + /* 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); + + /* (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_plugin) + free (exec_cmd->buffer_plugin); + if (exec_cmd->buffer_name) + free (exec_cmd->buffer_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 (" start_time. . . . . . . : %ld", ptr_exec_cmd->start_time); + weechat_log_printf (" end_time. . . . . . . . : %ld", ptr_exec_cmd->end_time); + weechat_log_printf (" buffer_plugin . . . . . : '%s'", ptr_exec_cmd->buffer_plugin); + weechat_log_printf (" buffer_name . . . . . . : '%s'", ptr_exec_cmd->buffer_name); + weechat_log_printf (" output_to_buffer. . . . : %d", ptr_exec_cmd->output_to_buffer); + 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[]) +{ + /* make C compiler happy */ + (void) argc; + (void) argv; + + 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 (); + + 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..21490aff6 --- /dev/null +++ b/src/plugins/exec/exec.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 Sébastien Helleu + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see . + */ + +#ifndef __WEECHAT_EXEC_H +#define __WEECHAT_EXEC_H 1 + +#include + +#define weechat_plugin weechat_exec_plugin +#define EXEC_PLUGIN_NAME "exec" + +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 */ + time_t start_time; /* start time */ + time_t end_time; /* end time */ + + /* buffer */ + char *buffer_plugin; /* buffer plugin (where cmd is exec) */ + char *buffer_name; /* buffer name (where cmd is exec) */ + int output_to_buffer; /* 1 if output is sent to buffer */ + + /* 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 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/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