821 lines
22 KiB
C
821 lines
22 KiB
C
/*
|
|
* wee-hook.c - WeeChat hooks management
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/socket.h>
|
|
#include <errno.h>
|
|
|
|
#include "weechat.h"
|
|
#include "wee-hook.h"
|
|
#include "wee-hashtable.h"
|
|
#include "wee-infolist.h"
|
|
#include "wee-log.h"
|
|
#include "wee-string.h"
|
|
#include "wee-util.h"
|
|
#include "../gui/gui-chat.h"
|
|
#include "../plugins/plugin.h"
|
|
|
|
|
|
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" };
|
|
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 */
|
|
int hooks_count_total = 0; /* total number of hooks */
|
|
int hook_exec_recursion = 0; /* 1 when a hook is executed */
|
|
int real_delete_pending = 0; /* 1 if some hooks must be deleted */
|
|
|
|
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 };
|
|
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 };
|
|
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 };
|
|
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 };
|
|
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 };
|
|
|
|
|
|
/*
|
|
* Initializes hooks.
|
|
*/
|
|
|
|
void
|
|
hook_init ()
|
|
{
|
|
int type, sock[2], rc;
|
|
|
|
/* initialize list of hooks and callbacks */
|
|
for (type = 0; type < HOOK_NUM_TYPES; type++)
|
|
{
|
|
weechat_hooks[type] = NULL;
|
|
last_weechat_hook[type] = NULL;
|
|
hooks_count[type] = 0;
|
|
}
|
|
hooks_count_total = 0;
|
|
hook_last_system_time = time (NULL);
|
|
|
|
/*
|
|
* Set a flag to 0 if socketpair() function is not available.
|
|
*
|
|
* For the connect hook, when this is defined an array of sockets will
|
|
* be passed from the parent process to the child process instead of using
|
|
* SCM_RIGHTS to pass a socket back from the child process to parent
|
|
* process.
|
|
*
|
|
* This allows connections to work on Windows but it limits the number of
|
|
* IPs that can be attempted each time.
|
|
*/
|
|
hook_socketpair_ok = 1;
|
|
|
|
#if defined(__CYGWIN__) || defined(__APPLE__) || defined(__MACH__)
|
|
hook_socketpair_ok = 0;
|
|
(void) sock;
|
|
(void) rc;
|
|
#else
|
|
/*
|
|
* Test if socketpair() function is working fine: this is NOT the case
|
|
* on Windows with Ubuntu bash
|
|
* (errno == 94: ESOCKTNOSUPPORT: socket type not supported)
|
|
*/
|
|
rc = socketpair (AF_LOCAL, SOCK_DGRAM, 0, sock);
|
|
if (rc < 0)
|
|
{
|
|
/* Windows/Ubuntu */
|
|
hook_socketpair_ok = 0;
|
|
}
|
|
else
|
|
{
|
|
close (sock[0]);
|
|
close (sock[1]);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Searches for a hook type.
|
|
*
|
|
* Returns index of type in enum t_hook_type, -1 if type is not found.
|
|
*/
|
|
|
|
int
|
|
hook_search_type (const char *type)
|
|
{
|
|
int i;
|
|
|
|
if (!type)
|
|
return -1;
|
|
|
|
for (i = 0; i < HOOK_NUM_TYPES; i++)
|
|
{
|
|
if (strcmp (hook_type_string[i], type) == 0)
|
|
return i;
|
|
}
|
|
|
|
/* type not found */
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Searches for position of hook in list (to keep hooks sorted).
|
|
*
|
|
* Hooks are sorted by priority, except commands which are sorted by command
|
|
* name, and then priority.
|
|
*/
|
|
|
|
struct t_hook *
|
|
hook_find_pos (struct t_hook *hook)
|
|
{
|
|
struct t_hook *ptr_hook;
|
|
int rc_cmp;
|
|
|
|
if (hook->type == HOOK_TYPE_COMMAND)
|
|
{
|
|
/* for command hook, sort on command name + priority */
|
|
for (ptr_hook = weechat_hooks[hook->type]; ptr_hook;
|
|
ptr_hook = ptr_hook->next_hook)
|
|
{
|
|
if (!ptr_hook->deleted)
|
|
{
|
|
rc_cmp = string_strcasecmp (HOOK_COMMAND(hook, command),
|
|
HOOK_COMMAND(ptr_hook, command));
|
|
if (rc_cmp < 0)
|
|
return ptr_hook;
|
|
if ((rc_cmp == 0) && (hook->priority > ptr_hook->priority))
|
|
return ptr_hook;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* for other types, sort on priority */
|
|
for (ptr_hook = weechat_hooks[hook->type]; ptr_hook;
|
|
ptr_hook = ptr_hook->next_hook)
|
|
{
|
|
if (!ptr_hook->deleted && (hook->priority > ptr_hook->priority))
|
|
return ptr_hook;
|
|
}
|
|
}
|
|
|
|
/* position not found, add at the end */
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Adds a hook to list.
|
|
*/
|
|
|
|
void
|
|
hook_add_to_list (struct t_hook *new_hook)
|
|
{
|
|
struct t_hook *pos_hook;
|
|
|
|
if (weechat_hooks[new_hook->type])
|
|
{
|
|
pos_hook = hook_find_pos (new_hook);
|
|
if (pos_hook)
|
|
{
|
|
/* add hook before "pos_hook" */
|
|
new_hook->prev_hook = pos_hook->prev_hook;
|
|
new_hook->next_hook = pos_hook;
|
|
if (pos_hook->prev_hook)
|
|
(pos_hook->prev_hook)->next_hook = new_hook;
|
|
else
|
|
weechat_hooks[new_hook->type] = new_hook;
|
|
pos_hook->prev_hook = new_hook;
|
|
}
|
|
else
|
|
{
|
|
/* add hook to end of list */
|
|
new_hook->prev_hook = last_weechat_hook[new_hook->type];
|
|
new_hook->next_hook = NULL;
|
|
last_weechat_hook[new_hook->type]->next_hook = new_hook;
|
|
last_weechat_hook[new_hook->type] = new_hook;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
new_hook->prev_hook = NULL;
|
|
new_hook->next_hook = NULL;
|
|
weechat_hooks[new_hook->type] = new_hook;
|
|
last_weechat_hook[new_hook->type] = new_hook;
|
|
}
|
|
|
|
hooks_count[new_hook->type]++;
|
|
hooks_count_total++;
|
|
|
|
if (hook_callback_add[new_hook->type])
|
|
(hook_callback_add[new_hook->type]) (new_hook);
|
|
}
|
|
|
|
/*
|
|
* Removes a hook from list.
|
|
*/
|
|
|
|
void
|
|
hook_remove_from_list (struct t_hook *hook)
|
|
{
|
|
struct t_hook *new_hooks;
|
|
int type;
|
|
|
|
type = hook->type;
|
|
|
|
if (last_weechat_hook[hook->type] == hook)
|
|
last_weechat_hook[hook->type] = hook->prev_hook;
|
|
if (hook->prev_hook)
|
|
{
|
|
(hook->prev_hook)->next_hook = hook->next_hook;
|
|
new_hooks = weechat_hooks[hook->type];
|
|
}
|
|
else
|
|
new_hooks = hook->next_hook;
|
|
|
|
if (hook->next_hook)
|
|
(hook->next_hook)->prev_hook = hook->prev_hook;
|
|
|
|
weechat_hooks[type] = new_hooks;
|
|
|
|
hooks_count[type]--;
|
|
hooks_count_total--;
|
|
|
|
if (hook_callback_remove[hook->type])
|
|
(hook_callback_remove[hook->type]) (hook);
|
|
|
|
free (hook);
|
|
}
|
|
|
|
/*
|
|
* Removes hooks marked as "deleted" from list.
|
|
*/
|
|
|
|
void
|
|
hook_remove_deleted ()
|
|
{
|
|
int type;
|
|
struct t_hook *ptr_hook, *next_hook;
|
|
|
|
if (real_delete_pending)
|
|
{
|
|
for (type = 0; type < HOOK_NUM_TYPES; type++)
|
|
{
|
|
ptr_hook = weechat_hooks[type];
|
|
while (ptr_hook)
|
|
{
|
|
next_hook = ptr_hook->next_hook;
|
|
|
|
if (ptr_hook->deleted)
|
|
hook_remove_from_list (ptr_hook);
|
|
|
|
ptr_hook = next_hook;
|
|
}
|
|
}
|
|
real_delete_pending = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Extracts priority and name from a string.
|
|
*
|
|
* String can be:
|
|
* - a simple name like "test":
|
|
* => priority = 1000 (default), name = "test"
|
|
* - a priority + "|" + name, like "500|test":
|
|
* => priority = 500, name = "test"
|
|
*/
|
|
|
|
void
|
|
hook_get_priority_and_name (const char *string,
|
|
int *priority, const char **name)
|
|
{
|
|
char *pos, *str_priority, *error;
|
|
long number;
|
|
|
|
if (priority)
|
|
*priority = HOOK_PRIORITY_DEFAULT;
|
|
if (name)
|
|
*name = string;
|
|
|
|
pos = strchr (string, '|');
|
|
if (pos)
|
|
{
|
|
str_priority = string_strndup (string, pos - string);
|
|
if (str_priority)
|
|
{
|
|
error = NULL;
|
|
number = strtol (str_priority, &error, 10);
|
|
if (error && !error[0])
|
|
{
|
|
if (priority)
|
|
*priority = number;
|
|
if (name)
|
|
*name = pos + 1;
|
|
}
|
|
free (str_priority);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initializes a new hook with default values.
|
|
*/
|
|
|
|
void
|
|
hook_init_data (struct t_hook *hook, struct t_weechat_plugin *plugin,
|
|
int type, int priority,
|
|
const void *callback_pointer, void *callback_data)
|
|
{
|
|
hook->plugin = plugin;
|
|
hook->subplugin = NULL;
|
|
hook->type = type;
|
|
hook->deleted = 0;
|
|
hook->running = 0;
|
|
hook->priority = priority;
|
|
hook->callback_pointer = callback_pointer;
|
|
hook->callback_data = callback_data;
|
|
hook->hook_data = NULL;
|
|
|
|
if (weechat_debug_core >= 2)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
"debug: adding hook: type=%d (%s), plugin=\"%s\", "
|
|
"priority=%d",
|
|
hook->type,
|
|
hook_type_string[hook->type],
|
|
plugin_get_name (hook->plugin),
|
|
hook->priority);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Checks if a hook pointer is valid.
|
|
*
|
|
* Returns:
|
|
* 1: hook exists
|
|
* 0: hook does not exist
|
|
*/
|
|
|
|
int
|
|
hook_valid (struct t_hook *hook)
|
|
{
|
|
int type;
|
|
struct t_hook *ptr_hook;
|
|
|
|
if (!hook)
|
|
return 0;
|
|
|
|
for (type = 0; type < HOOK_NUM_TYPES; type++)
|
|
{
|
|
for (ptr_hook = weechat_hooks[type]; ptr_hook;
|
|
ptr_hook = ptr_hook->next_hook)
|
|
{
|
|
if (!ptr_hook->deleted && (ptr_hook == hook))
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* hook not found */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Starts a hook exec.
|
|
*/
|
|
|
|
void
|
|
hook_exec_start ()
|
|
{
|
|
hook_exec_recursion++;
|
|
}
|
|
|
|
/*
|
|
* Ends a hook_exec.
|
|
*/
|
|
|
|
void
|
|
hook_exec_end ()
|
|
{
|
|
if (hook_exec_recursion > 0)
|
|
hook_exec_recursion--;
|
|
|
|
if (hook_exec_recursion == 0)
|
|
hook_remove_deleted ();
|
|
}
|
|
|
|
/*
|
|
* Sets a hook property (string).
|
|
*/
|
|
|
|
void
|
|
hook_set (struct t_hook *hook, const char *property, const char *value)
|
|
{
|
|
ssize_t num_written;
|
|
char *error;
|
|
long number;
|
|
int rc;
|
|
|
|
/* invalid hook? */
|
|
if (!hook_valid (hook))
|
|
return;
|
|
|
|
if (string_strcasecmp (property, "subplugin") == 0)
|
|
{
|
|
if (hook->subplugin)
|
|
free (hook->subplugin);
|
|
hook->subplugin = strdup (value);
|
|
}
|
|
else if (string_strcasecmp (property, "stdin") == 0)
|
|
{
|
|
if (!hook->deleted
|
|
&& (hook->type == HOOK_TYPE_PROCESS)
|
|
&& (HOOK_PROCESS(hook, child_write[HOOK_PROCESS_STDIN]) >= 0))
|
|
{
|
|
/* send data on child's stdin */
|
|
num_written = write (HOOK_PROCESS(hook, child_write[HOOK_PROCESS_STDIN]),
|
|
value, strlen (value));
|
|
(void) num_written;
|
|
}
|
|
}
|
|
else if (string_strcasecmp (property, "stdin_close") == 0)
|
|
{
|
|
if (!hook->deleted
|
|
&& (hook->type == HOOK_TYPE_PROCESS)
|
|
&& (HOOK_PROCESS(hook, child_write[HOOK_PROCESS_STDIN]) >= 0))
|
|
{
|
|
/* close stdin pipe */
|
|
close (HOOK_PROCESS(hook, child_write[HOOK_PROCESS_STDIN]));
|
|
HOOK_PROCESS(hook, child_write[HOOK_PROCESS_STDIN]) = -1;
|
|
}
|
|
}
|
|
else if (string_strcasecmp (property, "signal") == 0)
|
|
{
|
|
if (!hook->deleted
|
|
&& (hook->type == HOOK_TYPE_PROCESS)
|
|
&& (HOOK_PROCESS(hook, child_pid) > 0))
|
|
{
|
|
error = NULL;
|
|
number = strtol (value, &error, 10);
|
|
if (!error || error[0])
|
|
{
|
|
/* not a number? look for signal by name */
|
|
number = util_signal_search (value);
|
|
}
|
|
if (number >= 0)
|
|
{
|
|
rc = kill (HOOK_PROCESS(hook, child_pid), (int)number);
|
|
if (rc < 0)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
_("%sError sending signal %d to pid %d: %s"),
|
|
gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
|
|
(int)number,
|
|
HOOK_PROCESS(hook, child_pid),
|
|
strerror (errno));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Unhooks something.
|
|
*/
|
|
|
|
void
|
|
unhook (struct t_hook *hook)
|
|
{
|
|
/* invalid hook? */
|
|
if (!hook_valid (hook))
|
|
return;
|
|
|
|
/* hook already deleted? */
|
|
if (hook->deleted)
|
|
return;
|
|
|
|
if (weechat_debug_core >= 2)
|
|
{
|
|
gui_chat_printf (NULL,
|
|
"debug: removing hook: type=%d (%s), plugin=\"%s\"",
|
|
hook->type,
|
|
hook_type_string[hook->type],
|
|
plugin_get_name (hook->plugin));
|
|
}
|
|
|
|
/* free data specific to the hook */
|
|
(hook_callback_free_data[hook->type]) (hook);
|
|
|
|
/* free data common to all hooks */
|
|
if (hook->subplugin)
|
|
{
|
|
free (hook->subplugin);
|
|
hook->subplugin = NULL;
|
|
}
|
|
if (hook->callback_data)
|
|
{
|
|
free (hook->callback_data);
|
|
hook->callback_data = NULL;
|
|
}
|
|
|
|
/* remove hook from list (if there's no hook exec pending) */
|
|
if (hook_exec_recursion == 0)
|
|
{
|
|
hook_remove_from_list (hook);
|
|
}
|
|
else
|
|
{
|
|
/* there is one or more hook exec, then delete later */
|
|
hook->deleted = 1;
|
|
real_delete_pending = 1;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Unhooks everything for a plugin/subplugin.
|
|
*/
|
|
|
|
void
|
|
unhook_all_plugin (struct t_weechat_plugin *plugin, const char *subplugin)
|
|
{
|
|
int type;
|
|
struct t_hook *ptr_hook, *next_hook;
|
|
|
|
for (type = 0; type < HOOK_NUM_TYPES; type++)
|
|
{
|
|
ptr_hook = weechat_hooks[type];
|
|
while (ptr_hook)
|
|
{
|
|
next_hook = ptr_hook->next_hook;
|
|
if (ptr_hook->plugin == plugin)
|
|
{
|
|
if (!subplugin
|
|
|| (ptr_hook->subplugin &&
|
|
strcmp (ptr_hook->subplugin, subplugin) == 0))
|
|
{
|
|
unhook (ptr_hook);
|
|
}
|
|
}
|
|
ptr_hook = next_hook;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Unhooks everything.
|
|
*/
|
|
|
|
void
|
|
unhook_all ()
|
|
{
|
|
int type;
|
|
struct t_hook *ptr_hook, *next_hook;
|
|
|
|
for (type = 0; type < HOOK_NUM_TYPES; type++)
|
|
{
|
|
ptr_hook = weechat_hooks[type];
|
|
while (ptr_hook)
|
|
{
|
|
next_hook = ptr_hook->next_hook;
|
|
unhook (ptr_hook);
|
|
ptr_hook = next_hook;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Adds a hook in an infolist.
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
hook_add_to_infolist_pointer (struct t_infolist *infolist, struct t_hook *hook)
|
|
{
|
|
struct t_infolist_item *ptr_item;
|
|
|
|
ptr_item = infolist_new_item (infolist);
|
|
if (!ptr_item)
|
|
return 0;
|
|
|
|
if (!infolist_new_var_pointer (ptr_item, "pointer", hook))
|
|
return 0;
|
|
if (!infolist_new_var_pointer (ptr_item, "plugin", hook->plugin))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "plugin_name",
|
|
(hook->plugin) ?
|
|
hook->plugin->name : NULL))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "subplugin", hook->subplugin))
|
|
return 0;
|
|
if (!infolist_new_var_string (ptr_item, "type", hook_type_string[hook->type]))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "deleted", hook->deleted))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "running", hook->running))
|
|
return 0;
|
|
if (!infolist_new_var_integer (ptr_item, "priority", hook->priority))
|
|
return 0;
|
|
if (!infolist_new_var_pointer (ptr_item, "callback_pointer", (void *)hook->callback_pointer))
|
|
return 0;
|
|
if (!infolist_new_var_pointer (ptr_item, "callback_data", (void *)hook->callback_data))
|
|
return 0;
|
|
|
|
/* hook deleted? return only hook info above */
|
|
if (hook->deleted)
|
|
return 1;
|
|
|
|
/* hook not deleted: add extra hook info */
|
|
if (!(hook_callback_add_to_infolist[hook->type]) (ptr_item, hook))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Adds hooks of a type in an infolist.
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
hook_add_to_infolist_type (struct t_infolist *infolist, int type,
|
|
const char *arguments)
|
|
{
|
|
struct t_hook *ptr_hook;
|
|
int match;
|
|
|
|
for (ptr_hook = weechat_hooks[type]; ptr_hook;
|
|
ptr_hook = ptr_hook->next_hook)
|
|
{
|
|
match = 1;
|
|
if (arguments && !ptr_hook->deleted)
|
|
{
|
|
switch (ptr_hook->type)
|
|
{
|
|
case HOOK_TYPE_COMMAND:
|
|
match = string_match (HOOK_COMMAND(ptr_hook, command), arguments, 0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!match)
|
|
continue;
|
|
|
|
hook_add_to_infolist_pointer (infolist, ptr_hook);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Adds hooks in an infolist.
|
|
*
|
|
* Argument "arguments" can be a hook type with optional comma + name after.
|
|
*
|
|
* Returns:
|
|
* 1: OK
|
|
* 0: error
|
|
*/
|
|
|
|
int
|
|
hook_add_to_infolist (struct t_infolist *infolist, struct t_hook *pointer,
|
|
const char *arguments)
|
|
{
|
|
const char *pos_arguments;
|
|
char *type;
|
|
int i, type_int;
|
|
|
|
if (!infolist)
|
|
return 0;
|
|
|
|
if (pointer)
|
|
return hook_add_to_infolist_pointer (infolist, pointer);
|
|
|
|
type = NULL;
|
|
pos_arguments = NULL;
|
|
|
|
if (arguments && arguments[0])
|
|
{
|
|
pos_arguments = strchr (arguments, ',');
|
|
if (pos_arguments)
|
|
{
|
|
type = string_strndup (arguments, pos_arguments - arguments);
|
|
pos_arguments++;
|
|
}
|
|
else
|
|
type = strdup (arguments);
|
|
}
|
|
|
|
type_int = (type) ? hook_search_type (type) : -1;
|
|
|
|
for (i = 0; i < HOOK_NUM_TYPES; i++)
|
|
{
|
|
if ((type_int < 0) || (type_int == i))
|
|
hook_add_to_infolist_type (infolist, i, pos_arguments);
|
|
}
|
|
|
|
if (type)
|
|
free (type);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Prints hooks in WeeChat log file (usually for crash dump).
|
|
*/
|
|
|
|
void
|
|
hook_print_log ()
|
|
{
|
|
int type;
|
|
struct t_hook *ptr_hook;
|
|
|
|
for (type = 0; type < HOOK_NUM_TYPES; type++)
|
|
{
|
|
for (ptr_hook = weechat_hooks[type]; ptr_hook;
|
|
ptr_hook = ptr_hook->next_hook)
|
|
{
|
|
log_printf ("");
|
|
log_printf ("[hook (addr:0x%lx)]", ptr_hook);
|
|
log_printf (" plugin. . . . . . . . . : 0x%lx ('%s')",
|
|
ptr_hook->plugin, plugin_get_name (ptr_hook->plugin));
|
|
log_printf (" subplugin . . . . . . . : '%s'", ptr_hook->subplugin);
|
|
log_printf (" type. . . . . . . . . . : %d (%s)",
|
|
ptr_hook->type, hook_type_string[ptr_hook->type]);
|
|
log_printf (" deleted . . . . . . . . : %d", ptr_hook->deleted);
|
|
log_printf (" running . . . . . . . . : %d", ptr_hook->running);
|
|
log_printf (" priority. . . . . . . . : %d", ptr_hook->priority);
|
|
log_printf (" callback_pointer. . . . : 0x%lx", ptr_hook->callback_pointer);
|
|
log_printf (" callback_data . . . . . : 0x%lx", ptr_hook->callback_data);
|
|
if (ptr_hook->deleted)
|
|
continue;
|
|
|
|
(hook_callback_print_log[ptr_hook->type]) (ptr_hook);
|
|
|
|
log_printf (" prev_hook . . . . . . . : 0x%lx", ptr_hook->prev_hook);
|
|
log_printf (" next_hook . . . . . . . : 0x%lx", ptr_hook->next_hook);
|
|
}
|
|
}
|
|
}
|