]> arthur.barton.de Git - ngircd.git/blobdiff - src/ngircd/channel.c
Implemented xop support
[ngircd.git] / src / ngircd / channel.c
index 781d91a5a69ef13f12ec24b3210d46a955620ffb..90d2efab3e191f7ef1f3931bb1f2de6e90e5837d 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);
@@ -285,6 +294,8 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name,
             const char *Reason )
 {
        CHANNEL *chan;
+       char *ptr, *target_modes;
+       bool can_kick = false;
 
        assert(Peer != NULL);
        assert(Target != NULL);
@@ -305,14 +316,51 @@ Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name,
                /* Check that user is on the specified channel */
                if (!Channel_IsMemberOf(chan, Origin)) {
                        IRC_WriteStrClient( Origin, ERR_NOTONCHANNEL_MSG,
-                                          Client_ID(Origin), Name);
+                                           Client_ID(Origin), Name);
                        return;
                }
+       }
 
-               /* Check if user has operator status */
-               if (!strchr(Channel_UserModes(chan, Origin), 'o')) {
-                       IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG,
-                                          Client_ID(Origin), Name);
+       if(Client_Type(Peer) == CLIENT_USER) {
+               /* Check if client has the rights to kick target */
+               ptr = Channel_UserModes(chan, Peer);
+               target_modes = Channel_UserModes(chan, Target);
+               while(*ptr) {
+                       /* Owner can kick everyone */
+                       if ( *ptr == 'q') {
+                               can_kick = true;
+                               break;
+                       }
+                       /* Admin can't kick owner */
+                       if ( *ptr == 'a' ) {
+                               if (!strchr(target_modes, 'q')) {
+                                       can_kick = true;
+                                       break;
+                               }
+                       }
+                       /* Op can't kick owner | admin */
+                       if ( *ptr == 'o' ) {
+                               if (!strchr(target_modes, 'q') &&
+                                   !strchr(target_modes, 'a')) {
+                                       can_kick = true;
+                                       break;
+                               }
+                       }
+                       /* Half Op can't kick owner | admin | op */ 
+                       if ( *ptr == 'h' ) {
+                               if (!strchr(target_modes, 'q') &&
+                                   !strchr(target_modes, 'a') &&
+                                   !strchr(target_modes, 'o')) {
+                                       can_kick = true;
+                                       break;
+                               }
+                       }
+                       ptr++;
+               }
+               
+               if(!can_kick) {
+                       IRC_WriteStrClient(Origin, ERR_CHANOPPRIVTOLOW_MSG,
+                               Client_ID(Origin), Name);
                        return;
                }
        }
@@ -788,12 +836,19 @@ 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)
 {
-       bool is_member, has_voice, is_op;
+       bool is_member, has_voice, is_halfop, is_op, is_chanadmin, is_owner;
 
-       is_member = has_voice = is_op = false;
+       is_member = has_voice = is_halfop = is_op = is_chanadmin = is_owner = false;
 
        /* The server itself always can send messages :-) */
        if (Client_ThisServer() == From)
@@ -803,8 +858,14 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
                is_member = true;
                if (strchr(Channel_UserModes(Chan, From), 'v'))
                        has_voice = true;
+               if (strchr(Channel_UserModes(Chan, From), 'h'))
+                       is_halfop = true;
                if (strchr(Channel_UserModes(Chan, From), 'o'))
                        is_op = true;
+               if (strchr(Channel_UserModes(Chan, From), 'a'))
+                       is_chanadmin = true;
+               if (strchr(Channel_UserModes(Chan, From), 'q'))
+                       is_owner = true;
        }
 
        /*
@@ -816,12 +877,15 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
        if (strchr(Channel_Modes(Chan), 'n') && !is_member)
                return false;
 
-       if (is_op || has_voice)
+       if (has_voice || is_halfop || is_op || is_chanadmin || is_owner)
                return true;
 
        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 +1077,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 +1095,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 +1136,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 )
 {
@@ -1146,64 +1232,6 @@ Channel_CheckKey(CHANNEL *Chan, CLIENT *Client, const char *Key)
 } /* Channel_CheckKey */
 
 
-/**
- * Check wether a client is allowed to administer a channel or not.
- *
- * @param Chan         The channel to test.
- * @param Client       The client from which the command has been received.
- * @param Origin       The originator of the command (or NULL).
- * @param OnChannel    Set to true if the originator is member of the channel.
- * @param AdminOk      Set to true if the client is allowed to do
- *                     administrative tasks on this channel.
- * @param UseServerMode        Set to true if ngIRCd should emulate "server mode",
- *                     that is send commands as if originating from a server
- *                     and not the originator of the command.
- */
-GLOBAL void
-Channel_CheckAdminRights(CHANNEL *Chan, CLIENT *Client, CLIENT *Origin,
-                        bool *OnChannel, bool *AdminOk, bool *UseServerMode)
-{
-       assert (Chan != NULL);
-       assert (Client != NULL);
-       assert (OnChannel != NULL);
-       assert (AdminOk != NULL);
-       assert (UseServerMode != NULL);
-
-       /* Use the client as origin, if no origin has been given (no prefix?) */
-       if (!Origin)
-               Origin = Client;
-
-       *OnChannel = false;
-       *AdminOk = false;
-       *UseServerMode = false;
-
-       if (Client_Type(Client) != CLIENT_USER
-           && Client_Type(Client) != CLIENT_SERVER
-           && Client_Type(Client) != CLIENT_SERVICE)
-               return;
-
-       /* Allow channel administration if the client is a server or service */
-       if (Client_Type(Client) != CLIENT_USER) {
-               *AdminOk = true;
-               return;
-       }
-
-       *OnChannel = Channel_IsMemberOf(Chan, Origin);
-
-       if (*OnChannel && strchr(Channel_UserModes(Chan, Origin), 'o')) {
-               /* User is a channel operator */
-               *AdminOk = true;
-       } else if (Conf_OperCanMode) {
-               /* IRC operators are allowed to administer channels as well */
-               if (Client_OperByMe(Origin)) {
-                       *AdminOk = true;
-                       if (Conf_OperServerMode)
-                               *UseServerMode = true;
-               }
-       }
-} /* Channel_CheckAdminRights */
-
-
 static CL2CHAN *
 Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
 {