diff options
Diffstat (limited to 'src/plugins/scripts')
-rw-r--r-- | src/plugins/scripts/Makefile.am | 37 | ||||
-rw-r--r-- | src/plugins/scripts/perl/Makefile.am | 26 | ||||
-rw-r--r-- | src/plugins/scripts/perl/weechat-perl.c | 739 | ||||
-rw-r--r-- | src/plugins/scripts/python/Makefile.am | 26 | ||||
-rw-r--r-- | src/plugins/scripts/python/weechat-python.c | 855 | ||||
-rw-r--r-- | src/plugins/scripts/ruby/Makefile.am | 26 | ||||
-rw-r--r-- | src/plugins/scripts/ruby/weechat-ruby.c | 599 | ||||
-rw-r--r-- | src/plugins/scripts/weechat-script.c | 189 | ||||
-rw-r--r-- | src/plugins/scripts/weechat-script.h | 52 |
9 files changed, 2549 insertions, 0 deletions
diff --git a/src/plugins/scripts/Makefile.am b/src/plugins/scripts/Makefile.am new file mode 100644 index 000000000..3ff3b4501 --- /dev/null +++ b/src/plugins/scripts/Makefile.am @@ -0,0 +1,37 @@ +# Copyright (c) 2003-2005 FlashCode <flashcode@flashtux.org> +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\" + +noinst_LTLIBRARIES = lib_weechat_plugins_scripts.la + +lib_weechat_plugins_scripts_la_SOURCES = weechat-script.h \ + weechat-script.c + +if PLUGIN_PERL +perl_dir = perl +endif + +if PLUGIN_PYTHON +python_dir = python +endif + +if PLUGIN_RUBY +#ruby_dir = ruby +endif + +SUBDIRS = . $(perl_dir) $(python_dir) $(ruby_dir) diff --git a/src/plugins/scripts/perl/Makefile.am b/src/plugins/scripts/perl/Makefile.am new file mode 100644 index 000000000..1327bab98 --- /dev/null +++ b/src/plugins/scripts/perl/Makefile.am @@ -0,0 +1,26 @@ +# Copyright (c) 2003-2005 FlashCode <flashcode@flashtux.org> +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\" $(PERL_CFLAGS) + +libdir = ${weechat_libdir}/plugins + +lib_LTLIBRARIES = libperl.la + +libperl_la_SOURCES = weechat-perl.c +libperl_la_LDFLAGS = -module +libperl_la_LIBADD = ../lib_weechat_plugins_scripts.la $(PERL_LFLAGS) diff --git a/src/plugins/scripts/perl/weechat-perl.c b/src/plugins/scripts/perl/weechat-perl.c new file mode 100644 index 000000000..504a0a596 --- /dev/null +++ b/src/plugins/scripts/perl/weechat-perl.c @@ -0,0 +1,739 @@ +/* + * Copyright (c) 2003-2005 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* weechat-perl.c: Perl plugin support for WeeChat */ + + +#include <stdlib.h> +#include <EXTERN.h> +#include <perl.h> +#include <XSUB.h> +#undef _ +#include "../../weechat-plugin.h" +#include "../weechat-script.h" + + +char plugin_name[] = "Perl"; +char plugin_version[] = "0.1"; +char plugin_description[] = "Perl scripts support"; + +t_weechat_plugin *perl_plugin; + +t_plugin_script *perl_scripts = NULL; +t_plugin_script *current_perl_script = NULL; + +static PerlInterpreter *my_perl = NULL; + +extern void boot_DynaLoader (pTHX_ CV* cv); + + +/* + * weechat_perl_exec: execute a Perl script + */ + +int +weechat_perl_exec (t_weechat_plugin *plugin, + t_plugin_script *script, + char *function, char *server, char *arguments) +{ + char empty_server[1] = { '\0' }; + char *argv[3]; + unsigned int count; + int return_code; + SV *sv; + + /* make gcc happy */ + (void) script; + + dSP; + ENTER; + SAVETMPS; + PUSHMARK(sp); + if (!server) + argv[0] = empty_server; + else + argv[0] = server; + argv[1] = arguments; + argv[2] = NULL; + count = perl_call_argv (function, G_EVAL | G_SCALAR, argv); + SPAGAIN; + + sv = GvSV (gv_fetchpv ("@", TRUE, SVt_PV)); + return_code = 1; + if (SvTRUE (sv)) + { + plugin->printf_server (plugin, "Perl error: %s", SvPV (sv, count)); + POPs; + } + else + { + if (count != 1) + { + plugin->printf_server (plugin, + "Perl error: too much values from \"%s\" (%d). Expected: 1.", + function, count); + } + else + return_code = POPi; + } + + PUTBACK; + FREETMPS; + LEAVE; + + return return_code; +} + +/* + * weechat_perl_handler: general message and command handler for Perl + */ + +int +weechat_perl_handler (t_weechat_plugin *plugin, + char *server, char *command, char *arguments, + char *handler_args, void *handler_pointer) +{ + /* make gcc happy */ + (void) command; + + weechat_perl_exec (plugin, (t_plugin_script *)handler_pointer, + handler_args, server, arguments); + return 1; +} + +/* + * weechat::register: startup function for all WeeChat Perl scripts + */ + +static XS (XS_weechat_register) +{ + char *name, *version, *shutdown_func, *description; + unsigned int integer; + dXSARGS; + + /* make gcc happy */ + (void) items; + (void) cv; + + if (items != 4) + { + perl_plugin->printf_server (perl_plugin, + "Perl error: wrong parameters for " + "\"register\" function"); + XSRETURN (0); + return; + } + + name = SvPV (ST (0), integer); + version = SvPV (ST (1), integer); + shutdown_func = SvPV (ST (2), integer); + description = SvPV (ST (3), integer); + + if (weechat_script_search (perl_plugin, &perl_scripts, name)) + { + /* error: another script already exists with this name! */ + perl_plugin->printf_server (perl_plugin, + "Perl error: unable to register " + "\"%s\" script (another script " + "already exists with this name)", + name); + XSRETURN (0); + return; + } + + /* register script */ + current_perl_script = weechat_script_add (perl_plugin, + &perl_scripts, + "", + name, version, shutdown_func, + description); + if (current_perl_script) + { + perl_plugin->printf_server (perl_plugin, + "Perl: registered script \"%s\", " + "version %s (%s)", + name, version, description); + } + else + { + perl_plugin->printf_server (perl_plugin, + "Perl error: unable to load script " + "\"%s\" (not enough memory)", + name); + XSRETURN (0); + return; + } + XSRETURN (1); +} + +/* + * weechat::print: print message into a buffer (current or specified one) + */ + +static XS (XS_weechat_print) +{ + unsigned int integer; + char *message, *channel_name, *server_name; + dXSARGS; + + /* make gcc happy */ + (void) cv; + + if ((items < 1) || (items > 3)) + { + perl_plugin->printf_server (perl_plugin, + "Perl error: wrong parameters for " + "\"print\" function"); + XSRETURN_NO; + return; + } + + channel_name = NULL; + server_name = NULL; + + if (items > 1) + { + channel_name = SvPV (ST (1), integer); + if (items > 2) + server_name = SvPV (ST (2), integer); + } + + message = SvPV (ST (0), integer); + perl_plugin->printf (perl_plugin, + server_name, channel_name, + "%s", message); + XSRETURN_YES; +} + +/* + * weechat::print_infobar: print message to infobar + */ + +static XS (XS_weechat_print_infobar) +{ + unsigned int integer; + dXSARGS; + + /* make gcc happy */ + (void) cv; + + if (items != 2) + { + perl_plugin->printf_server (perl_plugin, + "Perl error: wrong parameters for " + "\"print_infobar\" function"); + XSRETURN_NO; + } + + perl_plugin->infobar_printf (perl_plugin, + SvIV (ST (0)), + SvPV (ST (1), integer)); + XSRETURN_YES; +} + +/* + * weechat::command: send command to server + */ + +static XS (XS_weechat_command) +{ + unsigned int integer; + char *channel_name, *server_name; + dXSARGS; + + /* make gcc happy */ + (void) cv; + + if ((items < 1) || (items > 3)) + { + perl_plugin->printf_server (perl_plugin, + "Perl error: wrong parameters for " + "\"command\" function"); + XSRETURN_NO; + return; + } + + channel_name = NULL; + server_name = NULL; + + if (items > 1) + { + channel_name = SvPV (ST (1), integer); + if (items > 2) + server_name = SvPV (ST (2), integer); + } + + perl_plugin->exec_command (perl_plugin, + server_name, channel_name, + SvPV (ST (0), integer)); + XSRETURN_YES; +} + +/* + * weechat::add_message_handler: add handler for messages (privmsg, ...) + */ + +static XS (XS_weechat_add_message_handler) +{ + char *name, *function; + unsigned int integer; + dXSARGS; + + /* make gcc happy */ + (void) cv; + + if (items != 2) + { + perl_plugin->printf_server (perl_plugin, + "Perl error: wrong parameters for " + "\"add_message_handler\" function"); + XSRETURN_NO; + } + + name = SvPV (ST (0), integer); + function = SvPV (ST (1), integer); + perl_plugin->msg_handler_add (perl_plugin, name, + weechat_perl_handler, function, + (void *)current_perl_script); + XSRETURN_YES; +} + +/* + * weechat::add_command_handler: add command handler (define/redefine commands) + */ + +static XS (XS_weechat_add_command_handler) +{ + char *command, *function, *description, *arguments, *arguments_description; + unsigned int integer; + dXSARGS; + + /* make gcc happy */ + (void) cv; + + if (items < 2) + { + perl_plugin->printf_server (perl_plugin, + "Perl error: wrong parameters for " + "\"add_command_handler\" function"); + XSRETURN_NO; + } + + command = SvPV (ST (0), integer); + function = SvPV (ST (1), integer); + description = (items >= 3) ? SvPV (ST (2), integer) : NULL; + arguments = (items >= 4) ? SvPV (ST (3), integer) : NULL; + arguments_description = (items >= 5) ? SvPV (ST (4), integer) : NULL; + + perl_plugin->cmd_handler_add (perl_plugin, + command, + description, + arguments, + arguments_description, + weechat_perl_handler, + function, + (void *)current_perl_script); + XSRETURN_YES; +} + +/* + * weechat::get_info: get various infos + */ + +static XS (XS_weechat_get_info) +{ + char *arg, *info, *server_name, *channel_name; + unsigned int integer; + dXSARGS; + + /* make gcc happy */ + (void) cv; + + if ((items < 1) || (items > 3)) + { + perl_plugin->printf_server (perl_plugin, + "Perl error: wrong parameters for " + "\"get_info\" function"); + XSRETURN_NO; + } + + server_name = NULL; + channel_name = NULL; + + if (items >= 2) + server_name = SvPV (ST (1), integer); + if (items == 3) + channel_name = SvPV (ST (2), integer); + + arg = SvPV (ST (0), integer); + if (arg) + { + info = perl_plugin->get_info (perl_plugin, arg, server_name, channel_name); + + if (info) + { + XST_mPV (0, info); + free (info); + } + else + XST_mPV (0, ""); + } + + XSRETURN (1); +} + +/* + * weechat::get_dcc_info: get infos about DCC + */ + +static XS (XS_weechat_get_dcc_info) +{ + t_plugin_dcc_info *dcc_info, *ptr_dcc; + int dcc_count; + dXSARGS; + + /* make gcc happy */ + (void) cv; + (void) items; + + dcc_info = perl_plugin->get_dcc_info (perl_plugin); + dcc_count = 0; + + if (!dcc_info) + { + XSRETURN (0); + return; + } + + for (ptr_dcc = dcc_info; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc) + { + HV *infohash = (HV *) sv_2mortal((SV *) newHV()); + + hv_store (infohash, "server", 6, newSVpv (ptr_dcc->server, 0), 0); + hv_store (infohash, "channel", 7, newSVpv (ptr_dcc->channel, 0), 0); + hv_store (infohash, "type", 4, newSViv (ptr_dcc->type), 0); + hv_store (infohash, "status", 6, newSViv (ptr_dcc->status), 0); + hv_store (infohash, "start_time", 10, newSViv (ptr_dcc->start_time), 0); + hv_store (infohash, "start_transfer", 14, newSViv (ptr_dcc->start_transfer), 0); + hv_store (infohash, "address", 7, newSViv (ptr_dcc->addr), 0); + hv_store (infohash, "port", 4, newSViv (ptr_dcc->port), 0); + hv_store (infohash, "nick", 4, newSVpv (ptr_dcc->nick, 0), 0); + hv_store (infohash, "remote_file", 11, newSVpv (ptr_dcc->filename, 0), 0); + hv_store (infohash, "local_file", 10, newSVpv (ptr_dcc->local_filename, 0), 0); + hv_store (infohash, "filename_suffix", 15, newSViv (ptr_dcc->filename_suffix), 0); + hv_store (infohash, "size", 4, newSVnv (ptr_dcc->size), 0); + hv_store (infohash, "pos", 3, newSVnv (ptr_dcc->pos), 0); + hv_store (infohash, "start_resume", 12, newSVnv (ptr_dcc->start_resume), 0); + hv_store (infohash, "cps", 3, newSViv (ptr_dcc->bytes_per_sec), 0); + + XPUSHs(newRV((SV *) infohash)); + dcc_count++; + } + + perl_plugin->free_dcc_info (perl_plugin, dcc_info); + + XSRETURN (dcc_count); +} + +/* + * weechat_perl_xs_init: initialize subroutines + */ + +void +weechat_perl_xs_init (pTHX) +{ + newXS ("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__); + + newXS ("weechat::register", XS_weechat_register, "weechat"); + newXS ("weechat::print", XS_weechat_print, "weechat"); + newXS ("weechat::print_infobar", XS_weechat_print_infobar, "weechat"); + newXS ("weechat::command", XS_weechat_command, "weechat"); + newXS ("weechat::add_message_handler", XS_weechat_add_message_handler, "weechat"); + newXS ("weechat::add_command_handler", XS_weechat_add_command_handler, "weechat"); + newXS ("weechat::get_info", XS_weechat_get_info, "weechat"); + newXS ("weechat::get_dcc_info", XS_weechat_get_dcc_info, "weechat"); +} + +/* + * wee_perl_load: load a Perl script + */ + +int +weechat_perl_load (t_weechat_plugin *plugin, char *filename) +{ + plugin->printf_server (plugin, "Loading Perl script \"%s\"", filename); + return weechat_perl_exec (plugin, NULL, "wee_perl_load_eval_file", filename, ""); +} + +/* + * weechat_perl_unload: unload a Perl script + */ + +void +weechat_perl_unload (t_weechat_plugin *plugin, t_plugin_script *script) +{ + if (script->shutdown_func && script->shutdown_func[0]) + weechat_perl_exec (plugin, script, script->shutdown_func, "", ""); + + weechat_script_remove (plugin, &perl_scripts, script); +} + +/* + * weechat_perl_unload_all: unload all Perl scripts + */ + +void +weechat_perl_unload_all (t_weechat_plugin *plugin) +{ + plugin->printf_server (plugin, + "Unloading all Perl scripts"); + while (perl_scripts) + weechat_perl_unload (plugin, perl_scripts); + + plugin->printf_server (plugin, + "Perl scripts unloaded"); +} + +/* + * weechat_perl_cmd: /perl command handler + */ + +int +weechat_perl_cmd (t_weechat_plugin *plugin, + char *server, char *command, char *arguments, + char *handler_args, void *handler_pointer) +{ + int argc, path_length, handler_found; + char **argv, *path_script, *dir_home; + t_plugin_script *ptr_plugin_script; + t_plugin_msg_handler *ptr_msg_handler; + t_plugin_cmd_handler *ptr_cmd_handler; + + /* make gcc happy */ + (void) server; + (void) command; + (void) handler_args; + (void) handler_pointer; + + argv = plugin->explode_string (plugin, arguments, " ", 0, &argc); + + switch (argc) + { + case 0: + /* list registered Perl scripts */ + plugin->printf_server (plugin, ""); + plugin->printf_server (plugin, "Registered Perl scripts:"); + if (perl_scripts) + { + for (ptr_plugin_script = perl_scripts; ptr_plugin_script; + ptr_plugin_script = ptr_plugin_script->next_script) + { + plugin->printf_server (plugin, " %s v%s%s%s", + ptr_plugin_script->name, + ptr_plugin_script->version, + (ptr_plugin_script->description[0]) ? " - " : "", + ptr_plugin_script->description); + } + } + else + plugin->printf_server (plugin, " (none)"); + + /* list Perl message handlers */ + plugin->printf_server (plugin, ""); + plugin->printf_server (plugin, "Perl message handlers:"); + handler_found = 0; + for (ptr_msg_handler = plugin->msg_handlers; ptr_msg_handler; + ptr_msg_handler = ptr_msg_handler->next_handler) + { + if (ptr_msg_handler->msg_handler_args) + { + handler_found = 1; + plugin->printf_server (plugin, " IRC(%s) => Perl(%s)", + ptr_msg_handler->irc_command, + ptr_msg_handler->msg_handler_args); + } + } + if (!handler_found) + plugin->printf_server (plugin, " (none)"); + + /* list Perl command handlers */ + plugin->printf_server (plugin, ""); + plugin->printf_server (plugin, "Perl command handlers:"); + handler_found = 0; + for (ptr_cmd_handler = plugin->cmd_handlers; ptr_cmd_handler; + ptr_cmd_handler = ptr_cmd_handler->next_handler) + { + if (ptr_cmd_handler->cmd_handler_args) + { + handler_found = 1; + plugin->printf_server (plugin, " /%s => Perl(%s)", + ptr_cmd_handler->command, + ptr_cmd_handler->cmd_handler_args); + } + } + if (!handler_found) + plugin->printf_server (plugin, " (none)"); + break; + case 1: + if (plugin->ascii_strcasecmp (plugin, argv[0], "autoload") == 0) + weechat_script_auto_load (plugin, "perl", weechat_perl_load); + else if (plugin->ascii_strcasecmp (plugin, argv[0], "reload") == 0) + { + weechat_perl_unload_all (plugin); + weechat_script_auto_load (plugin, "perl", weechat_perl_load); + } + else if (plugin->ascii_strcasecmp (plugin, argv[0], "unload") == 0) + weechat_perl_unload_all (plugin); + break; + case 2: + if (plugin->ascii_strcasecmp (plugin, argv[0], "load") == 0) + { + /* load Perl script */ + if ((strstr (argv[1], "/")) || (strstr (argv[1], "\\"))) + path_script = NULL; + else + { + dir_home = plugin->get_info (plugin, "weechat_dir", NULL, NULL); + if (dir_home) + { + path_length = strlen (dir_home) + strlen (argv[1]) + 16; + path_script = (char *) malloc (path_length * sizeof (char)); + if (path_script) + snprintf (path_script, path_length, "%s/perl/%s", + dir_home, argv[1]); + else + path_script = NULL; + free (dir_home); + } + else + path_script = NULL; + } + weechat_perl_load (plugin, (path_script) ? path_script : argv[1]); + if (path_script) + free (path_script); + } + else + { + plugin->printf_server (plugin, + "Perl error: unknown option for " + "\"perl\" command"); + } + break; + default: + plugin->printf_server (plugin, + "Perl error: wrong argument count for \"perl\" command"); + } + plugin->free_exploded_string (plugin, argv); + return 1; +} + +/* + * weechat_plugin_init: initialize Perl plugin + */ + +int +weechat_plugin_init (t_weechat_plugin *plugin) +{ + char *perl_args[] = { "", "-e", "0" }; + /* Following Perl code is extracted/modified from X-Chat IRC client */ + /* X-Chat is (c) 1998-2005 Peter Zelezny */ + char *weechat_perl_func = + { + "sub wee_perl_load_file" + "{" + " my $filename = shift;" + " local $/ = undef;" + " open FILE, $filename or return \"__WEECHAT_ERROR__\";" + " $_ = <FILE>;" + " close FILE;" + " return $_;" + "}" + "sub wee_perl_load_eval_file" + "{" + " my $filename = shift;" + " my $content = wee_perl_load_file ($filename);" + " if ($content eq \"__WEECHAT_ERROR__\")" + " {" + " weechat::print \"Perl error: script '$filename' not found.\", \"\";" + " return 1;" + " }" + " eval $content;" + " if ($@)" + " {" + " weechat::print \"Perl error: unable to load script '$filename':\", \"\";" + " weechat::print \"$@\";" + " return 2;" + " }" + " return 0;" + "}" + "$SIG{__WARN__} = sub { weechat::print \"$_[0]\", \"\"; };" + }; + + perl_plugin = plugin; + + plugin->printf_server (plugin, "Loading Perl module \"weechat\""); + + my_perl = perl_alloc (); + if (!my_perl) + { + plugin->printf_server (plugin, + "Perl error: unable to initialize Perl"); + return 0; + } + perl_construct (my_perl); + perl_parse (my_perl, weechat_perl_xs_init, 3, perl_args, NULL); + eval_pv (weechat_perl_func, TRUE); + + plugin->cmd_handler_add (plugin, "perl", + "list/load/unload Perl scripts", + "[load filename] | [autoload] | [reload] | [unload]", + "filename: Perl script (file) to load\n\n" + "Without argument, /perl command lists all loaded Perl scripts.", + weechat_perl_cmd, NULL, NULL); + + plugin->mkdir_home (plugin, "perl"); + plugin->mkdir_home (plugin, "perl/autoload"); + + weechat_script_auto_load (plugin, "perl", weechat_perl_load); + + /* init ok */ + return 1; +} + +/* + * weechat_plugin_end: shutdown Perl interface + */ + +void +weechat_plugin_end (t_weechat_plugin *plugin) +{ + /* unload all scripts */ + weechat_perl_unload_all (plugin); + + /* free Perl interpreter */ + if (my_perl) + { + perl_destruct (my_perl); + perl_free (my_perl); + my_perl = NULL; + } + + perl_plugin->printf_server (perl_plugin, + "Perl plugin ended"); +} diff --git a/src/plugins/scripts/python/Makefile.am b/src/plugins/scripts/python/Makefile.am new file mode 100644 index 000000000..fed11c566 --- /dev/null +++ b/src/plugins/scripts/python/Makefile.am @@ -0,0 +1,26 @@ +# Copyright (c) 2003-2005 FlashCode <flashcode@flashtux.org> +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\" $(PYTHON_CFLAGS) + +libdir = ${weechat_libdir}/plugins + +lib_LTLIBRARIES = libpython.la + +libpython_la_SOURCES = weechat-python.c +libpython_la_LDFLAGS = -module +libpython_la_LIBADD = ../lib_weechat_plugins_scripts.la $(PYTHON_LFLAGS) diff --git a/src/plugins/scripts/python/weechat-python.c b/src/plugins/scripts/python/weechat-python.c new file mode 100644 index 000000000..9a4f54d63 --- /dev/null +++ b/src/plugins/scripts/python/weechat-python.c @@ -0,0 +1,855 @@ +/* + * Copyright (c) 2003-2005 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* weechat-python.c: Python plugin support for WeeChat */ + + +#include <Python.h> +#include <stdlib.h> +#include <string.h> +#undef _ +#include "../../weechat-plugin.h" +#include "../weechat-script.h" + + +char plugin_name[] = "Python"; +char plugin_version[] = "0.1"; +char plugin_description[] = "Python scripts support"; + +t_weechat_plugin *python_plugin; + +t_plugin_script *python_scripts = NULL; +t_plugin_script *python_current_script = NULL; +char *python_current_script_filename = NULL; +PyThreadState *python_mainThreadState = NULL; + + +/* + * weechat_python_exec: execute a Python script + */ + +int +weechat_python_exec (t_weechat_plugin *plugin, + t_plugin_script *script, + char *function, char *server, char *arguments) +{ + PyObject *evMain; + PyObject *evDict; + PyObject *evFunc; + + PyThreadState_Swap (NULL); + + PyEval_AcquireLock (); + + PyThreadState_Swap (script->interpreter); + + evMain = PyImport_AddModule ((char *) "__main__"); + evDict = PyModule_GetDict (evMain); + evFunc = PyDict_GetItemString (evDict, function); + + if ( !(evFunc && PyCallable_Check (evFunc)) ) + { + plugin->printf_server (plugin, + "Python error: unable to run function \"%s\"", + function); + PyEval_ReleaseLock(); + return 1; + } + + PyObject_CallFunction(evFunc, "ss", server == NULL ? "" : server, arguments == NULL ? "" : arguments); + + PyEval_ReleaseLock(); + + return 0; +} + +/* + * weechat_python_handler: general message and command handler for Python + */ + +int +weechat_python_handler (t_weechat_plugin *plugin, + char *server, char *command, char *arguments, + char *handler_args, void *handler_pointer) +{ + /* make gcc happy */ + (void) command; + + weechat_python_exec (plugin, (t_plugin_script *)handler_pointer, + handler_args, server, arguments); + return 1; +} + +/* + * weechat.register: startup function for all WeeChat Python scripts + */ + +static PyObject * +weechat_python_register (PyObject *self, PyObject *args) +{ + char *name, *version, *shutdown_func, *description; + + /* make gcc happy */ + (void) self; + + name = NULL; + version = NULL; + shutdown_func = NULL; + description = NULL; + + if (!PyArg_ParseTuple (args, "ssss", &name, &version, &shutdown_func, &description)) + { + python_plugin->printf_server (python_plugin, + "Python error: wrong parameters for " + "\"register\" function"); + return NULL; + } + + if (weechat_script_search (python_plugin, &python_scripts, name)) + { + /* error: another scripts already exists with this name! */ + python_plugin->printf_server (python_plugin, + "Python error: unable to register " + "\"%s\" script (another script " + "already exists with this name)", + name); + return NULL; + } + + /* register script */ + python_current_script = weechat_script_add (python_plugin, + &python_scripts, + (python_current_script_filename) ? + python_current_script_filename : "", + name, version, shutdown_func, + description); + if (python_current_script) + { + python_plugin->printf_server (python_plugin, + "Python: registered script \"%s\", " + "version %s (%s)", + name, version, description); + } + else + { + python_plugin->printf_server (python_plugin, + "Python error: unable to load script " + "\"%s\" (not enough memory)", + name); + return NULL; + } + + Py_INCREF (Py_None); + return Py_None; +} + +/* + * weechat.print: print message into a buffer (current or specified one) + */ + +static PyObject * +weechat_python_print (PyObject *self, PyObject *args) +{ + char *message, *channel_name, *server_name; + + /* make gcc happy */ + (void) self; + + message = NULL; + channel_name = NULL; + server_name = NULL; + + if (!PyArg_ParseTuple (args, "s|ss", &message, &channel_name, &server_name)) + { + python_plugin->printf_server (python_plugin, + "Python error: wrong parameters for " + "\"print\" function"); + return NULL; + } + + python_plugin->printf (python_plugin, + server_name, channel_name, + "%s", message); + return Py_BuildValue ("i", 1); +} + +/* + * weechat.print_infobar: print message to infobar + */ + +static PyObject * +weechat_python_print_infobar (PyObject *self, PyObject *args) +{ + int delay; + char *message; + + /* make gcc happy */ + (void) self; + + delay = 1; + message = NULL; + + if (!PyArg_ParseTuple (args, "is", &delay, &message)) + { + python_plugin->printf_server (python_plugin, + "Python error: wrong parameters for " + "\"print_infobar\" function"); + return NULL; + } + + python_plugin->infobar_printf (python_plugin, delay, message); + + Py_INCREF (Py_None); + return Py_None; +} + +/* + * weechat.command: send command to server + */ + +static PyObject * +weechat_python_command (PyObject *self, PyObject *args) +{ + char *command, *channel_name, *server_name; + + /* make gcc happy */ + (void) self; + + command = NULL; + channel_name = NULL; + server_name = NULL; + + if (!PyArg_ParseTuple (args, "s|ss", &command, &channel_name, &server_name)) + { + python_plugin->printf_server (python_plugin, + "Python error: wrong parameters for " + "\"command\" function"); + return NULL; + } + + python_plugin->exec_command (python_plugin, + server_name, channel_name, + command); + return Py_BuildValue ("i", 1); +} + +/* + * weechat.add_message_handler: add handler for messages + */ + +static PyObject * +weechat_python_add_message_handler (PyObject *self, PyObject *args) +{ + char *message, *function; + + /* make gcc happy */ + (void) self; + + message = NULL; + function = NULL; + + if (!PyArg_ParseTuple (args, "ss", &message, &function)) + { + python_plugin->printf_server (python_plugin, + "Python error: wrong parameters for " + "\"add_message_handler\" function"); + return NULL; + } + + if (python_current_script) + python_plugin->msg_handler_add (python_plugin, message, + weechat_python_handler, function, + (void *)python_current_script); + else + { + python_plugin->printf_server (python_plugin, + "Python error: unable to add message handler, " + "script not initialized"); + return NULL; + } + + Py_INCREF (Py_None); + return Py_None; +} + +/* + * weechat.add_command_handler: define/redefines commands + */ + +static PyObject * +weechat_python_add_command_handler (PyObject *self, PyObject *args) +{ + char *command, *function, *description, *arguments, *arguments_description; + + /* make gcc happy */ + (void) self; + + command = NULL; + function = NULL; + description = NULL; + arguments = NULL; + arguments_description = NULL; + + if (!PyArg_ParseTuple (args, "ss|sss", &command, &function, + &description, &arguments, &arguments_description)) + { + python_plugin->printf_server (python_plugin, + "Python error: wrong parameters for " + "\"add_command_handler\" function"); + return NULL; + } + + if (python_current_script) + python_plugin->cmd_handler_add (python_plugin, + command, + description, + arguments, + arguments_description, + weechat_python_handler, + function, + (void *)python_current_script); + else + { + python_plugin->printf_server (python_plugin, + "Python error: unable to add command handler, " + "script not initialized"); + return NULL; + } + + Py_INCREF (Py_None); + return Py_None; +} + +/* + * weechat.get_info: get various infos + */ + +static PyObject * +weechat_python_get_info (PyObject *self, PyObject *args) +{ + char *arg, *server_name, *channel_name, *info; + PyObject *object; + + /* make gcc happy */ + (void) self; + + arg = NULL; + server_name = NULL; + channel_name = NULL; + + if (!PyArg_ParseTuple (args, "s|ss", &arg, &server_name, &channel_name)) + { + python_plugin->printf_server (python_plugin, + "Python error: wrong parameters for " + "\"get_info\" function"); + return NULL; + } + + if (arg) + { + info = python_plugin->get_info (python_plugin, arg, server_name, channel_name); + + if (info) + { + object = Py_BuildValue ("s", info); + free (info); + return object; + } + else + return Py_BuildValue ("s", ""); + } + + return Py_BuildValue ("i", 1); +} + +/* + * weechat.get_dcc_info: get infos about DCC + */ + +static PyObject * +weechat_python_get_dcc_info (PyObject *self, PyObject *args) +{ + t_plugin_dcc_info *dcc_info, *ptr_dcc; + int dcc_count; + PyObject *list, *listvalue; + + /* make gcc happy */ + (void) self; + (void) args; + + dcc_info = python_plugin->get_dcc_info (python_plugin); + dcc_count = 0; + + if (!dcc_info) + return Py_None; + + for (ptr_dcc = dcc_info; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc) + { + dcc_count++; + } + + list = PyList_New (dcc_count); + + if (!list) + { + python_plugin->free_dcc_info (python_plugin, dcc_info); + return Py_None; + } + + dcc_count = 0; + for(ptr_dcc = dcc_info; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc) + { + listvalue = Py_BuildValue ("{s:s,s:s,s:i,s:i,s:k,s:k,s:k,s:i,s:s,s:s," + "s:s,s:s,s:k,s:k,s:k,s:k}", + "server", ptr_dcc->server, + "channel", ptr_dcc->channel, + "type", ptr_dcc->type, + "status", ptr_dcc->status, + "start_time", ptr_dcc->start_time, + "start_transfer", ptr_dcc->start_transfer, + "address", ptr_dcc->addr, + "port", ptr_dcc->port, + "nick", ptr_dcc->nick, + "remote_file", ptr_dcc->filename, + "local_file", ptr_dcc->local_filename, + "filename_suffix", ptr_dcc->filename_suffix, + "size", ptr_dcc->size, + "pos", ptr_dcc->pos, + "start_resume", ptr_dcc->start_resume, + "cps", ptr_dcc->bytes_per_sec); + if (listvalue) + { + if (PyList_SetItem (list, dcc_count, listvalue) != 0) + { + PyMem_Free (listvalue); + PyMem_Free (list); + python_plugin->free_dcc_info (python_plugin, dcc_info); + return Py_None; + } + PyMem_Free (listvalue); + } + else + { + python_plugin->free_dcc_info (python_plugin, dcc_info); + return Py_None; + } + dcc_count++; + } + + python_plugin->free_dcc_info (python_plugin, dcc_info); + + return list; +} + +/* + * Python subroutines + */ + +static +PyMethodDef weechat_funcs[] = { + { "register", weechat_python_register, METH_VARARGS, "" }, + { "prnt", weechat_python_print, METH_VARARGS, "" }, + { "print_infobar", weechat_python_print_infobar, METH_VARARGS, "" }, + { "command", weechat_python_command, METH_VARARGS, "" }, + { "add_message_handler", weechat_python_add_message_handler, METH_VARARGS, "" }, + { "add_command_handler", weechat_python_add_command_handler, METH_VARARGS, "" }, + { "get_info", weechat_python_get_info, METH_VARARGS, "" }, + { "get_dcc_info", weechat_python_get_dcc_info, METH_VARARGS, "" }, + { NULL, NULL, 0, NULL } +}; + +/* + * weechat_python_load: load a Python script + */ + +int +weechat_python_load (t_weechat_plugin *plugin, char *filename) +{ + FILE *fp; + PyThreadState *python_current_interpreter; + + plugin->printf_server (plugin, "Loading Python script \"%s\"", filename); + + if ((fp = fopen (filename, "r")) == NULL) + { + plugin->printf_server (plugin, + "Python error: unable to open file \"%s\"", + filename); + return 0; + } + + python_current_script = NULL; + + PyThreadState_Swap(NULL); + + PyEval_AcquireLock(); + + python_current_interpreter = PyThreadState_New (python_mainThreadState->interp); + + if (python_current_interpreter == NULL) + { + plugin->printf_server (plugin, + "Python error: unable to create new sub-interpreter"); + PyEval_ReleaseLock(); + fclose (fp); + return 0; + } + + PyThreadState_Swap (python_current_interpreter); + + if (Py_InitModule ("weechat", weechat_funcs) == NULL) + { + plugin->printf_server (plugin, + "Python error: unable to initialize WeeChat module"); + PyThreadState_Swap (NULL); + PyThreadState_Clear (python_current_interpreter); + PyThreadState_Delete (python_current_interpreter); + PyEval_ReleaseLock (); + fclose (fp); + return 0; + } + + if (PyRun_SimpleString ( + "import weechat, sys, string\n" + + "class weechatStdout:\n" + "\tdef write(self, str):\n" + "\t\tstr = string.strip(str)\n" + "\t\tif str != \"\":\n" + "\t\t\tweechat.prnt(\"Python stdout : \" + str, \"\")\n" + + "class weechatStderr:\n" + "\tdef write(self, str):\n" + "\t\tstr = string.strip(str)\n" + "\t\tif str != \"\":\n" + "\t\t\tweechat.prnt(\"Python stderr : \" + str, \"\")\n" + + "sys.stdout = weechatStdout()\n" + "sys.stderr = weechatStderr()\n" + ) != 0) + { + plugin->printf_server (plugin, + "Python warning: unable to redirect stdout and stderr"); + } + + python_current_script_filename = strdup (filename); + + if (PyRun_SimpleFile (fp, filename) != 0) + { + plugin->printf_server (plugin, + "Python error: unable to parse file \"%s\"", + filename); + free (python_current_script_filename); + PyThreadState_Swap (NULL); + PyThreadState_Clear (python_current_interpreter); + PyThreadState_Delete (python_current_interpreter); + PyEval_ReleaseLock (); + fclose (fp); + return 0; + } + + fclose (fp); + free (python_current_script_filename); + + if (python_current_script == NULL) + { + plugin->printf_server (plugin, + "Python error: function \"register\" not found " + "in file \"%s\"", + filename); + PyThreadState_Swap (NULL); + PyThreadState_Clear (python_current_interpreter); + PyThreadState_Delete (python_current_interpreter); + PyEval_ReleaseLock (); + return 0; + } + + python_current_script->interpreter = (PyThreadState *) python_current_interpreter; + PyThreadState_Swap (NULL); + PyEval_ReleaseLock (); + + return 1; +} + +/* + * weechat_python_unload: unload a Python script + */ + +void +weechat_python_unload (t_weechat_plugin *plugin, t_plugin_script *script) +{ + plugin->printf_server (plugin, + "Unloading Python script \"%s\"", + script->name); + + if (script->shutdown_func[0]) + weechat_python_exec (plugin, script, script->shutdown_func, "", ""); + + PyThreadState_Swap (NULL); + PyThreadState_Clear (script->interpreter); + PyThreadState_Delete (script->interpreter); + + weechat_script_remove (plugin, &python_scripts, script); +} + +/* + * weechat_python_unload_name: unload a Python script by name + */ + +void +weechat_python_unload_name (t_weechat_plugin *plugin, char *name) +{ + t_plugin_script *ptr_script; + + ptr_script = weechat_script_search (plugin, &python_scripts, name); + if (ptr_script) + { + weechat_python_unload (plugin, ptr_script); + plugin->printf_server (plugin, + "Python script \"%s\" unloaded", + name); + } + else + { + plugin->printf_server (plugin, + "Python error: script \"%s\" not loaded", + name); + } +} + +/* + * weechat_python_unload_all: unload all Python scripts + */ + +void +weechat_python_unload_all (t_weechat_plugin *plugin) +{ + plugin->printf_server (plugin, + "Unloading all Python scripts"); + while (python_scripts) + weechat_python_unload (plugin, python_scripts); + + plugin->printf_server (plugin, + "Python scripts unloaded"); +} + +/* + * weechat_python_cmd: /python command handler + */ + +int +weechat_python_cmd (t_weechat_plugin *plugin, + char *server, char *command, char *arguments, + char *handler_args, void *handler_pointer) +{ + int argc, path_length, handler_found; + char **argv, *path_script, *dir_home; + t_plugin_script *ptr_plugin_script; + t_plugin_msg_handler *ptr_msg_handler; + t_plugin_cmd_handler *ptr_cmd_handler; + + /* make gcc happy */ + (void) server; + (void) command; + (void) handler_args; + (void) handler_pointer; + + argv = plugin->explode_string (plugin, arguments, " ", 0, &argc); + + switch (argc) + { + case 0: + /* list registered Python scripts */ + plugin->printf_server (plugin, ""); + plugin->printf_server (plugin, "Registered Python scripts:"); + if (python_scripts) + { + for (ptr_plugin_script = python_scripts; ptr_plugin_script; + ptr_plugin_script = ptr_plugin_script->next_script) + { + plugin->printf_server (plugin, " %s v%s%s%s", + ptr_plugin_script->name, + ptr_plugin_script->version, + (ptr_plugin_script->description[0]) ? " - " : "", + ptr_plugin_script->description); + } + } + else + plugin->printf_server (plugin, " (none)"); + + /* list Python message handlers */ + plugin->printf_server (plugin, ""); + plugin->printf_server (plugin, "Python message handlers:"); + handler_found = 0; + for (ptr_msg_handler = plugin->msg_handlers; ptr_msg_handler; + ptr_msg_handler = ptr_msg_handler->next_handler) + { + if (ptr_msg_handler->msg_handler_args) + { + handler_found = 1; + plugin->printf_server (plugin, " IRC(%s) => Python(%s)", + ptr_msg_handler->irc_command, + ptr_msg_handler->msg_handler_args); + } + } + if (!handler_found) + plugin->printf_server (plugin, " (none)"); + + /* list Python command handlers */ + plugin->printf_server (plugin, ""); + plugin->printf_server (plugin, "Python command handlers:"); + handler_found = 0; + for (ptr_cmd_handler = plugin->cmd_handlers; ptr_cmd_handler; + ptr_cmd_handler = ptr_cmd_handler->next_handler) + { + if (ptr_cmd_handler->cmd_handler_args) + { + handler_found = 1; + plugin->printf_server (plugin, " /%s => Python(%s)", + ptr_cmd_handler->command, + ptr_cmd_handler->cmd_handler_args); + } + } + if (!handler_found) + plugin->printf_server (plugin, " (none)"); + break; + case 1: + if (plugin->ascii_strcasecmp (plugin, argv[0], "autoload") == 0) + weechat_script_auto_load (plugin, "python", weechat_python_load); + else if (plugin->ascii_strcasecmp (plugin, argv[0], "reload") == 0) + { + weechat_python_unload_all (plugin); + weechat_script_auto_load (plugin, "python", weechat_python_load); + } + else if (plugin->ascii_strcasecmp (plugin, argv[0], "unload") == 0) + weechat_python_unload_all (plugin); + break; + case 2: + if (plugin->ascii_strcasecmp (plugin, argv[0], "load") == 0) + { + /* load Python script */ + if ((strstr (argv[1], "/")) || (strstr (argv[1], "\\"))) + path_script = NULL; + else + { + dir_home = plugin->get_info (plugin, "weechat_dir", NULL, NULL); + if (dir_home) + { + path_length = strlen (dir_home) + strlen (argv[1]) + 16; + path_script = (char *) malloc (path_length * sizeof (char)); + if (path_script) + snprintf (path_script, path_length, "%s/python/%s", + dir_home, argv[1]); + else + path_script = NULL; + free (dir_home); + } + else + path_script = NULL; + } + weechat_python_load (plugin, (path_script) ? path_script : argv[1]); + if (path_script) + free (path_script); + } + else if (plugin->ascii_strcasecmp (plugin, argv[0], "unload") == 0) + { + /* unload Python script */ + weechat_python_unload_name (plugin, argv[1]); + } + else + { + plugin->printf_server (plugin, + "Python error: unknown option for " + "\"python\" command"); + } + break; + default: + plugin->printf_server (plugin, + "Python error: wrong argument count for \"python\" command"); + } + plugin->free_exploded_string (plugin, argv); + return 1; +} + +/* + * weechat_plugin_init: initialize Python plugin + */ + +int +weechat_plugin_init (t_weechat_plugin *plugin) +{ + python_plugin = plugin; + + plugin->printf_server (plugin, "Loading Python module \"weechat\""); + + Py_Initialize (); + if (Py_IsInitialized () == 0) + { + plugin->printf_server (plugin, + "Python error: unable to launch global interpreter"); + return 0; + } + + PyEval_InitThreads(); + + python_mainThreadState = PyThreadState_Get(); + + if (python_mainThreadState == NULL) + { + plugin->printf_server (plugin, + "Python error: unable to get current interpreter state"); + return 0; + } + + PyEval_ReleaseLock (); + + plugin->cmd_handler_add (plugin, "python", + "list/load/unload Python scripts", + "[load filename] | [autoload] | [reload] | [unload]", + "filename: Python script (file) to load\n\n" + "Without argument, /python command lists all loaded Python scripts.", + weechat_python_cmd, NULL, NULL); + + plugin->mkdir_home (plugin, "python"); + plugin->mkdir_home (plugin, "python/autoload"); + + weechat_script_auto_load (plugin, "python", weechat_python_load); + + return 1; +} + +/* + * weechat_plugin_end: shutdown Python interface + */ + +void +weechat_plugin_end (t_weechat_plugin *plugin) +{ + /* unload all scripts */ + weechat_python_unload_all (plugin); + + /* free Python interpreter */ + /*Py_Finalize (); + if (Py_IsInitialized () != 0) + python_plugin->printf_server (python_plugin, + "Python error: unable to free interpreter"); + + python_plugin->printf_server (python_plugin, + "Python plugin ended");*/ +} diff --git a/src/plugins/scripts/ruby/Makefile.am b/src/plugins/scripts/ruby/Makefile.am new file mode 100644 index 000000000..07e8f9210 --- /dev/null +++ b/src/plugins/scripts/ruby/Makefile.am @@ -0,0 +1,26 @@ +# Copyright (c) 2003-2005 FlashCode <flashcode@flashtux.org> +# +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\" $(RUBY_CFLAGS) + +libdir = ${weechat_libdir}/plugins + +lib_LTLIBRARIES = libruby.la + +libruby_la_SOURCES = weechat-ruby.c +libruby_la_LDFLAGS = -module +libruby_la_LIBADD = ../lib_weechat_plugins_scripts.la $(RUBY_LFLAGS) diff --git a/src/plugins/scripts/ruby/weechat-ruby.c b/src/plugins/scripts/ruby/weechat-ruby.c new file mode 100644 index 000000000..b517aa1f2 --- /dev/null +++ b/src/plugins/scripts/ruby/weechat-ruby.c @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2003-2005 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* wee-ruby.c: Ruby plugin support for WeeChat */ + + +#include <ruby.h> + +#include <stdlib.h> +#include <string.h> +#undef _ +#include "../../weechat-plugin.h" +#include "../weechat-script.h" + + +t_plugin_script *ruby_scripts = NULL; +t_plugin_script *last_ruby_script = NULL; + + +/* + * register: startup function for all WeeChat Ruby scripts + */ + +static VALUE +wee_ruby_register (VALUE class, VALUE name, VALUE version, VALUE shutdown_func, VALUE description) +{ + char *c_name, *c_version, *c_shutdown_func, *c_description; + t_plugin_script *ptr_ruby_script, *ruby_script_found, *new_ruby_script; + + if (NIL_P (name) || NIL_P (version) || NIL_P (shutdown_func) || NIL_P (description)) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: wrong parameters for \"%s\" function\n"), + "Ruby", "register"); + return Qnil; + } + + Check_Type (name, T_STRING); + Check_Type (version, T_STRING); + Check_Type (shutdown_func, T_STRING); + Check_Type (description, T_STRING); + + c_name = STR2CSTR (name); + c_version = STR2CSTR (version); + c_shutdown_func = STR2CSTR (shutdown_func); + c_description = STR2CSTR (description); + + ruby_script_found = NULL; + for (ptr_ruby_script = ruby_scripts; ptr_ruby_script; + ptr_ruby_script = ptr_ruby_script->next_script) + { + if (ascii_strcasecmp (ptr_ruby_script->name, c_name) == 0) + { + ruby_script_found = ptr_ruby_script; + break; + } + } + + if (ruby_script_found) + { + /* error: another script already exists with this name! */ + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: unable to register \"%s\" script (another script " + "already exists with this name)\n"), + "Ruby", name); + } + else + { + /* registering script */ + new_ruby_script = (t_plugin_script *)malloc (sizeof (t_plugin_script)); + if (new_ruby_script) + { + new_ruby_script->name = strdup (c_name); + new_ruby_script->version = strdup (c_version); + new_ruby_script->shutdown_func = strdup (c_shutdown_func); + new_ruby_script->description = strdup (c_description); + + /* add new script to list */ + new_ruby_script->prev_script = last_ruby_script; + new_ruby_script->next_script = NULL; + if (ruby_scripts) + last_ruby_script->next_script = new_ruby_script; + else + ruby_scripts = new_ruby_script; + last_ruby_script = new_ruby_script; + + wee_log_printf (_("Registered %s script: \"%s\", version %s (%s)\n"), + "Ruby", c_name, c_version, c_description); + } + else + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: unable to load script \"%s\" (not enough memory)\n"), + "Ruby", c_name); + } + } + + return Qnil; +} + +/* + * print: print message into a buffer (current or specified one) + */ + +static VALUE +wee_ruby_print (VALUE class, VALUE message, VALUE channel_name, VALUE server_name) +{ + char *c_message, *c_channel_name, *c_server_name; + t_gui_buffer *ptr_buffer; + + c_message = NULL; + c_channel_name = NULL; + c_server_name = NULL; + + if (NIL_P (message)) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: wrong parameters for \"%s\" function\n"), + "Ruby", "print"); + return Qnil; + } + + Check_Type (message, T_STRING); + if (!NIL_P (channel_name)) + Check_Type (channel_name, T_STRING); + if (!NIL_P (server_name)) + Check_Type (server_name, T_STRING); + + c_message = STR2CSTR (message); + if (!NIL_P (channel_name)) + c_channel_name = STR2CSTR (channel_name); + if (!NIL_P (server_name)) + c_server_name = STR2CSTR (server_name); + + ptr_buffer = plugin_find_buffer (c_server_name, c_channel_name); + if (ptr_buffer) + { + irc_display_prefix (ptr_buffer, PREFIX_PLUGIN); + gui_printf (ptr_buffer, "%s\n", c_message); + return INT2FIX (1); + } + + /* buffer not found */ + return INT2FIX (0); +} + +/* + * print_infobar: print message to infobar + */ + +static VALUE +wee_ruby_print_infobar (VALUE class, VALUE delay, VALUE message) +{ + int c_delay; + char *c_message; + + c_delay = 1; + c_message = NULL; + + if (NIL_P (delay) || NIL_P (message)) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: wrong parameters for \"%s\" function\n"), + "Ruby", "print_infobar"); + return Qfalse; + } + + Check_Type (delay, T_FIXNUM); + Check_Type (message, T_STRING); + + c_delay = FIX2INT (delay); + c_message = STR2CSTR (message); + + gui_infobar_printf (delay, COLOR_WIN_INFOBAR, c_message); + + return Qtrue; +} + +/* + * command: send command to server + */ + +static VALUE +wee_ruby_command (VALUE class, VALUE command, VALUE channel_name, VALUE server_name) +{ + char *c_command, *c_channel_name, *c_server_name; + t_gui_buffer *ptr_buffer; + + c_command = NULL; + c_channel_name = NULL; + c_server_name = NULL; + + if (NIL_P (command)) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: wrong parameters for \"%s\" function\n"), + "Ruby", "command"); + return Qnil; + } + + Check_Type (command, T_STRING); + if (!NIL_P (channel_name)) + Check_Type (channel_name, T_STRING); + if (!NIL_P (server_name)) + Check_Type (server_name, T_STRING); + + c_command = STR2CSTR (command); + if (!NIL_P (channel_name)) + c_channel_name = STR2CSTR (channel_name); + if (!NIL_P (server_name)) + c_server_name = STR2CSTR (server_name); + + ptr_buffer = plugin_find_buffer (c_server_name, c_channel_name); + if (ptr_buffer) + { + user_command (SERVER(ptr_buffer), ptr_buffer, c_command); + return INT2FIX (1); + } + + /* buffer not found */ + return INT2FIX (0); +} + +/* + * add_message_handler: add handler for messages + */ + +static VALUE +wee_ruby_add_message_handler (VALUE class, VALUE message, VALUE function) +{ + char *c_message, *c_function; + + if (NIL_P (message) || NIL_P (function)) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: wrong parameters for \"%s\" function\n"), + "Ruby", "add_message_handler"); + return Qnil; + } + + Check_Type (message, T_STRING); + Check_Type (function, T_STRING); + + c_message = STR2CSTR (message); + c_function = STR2CSTR (function); + + plugin_handler_add (&plugin_msg_handlers, &last_plugin_msg_handler, + PLUGIN_TYPE_RUBY, c_message, c_function); + + return Qtrue; +} + +/* + * add_command_handler: define/redefines commands + */ + +static VALUE +wee_ruby_add_command_handler (VALUE class, VALUE name, VALUE function) +{ + char *c_name, *c_function; + t_plugin_handler *ptr_plugin_handler; + + if (NIL_P (name) || NIL_P (function)) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: wrong parameters for \"%s\" function\n"), + "Ruby", "add_command_handler"); + return Qnil; + } + + Check_Type (name, T_STRING); + Check_Type (function, T_STRING); + + c_name = STR2CSTR (name); + c_function = STR2CSTR (function); + + if (!weelist_search (index_commands, c_name)) + weelist_add (&index_commands, &last_index_command, c_name); + + ptr_plugin_handler = plugin_handler_search (plugin_cmd_handlers, c_name); + if (ptr_plugin_handler) + { + free (ptr_plugin_handler->function_name); + ptr_plugin_handler->function_name = strdup (c_function); + } + else + plugin_handler_add (&plugin_cmd_handlers, &last_plugin_cmd_handler, + PLUGIN_TYPE_PYTHON, c_name, c_function); + + return Qtrue; +} + +/* + * get_info: get various infos + */ + +static VALUE +wee_ruby_get_info (VALUE class, VALUE arg, VALUE server_name) +{ + char *c_arg, *info, *c_server_name; + t_irc_server *ptr_server; + + if (NIL_P (arg)) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: wrong parameters for \"%s\" function\n"), + "Ruby", "get_info"); + return Qnil; + } + + Check_Type (arg, T_STRING); + if (!NIL_P (server_name)) + Check_Type (server_name, T_STRING); + + c_arg = STR2CSTR (arg); + if (!NIL_P (server_name)) + c_server_name = STR2CSTR (server_name); + + if (c_server_name == NULL) + { + ptr_server = SERVER(gui_current_window->buffer); + } + else + { + for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) + { + if (ascii_strcasecmp (ptr_server->name, c_server_name) == 0) + break; + } + if (!ptr_server) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: server not found for \"%s\" function\n"), + "Ruby", "get_info"); + return Qnil; + } + } + + if (ptr_server && c_arg) + { + if ( (ascii_strcasecmp (c_arg, "0") == 0) || (ascii_strcasecmp (c_arg, "version") == 0) ) + { + info = PACKAGE_STRING; + } + else if ( (ascii_strcasecmp (c_arg, "1") == 0) || (ascii_strcasecmp (c_arg, "nick") == 0) ) + { + if (ptr_server->nick) + info = ptr_server->nick; + } + else if ( (ascii_strcasecmp (c_arg, "2") == 0) || (ascii_strcasecmp (c_arg, "channel") == 0) ) + { + if (BUFFER_IS_CHANNEL (gui_current_window->buffer)) + info = CHANNEL (gui_current_window->buffer)->name; + } + else if ( (ascii_strcasecmp (c_arg, "3") == 0) || (ascii_strcasecmp (c_arg, "server") == 0) ) + { + if (ptr_server->name) + info = ptr_server->name; + } + else if ( (ascii_strcasecmp (c_arg, "4") == 0) || (ascii_strcasecmp (c_arg, "weechatdir") == 0) ) + { + info = weechat_home; + } + else if ( (ascii_strcasecmp (c_arg, "5") == 0) || (ascii_strcasecmp (c_arg, "away") == 0) ) + { + return INT2FIX (SERVER(gui_current_window->buffer)->is_away); + } + else if ( (ascii_strcasecmp (c_arg, "100") == 0) || (ascii_strcasecmp (c_arg, "dccs") == 0) ) + { + /* TODO: build dcc list */ + } + + if (info) + return rb_str_new2 (info); + else + return rb_str_new2 (""); + } + + return INT2FIX (1); +} + +/* + * Ruby subroutines + */ + +/* + * wee_ruby_init: initialize Ruby interface for WeeChat + */ + +void +wee_ruby_init () +{ + + /* TODO: init Ruby environment */ + /* ruby_init (); + if () + { + irc_display_prefix (NULL, PREFIX_PLUGIN); + gui_printf (NULL, _("%s error: error while launching interpreter\n"), + "Ruby"); + } + else + { + wee_log_printf (_("Loading %s module \"weechat\"\n"), "Ruby"); + }*/ +} + +/* + * wee_ruby_search: search a (loaded) Ruby script by name + */ + +t_plugin_script * +wee_ruby_search (char *name) +{ + t_plugin_script *ptr_ruby_script; + + for (ptr_ruby_script = ruby_scripts; ptr_ruby_script; + ptr_ruby_script = ptr_ruby_script->next_script) + { + if (strcmp (ptr_ruby_script->name, name) == 0) + return ptr_ruby_script; + } + + /* script not found */ + return NULL; +} + +/* + * wee_ruby_exec: execute a Ruby script + */ + +int +wee_ruby_exec (char *function, char *server, char *arguments) +{ + /* TODO: exec Ruby script */ +} + +/* + * wee_ruby_load: load a Ruby script + */ + +int +wee_ruby_load (char *filename) +{ + FILE *fp; + + /* TODO: load & exec Ruby script */ + gui_printf (NULL, "Ruby scripts not developed!\n"); + /* execute Ruby script */ + /*wee_log_printf (_("Loading %s script \"%s\"\n"), "Ruby", filename); + irc_display_prefix (NULL, PREFIX_PLUGIN); + gui_printf (NULL, _("Loading %s script \"%s\"\n"), "Ruby", filename); + + if ((fp = fopen (filename, "r")) == NULL) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: error while opening file \"%s\"\n"), + "Ruby", filename); + return 1; + } + + if (xxxxxxx (fp, filename) != 0) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s error: error while parsing file \"%s\"\n"), + "Ruby", filename); + return 1; + } + + fclose (fp); + return 0;*/ +} + +/* + * wee_ruby_script_free: free a Ruby script + */ + +void +wee_ruby_script_free (t_plugin_script *ptr_ruby_script) +{ + t_plugin_script *new_ruby_scripts; + + /* remove script from list */ + if (last_ruby_script == ptr_ruby_script) + last_ruby_script = ptr_ruby_script->prev_script; + if (ptr_ruby_script->prev_script) + { + (ptr_ruby_script->prev_script)->next_script = ptr_ruby_script->next_script; + new_ruby_scripts = ruby_scripts; + } + else + new_ruby_scripts = ptr_ruby_script->next_script; + + if (ptr_ruby_script->next_script) + (ptr_ruby_script->next_script)->prev_script = ptr_ruby_script->prev_script; + + /* free data */ + if (ptr_ruby_script->name) + free (ptr_ruby_script->name); + if (ptr_ruby_script->version) + free (ptr_ruby_script->version); + if (ptr_ruby_script->shutdown_func) + free (ptr_ruby_script->shutdown_func); + if (ptr_ruby_script->description) + free (ptr_ruby_script->description); + free (ptr_ruby_script); + ruby_scripts = new_ruby_scripts; +} + +/* + * wee_ruby_unload: unload a Ruby script + */ + +void +wee_ruby_unload (t_plugin_script *ptr_ruby_script) +{ + if (ptr_ruby_script) + { + wee_log_printf (_("Unloading %s script \"%s\"\n"), + "Ruby", ptr_ruby_script->name); + + /* call shutdown callback function */ + if (ptr_ruby_script->shutdown_func[0]) + wee_ruby_exec (ptr_ruby_script->shutdown_func, "", ""); + wee_ruby_script_free (ptr_ruby_script); + } +} + +/* + * wee_ruby_unload_all: unload all Ruby scripts + */ + +void +wee_ruby_unload_all () +{ + wee_log_printf (_("Unloading all %s scripts...\n"), "Ruby"); + while (ruby_scripts) + wee_ruby_unload (ruby_scripts); + + irc_display_prefix (NULL, PREFIX_PLUGIN); + gui_printf (NULL, _("%s scripts unloaded\n"), "Ruby"); +} + +/* + * wee_ruby_end: shutdown Ruby interface + */ + +void +wee_ruby_end () +{ + /* unload all scripts */ + wee_ruby_unload_all (); + + /* free all handlers */ + plugin_handler_free_all_type (&plugin_msg_handlers, + &last_plugin_msg_handler, + PLUGIN_TYPE_RUBY); + plugin_handler_free_all_type (&plugin_cmd_handlers, + &last_plugin_cmd_handler, + PLUGIN_TYPE_RUBY); + + /* TODO: free Ruby interpreter */ + /* free Ruby interpreter */ + /* xxxxx (); + if () + { + irc_display_prefix (NULL, PREFIX_PLUGIN); + gui_printf (NULL, _("%s error: error while freeing interpreter\n"), + "Ruby"); + }*/ +} diff --git a/src/plugins/scripts/weechat-script.c b/src/plugins/scripts/weechat-script.c new file mode 100644 index 000000000..ae2555184 --- /dev/null +++ b/src/plugins/scripts/weechat-script.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2003-2005 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* scripts.c: script interface for WeeChat plugins */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> + +#include "../weechat-plugin.h" +#include "weechat-script.h" + + +/* + * weechat_script_auto_load: auto-load all scripts in a directory + */ + +void +weechat_script_auto_load (t_weechat_plugin *plugin, char *language, + int (*callback)(t_weechat_plugin *, char *)) +{ + char *dir_home, *dir_name; + int dir_length; + + /* build directory, adding WeeChat home */ + dir_home = plugin->get_info (plugin, "weechat_dir", NULL, NULL); + if (!dir_home) + return; + dir_length = strlen (dir_home) + strlen (language) + 16; + dir_name = + (char *) malloc (dir_length * sizeof (char)); + if (!dir_name) + { + free (dir_home); + return; + } + snprintf (dir_name, dir_length, "%s/%s/autoload", dir_home, language); + + plugin->exec_on_files (plugin, dir_name, callback); + + free (dir_name); + free (dir_home); +} + +/* + * weechat_script_search: search a script in list + */ + +t_plugin_script * +weechat_script_search (t_weechat_plugin *plugin, + t_plugin_script **list, char *name) +{ + t_plugin_script *ptr_script; + + for (ptr_script = *list; ptr_script; + ptr_script = ptr_script->next_script) + { + if (plugin->ascii_strcasecmp (plugin, ptr_script->name, name) == 0) + return ptr_script; + } + + /* script not found */ + return NULL; +} + +/* + * weechat_script_add: add a script to list of scripts + */ + +t_plugin_script * +weechat_script_add (t_weechat_plugin *plugin, + t_plugin_script **script_list, + char *filename, + char *name, char *version, + char *shutdown_func, char *description) +{ + t_plugin_script *new_script; + + /* make gcc happy */ + (void) plugin; + + new_script = (t_plugin_script *)malloc (sizeof (t_plugin_script)); + if (new_script) + { + new_script->filename = strdup (filename); + new_script->interpreter = NULL; + new_script->name = strdup (name); + new_script->version = strdup (version); + new_script->shutdown_func = strdup (shutdown_func); + new_script->description = strdup (description); + + /* add new script to list */ + if ((*script_list)) + (*script_list)->prev_script = new_script; + new_script->prev_script = NULL; + new_script->next_script = (*script_list); + (*script_list) = new_script; + return new_script; + } + + return NULL; +} + +/* + * weechat_script_remove: remove a script from list of scripts + */ + +void +weechat_script_remove (t_weechat_plugin *plugin, + t_plugin_script **script_list, t_plugin_script *script) +{ + t_plugin_msg_handler *ptr_msg_handler, *next_msg_handler; + t_plugin_cmd_handler *ptr_cmd_handler, *next_cmd_handler; + + /* make gcc happy */ + (void) plugin; + + /* remove message handlers */ + ptr_msg_handler = plugin->msg_handlers; + while (ptr_msg_handler) + { + if ((t_plugin_script *)ptr_msg_handler->msg_handler_pointer == script) + { + next_msg_handler = ptr_msg_handler->next_handler; + plugin->msg_handler_remove (plugin, ptr_msg_handler); + ptr_msg_handler = next_msg_handler; + } + else + ptr_msg_handler = ptr_msg_handler->next_handler; + } + + /* remove command handlers */ + ptr_cmd_handler = plugin->cmd_handlers; + while (ptr_cmd_handler) + { + if ((t_plugin_script *)ptr_cmd_handler->cmd_handler_pointer == script) + { + next_cmd_handler = ptr_cmd_handler->next_handler; + plugin->cmd_handler_remove (plugin, ptr_cmd_handler); + ptr_cmd_handler = next_cmd_handler; + } + else + ptr_cmd_handler = ptr_cmd_handler->next_handler; + } + + /* free data */ + if (script->filename) + free (script->filename); + if (script->name) + free (script->name); + if (script->description) + free (script->description); + if (script->version) + free (script->version); + if (script->shutdown_func) + free (script->shutdown_func); + + /* remove script from list */ + if (script->prev_script) + (script->prev_script)->next_script = script->next_script; + else + (*script_list) = script->next_script; + if (script->next_script) + (script->next_script)->prev_script = script->prev_script; + + /* free script */ + free (script); +} diff --git a/src/plugins/scripts/weechat-script.h b/src/plugins/scripts/weechat-script.h new file mode 100644 index 000000000..496a126e5 --- /dev/null +++ b/src/plugins/scripts/weechat-script.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2003-2005 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * This program 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 2 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* This header is designed to be distributed with WeeChat plugins, if scripts + management is needed */ + +#ifndef __WEECHAT_WEECHAT_SCRIPT_H +#define __WEECHAT_WEECHAT_SCRIPT_H 1 + +typedef struct t_plugin_script t_plugin_script; + +struct t_plugin_script +{ + /* script variables */ + char *filename; /* name of script on disk */ + void *interpreter; /* interpreter for script */ + char *name; /* script name */ + char *description; /* plugin description */ + char *version; /* plugin version */ + char *shutdown_func; /* function when script is unloaded */ + + t_plugin_script *prev_script; /* link to previous script */ + t_plugin_script *next_script; /* link to next script */ +}; + +extern void weechat_script_auto_load (t_weechat_plugin *, char *, + int (*)(t_weechat_plugin *, char *)); +extern t_plugin_script *weechat_script_search (t_weechat_plugin *, + t_plugin_script **, char *); +extern t_plugin_script *weechat_script_add (t_weechat_plugin *, + t_plugin_script **, char *, char *, + char *, char *, char *); +extern void weechat_script_remove (t_weechat_plugin *, + t_plugin_script **, t_plugin_script *); + +#endif /* weechat-script.h */ |