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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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, \
|
||||
|
||||
Reference in New Issue
Block a user