1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-05 01:03:14 +02:00

Merge branch 'exec'

This commit is contained in:
Sebastien Helleu
2014-03-15 12:28:07 +01:00
46 changed files with 3223 additions and 86 deletions
+4
View File
@@ -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)
+8 -4
View File
@@ -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
+30
View File
@@ -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)
+40
View File
@@ -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
+146
View File
@@ -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;
}
+27
View File
@@ -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 */
+753
View File
@@ -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);
}
+46
View File
@@ -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 */
+73
View File
@@ -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);
}
+25
View File
@@ -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 */
+191
View File
@@ -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;
}
}
+42
View File
@@ -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 */
+587
View File
@@ -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;
}
+79
View File
@@ -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 */
+406 -2
View File
@@ -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;
/*
@@ -361,6 +382,371 @@ irc_color_encode (const char *string, int keep_colors)
return (char *)out;
}
/*
* 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".
*
@@ -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;
}
}
+11
View File
@@ -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 */
+3
View File
@@ -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;
}
+68 -1
View File
@@ -277,6 +277,25 @@ plugin_api_command (struct t_weechat_plugin *plugin,
free (command2);
}
/*
* 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"),
+2 -1
View File
@@ -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 */
+8 -4
View File
@@ -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, \