Commit Diff


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 :"