diff --git a/include/hook.h b/include/hook.h index 58a94d41..099eeec7 100644 --- a/include/hook.h +++ b/include/hook.h @@ -95,6 +95,7 @@ typedef struct int approved; int dir; const char *modestr; + const char *error; } hook_data_channel_approval; typedef struct diff --git a/modules/m_invite.c b/modules/m_invite.c index 63645e2b..044c72f5 100644 --- a/modules/m_invite.c +++ b/modules/m_invite.c @@ -48,14 +48,22 @@ struct Message invite_msgtab = { {mg_unreg, {m_invite, 3}, {m_invite, 3}, mg_ignore, mg_ignore, {m_invite, 3}} }; +static int can_invite_hook; +static int invite_hook; + mapi_clist_av1 invite_clist[] = { &invite_msgtab, NULL }; +mapi_hlist_av1 invite_hlist[] = { + { "can_invite", &can_invite_hook }, + { "invite", &invite_hook }, + { NULL, NULL } +}; mapi_cap_list_av2 invite_cap_list[] = { { MAPI_CAP_CLIENT, "invite-notify", NULL, &CAP_INVITE_NOTIFY }, { 0, NULL, NULL, NULL } }; -DECLARE_MODULE_AV2(invite, NULL, NULL, invite_clist, NULL, NULL, invite_cap_list, NULL, invite_desc); +DECLARE_MODULE_AV2(invite, NULL, NULL, invite_clist, invite_hlist, NULL, invite_cap_list, NULL, invite_desc); static bool add_invite(struct Channel *, struct Client *); @@ -70,6 +78,7 @@ m_invite(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source struct Channel *chptr; struct membership *msptr; int store_invite = 0; + hook_data_channel_approval hdata = { 0 }; if(MyClient(source_p) && !IsFloodDone(source_p)) flood_endgrace(source_p); @@ -142,14 +151,24 @@ m_invite(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source return; } - /* unconditionally require ops, unless the channel is +g */ - /* treat remote clients as chanops */ - if(MyClient(source_p) && !is_chanop(msptr) && - !(chptr->mode.mode & MODE_FREEINVITE)) + if (MyClient(source_p)) { - sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), - me.name, source_p->name, parv[2]); - return; + hdata.chptr = chptr; + hdata.msptr = msptr; + hdata.client = source_p; + hdata.target = target_p; + hdata.approved = !(is_chanop(msptr) || (chptr->mode.mode & MODE_FREEINVITE)); + + call_hook(can_invite_hook, &hdata); + if (hdata.approved) + { + if (hdata.error) + sendto_one_numeric(source_p, hdata.approved, "%s", hdata.error); + else + sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED), + me.name, source_p->name, parv[2]); + return; + } } /* store invites when they could affect the ability to join @@ -214,6 +233,22 @@ m_invite(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source target_p->localClient->last_caller_id_time = rb_current_time(); } } + + hdata.chptr = chptr; + hdata.msptr = msptr; + hdata.client = source_p; + hdata.target = target_p; + hdata.approved = 0; + + call_hook(invite_hook, &hdata); + + if (hdata.approved) + { + if (hdata.error) + sendto_one_numeric(source_p, hdata.approved, "%s", hdata.error); + return; + } + add_reply_target(target_p, source_p); sendto_one(target_p, ":%s!%s@%s INVITE %s :%s", source_p->name, source_p->username, source_p->host,