mirror of
https://github.com/ZoiteChat/zoitechat.git
synced 2026-11-08 17:05:38 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66c93fe2e1 |
No files matched your search
@@ -1,35 +0,0 @@
|
|||||||
# Script-supported capabilities
|
|
||||||
|
|
||||||
`register_capability(name, userdata=None, connection_id=None)` returns a normal
|
|
||||||
hook handle. Register before connecting/reconnecting. Core requests the name only
|
|
||||||
if advertised in CAP LS or CAP NEW. Existing built-in requests remain enabled;
|
|
||||||
SASL and STS registration is rejected so scripts cannot change authentication or
|
|
||||||
transport policy through this API. None/-1 means any connection (zero is a valid
|
|
||||||
connection ID). Names are lowercase ASCII alphanumerics plus - . / _, 1-200 bytes.
|
|
||||||
Duplicate registrations do not duplicate requests for an advertised token.
|
|
||||||
|
|
||||||
`unhook(handle)` or script/plugin unload removes future request ownership. It
|
|
||||||
intentionally does not disable a capability already acknowledged on a live
|
|
||||||
connection, because another plugin/core may depend on it. Registering after CAP
|
|
||||||
LS does not retrospectively negotiate an already-advertised capability: reconnect
|
|
||||||
or wait for CAP NEW. Core retains ownership of CAP END; this API does not extend
|
|
||||||
SASL waiting or delay registration awaiting plugin-only CAP ACKs.
|
|
||||||
|
|
||||||
`hook_capability(name, callback, userdata=None, priority=PRI_NORM)` independently
|
|
||||||
observes negotiation through existing raw CAP hooks. Callback receives
|
|
||||||
`(CapabilityEvent, userdata)` with name, subcommand, value, enabled, context and
|
|
||||||
connection_id. LS/NEW mean advertised (`enabled=None`), ACK/LIST mean enabled
|
|
||||||
(unless a negative ACK), NAK means rejected and DEL means removed. Callback
|
|
||||||
returns are ignored so this observer cannot eat core negotiation. Existing raw
|
|
||||||
hooks may still eat CAP before this hook according to their normal priorities.
|
|
||||||
|
|
||||||
C: `zoitechat_register_capability(ph, name, flags, connection_id, userdata)`;
|
|
||||||
flags=0, ID=-1 for any. Check get_info("api_plugin_caps") for "1" before using
|
|
||||||
the appended Windows slot. Use existing server CAP hooks for notifications.
|
|
||||||
Requests are split at complete token boundaries within the existing wire limit.
|
|
||||||
|
|
||||||
```python
|
|
||||||
registration = zoitechat.register_capability('draft/example')
|
|
||||||
zoitechat.hook_capability('draft/example', lambda event, data:
|
|
||||||
event.context.prnt('{}: {}'.format(event.subcommand, event.enabled)))
|
|
||||||
```
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Python descriptor hooks
|
||||||
|
|
||||||
|
`hook_fd(fd, callback, userdata=None, flags=FD_READ)` returns an ordinary hook
|
||||||
|
handle accepted by `unhook()`. Callback arguments are `(fd, ready_flags, userdata)`;
|
||||||
|
return True to retain the watch and False/None to remove it. Exceptions print a
|
||||||
|
traceback and remove the watch. Unloading the script removes its watches.
|
||||||
|
The callback runs in the context captured during registration, and that context
|
||||||
|
is restored afterwards. A closed context removes the watch.
|
||||||
|
|
||||||
|
Use nonblocking IO and bounded reads/writes. The descriptor belongs to the script;
|
||||||
|
unhook before closing it. On Windows socket descriptors use the default flags;
|
||||||
|
CRT descriptors need FD_NOTSOCKET. The existing C API uses int descriptors: values
|
||||||
|
outside its range are rejected rather than truncated. This does not add threads.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```python
|
||||||
|
watch = zoitechat.hook_fd(sock.fileno(), on_readable, flags=zoitechat.FD_READ)
|
||||||
|
# def on_readable(fd, flags, userdata): ...; return True
|
||||||
|
```
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
"""Script-owned capability requests and structured negotiation observations."""
|
|
||||||
from collections import namedtuple
|
|
||||||
import operator
|
|
||||||
import _zoitechat as api
|
|
||||||
from _zoitechat_embedded import ffi, lib
|
|
||||||
|
|
||||||
__all__ = ['CapabilityEvent', 'register_capability', 'hook_capability']
|
|
||||||
CapabilityEvent = namedtuple('CapabilityEvent',
|
|
||||||
'name subcommand value enabled context connection_id')
|
|
||||||
|
|
||||||
|
|
||||||
def register_capability(name, userdata=None, connection_id=None):
|
|
||||||
"""Request an advertised capability on next negotiation; unhook releases ownership."""
|
|
||||||
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(None, userdata)
|
|
||||||
handle = lib.zoitechat_register_capability(lib.ph, name.encode(), 0,
|
|
||||||
connection_id, hook.handle)
|
|
||||||
if handle == ffi.NULL:
|
|
||||||
hook.is_unload = True
|
|
||||||
plugin.remove_hook(id(hook))
|
|
||||||
raise ValueError('invalid capability name, reserved capability or connection ID')
|
|
||||||
hook.zoitechat_hook = handle
|
|
||||||
return id(hook)
|
|
||||||
|
|
||||||
|
|
||||||
def hook_capability(name, callback, userdata=None, priority=api.PRI_NORM):
|
|
||||||
"""Observe LS/NEW/ACK/NAK/DEL/LIST; this hook does not itself request the capability."""
|
|
||||||
if not callable(callback):
|
|
||||||
raise TypeError('callback must be callable')
|
|
||||||
|
|
||||||
def dispatch(word, word_eol, data):
|
|
||||||
if not word_eol:
|
|
||||||
return api.EAT_NONE
|
|
||||||
line = word_eol[0]
|
|
||||||
if line.startswith(':'):
|
|
||||||
unused, separator, line = line.partition(' ')
|
|
||||||
parts = line.split(' ', 3)
|
|
||||||
if len(parts) != 4 or parts[0].upper() != 'CAP':
|
|
||||||
return api.EAT_NONE
|
|
||||||
subcommand, tokens = parts[2].upper(), parts[3]
|
|
||||||
if subcommand not in ('LS', 'NEW', 'ACK', 'NAK', 'DEL', 'LIST'):
|
|
||||||
return api.EAT_NONE
|
|
||||||
if tokens.startswith('* '):
|
|
||||||
tokens = tokens[2:]
|
|
||||||
tokens = tokens.lstrip(':')
|
|
||||||
for token in tokens.split():
|
|
||||||
negative = token.startswith('-')
|
|
||||||
cap, equals, value = token.lstrip('-').partition('=')
|
|
||||||
if cap != name:
|
|
||||||
continue
|
|
||||||
enabled = None
|
|
||||||
if subcommand in ('ACK', 'LIST'):
|
|
||||||
enabled = not negative
|
|
||||||
elif subcommand in ('DEL', 'NAK'):
|
|
||||||
enabled = False
|
|
||||||
event = CapabilityEvent(cap, subcommand, value if equals else None,
|
|
||||||
enabled, api.get_context(), api.get_prefs('id'))
|
|
||||||
callback(event, data)
|
|
||||||
return api.EAT_NONE # observing CAP must not suppress core negotiation
|
|
||||||
|
|
||||||
return api.hook_server('CAP', dispatch, userdata, priority)
|
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
"""File descriptor readiness hooks; callbacks execute on the main thread."""
|
||||||
|
import operator
|
||||||
|
import _zoitechat as api
|
||||||
|
from _zoitechat_embedded import ffi, lib
|
||||||
|
|
||||||
|
__all__ = ['FD_READ', 'FD_WRITE', 'FD_EXCEPTION', 'FD_NOTSOCKET', 'hook_fd']
|
||||||
|
FD_READ, FD_WRITE, FD_EXCEPTION, FD_NOTSOCKET = 1, 2, 4, 8
|
||||||
|
|
||||||
|
|
||||||
|
def hook_fd(fd, callback, userdata=None, flags=FD_READ):
|
||||||
|
"""callback(fd, ready_flags, userdata): True keeps the watch, False removes it."""
|
||||||
|
fd = operator.index(fd)
|
||||||
|
flags = operator.index(flags)
|
||||||
|
if fd < 0 or fd > 2147483647:
|
||||||
|
raise ValueError('fd must fit the C API nonnegative int descriptor')
|
||||||
|
if flags & ~15 or not flags & 7:
|
||||||
|
raise ValueError('flags must select READ, WRITE or EXCEPTION')
|
||||||
|
if not callable(callback):
|
||||||
|
raise TypeError('callback must be callable')
|
||||||
|
plugin = api.__get_current_plugin()
|
||||||
|
context = api.get_context()
|
||||||
|
|
||||||
|
def dispatch(descriptor, ready, data):
|
||||||
|
previous = api.get_context()
|
||||||
|
if not context.set():
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
return callback(descriptor, ready, data)
|
||||||
|
finally:
|
||||||
|
previous.set()
|
||||||
|
|
||||||
|
hook = plugin.add_hook(dispatch, userdata)
|
||||||
|
handle = lib.zoitechat_hook_fd(lib.ph, fd, flags, lib._on_fd_hook, hook.handle)
|
||||||
|
if handle == ffi.NULL:
|
||||||
|
hook.is_unload = True
|
||||||
|
plugin.remove_hook(id(hook))
|
||||||
|
raise RuntimeError('unable to watch descriptor')
|
||||||
|
hook.zoitechat_hook = handle
|
||||||
|
return id(hook)
|
||||||
@@ -38,6 +38,7 @@ extern "Python" int _on_print_attrs_hook(char **, zoitechat_event_attrs *, void
|
|||||||
extern "Python" int _on_server_hook(char **, char **, void *);
|
extern "Python" int _on_server_hook(char **, char **, void *);
|
||||||
extern "Python" int _on_server_attrs_hook(char **, char **, zoitechat_event_attrs *, void *);
|
extern "Python" int _on_server_attrs_hook(char **, char **, zoitechat_event_attrs *, void *);
|
||||||
extern "Python" int _on_timer_hook(void *);
|
extern "Python" int _on_timer_hook(void *);
|
||||||
|
extern "Python" int _on_fd_hook(int, int, void *);
|
||||||
|
|
||||||
extern "Python" int _on_plugin_init(char **, char **, char **, char *, char *);
|
extern "Python" int _on_plugin_init(char **, char **, char **, char *, char *);
|
||||||
extern "Python" int _on_plugin_deinit(void);
|
extern "Python" int _on_plugin_deinit(void);
|
||||||
|
|||||||
@@ -304,6 +304,28 @@ def _on_timer_hook(userdata):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.def_extern()
|
||||||
|
def _on_fd_hook(fd, flags, userdata):
|
||||||
|
hook = ffi.from_handle(userdata)
|
||||||
|
keep = False
|
||||||
|
try:
|
||||||
|
keep = bool(hook.callback(fd, flags, hook.userdata))
|
||||||
|
except Exception:
|
||||||
|
traceback.print_exc()
|
||||||
|
if not keep:
|
||||||
|
# The C watch removes itself on return; do not unhook it a second time.
|
||||||
|
try:
|
||||||
|
hook.is_unload = True
|
||||||
|
# from_handle() yields a weak proxy: id(proxy) is not id(Hook).
|
||||||
|
for existing in hook.plugin.hooks:
|
||||||
|
if existing == hook:
|
||||||
|
hook.plugin.remove_hook(id(existing))
|
||||||
|
break
|
||||||
|
except ReferenceError:
|
||||||
|
pass # the callback already unhooked itself
|
||||||
|
return int(keep)
|
||||||
|
|
||||||
|
|
||||||
@ffi.def_extern()
|
@ffi.def_extern()
|
||||||
def _on_say_command(word, word_eol, userdata):
|
def _on_say_command(word, word_eol, userdata):
|
||||||
"""Handle input in the special >>python<< tab.
|
"""Handle input in the special >>python<< tab.
|
||||||
|
|||||||
+20
-86
@@ -41,8 +41,6 @@
|
|||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "outbound.h"
|
#include "outbound.h"
|
||||||
#include <gmodule.h>
|
|
||||||
#include "plugin.h"
|
|
||||||
#include "inbound.h"
|
#include "inbound.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "servlist.h"
|
#include "servlist.h"
|
||||||
@@ -1982,22 +1980,6 @@ inbound_cap_ack (server *serv, char *nick, char *extensions,
|
|||||||
inbound_toggle_caps (serv, extensions, TRUE);
|
inbound_toggle_caps (serv, extensions, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep CAP REQ tokens intact and below the existing 500-byte buffer. */
|
|
||||||
static void
|
|
||||||
inbound_cap_request_append (server *serv, char *buffer, gsize size,
|
|
||||||
const char *name, time_t timestamp)
|
|
||||||
{
|
|
||||||
if (strlen (buffer) + strlen (name) + 1 >= size)
|
|
||||||
{
|
|
||||||
EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPREQ, serv->server_session,
|
|
||||||
buffer + 9, NULL, NULL, NULL, 0, timestamp);
|
|
||||||
tcp_sendf (serv, "%s\r\n", g_strchomp (buffer));
|
|
||||||
g_strlcpy (buffer, "CAP REQ :", size);
|
|
||||||
}
|
|
||||||
g_strlcat (buffer, name, size);
|
|
||||||
g_strlcat (buffer, " ", size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void inbound_request_new_caps (server *serv, const char *extensions_str,
|
static void inbound_request_new_caps (server *serv, const char *extensions_str,
|
||||||
const message_tags_data *tags_data);
|
const message_tags_data *tags_data);
|
||||||
|
|
||||||
@@ -2113,32 +2095,6 @@ inbound_request_new_caps (server *serv, const char *extensions_str,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Also request plugin-owned capabilities, without repeating core requests. */
|
|
||||||
for (i = 0; extensions[i]; i++)
|
|
||||||
{
|
|
||||||
gsize previous;
|
|
||||||
gboolean builtin = FALSE;
|
|
||||||
for (x = 0; x < G_N_ELEMENTS (supported_caps); x++)
|
|
||||||
{
|
|
||||||
if (!strcmp (extensions[i], supported_caps[x]))
|
|
||||||
{
|
|
||||||
builtin = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (builtin || !plugin_requests_capability (serv, extensions[i]))
|
|
||||||
continue;
|
|
||||||
for (previous = 0; previous < i; previous++)
|
|
||||||
{
|
|
||||||
if (!strcmp (extensions[previous], extensions[i]))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (previous != i)
|
|
||||||
continue;
|
|
||||||
EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPREQ, serv->server_session,
|
|
||||||
extensions[i], NULL, NULL, NULL, 0, tags_data->timestamp);
|
|
||||||
tcp_sendf (serv, "CAP REQ :%s\r\n", extensions[i]);
|
|
||||||
}
|
|
||||||
g_strfreev (extensions);
|
g_strfreev (extensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2205,8 +2161,6 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
|
|||||||
gboolean want_cap = FALSE; /* format the CAP REQ string based on previous capabilities being requested or not */
|
gboolean want_cap = FALSE; /* format the CAP REQ string based on previous capabilities being requested or not */
|
||||||
gboolean sts_upgrade_triggered = FALSE;
|
gboolean sts_upgrade_triggered = FALSE;
|
||||||
char **extensions;
|
char **extensions;
|
||||||
GString *requests = g_string_new (NULL);
|
|
||||||
GHashTable *seen = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (g_str_has_prefix (extensions_str, "* "))
|
if (g_str_has_prefix (extensions_str, "* "))
|
||||||
@@ -2272,56 +2226,36 @@ inbound_cap_ls (server *serv, char *nick, char *extensions_str,
|
|||||||
}
|
}
|
||||||
want_cap = TRUE;
|
want_cap = TRUE;
|
||||||
serv->waiting_on_sasl = TRUE;
|
serv->waiting_on_sasl = TRUE;
|
||||||
if (g_hash_table_add (seen, g_strdup ("sasl")))
|
g_strlcat (buffer, "sasl ", sizeof(buffer));
|
||||||
g_string_append (requests, "sasl ");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (x = 0; x < G_N_ELEMENTS (supported_caps); ++x)
|
for (x = 0; x < G_N_ELEMENTS(supported_caps); ++x)
|
||||||
{
|
{
|
||||||
if (!g_strcmp0 (extension, supported_caps[x]))
|
if (!g_strcmp0 (extension, supported_caps[x]))
|
||||||
break;
|
{
|
||||||
}
|
g_strlcat (buffer, extension, sizeof(buffer));
|
||||||
if (x < G_N_ELEMENTS (supported_caps) ||
|
g_strlcat (buffer, " ", sizeof(buffer));
|
||||||
plugin_requests_capability (serv, extension))
|
want_cap = TRUE;
|
||||||
{
|
}
|
||||||
if (g_hash_table_add (seen, g_strdup (extension)))
|
}
|
||||||
{
|
|
||||||
g_string_append (requests, extension);
|
|
||||||
g_string_append_c (requests, ' ');
|
|
||||||
want_cap = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_strfreev (extensions);
|
g_strfreev (extensions);
|
||||||
|
|
||||||
if (sts_upgrade_triggered)
|
if (sts_upgrade_triggered)
|
||||||
{
|
{
|
||||||
g_hash_table_destroy (seen);
|
return;
|
||||||
g_string_free (requests, TRUE);
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (want_cap)
|
if (want_cap)
|
||||||
{
|
{
|
||||||
char **tokens = g_strsplit (requests->str, " ", 0);
|
/* buffer + 9 = emit buffer without "CAP REQ :" */
|
||||||
for (i = 0; tokens[i]; i++)
|
EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPREQ, serv->server_session,
|
||||||
{
|
buffer + 9, NULL, NULL, NULL, 0,
|
||||||
if (tokens[i][0])
|
tags_data->timestamp);
|
||||||
inbound_cap_request_append (serv, buffer, sizeof (buffer),
|
tcp_sendf (serv, "%s\r\n", g_strchomp (buffer));
|
||||||
tokens[i], tags_data->timestamp);
|
}
|
||||||
}
|
|
||||||
g_strfreev (tokens);
|
|
||||||
if (buffer[9])
|
|
||||||
{
|
|
||||||
EMIT_SIGNAL_TIMESTAMP (XP_TE_CAPREQ, serv->server_session,
|
|
||||||
buffer + 9, NULL, NULL, NULL, 0, tags_data->timestamp);
|
|
||||||
tcp_sendf (serv, "%s\r\n", g_strchomp (buffer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_hash_table_destroy (seen);
|
|
||||||
g_string_free (requests, TRUE);
|
|
||||||
if (!serv->waiting_on_sasl && !serv->waiting_on_cap)
|
if (!serv->waiting_on_sasl && !serv->waiting_on_cap)
|
||||||
{
|
{
|
||||||
/* if we use SASL, CAP END is dealt via raw numerics */
|
/* if we use SASL, CAP END is dealt via raw numerics */
|
||||||
|
|||||||
+1
-42
@@ -99,7 +99,6 @@ struct _zoitechat_hook
|
|||||||
int tag; /* for timers & FDs only */
|
int tag; /* for timers & FDs only */
|
||||||
int type; /* HOOK_* */
|
int type; /* HOOK_* */
|
||||||
int pri; /* fd */ /* priority / fd for HOOK_FD only */
|
int pri; /* fd */ /* priority / fd for HOOK_FD only */
|
||||||
int cap_connection_id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _zoitechat_list
|
struct _zoitechat_list
|
||||||
@@ -144,8 +143,7 @@ enum
|
|||||||
HOOK_PRINT_ATTRS = 1 << 4, /* same as above, with attributes */
|
HOOK_PRINT_ATTRS = 1 << 4, /* same as above, with attributes */
|
||||||
HOOK_TIMER = 1 << 5, /* timeouts */
|
HOOK_TIMER = 1 << 5, /* timeouts */
|
||||||
HOOK_FD = 1 << 6, /* sockets & fds */
|
HOOK_FD = 1 << 6, /* sockets & fds */
|
||||||
HOOK_DELETED = 1 << 7, /* marked for deletion */
|
HOOK_DELETED = 1 << 7 /* marked for deletion */
|
||||||
HOOK_CAPABILITY = 1 << 9 /* script-owned CAP requests */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@@ -353,7 +351,6 @@ plugin_add (session *sess, char *filename, void *handle, void *init_func,
|
|||||||
pl->zoitechat_emit_print_attrs = zoitechat_emit_print_attrs;
|
pl->zoitechat_emit_print_attrs = zoitechat_emit_print_attrs;
|
||||||
pl->zoitechat_event_attrs_create = zoitechat_event_attrs_create;
|
pl->zoitechat_event_attrs_create = zoitechat_event_attrs_create;
|
||||||
pl->zoitechat_event_attrs_free = zoitechat_event_attrs_free;
|
pl->zoitechat_event_attrs_free = zoitechat_event_attrs_free;
|
||||||
pl->zoitechat_register_capability = zoitechat_register_capability;
|
|
||||||
|
|
||||||
/* run zoitechat_plugin_init, if it returns 0, close the plugin */
|
/* run zoitechat_plugin_init, if it returns 0, close the plugin */
|
||||||
if (((zoitechat_init_func *)init_func) (pl, &pl->name, &pl->desc, &pl->version, arg) == 0)
|
if (((zoitechat_init_func *)init_func) (pl, &pl->name, &pl->desc, &pl->version, arg) == 0)
|
||||||
@@ -1031,41 +1028,6 @@ zoitechat_unhook (zoitechat_plugin *ph, zoitechat_hook *hook)
|
|||||||
return hook->userdata;
|
return hook->userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
zoitechat_hook *
|
|
||||||
zoitechat_register_capability (zoitechat_plugin *ph, const char *name, int flags,
|
|
||||||
int connection_id, void *userdata)
|
|
||||||
{
|
|
||||||
const unsigned char *p;
|
|
||||||
zoitechat_hook *hook;
|
|
||||||
if (flags != 0 || connection_id < -1 || !name || !name[0] || strlen (name) > 200 ||
|
|
||||||
strcmp (name, "sasl") == 0 || strcmp (name, "sts") == 0)
|
|
||||||
return NULL;
|
|
||||||
for (p = (const unsigned char *)name; *p; p++)
|
|
||||||
{
|
|
||||||
if (!g_ascii_islower (*p) && !g_ascii_isdigit (*p) &&
|
|
||||||
*p != '-' && *p != '.' && *p != '/' && *p != '_')
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
hook = plugin_add_hook (ph, HOOK_CAPABILITY, 0, name, NULL, NULL, 0, userdata);
|
|
||||||
hook->cap_connection_id = connection_id;
|
|
||||||
return hook;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
plugin_requests_capability (server *serv, const char *name)
|
|
||||||
{
|
|
||||||
GSList *entry;
|
|
||||||
for (entry = hook_list; entry; entry = entry->next)
|
|
||||||
{
|
|
||||||
zoitechat_hook *hook = entry->data;
|
|
||||||
if (hook && hook->type == HOOK_CAPABILITY &&
|
|
||||||
(hook->cap_connection_id == -1 || hook->cap_connection_id == serv->id) &&
|
|
||||||
strcmp (hook->name, name) == 0)
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
zoitechat_hook *
|
zoitechat_hook *
|
||||||
zoitechat_hook_command (zoitechat_plugin *ph, const char *name, int pri,
|
zoitechat_hook_command (zoitechat_plugin *ph, const char *name, int pri,
|
||||||
zoitechat_cmd_cb *callb, const char *help_text, void *userdata)
|
zoitechat_cmd_cb *callb, const char *help_text, void *userdata)
|
||||||
@@ -1225,9 +1187,6 @@ zoitechat_get_info (zoitechat_plugin *ph, const char *id)
|
|||||||
return text_find_format_string (e);
|
return text_find_format_string (e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp (id, "api_plugin_caps") == 0)
|
|
||||||
return "1";
|
|
||||||
|
|
||||||
hash = str_hash (id);
|
hash = str_hash (id);
|
||||||
/* do the session independant ones first */
|
/* do the session independant ones first */
|
||||||
switch (hash)
|
switch (hash)
|
||||||
|
|||||||
@@ -183,7 +183,6 @@ int plugin_emit_command (session *sess, char *name, char *word[], char *word_eol
|
|||||||
int plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[],
|
int plugin_emit_server (session *sess, char *name, char *word[], char *word_eol[],
|
||||||
time_t server_time);
|
time_t server_time);
|
||||||
int plugin_emit_print (session *sess, char *word[], time_t server_time);
|
int plugin_emit_print (session *sess, char *word[], time_t server_time);
|
||||||
gboolean plugin_requests_capability (server *serv, const char *name);
|
|
||||||
int plugin_emit_dummy_print (session *sess, char *name);
|
int plugin_emit_dummy_print (session *sess, char *name);
|
||||||
int plugin_emit_keypress (session *sess, unsigned int state, unsigned int keyval, gunichar key);
|
int plugin_emit_keypress (session *sess, unsigned int state, unsigned int keyval, gunichar key);
|
||||||
GList* plugin_command_list(GList *tmp_list);
|
GList* plugin_command_list(GList *tmp_list);
|
||||||
|
|||||||
@@ -206,10 +206,6 @@ struct _zoitechat_plugin
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* api_plugin_caps=1: register before CAP LS; flags=0, connection_id=-1 for any. */
|
|
||||||
zoitechat_hook *zoitechat_register_capability (zoitechat_plugin *ph,
|
|
||||||
const char *name, int flags, int connection_id, void *userdata);
|
|
||||||
|
|
||||||
zoitechat_hook *
|
zoitechat_hook *
|
||||||
zoitechat_hook_command (zoitechat_plugin *ph,
|
zoitechat_hook_command (zoitechat_plugin *ph,
|
||||||
const char *name,
|
const char *name,
|
||||||
@@ -429,7 +425,6 @@ zoitechat_pluginpref_list (zoitechat_plugin *ph,
|
|||||||
#define zoitechat_hook_server ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server)
|
#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_server_attrs ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_server_attrs)
|
||||||
#define zoitechat_hook_print ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print)
|
#define zoitechat_hook_print ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print)
|
||||||
#define zoitechat_register_capability ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_register_capability)
|
|
||||||
#define zoitechat_hook_print_attrs ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print_attrs)
|
#define zoitechat_hook_print_attrs ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_print_attrs)
|
||||||
#define zoitechat_hook_timer ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_timer)
|
#define zoitechat_hook_timer ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_timer)
|
||||||
#define zoitechat_hook_fd ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_fd)
|
#define zoitechat_hook_fd ((ZOITECHAT_PLUGIN_HANDLE)->zoitechat_hook_fd)
|
||||||
|
|||||||
Reference in new issue
Block a user