commit f2fa1045e24f81e5c844dd50d6e299cb1ad9acb2 from: Alexander Barton date: Sat Jan 21 18:59:57 2012 UTC Implement channel exception list (mode 'e') This allows a channel operator to define exception masks that allow users to join the channel even when a "ban" would match and prevent them from joining: the exception list (e) overrides the ban list (b). commit - 33a165721b79bf896a1895e79fa0809fd6f71174 commit + f2fa1045e24f81e5c844dd50d6e299cb1ad9acb2 blob - 781d91a5a69ef13f12ec24b3210d46a955620ffb blob + ff470246fec79e09d67ab764c6bca583138e2a00 --- src/ngircd/channel.c +++ src/ngircd/channel.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -88,6 +88,14 @@ Channel_GetListBans(CHANNEL *c) GLOBAL struct list_head * +Channel_GetListExcepts(CHANNEL *c) +{ + assert(c != NULL); + return &c->list_excepts; +} + + +GLOBAL struct list_head * Channel_GetListInvites(CHANNEL *c) { assert(c != NULL); @@ -161,6 +169,7 @@ Free_Channel(CHANNEL *chan) array_free(&chan->topic); array_free(&chan->keyfile); Lists_Free(&chan->list_bans); + Lists_Free(&chan->list_excepts); Lists_Free(&chan->list_invites); free(chan); @@ -788,6 +797,13 @@ Channel_SetMaxUsers(CHANNEL *Chan, unsigned long Count } /* Channel_SetMaxUsers */ +/** + * Check if a client is allowed to send to a specific channel. + * + * @param Chan The channel to check. + * @param From The client that wants to send. + * @return true if the client is allowed to send, false otherwise. + */ static bool Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From) { @@ -822,6 +838,9 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From) if (strchr(Channel_Modes(Chan), 'm')) return false; + if (Lists_Check(&Chan->list_excepts, From)) + return true; + return !Lists_Check(&Chan->list_bans, From); } @@ -1013,16 +1032,25 @@ GLOBAL bool Channel_AddBan(CHANNEL *c, const char *mask ) { struct list_head *h = Channel_GetListBans(c); - LogDebug("Adding \"%s\" to \"%s\" %s list", mask, Channel_Name(c), "ban"); + LogDebug("Adding \"%s\" to \"%s\" ban list", mask, Channel_Name(c)); return Lists_Add(h, mask, false, NULL); } GLOBAL bool +Channel_AddExcept(CHANNEL *c, const char *mask ) +{ + struct list_head *h = Channel_GetListExcepts(c); + LogDebug("Adding \"%s\" to \"%s\" exception list", mask, Channel_Name(c)); + return Lists_Add(h, mask, false, NULL); +} + + +GLOBAL bool Channel_AddInvite(CHANNEL *c, const char *mask, bool onlyonce) { struct list_head *h = Channel_GetListInvites(c); - LogDebug("Adding \"%s\" to \"%s\" %s list", mask, Channel_Name(c), "invite"); + LogDebug("Adding \"%s\" to \"%s\" invite list", mask, Channel_Name(c)); return Lists_Add(h, mask, onlyonce, NULL); } @@ -1064,6 +1092,19 @@ Channel_ShowBans( CLIENT *Client, CHANNEL *Channel ) GLOBAL bool +Channel_ShowExcepts( CLIENT *Client, CHANNEL *Channel ) +{ + struct list_head *h; + + assert( Channel != NULL ); + + h = Channel_GetListExcepts(Channel); + return ShowChannelList(h, Client, Channel, RPL_EXCEPTLIST_MSG, + RPL_ENDOFEXCEPTLIST_MSG); +} + + +GLOBAL bool Channel_ShowInvites( CLIENT *Client, CHANNEL *Channel ) { struct list_head *h; blob - ba3f2ca6480bc3841c70a30bec34a2012b88cda1 blob + d8607a9cb68cf6c27c2428a6e6d4df4d18bceaaa --- src/ngircd/channel.h +++ src/ngircd/channel.h @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,6 +38,7 @@ typedef struct _CHANNEL char key[CLIENT_PASS_LEN]; /* Channel key ("password", mode "k" ) */ unsigned long maxusers; /* Maximum number of members (mode "l") */ struct list_head list_bans; /* list head of banned users */ + struct list_head list_excepts; /* list head of (ban) exception list */ struct list_head list_invites; /* list head of invited users */ array keyfile; /* Name of the channel key file */ } CHANNEL; @@ -58,6 +59,7 @@ typedef POINTER CL2CHAN; #endif GLOBAL struct list_head *Channel_GetListBans PARAMS((CHANNEL *c)); +GLOBAL struct list_head *Channel_GetListExcepts PARAMS((CHANNEL *c)); GLOBAL struct list_head *Channel_GetListInvites PARAMS((CHANNEL *c)); GLOBAL void Channel_Init PARAMS(( void )); @@ -123,10 +125,13 @@ GLOBAL char *Channel_TopicWho PARAMS(( CHANNEL *Chan ) GLOBAL unsigned int Channel_CreationTime PARAMS(( CHANNEL *Chan )); #endif -GLOBAL bool Channel_AddInvite PARAMS((CHANNEL *c, const char *Mask, bool OnlyOnce )); -GLOBAL bool Channel_AddBan PARAMS((CHANNEL *c, const char *Mask )); +GLOBAL bool Channel_AddBan PARAMS((CHANNEL *c, const char *Mask)); +GLOBAL bool Channel_AddExcept PARAMS((CHANNEL *c, const char *Mask)); +GLOBAL bool Channel_AddInvite PARAMS((CHANNEL *c, const char *Mask, + bool OnlyOnce)); GLOBAL bool Channel_ShowBans PARAMS((CLIENT *client, CHANNEL *c)); +GLOBAL bool Channel_ShowExcepts PARAMS((CLIENT *client, CHANNEL *c)); GLOBAL bool Channel_ShowInvites PARAMS((CLIENT *client, CHANNEL *c)); GLOBAL void Channel_LogServer PARAMS((const char *msg)); blob - 9dc5e92d4f4ec074247bd9f2741a8e4431b3b79f blob + c63abc9351f1bd3a435b8aef2d25305c7c928ea5 --- src/ngircd/defines.h +++ src/ngircd/defines.h @@ -161,7 +161,7 @@ #define USERMODES "acCiorRswx" /** Supported channel modes. */ -#define CHANMODES "biIklmnoOPRstvz" +#define CHANMODES "beiIklmnoOPRstvz" /** Away message for users connected to linked servers. */ #define DEFAULT_AWAY_MSG "Away" blob - 77deed7abde03f455c33018d8e01cf33fba47e53 blob + 2d520b314798b7364f7d90f664c64f5917f5ba23 --- src/ngircd/irc-channel.c +++ src/ngircd/irc-channel.c @@ -82,7 +82,7 @@ static bool join_allowed(CLIENT *Client, CHANNEL *chan, const char *channame, const char *key) { - bool is_invited, is_banned; + bool is_invited, is_banned, is_exception;; const char *channel_modes; /* Allow IRC operators to overwrite channel limits */ @@ -90,9 +90,10 @@ join_allowed(CLIENT *Client, CHANNEL *chan, const char return true; is_banned = Lists_Check(Channel_GetListBans(chan), Client); + is_exception = Lists_Check(Channel_GetListExcepts(chan), Client); is_invited = Lists_Check(Channel_GetListInvites(chan), Client); - if (is_banned && !is_invited) { + if (is_banned && !is_invited && !is_exception) { /* Client is banned from channel (and not on invite list) */ IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG, Client_ID(Client), channame); blob - 71c9f796e952d592b28603c354012826b9dceeff blob + ad83ae98a7aa93d0ee0931e5e6396de91cfa8d57 --- src/ngircd/irc-mode.c +++ src/ngircd/irc-mode.c @@ -662,6 +662,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Ori /* --- Channel lists --- */ case 'I': /* Invite lists */ case 'b': /* Ban lists */ + case 'e': /* Channel exception lists */ if (Mode_Limit_Reached(Client, mode_arg_count++)) goto chan_exit; if (arg_arg > mode_arg) { @@ -683,10 +684,17 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Ori Req->argv[arg_arg][0] = '\0'; arg_arg++; } else { - if (*mode_ptr == 'I') - Channel_ShowInvites(Origin, Channel); - else + switch (*mode_ptr) { + case 'I': + Channel_ShowInvites(Origin, Channel); + break; + case 'b': Channel_ShowBans(Origin, Channel); + break; + case 'e': + Channel_ShowExcepts(Origin, Channel); + break; + } } break; default: @@ -836,7 +844,7 @@ IRC_AWAY( CLIENT *Client, REQUEST *Req ) /** * Add entries to channel invite, ban and exception lists. * - * @param what Can be 'I' for invite or 'b' for ban list. + * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list. * @param Prefix The originator of the command. * @param Client The sender of the command. * @param Channel The channel of which the list should be modified. @@ -853,7 +861,7 @@ Add_To_List(char what, CLIENT *Prefix, CLIENT *Client, assert(Client != NULL); assert(Channel != NULL); assert(Pattern != NULL); - assert(what == 'I' || what == 'b'); + assert(what == 'I' || what == 'b' || what == 'e'); mask = Lists_MakeMask(Pattern); @@ -864,6 +872,9 @@ Add_To_List(char what, CLIENT *Prefix, CLIENT *Client, case 'b': list = Channel_GetListBans(Channel); break; + case 'e': + list = Channel_GetListExcepts(Channel); + break; } if (Lists_CheckDupeMask(list, mask)) @@ -884,6 +895,10 @@ Add_To_List(char what, CLIENT *Prefix, CLIENT *Client, if (!Channel_AddBan(Channel, mask)) return CONNECTED; break; + case 'e': + if (!Channel_AddExcept(Channel, mask)) + return CONNECTED; + break; } return Send_ListChange(true, what, Prefix, Client, Channel, mask); } @@ -892,7 +907,7 @@ Add_To_List(char what, CLIENT *Prefix, CLIENT *Client, /** * Delete entries from channel invite, ban and exeption lists. * - * @param what Can be 'I' for invite or 'b' for ban list. + * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list. * @param Prefix The originator of the command. * @param Client The sender of the command. * @param Channel The channel of which the list should be modified. @@ -909,7 +924,7 @@ Del_From_List(char what, CLIENT *Prefix, CLIENT *Clien assert(Client != NULL); assert(Channel != NULL); assert(Pattern != NULL); - assert(what == 'I' || what == 'b'); + assert(what == 'I' || what == 'b' || what == 'e'); mask = Lists_MakeMask(Pattern); @@ -920,6 +935,9 @@ Del_From_List(char what, CLIENT *Prefix, CLIENT *Clien case 'b': list = Channel_GetListBans(Channel); break; + case 'e': + list = Channel_GetListExcepts(Channel); + break; } if (!Lists_CheckDupeMask(list, mask)) @@ -931,7 +949,7 @@ Del_From_List(char what, CLIENT *Prefix, CLIENT *Clien /** - * Send information about changed channel ban/invite lists to clients. + * Send information about changed channel invite/ban/exception lists to clients. * * @param IsAdd true if the list item has been added, false otherwise. * @param ModeChar The mode to use (e. g. 'b' or 'I') blob - 6a784fe9eb97a98ebc8194bee63232e7893f6c82 blob + 26be69ab86d27072f5f64d200176bcd8b8a18282 --- src/ngircd/messages.h +++ src/ngircd/messages.h @@ -21,8 +21,8 @@ #define RPL_YOURHOST_MSG "002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)" #define RPL_CREATED_MSG "003 %s :This server has been started %s" #define RPL_MYINFO_MSG "004 %s %s ngircd-%s %s %s" -#define RPL_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=bI,k,l,imnOPRstz CHANLIMIT=#&+:%d :are supported on this server" -#define RPL_ISUPPORT2_MSG "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d MODES=%d MAXLIST=bI:%d PENALTY :are supported on this server" +#define RPL_ISUPPORT1_MSG "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(ov)@+ CHANTYPES=#&+ CHANMODES=beI,k,l,imnOPRstz CHANLIMIT=#&+:%d :are supported on this server" +#define RPL_ISUPPORT2_MSG "005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d MODES=%d MAXLIST=beI:%d PENALTY :are supported on this server" #define RPL_TRACELINK_MSG "200 %s Link %s-%s %s %s V%s %ld %d %d" #define RPL_TRACEOPERATOR_MSG "204 %s Oper 2 :%s" @@ -75,6 +75,8 @@ #define RPL_INVITING_MSG "341 %s %s %s%s" #define RPL_INVITELIST_MSG "346 %s %s %s" #define RPL_ENDOFINVITELIST_MSG "347 %s %s :End of channel invite list" +#define RPL_EXCEPTLIST_MSG "348 %s %s %s" +#define RPL_ENDOFEXCEPTLIST_MSG "349 %s %s :End of channel exception list" #define RPL_VERSION_MSG "351 %s %s-%s.%s %s :%s" #define RPL_WHOREPLY_MSG "352 %s %s %s %s %s %s %s :%d %s" #define RPL_NAMREPLY_MSG "353 %s %s %s :"