summaryrefslogtreecommitdiff
path: root/src/plugins/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/script')
-rw-r--r--src/plugins/script/CMakeLists.txt43
-rw-r--r--src/plugins/script/Makefile.am46
-rw-r--r--src/plugins/script/script-action.c710
-rw-r--r--src/plugins/script/script-action.h29
-rw-r--r--src/plugins/script/script-buffer.c797
-rw-r--r--src/plugins/script/script-buffer.h44
-rw-r--r--src/plugins/script/script-command.c270
-rw-r--r--src/plugins/script/script-command.h25
-rw-r--r--src/plugins/script/script-completion.c192
-rw-r--r--src/plugins/script/script-completion.h25
-rw-r--r--src/plugins/script/script-config.c587
-rw-r--r--src/plugins/script/script-config.h71
-rw-r--r--src/plugins/script/script-info.c110
-rw-r--r--src/plugins/script/script-info.h25
-rw-r--r--src/plugins/script/script-repo.c1369
-rw-r--r--src/plugins/script/script-repo.h83
-rw-r--r--src/plugins/script/script.c292
-rw-r--r--src/plugins/script/script.h37
18 files changed, 4755 insertions, 0 deletions
diff --git a/src/plugins/script/CMakeLists.txt b/src/plugins/script/CMakeLists.txt
new file mode 100644
index 000000000..e1d8b5570
--- /dev/null
+++ b/src/plugins/script/CMakeLists.txt
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2003-2012 Sebastien 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(script MODULE
+script.c script.h
+script-action.c script-action.h
+script-buffer.c script-buffer.h
+script-command.c script-command.h
+script-completion.c script-completion.h
+script-config.c script-config.h
+script-info.c script-info.h
+script-repo.c script-repo.h)
+SET_TARGET_PROPERTIES(script PROPERTIES PREFIX "")
+
+SET (LINK_LIBS)
+
+IF(ZLIB_FOUND)
+ LIST(APPEND LINK_LIBS ${ZLIB_LIBRARY})
+ENDIF(ZLIB_FOUND)
+
+IF(GCRYPT_FOUND)
+ LIST(APPEND LINK_LIBS gcrypt)
+ENDIF(GCRYPT_FOUND)
+
+TARGET_LINK_LIBRARIES(script ${LINK_LIBS})
+
+INSTALL(TARGETS script LIBRARY DESTINATION ${LIBDIR}/plugins)
diff --git a/src/plugins/script/Makefile.am b/src/plugins/script/Makefile.am
new file mode 100644
index 000000000..0f07f3dfe
--- /dev/null
+++ b/src/plugins/script/Makefile.am
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2003-2012 Sebastien 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/>.
+#
+
+INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\" $(ZLIB_CFLAGS) $(GCRYPT_CFLAGS)
+
+libdir = ${weechat_libdir}/plugins
+
+lib_LTLIBRARIES = script.la
+
+script_la_SOURCES = script.c \
+ script.h \
+ script-action.c \
+ script-action.h \
+ script-buffer.c \
+ script-buffer.h \
+ script-command.c \
+ script-command.h \
+ script-completion.c \
+ script-completion.h \
+ script-config.c \
+ script-config.h \
+ script-info.c \
+ script-info.h \
+ script-repo.c \
+ script-repo.h
+
+script_la_LDFLAGS = -module
+script_la_LIBADD = $(SCRIPT_LFLAGS) $(ZLIB_LFLAGS) $(GCRYPT_LFLAGS)
+
+EXTRA_DIST = CMakeLists.txt
diff --git a/src/plugins/script/script-action.c b/src/plugins/script/script-action.c
new file mode 100644
index 000000000..aabb8e504
--- /dev/null
+++ b/src/plugins/script/script-action.c
@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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/>.
+ */
+
+/*
+ * script-action.c: actions on scripts (load/unload, install/remove, hold, ...)
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <libgen.h>
+
+#include "../weechat-plugin.h"
+#include "script.h"
+#include "script-action.h"
+#include "script-buffer.h"
+#include "script-config.h"
+#include "script-repo.h"
+
+
+char *script_actions = NULL;
+
+
+void script_action_install ();
+
+
+/*
+ * script_action_list: list loaded scripts (all languages)
+ */
+
+void
+script_action_list ()
+{
+ int i, scripts_loaded;
+ char hdata_name[128];
+ const char *ptr_name;
+ struct t_hdata *hdata;
+ void *ptr_script;
+
+ weechat_printf (NULL, "");
+ weechat_printf (NULL, _("Scripts loaded:"));
+
+ scripts_loaded = 0;
+
+ for (i = 0; script_language[i]; i++)
+ {
+ snprintf (hdata_name, sizeof (hdata_name),
+ "%s_script", script_language[i]);
+ hdata = weechat_hdata_get (hdata_name);
+ ptr_script = weechat_hdata_get_list (hdata, "scripts");
+ while (ptr_script)
+ {
+ ptr_name = weechat_hdata_string (hdata, ptr_script, "name");
+ weechat_printf (NULL, " %s %s%s%s.%s %s%s %s(%s%s%s)",
+ script_repo_get_status_for_display (script_repo_search_by_name (ptr_name),
+ "*?HN", 0),
+ weechat_color (weechat_config_string (script_config_color_text_name)),
+ ptr_name,
+ weechat_color (weechat_config_string (script_config_color_text_extension)),
+ script_extension[i],
+ weechat_color (weechat_config_string (script_config_color_text_version)),
+ weechat_hdata_string (hdata, ptr_script, "version"),
+ weechat_color ("chat_delimiters"),
+ weechat_color (weechat_config_string (script_config_color_text_description)),
+ weechat_hdata_string (hdata, ptr_script, "description"),
+ weechat_color ("chat_delimiters"));
+ scripts_loaded++;
+ ptr_script = weechat_hdata_move (hdata, ptr_script, 1);
+ }
+ }
+
+ if (scripts_loaded == 0)
+ {
+ weechat_printf (NULL, _(" (none)"));
+ }
+}
+
+/*
+ * script_action_load: load a script
+ */
+
+void
+script_action_load (const char *name)
+{
+ char *pos, str_command[1024];
+ int language;
+
+ language = -1;
+ pos = strrchr (name, '.');
+ if (pos)
+ language = script_language_search_by_extension (pos + 1);
+ if (language < 0)
+ {
+ weechat_printf (NULL,
+ _("%s: unknown language for script \"%s\""),
+ SCRIPT_PLUGIN_NAME, name);
+ return;
+ }
+
+ /* execute command (for example: "/perl load iset.pl") */
+ snprintf (str_command, sizeof (str_command),
+ "/%s load %s",
+ script_language[language],
+ name);
+ weechat_command (NULL, str_command);
+}
+
+/*
+ * script_action_unload: unload a script
+ */
+
+void
+script_action_unload (const char *name)
+{
+ char *pos, hdata_name[128], *filename, *ptr_base_name, str_command[1024];
+ const char *ptr_filename, *ptr_registered_name;
+ int language, found, i;
+ struct t_hdata *hdata;
+ void *ptr_script;
+
+ language = -1;
+ pos = strrchr (name, '.');
+ if (pos)
+ {
+ /* unload script by using name + extension (example: "iset.pl") */
+ language = script_language_search_by_extension (pos + 1);
+ if (language < 0)
+ {
+ weechat_printf (NULL,
+ _("%s: unknown language for script \"%s\""),
+ SCRIPT_PLUGIN_NAME, name);
+ return;
+ }
+ /*
+ * search registered name of script using name with extension,
+ * for example with "iset.pl" we should find "iset"
+ */
+ snprintf (hdata_name, sizeof (hdata_name),
+ "%s_script", script_language[language]);
+ hdata = weechat_hdata_get (hdata_name);
+ ptr_script = weechat_hdata_get_list (hdata, "scripts");
+ while (ptr_script)
+ {
+ found = 0;
+ ptr_filename = weechat_hdata_string (hdata, ptr_script, "filename");
+ if (ptr_filename)
+ {
+ filename = strdup (ptr_filename);
+ if (filename)
+ {
+ ptr_base_name = basename (filename);
+ if (strcmp (ptr_base_name, name) == 0)
+ found = 1;
+ free (filename);
+ }
+ }
+ if (found)
+ {
+ ptr_registered_name = weechat_hdata_string (hdata, ptr_script,
+ "name");
+ if (ptr_registered_name)
+ {
+ snprintf (str_command, sizeof (str_command),
+ "/%s unload %s",
+ script_language[language],
+ ptr_registered_name);
+ weechat_command (NULL, str_command);
+ }
+ return;
+ }
+ ptr_script = weechat_hdata_move (hdata, ptr_script, 1);
+ }
+ }
+ else
+ {
+ /* unload script by using name (example: "iset") */
+ for (i = 0; script_language[i]; i++)
+ {
+ snprintf (hdata_name, sizeof (hdata_name),
+ "%s_script", script_language[i]);
+ hdata = weechat_hdata_get (hdata_name);
+ ptr_script = weechat_hdata_get_list (hdata, "scripts");
+ while (ptr_script)
+ {
+ ptr_registered_name = weechat_hdata_string (hdata, ptr_script,
+ "name");
+ if (strcmp (ptr_registered_name, name) == 0)
+ {
+ snprintf (str_command, sizeof (str_command),
+ "/%s unload %s",
+ script_language[i],
+ name);
+ weechat_command (NULL, str_command);
+ return;
+ }
+ ptr_script = weechat_hdata_move (hdata, ptr_script, 1);
+ }
+ }
+ }
+}
+
+/*
+ * script_action_installnext_timer_cb: callback called to install next script
+ */
+
+int
+script_action_installnext_timer_cb (void *data, int remaining_calls)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) remaining_calls;
+
+ script_action_install ();
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_action_install_process_cb: callback called when script is downloaded
+ */
+
+int
+script_action_install_process_cb (void *data, const char *command,
+ int return_code, const char *out,
+ const char *err)
+{
+ char *pos, *filename, str_signal[256];
+ struct t_repo_script *ptr_script;
+
+ /* make C compiler happy */
+ (void) data;
+
+ if (return_code >= 0)
+ {
+ pos = strrchr (command, '/');
+
+ if ((err && err[0]) || (out && (strncmp (out, "error:", 6) == 0)))
+ {
+ weechat_printf (NULL,
+ _("%s%s: error downloading script \"%s\": %s"),
+ weechat_prefix ("error"),
+ SCRIPT_PLUGIN_NAME,
+ (pos) ? pos + 1 : "?",
+ (err && err[0]) ? err : out + 6);
+ return WEECHAT_RC_OK;
+ }
+
+ if (pos)
+ {
+ ptr_script = script_repo_search_by_name_ext (pos + 1);
+ if (ptr_script)
+ {
+ filename = script_config_get_script_download_filename (ptr_script);
+ if (filename)
+ {
+ snprintf (str_signal, sizeof (str_signal),
+ "%s_script_install",
+ script_language[ptr_script->language]);
+ weechat_hook_signal_send (str_signal,
+ WEECHAT_HOOK_SIGNAL_STRING,
+ filename);
+ free (filename);
+ }
+
+ /* schedule install of next script */
+ weechat_hook_timer (10, 0, 1,
+ &script_action_installnext_timer_cb, NULL);
+ }
+ }
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_action_install: install script(s) marked for install
+ */
+
+void
+script_action_install ()
+{
+ struct t_repo_script *ptr_script, *ptr_script_to_install;
+ char *filename, *url;
+ int length;
+ struct t_hashtable *options;
+
+ ptr_script_to_install = NULL;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (ptr_script->install_order > 0)
+ {
+ if (ptr_script->install_order == 1)
+ ptr_script_to_install = ptr_script;
+ ptr_script->install_order--;
+ }
+ }
+
+ if (ptr_script_to_install)
+ {
+ filename = script_config_get_script_download_filename (ptr_script_to_install);
+ if (filename)
+ {
+ options = weechat_hashtable_new (8,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL,
+ NULL);
+ if (options)
+ {
+ length = 4 + strlen (ptr_script_to_install->url) + 1;
+ url = malloc (length);
+ if (url)
+ {
+ weechat_printf (NULL,
+ _("%s: downloading script \"%s\"..."),
+ SCRIPT_PLUGIN_NAME,
+ ptr_script_to_install->name_with_extension);
+
+ snprintf (url, length, "url:%s",
+ ptr_script_to_install->url);
+ weechat_hashtable_set (options, "file_out", filename);
+ weechat_hook_process_hashtable (url, options, 30000,
+ &script_action_install_process_cb,
+ NULL);
+ free (url);
+ }
+ weechat_hashtable_free (options);
+ }
+ free (filename);
+ }
+ }
+}
+
+/*
+ * script_action_remove: remove a script
+ */
+
+void
+script_action_remove (const char *name)
+{
+ struct t_repo_script *ptr_script;
+ char str_signal[256];
+
+ ptr_script = script_repo_search_by_name_ext (name);
+ if (ptr_script)
+ {
+ if (!(ptr_script->status & SCRIPT_STATUS_INSTALLED))
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" is not installed"),
+ SCRIPT_PLUGIN_NAME, name);
+ }
+ else if (ptr_script->status & SCRIPT_STATUS_HELD)
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" is held"),
+ SCRIPT_PLUGIN_NAME, name);
+ }
+ else
+ {
+ snprintf (str_signal, sizeof (str_signal),
+ "%s_script_remove",
+ script_language[ptr_script->language]);
+ weechat_hook_signal_send (str_signal,
+ WEECHAT_HOOK_SIGNAL_STRING,
+ ptr_script->name_with_extension);
+ }
+ }
+ else
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" not found"),
+ SCRIPT_PLUGIN_NAME, name);
+ }
+}
+
+/*
+ * script_action_hold: (un)hold a script
+ * return 1 if ok, 0 if error
+ */
+
+int
+script_action_hold (const char *name, int quiet)
+{
+ struct t_repo_script *ptr_script;
+
+ ptr_script = script_repo_search_by_name_ext (name);
+ if (ptr_script)
+ {
+ if (ptr_script->status & SCRIPT_STATUS_HELD)
+ {
+ script_config_unhold (ptr_script->name_with_extension);
+ if (!quiet)
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" not "
+ "held any more"),
+ SCRIPT_PLUGIN_NAME, name);
+ }
+ }
+ else
+ {
+ script_config_hold (ptr_script->name_with_extension);
+ if (!quiet)
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" held"),
+ SCRIPT_PLUGIN_NAME, name);
+ }
+ }
+ script_repo_update_status (ptr_script);
+ return 1;
+ }
+ else
+ {
+ if (!quiet)
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" not found"),
+ SCRIPT_PLUGIN_NAME, name);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * script_action_show: show detailed info on a script
+ */
+
+void
+script_action_show (const char *name, int quiet)
+{
+ struct t_repo_script *ptr_script;
+
+ if (name)
+ {
+ ptr_script = script_repo_search_by_name_ext (name);
+ if (ptr_script)
+ {
+ script_buffer_show_detail_script (ptr_script);
+ }
+ else
+ {
+ if (!quiet)
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" not found"),
+ SCRIPT_PLUGIN_NAME, name);
+ }
+ }
+ }
+ else
+ script_buffer_show_detail_script (NULL);
+}
+
+/*
+ * script_action_run: run planned actions
+ * return 1 if an action was executed, otherwise 0
+ */
+
+int
+script_action_run ()
+{
+ char **actions, **argv, **argv_eol, *ptr_action;
+ int num_actions, argc, i, j, quiet, script_found;
+ struct t_repo_script *ptr_script;
+
+ if (!script_actions)
+ return 0;
+
+ actions = weechat_string_split (script_actions, "\n", 0, 0, &num_actions);
+ if (actions)
+ {
+ for (i = 0; i < num_actions; i++)
+ {
+ quiet = 0;
+ ptr_action = actions[i];
+ if (ptr_action[0] == '-')
+ {
+ /*
+ * if action starts with options (like "-q"),
+ * read and skip them
+ */
+ ptr_action++;
+ while (ptr_action[0] && (ptr_action[0] != ' '))
+ {
+ switch (ptr_action[0])
+ {
+ case 'q': /* quiet */
+ quiet = 1;
+ break;
+ }
+ ptr_action++;
+ }
+ while (ptr_action[0] == ' ')
+ {
+ ptr_action++;
+ }
+ }
+ argv = weechat_string_split (ptr_action, " ", 0, 0, &argc);
+ argv_eol = weechat_string_split (ptr_action, " ", 1, 0, &argc);
+ if (argv && argv_eol)
+ {
+ if (weechat_strcasecmp (argv[0], "buffer") == 0)
+ {
+ /* open buffer with list of scripts */
+ if (!script_buffer)
+ {
+ script_buffer_open ();
+ script_buffer_refresh (1);
+ }
+ weechat_buffer_set (script_buffer, "display", "1");
+ }
+ else if (weechat_strcasecmp (argv[0], "list") == 0)
+ {
+ script_action_list ();
+ }
+ else if (weechat_strcasecmp (argv[0], "load") == 0)
+ {
+ for (j = 1; j < argc; j++)
+ {
+ script_action_load (argv[j]);
+ }
+ }
+ else if (weechat_strcasecmp (argv[0], "unload") == 0)
+ {
+ for (j = 1; j < argc; j++)
+ {
+ script_action_unload (argv[j]);
+ }
+ }
+ else if (weechat_strcasecmp (argv[0], "install") == 0)
+ {
+ script_found = 0;
+ for (j = 1; j < argc; j++)
+ {
+ ptr_script = script_repo_search_by_name_ext (argv[j]);
+ if (ptr_script)
+ {
+ if (ptr_script->status & SCRIPT_STATUS_HELD)
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" is held"),
+ SCRIPT_PLUGIN_NAME, argv[j]);
+ }
+ else if ((ptr_script->status & SCRIPT_STATUS_INSTALLED)
+ && !(ptr_script->status & SCRIPT_STATUS_NEW_VERSION))
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" is already "
+ "installed and up-to-date"),
+ SCRIPT_PLUGIN_NAME, argv[j]);
+ }
+ else
+ {
+ script_found++;
+ ptr_script->install_order = script_found;
+ }
+ }
+ else
+ {
+ weechat_printf (NULL,
+ _("%s: script \"%s\" not found"),
+ SCRIPT_PLUGIN_NAME, argv[j]);
+ }
+ }
+ if (script_found)
+ script_action_install ();
+ }
+ else if (weechat_strcasecmp (argv[0], "remove") == 0)
+ {
+ for (j = 1; j < argc; j++)
+ {
+ script_action_remove (argv[j]);
+ }
+ }
+ else if (weechat_strcasecmp (argv[0], "hold") == 0)
+ {
+ script_found = 0;
+ for (j = 1; j < argc; j++)
+ {
+ if (script_action_hold (argv[j], quiet))
+ script_found = 1;
+ }
+ if (script_found)
+ script_buffer_refresh (0);
+ }
+ else if (weechat_strcasecmp (argv[0], "show") == 0)
+ {
+ if (!script_buffer)
+ script_buffer_open ();
+ script_action_show ((argc >= 2) ? argv[1] : NULL,
+ quiet);
+ weechat_buffer_set (script_buffer, "display", "1");
+ }
+ else if (weechat_strcasecmp (argv[0], "upgrade") == 0)
+ {
+ script_found = 0;
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ /*
+ * if script is intalled, with new version available,
+ * and not held, then upgrade it
+ */
+ if ((ptr_script->status & SCRIPT_STATUS_INSTALLED)
+ && (ptr_script->status & SCRIPT_STATUS_NEW_VERSION)
+ && !(ptr_script->status & SCRIPT_STATUS_HELD))
+ {
+ script_found++;
+ ptr_script->install_order = script_found;
+ }
+ }
+ if (script_found)
+ script_action_install ();
+ else
+ {
+ weechat_printf (NULL,
+ _("%s: all scripts are up-to-date"),
+ SCRIPT_PLUGIN_NAME);
+ }
+ }
+ }
+ if (argv)
+ weechat_string_free_split (argv);
+ if (argv_eol)
+ weechat_string_free_split (argv_eol);
+ }
+ weechat_string_free_split (actions);
+ }
+
+ free (script_actions);
+ script_actions = NULL;
+
+ return 1;
+}
+
+
+/*
+ * script_action_add: add an action to list of actions
+ */
+
+void
+script_action_add (const char *action)
+{
+ char *new_actions;
+
+ if (!action)
+ return;
+
+ if (script_actions)
+ {
+ new_actions = realloc (script_actions,
+ strlen (script_actions) + 1 + strlen (action) + 1);
+ if (!new_actions)
+ return;
+ script_actions = new_actions;
+ strcat (script_actions, "\n");
+ strcat (script_actions, action);
+ }
+ else
+ {
+ script_actions = strdup (action);
+ }
+}
+
+/*
+ * script_action_schedule: schedule action
+ * if "need_repository" is 1, then the action will be
+ * executed only when the repository file is up-to-date
+ */
+
+void
+script_action_schedule (const char *action, int need_repository, int quiet)
+{
+ script_action_add (action);
+
+ if (need_repository)
+ {
+ if (script_repo_file_is_uptodate ())
+ {
+ if (!repo_scripts)
+ script_repo_file_read (quiet);
+ script_action_run ();
+ }
+ else
+ script_repo_file_update (quiet);
+ }
+ else
+ script_action_run ();
+}
diff --git a/src/plugins/script/script-action.h b/src/plugins/script/script-action.h
new file mode 100644
index 000000000..42af8c639
--- /dev/null
+++ b/src/plugins/script/script-action.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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_SCRIPT_ACTION_H
+#define __WEECHAT_SCRIPT_ACTION_H 1
+
+extern char *script_actions;
+
+extern int script_action_run ();
+extern void script_action_schedule (const char *action, int need_repository,
+ int quiet);
+
+#endif /* __WEECHAT_SCRIPT_ACTION_H */
diff --git a/src/plugins/script/script-buffer.c b/src/plugins/script/script-buffer.c
new file mode 100644
index 000000000..bf040010d
--- /dev/null
+++ b/src/plugins/script/script-buffer.c
@@ -0,0 +1,797 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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/>.
+ */
+
+/*
+ * script-buffer.c: display scripts on script buffer
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "../weechat-plugin.h"
+#include "script.h"
+#include "script-buffer.h"
+#include "script-config.h"
+#include "script-repo.h"
+
+
+struct t_gui_buffer *script_buffer = NULL;
+int script_buffer_selected_line = 0;
+struct t_repo_script *script_buffer_detail_script = NULL;
+
+
+/*
+ * script_buffer_display_line_script: display a line with script
+ */
+
+void
+script_buffer_display_line_script (int line, struct t_repo_script *script)
+{
+ char str_line[16384], str_item[1024], str_color_name[256], str_color[32];
+ char str_format[256], str_date[64], str_key[2], utf_char[16], *tags;
+ const char *columns, *ptr_col;
+ int char_size, *ptr_max_length, max_length, num_spaces, unknown;
+ struct tm *tm;
+
+ snprintf (str_color_name, sizeof (str_color_name),
+ "%s,%s",
+ (line == script_buffer_selected_line) ?
+ weechat_config_string (script_config_color_text_selected) :
+ weechat_config_string (script_config_color_text),
+ (line == script_buffer_selected_line) ?
+ weechat_config_string (script_config_color_text_bg_selected) :
+ weechat_config_string (script_config_color_text_bg));
+ snprintf (str_color, sizeof (str_color),
+ "%s", weechat_color (str_color_name));
+
+ columns = weechat_config_string (script_config_look_columns);
+ ptr_col = columns;
+
+ str_line[0] = '\0';
+ while (ptr_col[0])
+ {
+ unknown = 0;
+ str_item[0] = '\0';
+ num_spaces = 0;
+ char_size = weechat_utf8_char_size (ptr_col);
+ memcpy (utf_char, ptr_col, char_size);
+ utf_char[char_size] = '\0';
+ if (utf_char[0] == '%')
+ {
+ ptr_col += char_size;
+ char_size = weechat_utf8_char_size (ptr_col);
+ memcpy (utf_char, ptr_col, char_size);
+ utf_char[char_size] = '\0';
+
+ str_key[0] = ptr_col[0];
+ str_key[1] = '\0';
+ ptr_max_length = weechat_hashtable_get (script_repo_max_length_field,
+ str_key);
+ max_length = (ptr_max_length) ? *ptr_max_length : 0;
+ num_spaces = max_length;
+
+ switch (utf_char[0])
+ {
+ case 'a': /* author */
+ if (script->author)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->author);
+ snprintf (str_item, sizeof (str_item),
+ "%s", script->author);
+ }
+ break;
+ case 'd': /* description */
+ if (script->description)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->description);
+ snprintf (str_item, sizeof (str_item),
+ "%s%s",
+ weechat_color ((line == script_buffer_selected_line) ? "white" : "249"),
+ script->description);
+ }
+ break;
+ case 'D': /* date added */
+ if (script->date_added > 0)
+ {
+ tm = localtime (&script->date_added);
+ strftime (str_date, sizeof (str_date),
+ "%Y-%m-%d", tm);
+ snprintf (str_item, sizeof (str_item),
+ "%s%s",
+ weechat_color (
+ weechat_config_string (
+ (line == script_buffer_selected_line) ?
+ script_config_color_text_date_selected :
+ script_config_color_text_date)),
+ str_date);
+ }
+ else
+ num_spaces = 10;
+ break;
+ case 'e': /* file extension */
+ if (script->language >= 0)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script_extension[script->language]);
+ snprintf (str_item, sizeof (str_item),
+ "%s%s",
+ weechat_color (
+ weechat_config_string (
+ (line == script_buffer_selected_line) ?
+ script_config_color_text_extension_selected :
+ script_config_color_text_extension)),
+ script_extension[script->language]);
+ }
+ break;
+ case 'l': /* language */
+ if (script->language >= 0)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script_language[script->language]);
+ snprintf (str_item, sizeof (str_item),
+ "%s", script_language[script->language]);
+ }
+ break;
+ case 'L': /* license */
+ if (script->license)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->license);
+ snprintf (str_item, sizeof (str_item),
+ "%s", script->license);
+ }
+ break;
+ case 'n': /* name + extension */
+ if (script->name_with_extension)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->name_with_extension);
+ snprintf (str_item, sizeof (str_item),
+ "%s%s%s.%s",
+ weechat_color (
+ weechat_config_string (
+ (line == script_buffer_selected_line) ?
+ script_config_color_text_name_selected :
+ script_config_color_text_name)),
+ script->name,
+ weechat_color (
+ weechat_config_string (
+ (line == script_buffer_selected_line) ?
+ script_config_color_text_extension_selected :
+ script_config_color_text_extension)),
+ script_extension[script->language]);
+ }
+ break;
+ case 'N': /* name (without extension) */
+ if (script->name)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->name);
+ snprintf (str_item, sizeof (str_item),
+ "%s%s",
+ weechat_color (
+ weechat_config_string (
+ (line == script_buffer_selected_line) ?
+ script_config_color_text_name_selected :
+ script_config_color_text_name)),
+ script->name);
+ }
+ break;
+ case 'r': /* requirements */
+ if (script->requirements)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->requirements);
+ snprintf (str_item, sizeof (str_item),
+ "%s", script->requirements);
+ }
+ break;
+ case 's': /* status */
+ snprintf (str_item, sizeof (str_item),
+ script_repo_get_status_for_display (script,
+ "*iHrN", 0));
+ break;
+ case 't': /* tags */
+ if (script->tags)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->tags);
+ tags = weechat_string_replace (script->tags, ",", " ");
+ if (tags)
+ {
+ snprintf (str_item, sizeof (str_item),
+ "%s%s",
+ weechat_color (
+ weechat_config_string (
+ (line == script_buffer_selected_line) ?
+ script_config_color_text_tags_selected :
+ script_config_color_text_tags)),
+ tags);
+ free (tags);
+ }
+ }
+ break;
+ case 'u': /* date updated */
+ if (script->date_updated > 0)
+ {
+ tm = localtime (&script->date_updated);
+ strftime (str_date, sizeof (str_date),
+ "%Y-%m-%d", tm);
+ snprintf (str_item, sizeof (str_item),
+ "%s%s",
+ weechat_color (
+ weechat_config_string (
+ (line == script_buffer_selected_line) ?
+ script_config_color_text_date_selected :
+ script_config_color_text_date)),
+ str_date);
+ }
+ else
+ num_spaces = 10;
+ break;
+ case 'v': /* version */
+ if (script->version)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->version);
+ snprintf (str_item, sizeof (str_item),
+ "%s%s",
+ weechat_color (
+ weechat_config_string (
+ (line == script_buffer_selected_line) ?
+ script_config_color_text_version_selected :
+ script_config_color_text_version)),
+ script->version);
+ }
+ break;
+ case 'V': /* version loaded */
+ if (script->version_loaded)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->version_loaded);
+ snprintf (str_item, sizeof (str_item),
+ "%s%s",
+ weechat_color (
+ weechat_config_string (
+ (line == script_buffer_selected_line) ?
+ script_config_color_text_version_loaded_selected :
+ script_config_color_text_version_loaded)),
+ script->version_loaded);
+ }
+ break;
+ case 'w': /* min_weechat */
+ if (script->min_weechat)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->min_weechat);
+ snprintf (str_item, sizeof (str_item),
+ "%s", script->min_weechat);
+ }
+ break;
+ case 'W': /* max_weechat */
+ if (script->max_weechat)
+ {
+ num_spaces = max_length - weechat_utf8_strlen_screen (script->max_weechat);
+ snprintf (str_item, sizeof (str_item),
+ "%s", script->max_weechat);
+ }
+ break;
+ case '%': /* "%%" will display a single "%" */
+ snprintf (str_item, sizeof (str_item),
+ "%s%%",
+ weechat_color (weechat_config_string (script_config_color_text_delimiters)));
+ break;
+ default:
+ unknown = 1;
+ break;
+ }
+ }
+ else
+ {
+ snprintf (str_item, sizeof (str_item),
+ "%s%s",
+ weechat_color (weechat_config_string (script_config_color_text_delimiters)),
+ utf_char);
+ }
+ if (!unknown)
+ {
+ if (str_item[0])
+ {
+ strcat (str_line, str_color);
+ strcat (str_line, str_item);
+ }
+ if (num_spaces > 0)
+ {
+ snprintf (str_format, sizeof (str_format),
+ "%%-%ds",
+ num_spaces);
+ snprintf (str_item, sizeof (str_item),
+ str_format, " ");
+ strcat (str_line, str_item);
+ }
+ }
+ ptr_col += char_size;
+ }
+
+ weechat_printf_y (script_buffer, line, "%s", str_line);
+}
+
+/*
+ * script_buffer_detail_label: get header of a line for detail of script
+ * The returned string is aligned on the right
+ */
+
+const char *
+script_buffer_detail_label (const char *text, int max_length)
+{
+ char str_format[16];
+ static char result[1024];
+ int num_spaces;
+
+ num_spaces = max_length - weechat_utf8_strlen_screen (text);
+ snprintf (str_format, sizeof (str_format),
+ "%%-%ds%%s", num_spaces);
+ snprintf (result, sizeof (result),
+ str_format,
+ (num_spaces > 0) ? " " : "",
+ text);
+
+ return result;
+}
+
+/*
+ * script_buffer_display_detail_script: display detail on a script
+ */
+
+void
+script_buffer_display_detail_script (struct t_repo_script *script)
+{
+ struct tm *tm;
+ char str_time[1024];
+ char *labels[] = { N_("Script"), N_("Version"), N_("Author"),
+ N_("License"), N_("Description"), N_("Tags"),
+ N_("Status"), N_("Date added"), N_("Date updated"),
+ N_("URL"), N_("MD5"), N_("Requires"), N_("Min WeeChat"),
+ N_("Max WeeChat"), NULL };
+ int i, length, max_length, line;
+
+ max_length = 0;
+ for (i = 0; labels[i]; i++)
+ {
+ length = weechat_utf8_strlen_screen (_(labels[i]));
+ if (length > max_length)
+ max_length = length;
+ }
+
+ line = 0;
+
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s%s%s.%s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ weechat_color (weechat_config_string (script_config_color_text_name)),
+ script->name,
+ weechat_color (weechat_config_string (script_config_color_text_extension)),
+ script_extension[script->language]);
+ line++;
+ weechat_printf_y (script_buffer, line + 1, "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ script->version);
+ line++;
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s <%s>",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ script->author,
+ script->mail);
+ line++;
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ script->license);
+ line++;
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ script->description);
+ line++;
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ script->tags);
+ line++;
+ if ((script->popularity == 0) && (script->status == 0))
+ {
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: -",
+ script_buffer_detail_label (_(labels[line]), max_length));
+ }
+ else
+ {
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s%s (%s%s%s%s%s%s%s%s%s%s )",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ script_repo_get_status_for_display (script, "*iHrN", 1),
+ weechat_color ("chat"),
+ (script->popularity > 0) ? " " : "",
+ (script->popularity > 0) ? _("popular") : "",
+ (script->status & SCRIPT_STATUS_INSTALLED) ? " " : "",
+ (script->status & SCRIPT_STATUS_INSTALLED) ? _("installed") : "",
+ (script->status & SCRIPT_STATUS_HELD) ? " " : "",
+ (script->status & SCRIPT_STATUS_HELD) ? _("held") : "",
+ (script->status & SCRIPT_STATUS_RUNNING) ? " " : "",
+ (script->status & SCRIPT_STATUS_RUNNING) ? _("running") : "",
+ (script->status & SCRIPT_STATUS_NEW_VERSION) ? " " : "",
+ (script->status & SCRIPT_STATUS_NEW_VERSION) ? _("obsolete") : "");
+ }
+ line++;
+ tm = localtime (&script->date_added);
+ strftime (str_time, sizeof (str_time), "%Y-%m-%d %H:%M:%S", tm);
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ str_time);
+ line++;
+ tm = localtime (&script->date_updated);
+ strftime (str_time, sizeof (str_time), "%Y-%m-%d %H:%M:%S", tm);
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ str_time);
+ line++;
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ script->url);
+ line++;
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ script->md5sum);
+ line++;
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ (script->requirements) ? script->requirements : "-");
+ line++;
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ (script->min_weechat) ? script->min_weechat : "-");
+ line++;
+ weechat_printf_y (script_buffer, line + 1,
+ "%s: %s",
+ script_buffer_detail_label (_(labels[line]), max_length),
+ (script->max_weechat) ? script->max_weechat : "-");
+}
+
+/*
+ * script_buffer_refresh: update list of scripts in script buffer
+ */
+
+void
+script_buffer_refresh (int clear)
+{
+ struct t_repo_script *ptr_script;
+ int line;
+ char str_title[1024];
+
+ if (!script_buffer)
+ return;
+
+ if (clear)
+ {
+ weechat_buffer_clear (script_buffer);
+ script_buffer_selected_line = (script_repo_count_displayed > 0) ? 0 : -1;
+ }
+
+ if (script_buffer_detail_script)
+ {
+ snprintf (str_title, sizeof (str_title),
+ _("alt+d=back to list"));
+ }
+ else
+ {
+ snprintf (str_title, sizeof (str_title),
+ _("%d/%d scripts (filter: %s) | Sort: %s | "
+ "alt+i=install r=remove l=load u=unload h=(un)hold "
+ "d=show detail | Input: 'q'=close 'r'=refresh 's:x,y'=sort "
+ "'words'=filter '*'=reset filter"),
+ script_repo_count_displayed,
+ script_repo_count,
+ (script_repo_filter) ? script_repo_filter : "*",
+ weechat_config_string (script_config_look_sort));
+ }
+ weechat_buffer_set (script_buffer, "title", str_title);
+
+ if (script_buffer_detail_script)
+ {
+ /* detail on a script */
+ script_buffer_display_detail_script (script_buffer_detail_script);
+ }
+ else
+ {
+ /* list of scripts */
+ line = 0;
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (ptr_script->displayed)
+ {
+ script_buffer_display_line_script (line, ptr_script);
+ line++;
+ }
+ }
+ }
+}
+
+/*
+ * script_buffer_set_current_line: set current selected line in script buffer
+ */
+
+void
+script_buffer_set_current_line (int line)
+{
+ int old_line;
+
+ old_line = script_buffer_selected_line;
+ script_buffer_selected_line = line;
+
+ script_buffer_display_line_script (old_line,
+ script_repo_search_displayed_by_number (old_line));
+ script_buffer_display_line_script (script_buffer_selected_line,
+ script_repo_search_displayed_by_number (script_buffer_selected_line));
+}
+
+/*
+ * script_buffer_show_detail_script: show detailed info on a script
+ */
+
+void
+script_buffer_show_detail_script (struct t_repo_script *script)
+{
+ if (!script_buffer)
+ return;
+
+ if (script_buffer_detail_script == script)
+ script_buffer_detail_script = NULL;
+ else
+ script_buffer_detail_script = script;
+
+ weechat_buffer_clear (script_buffer);
+ script_buffer_refresh (0);
+
+ if (!script_buffer_detail_script)
+ script_buffer_check_line_outside_window ();
+}
+
+/*
+ * script_buffer_get_window_info: get infos about window
+ */
+
+void
+script_buffer_get_window_info (struct t_gui_window *window,
+ int *start_line_y, int *chat_height)
+{
+ struct t_hdata *hdata_window, *hdata_window_scroll, *hdata_line;
+ struct t_hdata *hdata_line_data;
+ void *window_scroll, *start_line, *line_data;
+
+ hdata_window = weechat_hdata_get ("window");
+ hdata_window_scroll = weechat_hdata_get ("window_scroll");
+ hdata_line = weechat_hdata_get ("line");
+ hdata_line_data = weechat_hdata_get ("line_data");
+ *start_line_y = 0;
+ window_scroll = weechat_hdata_pointer (hdata_window, window, "scroll");
+ if (window_scroll)
+ {
+ start_line = weechat_hdata_pointer (hdata_window_scroll, window_scroll,
+ "start_line");
+ if (start_line)
+ {
+ line_data = weechat_hdata_pointer (hdata_line, start_line, "data");
+ if (line_data)
+ {
+ *start_line_y = weechat_hdata_integer (hdata_line_data,
+ line_data, "y");
+ }
+ }
+ }
+ *chat_height = weechat_hdata_integer (hdata_window, window,
+ "win_chat_height");
+}
+
+/*
+ * script_buffer_check_line_outside_window: check if current line is outside
+ * window
+ */
+
+void
+script_buffer_check_line_outside_window ()
+{
+ struct t_gui_window *window;
+ int start_line_y, chat_height;
+ char str_command[256];
+
+ window = weechat_window_search_with_buffer (script_buffer);
+ if (!window)
+ return;
+
+ script_buffer_get_window_info (window, &start_line_y, &chat_height);
+ if ((start_line_y > script_buffer_selected_line)
+ || (start_line_y <= script_buffer_selected_line - chat_height))
+ {
+ snprintf (str_command, sizeof (str_command),
+ "/window scroll -window %d %s%d",
+ weechat_window_get_integer (window, "number"),
+ (start_line_y > script_buffer_selected_line) ? "-" : "+",
+ (start_line_y > script_buffer_selected_line) ?
+ start_line_y - script_buffer_selected_line :
+ script_buffer_selected_line - start_line_y - chat_height + 1);
+ weechat_command (script_buffer, str_command);
+ }
+}
+
+/*
+ * script_buffer_window_scrolled_cb: called when signal "window_scrolled" is
+ * received
+ */
+
+int
+script_buffer_window_scrolled_cb (void *data, const char *signal,
+ const char *type_data,
+ void *signal_data)
+{
+ int start_line_y, chat_height, line;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) signal;
+ (void) type_data;
+
+ /* scrolled another window/buffer? then just ignore */
+ if (weechat_window_get_pointer (signal_data, "buffer") != script_buffer)
+ return WEECHAT_RC_OK;
+
+ /* ignore if detail of a script is displayed */
+ if (script_buffer_detail_script)
+ return WEECHAT_RC_OK;
+
+ script_buffer_get_window_info (signal_data, &start_line_y, &chat_height);
+
+ line = script_buffer_selected_line;
+ while (line < start_line_y)
+ {
+ line += chat_height;
+ }
+ while (line >= start_line_y + chat_height)
+ {
+ line -= chat_height;
+ }
+ if (line < start_line_y)
+ line = start_line_y;
+ if (line >= script_repo_count_displayed)
+ line = script_repo_count_displayed - 1;
+ script_buffer_set_current_line (line);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_buffer_input_cb: callback called when user send data to script list
+ * buffer
+ */
+
+int
+script_buffer_input_cb (void *data, struct t_gui_buffer *buffer,
+ const char *input_data)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) buffer;
+
+ if (strcmp (input_data, "q") == 0)
+ {
+ weechat_buffer_close (buffer);
+ return WEECHAT_RC_OK;
+ }
+
+ if (strncmp (input_data, "s:", 2) == 0)
+ {
+ if (input_data[2])
+ weechat_config_option_set (script_config_look_sort, input_data + 2, 1);
+ else
+ weechat_config_option_reset (script_config_look_sort, 1);
+ return WEECHAT_RC_OK;
+ }
+
+ if (strcmp (input_data, "r") == 0)
+ {
+ script_get_loaded_scripts ();
+ script_repo_remove_all ();
+ script_repo_file_read (1);
+ script_buffer_refresh (1);
+ return WEECHAT_RC_OK;
+ }
+
+ script_repo_filter_scripts (input_data);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_buffer_close_cb: callback called when script buffer is closed
+ */
+
+int
+script_buffer_close_cb (void *data, struct t_gui_buffer *buffer)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) buffer;
+
+ script_buffer = NULL;
+ script_buffer_selected_line = 0;
+ script_buffer_detail_script = NULL;
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_buffer_set_callbacks: restore buffers callbacks (input and close) for
+ * buffer created by script plugin
+ */
+
+void
+script_buffer_set_callbacks ()
+{
+ struct t_gui_buffer *ptr_buffer;
+
+ ptr_buffer = weechat_buffer_search (SCRIPT_PLUGIN_NAME, SCRIPT_BUFFER_NAME);
+ if (ptr_buffer)
+ {
+ script_buffer = ptr_buffer;
+ weechat_buffer_set_pointer (script_buffer, "close_callback", &script_buffer_close_cb);
+ weechat_buffer_set_pointer (script_buffer, "input_callback", &script_buffer_input_cb);
+ }
+}
+
+/*
+ * script_buffer_open: open script buffer (to display list of scripts)
+ */
+
+void
+script_buffer_open ()
+{
+ if (!script_buffer)
+ {
+ script_buffer = weechat_buffer_new (SCRIPT_BUFFER_NAME,
+ &script_buffer_input_cb, NULL,
+ &script_buffer_close_cb, NULL);
+
+ /* failed to create buffer ? then exit */
+ if (!script_buffer)
+ return;
+
+ weechat_buffer_set (script_buffer, "type", "free");
+ weechat_buffer_set (script_buffer, "title", _("Scripts"));
+ weechat_buffer_set (script_buffer, "key_bind_meta2-A", "/script up");
+ weechat_buffer_set (script_buffer, "key_bind_meta2-B", "/script down");
+ weechat_buffer_set (script_buffer, "key_bind_meta-l", "/script load");
+ weechat_buffer_set (script_buffer, "key_bind_meta-u", "/script unload");
+ weechat_buffer_set (script_buffer, "key_bind_meta-i", "/script install");
+ weechat_buffer_set (script_buffer, "key_bind_meta-r", "/script remove");
+ weechat_buffer_set (script_buffer, "key_bind_meta-h", "/script hold");
+ weechat_buffer_set (script_buffer, "key_bind_meta-d", "/script show");
+ weechat_buffer_set (script_buffer, "localvar_set_type", "script");
+
+ script_buffer_selected_line = 0;
+ script_buffer_detail_script = NULL;
+ }
+}
diff --git a/src/plugins/script/script-buffer.h b/src/plugins/script/script-buffer.h
new file mode 100644
index 000000000..a9a29d326
--- /dev/null
+++ b/src/plugins/script/script-buffer.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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_SCRIPT_BUFFER_H
+#define __WEECHAT_SCRIPT_BUFFER_H 1
+
+#define SCRIPT_BUFFER_NAME "scripts"
+
+struct t_repo_script;
+
+extern struct t_gui_buffer *script_buffer;
+extern int script_buffer_selected_line;
+extern struct t_repo_script *script_buffer_detail_script;
+
+extern void script_buffer_refresh (int clear);
+extern void script_buffer_set_current_line (int line);
+extern void script_buffer_show_detail_script (struct t_repo_script *script);
+extern void script_buffer_check_line_outside_window ();
+extern int script_buffer_window_scrolled_cb (void *data, const char *signal,
+ const char *type_data,
+ void *signal_data);
+extern int script_buffer_input_cb (void *data, struct t_gui_buffer *buffer,
+ const char *input_data);
+extern int script_buffer_close_cb (void *data, struct t_gui_buffer *buffer);
+extern void script_buffer_set_callbacks ();
+extern void script_buffer_open ();
+
+#endif /* __WEECHAT_SCRIPT_BUFFER_H */
diff --git a/src/plugins/script/script-command.c b/src/plugins/script/script-command.c
new file mode 100644
index 000000000..4ba65cb84
--- /dev/null
+++ b/src/plugins/script/script-command.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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/>.
+ */
+
+/*
+ * script-command.c: script commands
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "../weechat-plugin.h"
+#include "script.h"
+#include "script-command.h"
+#include "script-action.h"
+#include "script-buffer.h"
+#include "script-config.h"
+#include "script-repo.h"
+
+
+/*
+ * script_command_action: run action
+ */
+
+void
+script_command_action (struct t_gui_buffer *buffer, const char *action,
+ const char *action_with_args, int need_repository)
+{
+ struct t_repo_script *ptr_script;
+ char str_action[4096];
+
+ if (action_with_args)
+ {
+ /* action with arguments on command line */
+ script_action_schedule (action_with_args, need_repository, 0);
+ }
+ else if (script_buffer && (buffer == script_buffer))
+ {
+ /* action on current line of script buffer */
+ if ((weechat_strcasecmp (action, "show") == 0)
+ && script_buffer_detail_script)
+ {
+ /* if detail on script is displayed, back to list */
+ snprintf (str_action, sizeof (str_action),
+ "-q %s",
+ action);
+ script_action_schedule (str_action, need_repository, 1);
+ }
+ else
+ {
+ /* if list is displayed, execute action on script */
+ if (!script_buffer_detail_script)
+ {
+ ptr_script = script_repo_search_displayed_by_number (script_buffer_selected_line);
+ if (ptr_script)
+ {
+ snprintf (str_action, sizeof (str_action),
+ "-q %s %s",
+ action,
+ ptr_script->name_with_extension);
+ script_action_schedule (str_action, need_repository, 1);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * script_command_script: command to manage scripts
+ */
+
+int
+script_command_script (void *data, struct t_gui_buffer *buffer, int argc,
+ char **argv, char **argv_eol)
+{
+ char *error;
+ long value;
+ int line;
+
+ /* make C compiler happy */
+ (void) data;
+
+ if (argc == 1)
+ {
+ script_action_schedule ("buffer", 1, 0);
+ return WEECHAT_RC_OK;
+ }
+
+ if (weechat_strcasecmp (argv[1], "list") == 0)
+ {
+ script_action_schedule ("list", 1, 0);
+ return WEECHAT_RC_OK;
+ }
+
+ if ((weechat_strcasecmp (argv[1], "load") == 0)
+ || (weechat_strcasecmp (argv[1], "unload") == 0))
+ {
+ script_command_action (buffer,
+ argv[1],
+ (argc > 2) ? argv_eol[1] : NULL,
+ 0);
+ return WEECHAT_RC_OK;
+ }
+
+ if ((weechat_strcasecmp (argv[1], "install") == 0)
+ || (weechat_strcasecmp (argv[1], "remove") == 0)
+ || (weechat_strcasecmp (argv[1], "hold") == 0)
+ || (weechat_strcasecmp (argv[1], "show") == 0))
+ {
+ script_command_action (buffer,
+ argv[1],
+ (argc > 2) ? argv_eol[1] : NULL,
+ 1);
+ return WEECHAT_RC_OK;
+ }
+
+ if (weechat_strcasecmp (argv[1], "upgrade") == 0)
+ {
+ script_action_schedule ("upgrade", 1, 0);
+ return WEECHAT_RC_OK;
+ }
+
+ if (weechat_strcasecmp (argv[1], "update") == 0)
+ {
+ script_repo_file_update (0);
+ return WEECHAT_RC_OK;
+ }
+
+ if (!script_buffer)
+ script_buffer_open ();
+
+ if (script_buffer)
+ {
+ weechat_buffer_set (script_buffer, "display", "1");
+
+ if (argc > 1)
+ {
+ if (!script_buffer_detail_script
+ && (script_buffer_selected_line >= 0)
+ && (script_repo_count_displayed > 0))
+ {
+ if (strcmp (argv[1], "up") == 0)
+ {
+ value = 1;
+ if (argc > 2)
+ {
+ error = NULL;
+ value = strtol (argv[2], &error, 10);
+ if (!error || error[0])
+ value = 1;
+ }
+ line = script_buffer_selected_line - value;
+ if (line < 0)
+ line = 0;
+ if (line != script_buffer_selected_line)
+ {
+ script_buffer_set_current_line (line);
+ script_buffer_check_line_outside_window ();
+ }
+ return WEECHAT_RC_OK;
+ }
+ else if (strcmp (argv[1], "down") == 0)
+ {
+ value = 1;
+ if (argc > 2)
+ {
+ error = NULL;
+ value = strtol (argv[2], &error, 10);
+ if (!error || error[0])
+ value = 1;
+ }
+ line = script_buffer_selected_line + value;
+ if (line >= script_repo_count_displayed)
+ line = script_repo_count_displayed - 1;
+ if (line != script_buffer_selected_line)
+ {
+ script_buffer_set_current_line (line);
+ script_buffer_check_line_outside_window ();
+ }
+ return WEECHAT_RC_OK;
+ }
+ }
+ }
+ }
+
+ script_buffer_refresh (0);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * scrit_command_init: init script commands (create hooks)
+ */
+
+void
+script_command_init ()
+{
+ weechat_hook_command ("script",
+ N_("WeeChat scripts manager"),
+ N_("list || show <script>"
+ " || load|unload <script> [<script>...]"
+ " || install|remove|hold <script> [<script>...]"
+ " || upgrade || update"),
+ N_(" list: list loaded scripts (all languages)\n"
+ " show: show detailed info about a script\n"
+ " load: load script(s)\n"
+ " unload: unload script(s)\n"
+ " install: install/upgrade script(s)\n"
+ " remove: remove script(s)\n"
+ " hold: hold/unhold script(s) (a script held "
+ "will not be upgraded any more and cannot be "
+ "removed)\n"
+ " upgrade: upgrade all installed scripts which "
+ "are obsolete (new version available)\n"
+ " update: update local scripts cache\n\n"
+ "Without argument, this command opens a buffer "
+ "with list of scripts.\n\n"
+ "On script buffer, the possible status for each "
+ "script are:\n"
+ " * i H r N\n"
+ " | | | | |\n"
+ " | | | | obsolete (new version available)\n"
+ " | | | running (loaded)\n"
+ " | | held\n"
+ " | installed\n"
+ " popular script\n\n"
+ "Keys on script buffer:\n"
+ " alt+i install script\n"
+ " alt+r remove script\n"
+ " alt+l load script\n"
+ " alt+u unload script\n"
+ " alt+h (un)hold script\n\n"
+ "Input allowed on script buffer:\n"
+ " q close buffer\n"
+ " r refresh buffer\n"
+ " s:x,y sort buffer using keys x and y (see /help "
+ "script.look.sort)\n"
+ " s: reset sort (use default sort)\n"
+ " word(s) filter scripts: search word(s) in "
+ "scripts (description, tags, ...)\n"
+ " * remove filter"),
+ "list"
+ " || show %(script_scripts)"
+ " || load %(script_files)"
+ " || unload %(python_script)|%(perl_script)|"
+ "%(ruby_script)|%(tcl_script)|%(lua_script)|"
+ "%(guile_script)"
+ " || install %(script_scripts)|%*"
+ " || remove %(script_scripts_installed)|%*"
+ " || hold %(script_scripts)"
+ " || update"
+ " || upgrade",
+ &script_command_script, NULL);
+}
diff --git a/src/plugins/script/script-command.h b/src/plugins/script/script-command.h
new file mode 100644
index 000000000..0af7d2098
--- /dev/null
+++ b/src/plugins/script/script-command.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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_SCRIPT_COMMAND_H
+#define __WEECHAT_SCRIPT_COMMAND_H 1
+
+extern void script_command_init ();
+
+#endif /* __WEECHAT_SCRIPT_COMMAND_H */
diff --git a/src/plugins/script/script-completion.c b/src/plugins/script/script-completion.c
new file mode 100644
index 000000000..e9d6fbc99
--- /dev/null
+++ b/src/plugins/script/script-completion.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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/>.
+ */
+
+/*
+ * script-completion.c: completion for script commands
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libgen.h>
+
+#include "../weechat-plugin.h"
+#include "script.h"
+#include "script-repo.h"
+
+
+/*
+ * script_completion_scripts_cb: callback for completion with scripts in
+ * repository
+ */
+
+int
+script_completion_scripts_cb (void *data, const char *completion_item,
+ struct t_gui_buffer *buffer,
+ struct t_gui_completion *completion)
+{
+ struct t_repo_script *ptr_script;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) completion_item;
+ (void) buffer;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ weechat_hook_completion_list_add (completion,
+ ptr_script->name_with_extension,
+ 0, WEECHAT_LIST_POS_SORT);
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_completion_scripts_installed_cb: callback for completion with scripts
+ * installed
+ */
+
+int
+script_completion_scripts_installed_cb (void *data, const char *completion_item,
+ struct t_gui_buffer *buffer,
+ struct t_gui_completion *completion)
+{
+ struct t_repo_script *ptr_script;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) completion_item;
+ (void) buffer;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (ptr_script->status & SCRIPT_STATUS_INSTALLED)
+ {
+ weechat_hook_completion_list_add (completion,
+ ptr_script->name_with_extension,
+ 0, WEECHAT_LIST_POS_SORT);
+ }
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_completion_exec_file_cb: callback called for each file in script
+ * directories
+ */
+
+void
+script_completion_exec_file_cb (void *data, const char *filename)
+{
+ struct t_gui_completion *completion;
+ const char *extension;
+ char *pos, *filename2, *ptr_base_name;
+
+ completion = (struct t_gui_completion *)(((void **)data)[0]);
+ extension = (const char *)(((void **)data)[1]);
+
+ pos = strrchr (filename, '.');
+ if (!pos)
+ return;
+
+ /* ignore scripts that do not ends with expected extension */
+ if (strcmp (pos + 1, extension) != 0)
+ return;
+
+ filename2 = strdup (filename);
+ if (filename2)
+ {
+ ptr_base_name = basename (filename2);
+ weechat_hook_completion_list_add (completion,
+ ptr_base_name,
+ 0, WEECHAT_LIST_POS_SORT);
+ free (filename2);
+ }
+}
+
+/*
+ * script_completion_scripts_files_cb: callback for completion with files in
+ * script directories
+ */
+
+int
+script_completion_scripts_files_cb (void *data, const char *completion_item,
+ struct t_gui_buffer *buffer,
+ struct t_gui_completion *completion)
+{
+ const char *weechat_home;
+ char *directory;
+ int length, i;
+ void *pointers[2];
+
+ /* make C compiler happy */
+ (void) data;
+ (void) completion_item;
+ (void) buffer;
+
+ weechat_home = weechat_info_get ("weechat_dir", NULL);
+
+ length = strlen (weechat_home) + 128 + 1;
+ directory = malloc (length);
+ if (directory)
+ {
+ for (i = 0; script_language[i]; i++)
+ {
+ pointers[0] = completion;
+ pointers[1] = script_extension[i];
+
+ /* look for files in "~/.weechat/<language>/" */
+ snprintf (directory, length,
+ "%s/%s", weechat_home, script_language[i]);
+ weechat_exec_on_files (directory, 0,
+ pointers, &script_completion_exec_file_cb);
+
+ /* look for files in "~/.weechat/<language>/autoload/" */
+ snprintf (directory, length,
+ "%s/%s/autoload", weechat_home, script_language[i]);
+ weechat_exec_on_files (directory, 0,
+ pointers, &script_completion_exec_file_cb);
+ }
+ free (directory);
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_completion_init: init completion for script plugin
+ */
+
+void
+script_completion_init ()
+{
+ weechat_hook_completion ("script_scripts",
+ N_("list of scripts in repository"),
+ &script_completion_scripts_cb, NULL);
+ weechat_hook_completion ("script_scripts_installed",
+ N_("list of scripts installed (from repository)"),
+ &script_completion_scripts_installed_cb, NULL);
+ weechat_hook_completion ("script_files",
+ N_("files in script directories"),
+ &script_completion_scripts_files_cb, NULL);
+}
diff --git a/src/plugins/script/script-completion.h b/src/plugins/script/script-completion.h
new file mode 100644
index 000000000..a14e2a0ba
--- /dev/null
+++ b/src/plugins/script/script-completion.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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_SCRIPT_COMPLETION_H
+#define __WEECHAT_SCRIPT_COMPLETION_H 1
+
+extern void script_completion_init ();
+
+#endif /* __WEECHAT_SCRIPT_COMPLETION_H */
diff --git a/src/plugins/script/script-config.c b/src/plugins/script/script-config.c
new file mode 100644
index 000000000..0123b7c8c
--- /dev/null
+++ b/src/plugins/script/script-config.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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/>.
+ */
+
+/*
+ * script-config.c: script configuration options (file script.conf)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "../weechat-plugin.h"
+#include "script.h"
+#include "script-config.h"
+#include "script-buffer.h"
+#include "script-repo.h"
+
+
+struct t_config_file *script_config_file = NULL;
+struct t_config_section *script_config_section_look = NULL;
+struct t_config_section *script_config_section_color = NULL;
+struct t_config_section *script_config_section_scripts = NULL;
+
+/* script config, look section */
+
+struct t_config_option *script_config_look_columns;
+struct t_config_option *script_config_look_sort;
+
+/* script config, color section */
+
+struct t_config_option *script_config_color_status_popular;
+struct t_config_option *script_config_color_status_installed;
+struct t_config_option *script_config_color_status_held;
+struct t_config_option *script_config_color_status_running;
+struct t_config_option *script_config_color_status_obsolete;
+struct t_config_option *script_config_color_status_unknown;
+struct t_config_option *script_config_color_text;
+struct t_config_option *script_config_color_text_date;
+struct t_config_option *script_config_color_text_delimiters;
+struct t_config_option *script_config_color_text_description;
+struct t_config_option *script_config_color_text_extension;
+struct t_config_option *script_config_color_text_name;
+struct t_config_option *script_config_color_text_tags;
+struct t_config_option *script_config_color_text_version;
+struct t_config_option *script_config_color_text_version_loaded;
+struct t_config_option *script_config_color_text_bg;
+struct t_config_option *script_config_color_text_selected;
+struct t_config_option *script_config_color_text_date_selected;
+struct t_config_option *script_config_color_text_description_selected;
+struct t_config_option *script_config_color_text_extension_selected;
+struct t_config_option *script_config_color_text_name_selected;
+struct t_config_option *script_config_color_text_tags_selected;
+struct t_config_option *script_config_color_text_version_selected;
+struct t_config_option *script_config_color_text_version_loaded_selected;
+struct t_config_option *script_config_color_text_bg_selected;
+
+/* script config, scripts section */
+
+struct t_config_option *script_config_scripts_cache_expire;
+struct t_config_option *script_config_scripts_dir;
+struct t_config_option *script_config_scripts_hold;
+struct t_config_option *script_config_scripts_url;
+
+
+/*
+ * script_config_get_dir: get local directory for script
+ * Note: result must be freed after use
+ */
+
+char *
+script_config_get_dir ()
+{
+ const char *weechat_home;
+ char *path, *path2;
+
+ weechat_home = weechat_info_get ("weechat_dir", NULL);
+
+ path = weechat_string_expand_home (weechat_config_string (script_config_scripts_dir));
+ path2 = weechat_string_replace ((path) ?
+ path : weechat_config_string (script_config_scripts_dir),
+ "%h", weechat_home);
+
+ if (path && path2)
+ {
+ free (path);
+ path = NULL;
+ }
+
+ if (path2)
+ return path2;
+ if (path)
+ return path;
+ return strdup (weechat_config_string (script_config_scripts_dir));
+}
+
+/*
+ * script_config_get_xml_filename: get filename with scripts (by default
+ * "/home/xxx/.weechat/script/plugins.xml.gz")
+ * Note: result must be freed after use
+ */
+
+char *
+script_config_get_xml_filename ()
+{
+ char *path, *filename;
+ int length;
+
+ path = script_config_get_dir ();
+ length = strlen (path) + 64;
+ filename = malloc (length);
+ if (filename)
+ snprintf (filename, length, "%s/plugins.xml.gz", path);
+ free (path);
+ return filename;
+}
+
+/*
+ * script_config_get_script_download_filename: get filename for a script to
+ * download, for eample:
+ * "/home/xxx/.weechat/script/iset.pl"
+ * Note: result must be freed after
+ * use
+ */
+
+char *
+script_config_get_script_download_filename (struct t_repo_script *script)
+{
+ char *path, *filename;
+ int length;
+
+ path = script_config_get_dir ();
+ length = strlen (path) + 1 + strlen (script->name_with_extension) + 1;
+ filename = malloc (length);
+ if (filename)
+ snprintf (filename, length, "%s/%s", path, script->name_with_extension);
+ free (path);
+ return filename;
+}
+
+/*
+ * script_config_refresh_cb: callback called when user changes xfer option that
+ * needs a refresh of script list
+ */
+
+void
+script_config_refresh_cb (void *data, struct t_config_option *option)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) option;
+
+ if (script_buffer)
+ script_buffer_refresh (0);
+}
+
+/*
+ * script_config_change_sort_cb: callback called when default sort keys are
+ * changed
+ */
+
+void
+script_config_change_sort_cb (void *data, struct t_config_option *option)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) option;
+
+ if (repo_scripts)
+ {
+ script_repo_remove_all ();
+ script_repo_file_read (1);
+ script_buffer_refresh (1);
+ }
+}
+
+/*
+ * script_config_change_hold_cb: callback called when list of scripts to "hold"
+ * is changed
+ */
+
+void
+script_config_change_hold_cb (void *data, struct t_config_option *option)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) option;
+
+ script_repo_update_status_all ();
+ if (script_buffer)
+ script_buffer_refresh (0);
+}
+
+/*
+ * script_config_hold: hold a script
+ * Note: the option is changed, but the status "held"
+ * in script is NOT updated by this function
+ */
+
+void
+script_config_hold (const char *name_with_extension)
+{
+ char **items, *hold;
+ int num_items, i, length;
+
+ length = strlen (weechat_config_string (script_config_scripts_hold)) +
+ 1 + strlen (name_with_extension) + 1;
+ hold = malloc (length);
+ if (hold)
+ {
+ hold[0] = '\0';
+ items = weechat_string_split (weechat_config_string (script_config_scripts_hold),
+ ",", 0, 0, &num_items);
+ if (items)
+ {
+ for (i = 0; i < num_items; i++)
+ {
+ if (strcmp (items[i], name_with_extension) != 0)
+ {
+ if (hold[0])
+ strcat (hold, ",");
+ strcat (hold, items[i]);
+ }
+ }
+ weechat_string_free_split (items);
+ }
+ if (hold[0])
+ strcat (hold, ",");
+ strcat (hold, name_with_extension);
+
+ weechat_config_option_set (script_config_scripts_hold, hold, 0);
+
+ free (hold);
+ }
+}
+
+/*
+ * script_config_unhold: unhold a script
+ * Note: the option is changed, but the status "held"
+ * in script is NOT updated by this function
+ */
+
+void
+script_config_unhold (const char *name_with_extension)
+{
+ char **items, *hold;
+ int num_items, i, length;
+
+ length = strlen (weechat_config_string (script_config_scripts_hold)) + 1;
+ hold = malloc (length);
+ if (hold)
+ {
+ hold[0] = '\0';
+ items = weechat_string_split (weechat_config_string (script_config_scripts_hold),
+ ",", 0, 0, &num_items);
+ if (items)
+ {
+ for (i = 0; i < num_items; i++)
+ {
+ if (strcmp (items[i], name_with_extension) != 0)
+ {
+ if (hold[0])
+ strcat (hold, ",");
+ strcat (hold, items[i]);
+ }
+ }
+ weechat_string_free_split (items);
+ }
+
+ weechat_config_option_set (script_config_scripts_hold, hold, 0);
+
+ free (hold);
+ }
+}
+
+/*
+ * script_config_reaload: reload script configuration file
+ */
+
+int
+script_config_reload (void *data, struct t_config_file *config_file)
+{
+ /* make C compiler happy */
+ (void) data;
+
+ return weechat_config_reload (config_file);
+}
+
+/*
+ * script_config_init: init script configuration file
+ * return: 1 if ok, 0 if error
+ */
+
+int
+script_config_init ()
+{
+ struct t_config_section *ptr_section;
+
+ script_config_file = weechat_config_new (SCRIPT_CONFIG_NAME,
+ &script_config_reload, NULL);
+ if (!script_config_file)
+ return 0;
+
+ /* look */
+ ptr_section = weechat_config_new_section (script_config_file, "look",
+ 0, 0,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ if (!ptr_section)
+ {
+ weechat_config_free (script_config_file);
+ return 0;
+ }
+
+ script_config_look_columns = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "columns", "string",
+ N_("format of columns displayed in script buffer: following column "
+ "identifiers are replaced by their value: %a=author, %d=description, "
+ "%D=date added, %e=extension, %l=language, %L=license, %n=name with "
+ "extension, %N=name, %r=requirements, %s=status, %t=tags, "
+ "%u=date updated, %v=version, %V=version loaded, %w=min_weechat, "
+ "%W=max_weechat)"),
+ NULL, 0, 0, "%s %n %V %v %u | %d | %t", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_look_sort = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "sort", "string",
+ N_("default sort keys for scripts: comma-separated list of identifiers: "
+ "a=author, d=date added, e=extension, i=installed, l=language, "
+ "n=name, o=obsolete, p=popularity, r=running, u=date updated; char "
+ "\"-\" can be used before identifier to reverse order; example: "
+ "\"i,u\": installed scripts first, sorted by update date"),
+ NULL, 0, 0, "p,n", NULL, 0,
+ NULL, NULL, &script_config_change_sort_cb, NULL, NULL, NULL);
+
+ /* color */
+ ptr_section = weechat_config_new_section (script_config_file, "color",
+ 0, 0,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ if (!ptr_section)
+ {
+ weechat_config_free (script_config_file);
+ return 0;
+ }
+
+ script_config_color_status_popular = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "status_popular", "color",
+ N_("color for status \"popular\" (\"*\")"),
+ NULL, 0, 0, "yellow", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_status_installed = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "status_installed", "color",
+ N_("color for status \"installed\" (\"i\")"),
+ NULL, 0, 0, "lightcyan", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_status_held = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "status_held", "color",
+ N_("color for status \"held\" (\"H\")"),
+ NULL, 0, 0, "white", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_status_running = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "status_running", "color",
+ N_("color for status \"running\" (\"r\")"),
+ NULL, 0, 0, "lightgreen", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_status_obsolete = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "status_obsolete", "color",
+ N_("color for status \"obsolete\" (\"N\")"),
+ NULL, 0, 0, "lightmagenta", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_status_unknown = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "status_unknown", "color",
+ N_("color for status \"unknown\" (\"?\")"),
+ NULL, 0, 0, "lightred", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text", "color",
+ N_("text color in script buffer"),
+ NULL, 0, 0, "default", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_date = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_date", "color",
+ N_("text color of dates in script buffer"),
+ NULL, 0, 0, "default", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_delimiters = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_delimiters", "color",
+ N_("text color of delimiters in script buffer"),
+ NULL, 0, 0, "darkgray", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_description = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_description", "color",
+ N_("text color of description in script buffer"),
+ NULL, 0, 0, "default", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_extension = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_extension", "color",
+ N_("text color of extension in script buffer"),
+ NULL, 0, 0, "default", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_name = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_name", "color",
+ N_("text color of script name in script buffer"),
+ NULL, 0, 0, "cyan", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_tags = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_tags", "color",
+ N_("text color of tags in script buffer"),
+ NULL, 0, 0, "brown", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_version = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_version", "color",
+ N_("text color of version in script buffer"),
+ NULL, 0, 0, "magenta", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_version_loaded = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_version_loaded", "color",
+ N_("text color of version loaded in script buffer"),
+ NULL, 0, 0, "default", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_bg = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_bg", "color",
+ N_("background color in script buffer"),
+ NULL, 0, 0, "default", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_selected = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_selected", "color",
+ N_("text color for selected line in script buffer"),
+ NULL, 0, 0, "white", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_date_selected = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_date_selected", "color",
+ N_("text color of dates for selected line in script buffer"),
+ NULL, 0, 0, "white", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_description_selected = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_description_selected", "color",
+ N_("text color of description for selected line in script buffer"),
+ NULL, 0, 0, "white", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_extension_selected = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_extension_selected", "color",
+ N_("text color of extension for selected line in script buffer"),
+ NULL, 0, 0, "white", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_name_selected = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_name_selected", "color",
+ N_("text color of script name for selected line in script buffer"),
+ NULL, 0, 0, "lightcyan", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_tags_selected = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_tags_selected", "color",
+ N_("text color of tags for selected line in script buffer"),
+ NULL, 0, 0, "yellow", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_version_selected = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_version_selected", "color",
+ N_("text color of version for selected line in script buffer"),
+ NULL, 0, 0, "lightmagenta", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_version_loaded_selected = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_version_loaded_selected", "color",
+ N_("text color of version loaded for selected line in script buffer"),
+ NULL, 0, 0, "white", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+ script_config_color_text_bg_selected = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "text_bg_selected", "color",
+ N_("background color for selected line in script buffer"),
+ NULL, 0, 0, "red", NULL, 0,
+ NULL, NULL, &script_config_refresh_cb, NULL, NULL, NULL);
+
+ /* scripts */
+ ptr_section = weechat_config_new_section (script_config_file, "scripts",
+ 0, 0,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ if (!ptr_section)
+ {
+ weechat_config_free (script_config_file);
+ return 0;
+ }
+
+ script_config_scripts_cache_expire = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "cache_expire", "integer",
+ N_("local cache expiration time, in minutes (-1 = never expires, "
+ "0 = always expire)"),
+ NULL, -1, 525600, "60", NULL, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ script_config_scripts_dir = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "dir", "string",
+ N_("local cache directory for scripts"),
+ NULL, 0, 0, "%h/script", NULL, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+ script_config_scripts_hold = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "hold", "string",
+ N_("scripts to \"hold\": comma-separated list of scripts which will "
+ "never been upgraded and can not be removed, for example: "
+ "\"buffers.pl,iset.pl\""),
+ NULL, 0, 0, "", NULL, 0, NULL, NULL,
+ &script_config_change_hold_cb, NULL, NULL, NULL);
+ script_config_scripts_url = weechat_config_new_option (
+ script_config_file, ptr_section,
+ "url", "string",
+ N_("URL for file with list of scripts"),
+ NULL, 0, 0, "http://www.weechat.org/files/plugins.xml.gz", NULL, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL);
+
+ return 1;
+}
+
+/*
+ * script_config_read: read script configuration file
+ */
+
+int
+script_config_read ()
+{
+ return weechat_config_read (script_config_file);
+}
+
+/*
+ * script_config_write: write script configuration file
+ */
+
+int
+script_config_write ()
+{
+ return weechat_config_write (script_config_file);
+}
+
+/*
+ * script_config_free: free script configuration file
+ */
+
+void
+script_config_free ()
+{
+ weechat_config_free (script_config_file);
+}
diff --git a/src/plugins/script/script-config.h b/src/plugins/script/script-config.h
new file mode 100644
index 000000000..31ec84bb5
--- /dev/null
+++ b/src/plugins/script/script-config.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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_SCRIPT_CONFIG_H
+#define __WEECHAT_SCRIPT_CONFIG_H 1
+
+#define SCRIPT_CONFIG_NAME "script"
+
+struct t_repo_script;
+
+extern struct t_config_option *script_config_look_columns;
+extern struct t_config_option *script_config_look_sort;
+
+extern struct t_config_option *script_config_color_status_popular;
+extern struct t_config_option *script_config_color_status_installed;
+extern struct t_config_option *script_config_color_status_held;
+extern struct t_config_option *script_config_color_status_running;
+extern struct t_config_option *script_config_color_status_obsolete;
+extern struct t_config_option *script_config_color_status_unknown;
+extern struct t_config_option *script_config_color_text;
+extern struct t_config_option *script_config_color_text_date;
+extern struct t_config_option *script_config_color_text_delimiters;
+extern struct t_config_option *script_config_color_text_description;
+extern struct t_config_option *script_config_color_text_extension;
+extern struct t_config_option *script_config_color_text_name;
+extern struct t_config_option *script_config_color_text_tags;
+extern struct t_config_option *script_config_color_text_version;
+extern struct t_config_option *script_config_color_text_version_loaded;
+extern struct t_config_option *script_config_color_text_bg;
+extern struct t_config_option *script_config_color_text_selected;
+extern struct t_config_option *script_config_color_text_date_selected;
+extern struct t_config_option *script_config_color_text_description_selected;
+extern struct t_config_option *script_config_color_text_extension_selected;
+extern struct t_config_option *script_config_color_text_name_selected;
+extern struct t_config_option *script_config_color_text_tags_selected;
+extern struct t_config_option *script_config_color_text_version_selected;
+extern struct t_config_option *script_config_color_text_version_loaded_selected;
+extern struct t_config_option *script_config_color_text_bg_selected;
+
+extern struct t_config_option *script_config_scripts_cache_expire;
+extern struct t_config_option *script_config_scripts_dir;
+extern struct t_config_option *script_config_scripts_hold;
+extern struct t_config_option *script_config_scripts_url;
+
+extern char *script_config_get_dir ();
+extern char *script_config_get_xml_filename ();
+extern char *script_config_get_script_download_filename (struct t_repo_script *script);
+extern void script_config_hold (const char *name_with_extension);
+extern void script_config_unhold (const char *name_with_extension);
+extern int script_config_init ();
+extern int script_config_read ();
+extern int script_config_write ();
+extern void script_config_free ();
+
+#endif /* __WEECHAT_SCRIPT_CONFIG_H */
diff --git a/src/plugins/script/script-info.c b/src/plugins/script/script-info.c
new file mode 100644
index 000000000..c04959223
--- /dev/null
+++ b/src/plugins/script/script-info.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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/>.
+ */
+
+/*
+ * script-info.c: info, infolist and hdata hooks for script plugin
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "../weechat-plugin.h"
+#include "script.h"
+#include "script-repo.h"
+
+
+/*
+ * script_info_get_infolist_cb: callback called when script infolist is asked
+ */
+
+struct t_infolist *
+script_info_get_infolist_cb (void *data, const char *infolist_name,
+ void *pointer, const char *arguments)
+{
+ struct t_infolist *ptr_infolist;
+ struct t_repo_script *ptr_script;
+
+ /* make C compiler happy */
+ (void) data;
+
+ if (!infolist_name || !infolist_name[0])
+ return NULL;
+
+ if (weechat_strcasecmp (infolist_name, "script_script") == 0)
+ {
+ if (pointer && !script_repo_script_valid (pointer))
+ return NULL;
+
+ ptr_infolist = weechat_infolist_new ();
+ if (ptr_infolist)
+ {
+ if (pointer)
+ {
+ /* build list with only one script */
+ if (!script_repo_add_to_infolist (ptr_infolist, pointer))
+ {
+ weechat_infolist_free (ptr_infolist);
+ return NULL;
+ }
+ return ptr_infolist;
+ }
+ else
+ {
+ /* build list with all scripts matching arguments */
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (!arguments || !arguments[0]
+ || weechat_string_match (ptr_script->name_with_extension,
+ arguments, 0))
+ {
+ if (!script_repo_add_to_infolist (ptr_infolist, ptr_script))
+ {
+ weechat_infolist_free (ptr_infolist);
+ return NULL;
+ }
+ }
+ }
+ return ptr_infolist;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * script_info_init: initialize info, infolist and hdata hooks for script plugin
+ */
+
+void
+script_info_init ()
+{
+ /* infolist hooks */
+ weechat_hook_infolist ("script_script",
+ N_("list of scripts"),
+ N_("script pointer (optional)"),
+ N_("script name with extension (can start or end with \"*\" as wildcard) (optional)"),
+ &script_info_get_infolist_cb, NULL);
+
+ /* hdata hooks */
+ weechat_hook_hdata ("script_script", N_("scripts from repository"),
+ &script_repo_hdata_script_cb, NULL);
+}
diff --git a/src/plugins/script/script-info.h b/src/plugins/script/script-info.h
new file mode 100644
index 000000000..2e2811d90
--- /dev/null
+++ b/src/plugins/script/script-info.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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_SCRIPT_INFO_H
+#define __WEECHAT_SCRIPT_INFO_H 1
+
+extern void script_info_init ();
+
+#endif /* __WEECHAT_SCRIPT_INFO_H */
diff --git a/src/plugins/script/script-repo.c b/src/plugins/script/script-repo.c
new file mode 100644
index 000000000..12a326c6e
--- /dev/null
+++ b/src/plugins/script/script-repo.c
@@ -0,0 +1,1369 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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/>.
+ */
+
+/*
+ * script-repo.c: download and read repository file (plugins.xml.gz)
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <zlib.h>
+#include <gcrypt.h>
+
+#include "../weechat-plugin.h"
+#include "script.h"
+#include "script-repo.h"
+#include "script-action.h"
+#include "script-buffer.h"
+#include "script-config.h"
+
+
+struct t_repo_script *repo_scripts = NULL;
+struct t_repo_script *last_repo_script = NULL;
+int script_repo_count = 0;
+int script_repo_count_displayed = 0;
+struct t_hashtable *script_repo_max_length_field = NULL;
+char *script_repo_filter = NULL;
+
+
+/*
+ * script_repo_script_valid: check if a script pointer exists
+ * return 1 if script exists
+ * 0 if script is not found
+ */
+
+int
+script_repo_script_valid (struct t_repo_script *script)
+{
+ struct t_repo_script *ptr_script;
+
+ if (!script)
+ return 0;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (ptr_script == script)
+ return 1;
+ }
+
+ /* script not found */
+ return 0;
+}
+
+/*
+ * script_repo_search_displayed_by_number: search a script displayed by number
+ * (first script displayed is 0)
+ */
+
+struct t_repo_script *
+script_repo_search_displayed_by_number (int number)
+{
+ struct t_repo_script *ptr_script;
+ int i;
+
+ if (number < 0)
+ return NULL;
+
+ i = 0;
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (ptr_script->displayed)
+ {
+ if (i == number)
+ return ptr_script;
+ i++;
+ }
+ }
+
+ /* script not found */
+ return NULL;
+}
+
+/*
+ * script_repo_search_by_name: search a script by name
+ * (example: "iset")
+ */
+
+struct t_repo_script *
+script_repo_search_by_name (const char *name)
+{
+ struct t_repo_script *ptr_script;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (strcmp (ptr_script->name, name) == 0)
+ return ptr_script;
+ }
+
+ /* script not found */
+ return NULL;
+}
+
+/*
+ * script_repo_search_by_name_ext: search a script by name/extension
+ * (example: "iset.pl")
+ */
+
+struct t_repo_script *
+script_repo_search_by_name_ext (const char *name_with_extension)
+{
+ struct t_repo_script *ptr_script;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (strcmp (ptr_script->name_with_extension, name_with_extension) == 0)
+ return ptr_script;
+ }
+
+ /* script not found */
+ return NULL;
+}
+
+/*
+ * script_repo_get_status_for_display: get status for display
+ * list is the codes of status to display
+ * (exemple: "*iHrN" for all status)
+ */
+
+const char *
+script_repo_get_status_for_display (struct t_repo_script *script,
+ const char *list,
+ int collapse)
+{
+ static char str_status[128];
+ const char *ptr_list;
+ char str_space[2];
+
+ str_space[0] = (collapse) ? '\0' : ' ';
+ str_space[1] = '\0';
+
+ str_status[0] = '\0';
+
+ for (ptr_list = list; ptr_list[0]; ptr_list++)
+ {
+ switch (ptr_list[0])
+ {
+ case '*':
+ strcat (str_status, weechat_color (weechat_config_string (script_config_color_status_popular)));
+ strcat (str_status, (script && (script->popularity > 0)) ? "*" : str_space);
+ break;
+ case 'i':
+ strcat (str_status, weechat_color (weechat_config_string (script_config_color_status_installed)));
+ strcat (str_status, (script && (script->status & SCRIPT_STATUS_INSTALLED)) ? "i" : str_space);
+ break;
+ case '?':
+ strcat (str_status, weechat_color (weechat_config_string (script_config_color_status_unknown)));
+ strcat (str_status, (script) ? str_space : "?");
+ break;
+ case 'H':
+ strcat (str_status, weechat_color (weechat_config_string (script_config_color_status_held)));
+ strcat (str_status, (script && (script->status & SCRIPT_STATUS_HELD)) ? "H" : str_space);
+ break;
+ case 'r':
+ strcat (str_status, weechat_color (weechat_config_string (script_config_color_status_running)));
+ strcat (str_status, (script && (script->status & SCRIPT_STATUS_RUNNING)) ? "r" : str_space);
+ break;
+ case 'N':
+ strcat (str_status, weechat_color (weechat_config_string (script_config_color_status_obsolete)));
+ strcat (str_status, (script && (script->status & SCRIPT_STATUS_NEW_VERSION)) ? "N" : str_space);
+ break;
+ }
+ }
+
+ return str_status;
+}
+
+/*
+ * script_repo_alloc: allocate a script structure
+ */
+
+struct t_repo_script *
+script_repo_alloc ()
+{
+ struct t_repo_script *new_script;
+
+ new_script = malloc (sizeof (*new_script));
+ if (new_script)
+ {
+ new_script->name = NULL;
+ new_script->name_with_extension = NULL;
+ new_script->language = -1;
+ new_script->author = NULL;
+ new_script->mail = NULL;
+ new_script->version = NULL;
+ new_script->license = NULL;
+ new_script->description = NULL;
+ new_script->tags = NULL;
+ new_script->requirements = NULL;
+ new_script->min_weechat = NULL;
+ new_script->max_weechat = NULL;
+ new_script->md5sum = NULL;
+ new_script->url = NULL;
+ new_script->popularity = 0;
+ new_script->date_added = 0;
+ new_script->date_updated = 0;
+ new_script->status = 0;
+ new_script->version_loaded = NULL;
+ new_script->displayed = 1;
+ new_script->install_order = 0;
+ new_script->prev_script = NULL;
+ new_script->next_script = NULL;
+ }
+
+ return new_script;
+}
+
+/*
+ * script_repo_compare_scripts: compare two scripts using sort key(s)
+ * (from option script.look.sort)
+ */
+
+int
+script_repo_compare_scripts (struct t_repo_script *script1,
+ struct t_repo_script *script2)
+{
+ const char *ptr_sort;
+ int cmp, reverse;
+
+ reverse = 1;
+ ptr_sort = weechat_config_string (script_config_look_sort);
+ while (ptr_sort[0])
+ {
+ cmp = 0;
+ switch (ptr_sort[0])
+ {
+ case '-': /* reverse order */
+ reverse = -1;
+ break;
+ case 'a': /* author */
+ cmp = strcmp (script1->author, script2->author);
+ break;
+ case 'd': /* date added */
+ if (script1->date_added > script2->date_added)
+ cmp = -1;
+ else if (script1->date_added < script2->date_added)
+ cmp = 1;
+ break;
+ case 'e': /* extension */
+ cmp = strcmp (script_extension[script1->language],
+ script_extension[script2->language]);
+ break;
+ case 'i': /* status "installed" */
+ if ((script1->status & SCRIPT_STATUS_INSTALLED)
+ && !(script2->status & SCRIPT_STATUS_INSTALLED))
+ cmp = -1;
+ else if (!(script1->status & SCRIPT_STATUS_INSTALLED)
+ && (script2->status & SCRIPT_STATUS_INSTALLED))
+ cmp = 1;
+ break;
+ case 'l': /* language */
+ cmp = strcmp (script_language[script1->language],
+ script_language[script2->language]);
+ break;
+ case 'n': /* name */
+ cmp = strcmp (script1->name, script2->name);
+ break;
+ case 'o': /* status "new version" (script obsolete) */
+ if ((script1->status & SCRIPT_STATUS_NEW_VERSION)
+ && !(script2->status & SCRIPT_STATUS_NEW_VERSION))
+ cmp = -1;
+ else if (!(script1->status & SCRIPT_STATUS_NEW_VERSION)
+ && (script2->status & SCRIPT_STATUS_NEW_VERSION))
+ cmp = 1;
+ break;
+ case 'p': /* popularity */
+ if (script1->popularity > script2->popularity)
+ cmp = -1;
+ else if (script1->popularity < script2->popularity)
+ cmp = 1;
+ break;
+ case 'r': /* status "running" */
+ if ((script1->status & SCRIPT_STATUS_RUNNING)
+ && !(script2->status & SCRIPT_STATUS_RUNNING))
+ cmp = -1;
+ else if (!(script1->status & SCRIPT_STATUS_RUNNING)
+ && (script2->status & SCRIPT_STATUS_RUNNING))
+ cmp = 1;
+ break;
+ case 'u': /* date updated */
+ if (script1->date_updated > script2->date_updated)
+ cmp = -1;
+ else if (script1->date_updated < script2->date_updated)
+ cmp = 1;
+ break;
+ default:
+ reverse = 1;
+ break;
+ }
+ if (cmp != 0)
+ return cmp * reverse;
+ ptr_sort++;
+ }
+
+ return 0;
+}
+
+/*
+ * script_repo_find_pos: find position for script in list
+ */
+
+struct t_repo_script *
+script_repo_find_pos (struct t_repo_script *script)
+{
+ struct t_repo_script *ptr_script;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (script_repo_compare_scripts (ptr_script, script) > 0)
+ return ptr_script;
+ }
+
+ /* position not found, add to the end */
+ return NULL;
+}
+
+/*
+ * script_repo_set_max_length_field: set max length for a field in hashtable
+ * "script_repo_max_length_field"
+ */
+
+void
+script_repo_set_max_length_field (const char *field, int length)
+{
+ int *value;
+
+ value = weechat_hashtable_get (script_repo_max_length_field, field);
+ if (!value || (length > *value))
+ weechat_hashtable_set (script_repo_max_length_field, field, &length);
+}
+
+/*
+ * script_repo_add: add script to list of scripts
+ */
+
+void
+script_repo_add (struct t_repo_script *script)
+{
+ struct t_repo_script *ptr_script;
+
+ ptr_script = script_repo_find_pos (script);
+ if (ptr_script)
+ {
+ /* insert script before script found */
+ script->prev_script = ptr_script->prev_script;
+ script->next_script = ptr_script;
+ if (ptr_script->prev_script)
+ (ptr_script->prev_script)->next_script = script;
+ else
+ repo_scripts = script;
+ ptr_script->prev_script = script;
+ }
+ else
+ {
+ /* add script to the end */
+ script->prev_script = last_repo_script;
+ script->next_script = NULL;
+ if (repo_scripts)
+ last_repo_script->next_script = script;
+ else
+ repo_scripts = script;
+ last_repo_script = script;
+ }
+
+ /* set max length for fields */
+ if (script->name)
+ script_repo_set_max_length_field ("N", weechat_utf8_strlen_screen (script->name));
+ if (script->name_with_extension)
+ script_repo_set_max_length_field ("n", weechat_utf8_strlen_screen (script->name_with_extension));
+ if (script->language >= 0)
+ {
+ script_repo_set_max_length_field ("l", weechat_utf8_strlen_screen (script_language[script->language]));
+ script_repo_set_max_length_field ("e", weechat_utf8_strlen_screen (script_extension[script->language]));
+ }
+ if (script->author)
+ script_repo_set_max_length_field ("a", weechat_utf8_strlen_screen (script->author));
+ if (script->version)
+ script_repo_set_max_length_field ("v", weechat_utf8_strlen_screen (script->version));
+ if (script->version_loaded)
+ script_repo_set_max_length_field ("V", weechat_utf8_strlen_screen (script->version_loaded));
+ if (script->license)
+ script_repo_set_max_length_field ("L", weechat_utf8_strlen_screen (script->license));
+ if (script->description)
+ script_repo_set_max_length_field ("d", weechat_utf8_strlen_screen (script->description));
+ if (script->tags)
+ script_repo_set_max_length_field ("t", weechat_utf8_strlen_screen (script->tags));
+ if (script->requirements)
+ script_repo_set_max_length_field ("r", weechat_utf8_strlen_screen (script->requirements));
+ if (script->min_weechat)
+ script_repo_set_max_length_field ("w", weechat_utf8_strlen_screen (script->min_weechat));
+ if (script->max_weechat)
+ script_repo_set_max_length_field ("W", weechat_utf8_strlen_screen (script->max_weechat));
+
+ script_repo_count++;
+ if (script->displayed)
+ script_repo_count_displayed++;
+}
+
+/*
+ * script_repo_free: free data in script
+ */
+
+void
+script_repo_free (struct t_repo_script *script)
+{
+ if (script->name)
+ free (script->name);
+ if (script->name_with_extension)
+ free (script->name_with_extension);
+ if (script->author)
+ free (script->author);
+ if (script->mail)
+ free (script->mail);
+ if (script->version)
+ free (script->version);
+ if (script->license)
+ free (script->license);
+ if (script->description)
+ free (script->description);
+ if (script->tags)
+ free (script->tags);
+ if (script->requirements)
+ free (script->requirements);
+ if (script->min_weechat)
+ free (script->min_weechat);
+ if (script->max_weechat)
+ free (script->max_weechat);
+ if (script->md5sum)
+ free (script->md5sum);
+ if (script->url)
+ free (script->url);
+ if (script->version_loaded)
+ free (script->version_loaded);
+
+ free (script);
+ }
+
+/*
+ * script_repo_remove: remove a script from list
+ */
+
+void
+script_repo_remove (struct t_repo_script *script)
+{
+ struct t_repo_script *new_repo_scripts;
+
+ /* remove script from list */
+ if (last_repo_script == script)
+ last_repo_script = script->prev_script;
+ if (script->prev_script)
+ {
+ (script->prev_script)->next_script = script->next_script;
+ new_repo_scripts = repo_scripts;
+ }
+ else
+ new_repo_scripts = script->next_script;
+ if (script->next_script)
+ (script->next_script)->prev_script = script->prev_script;
+
+ /* free data */
+ if (script->displayed)
+ script_repo_count_displayed--;
+ script_repo_free (script);
+
+ repo_scripts = new_repo_scripts;
+
+ script_repo_count--;
+
+ if (script_buffer_selected_line >= script_repo_count_displayed)
+ {
+ script_buffer_selected_line = (script_repo_count_displayed == 0) ?
+ 0 : script_repo_count_displayed - 1;
+ }
+}
+
+/*
+ * script_repo_remove_all: remove all scripts from list
+ */
+
+void
+script_repo_remove_all ()
+{
+ while (repo_scripts)
+ {
+ script_repo_remove (repo_scripts);
+ }
+ if (script_repo_max_length_field)
+ {
+ weechat_hashtable_free (script_repo_max_length_field);
+ script_repo_max_length_field = NULL;
+ }
+}
+
+/*
+ * script_repo_script_is_held: return 1 if script is held, 0 otherwise
+ */
+
+int
+script_repo_script_is_held (struct t_repo_script *script)
+{
+ const char *hold;
+ char *pos;
+ int length;
+
+ hold = weechat_config_string (script_config_scripts_hold);
+ length = strlen (script->name_with_extension);
+ pos = strstr (hold, script->name_with_extension);
+ while (pos)
+ {
+ if (((pos == hold) || (*(pos - 1) == ','))
+ && ((pos[length] == ',') || !pos[length]))
+ {
+ /* script held */
+ return 1;
+ }
+ pos = strstr (pos + 1, script->name_with_extension);
+ }
+
+ /* script not held */
+ return 0;
+}
+
+/*
+ * script_repo_md5sum_file: return MD5 checksum for content of a file
+ * Note: result has to be free() after use
+ */
+
+char *
+script_repo_md5sum_file (const char *filename)
+{
+ struct stat st;
+ FILE *file;
+ char md5sum[512];
+ const char *hexa = "0123456789abcdef";
+ unsigned char *data, *result;
+ gcry_md_hd_t hd;
+ int mdlen, i;
+
+ md5sum[0] = '\0';
+
+ if (stat (filename, &st) == -1)
+ return NULL;
+
+ data = malloc (st.st_size);
+ if (!data)
+ return NULL;
+
+ file = fopen (filename, "r");
+ if ((int)fread (data, 1, st.st_size, file) < st.st_size)
+ {
+ free (data);
+ return NULL;
+ }
+ fclose (file);
+
+ gcry_md_open (&hd, GCRY_MD_MD5, 0);
+ mdlen = gcry_md_get_algo_dlen (GCRY_MD_MD5);
+ gcry_md_write (hd, data, st.st_size);
+ result = gcry_md_read (hd, GCRY_MD_MD5);
+ for (i = 0; i < mdlen; i++)
+ {
+ md5sum[i * 2] = hexa[(result[i] & 0xFF) / 16];
+ md5sum[(i * 2) + 1] = hexa[(result[i] & 0xFF) % 16];
+ }
+ md5sum[((mdlen - 1) * 2) + 2] = '\0';
+ gcry_md_close (hd);
+
+ free (data);
+
+ return strdup (md5sum);
+}
+
+/*
+ * script_repo_update_status: update status of a script, which are:
+ * - script installed?
+ * - script running?
+ * - new version available?
+ */
+
+void
+script_repo_update_status (struct t_repo_script *script)
+{
+ const char *weechat_home, *version;
+ char *filename, *md5sum;
+ struct stat st;
+ int length;
+ struct t_repo_script *ptr_script;
+
+ script->status = 0;
+ md5sum = NULL;
+
+ /* check if script is installed (file found on disk) */
+ weechat_home = weechat_info_get ("weechat_dir", NULL);
+ length = strlen (weechat_home) + strlen (script->name_with_extension) + 64;
+ filename = malloc (length);
+ if (filename)
+ {
+ snprintf (filename, length, "%s/%s/autoload/%s",
+ weechat_home,
+ script_language[script->language],
+ script->name_with_extension);
+ if (stat (filename, &st) == 0)
+ {
+ script->status |= SCRIPT_STATUS_INSTALLED;
+ md5sum = script_repo_md5sum_file (filename);
+ }
+ else
+ {
+ snprintf (filename, length, "%s/%s/%s",
+ weechat_home,
+ script_language[script->language],
+ script->name_with_extension);
+ if (stat (filename, &st) == 0)
+ {
+ script->status |= SCRIPT_STATUS_INSTALLED;
+ md5sum = script_repo_md5sum_file (filename);
+ }
+ }
+ free (filename);
+ }
+
+ /* check if script is held */
+ if (script_repo_script_is_held (script))
+ script->status |= SCRIPT_STATUS_HELD;
+
+ /* check if script is running (loaded) */
+ version = weechat_hashtable_get (script_loaded, script->name_with_extension);
+ if (version)
+ {
+ script->status |= SCRIPT_STATUS_RUNNING;
+ if (script->version_loaded)
+ free (script->version_loaded);
+ script->version_loaded = strdup (version);
+ }
+ else
+ {
+ if (script->version_loaded)
+ {
+ free (script->version_loaded);
+ script->version_loaded = NULL;
+ }
+ }
+
+ /* check if script has new version (script is obsolete) */
+ if (md5sum && script->md5sum && (strcmp (script->md5sum, md5sum) != 0))
+ script->status |= SCRIPT_STATUS_NEW_VERSION;
+
+ /* recompute max length for version loaded (for display) */
+ if (script_repo_max_length_field)
+ {
+ length = 0;
+ weechat_hashtable_set (script_repo_max_length_field, "V", &length);
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ if (ptr_script->version_loaded)
+ script_repo_set_max_length_field ("V", weechat_utf8_strlen_screen (ptr_script->version_loaded));
+ }
+ }
+
+ if (md5sum)
+ free (md5sum);
+}
+
+/*
+ * script_repo_update_status_all: update status of all scripts
+ */
+
+void
+script_repo_update_status_all ()
+{
+ struct t_repo_script *ptr_script;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ script_repo_update_status (ptr_script);
+ }
+}
+
+/*
+ * script_repo_file_exists: return 1 if repository file (plugins.xml.gz) exists
+ * otherwise 0
+ */
+
+int
+script_repo_file_exists ()
+{
+ char *filename;
+ int rc;
+ struct stat st;
+
+ filename = script_config_get_xml_filename();
+ if (!filename)
+ return 0;
+
+ rc = 0;
+ if (stat (filename, &st) == 0)
+ rc = 1;
+
+ free (filename);
+
+ return rc;
+}
+
+/*
+ * script_repo_file_is_uptodate: return 1 if repository file (plugins.xml.gz)
+ * is up-to-date (file exists and is not outdated)
+ * otherwise 0 (file has to be downloaded)
+ */
+
+int
+script_repo_file_is_uptodate ()
+{
+ char *filename;
+ struct stat st;
+ int cache_expire;
+ time_t current_time;
+
+ cache_expire = weechat_config_integer (script_config_scripts_cache_expire);
+
+ /* cache always expires? => NOT up-to-date */
+ if (cache_expire == 0)
+ return 0;
+
+ filename = script_config_get_xml_filename ();
+
+ /* filename not found? => NOT up-to-date */
+ if (!filename)
+ return 0;
+
+ /* file does not exist? => NOT up-to-date */
+ if (stat (filename, &st) == -1)
+ {
+ free (filename);
+ return 0;
+ }
+
+ /* cache never expires? => OK, up-to-date! */
+ if (cache_expire < 0)
+ {
+ free (filename);
+ return 1;
+ }
+
+ current_time = time (NULL);
+
+ /* cache has expired? => NOT up-to-date */
+ if (current_time > st.st_mtime + (cache_expire * 60))
+ {
+ free (filename);
+ return 0;
+ }
+
+ /* OK, up-to-date! */
+ free (filename);
+ return 1;
+}
+
+/*
+ * script_repo_file_read: read scripts in repository file (plugins.xml.gz)
+ * return 1 if ok, 0 if error
+ */
+
+int
+script_repo_file_read (int quiet)
+{
+ char *filename, *ptr_line, line[4096], *pos, *pos2, *pos3;
+ char *name, *value1, *value2, *value3, *value, *error;
+ const char *version;
+ gzFile file;
+ struct t_repo_script *script;
+ int version_number, version_ok, script_ok, length;
+ struct tm tm_script;
+
+ script_get_loaded_scripts ();
+
+ script_repo_remove_all ();
+
+ if (!script_repo_max_length_field)
+ {
+ script_repo_max_length_field = weechat_hashtable_new (16,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_INTEGER,
+ NULL,
+ NULL);
+ }
+ else
+ weechat_hashtable_remove_all (script_repo_max_length_field);
+
+ if (script_repo_filter)
+ {
+ free (script_repo_filter);
+ script_repo_filter = NULL;
+ }
+
+ version = weechat_info_get ("version", NULL);
+ version_number = weechat_util_version_number (version);
+
+ filename = script_config_get_xml_filename ();
+ if (!filename)
+ {
+ weechat_printf (NULL, _("%s%s: error reading list of scripts"),
+ weechat_prefix ("error"),
+ SCRIPT_PLUGIN_NAME);
+ return 0;
+ }
+
+ script = NULL;
+ file = gzopen (filename, "r");
+ free (filename);
+ if (!file)
+ {
+ weechat_printf (NULL, _("%s%s: error reading list of scripts"),
+ weechat_prefix ("error"),
+ SCRIPT_PLUGIN_NAME);
+ return 0;
+ }
+
+ while (!gzeof (file))
+ {
+ ptr_line = gzgets (file, line, sizeof (line) - 1);
+ if (ptr_line)
+ {
+ if (strstr (ptr_line, "<plugin id="))
+ {
+ script = script_repo_alloc ();
+ }
+ else if (strstr (ptr_line, "</plugin>"))
+ {
+ if (script)
+ {
+ script_ok = 0;
+ if (script->name && (script->language >= 0))
+ {
+ version_ok = 1;
+ if (script->min_weechat)
+ {
+ if (weechat_util_version_number (script->min_weechat) > version_number)
+ version_ok = 0;
+ }
+ if (version_ok && script->max_weechat)
+ {
+ if (weechat_util_version_number (script->max_weechat) < version_number)
+ version_ok = 0;
+ }
+ if (version_ok)
+ {
+ length = strlen (script->name) + 1 +
+ strlen (script_extension[script->language]) + 1;
+ script->name_with_extension = malloc (length);
+ if (script->name_with_extension)
+ {
+ snprintf (script->name_with_extension,
+ length,
+ "%s.%s",
+ script->name,
+ script_extension[script->language]);
+ }
+ script_repo_update_status (script);
+ script_repo_add (script);
+ script_ok = 1;
+ }
+ }
+ if (!script_ok)
+ {
+ script_repo_free (script);
+ }
+ script = NULL;
+ }
+ }
+ else if (script)
+ {
+ pos = strchr (ptr_line, '<');
+ if (pos)
+ {
+ pos2 = strchr (pos + 1, '>');
+ if (pos2 && (pos2 > pos + 1))
+ {
+ pos3 = strstr (pos2 + 1, "</");
+ if (pos3 && (pos3 > pos2 + 1))
+ {
+ name = weechat_strndup (pos + 1, pos2 - pos - 1);
+ value1 = weechat_strndup (pos2 + 1, pos3 - pos2 - 1);
+ value2 = weechat_string_replace (value1, "&amp;", "&");
+ value3 = weechat_string_replace (value2, "&gt;", ">");
+ value = weechat_string_replace (value3, "&lt;", "<");
+ if (name && value)
+ {
+ if (strcmp (name, "name") == 0)
+ script->name = strdup (value);
+ else if (strcmp (name, "language") == 0)
+ script->language = script_language_search (value);
+ else if (strcmp (name, "author") == 0)
+ script->author = strdup (value);
+ else if (strcmp (name, "mail") == 0)
+ script->mail = strdup (value);
+ else if (strcmp (name, "version") == 0)
+ script->version = strdup (value);
+ else if (strcmp (name, "license") == 0)
+ script->license = strdup (value);
+ else if (strcmp (name, "desc_en") == 0)
+ script->description = strdup (value);
+ else if (strcmp (name, "tags") == 0)
+ script->tags = strdup (value);
+ else if (strcmp (name, "requirements") == 0)
+ script->requirements = strdup (value);
+ else if (strcmp (name, "min_weechat") == 0)
+ script->min_weechat = strdup (value);
+ else if (strcmp (name, "max_weechat") == 0)
+ script->max_weechat = strdup (value);
+ else if (strcmp (name, "md5sum") == 0)
+ script->md5sum = strdup (value);
+ else if (strcmp (name, "url") == 0)
+ script->url = strdup (value);
+ else if (strcmp (name, "popularity") == 0)
+ {
+ error = NULL;
+ script->popularity = (int)strtol (value,
+ &error,
+ 10);
+ if (!error || error[0])
+ script->popularity = 0;
+ }
+ else if (strcmp (name, "added") == 0)
+ {
+ /*
+ * initialize structure, because strptime
+ * does not do it
+ */
+ memset (&tm_script, 0, sizeof (tm_script));
+ error = strptime (value,
+ "%Y-%m-%d %H:%M:%S",
+ &tm_script);
+ if (error && !error[0])
+ script->date_added = mktime (&tm_script);
+ }
+ else if (strcmp (name, "updated") == 0)
+ {
+ /*
+ * initialize structure, because strptime
+ * does not do it
+ */
+ memset (&tm_script, 0, sizeof (tm_script));
+ error = strptime (value,
+ "%Y-%m-%d %H:%M:%S",
+ &tm_script);
+ if (error && !error[0])
+ script->date_updated = mktime (&tm_script);
+ }
+ }
+ if (name)
+ free (name);
+ if (value1)
+ free (value1);
+ if (value2)
+ free (value2);
+ if (value3)
+ free (value3);
+ if (value)
+ free (value);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ gzclose (file);
+
+ if (repo_scripts && !quiet)
+ {
+ weechat_printf (NULL,
+ _("%s: %d scripts for WeeChat %s"),
+ SCRIPT_PLUGIN_NAME, script_repo_count,
+ weechat_info_get ("version", NULL));
+ }
+
+ if (!repo_scripts)
+ {
+ weechat_printf (NULL,
+ _("%s%s: list of scripts is empty (repository file "
+ "is broken, or download has failed)"),
+ weechat_prefix ("error"),
+ SCRIPT_PLUGIN_NAME);
+ }
+
+ return 1;
+}
+
+/*
+ * script_repo_file_update_process_cb: callback called when list of scripts is
+ * downloaded
+ */
+
+int
+script_repo_file_update_process_cb (void *data, const char *command,
+ int return_code, const char *out,
+ const char *err)
+{
+ int quiet;
+
+ /* make C compiler happy */
+ (void) command;
+
+ quiet = (data == 0) ? 0 : 1;
+
+ if (return_code >= 0)
+ {
+ if ((err && err[0]) || (out && (strncmp (out, "error:", 6) == 0)))
+ {
+ weechat_printf (NULL,
+ _("%s%s: error downloading list of scripts: %s"),
+ weechat_prefix ("error"),
+ SCRIPT_PLUGIN_NAME,
+ (err && err[0]) ? err : out + 6);
+ return WEECHAT_RC_OK;
+ }
+
+ if (script_repo_file_read (quiet) && repo_scripts)
+ {
+ if (!script_action_run ())
+ script_buffer_refresh (1);
+ }
+ else
+ script_buffer_refresh (1);
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_repo_file_update: update repository file, and read it
+ */
+
+void
+script_repo_file_update (int quiet)
+{
+ char *filename, *url;
+ int length;
+ struct t_hashtable *options;
+
+ script_repo_remove_all ();
+
+ filename = script_config_get_xml_filename ();
+ if (!filename)
+ return;
+
+ options = weechat_hashtable_new (8,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL,
+ NULL);
+ if (options)
+ {
+ length = 4 + strlen (weechat_config_string (script_config_scripts_url)) + 1;
+ url = malloc (length);
+ if (url)
+ {
+ if (!quiet)
+ {
+ weechat_printf (NULL,
+ _("%s: downloading list of scripts..."),
+ SCRIPT_PLUGIN_NAME);
+ }
+
+ snprintf (url, length, "url:%s",
+ weechat_config_string (script_config_scripts_url));
+ weechat_hashtable_set (options, "file_out", filename);
+ weechat_hook_process_hashtable (url, options, 30000,
+ &script_repo_file_update_process_cb,
+ (quiet) ? (void *)1 : (void *)0);
+ free (url);
+ }
+ weechat_hashtable_free (options);
+ }
+
+ free (filename);
+}
+
+/*
+ * script_repo_match_search: return 1 if script is matching search string,
+ * otherwise 0
+ */
+
+int
+script_repo_match_search (struct t_repo_script *script, const char *search)
+{
+ char **words, **tags;
+ int num_words, num_tags, has_tag, match, i, j;
+
+ if (strcmp (search, "*") == 0)
+ return 1;
+
+ words = weechat_string_split (search, " ", 0, 0, &num_words);
+ tags = weechat_string_split ((script->tags) ? script->tags : "", ",", 0, 0,
+ &num_tags);
+ if (words)
+ {
+ for (i = 0; i < num_words; i++)
+ {
+ has_tag = 0;
+ if (tags)
+ {
+ for (j = 0; j < num_tags; j++)
+ {
+ if (weechat_strcasecmp (tags[j], words[i]) == 0)
+ {
+ has_tag = 1;
+ break;
+ }
+ }
+ }
+ if (!has_tag)
+ {
+ match = 0;
+ if (script->name_with_extension
+ && weechat_strcasestr (script->name_with_extension, words[i]))
+ match = 1;
+
+ if (!match && script->description
+ && weechat_strcasestr (script->description, words[i]))
+ match = 1;
+
+ if (!match && script->license
+ && weechat_strcasestr (script->license, words[i]))
+ match = 1;
+
+ if (!match && script->author
+ && weechat_strcasestr (script->author, words[i]))
+ match = 1;
+
+ if (!match)
+ {
+ weechat_string_free_split (words);
+ weechat_string_free_split (tags);
+ return 0;
+ }
+ }
+ }
+ }
+
+ if (words)
+ weechat_string_free_split (words);
+ if (tags)
+ weechat_string_free_split (tags);
+
+ return 1;
+}
+
+/*
+ * script_repo_filter_scripts: filter scripts (search string in
+ * name/description/tags) and mark scripts found as
+ * "displayed" (0 in displayed for non-matching
+ * scripts)
+ */
+
+void
+script_repo_filter_scripts (const char *search)
+{
+ struct t_repo_script *ptr_script;
+
+ if (script_repo_filter)
+ free (script_repo_filter);
+ script_repo_filter = strdup (search);
+
+ script_repo_count_displayed = 0;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ ptr_script->displayed = (script_repo_match_search (ptr_script, search));
+ if (ptr_script->displayed)
+ script_repo_count_displayed++;
+ }
+
+ script_buffer_refresh (1);
+}
+
+/*
+ * script_repo_hdata_script_cb: return hdata for script
+ */
+
+struct t_hdata *
+script_repo_hdata_script_cb (void *data, const char *hdata_name)
+{
+ struct t_hdata *hdata;
+
+ /* make C compiler happy */
+ (void) data;
+
+ hdata = weechat_hdata_new (hdata_name, "prev_script", "next_script");
+ if (hdata)
+ {
+ WEECHAT_HDATA_VAR(struct t_repo_script, name, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, name_with_extension, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, language, INTEGER, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, author, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, mail, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, version, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, license, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, description, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, tags, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, requirements, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, min_weechat, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, max_weechat, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, md5sum, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, url, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, popularity, INTEGER, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, date_added, TIME, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, date_updated, TIME, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, status, INTEGER, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, version_loaded, STRING, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, displayed, INTEGER, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, install_order, INTEGER, NULL, NULL);
+ WEECHAT_HDATA_VAR(struct t_repo_script, prev_script, POINTER, NULL, hdata_name);
+ WEECHAT_HDATA_VAR(struct t_repo_script, next_script, POINTER, NULL, hdata_name);
+ WEECHAT_HDATA_LIST(repo_scripts);
+ WEECHAT_HDATA_LIST(last_repo_script);
+ }
+ return hdata;
+}
+
+/*
+ * script_repo_add_to_infolist: add a script in an infolist
+ * return 1 if ok, 0 if error
+ */
+
+int
+script_repo_add_to_infolist (struct t_infolist *infolist,
+ struct t_repo_script *script)
+{
+ struct t_infolist_item *ptr_item;
+
+ if (!infolist || !script)
+ return 0;
+
+ ptr_item = weechat_infolist_new_item (infolist);
+ if (!ptr_item)
+ return 0;
+
+ if (!weechat_infolist_new_var_string (ptr_item, "name", script->name))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "name_with_extension", script->name_with_extension))
+ return 0;
+ if (!weechat_infolist_new_var_integer (ptr_item, "language", script->language))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "author", script->author))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "mail", script->mail))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "version", script->version))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "license", script->license))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "description", script->description))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "tags", script->tags))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "requirements", script->requirements))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "min_weechat", script->min_weechat))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "max_weechat", script->max_weechat))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "md5sum", script->md5sum))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "url", script->url))
+ return 0;
+ if (!weechat_infolist_new_var_integer (ptr_item, "popularity", script->popularity))
+ return 0;
+ if (!weechat_infolist_new_var_time (ptr_item, "date_added", script->date_added))
+ return 0;
+ if (!weechat_infolist_new_var_time (ptr_item, "date_updated", script->date_updated))
+ return 0;
+ if (!weechat_infolist_new_var_integer (ptr_item, "status", script->status))
+ return 0;
+ if (!weechat_infolist_new_var_string (ptr_item, "version_loaded", script->version_loaded))
+ return 0;
+ if (!weechat_infolist_new_var_integer (ptr_item, "displayed", script->displayed))
+ return 0;
+ if (!weechat_infolist_new_var_integer (ptr_item, "install_order", script->install_order))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * script_repo_print_log: print script infos in log (usually for crash dump)
+ */
+
+void
+script_repo_print_log ()
+{
+ struct t_repo_script *ptr_script;
+
+ for (ptr_script = repo_scripts; ptr_script;
+ ptr_script = ptr_script->next_script)
+ {
+ weechat_log_printf ("");
+ weechat_log_printf ("[script (addr:0x%lx)]", ptr_script);
+ weechat_log_printf (" name. . . . . . . . . : '%s'", ptr_script->name);
+ weechat_log_printf (" name_with_extension . : '%s'", ptr_script->name_with_extension);
+ weechat_log_printf (" language. . . . . . . : %d", ptr_script->language);
+ weechat_log_printf (" author. . . . . . . . : '%s'", ptr_script->author);
+ weechat_log_printf (" mail. . . . . . . . . : '%s'", ptr_script->mail);
+ weechat_log_printf (" version . . . . . . . : '%s'", ptr_script->version);
+ weechat_log_printf (" license . . . . . . . : '%s'", ptr_script->license);
+ weechat_log_printf (" description . . . . . : '%s'", ptr_script->description);
+ weechat_log_printf (" tags. . . . . . . . . : '%s'", ptr_script->tags);
+ weechat_log_printf (" requirements. . . . . : '%s'", ptr_script->requirements);
+ weechat_log_printf (" min_weechat . . . . . : '%s'", ptr_script->min_weechat);
+ weechat_log_printf (" max_weechat . . . . . : '%s'", ptr_script->max_weechat);
+ weechat_log_printf (" md5sum. . . . . . . . : '%s'", ptr_script->md5sum);
+ weechat_log_printf (" url . . . . . . . . . : '%s'", ptr_script->url);
+ weechat_log_printf (" popularity. . . . . . : %d", ptr_script->popularity);
+ weechat_log_printf (" date_added. . . . . . : %ld", ptr_script->date_added);
+ weechat_log_printf (" date_updated. . . . . : %ld", ptr_script->date_updated);
+ weechat_log_printf (" status. . . . . . . . : %d (%s%s%s%s )",
+ ptr_script->status,
+ (ptr_script->status & SCRIPT_STATUS_INSTALLED) ? " installed": "",
+ (ptr_script->status & SCRIPT_STATUS_HELD) ? " held": "",
+ (ptr_script->status & SCRIPT_STATUS_RUNNING) ? " running": "",
+ (ptr_script->status & SCRIPT_STATUS_NEW_VERSION) ? " new_version": "");
+ weechat_log_printf (" version_loaded. . . . : '%s'", ptr_script->version_loaded);
+ weechat_log_printf (" displayed . . . . . . : %d", ptr_script->displayed);
+ weechat_log_printf (" install_order . . . . : %d", ptr_script->install_order);
+ weechat_log_printf (" prev_script . . . . . : 0x%lx", ptr_script->prev_script);
+ weechat_log_printf (" next_script . . . . . : 0x%lx", ptr_script->next_script);
+ }
+}
diff --git a/src/plugins/script/script-repo.h b/src/plugins/script/script-repo.h
new file mode 100644
index 000000000..9bd05e6c7
--- /dev/null
+++ b/src/plugins/script/script-repo.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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_SCRIPT_REPO_H
+#define __WEECHAT_SCRIPT_REPO_H 1
+
+/* status for script */
+#define SCRIPT_STATUS_INSTALLED 1
+#define SCRIPT_STATUS_HELD 2
+#define SCRIPT_STATUS_RUNNING 4
+#define SCRIPT_STATUS_NEW_VERSION 8
+
+struct t_repo_script
+{
+ char *name; /* script name */
+ char *name_with_extension; /* script name with extension */
+ int language; /* language index */
+ char *author; /* author */
+ char *mail; /* author's mail */
+ char *version; /* plugin version */
+ char *license; /* license */
+ char *description; /* description */
+ char *tags; /* comma-separated list of tags */
+ char *requirements; /* requirements */
+ char *min_weechat; /* min WeeChat version */
+ char *max_weechat; /* max WeeChat version */
+ char *md5sum; /* md5sum of script content */
+ char *url; /* URL to download script */
+ int popularity; /* >0 for popular scripts only */
+ time_t date_added; /* date added */
+ time_t date_updated; /* date updated */
+ int status; /* installed/running/new version */
+ char *version_loaded; /* version of script loaded */
+ int displayed; /* script displayed? */
+ int install_order; /* order for install script (if >0)*/
+ struct t_repo_script *prev_script; /* link to previous script */
+ struct t_repo_script *next_script; /* link to next script */
+};
+
+extern struct t_repo_script *repo_scripts;
+extern struct t_repo_script *last_repo_script;
+extern int script_repo_count, script_repo_count_displayed;
+struct t_hashtable *script_repo_max_length_field;
+extern char *script_repo_filter;
+
+extern int script_repo_script_valid (struct t_repo_script *script);
+extern struct t_repo_script *script_repo_search_displayed_by_number (int number);
+extern struct t_repo_script *script_repo_search_by_name (const char *name);
+extern struct t_repo_script *script_repo_search_by_name_ext (const char *name_with_extension);
+extern const char *script_repo_get_status_for_display (struct t_repo_script *script,
+ const char *list,
+ int collapse);
+extern void script_repo_remove_all ();
+extern void script_repo_update_status (struct t_repo_script *script);
+extern void script_repo_update_status_all ();
+extern int script_repo_file_exists ();
+extern int script_repo_file_is_uptodate ();
+extern int script_repo_file_read (int quiet);
+extern void script_repo_file_update (int quiet);
+extern void script_repo_filter_scripts (const char *search);
+extern struct t_hdata *script_repo_hdata_script_cb (void *data,
+ const char *hdata_name);
+extern int script_repo_add_to_infolist (struct t_infolist *infolist,
+ struct t_repo_script *script);
+extern void script_repo_print_log ();
+
+#endif /* __WEECHAT_SCRIPT_REPO_H */
diff --git a/src/plugins/script/script.c b/src/plugins/script/script.c
new file mode 100644
index 000000000..a52f9d670
--- /dev/null
+++ b/src/plugins/script/script.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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/>.
+ */
+
+/*
+ * script.c: scripts manager for WeeChat
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <libgen.h>
+
+#include "../weechat-plugin.h"
+#include "script.h"
+#include "script-buffer.h"
+#include "script-command.h"
+#include "script-completion.h"
+#include "script-config.h"
+#include "script-info.h"
+#include "script-repo.h"
+
+
+WEECHAT_PLUGIN_NAME(SCRIPT_PLUGIN_NAME);
+WEECHAT_PLUGIN_DESCRIPTION(N_("Scripts manager"));
+WEECHAT_PLUGIN_AUTHOR("Sebastien Helleu <flashcode@flashtux.org>");
+WEECHAT_PLUGIN_VERSION(WEECHAT_VERSION);
+WEECHAT_PLUGIN_LICENSE(WEECHAT_LICENSE);
+
+struct t_weechat_plugin *weechat_script_plugin = NULL;
+
+char *script_language[] = { "guile", "lua", "perl", "python", "ruby", "tcl", NULL };
+char *script_extension[] = { "scm", "lua", "pl", "py", "rb", "tcl", NULL };
+
+struct t_hashtable *script_loaded = NULL;
+struct t_hook *script_timer_refresh = NULL;
+
+
+/*
+ * script_language_search: search language and return index
+ * return -1 if not found
+ */
+
+int
+script_language_search (const char *language)
+{
+ int i;
+
+ for (i = 0; script_language[i]; i++)
+ {
+ if (strcmp (script_language[i], language) == 0)
+ return i;
+ }
+
+ /* language not found */
+ return -1;
+}
+
+/*
+ * script_language_search_by_extension: search language by extension and return
+ * index
+ * return -1 if not found
+ */
+
+int
+script_language_search_by_extension (const char *extension)
+{
+ int i;
+
+ for (i = 0; script_extension[i]; i++)
+ {
+ if (strcmp (script_extension[i], extension) == 0)
+ return i;
+ }
+
+ /* extension not found */
+ return -1;
+}
+
+/*
+ * script_get_loaded_scripts: get loaded scripts (in hashtable)
+ */
+
+void
+script_get_loaded_scripts ()
+{
+ int i;
+ char hdata_name[128], *filename, *ptr_base_name;
+ const char *ptr_filename;
+ struct t_hdata *hdata;
+ void *ptr_script;
+
+ if (!script_loaded)
+ {
+ script_loaded = weechat_hashtable_new (16,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL,
+ NULL);
+ }
+ else
+ weechat_hashtable_remove_all (script_loaded);
+
+ for (i = 0; script_language[i]; i++)
+ {
+ snprintf (hdata_name, sizeof (hdata_name),
+ "%s_script", script_language[i]);
+ hdata = weechat_hdata_get (hdata_name);
+ ptr_script = weechat_hdata_get_list (hdata, "scripts");
+ while (ptr_script)
+ {
+ ptr_filename = weechat_hdata_string (hdata, ptr_script, "filename");
+ if (ptr_filename)
+ {
+ filename = strdup (ptr_filename);
+ if (filename)
+ {
+ ptr_base_name = basename (filename);
+ weechat_hashtable_set (script_loaded,
+ ptr_base_name,
+ weechat_hdata_string (hdata, ptr_script,
+ "version"));
+ free (filename);
+ }
+ }
+ ptr_script = weechat_hdata_move (hdata, ptr_script, 1);
+ }
+ }
+}
+
+/*
+ * script_debug_dump_cb: callback for "debug_dump" signal
+ */
+
+int
+script_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, SCRIPT_PLUGIN_NAME) == 0))
+ {
+ weechat_log_printf ("");
+ weechat_log_printf ("***** \"%s\" plugin dump *****",
+ weechat_plugin->name);
+
+ script_repo_print_log ();
+
+ weechat_log_printf ("");
+ weechat_log_printf ("***** End of \"%s\" plugin dump *****",
+ weechat_plugin->name);
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_timer_refresh_cb: callback for timer used to refresh list of scripts
+ */
+
+int
+script_timer_refresh_cb (void *data, int remaining_calls)
+{
+ /* make C compiler happy */
+ (void) data;
+
+ script_get_loaded_scripts ();
+ script_repo_update_status_all ();
+ script_buffer_refresh (0);
+
+ if (remaining_calls == 0)
+ script_timer_refresh = NULL;
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * script_signal_script_cb: callback for signals "xxx_script_yyy"
+ * (example: "python_script_loaded")
+ */
+
+int
+script_signal_script_cb (void *data, const char *signal, const char *type_data,
+ void *signal_data)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) signal;
+ (void) type_data;
+ (void) signal_data;
+
+ if (weechat_script_plugin->debug >= 2)
+ weechat_printf (NULL, "signal: %s, data: %s", signal, (char *)signal_data);
+
+ if (!script_timer_refresh)
+ {
+ script_timer_refresh = weechat_hook_timer (50, 0, 1,
+ &script_timer_refresh_cb, NULL);
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * weechat_plugin_init: initialize script plugin
+ */
+
+int
+weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[])
+{
+ /* make C compiler happy */
+ (void) argc;
+ (void) argv;
+
+ weechat_plugin = plugin;
+
+ script_buffer_set_callbacks ();
+
+ if (!script_config_init ())
+ return WEECHAT_RC_ERROR;
+
+ if (script_config_read () < 0)
+ return WEECHAT_RC_ERROR;
+
+ weechat_mkdir_home (SCRIPT_PLUGIN_NAME, 0755);
+
+ script_command_init ();
+ script_completion_init ();
+ script_info_init ();
+
+ weechat_hook_signal ("debug_dump", &script_debug_dump_cb, NULL);
+ weechat_hook_signal ("window_scrolled", &script_buffer_window_scrolled_cb, NULL);
+ weechat_hook_signal ("*_script_*", &script_signal_script_cb, NULL);
+
+ if (script_repo_file_exists ())
+ {
+ if (!script_repo_file_is_uptodate ())
+ script_repo_file_update (0);
+ else
+ script_repo_file_read (0);
+ }
+
+ if (script_buffer)
+ script_buffer_refresh (1);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * weechat_plugin_end: end script plugin
+ */
+
+int
+weechat_plugin_end (struct t_weechat_plugin *plugin)
+{
+ /* make C compiler happy */
+ (void) plugin;
+
+ script_config_write ();
+
+ script_repo_remove_all ();
+
+ if (script_repo_filter)
+ free (script_repo_filter);
+
+ if (script_loaded)
+ weechat_hashtable_free (script_loaded);
+
+ script_config_free ();
+
+ return WEECHAT_RC_OK;
+}
diff --git a/src/plugins/script/script.h b/src/plugins/script/script.h
new file mode 100644
index 000000000..e922c3011
--- /dev/null
+++ b/src/plugins/script/script.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2003-2012 Sebastien 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_SCRIPT_H
+#define __WEECHAT_SCRIPT_H 1
+
+#define weechat_plugin weechat_script_plugin
+#define SCRIPT_PLUGIN_NAME "script"
+
+extern struct t_weechat_plugin *weechat_script_plugin;
+
+extern char *script_language[];
+extern char *script_extension[];
+extern struct t_hashtable *script_loaded;
+
+extern int script_language_search (const char *language);
+extern int script_language_search_by_extension (const char *extension);
+extern void script_actions_add (const char *action);
+extern void script_get_loaded_scripts ();
+
+#endif /* __WEECHAT_SCRIPT_H */