Implement channel exception list (mode 'e')
authorAlexander Barton <alex@barton.de>
Sat, 21 Jan 2012 18:59:57 +0000 (19:59 +0100)
committerAlexander Barton <alex@barton.de>
Sat, 21 Jan 2012 18:59:57 +0000 (19:59 +0100)
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).

src/ngircd/channel.c
src/ngircd/channel.h
src/ngircd/defines.h
src/ngircd/irc-channel.c
src/ngircd/irc-mode.c
src/ngircd/messages.h

index 781d91a5a69ef13f12ec24b3210d46a955620ffb..ff470246fec79e09d67ab764c6bca583138e2a00 100644 (file)
@@ -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
@@ -87,6 +87,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)
 {
@@ -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,7 +1032,16 @@ 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);
 }
 
@@ -1022,7 +1050,7 @@ 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);
 }
 
@@ -1063,6 +1091,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 )
 {
index ba3f2ca6480bc3841c70a30bec34a2012b88cda1..d8607a9cb68cf6c27c2428a6e6d4df4d18bceaaa 100644 (file)
@@ -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));
index 9dc5e92d4f4ec074247bd9f2741a8e4431b3b79f..c63abc9351f1bd3a435b8aef2d25305c7c928ea5 100644 (file)
 #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"
index 77deed7abde03f455c33018d8e01cf33fba47e53..2d520b314798b7364f7d90f664c64f5917f5ba23 100644 (file)
@@ -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 *channame,
                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);
index 71c9f796e952d592b28603c354012826b9dceeff..ad83ae98a7aa93d0ee0931e5e6396de91cfa8d57 100644 (file)
@@ -662,6 +662,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
                /* --- 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 *Origin, CHANNEL *Channel)
                                Req->argv[arg_arg][0] = '\0';
                                arg_arg++;
                        } else {
-                               if (*mode_ptr == 'I')
+                               switch (*mode_ptr) {
+                               case 'I':
                                        Channel_ShowInvites(Origin, Channel);
-                               else
+                                       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, CHANNEL *Channel,
        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, CHANNEL *Channel,
                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, CHANNEL *Channel,
                        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, CHANNEL *Channel,
 /**
  * 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 *Client, CHANNEL *Channel,
        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 *Client, CHANNEL *Channel,
                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 *Client, CHANNEL *Channel,
 
 
 /**
- * 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')
index 6a784fe9eb97a98ebc8194bee63232e7893f6c82..26be69ab86d27072f5f64d200176bcd8b8a18282 100644 (file)
@@ -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 :"