mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-10-08 06:51:21 +00:00
filter hooks by connection and context in core
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
# Core-filtered hooks
|
||||
|
||||
Python: `hook_server_filtered(name, callback, userdata=None, priority=PRI_NORM,
|
||||
connection_id=None, channel=None)` and `hook_print_filtered(...)`.
|
||||
Callbacks match the existing attrs variants: `(word, word_eol, userdata, attrs)`.
|
||||
The connection ID distinguishes duplicate names; None/-1 means any connection
|
||||
(including connection ID zero). A channel restriction uses that connection's
|
||||
IRC comparator. None means any context; an empty string is an exact restriction.
|
||||
|
||||
C: the corresponding zoitechat_hook_*_filtered functions accept
|
||||
`(ph, name, pri, flags, connection_id, channel, callback, userdata)`;
|
||||
flags=0, ID=-1 for any and NULL channel for any. Check
|
||||
`get_info("api_context_filters")` for "1" before accessing the new Windows slots.
|
||||
|
||||
Filtering takes place before Python/interpreter entry. Existing unrestricted
|
||||
hooks, priority, EAT semantics and unload/unhook handling are unchanged.
|
||||
Filters refer to the core-selected context, not an IRC target parsed from the
|
||||
line: unknown queries/channels can still have a server-tab context, and QUIT
|
||||
has its usual single server-hook context. Connection IDs last only this process.
|
||||
|
||||
```python
|
||||
zoitechat.hook_print_filtered('Channel Message', callback,
|
||||
connection_id=zoitechat.get_prefs('id'), channel='#zoitechat')
|
||||
```
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Context restrictions evaluated by core before entering Python."""
|
||||
import operator
|
||||
import _zoitechat as api
|
||||
from _zoitechat_embedded import ffi, lib
|
||||
|
||||
__all__ = ['hook_server_filtered', 'hook_print_filtered']
|
||||
|
||||
|
||||
def _register(name, callback, userdata, priority, connection_id, channel, server):
|
||||
if not callable(callback):
|
||||
raise TypeError('callback must be callable')
|
||||
connection_id = -1 if connection_id is None else operator.index(connection_id)
|
||||
if connection_id < -1 or connection_id > 2147483647:
|
||||
raise ValueError('connection_id must fit the C API; -1 means any')
|
||||
plugin = api.__get_current_plugin()
|
||||
hook = plugin.add_hook(callback, userdata)
|
||||
register = lib.zoitechat_hook_server_filtered if server else lib.zoitechat_hook_print_filtered
|
||||
dispatch = lib._on_server_attrs_hook if server else lib._on_print_attrs_hook
|
||||
handle = register(lib.ph, name.encode(), priority, 0, connection_id,
|
||||
ffi.NULL if channel is None else channel.encode(), dispatch, hook.handle)
|
||||
if handle == ffi.NULL:
|
||||
hook.is_unload = True
|
||||
plugin.remove_hook(id(hook))
|
||||
raise RuntimeError('unable to install filtered hook')
|
||||
hook.zoitechat_hook = handle
|
||||
return id(hook)
|
||||
|
||||
|
||||
def hook_server_filtered(name, callback, userdata=None, priority=api.PRI_NORM,
|
||||
connection_id=None, channel=None):
|
||||
return _register(name, callback, userdata, priority, connection_id, channel, True)
|
||||
|
||||
|
||||
def hook_print_filtered(name, callback, userdata=None, priority=api.PRI_NORM,
|
||||
connection_id=None, channel=None):
|
||||
return _register(name, callback, userdata, priority, connection_id, channel, False)
|
||||
@@ -99,6 +99,9 @@ struct _zoitechat_hook
|
||||
int tag; /* for timers & FDs only */
|
||||
int type; /* HOOK_* */
|
||||
int pri; /* fd */ /* priority / fd for HOOK_FD only */
|
||||
int connection_filter;
|
||||
char *channel_filter;
|
||||
gboolean context_filtered;
|
||||
};
|
||||
|
||||
struct _zoitechat_list
|
||||
@@ -352,6 +355,8 @@ plugin_add (session *sess, char *filename, void *handle, void *init_func,
|
||||
pl->zoitechat_emit_print_attrs = zoitechat_emit_print_attrs;
|
||||
pl->zoitechat_event_attrs_create = zoitechat_event_attrs_create;
|
||||
pl->zoitechat_event_attrs_free = zoitechat_event_attrs_free;
|
||||
pl->zoitechat_hook_server_filtered = zoitechat_hook_server_filtered;
|
||||
pl->zoitechat_hook_print_filtered = zoitechat_hook_print_filtered;
|
||||
pl->zoitechat_hook_print_after = zoitechat_hook_print_after;
|
||||
|
||||
/* run zoitechat_plugin_init, if it returns 0, close the plugin */
|
||||
@@ -623,6 +628,15 @@ plugin_hook_run (session *sess, char *name, char *word[], char *word_eol[],
|
||||
|
||||
hook = list->data;
|
||||
next = list->next;
|
||||
if (hook->context_filtered &&
|
||||
(!is_session (sess) ||
|
||||
(hook->connection_filter != -1 && hook->connection_filter != sess->server->id) ||
|
||||
(hook->channel_filter && sess->server->p_cmp (hook->channel_filter, sess->channel))))
|
||||
{
|
||||
list = next;
|
||||
continue; /* filter in C before entering an interpreter */
|
||||
}
|
||||
|
||||
if (type == HOOK_PRINT_AFTER && hook->tag)
|
||||
{
|
||||
list = next;
|
||||
@@ -1052,6 +1066,8 @@ zoitechat_unhook (zoitechat_plugin *ph, zoitechat_hook *hook)
|
||||
|
||||
g_free (hook->name); /* NULL for timers & fds */
|
||||
g_free (hook->help_text); /* NULL for non-commands */
|
||||
g_free (hook->channel_filter);
|
||||
hook->channel_filter = NULL;
|
||||
|
||||
return hook->userdata;
|
||||
}
|
||||
@@ -1065,6 +1081,39 @@ zoitechat_hook_print_after (zoitechat_plugin *ph, const char *name, int pri,
|
||||
return plugin_add_hook (ph, HOOK_PRINT_AFTER, pri, name, NULL, callback, 0, userdata);
|
||||
}
|
||||
|
||||
static zoitechat_hook *
|
||||
plugin_add_filtered_hook (zoitechat_plugin *ph, const char *name, int pri,
|
||||
int flags, int connection_id, const char *channel,
|
||||
int type, void *callback, void *userdata)
|
||||
{
|
||||
zoitechat_hook *hook;
|
||||
if (flags != 0 || connection_id < -1 || !name || !callback)
|
||||
return NULL;
|
||||
hook = plugin_add_hook (ph, type, pri, name, NULL, callback, 0, userdata);
|
||||
hook->context_filtered = TRUE;
|
||||
hook->connection_filter = connection_id;
|
||||
hook->channel_filter = g_strdup (channel);
|
||||
return hook;
|
||||
}
|
||||
|
||||
zoitechat_hook *
|
||||
zoitechat_hook_server_filtered (zoitechat_plugin *ph, const char *name, int pri,
|
||||
int flags, int connection_id, const char *channel,
|
||||
zoitechat_serv_attrs_cb *callback, void *userdata)
|
||||
{
|
||||
return plugin_add_filtered_hook (ph, name, pri, flags, connection_id, channel,
|
||||
HOOK_SERVER_ATTRS, callback, userdata);
|
||||
}
|
||||
|
||||
zoitechat_hook *
|
||||
zoitechat_hook_print_filtered (zoitechat_plugin *ph, const char *name, int pri,
|
||||
int flags, int connection_id, const char *channel,
|
||||
zoitechat_print_attrs_cb *callback, void *userdata)
|
||||
{
|
||||
return plugin_add_filtered_hook (ph, name, pri, flags, connection_id, channel,
|
||||
HOOK_PRINT_ATTRS, callback, userdata);
|
||||
}
|
||||
|
||||
zoitechat_hook *
|
||||
zoitechat_hook_command (zoitechat_plugin *ph, const char *name, int pri,
|
||||
zoitechat_cmd_cb *callb, const char *help_text, void *userdata)
|
||||
@@ -1237,6 +1286,9 @@ zoitechat_get_info (zoitechat_plugin *ph, const char *id)
|
||||
if (strcmp (id, "api_hook_print_after") == 0)
|
||||
return "1";
|
||||
|
||||
if (strcmp (id, "api_context_filters") == 0)
|
||||
return "1";
|
||||
|
||||
hash = str_hash (id);
|
||||
/* do the session independant ones first */
|
||||
switch (hash)
|
||||
|
||||
@@ -212,6 +212,16 @@ zoitechat_hook *zoitechat_hook_print_after (zoitechat_plugin *ph,
|
||||
int (*callback) (char *word[], zoitechat_event_attrs *attrs, void *userdata),
|
||||
void *userdata);
|
||||
|
||||
/* api_context_filters=1: connection_id -1 is any; NULL channel is any. */
|
||||
zoitechat_hook *zoitechat_hook_server_filtered (zoitechat_plugin *ph,
|
||||
const char *name, int pri, int flags, int connection_id, const char *channel,
|
||||
int (*callback) (char *word[], char *word_eol[], zoitechat_event_attrs *attrs, void *userdata),
|
||||
void *userdata);
|
||||
zoitechat_hook *zoitechat_hook_print_filtered (zoitechat_plugin *ph,
|
||||
const char *name, int pri, int flags, int connection_id, const char *channel,
|
||||
int (*callback) (char *word[], zoitechat_event_attrs *attrs, void *userdata),
|
||||
void *userdata);
|
||||
|
||||
zoitechat_hook *
|
||||
zoitechat_hook_command (zoitechat_plugin *ph,
|
||||
const char *name,
|
||||
@@ -431,6 +441,8 @@ zoitechat_pluginpref_list (zoitechat_plugin *ph,
|
||||
#define zoitechat_hook_server ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server)
|
||||
#define zoitechat_hook_server_attrs ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server_attrs)
|
||||
#define zoitechat_hook_print ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print)
|
||||
#define zoitechat_hook_server_filtered ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server_filtered)
|
||||
#define zoitechat_hook_print_filtered ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print_filtered)
|
||||
#define zoitechat_hook_print_after ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print_after)
|
||||
#define zoitechat_hook_print_attrs ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print_attrs)
|
||||
#define zoitechat_hook_timer ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_timer)
|
||||
|
||||
Reference in New Issue
Block a user