]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/irc-channel.c
Make the maximum /list reply length a configurable limit.
[ngircd-alex.git] / src / ngircd / irc-channel.c
index c5eb369d269cb76fc676ac5e1c7bc6d4640f285a..ed4839afdcef63782be0510b876915d3522c8e10 100644 (file)
@@ -31,6 +31,7 @@
 #include "match.h"
 #include "messages.h"
 #include "parse.h"
+#include "irc.h"
 #include "irc-info.h"
 #include "irc-write.h"
 #include "conf.h"
@@ -81,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 */
@@ -89,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);
@@ -165,8 +167,10 @@ join_set_channelmodes(CHANNEL *chan, CLIENT *target, const char *flags)
                }
        }
 
-       /* If channel persistent and client is ircop: make client chanop */
-       if (strchr(Channel_Modes(chan), 'P') && strchr(Client_Modes(target), 'o'))
+       /* If the channel is persistent (+P) and client is an IRC op:
+        * make client chanop, if not disabled in configuration. */
+       if (strchr(Channel_Modes(chan), 'P') && Conf_OperChanPAutoOp
+           && strchr(Client_Modes(target), 'o'))
                Channel_UserModeAdd(chan, target, 'o');
 } /* join_set_channelmodes */
 
@@ -363,22 +367,32 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req )
                         /* channel must be created, but forbidden by config */
                        IRC_WriteStrClient(Client, ERR_BANNEDFROMCHAN_MSG,
                                           Client_ID(Client), channame);
-                       break;
+                       goto join_next;
                }
 
                /* Local client? */
                if (Client_Type(Client) == CLIENT_USER) {
+                       if (chan) {
+                               /* Already existing channel: already member? */
+                               if (Channel_IsMemberOf(chan, Client))
+                                   goto join_next;
+                       }
+
                        /* Test if the user has reached the channel limit */
                        if ((Conf_MaxJoins > 0) &&
-                           (Channel_CountForUser(Client) >= Conf_MaxJoins))
-                               return IRC_WriteStrClient(Client,
+                           (Channel_CountForUser(Client) >= Conf_MaxJoins)) {
+                               if (!IRC_WriteStrClient(Client,
                                                ERR_TOOMANYCHANNELS_MSG,
-                                               Client_ID(Client), channame);
+                                               Client_ID(Client), channame))
+                                       return DISCONNECTED;
+                               goto join_next;
+                       }
+
                        if (chan) {
                                /* Already existing channel: check if the
                                 * client is allowed to join */
                                if (!join_allowed(Client, chan, channame, key))
-                                       break;
+                                       goto join_next;
                        } else {
                                /* New channel: first user will become channel
                                 * operator unless this is a modeless channel */
@@ -498,7 +512,7 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req )
        CHANNEL *chan;
        CLIENT *from;
        char *topic;
-       bool onchannel, topicok, use_servermode, r;
+       bool r, topic_power;
 
        assert( Client != NULL );
        assert( Req != NULL );
@@ -521,12 +535,17 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req )
                return IRC_WriteStrClient(from, ERR_NOSUCHCHANNEL_MSG,
                                          Client_ID(from), Req->argv[0]);
 
-       Channel_CheckAdminRights(chan, Client, from,
-                                &onchannel, &topicok, &use_servermode);
-
-       if (!onchannel && !topicok)
-               return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG,
-                                         Client_ID(from), Req->argv[0]);
+       /* Only remote servers and channel members are allowed to change the
+        * channel topic, and IRC opreators when the Conf_OperCanMode option
+        * is set in the server configuration. */
+       if (Client_Type(Client) != CLIENT_SERVER) {
+               topic_power = Client_HasMode(from, 'o');
+               if (!Channel_IsMemberOf(chan, from)
+                   && !(Conf_OperCanMode && topic_power))
+                       return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG,
+                                                 Client_ID(from), Req->argv[0]);
+       } else
+               topic_power = true;
 
        if (Req->argc == 1) {
                /* Request actual topic */
@@ -553,8 +572,12 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req )
        }
 
        if (strchr(Channel_Modes(chan), 't')) {
-               /* Topic Lock. Is the user a channel or IRC operator? */
-               if (!topicok)
+               /* Topic Lock. Is the user a channel op or IRC operator? */
+               if(!topic_power &&
+                  !strchr(Channel_UserModes(chan, from), 'h') &&
+                  !strchr(Channel_UserModes(chan, from), 'o') &&
+                  !strchr(Channel_UserModes(chan, from), 'a') &&
+                  !strchr(Channel_UserModes(chan, from), 'q'))
                        return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
                                                  Client_ID(from),
                                                  Channel_Name(chan));
@@ -566,7 +589,7 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req )
                 Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
                 Req->argv[1][0] ? Req->argv[1] : "<none>");
 
-       if (use_servermode)
+       if (Conf_OperServerMode)
                from = Client_ThisServer();
 
        /* Update channel and forward new topic to other servers */
@@ -602,6 +625,7 @@ IRC_LIST( CLIENT *Client, REQUEST *Req )
        char *pattern;
        CHANNEL *chan;
        CLIENT *from, *target;
+       int count = 0;
 
        assert(Client != NULL);
        assert(Req != NULL);
@@ -638,26 +662,35 @@ IRC_LIST( CLIENT *Client, REQUEST *Req )
                        /* Target is indeed an other server, forward it! */
                        return IRC_WriteStrClientPrefix(target, from,
                                                        "LIST %s :%s",
-                                                       Client_ID(from),
+                                                       Req->argv[0],
                                                        Req->argv[1]);
                }
        }
 
        while (pattern) {
                /* Loop through all the channels */
+               if (Req->argc > 0)
+                       ngt_LowerStr(pattern);
                chan = Channel_First();
                while (chan) {
                        /* Check search pattern */
-                       if (Match(pattern, Channel_Name(chan))) {
+                       if (MatchCaseInsensitive(pattern, Channel_Name(chan))) {
                                /* Gotcha! */
                                if (!strchr(Channel_Modes(chan), 's')
-                                   || Channel_IsMemberOf(chan, from)) {
+                                   || Channel_IsMemberOf(chan, from)
+                                   || (!Conf_MorePrivacy && Client_OperByMe(Client))) {
+                                       if ((Conf_MaxListSize > 0)
+                                           && IRC_CheckListTooBig(from, count,
+                                                                  Conf_MaxListSize,
+                                                                  "LIST"))
+                                               break;
                                        if (!IRC_WriteStrClient(from,
                                             RPL_LIST_MSG, Client_ID(from),
                                             Channel_Name(chan),
                                             Channel_MemberCount(chan),
                                             Channel_Topic( chan )))
                                                return DISCONNECTED;
+                                       count++;
                                }
                        }
                        chan = Channel_Next(chan);
@@ -670,6 +703,7 @@ IRC_LIST( CLIENT *Client, REQUEST *Req )
                        pattern = NULL;
        }
 
+       IRC_SetPenalty(from, 2);
        return IRC_WriteStrClient(from, RPL_LISTEND_MSG, Client_ID(from));
 } /* IRC_LIST */