1698 lines
54 KiB
C
1698 lines
54 KiB
C
/*
|
|
* script-repo.c - download and read repository file (plugins.xml.gz)
|
|
*
|
|
* Copyright (C) 2003-2020 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* this define is needed for strptime()
|
|
* but is not used for OpenBSD, it causes bug with gcrypt (see bug #37373)
|
|
*/
|
|
#if !defined(__OpenBSD__) && !defined(__sun)
|
|
#define _XOPEN_SOURCE 700
|
|
#endif
|
|
|
|
#include <limits.h>
|
|
#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 "../weechat-plugin.h"
|
|
#include "script.h"
|
|
#include "script-repo.h"
|
|
#include "script-action.h"
|
|
#include "script-buffer.h"
|
|
#include "script-config.h"
|
|
|
|
|
|
struct t_script_repo *scripts_repo = NULL;
|
|
struct t_script_repo *last_script_repo = 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;
|
|
|
|
|
|
/*
|
|
* Checks if a script pointer is valid.
|
|
*
|
|
* Returns:
|
|
* 1: script exists
|
|
* 0: script does not exist
|
|
*/
|
|
|
|
int
|
|
script_repo_script_valid (struct t_script_repo *script)
|
|
{
|
|
struct t_script_repo *ptr_script;
|
|
|
|
if (!script)
|
|
return 0;
|
|
|
|
for (ptr_script = scripts_repo; ptr_script;
|
|
ptr_script = ptr_script->next_script)
|
|
{
|
|
if (ptr_script == script)
|
|
return 1;
|
|
}
|
|
|
|
/* script not found */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Searches for a script displayed by number (first script displayed is 0).
|
|
*
|
|
* Returns pointer to script found, NULL if not found.
|
|
*/
|
|
|
|
struct t_script_repo *
|
|
script_repo_search_displayed_by_number (int number)
|
|
{
|
|
struct t_script_repo *ptr_script;
|
|
int i;
|
|
|
|
if (number < 0)
|
|
return NULL;
|
|
|
|
i = 0;
|
|
for (ptr_script = scripts_repo; ptr_script;
|
|
ptr_script = ptr_script->next_script)
|
|
{
|
|
if (ptr_script->displayed)
|
|
{
|
|
if (i == number)
|
|
return ptr_script;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
/* script not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Searches for a script by name (example: "iset").
|
|
*
|
|
* Returns pointer to script found, NULL if not found.
|
|
*/
|
|
|
|
struct t_script_repo *
|
|
script_repo_search_by_name (const char *name)
|
|
{
|
|
struct t_script_repo *ptr_script;
|
|
|
|
for (ptr_script = scripts_repo; ptr_script;
|
|
ptr_script = ptr_script->next_script)
|
|
{
|
|
if (strcmp (ptr_script->name, name) == 0)
|
|
return ptr_script;
|
|
}
|
|
|
|
/* script not found */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Searches for a script by name/extension (example: "go.py").
|
|
*
|
|
* Returns pointer to script found, NULL if not found.
|
|
*/
|
|
|
|
struct t_script_repo *
|
|
script_repo_search_by_name_ext (const char *name_with_extension)
|
|
{
|
|
struct t_script_repo *ptr_script;
|
|
|
|
for (ptr_script = scripts_repo; 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;
|
|
}
|
|
|
|
/*
|
|
* Gets filename of a loaded script (returns name of file and not the link, if
|
|
* there is a symbolic to file).
|
|
*
|
|
* Note: result must be freed after use.
|
|
*/
|
|
|
|
char *
|
|
script_repo_get_filename_loaded (struct t_script_repo *script)
|
|
{
|
|
char *weechat_home, *filename, resolved_path[PATH_MAX];
|
|
int length;
|
|
struct stat st;
|
|
|
|
weechat_home = weechat_info_get ("weechat_dir", NULL);
|
|
length = strlen (weechat_home) + strlen (script->name_with_extension) + 64;
|
|
filename = malloc (length);
|
|
if (!filename)
|
|
{
|
|
if (weechat_home)
|
|
free (weechat_home);
|
|
return NULL;
|
|
}
|
|
|
|
snprintf (filename, length, "%s/%s/autoload/%s",
|
|
weechat_home,
|
|
script_language[script->language],
|
|
script->name_with_extension);
|
|
if (stat (filename, &st) != 0)
|
|
{
|
|
snprintf (filename, length, "%s/%s/%s",
|
|
weechat_home,
|
|
script_language[script->language],
|
|
script->name_with_extension);
|
|
if (stat (filename, &st) != 0)
|
|
{
|
|
filename[0] = '\0';
|
|
}
|
|
}
|
|
|
|
if (weechat_home)
|
|
free (weechat_home);
|
|
|
|
if (!filename[0])
|
|
{
|
|
free (filename);
|
|
return NULL;
|
|
}
|
|
|
|
if (realpath (filename, resolved_path))
|
|
{
|
|
if (strcmp (filename, resolved_path) != 0)
|
|
{
|
|
free (filename);
|
|
return strdup (resolved_path);
|
|
}
|
|
}
|
|
|
|
return filename;
|
|
}
|
|
|
|
/*
|
|
* Gets status for display.
|
|
*
|
|
* Argument "list" is the codes of status to display:
|
|
* * popular
|
|
* i installed
|
|
* a autoloaded
|
|
* ? unknown
|
|
* H held
|
|
* r running
|
|
* N obsolete
|
|
*/
|
|
|
|
const char *
|
|
script_repo_get_status_for_display (struct t_script_repo *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 'a':
|
|
strcat (str_status, weechat_color (weechat_config_string (script_config_color_status_autoloaded)));
|
|
strcat (str_status, (script && (script->status & SCRIPT_STATUS_AUTOLOADED)) ? "a" : 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;
|
|
}
|
|
|
|
/*
|
|
* Gets status description for display.
|
|
*
|
|
* Argument "list" is the codes of status to display (see function
|
|
* script_repo_get_status_for_display() above).
|
|
*/
|
|
|
|
const char *
|
|
script_repo_get_status_desc_for_display (struct t_script_repo *script,
|
|
const char *list)
|
|
{
|
|
static char str_status[256];
|
|
const char *ptr_list;
|
|
|
|
str_status[0] = '\0';
|
|
|
|
if (!script)
|
|
return str_status;
|
|
|
|
for (ptr_list = list; ptr_list[0]; ptr_list++)
|
|
{
|
|
switch (ptr_list[0])
|
|
{
|
|
case '*':
|
|
if (script->popularity > 0)
|
|
{
|
|
if (str_status[0])
|
|
strcat (str_status, " ");
|
|
/* TRANSLATORS: translation must be one short word without spaces (replace spaces by underscores if needed) */
|
|
strcat (str_status, _("popular"));
|
|
}
|
|
break;
|
|
case 'i':
|
|
if (script->status & SCRIPT_STATUS_INSTALLED)
|
|
{
|
|
if (str_status[0])
|
|
strcat (str_status, " ");
|
|
/* TRANSLATORS: translation must be one short word without spaces (replace spaces by underscores if needed) */
|
|
strcat (str_status, _("installed"));
|
|
}
|
|
break;
|
|
case 'a':
|
|
if (script->status & SCRIPT_STATUS_AUTOLOADED)
|
|
{
|
|
if (str_status[0])
|
|
strcat (str_status, " ");
|
|
/* TRANSLATORS: translation must be one short word without spaces (replace spaces by underscores if needed) */
|
|
strcat (str_status, _("autoloaded"));
|
|
}
|
|
break;
|
|
case 'H':
|
|
if (script->status & SCRIPT_STATUS_HELD)
|
|
{
|
|
if (str_status[0])
|
|
strcat (str_status, " ");
|
|
/* TRANSLATORS: translation must be one short word without spaces (replace spaces by underscores if needed) */
|
|
strcat (str_status, _("held"));
|
|
}
|
|
break;
|
|
case 'r':
|
|
if (script->status & SCRIPT_STATUS_RUNNING)
|
|
{
|
|
if (str_status[0])
|
|
strcat (str_status, " ");
|
|
/* TRANSLATORS: translation must be one short word without spaces (replace spaces by underscores if needed) */
|
|
strcat (str_status, _("running"));
|
|
}
|
|
break;
|
|
case 'N':
|
|
if (script->status & SCRIPT_STATUS_NEW_VERSION)
|
|
{
|
|
if (str_status[0])
|
|
strcat (str_status, " ");
|
|
/* TRANSLATORS: translation must be one short word without spaces (replace spaces by underscores if needed) */
|
|
strcat (str_status, _("obsolete"));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return str_status;
|
|
}
|
|
|
|
/*
|
|
* Allocates a script structure.
|
|
*
|
|
* Returns pointer to new script, NULL if error.
|
|
*/
|
|
|
|
struct t_script_repo *
|
|
script_repo_alloc ()
|
|
{
|
|
struct t_script_repo *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->sha512sum = 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;
|
|
}
|
|
|
|
/*
|
|
* Compares two scripts using sort key(s) (from option script.look.sort).
|
|
*
|
|
* Returns:
|
|
* < 0: script1 < script2
|
|
* 0: script1 == script2
|
|
* > 0: script1 > script2
|
|
*/
|
|
|
|
int
|
|
script_repo_compare_scripts (struct t_script_repo *script1,
|
|
struct t_script_repo *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 'A': /* status autoloaded */
|
|
if ((script1->status & SCRIPT_STATUS_AUTOLOADED)
|
|
&& !(script2->status & SCRIPT_STATUS_AUTOLOADED))
|
|
cmp = -1;
|
|
else if (!(script1->status & SCRIPT_STATUS_AUTOLOADED)
|
|
&& (script2->status & SCRIPT_STATUS_AUTOLOADED))
|
|
cmp = 1;
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Searches for position for script in list (to keep list sorted).
|
|
*/
|
|
|
|
struct t_script_repo *
|
|
script_repo_find_pos (struct t_script_repo *script)
|
|
{
|
|
struct t_script_repo *ptr_script;
|
|
|
|
for (ptr_script = scripts_repo; 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;
|
|
}
|
|
|
|
/*
|
|
* Sets 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);
|
|
}
|
|
|
|
/*
|
|
* Adds a script to list of scripts.
|
|
*/
|
|
|
|
void
|
|
script_repo_add (struct t_script_repo *script)
|
|
{
|
|
struct t_script_repo *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
|
|
scripts_repo = script;
|
|
ptr_script->prev_script = script;
|
|
}
|
|
else
|
|
{
|
|
/* add script to the end */
|
|
script->prev_script = last_script_repo;
|
|
script->next_script = NULL;
|
|
if (last_script_repo)
|
|
last_script_repo->next_script = script;
|
|
else
|
|
scripts_repo = script;
|
|
last_script_repo = 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++;
|
|
}
|
|
|
|
/*
|
|
* Frees data in a script.
|
|
*/
|
|
|
|
void
|
|
script_repo_free (struct t_script_repo *script)
|
|
{
|
|
if (!script)
|
|
return;
|
|
|
|
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->sha512sum)
|
|
free (script->sha512sum);
|
|
if (script->url)
|
|
free (script->url);
|
|
if (script->version_loaded)
|
|
free (script->version_loaded);
|
|
|
|
free (script);
|
|
}
|
|
|
|
/*
|
|
* Removes a script from list.
|
|
*/
|
|
|
|
void
|
|
script_repo_remove (struct t_script_repo *script)
|
|
{
|
|
struct t_script_repo *new_scripts_repo;
|
|
|
|
/* unlink script from buffer (if it is used) */
|
|
if (script_buffer_detail_script == script)
|
|
script_buffer_detail_script = NULL;
|
|
|
|
/* remove script from list */
|
|
if (last_script_repo == script)
|
|
last_script_repo = script->prev_script;
|
|
if (script->prev_script)
|
|
{
|
|
(script->prev_script)->next_script = script->next_script;
|
|
new_scripts_repo = scripts_repo;
|
|
}
|
|
else
|
|
new_scripts_repo = 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);
|
|
|
|
scripts_repo = new_scripts_repo;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Removes all scripts from list.
|
|
*/
|
|
|
|
void
|
|
script_repo_remove_all ()
|
|
{
|
|
while (scripts_repo)
|
|
{
|
|
script_repo_remove (scripts_repo);
|
|
}
|
|
if (script_repo_max_length_field)
|
|
{
|
|
weechat_hashtable_free (script_repo_max_length_field);
|
|
script_repo_max_length_field = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Checks if a script is held.
|
|
*
|
|
* Returns:
|
|
* 1: script is held
|
|
* 0: script is not held
|
|
*/
|
|
|
|
int
|
|
script_repo_script_is_held (struct t_script_repo *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;
|
|
}
|
|
|
|
/*
|
|
* Computes SHA-512 checksum for the content of a file.
|
|
*
|
|
* Note: result must be freed after use.
|
|
*/
|
|
|
|
char *
|
|
script_repo_sha512sum_file (const char *filename)
|
|
{
|
|
struct stat st;
|
|
FILE *file;
|
|
char *data, hash[512 / 8], hash_hexa[((512 / 8) * 2) + 1];
|
|
int length_hash;
|
|
|
|
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);
|
|
fclose (file);
|
|
return NULL;
|
|
}
|
|
fclose (file);
|
|
|
|
if (!weechat_crypto_hash (data, st.st_size, "sha512", hash, &length_hash))
|
|
{
|
|
free (data);
|
|
return NULL;
|
|
}
|
|
weechat_string_base_encode (16, hash, length_hash, hash_hexa);
|
|
weechat_string_tolower (hash_hexa);
|
|
|
|
free (data);
|
|
|
|
return strdup (hash_hexa);
|
|
}
|
|
|
|
/*
|
|
* Updates following status of a script:
|
|
* - script installed?
|
|
* - script running?
|
|
* - new version available?
|
|
*/
|
|
|
|
void
|
|
script_repo_update_status (struct t_script_repo *script)
|
|
{
|
|
const char *version;
|
|
char *weechat_home, *filename, *sha512sum;
|
|
struct stat st;
|
|
int length;
|
|
struct t_script_repo *ptr_script;
|
|
|
|
script->status = 0;
|
|
sha512sum = 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;
|
|
script->status |= SCRIPT_STATUS_AUTOLOADED;
|
|
sha512sum = script_repo_sha512sum_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;
|
|
sha512sum = script_repo_sha512sum_file (filename);
|
|
}
|
|
}
|
|
free (filename);
|
|
}
|
|
|
|
if (weechat_home)
|
|
free (weechat_home);
|
|
|
|
/* 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 (sha512sum && script->sha512sum
|
|
&& (strcmp (script->sha512sum, sha512sum) != 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 = scripts_repo; 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 (sha512sum)
|
|
free (sha512sum);
|
|
}
|
|
|
|
/*
|
|
* Updates status of all scripts.
|
|
*/
|
|
|
|
void
|
|
script_repo_update_status_all ()
|
|
{
|
|
struct t_script_repo *ptr_script;
|
|
|
|
for (ptr_script = scripts_repo; ptr_script;
|
|
ptr_script = ptr_script->next_script)
|
|
{
|
|
script_repo_update_status (ptr_script);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Sets filter for scripts.
|
|
*/
|
|
|
|
void
|
|
script_repo_set_filter (const char *filter)
|
|
{
|
|
if (script_repo_filter)
|
|
free (script_repo_filter);
|
|
script_repo_filter = (filter) ? strdup (filter) : NULL;
|
|
|
|
script_buffer_set_localvar_filter ();
|
|
}
|
|
|
|
/*
|
|
* Checks if a script is matching a filter string.
|
|
*
|
|
* Returns:
|
|
* 1: script is matching filter string
|
|
* 0: script does not match filter string
|
|
*/
|
|
|
|
int
|
|
script_repo_match_filter (struct t_script_repo *script)
|
|
{
|
|
char **words, **tags;
|
|
int num_words, num_tags, has_tag, match, i, j;
|
|
|
|
if (!script_repo_filter || strcmp (script_repo_filter, "*") == 0)
|
|
return 1;
|
|
|
|
words = weechat_string_split (script_repo_filter, " ", NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
|
0, &num_words);
|
|
tags = weechat_string_split ((script->tags) ? script->tags : "",
|
|
",",
|
|
NULL,
|
|
WEECHAT_STRING_SPLIT_STRIP_LEFT
|
|
| WEECHAT_STRING_SPLIT_STRIP_RIGHT
|
|
| WEECHAT_STRING_SPLIT_COLLAPSE_SEPS,
|
|
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
|
|
&& (weechat_strcasecmp (script_language[script->language],
|
|
words[i]) == 0))
|
|
{
|
|
match = 1;
|
|
}
|
|
|
|
if (!match
|
|
&& (weechat_strcasecmp (script_extension[script->language],
|
|
words[i]) == 0))
|
|
{
|
|
match = 1;
|
|
}
|
|
|
|
if (!match && script->description
|
|
&& weechat_strcasestr (script->description, 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;
|
|
}
|
|
|
|
/*
|
|
* Filters scripts (search string in name/description/tags) and marks scripts
|
|
* found as "displayed" (0 in displayed for non-matching scripts).
|
|
*/
|
|
|
|
void
|
|
script_repo_filter_scripts (const char *search)
|
|
{
|
|
struct t_script_repo *ptr_script;
|
|
|
|
script_repo_set_filter (search);
|
|
|
|
script_repo_count_displayed = 0;
|
|
|
|
for (ptr_script = scripts_repo; ptr_script;
|
|
ptr_script = ptr_script->next_script)
|
|
{
|
|
ptr_script->displayed = (script_repo_match_filter (ptr_script));
|
|
if (ptr_script->displayed)
|
|
script_repo_count_displayed++;
|
|
}
|
|
|
|
script_buffer_refresh (1);
|
|
}
|
|
|
|
/*
|
|
* Checks if repository file (plugins.xml.gz) exists.
|
|
*
|
|
* Returns:
|
|
* 1: repository file exists
|
|
* 0: repository file does not exist
|
|
*/
|
|
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Checks if repository file (plugins.xml.gz) is up-to-date (file exists and it
|
|
* not outdated).
|
|
*
|
|
* Returns:
|
|
* 1: repository file is up-to-date
|
|
* 0: repository file does not exist or is outdated
|
|
* (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;
|
|
}
|
|
|
|
/* file is empty? => NOT up-to-date */
|
|
if (st.st_size == 0)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Reads scripts in repository file (plugins.xml.gz).
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
script_repo_file_read (int quiet)
|
|
{
|
|
char *filename, *ptr_line, line[4096], *pos, *pos2, *pos3;
|
|
char *name, *value1, *value2, *value3, *value, *error;
|
|
char *info_locale, *locale, *locale_language, *version;
|
|
const char *ptr_desc;
|
|
gzFile file;
|
|
struct t_script_repo *script;
|
|
int version_number, version_ok, script_ok, length;
|
|
struct tm tm_script;
|
|
struct t_hashtable *descriptions;
|
|
|
|
script_get_loaded_plugins ();
|
|
script_get_scripts ();
|
|
|
|
script_repo_remove_all ();
|
|
|
|
if (!script_repo_max_length_field)
|
|
{
|
|
script_repo_max_length_field = weechat_hashtable_new (
|
|
32,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_INTEGER,
|
|
NULL, NULL);
|
|
}
|
|
else
|
|
weechat_hashtable_remove_all (script_repo_max_length_field);
|
|
|
|
version = weechat_info_get ("version", NULL);
|
|
version_number = weechat_util_version_number (version);
|
|
if (version)
|
|
free (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;
|
|
}
|
|
|
|
/*
|
|
* get locale and locale_languages
|
|
* example: if LANG=fr_FR.UTF-8, result is:
|
|
* locale = "fr_FR"
|
|
* locale_language = "fr"
|
|
*/
|
|
locale = NULL;
|
|
locale_language = NULL;
|
|
info_locale = weechat_info_get ("locale", NULL);
|
|
if (info_locale)
|
|
{
|
|
pos = strchr (info_locale, '.');
|
|
if (pos)
|
|
locale = weechat_strndup (info_locale, pos - info_locale);
|
|
else
|
|
locale = strdup (info_locale);
|
|
free (info_locale);
|
|
}
|
|
if (locale)
|
|
{
|
|
pos = strchr (locale, '_');
|
|
if (pos)
|
|
locale_language = weechat_strndup (locale, pos - locale);
|
|
else
|
|
locale_language = strdup (locale);
|
|
}
|
|
|
|
descriptions = weechat_hashtable_new (32,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL, NULL);
|
|
|
|
/* read plugins.xml.gz */
|
|
while (!gzeof (file))
|
|
{
|
|
ptr_line = gzgets (file, line, sizeof (line) - 1);
|
|
if (ptr_line)
|
|
{
|
|
if (strstr (ptr_line, "<plugin id="))
|
|
{
|
|
if (script)
|
|
script_repo_free (script);
|
|
script = script_repo_alloc ();
|
|
weechat_hashtable_remove_all (descriptions);
|
|
}
|
|
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)
|
|
{
|
|
ptr_desc = NULL;
|
|
if (weechat_config_boolean (script_config_look_translate_description))
|
|
{
|
|
/* try translated description (format "fr_FR") */
|
|
ptr_desc = weechat_hashtable_get (descriptions,
|
|
locale);
|
|
if (!ptr_desc)
|
|
{
|
|
/* try translated description (format "fr") */
|
|
ptr_desc = weechat_hashtable_get (descriptions,
|
|
locale_language);
|
|
}
|
|
}
|
|
if (!ptr_desc)
|
|
{
|
|
/* default description (English) */
|
|
ptr_desc = weechat_hashtable_get (descriptions,
|
|
"en");
|
|
}
|
|
if (ptr_desc)
|
|
{
|
|
script->description = strdup (ptr_desc);
|
|
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->displayed = (script_repo_match_filter (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, "&", "&");
|
|
value3 = weechat_string_replace (value2, ">", ">");
|
|
value = weechat_string_replace (value3, "<", "<");
|
|
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 (strncmp (name, "desc_", 5) == 0)
|
|
{
|
|
/*
|
|
* store translated description in hashtable
|
|
* (will be used later, by choosing
|
|
* appropriate language according to locale)
|
|
*/
|
|
weechat_hashtable_set (descriptions,
|
|
name + 5,
|
|
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, "sha512sum") == 0)
|
|
script->sha512sum = 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 (scripts_repo && !quiet)
|
|
{
|
|
version = weechat_info_get ("version", NULL);
|
|
weechat_printf (NULL,
|
|
_("%s: %d scripts for WeeChat %s"),
|
|
SCRIPT_PLUGIN_NAME, script_repo_count,
|
|
version);
|
|
if (version)
|
|
free (version);
|
|
}
|
|
|
|
if (!scripts_repo)
|
|
{
|
|
weechat_printf (NULL,
|
|
_("%s%s: list of scripts is empty (repository file "
|
|
"is broken, or download has failed)"),
|
|
weechat_prefix ("error"),
|
|
SCRIPT_PLUGIN_NAME);
|
|
}
|
|
|
|
if (script)
|
|
script_repo_free (script);
|
|
if (locale)
|
|
free (locale);
|
|
if (locale_language)
|
|
free (locale_language);
|
|
if (descriptions)
|
|
weechat_hashtable_free (descriptions);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Callback called when list of scripts is downloaded.
|
|
*/
|
|
|
|
int
|
|
script_repo_file_update_process_cb (const void *pointer, void *data,
|
|
const char *command,
|
|
int return_code, const char *out,
|
|
const char *err)
|
|
{
|
|
int quiet;
|
|
|
|
/* make C compiler happy */
|
|
(void) data;
|
|
(void) command;
|
|
(void) out;
|
|
|
|
quiet = (pointer) ? 1 : 0;
|
|
|
|
if (return_code >= 0)
|
|
{
|
|
if (err && err[0])
|
|
{
|
|
weechat_printf (NULL,
|
|
_("%s%s: error downloading list of scripts: %s"),
|
|
weechat_prefix ("error"),
|
|
SCRIPT_PLUGIN_NAME,
|
|
err);
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
if (script_repo_file_read (quiet) && scripts_repo)
|
|
{
|
|
if (script_buffer)
|
|
script_buffer_refresh (1);
|
|
if (!script_action_run ())
|
|
script_buffer_refresh (1);
|
|
}
|
|
else
|
|
script_buffer_refresh (1);
|
|
}
|
|
|
|
return WEECHAT_RC_OK;
|
|
}
|
|
|
|
/*
|
|
* Updates repository file and reads it.
|
|
*/
|
|
|
|
void
|
|
script_repo_file_update (int quiet)
|
|
{
|
|
char *filename, *url;
|
|
struct t_hashtable *options;
|
|
|
|
script_repo_remove_all ();
|
|
|
|
filename = script_config_get_xml_filename ();
|
|
if (!filename)
|
|
return;
|
|
|
|
options = weechat_hashtable_new (32,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
WEECHAT_HASHTABLE_STRING,
|
|
NULL, NULL);
|
|
if (options)
|
|
{
|
|
url = script_build_download_url (
|
|
weechat_config_string (script_config_scripts_url));
|
|
if (url)
|
|
{
|
|
if (!quiet)
|
|
{
|
|
weechat_printf (NULL,
|
|
_("%s: downloading list of scripts..."),
|
|
SCRIPT_PLUGIN_NAME);
|
|
}
|
|
weechat_hashtable_set (options, "file_out", filename);
|
|
weechat_hook_process_hashtable (
|
|
url,
|
|
options,
|
|
weechat_config_integer (script_config_scripts_download_timeout) * 1000,
|
|
&script_repo_file_update_process_cb,
|
|
(quiet) ? (void *)1 : (void *)0,
|
|
NULL);
|
|
free (url);
|
|
}
|
|
weechat_hashtable_free (options);
|
|
}
|
|
|
|
free (filename);
|
|
}
|
|
|
|
/*
|
|
* Returns hdata for script.
|
|
*/
|
|
|
|
struct t_hdata *
|
|
script_repo_hdata_script_cb (const void *pointer, void *data,
|
|
const char *hdata_name)
|
|
{
|
|
struct t_hdata *hdata;
|
|
|
|
/* make C compiler happy */
|
|
(void) pointer;
|
|
(void) data;
|
|
|
|
hdata = weechat_hdata_new (hdata_name, "prev_script", "next_script",
|
|
0, 0, NULL, NULL);
|
|
if (hdata)
|
|
{
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, name, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, name_with_extension, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, language, INTEGER, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, author, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, mail, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, version, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, license, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, description, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, tags, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, requirements, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, min_weechat, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, max_weechat, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, sha512sum, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, url, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, popularity, INTEGER, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, date_added, TIME, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, date_updated, TIME, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, status, INTEGER, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, version_loaded, STRING, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, displayed, INTEGER, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, install_order, INTEGER, 0, NULL, NULL);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, prev_script, POINTER, 0, NULL, hdata_name);
|
|
WEECHAT_HDATA_VAR(struct t_script_repo, next_script, POINTER, 0, NULL, hdata_name);
|
|
WEECHAT_HDATA_LIST(scripts_repo, WEECHAT_HDATA_LIST_CHECK_POINTERS);
|
|
WEECHAT_HDATA_LIST(last_script_repo, 0);
|
|
}
|
|
return hdata;
|
|
}
|
|
|
|
/*
|
|
* Adds a script in an infolist.
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
script_repo_add_to_infolist (struct t_infolist *infolist,
|
|
struct t_script_repo *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, "sha512sum", script->sha512sum))
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Prints scripts in WeeChat log file (usually for crash dump).
|
|
*/
|
|
|
|
void
|
|
script_repo_print_log ()
|
|
{
|
|
struct t_script_repo *ptr_script;
|
|
|
|
for (ptr_script = scripts_repo; 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 (" sha512sum . . . . . . : '%s'", ptr_script->sha512sum);
|
|
weechat_log_printf (" url . . . . . . . . . : '%s'", ptr_script->url);
|
|
weechat_log_printf (" popularity. . . . . . : %d", ptr_script->popularity);
|
|
weechat_log_printf (" date_added. . . . . . : %lld", (long long)ptr_script->date_added);
|
|
weechat_log_printf (" date_updated. . . . . : %lld", (long long)ptr_script->date_updated);
|
|
weechat_log_printf (" status. . . . . . . . : %d (%s%s%s%s%s )",
|
|
ptr_script->status,
|
|
(ptr_script->status & SCRIPT_STATUS_INSTALLED) ? " installed": "",
|
|
(ptr_script->status & SCRIPT_STATUS_AUTOLOADED) ? " autoloaded": "",
|
|
(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);
|
|
}
|
|
}
|