diff --git a/doc/sphinx_source/using/tcl-commands.rst b/doc/sphinx_source/using/tcl-commands.rst index 0fbbecb6df..6e2f3b460a 100644 --- a/doc/sphinx_source/using/tcl-commands.rst +++ b/doc/sphinx_source/using/tcl-commands.rst @@ -2900,6 +2900,13 @@ language Module: core +^^^^^^^^^^^^^^ +account-extban +^^^^^^^^^^^^^^ + Value: a string containing the value of ACCOUNTEXTBAN provided by the 005 connection message. This is the raw value and, depending on the IRC server formatting, could be in multiple formats such as "a", or "a,account". + + Module: channel + Binds ----- diff --git a/eggdrop.conf b/eggdrop.conf index bed1f7a5c2..49dfe648ae 100755 --- a/eggdrop.conf +++ b/eggdrop.conf @@ -1266,7 +1266,8 @@ set stack-limit 4 # Sets the default RPL_ISUPPORT (raw 005) information to use as a fallback. # These MUST be compatible to all IRCds you might want to connect to. # The actual server settings overwrite these, so you shouldn't need to modify. -#set isupport-default "CASEMAPPING=rfc1459 CHANNELLEN=80 NICKLEN=9 CHANTYPES=#& PREFIX=(ov)@+ CHANMODES=b,k,l,imnpst MODES=3 MAXCHANNELS=10 TOPICLEN=250 KICKLEN=250 STATUSMSG=@+" +#set isupport-default "CASEMAPPING=rfc1459 CHANNELLEN=80 NICKLEN=9 CHANTYPES=#& PREFIX=(ov)@+ CHANMODES=b,k,l,imnpst MODES=3 MAXCHANNELS=10 TOPICLEN=250 KICKLEN=250 STATUSMSG=@+ EXTBAN=~,ar ACCOUNTEXTBAN=a" + ### SERVER MODULE - OTHER NETWORKS (net-type "Other") ### diff --git a/src/mod/channels.mod/channels.c b/src/mod/channels.mod/channels.c index cb099f6cae..78db2587d3 100644 --- a/src/mod/channels.mod/channels.c +++ b/src/mod/channels.mod/channels.c @@ -28,9 +28,11 @@ #include "src/mod/module.h" static Function *global = NULL; - +static void get_extban_prefix(char *prefix); +static int is_extban_mask(const char *mask); static char chanfile[121], glob_chanmode[65]; static char *lastdeletedmask; +const char *isupport_get(const char *name, size_t len); static p_tcl_bind_list H_chanset; @@ -55,6 +57,73 @@ static int gfld_chan_thr, gfld_chan_time, gfld_deop_thr, gfld_deop_time, #include "userchan.c" #include "udefchan.c" +/* Parse extban mask into type and arg pointers. + * Supports both prefixed (:) and non-prefixed (:) forms. + */ +int extban_parse(const char *mask, char *type, const char **arg) +{ + if (!mask || !mask[0]) + return 0; + +/* Break out no-prefix mask */ + if (isalnum((unsigned char) mask[0]) && mask[1] == ':') { + if (type) + *type = mask[0]; + if (arg) + *arg = mask + 2; + return 1; + } + +/* Break out prefix mask */ + if (mask[0] && isalnum((unsigned char) mask[1]) && mask[2] == ':') { + if (type) + *type = mask[1]; + if (arg) + *arg = mask + 3; + return 1; + } + + return 0; +} + +/* Return 1 if mask uses extban syntax. */ +static int is_extban_mask(const char *mask) +{ + return extban_parse(mask, NULL, NULL); +} + +/* Extban prefix from ISUPPORT EXTBAN, if present. + * EXTBAN grammar is [prefix], + */ +static void get_extban_prefix(char *prefix) +{ + const char *value, *comma; + + /* Clear out old value */ + if (prefix) { + *prefix = '\0'; + } + value = isupport_get("EXTBAN", strlen("EXTBAN")); + if (!value || !value[0]) { + //TO DO: log issue to partyline + return; + } + comma = strchr(value, ','); + if (comma) { + if (comma == value) { + // No prefix + return; + } + if ((comma - value) == 1) { + if (prefix) + *prefix = value[0]; + // Prefix + return; + } + } + // What do we do if no , present? + return; +} static void *channel_malloc(int size, char *file, int line) { @@ -801,6 +870,23 @@ static char *traced_globchanset(ClientData cdata, Tcl_Interp *irp, return NULL; } +static char *traced_account_extban(ClientData cdata, Tcl_Interp *irp, + EGG_CONST char *name1, + EGG_CONST char *name2, int flags) +{ + const char *account_extban = isupport_get("ACCOUNTEXTBAN", strlen("ACCOUNTEXTBAN")); + + Tcl_SetVar2(interp, name1, name2, + (account_extban && account_extban[0]) ? account_extban : "", + TCL_GLOBAL_ONLY); + if (flags & TCL_TRACE_UNSETS) { + Tcl_TraceVar(interp, "account-extban", + TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, + traced_account_extban, NULL); + } + return NULL; +} + static tcl_ints my_tcl_ints[] = { {"use-info", &use_info, 0}, {"quiet-save", &quiet_save, 0}, @@ -879,6 +965,10 @@ static char *channels_close() Tcl_UntraceVar(interp, "default-chanset", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_globchanset, NULL); + Tcl_UntraceVar(interp, "account-extban", + TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, + traced_account_extban, NULL); + traced_account_extban(NULL, interp, "account-extban", NULL, TCL_TRACE_READS); rem_help_reference("channels.help"); rem_help_reference("chaninfo.help"); module_undepend(MODULE_NAME); @@ -950,6 +1040,7 @@ static Function channels_table[] = { (Function) & global_exempt_time, /* 48 - 51 */ (Function) & global_invite_time, + (Function) extban_parse, }; char *channels_start(Function *global_funcs) @@ -1030,6 +1121,9 @@ char *channels_start(Function *global_funcs) Tcl_TraceVar(interp, "default-chanset", TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, traced_globchanset, NULL); + Tcl_TraceVar(interp, "account-extban", + TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS, + traced_account_extban, NULL); H_chanset = add_bind_table("chanset", HT_STACKABLE, builtin_chanset); add_builtins(H_chon, my_chon); add_builtins(H_dcc, C_dcc_irc); diff --git a/src/mod/channels.mod/channels.h b/src/mod/channels.mod/channels.h index 86f19a08bb..84d01cbce6 100644 --- a/src/mod/channels.mod/channels.h +++ b/src/mod/channels.mod/channels.h @@ -65,6 +65,15 @@ struct udef_struct { * structures. */ }; +/* List of extban flags that Eggdrop can actively enforce. + * Any extban flag not in this list is treated as sticky by default. + */ +static int extban_is_enforceable_flag(char flag, char account_extban_flag) +{ + return (flag == 'U' || (account_extban_flag && flag == account_extban_flag)); +} + + static void del_chanrec(struct userrec *u, char *); static struct chanuserrec *get_chanrec(struct userrec *u, char *chname); static struct chanuserrec *add_chanrec(struct userrec *u, char *chname); @@ -180,6 +189,7 @@ static int check_tcl_chanset(const char *, const char *, const char *); #define global_exempt_time (*(int *)(channels_funcs[47])) /* 48 - 51 */ #define global_invite_time (*(int *)(channels_funcs[48])) +#define extban_parse ((int (*)(const char *, char *, const char **))channels_funcs[49]) #endif /* MAKING_CHANNELS */ diff --git a/src/mod/channels.mod/cmdschan.c b/src/mod/channels.mod/cmdschan.c index 4eb05aa0c1..1c81c39453 100644 --- a/src/mod/channels.mod/cmdschan.c +++ b/src/mod/channels.mod/cmdschan.c @@ -22,7 +22,7 @@ static struct flag_record user = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; static struct flag_record victim = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; - +int extban_parse(const char *mask, char *type, const char **arg); /* RFC 1035/2812- hostmasks can't be longer than 63 characters */ static void truncate_mask_hostname(char *s) { @@ -41,6 +41,10 @@ static void truncate_mask_hostname(char *s) { static void cmd_pls_ban(struct userrec *u, int idx, char *par) { char *chname, *who, s[UHOSTLEN], s1[UHOSTLEN], *p, *p_expire; + char extbanflag = 0, account_extban_flag = 0; + int extban_enabled = 1; + int extban_default_sticky = 0; + const char *value, *comma, *types, *extbanargs; long expire_foo; unsigned long expire_time = 0; int sticky = 0; @@ -121,32 +125,56 @@ static void cmd_pls_ban(struct userrec *u, int idx, char *par) par[MASKREASON_MAX] = 0; if (strlen(who) > UHOSTMAX - 4) who[UHOSTMAX - 4] = 0; - /* Fix missing ! or @ BEFORE checking against myself */ - if (!strchr(who, '!')) { - if (!strchr(who, '@')) - egg_snprintf(s, sizeof s, "%s!*@*", who); /* Lame nick ban */ - else - egg_snprintf(s, sizeof s, "*!%s", who); - } else if (!strchr(who, '@')) - egg_snprintf(s, sizeof s, "%s@*", who); /* brain-dead? */ - else + if (is_extban_mask(who)) { strlcpy(s, who, sizeof s); - if ((me = module_find("server", 0, 0)) && me->funcs) { - egg_snprintf(s1, sizeof s1, "%s!%s", me->funcs[SERVER_BOTNAME], - me->funcs[SERVER_BOTUSERHOST]); - if (match_addr(s, s1)) { - dprintf(idx, "I'm not going to ban myself.\n"); - putlog(LOG_CMDS, "*", "#%s# attempted +ban %s", dcc[idx].nick, s); - return; + /* If its an extban, check if it needs to be set as a sticky ban */ + if (extban_parse(s, &extbanflag, &extbanargs)) { + const char *account_extban; + + account_extban = isupport_get("ACCOUNTEXTBAN", strlen("ACCOUNTEXTBAN")); + if (account_extban && account_extban[0]) + account_extban_flag = account_extban[0]; + extban_default_sticky = !extban_is_enforceable_flag(extbanflag, account_extban_flag); + if (extban_default_sticky) + sticky = 1; + value = isupport_get("EXTBAN", strlen("EXTBAN")); + if (value && value[0]) { + comma = strchr(value, ','); + types = comma ? comma + 1 : value; + extban_enabled = strchr(types, extbanflag) ? 1 : 0; + } else { + extban_enabled = 0; + } + } + } else { + /* Fix missing ! or @ BEFORE checking against myself */ + if (!strchr(who, '!')) { + if (!strchr(who, '@')) + egg_snprintf(s, sizeof s, "%s!*@*", who); /* Lame nick ban */ + else + egg_snprintf(s, sizeof s, "*!%s", who); + } else if (!strchr(who, '@')) + egg_snprintf(s, sizeof s, "%s@*", who); /* brain-dead? */ + else + strlcpy(s, who, sizeof s); + if ((me = module_find("server", 0, 0)) && me->funcs) { + egg_snprintf(s1, sizeof s1, "%s!%s", me->funcs[SERVER_BOTNAME], + me->funcs[SERVER_BOTUSERHOST]); + if (match_addr(s, s1)) { + dprintf(idx, "I'm not going to ban myself.\n"); + putlog(LOG_CMDS, "*", "#%s# attempted +ban %s", dcc[idx].nick, s); + return; + } } + truncate_mask_hostname(s); } - truncate_mask_hostname(s); if (chan) { u_addban(chan, s, dcc[idx].nick, par, expire_time ? now + expire_time : 0, 0); - if (par[0] == '*') { + if (par[0] == '*' || extban_default_sticky) { sticky = 1; - par++; + if (par[0] == '*') + par++; putlog(LOG_CMDS, "*", "#%s# (%s) +ban %s %s (%s) (sticky)", dcc[idx].nick, dcc[idx].u.chat->con_chan, s, chan->dname, par); dprintf(idx, "New %s sticky ban: %s (%s)\n", chan->dname, s, par); @@ -158,14 +186,19 @@ static void cmd_pls_ban(struct userrec *u, int idx, char *par) /* Avoid unnesessary modes if you got +dynamicbans, and there is * no reason to set mode if irc.mod aint loaded. (dw 001120) */ - if ((me = module_find("irc", 0, 0))) - (me->funcs[IRC_CHECK_THIS_BAN]) (chan, s, sticky); + if ((me = module_find("irc", 0, 0))) { + if (!extbanflag || extban_enabled) + (me->funcs[IRC_CHECK_THIS_BAN]) (chan, s, sticky || extban_default_sticky); + else + dprintf(idx, "The %c extban is not enabled on this server. Eggdrop will save this ban but only set it when on a server that has the %c flag enabled.\n", extbanflag, extbanflag); + } } else { u_addban(NULL, s, dcc[idx].nick, par, expire_time ? now + expire_time : 0, 0); - if (par[0] == '*') { + if (par[0] == '*' || extban_default_sticky) { sticky = 1; - par++; + if (par[0] == '*') + par++; putlog(LOG_CMDS, "*", "#%s# (GLOBAL) +ban %s (%s) (sticky)", dcc[idx].nick, s, par); dprintf(idx, "New sticky ban: %s (%s)\n", s, par); @@ -174,13 +207,49 @@ static void cmd_pls_ban(struct userrec *u, int idx, char *par) s, par); dprintf(idx, "New ban: %s (%s)\n", s, par); } - if ((me = module_find("irc", 0, 0))) - for (chan = chanset; chan != NULL; chan = chan->next) - (me->funcs[IRC_CHECK_THIS_BAN]) (chan, s, sticky); + if ((me = module_find("irc", 0, 0))) { + if (!extbanflag || extban_enabled) { + for (chan = chanset; chan != NULL; chan = chan->next) + (me->funcs[IRC_CHECK_THIS_BAN]) (chan, s, sticky || extban_default_sticky); + } else + dprintf(idx, "The %c extban is not enabled on this server. Eggdrop will save this ban but only set it when on a server that has the %c flag enabled.\n", extbanflag, extbanflag); + } } } } + +static void cmd_pls_extban(struct userrec *u, int idx, char *par) +{ + char *flagstr, *arg; + char extban[UHOSTLEN], forwarded[LOGLINEMAX]; + char flag; + char prefix = '\0'; + + flagstr = newsplit(&par); + if (!flagstr[0] || flagstr[1]) { + dprintf(idx, "Usage: +extban [channel] [%%] [reason]\n"); + return; + } + + flag = flagstr[0]; + arg = newsplit(&par); + if (!arg[0]) { + dprintf(idx, "Usage: +extban [channel] [%%] [reason]\n"); + return; + } + + get_extban_prefix(&prefix); + if (prefix) + egg_snprintf(extban, sizeof extban, "%c%c:%s", prefix, flag, arg); + else + egg_snprintf(extban, sizeof extban, "%c:%s", flag, arg); + + egg_snprintf(forwarded, sizeof forwarded, "%s%s%s", extban, + par[0] ? " " : "", par); + cmd_pls_ban(u, idx, forwarded); +} + static void cmd_pls_exempt(struct userrec *u, int idx, char *par) { char *chname, *who, s[UHOSTLEN], *p, *p_expire; @@ -1624,6 +1693,7 @@ static void cmd_chanload(struct userrec *u, int idx, char *par) */ static cmd_t C_dcc_irc[] = { {"+ban", "ol|ol", (IntFunc) cmd_pls_ban, NULL}, + {"+extban", "ol|ol", (IntFunc) cmd_pls_extban, NULL}, {"+exempt", "ol|ol", (IntFunc) cmd_pls_exempt, NULL}, {"+invite", "ol|ol", (IntFunc) cmd_pls_invite, NULL}, {"+chan", "n", (IntFunc) cmd_pls_chan, NULL}, diff --git a/src/mod/channels.mod/help/channels.help b/src/mod/channels.mod/help/channels.help index 627bb0c487..c966967670 100644 --- a/src/mod/channels.mod/help/channels.help +++ b/src/mod/channels.mod/help/channels.help @@ -8,6 +8,16 @@ has to be expressed in years, days, hours and/or minutes. See also: bans, -ban, stick, unstick +%{help=+extban}%{+lo|lo} +### %b+extban%b [channel] [%%] [comment] + Adds a channel extban using allowed ISUPPORT EXTBAN values. + Extban masks are created as [prefix]: + + Not all extbans (notice blocking, ctcp blocking, etc) can be enforced by + Eggdrop. These non-enforceable extbans are set on-channel and managed as + sticky bans. + +See also: +ban, -ban, bans %{help=+exempt}%{+lo|lo} ### %b+exempt%b [channel] [%%] [comment] Adds an exempt to the list of exempts stored on the bot, with optional @@ -264,7 +274,7 @@ See also: stick, bans, exempts, invites, -ban, -exempt, -invite %binfo%b For channel ops or halfops: - %b+ban -ban bans stick%b + %b+ban +extban -ban bans stick%b %b+exempt -exempt exempts unstick%b %b+invite -invite invites%b @@ -286,7 +296,7 @@ See also: stick, bans, exempts, invites, -ban, -exempt, -invite %binfo%b %{+ol|ol} For channel ops or halfops: - %b+ban -ban bans stick%b + %b+ban +extban -ban bans stick%b %b+exempt -exempt exempts unstick%b %b+invite -invite invites%b %{+m|m} diff --git a/src/mod/channels.mod/userchan.c b/src/mod/channels.mod/userchan.c index f97c005698..84b385837e 100644 --- a/src/mod/channels.mod/userchan.c +++ b/src/mod/channels.mod/userchan.c @@ -220,9 +220,55 @@ static int u_equals_mask(maskrec *u, char *mask) static int u_match_mask(maskrec *rec, char *mask) { - for (; rec; rec = rec->next) + + char type, nick[NICKLEN]; + char *bang; + const char *arg, *accountflag = NULL; + memberlist *m = NULL; + module_entry *me; + + if (mask && mask[0]) { + bang = strchr(mask, '!'); + if (bang) { + size_t nicklen = (size_t)(bang - mask); + + if (nicklen >= sizeof nick) { + nicklen = sizeof nick - 1; + } + memcpy(nick, mask, nicklen); + nick[nicklen] = 0; + if (nick[0]) { + m = find_member_from_nick(nick); + } + } + } + + /* Loop through all ban records, see if user matches based on mask or + * flag (extban). + */ + for (; rec; rec = rec->next) { + /* Am I an extban? */ + if (extban_parse(rec->mask, &type, &arg)) { + me = module_find("server", 0, 0); + if (me && me->funcs && me->funcs[SERVER_GET_ISUPPORT]) { + accountflag = isupport_get("ACCOUNTEXTBAN", strlen("ACCOUNTEXTBAN")); + } + + if (accountflag && (type == accountflag[0])) { + if (!rfc_casecmp(m->account, arg)) { + return 1; + } + } else if (type == 'U') { + if (!strcmp(m->account, "*") && match_addr((char *) arg, mask)) { + return 1; + } + } + continue; + } + if (match_addr(rec->mask, mask)) return 1; + } return 0; } @@ -418,14 +464,28 @@ static void fix_broken_mask(char *newmask, const char *oldmask, size_t len) static int u_addban(struct chanset_t *chan, char *ban, char *from, char *note, time_t expire_time, int flags) { - char host[1024], s[1024]; + char host[1024], s[1024], extbantype, account_extban_flag = 0, isextban; + const char *extbanarg, *account_extban; maskrec *p = NULL, *l, **u = chan ? &chan->bans : &global_bans; module_entry *me; - /* Choke check: fix broken bans (must have '!' and '@') */ - fix_broken_mask(host, ban, sizeof host); + isextban = is_extban_mask(ban); + if (isextban) { + strlcpy(host, ban, sizeof host); + } else { + /* Choke check: fix broken bans (must have '!' and '@') */ + fix_broken_mask(host, ban, sizeof host); + } + if (isextban) { + account_extban = isupport_get("ACCOUNTEXTBAN", strlen("ACCOUNTEXTBAN")); + if (account_extban && account_extban[0]) + account_extban_flag = account_extban[0]; + if (extban_parse(host, &extbantype, &extbanarg) && + !extban_is_enforceable_flag(extbantype, account_extban_flag)) + flags |= MASKREC_STICKY; + } - if ((me = module_find("server", 0, 0)) && me->funcs) { + if (!isextban && (me = module_find("server", 0, 0)) && me->funcs) { simple_sprintf(s, "%s!%s", me->funcs[SERVER_BOTNAME], me->funcs[SERVER_BOTUSERHOST]); if (match_addr(host, s)) { diff --git a/src/mod/irc.mod/chan.c b/src/mod/irc.mod/chan.c index cadce03d13..b0085ff03f 100644 --- a/src/mod/irc.mod/chan.c +++ b/src/mod/irc.mod/chan.c @@ -35,6 +35,8 @@ static char last_invchan[CHANNELLEN + 1] = ""; static char botflag005; static int got315(char *from, char *msg); +static void refresh_ban_kick(struct chanset_t *chan, char *user, char *nick); +static void check_this_ban(struct chanset_t *chan, char *banmask, int sticky); /* ID length for !channels. */ @@ -92,6 +94,57 @@ static void update_idle(char *chname, char *nick) } } +static int extban_flag_supported(char flag) +{ + module_entry *me; + const char *value = NULL, *comma, *types; + + me = module_find("server", 0, 0); + if (me && me->funcs && me->funcs[SERVER_GET_ISUPPORT]) { + value = (const char *)isupport_get("EXTBAN", strlen("EXTBAN")); + } + if (!value || !value[0]) + return 0; + + comma = strchr(value, ','); + types = comma ? comma + 1 : value; + for (; *types; types++) + if (*types == flag) + return 1; + return 0; +} + +/* Document whether a ban matches a specific channel member + * banmask can be normal or extban, user is the traditional userhost. + * Returns 1 if the ban mask matches the member, 0 if not + */ +static int banmask_matches_member(const char *banmask, const char *user, memberlist *m) +{ + module_entry *me; + char type; + const char *v = NULL, *arg = NULL; + + /* Am I an extban? */ + if (!extban_parse(banmask, &type, &arg)) { + return match_addr((char *) banmask, (char *) user); + } + + me = module_find("server", 0, 0); + if (me && me->funcs && me->funcs[SERVER_GET_ISUPPORT]) { + v = (const char *)isupport_get("ACCOUNTEXTBAN", strlen("ACCOUNTEXTBAN")); + } + /* Try account extban matching */ + if (type && v && type == v[0]) { + return !rfc_casecmp(m->account, arg); + } + + /* Try U (unregistered) extban matching */ + if (type == 'U') { + return !strcmp(m->account, "*") && match_addr((char *) arg, (char *) user); + } + return 0; +} + /* set user account on all members on all channels, * trigger account bind if account state was not "unknown" (empty string) */ @@ -103,6 +156,8 @@ static void setaccount(char *nick, char *account) for (chan = chanset; chan; chan = chan->next) { if ((m = ismember(chan, nick))) { if (rfc_casecmp(m->account, account)) { + char user[UHOSTLEN]; + /* account was known */ if (m->account[0]) { if (!strcmp(account, "*")) { @@ -113,6 +168,12 @@ static void setaccount(char *nick, char *account) check_tcl_account(m->nick, m->userhost, get_user_from_member(m), chan->dname, account); } strlcpy(m->account, account, sizeof m->account); + + egg_snprintf(user, sizeof user, "%s!%s", m->nick, m->userhost); + if (u_match_mask(global_bans, user) || u_match_mask(chan->bans, user)) { + check_this_ban(chan, user, 0); + refresh_ban_kick(chan, user, m->nick); + } } } } @@ -475,7 +536,7 @@ static void refresh_ban_kick(struct chanset_t *chan, char *user, char *nick) /* Check global bans in first cycle and channel bans in second cycle. */ for (cycle = 0; cycle < 2; cycle++) { for (b = cycle ? chan->bans : global_bans; b; b = b->next) { - if (match_addr(b->mask, user)) { + if (banmask_matches_member(b->mask, user, m)) { struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; char c[512]; /* The ban comment. */ get_user_flagrec(get_user_from_member(m), &fr, @@ -574,10 +635,16 @@ static void recheck_bans(struct chanset_t *chan) /* Check global bans in first cycle and channel bans in second cycle. */ for (cycle = 0; cycle < 2; cycle++) { - for (u = cycle ? chan->bans : global_bans; u; u = u->next) + for (u = cycle ? chan->bans : global_bans; u; u = u->next) { + char extflag; + const char *extarg; + + if (extban_parse(u->mask, &extflag, &extarg) && !extban_flag_supported(extflag)) + continue; if (!isbanned(chan, u->mask) && (!channel_dynamicbans(chan) || (u->flags & MASKREC_STICKY))) add_mode(chan, '+', 'b', u->mask); + } } } @@ -668,14 +735,18 @@ static void resetmasks(struct chanset_t *chan, masklist *m, maskrec *mrec, static void check_this_ban(struct chanset_t *chan, char *banmask, int sticky) { memberlist *m; - char user[NICKMAX+UHOSTLEN+1]; + char user[NICKMAX+UHOSTLEN+1], extflag; + const char *extarg; if (HALFOP_CANTDOMODE('b')) return; + if (extban_parse(banmask, &extflag, &extarg) && !extban_flag_supported(extflag)) + return; + for (m = chan->channel.member; m && m->nick[0]; m = m->next) { sprintf(user, "%s!%s", m->nick, m->userhost); - if (match_addr(banmask, user) && + if (banmask_matches_member(banmask, user, m) && !(use_exempts && (u_match_mask(global_exempts, user) || u_match_mask(chan->exempts, user)))) @@ -2169,7 +2240,7 @@ static int gotjoin(char *from, char *channame) (!use_exempts || !isexempted(chan, from)) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) { for (b = chan->channel.ban; b->mask[0]; b = b->next) { - if (match_addr(b->mask, from)) { + if (banmask_matches_member(b->mask, from, m)) { dprintf(DP_SERVER, "KICK %s %s :%s\n", chname, m->nick, IRC_YOUREBANNED); m->flags |= SENTKICK; diff --git a/src/mod/modvals.h b/src/mod/modvals.h index 30314f19ba..c2f9b2a4ae 100644 --- a/src/mod/modvals.h +++ b/src/mod/modvals.h @@ -80,6 +80,7 @@ #define SERVER_BOTNAME 4 #define SERVER_BOTUSERHOST 5 #define SERVER_NICKLEN 37 +#define SERVER_GET_ISUPPORT 47 /* IRC */ #define IRC_RECHECK_CHANNEL 15 #define IRC_RECHECK_CHANNEL_MODES 17 diff --git a/src/mod/server.mod/isupport.c b/src/mod/server.mod/isupport.c index 321178a9bc..84b56ba615 100644 --- a/src/mod/server.mod/isupport.c +++ b/src/mod/server.mod/isupport.c @@ -31,7 +31,7 @@ typedef struct isupport { static isupport_t *isupport_list; static p_tcl_bind_list H_isupport; -static const char isupport_default[4096] = "CASEMAPPING=rfc1459 CHANNELLEN=80 NICKLEN=9 CHANTYPES=#& PREFIX=(ov)@+ CHANMODES=b,k,l,imnpst MODES=3 MAXCHANNELS=10 TOPICLEN=250 KICKLEN=250 STATUSMSG=@+"; +static const char isupport_default[4096] = "CASEMAPPING=rfc1459 CHANNELLEN=80 NICKLEN=9 CHANTYPES=#& PREFIX=(ov)@+ CHANMODES=b,k,l,imnpst MODES=3 MAXCHANNELS=10 TOPICLEN=250 KICKLEN=250 STATUSMSG=@+ EXTBAN=~,ar ACCOUNTEXTBAN=a"; static int hexdigit2dec[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 9 */