Merge branch 'automake-am11-am12'
authorAlexander Barton <alex@barton.de>
Mon, 24 Sep 2012 18:28:02 +0000 (20:28 +0200)
committerAlexander Barton <alex@barton.de>
Mon, 24 Sep 2012 18:28:02 +0000 (20:28 +0200)
* automake-am11-am12:
  autogen.sh: detect automake version format a.b.c and a.b
  configure.ng: don't require GIT tree to detect version string
  Include .mailmap file in distribution archives
  Include all build-system files into distribution archives
  Change build system to support new and old GNU automake

21 files changed:
INSTALL
configure.ng
doc/Makefile.am
doc/Modes.txt
src/ipaddr/Makefile.ng
src/ngircd/Makefile.ng
src/ngircd/channel.c
src/ngircd/conf.c
src/ngircd/conn-ssl.c
src/ngircd/defines.h
src/ngircd/irc-channel.c
src/ngircd/irc-info.c
src/ngircd/irc-mode.c
src/ngircd/irc-op.c
src/ngircd/irc-server.c
src/ngircd/messages.h
src/ngircd/ngircd.c
src/ngircd/numeric.c
src/testsuite/Makefile.ng
src/testsuite/mode-test.e
src/tool/Makefile.ng

diff --git a/INSTALL b/INSTALL
index 4e1cd2fb7916e779824b1bb08077ff278061fd0c..640df4ee3e81b7def928c2e4b2e3a3256a5574c8 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -149,10 +149,14 @@ This step is therefore only interesting for developers.
 
 autogen.sh produces the Makefile.in's, which are necessary for the configure
 script itself, and some more files for make. To run autogen.sh you'll need
-GNU autoconf and GNU automake (use recent versions! autoconf 2.53 and
-automake 1.6.1 are known to work).
-
-Again: "end users" do not need this step!
+GNU autoconf and GNU automake: at least autoconf 2.61 and automake 1.10 are
+requird, newer is better. But don't use automake 1.12 or newer for creating
+distribution archives: it will work but lack "de-ANSI-fucation" support in the
+generated Makefile's! Stick with automake 1.11.x for this purpose ...
+So automake 1.11.x and autoconf 2.67+ is recommended.
+
+Again: "end users" do not need this step and neither need GNU autoconf nor GNU
+automake at all!
 
 
 2): "./configure"
index da723e8fcae037dacbdf6710aef521b3538c1460..7f3e2d99c4cd6c8689bb09f89c76f300b213a119 100644 (file)
@@ -16,9 +16,13 @@ define(VERSION_ID,esyscmd([
        ( [ -n "$V" ] && echo "$V" || echo "??" ) | tr -d '\n';
 ]))
 
+m4_ifdef([AM_SILENT_RULES],
+       [m4_define([ng_color_tests], [color-tests])],
+       [m4_define([ng_color_tests], [])])
+
 # -- Initialisation --
 
-AC_PREREQ([2.67])
+AC_PREREQ([2.61])
 AC_INIT([ngIRCd], VERSION_ID,
        [ngircd-ml@ngircd.barton.de], [ngircd], [http://ngircd.barton.de/])
 
@@ -26,7 +30,7 @@ AC_CONFIG_SRCDIR([src/ngircd/ngircd.c])
 AC_CONFIG_HEADER([src/config.h])
 AC_CANONICAL_HOST
 
-AM_INIT_AUTOMAKE([1.11])
+AM_INIT_AUTOMAKE([-Wall 1.10 ]ng_color_tests)
 
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 
index 00f2530ce32e716fb2d186ea9b5f5a6457d4c724..cd51d7fe0de1d1c7d73231868f32068faf96b7ba 100644 (file)
@@ -19,6 +19,7 @@ SUFFIXES = .tmpl
 static_docs = \
        Bopm.txt \
        Capabilities.txt \
+       Contributing.txt \
        FAQ.txt \
        GIT.txt \
        HowToRelease.txt \
index c2c533f2a67e1784561869cfee1ac49c5bf0fd90..e3b754d69815c1aaa0729177b25a80b35986d447 100644 (file)
@@ -68,7 +68,12 @@ channel of which he is a member.
 
   mode since   description
 
+  q    20      User is channel owner can only be set by a service, other
+               owner and irc op. Can promote other users to q, a, o, h, v.
+  a    20      User is channel admin and can promote other users to v, h, o
   o    0.2.0   User is channel operator and can op/kick/... other members.
+  h    20      User is half op and can set channel modes imntvIbek and kick
+               voiced and normal users.
   v    0.2.0   User is "voiced" and can speak even if channel is moderated.
 
 
index a376e25fdb146bed494f6c5ce688adca99e1aaa7..cea6899e9c5cca37289c4a83e199d420c175951d 100644 (file)
@@ -7,7 +7,7 @@ __ng_Makefile_am_template__
 
 EXTRA_DIST = Makefile.ng
 
-INCLUDES = -I$(srcdir)/../portab
+AM_CPPFLAGS = -I$(srcdir)/../portab
 
 noinst_LIBRARIES = libngipaddr.a
 
index 8ee044d9e1ed4c95bd2a6d5e93746ee042c2ef27..5c8533523b4430c7055d1b21e625331670c8950c 100644 (file)
@@ -13,7 +13,7 @@ __ng_Makefile_am_template__
 
 EXTRA_DIST = Makefile.ng
 
-INCLUDES = -I$(srcdir)/../portab -I$(srcdir)/../tool -I$(srcdir)/../ipaddr
+AM_CPPFLAGS = -I$(srcdir)/../portab -I$(srcdir)/../tool -I$(srcdir)/../ipaddr
 
 LINTARGS = -weak -warnunixlib +unixlib -booltype BOOLEAN \
  -varuse -retvalother -emptyret -unrecog
@@ -122,7 +122,7 @@ lint:
        for f in *.c; do \
         echo "checking $$f ..."; \
         splint $$f $(LINTARGS) -I$(srcdir) -I$(srcdir)/.. \
-         $(INCLUDES) $(AM_CFLAGS) >lint.out 2>&1; \
+         $(AM_CPPFLAGS) $(AM_CFLAGS) >lint.out 2>&1; \
         grep "no warnings" lint.out > /dev/null 2>&1; \
         if [ $$? -ne 0 ]; then \
          waswarning=1; \
index f0a9525d348a5d992596f453fd9ba709cbd47c9a..59fe00229576d018900a600c548925fd4d9668cb 100644 (file)
@@ -299,6 +299,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);
@@ -319,14 +321,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;
                }
+       }
+
+       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++;
+               }
 
-               /* Check if user has operator status */
-               if (!strchr(Channel_UserModes(chan, Origin), 'o')) {
-                       IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG,
-                                          Client_ID(Origin), Name);
+               if(!can_kick) {
+                       IRC_WriteStrClient(Origin, ERR_CHANOPPRIVTOLOW_MSG,
+                               Client_ID(Origin), Name);
                        return;
                }
        }
@@ -812,9 +851,9 @@ Channel_SetMaxUsers(CHANNEL *Chan, unsigned long Count)
 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)
@@ -824,8 +863,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;
        }
 
        /*
@@ -841,7 +886,7 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
            && !Client_HasMode(From, 'o'))
                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'))
@@ -1196,64 +1241,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 )
 {
index 5853926e4df98dfc02a4c6e80e16f39135b7dca4..0052de8f91b505a639401253f79f8a6fbc9cf4bd 100644 (file)
@@ -104,6 +104,8 @@ ConfSSL_Init(void)
        free(Conf_SSLOptions.DHFile);
        Conf_SSLOptions.DHFile = NULL;
        array_free_wipe(&Conf_SSLOptions.KeyFilePassword);
+
+       array_free(&Conf_SSLOptions.ListenPorts);
 }
 
 /**
@@ -689,6 +691,7 @@ Set_Defaults(bool InitServers)
                 PACKAGE_NAME, PACKAGE_VERSION);
        free(Conf_ListenAddress);
        Conf_ListenAddress = NULL;
+       array_free(&Conf_ListenPorts);
        array_free(&Conf_Motd);
        strlcpy(Conf_MotdFile, SYSCONFDIR, sizeof(Conf_MotdFile));
        strlcat(Conf_MotdFile, MOTD_FILE, sizeof(Conf_MotdFile));
index 8f7b70afccb0e310793013e0f53ee5f38522a614..914d01651235ad16af2e81ebb3d9a045e1d39a37 100644 (file)
@@ -241,6 +241,9 @@ void ConnSSL_Free(CONNECTION *c)
 bool
 ConnSSL_InitLibrary( void )
 {
+       if (!array_bytes(&Conf_SSLOptions.ListenPorts))
+               return true;
+
 #ifdef HAVE_LIBSSL
        SSL_CTX *newctx;
 
@@ -256,12 +259,14 @@ ConnSSL_InitLibrary( void )
                 * According to OpenSSL RAND_egd(3): "The automatic query of /var/run/egd-pool et al was added in OpenSSL 0.9.7";
                 * so it makes little sense to deal with PRNGD seeding ourselves.
                 */
+               array_free(&Conf_SSLOptions.ListenPorts);
                return false;
        }
 
        newctx = SSL_CTX_new(SSLv23_method());
        if (!newctx) {
                LogOpenSSLError("SSL_CTX_new()", NULL);
+               array_free(&Conf_SSLOptions.ListenPorts);
                return false;
        }
 
@@ -276,6 +281,7 @@ ConnSSL_InitLibrary( void )
        return true;
 out:
        SSL_CTX_free(newctx);
+       array_free(&Conf_SSLOptions.ListenPorts);
        return false;
 #endif
 #ifdef HAVE_LIBGNUTLS
@@ -287,10 +293,13 @@ out:
        err = gnutls_global_init();
        if (err) {
                Log(LOG_ERR, "gnutls_global_init(): %s", gnutls_strerror(err));
+               array_free(&Conf_SSLOptions.ListenPorts);
                return false;
        }
-       if (!ConnSSL_LoadServerKey_gnutls())
+       if (!ConnSSL_LoadServerKey_gnutls()) {
+               array_free(&Conf_SSLOptions.ListenPorts);
                return false;
+       }
        Log(LOG_INFO, "gnutls %s initialized.", gnutls_check_version(NULL));
        initialized = true;
        return true;
@@ -313,7 +322,7 @@ ConnSSL_LoadServerKey_gnutls(void)
 
        cert_file = Conf_SSLOptions.CertFile ? Conf_SSLOptions.CertFile:Conf_SSLOptions.KeyFile;
        if (!cert_file) {
-               Log(LOG_NOTICE, "No SSL server key configured, SSL disabled.");
+               Log(LOG_ERR, "No SSL server key configured!");
                return false;
        }
 
@@ -344,7 +353,7 @@ ConnSSL_LoadServerKey_openssl(SSL_CTX *ctx)
 
        assert(ctx);
        if (!Conf_SSLOptions.KeyFile) {
-               Log(LOG_NOTICE, "No SSL server key configured, SSL disabled.");
+               Log(LOG_ERR, "No SSL server key configured!");
                return false;
        }
 
index 82837599aadbb6485f0f044b447739d7b5f922fa..ba7adf17adb204840418b7482b75fef975844138 100644 (file)
 #define USERMODES "aBcCiorRswx"
 
 /** Supported channel modes. */
-#define CHANMODES "beiIklmMnoOPrRstvz"
+#define CHANMODES "abehiIklmMnoOPqrRstvz"
 
 /** Away message for users connected to linked servers. */
 #define DEFAULT_AWAY_MSG "Away"
index d714b48fcb8e3d28aed8cb2101bc6e452295290b..9e88e1bd0031de480a33d3ddfb5b447fed81d013 100644 (file)
@@ -510,7 +510,7 @@ IRC_TOPIC( CLIENT *Client, REQUEST *Req )
        CHANNEL *chan;
        CLIENT *from;
        char *topic;
-       bool onchannel, topicok, use_servermode, r;
+       bool r, is_oper;
 
        assert( Client != NULL );
        assert( Req != NULL );
@@ -533,10 +533,9 @@ 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)
+       /* Only IRC opers and channel members allowed */
+       is_oper = Client_OperByMe(from);
+       if (!Channel_IsMemberOf(chan, from) && !is_oper)
                return IRC_WriteStrClient(from, ERR_NOTONCHANNEL_MSG,
                                          Client_ID(from), Req->argv[0]);
 
@@ -565,8 +564,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(!strchr(Channel_UserModes(chan, from), 'h') &&
+                  !strchr(Channel_UserModes(chan, from), 'o') &&
+                  !strchr(Channel_UserModes(chan, from), 'a') &&
+                  !strchr(Channel_UserModes(chan, from), 'q') &&
+                  !is_oper)
                        return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
                                                  Client_ID(from),
                                                  Channel_Name(chan));
@@ -578,7 +581,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 */
index fc04773ae14ef307d1ac5adb0b53f2a18a64dd03..4909a96a063a3a9940be0e52d9b9e070925a28c9 100644 (file)
@@ -117,7 +117,7 @@ IRC_INFO(CLIENT * Client, REQUEST * Req)
                target = Client_Search(Req->argv[0]);
        else
                target = Client_ThisServer();
-       
+
        /* Make sure that the target is a server */
        if (target && Client_Type(target) != CLIENT_SERVER)
                target = Client_Introducer(target);
@@ -807,22 +807,48 @@ who_flags_status(const char *client_modes)
 }
 
 
-static const char *
-who_flags_qualifier(CLIENT *Client, const char *chan_user_modes)
+/**
+ * Return channel user mode prefix(es).
+ *
+ * @param Client The client requesting the mode prefixes.
+ * @param chan_user_modes String with channel user modes.
+ * @param str String buffer to which the prefix(es) will be appended.
+ * @param len Size of "str" buffer.
+ * @return Pointer to "str".
+ */
+static char *
+who_flags_qualifier(CLIENT *Client, const char *chan_user_modes,
+                   char *str, size_t len)
 {
        assert(Client != NULL);
 
        if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
-               if (strchr(chan_user_modes, 'o') &&
-                   strchr(chan_user_modes, 'v'))
-                       return "@+";
+               if (strchr(chan_user_modes, 'q'))
+                       strlcat(str, "~", len);
+               if (strchr(chan_user_modes, 'a'))
+                       strlcat(str, "&", len);
+               if (strchr(chan_user_modes, 'o'))
+                       strlcat(str, "@", len);
+               if (strchr(chan_user_modes, 'h'))
+                       strlcat(str, "%", len);
+               if (strchr(chan_user_modes, 'v'))
+                       strlcat(str, "+", len);
+
+               return str;
        }
 
-       if (strchr(chan_user_modes, 'o'))
-               return "@";
+       if (strchr(chan_user_modes, 'q'))
+               strlcat(str, "~", len);
+       else if (strchr(chan_user_modes, 'a'))
+               strlcat(str, "&", len);
+       else if (strchr(chan_user_modes, 'o'))
+               strlcat(str, "@", len);
+       else if (strchr(chan_user_modes, 'h'))
+               strlcat(str, "%", len);
        else if (strchr(chan_user_modes, 'v'))
-               return "+";
-       return "";
+               strlcat(str, "+", len);
+
+       return str;
 }
 
 
@@ -840,8 +866,7 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
        bool is_visible, is_member, is_ircop;
        CL2CHAN *cl2chan;
        const char *client_modes;
-       const char *chan_user_modes;
-       char flags[8];
+       char flags[10];
        CLIENT *c;
        int count = 0;
 
@@ -872,9 +897,8 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
                        if (is_ircop)
                                strlcat(flags, "*", sizeof(flags));
 
-                       chan_user_modes = Channel_UserModes(Chan, c);
-                       strlcat(flags, who_flags_qualifier(c, chan_user_modes),
-                               sizeof(flags));
+                       who_flags_qualifier(Client, Channel_UserModes(Chan, c),
+                                           flags, sizeof(flags));
 
                        if (!write_whoreply(Client, c, Channel_Name(Chan),
                                            flags))
@@ -1090,8 +1114,8 @@ IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c)
                if (str[strlen(str) - 1] != ':')
                        strlcat(str, " ", sizeof(str));
 
-               strlcat(str, who_flags_qualifier(c, Channel_UserModes(chan, c)),
-                                                sizeof(str));
+               who_flags_qualifier(Client, Channel_UserModes(chan, c),
+                                   str, sizeof(str));
                strlcat(str, Channel_Name(chan), sizeof(str));
 
                if (strlen(str) > (LINE_LEN - CHANNEL_NAME_LEN - 4)) {
@@ -1465,7 +1489,7 @@ IRC_Send_LUSERS(CLIENT *Client)
                        Conn_CountMax(), Conn_CountAccepted()))
                return DISCONNECTED;
 #endif
-       
+
        return CONNECTED;
 } /* IRC_Send_LUSERS */
 
@@ -1595,16 +1619,9 @@ IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan)
                if (is_member || is_visible) {
                        if (str[strlen(str) - 1] != ':')
                                strlcat(str, " ", sizeof(str));
-                       if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX && 
-                                       strchr(Channel_UserModes(Chan, cl), 'o') &&
-                                       strchr(Channel_UserModes(Chan, cl), 'v')) {
-                               strlcat(str, "@+", sizeof(str));
-                       } else {
-                               if (strchr(Channel_UserModes(Chan, cl), 'o'))
-                                       strlcat(str, "@", sizeof(str));
-                               else if (strchr(Channel_UserModes(Chan, cl), 'v'))
-                                       strlcat(str, "+", sizeof(str));
-                       }
+
+                       who_flags_qualifier(Client, Channel_UserModes(Chan, cl),
+                                           str, sizeof(str));
                        strlcat(str, Client_ID(cl), sizeof(str));
 
                        if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 4)) {
index 71557201d8d938f4a5ff65416f50eb487f78333d..7380c6eb5c70308b030097aadf58a9ab3bc933e4 100644 (file)
@@ -418,13 +418,16 @@ static bool
 Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
 {
        char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
-           argadd[CLIENT_PASS_LEN], *mode_ptr;
-       bool connected, set, skiponce, retval, onchannel, modeok, use_servermode;
+           argadd[CLIENT_PASS_LEN], *mode_ptr, *o_mode_ptr;
+       bool connected, set, skiponce, retval, use_servermode,
+            is_halfop, is_op, is_admin, is_owner, is_machine, is_oper;
        int mode_arg, arg_arg, mode_arg_count = 0;
        CLIENT *client;
        long l;
        size_t len;
 
+       is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false;
+
        if (Channel_IsModeless(Channel))
                return IRC_WriteStrClient(Client, ERR_NOCHANMODES_MSG,
                                Client_ID(Client), Channel_Name(Channel));
@@ -433,10 +436,20 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
        if (Req->argc <= 1)
                return Channel_Mode_Answer_Request(Origin, Channel);
 
-       Channel_CheckAdminRights(Channel, Client, Origin,
-                                &onchannel, &modeok, &use_servermode);
+       /* Check if origin is oper and opers can use mode */
+       use_servermode = Conf_OperServerMode;
+       if(Client_OperByMe(Client) && Conf_OperCanMode) {
+               is_oper = true;
+       }
+
+       /* Check if client is a server/service */
+       if(Client_Type(Client) == CLIENT_SERVER ||
+          Client_Type(Client) == CLIENT_SERVICE) {
+               is_machine = true;
+       }
 
-       if (!onchannel && !modeok)
+       /* Check if client is member of channel or an oper or an server/service */
+       if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine)
                return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG,
                                          Client_ID(Origin),
                                          Channel_Name(Channel));
@@ -515,21 +528,44 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
                if (arg_arg >= Req->argc)
                        arg_arg = -1;
 
+               if(!is_machine) {
+                       o_mode_ptr = Channel_UserModes(Channel, Client);
+                       while( *o_mode_ptr ) {
+                               if ( *o_mode_ptr == 'q')
+                                       is_owner = true;
+                               if ( *o_mode_ptr == 'a')
+                                       is_admin = true;
+                               if ( *o_mode_ptr == 'o')
+                                       is_op = true;
+                               if ( *o_mode_ptr == 'h')
+                                       is_halfop = true;
+                               o_mode_ptr++;
+                       }
+               }
+
                /* Validate modes */
                x[0] = '\0';
                argadd[0] = '\0';
                client = NULL;
                switch (*mode_ptr) {
                /* --- Channel modes --- */
+               case 'R': /* Registered users only */
+               case 's': /* Secret channel */
+               case 'z': /* Secure connections only */
+                       if(!is_oper && !is_machine && !is_owner &&
+                          !is_admin && !is_op) {
+                               connected = IRC_WriteStrClient(Origin,
+                                       ERR_CHANOPRIVSNEEDED_MSG,
+                                       Client_ID(Origin), Channel_Name(Channel));
+                               goto chan_exit;
+                       }
                case 'i': /* Invite only */
                case 'M': /* Only identified nicks can write */
                case 'm': /* Moderated */
                case 'n': /* Only members can write */
-               case 'R': /* Registered users only */
-               case 's': /* Secret channel */
                case 't': /* Topic locked */
-               case 'z': /* Secure connections only */
-                       if (modeok)
+                       if(is_oper || is_machine || is_owner ||
+                          is_admin || is_op || is_halfop)
                                x[0] = *mode_ptr;
                        else
                                connected = IRC_WriteStrClient(Origin,
@@ -540,7 +576,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
                        if (Mode_Limit_Reached(Client, mode_arg_count++))
                                goto chan_exit;
                        if (!set) {
-                               if (modeok)
+                               if (is_oper || is_machine || is_owner ||
+                                   is_admin || is_op || is_halfop)
                                        x[0] = *mode_ptr;
                                else
                                        connected = IRC_WriteStrClient(Origin,
@@ -550,7 +587,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
                                break;
                        }
                        if (arg_arg > mode_arg) {
-                               if (modeok) {
+                               if (is_oper || is_machine || is_owner ||
+                                   is_admin || is_op || is_halfop) {
                                        Channel_ModeDel(Channel, 'k');
                                        Channel_SetKey(Channel,
                                                       Req->argv[arg_arg]);
@@ -576,7 +614,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
                        if (Mode_Limit_Reached(Client, mode_arg_count++))
                                goto chan_exit;
                        if (!set) {
-                               if (modeok)
+                               if (is_oper || is_machine || is_owner ||
+                                   is_admin || is_op || is_halfop)
                                        x[0] = *mode_ptr;
                                else
                                        connected = IRC_WriteStrClient(Origin,
@@ -586,7 +625,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
                                break;
                        }
                        if (arg_arg > mode_arg) {
-                               if (modeok) {
+                               if (is_oper || is_machine || is_owner ||
+                                   is_admin || is_op || is_halfop) {
                                        l = atol(Req->argv[arg_arg]);
                                        if (l > 0 && l < 0xFFFF) {
                                                Channel_ModeDel(Channel, 'l');
@@ -611,44 +651,47 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
                        }
                        break;
                case 'O': /* IRC operators only */
-                       if (modeok) {
+                       if (set) {
                                /* Only IRC operators are allowed to
                                 * set the 'O' channel mode! */
-                               if (set && !(Client_OperByMe(Client)
-                                   || Client_Type(Client) == CLIENT_SERVER))
+                               if(is_oper || is_machine)
+                                       x[0] = 'O';
+                               else
                                        connected = IRC_WriteStrClient(Origin,
                                                ERR_NOPRIVILEGES_MSG,
                                                Client_ID(Origin));
-                               else
-                                       x[0] = 'O';
-                       } else
+                       } else if(is_oper || is_machine || is_owner ||
+                                 is_admin || is_op)
+                               x[0] = 'O';
+                       else
                                connected = IRC_WriteStrClient(Origin,
-                                               ERR_CHANOPRIVSNEEDED_MSG,
-                                               Client_ID(Origin),
-                                               Channel_Name(Channel));
-                               break;
+                                       ERR_CHANOPRIVSNEEDED_MSG,
+                                       Client_ID(Origin),
+                                       Channel_Name(Channel));
+                       break;
                case 'P': /* Persistent channel */
-                       if (modeok) {
+                       if (set) {
                                /* Only IRC operators are allowed to
                                 * set the 'P' channel mode! */
-                               if (set && !(Client_OperByMe(Client)
-                                   || Client_Type(Client) == CLIENT_SERVER))
+                               if(is_oper || is_machine)
+                                       x[0] = 'P';
+                               else
                                        connected = IRC_WriteStrClient(Origin,
                                                ERR_NOPRIVILEGES_MSG,
                                                Client_ID(Origin));
-                               else
-                                       x[0] = 'P';
-                       } else
+                       } else if(is_oper || is_machine || is_owner ||
+                                 is_admin || is_op)
+                               x[0] = 'P';
+                       else
                                connected = IRC_WriteStrClient(Origin,
                                        ERR_CHANOPRIVSNEEDED_MSG,
                                        Client_ID(Origin),
                                        Channel_Name(Channel));
                        break;
                /* --- Channel user modes --- */
-               case 'a':
-               case 'h':
-               case 'q':
-                       if (Client_Type(Client) != CLIENT_SERVER) {
+               case 'q': /* Owner */
+               case 'a': /* Channel admin */
+                       if(!is_oper && !is_machine && !is_owner) {
                                connected = IRC_WriteStrClient(Origin,
                                        ERR_CHANOPRIVSNEEDED_MSG,
                                        Client_ID(Origin),
@@ -656,16 +699,34 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
                                goto chan_exit;
                        }
                case 'o': /* Channel operator */
+                       if(!is_oper && !is_machine && !is_owner &&
+                          !is_admin && !is_op) {
+                               connected = IRC_WriteStrClient(Origin,
+                                       ERR_CHANOPRIVSNEEDED_MSG,
+                                       Client_ID(Origin),
+                                       Channel_Name(Channel));
+                               goto chan_exit;
+                       }
+               case 'h': /* Half Op */
+                       if(!is_oper && !is_machine && !is_owner &&
+                          !is_admin && !is_op) {
+                               connected = IRC_WriteStrClient(Origin,
+                                       ERR_CHANOPRIVSNEEDED_MSG,
+                                       Client_ID(Origin),
+                                       Channel_Name(Channel));
+                               goto chan_exit;
+                       }
                case 'v': /* Voice */
                        if (arg_arg > mode_arg) {
-                               if (modeok) {
+                               if (is_oper || is_machine || is_owner ||
+                                   is_admin || is_op || is_halfop) {
                                        client = Client_Search(Req->argv[arg_arg]);
                                        if (client)
                                                x[0] = *mode_ptr;
                                        else
-                                               connected = IRC_WriteStrClient(Client,
+                                               connected = IRC_WriteStrClient(Origin,
                                                        ERR_NOSUCHNICK_MSG,
-                                                       Client_ID(Client),
+                                                       Client_ID(Origin),
                                                        Req->argv[arg_arg]);
                                } else {
                                        connected = IRC_WriteStrClient(Origin,
@@ -690,7 +751,8 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
                                goto chan_exit;
                        if (arg_arg > mode_arg) {
                                /* modify list */
-                               if (modeok) {
+                               if (is_oper || is_machine || is_owner ||
+                                   is_admin || is_op || is_halfop) {
                                        connected = set
                                           ? Add_To_List(*mode_ptr, Origin,
                                                Client, Channel,
index 5e36b02bef478ce9ac2a0d96e411deaf2e11c4cc..08495475f60520c7dd899d7cef9e10b4f4852550 100644 (file)
@@ -166,8 +166,11 @@ IRC_INVITE(CLIENT *Client, REQUEST *Req)
 
                /* Is the channel "invite-only"? */
                if (strchr(Channel_Modes(chan), 'i')) {
-                       /* Yes. The user must be channel operator! */
-                       if (!strchr(Channel_UserModes(chan, from), 'o'))
+                       /* Yes. The user must be channel owner/admin/operator/halfop! */
+                       if (!strchr(Channel_UserModes(chan, from), 'q') &&
+                           !strchr(Channel_UserModes(chan, from), 'a') &&
+                           !strchr(Channel_UserModes(chan, from), 'o') &&
+                           !strchr(Channel_UserModes(chan, from), 'h'))
                                return IRC_WriteStrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
                                                Client_ID(from), Channel_Name(chan));
                        remember = true;
index 8526a573ec361b0851222314343e079b447114f6..380ab6224f55cf9b0d504f80be5718eceff824ae 100644 (file)
@@ -54,7 +54,7 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req )
        CLIENT *from, *c;
        int i;
        CONN_ID con;
-       
+
        assert( Client != NULL );
        assert( Req != NULL );
 
@@ -88,7 +88,7 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req )
                        Conn_Close( Client_Conn( Client ), NULL, "Bad password", true);
                        return DISCONNECTED;
                }
-               
+
                /* Is there a registered server with this ID? */
                if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
 
@@ -203,10 +203,10 @@ GLOBAL bool
 IRC_NJOIN( CLIENT *Client, REQUEST *Req )
 {
        char nick_in[COMMAND_LEN], nick_out[COMMAND_LEN], *channame, *ptr, modes[8];
-       bool is_op, is_voiced;
+       bool is_owner, is_chanadmin, is_op, is_halfop, is_voiced;
        CHANNEL *chan;
        CLIENT *c;
-       
+
        assert( Client != NULL );
        assert( Req != NULL );
 
@@ -220,11 +220,15 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req )
        while( ptr )
        {
                is_op = is_voiced = false;
-               
+
                /* cut off prefixes */
-               while(( *ptr == '@' ) || ( *ptr == '+' ))
+               while(( *ptr == '~') || ( *ptr == '&' ) || ( *ptr == '@' ) ||
+                       ( *ptr == '%') || ( *ptr == '+' ))
                {
+                       if( *ptr == '~' ) is_owner = true;
+                       if( *ptr == '&' ) is_chanadmin = true;
                        if( *ptr == '@' ) is_op = true;
+                       if( *ptr == 'h' ) is_halfop = true;
                        if( *ptr == '+' ) is_voiced = true;
                        ptr++;
                }
@@ -235,8 +239,11 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req )
                        Channel_Join( c, channame );
                        chan = Channel_Search( channame );
                        assert( chan != NULL );
-                       
+
+                       if( is_owner ) Channel_UserModeAdd( chan, c, 'q' );
+                       if( is_chanadmin ) Channel_UserModeAdd( chan, c, 'a' );
                        if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
+                       if( is_halfop ) Channel_UserModeAdd( chan, c, 'h' );
                        if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );
 
                        /* announce to channel... */
@@ -251,12 +258,15 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req )
                        }
 
                        if( nick_out[0] != '\0' ) strlcat( nick_out, ",", sizeof( nick_out ));
+                       if( is_owner ) strlcat( nick_out, "~", sizeof( nick_out ));
+                       if( is_chanadmin ) strlcat( nick_out, "&", sizeof( nick_out ));
                        if( is_op ) strlcat( nick_out, "@", sizeof( nick_out ));
+                       if( is_halfop ) strlcat( nick_out, "%", sizeof( nick_out ));
                        if( is_voiced ) strlcat( nick_out, "+", sizeof( nick_out ));
                        strlcat( nick_out, ptr, sizeof( nick_out ));
                }
                else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame );
-               
+
                /* search for next Nick */
                ptr = strtok( NULL, "," );
        }
index 4f3a397b2647eabc6fd6ed21f9aa31d776df69e9..d99930faa5d079995932ba3140d207c08e20e5c9 100644 (file)
@@ -21,7 +21,7 @@
 #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=beI,k,l,imMnOPRstz CHANLIMIT=#&+:%d :are supported on this server"
+#define RPL_ISUPPORT1_MSG              "005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(qaohv)~&@%%+ CHANTYPES=#&+ CHANMODES=beI,k,l,imMnOPRstz 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 EXCEPTS=e INVEX=I PENALTY :are supported on this server"
 
 #define RPL_TRACELINK_MSG              "200 %s Link %s-%s %s %s V%s %ld %d %d"
 #define ERR_LISTFULL_MSG               "478 %s %s %s: Channel list is full (%d)"
 #define ERR_NOPRIVILEGES_MSG           "481 %s :Permission denied"
 #define ERR_CHANOPRIVSNEEDED_MSG       "482 %s %s :You are not channel operator"
+#define ERR_CHANOPPRIVTOLOW_MSG                "482 %s %s :Your privileges are to low"
 #define ERR_CANTKILLSERVER_MSG         "483 %s :You can't kill a server!"
 #define ERR_RESTRICTED_MSG             "484 %s :Your connection is restricted"
 #define ERR_NICKREGISTER_MSG           "484 %s :Cannot modify user mode (+R) -- Use IRC services"
index 585e2ac0ae8ad1981c7e0b033855df39c2996659..a4c2fe8aabc07c72ff5fa00b21330ea087612856 100644 (file)
@@ -662,7 +662,7 @@ NGIRCd_Init(bool NGIRCd_NoDaemon)
        /* SSL initialization */
        if (!ConnSSL_InitLibrary())
                Log(LOG_WARNING,
-                   "Warning: Error during SSL initialization, continuing ...");
+                   "Error during SSL initialization, continuing without SSL ...");
 
        /* Change root */
        if (Conf_Chroot[0]) {
index d59a1dc3a9be6895de5f2565337fe8e29a3fbb40..4bce60fb12a947908f14118b7aa200439f4284df 100644 (file)
@@ -67,10 +67,17 @@ Announce_Channel(CLIENT *Client, CHANNEL *Chan)
                         * (if user is channel operator or has voice) */
                        if (str[strlen(str) - 1] != ':')
                                strlcat(str, ",", sizeof(str));
-                       if (strchr(Channel_UserModes(Chan, cl), 'v'))
-                               strlcat(str, "+", sizeof(str));
+                       if (strchr(Channel_UserModes(Chan, cl), 'q'))
+                               strlcat(str, "~", sizeof(str));
+                       if (strchr(Channel_UserModes(Chan, cl), 'a'))
+                               strlcat(str, "&", sizeof(str));
                        if (strchr(Channel_UserModes(Chan, cl), 'o'))
                                strlcat(str, "@", sizeof(str));
+                       if (strchr(Channel_UserModes(Chan, cl), 'h'))
+                               strlcat(str, "%", sizeof(str));
+                       if (strchr(Channel_UserModes(Chan, cl), 'v'))
+                               strlcat(str, "+", sizeof(str));
+
                        strlcat(str, Client_ID(cl), sizeof(str));
 
                        /* Send the data if the buffer is "full" */
index 40076b46022044a4239b136cbbd0db074069173c..b47ba0e51fb537813a1fc80067d61c9a33a5a923 100644 (file)
@@ -11,7 +11,7 @@
 
 __ng_Makefile_am_template__
 
-INCLUDES = -I$(srcdir)/../portab
+AM_CPPFLAGS = -I$(srcdir)/../portab
 
 EXTRA_DIST = \
        Makefile.ng README functions.inc getpid.sh \
index 260cd03c12898ae46c5e9d58b1f5f4fb4bcf74ff..44b6e5dfe5a3bb3cb05dddba1e08498e1cb58bdd 100644 (file)
@@ -31,6 +31,46 @@ expect {
        "@* MODE nick :-i"
 }
 
+send "join #usermode\r"
+expect {
+       timeout { exit 1 }
+       "@* JOIN :#usermode"
+}
+expect {
+       timeout { exit 1 }
+       "366"
+}
+
+send "mode #usermode +v nick\r"
+expect {
+       timeout { exit 1 }
+       "@* MODE #usermode +v nick\r"
+}
+
+send "mode #usermode +h nick\r"
+expect {
+       timeout { exit 1 }
+       "@* MODE #usermode +h nick\r"
+}
+
+send "mode #usermode +a nick\r"
+expect {
+       timeout { exit 1 }
+       "482 nick"
+}
+
+send "mode #usermode +q nick\r"
+expect {
+       timeout { exit 1 }
+       "482 nick"
+}
+
+send "mode #usermode -vho nick nick nick\r"
+expect {
+       timeout { exit 1 }
+       "@* MODE #usermode -vho nick nick nick"
+}
+
 send "oper TestOp 123\r"
 expect {
        timeout { exit 1 }
@@ -47,6 +87,34 @@ expect {
        "221 nick +o"
 }
 
+send "mode #usermode +a nick\r"
+expect {
+       timeout { exit 1 }
+       "@* MODE #usermode +a nick"
+}
+
+send "mode #usermode +q nick\r"
+expect {
+       timeout { exit 1 }
+       "@* MODE #usermode +q nick"
+}
+
+send "names #usermode\r"
+expect {
+       timeout { exit 1 }
+       "353 nick = #usermode :~nick"
+}
+expect {
+       timeout { exit 1 }
+       "366 nick #usermode"
+}
+
+send "part #usermode\r"
+expect {
+       timeout { exit 1 }
+       "@* PART #usermode"
+}
+
 send "join #channel\r"
 expect {
        timeout { exit 1 }
index dc88420636b7be4ccf5774fa7bb27b12ee540591..460f1148c6aec913995dbae377f683ddd8e5a248 100644 (file)
@@ -13,7 +13,7 @@ __ng_Makefile_am_template__
 
 EXTRA_DIST = Makefile.ng
 
-INCLUDES = -I$(srcdir)/../portab
+AM_CPPFLAGS = -I$(srcdir)/../portab
 
 noinst_LIBRARIES = libngtool.a