diff --git a/extensions/invite_notify.c b/extensions/invite_notify.c index bc7c84f7..19708f90 100644 --- a/extensions/invite_notify.c +++ b/extensions/invite_notify.c @@ -13,7 +13,7 @@ static void m_invited(struct MsgBuf *, struct Client *, struct Client *, int, co static unsigned int CAP_INVITE_NOTIFY; mapi_hfn_list_av1 inv_notify_hfnlist[] = { - { "invite", hook_invite }, + { "invite", hook_invite, HOOK_MONITOR }, { NULL, NULL } }; diff --git a/extensions/m_webirc.c b/extensions/m_webirc.c index 04f59c96..2937189e 100644 --- a/extensions/m_webirc.c +++ b/extensions/m_webirc.c @@ -66,7 +66,8 @@ mapi_clist_av1 webirc_clist[] = { &webirc_msgtab, NULL }; static void new_local_user(void *data); mapi_hfn_list_av1 webirc_hfnlist[] = { - { "new_local_user", (hookfn) new_local_user }, + /* unintuitive but correct--we want to be called first */ + { "new_local_user", (hookfn) new_local_user, HOOK_LOWEST }, { NULL, NULL } }; diff --git a/extensions/override.c b/extensions/override.c index 20110a65..91b3d6eb 100644 --- a/extensions/override.c +++ b/extensions/override.c @@ -34,10 +34,10 @@ static void handle_client_exit(void *data); mapi_hfn_list_av1 override_hfnlist[] = { { "umode_changed", (hookfn) check_umode_change }, - { "get_channel_access", (hookfn) hack_channel_access }, - { "can_join", (hookfn) hack_can_join }, - { "can_kick", (hookfn) hack_can_kick }, - { "can_send", (hookfn) hack_can_send }, + { "get_channel_access", (hookfn) hack_channel_access, HOOK_HIGHEST }, + { "can_join", (hookfn) hack_can_join, HOOK_HIGHEST }, + { "can_kick", (hookfn) hack_can_kick, HOOK_HIGHEST }, + { "can_send", (hookfn) hack_can_send, HOOK_HIGHEST }, { "client_exit", (hookfn) handle_client_exit }, { NULL, NULL } }; diff --git a/extensions/override_kick_immunity.c b/extensions/override_kick_immunity.c index b6f7e518..df10ae8b 100644 --- a/extensions/override_kick_immunity.c +++ b/extensions/override_kick_immunity.c @@ -14,7 +14,7 @@ static const char override_kick_immunity_desc[] = static void can_kick(void *data); mapi_hfn_list_av1 override_kick_immunity_hfnlist[] = { - { "can_kick", (hookfn) can_kick }, + { "can_kick", (hookfn) can_kick, HOOK_HIGHEST }, { NULL, NULL } }; diff --git a/include/hook.h b/include/hook.h index 099eeec7..e185d46b 100644 --- a/include/hook.h +++ b/include/hook.h @@ -11,6 +11,16 @@ typedef struct rb_dlink_list hooks; } hook; +enum hook_priority +{ + HOOK_LOWEST = 10, + HOOK_LOW = 20, + HOOK_NORMAL = 30, + HOOK_HIGH = 40, + HOOK_HIGHEST = 50, + HOOK_MONITOR = 100 +}; + typedef void (*hookfn) (void *data); extern int h_iosend_id; @@ -39,6 +49,7 @@ extern int h_rehash; void init_hook(void); int register_hook(const char *name); void add_hook(const char *name, hookfn fn); +void add_hook_prio(const char *name, hookfn fn, enum hook_priority priority); void remove_hook(const char *name, hookfn fn); void call_hook(int id, void *arg); diff --git a/include/modules.h b/include/modules.h index 49539865..9a362c11 100644 --- a/include/modules.h +++ b/include/modules.h @@ -70,9 +70,9 @@ typedef struct { const char *hapi_name; hookfn fn; + enum hook_priority priority; } mapi_hfn_list_av1; - #define MAPI_CAP_CLIENT 1 #define MAPI_CAP_SERVER 2 diff --git a/ircd/hook.c b/ircd/hook.c index 70defd1c..2721a35c 100644 --- a/ircd/hook.c +++ b/ircd/hook.c @@ -42,6 +42,13 @@ hook *hooks; #define HOOK_INCREMENT 1000 +struct hook_entry +{ + rb_dlink_node node; + hookfn fn; + enum hook_priority priority; +}; + int num_hooks = 0; int last_hook = 0; int max_hooks = HOOK_INCREMENT; @@ -174,11 +181,34 @@ register_hook(const char *name) void add_hook(const char *name, hookfn fn) { + add_hook_prio(name, fn, HOOK_NORMAL); +} + +/* add_hook_prio() + * Adds a hook with the specified priority + */ +void +add_hook_prio(const char *name, hookfn fn, enum hook_priority priority) +{ + rb_dlink_node *ptr; + struct hook_entry *entry = rb_malloc(sizeof *entry); int i; i = register_hook(name); + entry->fn = fn; + entry->priority = priority; - rb_dlinkAddAlloc(fn, &hooks[i].hooks); + RB_DLINK_FOREACH(ptr, hooks[i].hooks.head) + { + struct hook_entry *o = ptr->data; + if (entry->priority <= o->priority) + { + rb_dlinkAddBefore(ptr, entry, &entry->node, &hooks[i].hooks); + return; + } + } + + rb_dlinkAddTail(entry, &entry->node, &hooks[i].hooks); } /* remove_hook() @@ -187,12 +217,21 @@ add_hook(const char *name, hookfn fn) void remove_hook(const char *name, hookfn fn) { + rb_dlink_node *ptr, *scratch; int i; if((i = find_hook(name)) < 0) return; - rb_dlinkFindDestroy(fn, &hooks[i].hooks); + RB_DLINK_FOREACH_SAFE(ptr, scratch, hooks[i].hooks.head) + { + struct hook_entry *entry = ptr->data; + if (entry->fn == fn) + { + rb_dlinkDelete(ptr, &hooks[i].hooks); + return; + } + } } /* call_hook() @@ -201,7 +240,6 @@ remove_hook(const char *name, hookfn fn) void call_hook(int id, void *arg) { - hookfn fn; rb_dlink_node *ptr; /* The ID we were passed is the position in the hook table of this @@ -209,8 +247,8 @@ call_hook(int id, void *arg) */ RB_DLINK_FOREACH(ptr, hooks[id].hooks.head) { - fn = ptr->data; - fn(arg); + struct hook_entry *entry = ptr->data; + entry->fn(arg); } } diff --git a/ircd/modules.c b/ircd/modules.c index 7a246cbe..6602a21d 100644 --- a/ircd/modules.c +++ b/ircd/modules.c @@ -586,7 +586,12 @@ load_a_module(const char *path, bool warn, int origin, bool core) { mapi_hfn_list_av1 *m; for (m = mheader->mapi_hfn_list; m->hapi_name; ++m) + { + int priority = m->priority; + if (priority == 0) + priority = HOOK_NORMAL; add_hook(m->hapi_name, m->fn); + } } /* New in MAPI v2 - version replacement */