1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-02 15:53:12 +02:00

api: add function hook_url

This commit is contained in:
Sébastien Helleu
2023-09-08 11:34:56 +02:00
parent a5f4c3770b
commit 63922ca038
18 changed files with 740 additions and 60 deletions
+1 -2
View File
@@ -27,8 +27,7 @@ New features::
* core: add options weechat.buffer.* to save buffer properties set by user, add option `setauto` in command `/buffer` (issue #352)
* core: add parameters and key bindings to move to edges of current area with commands `/cursor go` and `/cursor move` (issue #1282)
* core: add variables "_chat_focused_line_bol" and "_chat_focused_line_eol" in focus data (issue #1955)
* core: add algorithms `sha512-224`, `sha512-256`, `sha3-*`, blake2b-*` and `blake2s-*` in option sec.crypt.hash_algo (issue #2008)
* api: add algorithms `sha512-224`, `sha512-256`, blake2b-*` and `blake2s-*` in hash functions (issue #2008)
* api: add function hook_url, add option `url` in command `/debug` (issue #1723)
* api: add support of path to variable and hashtable comparison in function hdata_compare (issue #1066)
* api: add infos "nick_color_ignore_case" and "nick_color_name_ignore_case" (issue #194)
* api: add info "buffer" (issue #1962)
+1
View File
@@ -167,6 +167,7 @@ WeeChat "core" is located in following directories:
|       wee-hook-process.c | Hook "process".
|       wee-hook-signal.c | Hook "signal".
|       wee-hook-timer.c | Hook "timer".
|       wee-hook-url.c | Hook "url".
| gui/ | Functions for buffers, windows, ... (used by all interfaces).
|    gui-bar-item.c | Bar items.
|    gui-bar-window.c | Bar windows.
+1
View File
@@ -169,6 +169,7 @@ Le cœur de WeeChat est situé dans les répertoires suivants :
|       wee-hook-process.c | Hook "process".
|       wee-hook-signal.c | Hook "signal".
|       wee-hook-timer.c | Hook "timer".
|       wee-hook-url.c | Hook "url".
| gui/ | Fonctions pour les tampons, fenêtres, ... (utilisées par toutes les interfaces).
|    gui-bar-item.c | Objets de barre.
|    gui-bar-window.c | Fenêtres de barre.
+1
View File
@@ -180,6 +180,7 @@ WeeChat "core" は以下のディレクトリに配置されています:
|       wee-hook-process.c | "process" フック
|       wee-hook-signal.c | "signal" フック
|       wee-hook-timer.c | "timer" フック
|       wee-hook-url.c | "url" フック
| gui/ | バッファ、ウィンドウなどの関数 (全てのインターフェースで利用)
|    gui-bar-item.c | バー要素
|    gui-bar-window.c | バーウィンドウ
+1
View File
@@ -169,6 +169,7 @@ WeeChat „језгро” се налази у следећим директо
|       wee-hook-process.c | Кука "process".
|       wee-hook-signal.c | Кука "signal".
|       wee-hook-timer.c | Кука "timer".
|       wee-hook-url.c | Кука "url".
| gui/ | Функције за бафере, прозоре, ... (користе их сви интерфејси).
|    gui-bar-item.c | Ставке трака.
|    gui-bar-window.c | Прозори трака.
+2
View File
@@ -35,6 +35,8 @@ SET(WEECHAT_SOURCES
./src/core/hook/wee-hook-signal.h
./src/core/hook/wee-hook-timer.c
./src/core/hook/wee-hook-timer.h
./src/core/hook/wee-hook-url.c
./src/core/hook/wee-hook-url.h
./src/core/wee-arraylist.c
./src/core/wee-arraylist.h
./src/core/wee-backtrace.c
+1
View File
@@ -72,6 +72,7 @@ set(LIB_CORE_SRC
hook/wee-hook-process.c hook/wee-hook-process.h
hook/wee-hook-signal.c hook/wee-hook-signal.h
hook/wee-hook-timer.c hook/wee-hook-timer.h
hook/wee-hook-url.c hook/wee-hook-url.h
)
# Check for flock support
+3 -1
View File
@@ -278,7 +278,9 @@ hook_process_child (struct t_hook *hook_process)
{
ptr_url++;
}
rc = weeurl_download (ptr_url, HOOK_PROCESS(hook_process, options));
rc = weeurl_download (ptr_url,
HOOK_PROCESS(hook_process, options),
NULL); /* output */
}
else if (strncmp (HOOK_PROCESS(hook_process, command), "func:", 5) == 0)
{
+419
View File
@@ -0,0 +1,419 @@
/*
* wee-hook-url.c - WeeChat URL hook
*
* Copyright (C) 2023 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/>.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <poll.h>
#include <fcntl.h>
#include <errno.h>
#include <pthread.h>
#include "../weechat.h"
#include "../wee-hashtable.h"
#include "../wee-hook.h"
#include "../wee-infolist.h"
#include "../wee-log.h"
#include "../wee-string.h"
#include "../wee-url.h"
#include "../../gui/gui-chat.h"
#include "../../plugins/plugin.h"
/*
* Returns description of hook.
*
* Note: result must be freed after use.
*/
char *
hook_url_get_description (struct t_hook *hook)
{
char str_desc[1024];
snprintf (str_desc, sizeof (str_desc),
"URL: \"%s\", thread id: %d",
HOOK_URL(hook, url),
0);
return strdup (str_desc);
}
/*
* Displays keys and values of a hashtable.
*/
void
hook_url_hashtable_map_cb (void *data, struct t_hashtable *hashtable,
const void *key, const void *value)
{
/* make C compiler happy */
(void) data;
(void) hashtable;
gui_chat_printf (NULL, " %s: \"%s\"",
(const char *)key,
(const char *)value);
}
/*
* Runs callback of url hook.
*/
void
hook_url_run_callback (struct t_hook *hook)
{
if (url_debug)
{
gui_chat_printf (NULL, "Running hook_url callback for URL \"%s\":",
HOOK_URL(hook, url));
gui_chat_printf (NULL, " options:");
hashtable_map (HOOK_URL(hook, options), &hook_url_hashtable_map_cb, NULL);
gui_chat_printf (NULL, " output:");
hashtable_map (HOOK_URL(hook, output), &hook_url_hashtable_map_cb, NULL);
}
(void) (HOOK_URL(hook, callback))
(hook->callback_pointer,
hook->callback_data,
HOOK_URL(hook, url),
HOOK_URL(hook, options),
HOOK_URL(hook, output));
}
/*
* Thread cleanup function: mark thread as not running any more.
*/
void
hook_url_thread_cleanup (void *hook_pointer)
{
struct t_hook *hook;
hook = (struct t_hook *)hook_pointer;
HOOK_URL(hook, thread_running) = 0;
}
/*
* URL transfer (in a separate thread).
*/
void *
hook_url_transfer_thread (void *hook_pointer)
{
struct t_hook *hook;
hook = (struct t_hook *)hook_pointer;
pthread_cleanup_push (&hook_url_thread_cleanup, hook);
(void) weeurl_download (HOOK_URL(hook, url),
HOOK_URL(hook, options),
HOOK_URL(hook, output));
pthread_cleanup_pop (1);
return NULL;
}
/*
* Checks if thread is still alive.
*/
int
hook_url_timer_cb (const void *pointer, void *data, int remaining_calls)
{
struct t_hook *hook;
const char *ptr_error;
/* make C compiler happy */
(void) data;
(void) remaining_calls;
hook = (struct t_hook *)pointer;
if (hook->deleted)
return WEECHAT_RC_OK;
if (!HOOK_URL(hook, thread_running))
{
hook_url_run_callback (hook);
ptr_error = hashtable_get (HOOK_URL(hook, output), "error");
if (ptr_error && ptr_error[0])
{
gui_chat_printf (
NULL,
_("%sURL transfer error: %s (URL: \"%s\")"),
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
ptr_error,
HOOK_URL(hook, url));
}
unhook (hook);
return WEECHAT_RC_OK;
}
if (remaining_calls == 0)
{
hook_url_run_callback (hook);
if (weechat_debug_core >= 1)
{
gui_chat_printf (
NULL,
_("End of URL transfer '%s', timeout reached (%.1fs)"),
HOOK_URL(hook, url),
((float)HOOK_URL(hook, timeout)) / 1000);
}
pthread_cancel (HOOK_URL(hook, thread_id));
usleep (1000);
unhook (hook);
}
return WEECHAT_RC_OK;
}
/*
* Starts transfer for an URL hook.
*/
void
hook_url_transfer (struct t_hook *hook)
{
int rc, timeout, max_calls;
long interval;
HOOK_URL(hook, thread_running) = 1;
/* create thread */
rc = pthread_create (&(HOOK_URL(hook, thread_id)), NULL,
&hook_url_transfer_thread, hook);
if (rc != 0)
{
gui_chat_printf (NULL,
_("%sError running thread in hook_url: %s (URL: \"%s\")"),
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
strerror (rc),
HOOK_URL(hook, url));
unhook (hook);
return;
}
/* main thread */
timeout = HOOK_URL(hook, timeout);
interval = 100;
max_calls = 0;
if (timeout > 0)
{
if (timeout <= 100)
{
interval = timeout;
max_calls = 1;
}
else
{
interval = 100;
max_calls = timeout / 100;
if (timeout % 100 == 0)
max_calls++;
}
}
HOOK_URL(hook, hook_timer) = hook_timer (hook->plugin,
interval, 0, max_calls,
&hook_url_timer_cb,
hook,
NULL);
}
/*
* Hooks a URL.
*
* Returns pointer to new hook, NULL if error.
*/
struct t_hook *
hook_url (struct t_weechat_plugin *plugin,
const char *url,
struct t_hashtable *options,
int timeout,
t_hook_callback_url *callback,
const void *callback_pointer,
void *callback_data)
{
struct t_hook *new_hook;
struct t_hook_url *new_hook_url;
new_hook = NULL;
new_hook_url = NULL;
if (!url || !url[0] || !callback)
goto error;
new_hook = malloc (sizeof (*new_hook));
if (!new_hook)
goto error;
new_hook_url = malloc (sizeof (*new_hook_url));
if (!new_hook_url)
goto error;
hook_init_data (new_hook, plugin, HOOK_TYPE_URL, HOOK_PRIORITY_DEFAULT,
callback_pointer, callback_data);
new_hook->hook_data = new_hook_url;
new_hook_url->callback = callback;
new_hook_url->url = strdup (url);
new_hook_url->options = (options) ? hashtable_dup (options) : NULL;
new_hook_url->timeout = timeout;
new_hook_url->thread_id = 0;
new_hook_url->thread_running = 0;
new_hook_url->hook_timer = NULL;
new_hook_url->output = hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL, NULL);
hook_add_to_list (new_hook);
if (weechat_debug_core >= 1)
{
gui_chat_printf (NULL,
"debug: hook_url: url=\"%s\", "
"options=\"%s\", timeout=%d",
new_hook_url->url,
hashtable_get_string (new_hook_url->options,
"keys_values"),
new_hook_url->timeout);
}
hook_url_transfer (new_hook);
return new_hook;
error:
if (new_hook)
free (new_hook);
if (new_hook_url)
free (new_hook_url);
return NULL;
}
/*
* Frees data in a url hook.
*/
void
hook_url_free_data (struct t_hook *hook)
{
if (!hook || !hook->hook_data)
return;
if (HOOK_URL(hook, url))
{
free (HOOK_URL(hook, url));
HOOK_URL(hook, url) = NULL;
}
if (HOOK_URL(hook, options))
{
hashtable_free (HOOK_URL(hook, options));
HOOK_URL(hook, options) = NULL;
}
if (HOOK_URL(hook, hook_timer))
{
unhook (HOOK_URL(hook, hook_timer));
HOOK_URL(hook, hook_timer) = NULL;
}
if (HOOK_URL(hook, thread_running))
{
pthread_cancel (HOOK_URL(hook, thread_id));
HOOK_URL(hook, thread_running) = 0;
}
if (HOOK_URL(hook, output))
{
hashtable_free (HOOK_URL(hook, output));
HOOK_URL(hook, output) = NULL;
}
free (hook->hook_data);
hook->hook_data = NULL;
}
/*
* Adds url hook data in the infolist item.
*
* Returns:
* 1: OK
* 0: error
*/
int
hook_url_add_to_infolist (struct t_infolist_item *item,
struct t_hook *hook)
{
if (!item || !hook || !hook->hook_data)
return 0;
if (!infolist_new_var_pointer (item, "callback", HOOK_URL(hook, callback)))
return 0;
if (!infolist_new_var_string (item, "url", HOOK_URL(hook, url)))
return 0;
if (!infolist_new_var_string (item, "options", hashtable_get_string (HOOK_URL(hook, options), "keys_values")))
return 0;
if (!infolist_new_var_integer (item, "timeout", (int)(HOOK_URL(hook, timeout))))
return 0;
if (!infolist_new_var_integer (item, "thread_running", (int)(HOOK_URL(hook, thread_running))))
return 0;
if (!infolist_new_var_pointer (item, "hook_timer", HOOK_URL(hook, hook_timer)))
return 0;
if (!infolist_new_var_string (item, "output", hashtable_get_string (HOOK_URL(hook, output), "keys_values")))
return 0;
return 1;
}
/*
* Prints url hook data in WeeChat log file (usually for crash dump).
*/
void
hook_url_print_log (struct t_hook *hook)
{
if (!hook || !hook->hook_data)
return;
log_printf (" url data:");
log_printf (" callback. . . . . . . : 0x%lx", HOOK_URL(hook, callback));
log_printf (" url . . . . . . . . . : '%s'", HOOK_URL(hook, url));
log_printf (" options . . . . . . . : 0x%lx (hashtable: '%s')",
HOOK_URL(hook, options),
hashtable_get_string (HOOK_URL(hook, options),
"keys_values"));
log_printf (" timeout . . . . . . . : %ld", HOOK_URL(hook, timeout));
log_printf (" thread_running. . . . : %d", (int)HOOK_URL(hook, thread_running));
log_printf (" hook_timer. . . . . . : 0x%lx", HOOK_URL(hook, hook_timer));
log_printf (" output. . . . . . . . : 0x%lx (hashtable: '%s')",
HOOK_URL(hook, output),
hashtable_get_string (HOOK_URL(hook, output),
"keys_values"));
}
+59
View File
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2023 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/>.
*/
#ifndef WEECHAT_HOOK_URL_H
#define WEECHAT_HOOK_URL_H
struct t_weechat_plugin;
struct t_infolist_item;
struct t_hashtable;
#define HOOK_URL(hook, var) (((struct t_hook_url *)hook->hook_data)->var)
typedef int (t_hook_callback_url)(const void *pointer, void *data,
const char *url,
struct t_hashtable *options,
struct t_hashtable *output);
struct t_hook_url
{
t_hook_callback_url *callback; /* URL callback */
char *url; /* URL */
struct t_hashtable *options; /* URL options (see doc) */
long timeout; /* timeout (ms) (0 = no timeout) */
pthread_t thread_id; /* thread id */
int thread_running; /* 1 if thread is running */
struct t_hook *hook_timer; /* timer to check if thread has ended*/
struct t_hashtable *output; /* URL transfer output data */
};
extern char *hook_url_get_description (struct t_hook *hook);
extern struct t_hook *hook_url (struct t_weechat_plugin *plugin,
const char *url,
struct t_hashtable *options,
int timeout,
t_hook_callback_url *callback,
const void *callback_pointer,
void *callback_data);
extern void hook_url_free_data (struct t_hook *hook);
extern int hook_url_add_to_infolist (struct t_infolist_item *item,
struct t_hook *hook);
extern void hook_url_print_log (struct t_hook *hook);
#endif /* WEECHAT_HOOK_URL_H */
+20 -5
View File
@@ -63,6 +63,7 @@
#include "wee-string.h"
#include "wee-sys.h"
#include "wee-upgrade.h"
#include "wee-url.h"
#include "wee-utf8.h"
#include "wee-util.h"
#include "wee-version.h"
@@ -2223,6 +2224,15 @@ COMMAND_CALLBACK(debug)
return WEECHAT_RC_OK;
}
if (string_strcmp (argv[1], "url") == 0)
{
url_debug ^= 1;
gui_chat_printf (NULL,
_("Debug hook_url: %s"),
(url_debug) ? _("enabled") : _("disabled"));
return WEECHAT_RC_OK;
}
if (string_strcmp (argv[1], "windows") == 0)
{
debug_windows_tree ();
@@ -7056,14 +7066,17 @@ COMMAND_CALLBACK(upgrade)
}
/*
* it is forbidden to upgrade while there are some background process
* (hook type "process" or "connect")
* it is forbidden to upgrade while there are some background process or
* thread (hook types: process, connect, url)
*/
if (weechat_hooks[HOOK_TYPE_PROCESS] || weechat_hooks[HOOK_TYPE_CONNECT])
if (weechat_hooks[HOOK_TYPE_PROCESS]
|| weechat_hooks[HOOK_TYPE_CONNECT]
|| weechat_hooks[HOOK_TYPE_URL])
{
gui_chat_printf (NULL,
_("%sCan't upgrade: there is one or more background "
"process (hook type 'process' or 'connect')"),
"process/thread running (hook type: process, "
"connect or url)"),
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR]);
return WEECHAT_RC_OK;
}
@@ -8189,7 +8202,7 @@ command_init ()
" || set <plugin> <level>"
" || dump|hooks [<plugin>]"
" || buffer|certs|color|dirs|infolists|libs|memory|tags|"
"term|windows"
"term|url|windows"
" || callbacks <duration>[<unit>]"
" || mouse|cursor [verbose]"
" || hdata [free]"
@@ -8227,6 +8240,7 @@ command_init ()
" mouse: toggle debug for mouse\n"
" tags: display tags for lines\n"
" term: display infos about terminal\n"
" url: toggle debug for calls to hook_url (display output hashtable)\n"
" windows: display windows tree\n"
" time: measure time to execute a command or to send text to "
"the current buffer\n"
@@ -8256,6 +8270,7 @@ command_init ()
" || mouse verbose"
" || tags"
" || term"
" || url"
" || windows"
" || time %(commands:/)"
" || unicode",
+87 -39
View File
@@ -46,7 +46,7 @@
char *hook_type_string[HOOK_NUM_TYPES] =
{ "command", "command_run", "timer", "fd", "process", "connect", "line",
"print", "signal", "hsignal", "config", "completion", "modifier",
"info", "info_hashtable", "infolist", "hdata", "focus" };
"info", "info_hashtable", "infolist", "hdata", "focus", "url" };
struct t_hook *weechat_hooks[HOOK_NUM_TYPES]; /* list of hooks */
struct t_hook *last_weechat_hook[HOOK_NUM_TYPES]; /* last hook */
int hooks_count[HOOK_NUM_TYPES]; /* number of hooks */
@@ -59,50 +59,98 @@ int hook_socketpair_ok = 0; /* 1 if socketpair() is OK */
/* hook callbacks */
t_callback_hook *hook_callback_add[HOOK_NUM_TYPES] =
{ NULL, NULL, NULL, &hook_fd_add_cb, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
t_callback_hook *hook_callback_remove[HOOK_NUM_TYPES] =
{ NULL, NULL, NULL, &hook_fd_remove_cb, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
t_callback_hook *hook_callback_free_data[HOOK_NUM_TYPES] =
{ &hook_command_free_data, &hook_command_run_free_data,
&hook_timer_free_data, &hook_fd_free_data,
&hook_process_free_data, &hook_connect_free_data,
&hook_line_free_data, &hook_print_free_data,
&hook_signal_free_data, &hook_hsignal_free_data,
&hook_config_free_data, &hook_completion_free_data,
&hook_modifier_free_data, &hook_info_free_data,
&hook_info_hashtable_free_data, &hook_infolist_free_data,
&hook_hdata_free_data, &hook_focus_free_data };
{
&hook_command_free_data,
&hook_command_run_free_data,
&hook_timer_free_data,
&hook_fd_free_data,
&hook_process_free_data,
&hook_connect_free_data,
&hook_line_free_data,
&hook_print_free_data,
&hook_signal_free_data,
&hook_hsignal_free_data,
&hook_config_free_data,
&hook_completion_free_data,
&hook_modifier_free_data,
&hook_info_free_data,
&hook_info_hashtable_free_data,
&hook_infolist_free_data,
&hook_hdata_free_data,
&hook_focus_free_data,
&hook_url_free_data,
};
t_callback_hook_get_desc *hook_callback_get_desc[HOOK_NUM_TYPES] =
{ &hook_command_get_description, &hook_command_run_get_description,
&hook_timer_get_description, &hook_fd_get_description,
&hook_process_get_description, &hook_connect_get_description,
&hook_line_get_description, &hook_print_get_description,
&hook_signal_get_description, &hook_hsignal_get_description,
&hook_config_get_description, &hook_completion_get_description,
&hook_modifier_get_description, &hook_info_get_description,
&hook_info_hashtable_get_description, &hook_infolist_get_description,
&hook_hdata_get_description, &hook_focus_get_description };
{
&hook_command_get_description,
&hook_command_run_get_description,
&hook_timer_get_description,
&hook_fd_get_description,
&hook_process_get_description,
&hook_connect_get_description,
&hook_line_get_description,
&hook_print_get_description,
&hook_signal_get_description,
&hook_hsignal_get_description,
&hook_config_get_description,
&hook_completion_get_description,
&hook_modifier_get_description,
&hook_info_get_description,
&hook_info_hashtable_get_description,
&hook_infolist_get_description,
&hook_hdata_get_description,
&hook_focus_get_description,
&hook_url_get_description,
};
t_callback_hook_infolist *hook_callback_add_to_infolist[HOOK_NUM_TYPES] =
{ &hook_command_add_to_infolist, &hook_command_run_add_to_infolist,
&hook_timer_add_to_infolist, &hook_fd_add_to_infolist,
&hook_process_add_to_infolist, &hook_connect_add_to_infolist,
&hook_line_add_to_infolist, &hook_print_add_to_infolist,
&hook_signal_add_to_infolist, &hook_hsignal_add_to_infolist,
&hook_config_add_to_infolist, &hook_completion_add_to_infolist,
&hook_modifier_add_to_infolist, &hook_info_add_to_infolist,
&hook_info_hashtable_add_to_infolist, &hook_infolist_add_to_infolist,
&hook_hdata_add_to_infolist, &hook_focus_add_to_infolist };
{
&hook_command_add_to_infolist,
&hook_command_run_add_to_infolist,
&hook_timer_add_to_infolist,
&hook_fd_add_to_infolist,
&hook_process_add_to_infolist,
&hook_connect_add_to_infolist,
&hook_line_add_to_infolist,
&hook_print_add_to_infolist,
&hook_signal_add_to_infolist,
&hook_hsignal_add_to_infolist,
&hook_config_add_to_infolist,
&hook_completion_add_to_infolist,
&hook_modifier_add_to_infolist,
&hook_info_add_to_infolist,
&hook_info_hashtable_add_to_infolist,
&hook_infolist_add_to_infolist,
&hook_hdata_add_to_infolist,
&hook_focus_add_to_infolist,
&hook_url_add_to_infolist,
};
t_callback_hook *hook_callback_print_log[HOOK_NUM_TYPES] =
{ &hook_command_print_log, &hook_command_run_print_log,
&hook_timer_print_log, &hook_fd_print_log,
&hook_process_print_log, &hook_connect_print_log,
&hook_line_print_log, &hook_print_print_log,
&hook_signal_print_log, &hook_hsignal_print_log,
&hook_config_print_log, &hook_completion_print_log,
&hook_modifier_print_log, &hook_info_print_log,
&hook_info_hashtable_print_log, &hook_infolist_print_log,
&hook_hdata_print_log, &hook_focus_print_log };
{
&hook_command_print_log,
&hook_command_run_print_log,
&hook_timer_print_log,
&hook_fd_print_log,
&hook_process_print_log,
&hook_connect_print_log,
&hook_line_print_log,
&hook_print_print_log,
&hook_signal_print_log,
&hook_hsignal_print_log,
&hook_config_print_log,
&hook_completion_print_log,
&hook_modifier_print_log,
&hook_info_print_log,
&hook_info_hashtable_print_log,
&hook_infolist_print_log,
&hook_hdata_print_log,
&hook_focus_print_log,
&hook_url_print_log,
};
/*
+2
View File
@@ -40,6 +40,7 @@ struct t_hook;
#include "hook/wee-hook-process.h"
#include "hook/wee-hook-signal.h"
#include "hook/wee-hook-timer.h"
#include "hook/wee-hook-url.h"
struct t_gui_bar;
struct t_gui_buffer;
@@ -73,6 +74,7 @@ enum t_hook_type
HOOK_TYPE_INFOLIST, /* get some info as infolist */
HOOK_TYPE_HDATA, /* get hdata pointer */
HOOK_TYPE_FOCUS, /* focus event (mouse/key) */
HOOK_TYPE_URL, /* URL transfer */
/* number of hook types */
HOOK_NUM_TYPES,
};
+116 -11
View File
@@ -44,6 +44,7 @@
{ #__name, CURLOPT_##__name, URL_TYPE_##__type, __constants }
int url_debug = 0;
char *url_type_string[] = { "string", "long", "long long", "mask", "list" };
/*
@@ -1013,8 +1014,6 @@ struct t_url_option url_options[] =
{ NULL, 0, 0, NULL },
};
char url_error[CURL_ERROR_SIZE + 1];
/*
* Searches for a constant in array of constants.
@@ -1116,7 +1115,7 @@ weeurl_search_option (const char *name)
*/
size_t
weeurl_read (void *buffer, size_t size, size_t nmemb, void *stream)
weeurl_read_stream (void *buffer, size_t size, size_t nmemb, void *stream)
{
return (stream) ? fread (buffer, size, nmemb, stream) : 0;
}
@@ -1126,11 +1125,26 @@ weeurl_read (void *buffer, size_t size, size_t nmemb, void *stream)
*/
size_t
weeurl_write (void *buffer, size_t size, size_t nmemb, void *stream)
weeurl_write_stream (void *buffer, size_t size, size_t nmemb, void *stream)
{
return (stream) ? fwrite (buffer, size, nmemb, stream) : 0;
}
/*
* Adds data to a dynamic string (callback called to catch stdout).
*/
size_t
weeurl_write_string (void *buffer, size_t size, size_t nmemb, void *string)
{
if (!string)
return 0;
string_dyn_concat ((char **)string, buffer, size * nmemb);
return size * nmemb;
}
/*
* Sets option in CURL easy handle (callback called for each option in hashtable
* "options").
@@ -1303,6 +1317,17 @@ weeurl_set_proxy (CURL *curl, struct t_proxy *proxy)
/*
* Downloads URL using options.
*
* If output is not NULL, it must be a hashtable with keys and values of type
* "string". The following keys may be added in the hashtable,
* depending on the success or error of the URL transfer:
*
* key | description
* --------------|--------------------------------------------------------
* response_code | HTTP response code (as string)
* headers | HTTP headers in response
* output | stdout (set only if "file_out" was not set in options)
* error | error message (set only in case of error)
*
* Returns:
* 0: OK
* 1: invalid URL
@@ -1312,20 +1337,28 @@ weeurl_set_proxy (CURL *curl, struct t_proxy *proxy)
*/
int
weeurl_download (const char *url, struct t_hashtable *options)
weeurl_download (const char *url, struct t_hashtable *options,
struct t_hashtable *output)
{
CURL *curl;
struct t_url_file url_file[2];
char *url_file_option[2] = { "file_in", "file_out" };
char *url_file_mode[2] = { "rb", "wb" };
char url_error[CURL_ERROR_SIZE + 1], **string_headers, **string_output;
char str_response_code[32];
CURLoption url_file_opt_func[2] = { CURLOPT_READFUNCTION, CURLOPT_WRITEFUNCTION };
CURLoption url_file_opt_data[2] = { CURLOPT_READDATA, CURLOPT_WRITEDATA };
void *url_file_opt_cb[2] = { &weeurl_read, &weeurl_write };
void *url_file_opt_cb[2] = { &weeurl_read_stream, &weeurl_write_stream };
struct t_proxy *ptr_proxy;
int rc, curl_rc, i;
int rc, curl_rc, i, output_to_file;
long response_code;
rc = 0;
string_headers = NULL;
string_output = NULL;
url_error[0] = '\0';
for (i = 0; i < 2; i++)
{
url_file[i].filename = NULL;
@@ -1334,6 +1367,7 @@ weeurl_download (const char *url, struct t_hashtable *options)
if (!url || !url[0])
{
snprintf (url_error, sizeof (url_error), "%s", _("invalid URL"));
rc = 1;
goto end;
}
@@ -1341,6 +1375,7 @@ weeurl_download (const char *url, struct t_hashtable *options)
curl = curl_easy_init ();
if (!curl)
{
snprintf (url_error, sizeof (url_error), "%s", _("not enough memory"));
rc = 3;
goto end;
}
@@ -1358,7 +1393,19 @@ weeurl_download (const char *url, struct t_hashtable *options)
weeurl_set_proxy (curl, ptr_proxy);
}
/* set callback to retrieve HTTP headers */
if (output)
{
string_headers = string_dyn_alloc (1024);
if (string_headers)
{
curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, &weeurl_write_string);
curl_easy_setopt (curl, CURLOPT_HEADERDATA, string_headers);
}
}
/* set file in/out from options in hashtable */
output_to_file = 0;
if (options)
{
for (i = 0; i < 2; i++)
@@ -1369,15 +1416,33 @@ weeurl_download (const char *url, struct t_hashtable *options)
url_file[i].stream = fopen (url_file[i].filename, url_file_mode[i]);
if (!url_file[i].stream)
{
snprintf (url_error, sizeof (url_error),
(i == 0) ?
_("file \"%s\" not found") :
_("can not write file \"%s\""),
url_file[i].filename);
rc = 4;
goto end;
}
curl_easy_setopt (curl, url_file_opt_func[i], url_file_opt_cb[i]);
curl_easy_setopt (curl, url_file_opt_data[i], url_file[i].stream);
if (i == 1)
output_to_file = 1;
}
}
}
/* redirect stdout if no filename was given (via key "file_out") */
if (output && !output_to_file)
{
string_output = string_dyn_alloc (1024);
if (string_output)
{
curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, &weeurl_write_string);
curl_easy_setopt (curl, CURLOPT_WRITEDATA, string_output);
}
}
/* set other options in hashtable */
hashtable_map (options, &weeurl_option_map_cb, curl);
@@ -1386,11 +1451,36 @@ weeurl_download (const char *url, struct t_hashtable *options)
/* perform action! */
curl_rc = curl_easy_perform (curl);
if (curl_rc != CURLE_OK)
if (curl_rc == CURLE_OK)
{
fprintf (stderr,
_("curl error %d (%s) (URL: \"%s\")\n"),
curl_rc, url_error, url);
if (output)
{
curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &response_code);
snprintf (str_response_code, sizeof (str_response_code),
"%ld", response_code);
hashtable_set (output, "response_code", str_response_code);
}
}
else
{
if (output)
{
if (!url_error[0])
{
snprintf (url_error, sizeof (url_error),
"%s", _("transfer error"));
}
}
else
{
/*
* URL transfer done in a forked process: display error on stderr,
* which will be sent to the hook_process callback
*/
fprintf (stderr,
_("curl error %d (%s) (URL: \"%s\")\n"),
curl_rc, url_error, url);
}
rc = 2;
}
@@ -1403,6 +1493,21 @@ end:
if (url_file[i].stream)
fclose (url_file[i].stream);
}
if (output)
{
if (string_headers)
{
hashtable_set (output, "headers", *string_headers);
string_dyn_free (string_headers, 1);
}
if (string_output)
{
hashtable_set (output, "output", *string_output);
string_dyn_free (string_output, 1);
}
if (url_error[0])
hashtable_set (output, "error", url_error);
}
return rc;
}
+3 -1
View File
@@ -54,10 +54,12 @@ struct t_url_file
FILE *stream; /* file stream */
};
extern int url_debug;
extern char *url_type_string[];
extern struct t_url_option url_options[];
extern int weeurl_download (const char *url, struct t_hashtable *options);
extern int weeurl_download (const char *url, struct t_hashtable *options,
struct t_hashtable *output);
extern int weeurl_option_add_to_infolist (struct t_infolist *infolist,
struct t_url_option *option);
+1
View File
@@ -798,6 +798,7 @@ plugin_load (const char *filename, int init_plugin, int argc, char **argv)
new_plugin->hook_fd = &hook_fd;
new_plugin->hook_process = &hook_process;
new_plugin->hook_process_hashtable = &hook_process_hashtable;
new_plugin->hook_url = &hook_url;
new_plugin->hook_connect = &hook_connect;
new_plugin->hook_line = &hook_line;
new_plugin->hook_print = &hook_print;
+18 -1
View File
@@ -68,7 +68,7 @@ struct timeval;
* please change the date with current one; for a second change at same
* date, increment the 01, otherwise please keep 01.
*/
#define WEECHAT_PLUGIN_API_VERSION "20230706-01"
#define WEECHAT_PLUGIN_API_VERSION "20230908-01"
/* macros for defining plugin infos */
#define WEECHAT_PLUGIN_NAME(__name) \
@@ -748,6 +748,17 @@ struct t_weechat_plugin
const char *err),
const void *callback_pointer,
void *callback_data);
struct t_hook *(*hook_url) (struct t_weechat_plugin *plugin,
const char *url,
struct t_hashtable *options,
int timeout,
int (*callback)(const void *pointer,
void *data,
const char *url,
struct t_hashtable *options,
struct t_hashtable *output),
const void *callback_pointer,
void *callback_data);
struct t_hook *(*hook_connect) (struct t_weechat_plugin *plugin,
const char *proxy,
const char *address,
@@ -1810,6 +1821,12 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin);
__callback, \
__callback_pointer, \
__callback_data)
#define weechat_hook_url(__command, __options, __timeout, \
__callback, __callback_pointer, \
__callback_data) \
(weechat_plugin->hook_url)(weechat_plugin, __command, __options, \
__timeout, __callback, \
__callback_pointer, __callback_data)
#define weechat_hook_connect(__proxy, __address, __port, __ipv6, \
__retry, __gnutls_sess, __gnutls_cb, \
__gnutls_dhkey_size, __gnutls_priorities, \
+4
View File
@@ -139,6 +139,10 @@ if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
endif()
endif()
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Haiku")
list(APPEND EXTRA_LIBS "pthread")
endif()
# binary to run tests
set(WEECHAT_TESTS_SRC
tests.cpp tests.h