mirror of
https://github.com/weechat/weechat.git
synced 2026-06-25 04:16:38 +02:00
145191dbc5
This plugin was originally written by Koka El Kiwi (repository: https://github.com/KokaKiwi/weechat-js-plugin). This plugin uses Google V8 engine to execute JS scripts.
466 lines
12 KiB
C
466 lines
12 KiB
C
/*
|
|
* script.c - scripts manager for WeeChat
|
|
*
|
|
* Copyright (C) 2003-2015 Sébastien Helleu <flashcode@flashtux.org>
|
|
*
|
|
* This file is part of WeeChat, the extensible chat client.
|
|
*
|
|
* WeeChat is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* WeeChat is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <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("Sébastien Helleu <flashcode@flashtux.org>");
|
|
WEECHAT_PLUGIN_VERSION(WEECHAT_VERSION);
|
|
WEECHAT_PLUGIN_LICENSE(WEECHAT_LICENSE);
|
|
WEECHAT_PLUGIN_PRIORITY(2000);
|
|
|
|
struct t_weechat_plugin *weechat_script_plugin = NULL;
|
|
|
|
char *script_language[SCRIPT_NUM_LANGUAGES] =
|
|
{ "guile", "lua", "perl", "python", "ruby", "tcl", "javascript" };
|
|
char *script_extension[SCRIPT_NUM_LANGUAGES] =
|
|
{ "scm", "lua", "pl", "py", "rb", "tcl", "js" };
|
|
|
|
int script_plugin_loaded[SCRIPT_NUM_LANGUAGES];
|
|
struct t_hashtable *script_loaded = NULL;
|
|
struct t_hook *script_timer_refresh = NULL;
|
|
|
|
|
|
/*
|
|
* Searches for a language.
|
|
*
|
|
* Returns index of language, -1 if not found.
|
|
*/
|
|
|
|
int
|
|
script_language_search (const char *language)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SCRIPT_NUM_LANGUAGES; i++)
|
|
{
|
|
if (strcmp (script_language[i], language) == 0)
|
|
return i;
|
|
}
|
|
|
|
/* language not found */
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Searches for a language by extension.
|
|
*
|
|
* Returns index of language, -1 if not found.
|
|
*/
|
|
|
|
int
|
|
script_language_search_by_extension (const char *extension)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < SCRIPT_NUM_LANGUAGES; i++)
|
|
{
|
|
if (strcmp (script_extension[i], extension) == 0)
|
|
return i;
|
|
}
|
|
|
|
/* extension not found */
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Builds download URL (to use with hook_process or hook_process_hashtable).
|
|
*
|
|
* If the option script.scripts.url_force_https is enabled, the protocol is
|
|
* forced to HTTPS (if URL starts with "http://").
|
|
*
|
|
* Note: result must be freed after use.
|
|
*/
|
|
|
|
char *
|
|
script_build_download_url (const char *url)
|
|
{
|
|
char *result;
|
|
int length;
|
|
|
|
if (!url || !url[0])
|
|
return NULL;
|
|
|
|
/* length of url + "url:" + 1 (for httpS) */
|
|
length = 4 + 1 + strlen (url) + 1;
|
|
result = malloc (length);
|
|
if (!result)
|
|
return NULL;
|
|
|
|
if (weechat_config_boolean (script_config_scripts_url_force_https)
|
|
&& (weechat_strncasecmp (url, "http://", 7) == 0))
|
|
{
|
|
snprintf (result, length, "url:https://%s", url + 7);
|
|
}
|
|
else
|
|
{
|
|
snprintf (result, length, "url:%s", url);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Gets loaded plugins (in array of integers) and scripts (in hashtable).
|
|
*/
|
|
|
|
void
|
|
script_get_loaded_plugins_and_scripts ()
|
|
{
|
|
int i, language;
|
|
char hdata_name[128], *filename, *ptr_base_name;
|
|
const char *ptr_filename;
|
|
struct t_hdata *hdata;
|
|
void *ptr_plugin, *ptr_script;
|
|
|
|
/* get loaded plugins */
|
|
for (i = 0; i < SCRIPT_NUM_LANGUAGES; i++)
|
|
{
|
|
script_plugin_loaded[i] = 0;
|
|
}
|
|
hdata = weechat_hdata_get ("plugin");
|
|
ptr_plugin = weechat_hdata_get_list (hdata, "weechat_plugins");
|
|
while (ptr_plugin)
|
|
{
|
|
language = script_language_search (weechat_hdata_string (hdata,
|
|
ptr_plugin,
|
|
"name"));
|
|
if (language >= 0)
|
|
script_plugin_loaded[language] = 1;
|
|
ptr_plugin = weechat_hdata_move (hdata, ptr_plugin, 1);
|
|
}
|
|
|
|
/* get loaded scripts */
|
|
if (!script_loaded)
|
|
{
|
|
script_loaded = weechat_hashtable_new (32,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
else
|
|
weechat_hashtable_remove_all (script_loaded);
|
|
|
|
for (i = 0; i < SCRIPT_NUM_LANGUAGES; 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Callback for signal "debug_dump".
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Callback for timer to refresh list of scripts.
|
|
*/
|
|
|
|
int
|
|
script_timer_refresh_cb (void *data, int remaining_calls)
|
|
{
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
|
|
script_get_loaded_plugins_and_scripts ();
|
|
script_repo_update_status_all ();
|
|
script_buffer_refresh (0);
|
|
|
|
if (remaining_calls == 0)
|
|
script_timer_refresh = NULL;
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Callback for signals "plugin_loaded" and "plugin_unloaded".
|
|
*/
|
|
|
|
int
|
|
script_signal_plugin_cb (void *data, const char *signal, const char *type_data,
|
|
void *signal_data)
|
|
{
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
(void) type_data;
|
|
|
|
if (weechat_script_plugin->debug >= 2)
|
|
{
|
|
weechat_printf (NULL, "%s: signal: %s, data: %s",
|
|
SCRIPT_PLUGIN_NAME,
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* 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) type_data;
|
|
|
|
if (weechat_script_plugin->debug >= 2)
|
|
{
|
|
weechat_printf (NULL, "%s: signal: %s, data: %s",
|
|
SCRIPT_PLUGIN_NAME,
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Callback called when a mouse action occurs in chat area.
|
|
*/
|
|
|
|
struct t_hashtable *
|
|
script_focus_chat_cb (void *data, struct t_hashtable *info)
|
|
{
|
|
const char *buffer;
|
|
int rc;
|
|
long unsigned int value;
|
|
struct t_gui_buffer *ptr_buffer;
|
|
long x;
|
|
char *error, str_date[64];
|
|
struct t_script_repo *ptr_script;
|
|
struct tm *tm;
|
|
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
|
|
if (!script_buffer)
|
|
return info;
|
|
|
|
buffer = weechat_hashtable_get (info, "_buffer");
|
|
if (!buffer)
|
|
return info;
|
|
|
|
rc = sscanf (buffer, "%lx", &value);
|
|
if ((rc == EOF) || (rc == 0))
|
|
return info;
|
|
|
|
ptr_buffer = (struct t_gui_buffer *)value;
|
|
|
|
if (!ptr_buffer || (ptr_buffer != script_buffer))
|
|
return info;
|
|
|
|
if (script_buffer_detail_script)
|
|
ptr_script = script_buffer_detail_script;
|
|
else
|
|
{
|
|
error = NULL;
|
|
x = strtol (weechat_hashtable_get (info, "_chat_line_y"), &error, 10);
|
|
if (!error || error[0])
|
|
return info;
|
|
|
|
if (x < 0)
|
|
return info;
|
|
|
|
ptr_script = script_repo_search_displayed_by_number (x);
|
|
if (!ptr_script)
|
|
return info;
|
|
}
|
|
|
|
weechat_hashtable_set (info, "script_name", ptr_script->name);
|
|
weechat_hashtable_set (info, "script_name_with_extension", ptr_script->name_with_extension);
|
|
weechat_hashtable_set (info, "script_language", script_language[ptr_script->language]);
|
|
weechat_hashtable_set (info, "script_author",ptr_script->author);
|
|
weechat_hashtable_set (info, "script_mail", ptr_script->mail);
|
|
weechat_hashtable_set (info, "script_version", ptr_script->version);
|
|
weechat_hashtable_set (info, "script_license", ptr_script->license);
|
|
weechat_hashtable_set (info, "script_description", ptr_script->description);
|
|
weechat_hashtable_set (info, "script_tags", ptr_script->tags);
|
|
weechat_hashtable_set (info, "script_requirements", ptr_script->requirements);
|
|
weechat_hashtable_set (info, "script_min_weechat", ptr_script->min_weechat);
|
|
weechat_hashtable_set (info, "script_max_weechat", ptr_script->max_weechat);
|
|
weechat_hashtable_set (info, "script_md5sum", ptr_script->md5sum);
|
|
weechat_hashtable_set (info, "script_url", ptr_script->url);
|
|
tm = localtime (&ptr_script->date_added);
|
|
strftime (str_date, sizeof (str_date), "%Y-%m-%d %H:%M:%S", tm);
|
|
weechat_hashtable_set (info, "script_date_added", str_date);
|
|
tm = localtime (&ptr_script->date_updated);
|
|
strftime (str_date, sizeof (str_date), "%Y-%m-%d %H:%M:%S", tm);
|
|
weechat_hashtable_set (info, "script_date_updated", str_date);
|
|
weechat_hashtable_set (info, "script_version_loaded", ptr_script->version_loaded);
|
|
|
|
return info;
|
|
}
|
|
|
|
/*
|
|
* Initializes script plugin.
|
|
*/
|
|
|
|
int
|
|
weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[])
|
|
{
|
|
int i;
|
|
|
|
/* make C compiler happy */
|
|
(void) argc;
|
|
(void) argv;
|
|
|
|
weechat_plugin = plugin;
|
|
|
|
for (i = 0; i < SCRIPT_NUM_LANGUAGES; i++)
|
|
{
|
|
script_plugin_loaded[i] = 0;
|
|
}
|
|
|
|
script_buffer_set_callbacks ();
|
|
|
|
if (!script_config_init ())
|
|
return WEECHAT_RC_ERROR;
|
|
|
|
script_config_read ();
|
|
|
|
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 ("plugin_*", &script_signal_plugin_cb, NULL);
|
|
weechat_hook_signal ("*_script_*", &script_signal_script_cb, NULL);
|
|
|
|
weechat_hook_focus ("chat", &script_focus_chat_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;
|
|
}
|
|
|
|
/*
|
|
* Ends 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;
|
|
}
|