]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/numeric.c
Only log "IDENT ... no result" when IDENT was looked up
[ngircd-alex.git] / src / ngircd / numeric.c
index d22bf3ae348c3b2ebeccf63dc3fbad1e5f3d56a0..a43739f18bf4dec9b44183396526c157d408b84b 100644 (file)
@@ -7,12 +7,15 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
- *
- * Handlers for IRC numerics sent to the server
  */
 
 #include "portab.h"
 
+/**
+ * @file
+ * Handlers for IRC numerics sent to the server
+ */
+
 #include "imp.h"
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
 #include "defines.h"
-#include "resolve.h"
 #include "conn.h"
 #include "conf.h"
 #include "conn.h"
 #include "conn-func.h"
-#include "client.h"
 #include "channel.h"
+#include "class.h"
 #include "irc-write.h"
 #include "lists.h"
 #include "log.h"
 #include "numeric.h"
 
 
+/**
+ * Announce a channel and its users in the network.
+ */
+static bool
+Announce_Channel(CLIENT *Client, CHANNEL *Chan)
+{
+       CL2CHAN *cl2chan;
+       CLIENT *cl;
+       char str[LINE_LEN], *ptr;
+       bool njoin, xop;
+
+       /* Check features of remote server */
+       njoin = Conn_Options(Client_Conn(Client)) & CONN_RFC1459 ? false : true;
+       xop = Client_HasFlag(Client, 'X') ? true : false;
+
+       /* Get all the members of this channel */
+       cl2chan = Channel_FirstMember(Chan);
+       snprintf(str, sizeof(str), "NJOIN %s :", Channel_Name(Chan));
+       while (cl2chan) {
+               cl = Channel_GetClient(cl2chan);
+               assert(cl != NULL);
+
+               if (njoin) {
+                       /* RFC 2813: send NJOIN with nicknames and modes
+                        * (if user is channel operator or has voice) */
+                       if (str[strlen(str) - 1] != ':')
+                               strlcat(str, ",", sizeof(str));
+
+                       /* Prepare user prefix (ChanOp, voiced, ...) */
+                       if (xop && Channel_UserHasMode(Chan, cl, 'q'))
+                               strlcat(str, "~", sizeof(str));
+                       if (xop && Channel_UserHasMode(Chan, cl, 'a'))
+                               strlcat(str, "&", sizeof(str));
+                       if (Channel_UserHasMode(Chan, cl, 'o'))
+                               strlcat(str, "@", sizeof(str));
+                       if (xop && Channel_UserHasMode(Chan, cl, 'h'))
+                               strlcat(str, "%", sizeof(str));
+                       if (Channel_UserHasMode(Chan, cl, 'v'))
+                               strlcat(str, "+", sizeof(str));
+
+                       strlcat(str, Client_ID(cl), sizeof(str));
+
+                       /* Send the data if the buffer is "full" */
+                       if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 8)) {
+                               if (!IRC_WriteStrClient(Client, "%s", str))
+                                       return DISCONNECTED;
+                               snprintf(str, sizeof(str), "NJOIN %s :",
+                                        Channel_Name(Chan));
+                       }
+               } else {
+                       /* RFC 1459: no NJOIN, send JOIN and MODE */
+                       if (!IRC_WriteStrClientPrefix(Client, cl, "JOIN %s",
+                                               Channel_Name(Chan)))
+                               return DISCONNECTED;
+                       ptr = Channel_UserModes(Chan, cl);
+                       while (*ptr) {
+                               if (!IRC_WriteStrClientPrefix(Client, cl,
+                                                  "MODE %s +%c %s",
+                                                  Channel_Name(Chan), ptr[0],
+                                                  Client_ID(cl)))
+                                       return DISCONNECTED;
+                               ptr++;
+                       }
+               }
+
+               cl2chan = Channel_NextMember(Chan, cl2chan);
+       }
+
+       /* Data left in the buffer? */
+       if (str[strlen(str) - 1] != ':') {
+               /* Yes, send it ... */
+               if (!IRC_WriteStrClient(Client, "%s", str))
+                       return DISCONNECTED;
+       }
+
+       return CONNECTED;
+} /* Announce_Channel */
+
+
 /**
  * Announce new server in the network
  * @param Client New server
@@ -60,7 +141,7 @@ Announce_Server(CLIENT * Client, CLIENT * Server)
        if (Client_Hops(Server) == 1)
                c = Client_ThisServer();
        else
-               c = Client_Introducer(Server);
+               c = Client_TopServer(Server);
 
        /* Inform new server about the one already registered in the network */
        return IRC_WriteStrClientPrefix(Client, c, "SERVER %s %d %d :%s",
@@ -69,43 +150,13 @@ Announce_Server(CLIENT * Client, CLIENT * Server)
 } /* Announce_Server */
 
 
-/**
- * Announce existing user to a new server
- * @param Client New server
- * @param User Existing user in the network
- */
-static bool
-Announce_User(CLIENT * Client, CLIENT * User)
-{
-       CONN_ID conn;
-       conn = Client_Conn(Client);
-       if (Conn_Options(conn) & CONN_RFC1459) {
-               /* RFC 1459 mode: separate NICK and USER commands */
-               if (! Conn_WriteStr(conn, "NICK %s :%d",
-                                   Client_ID(User), Client_Hops(User) + 1))
-                       return DISCONNECTED;
-               return Conn_WriteStr(conn, ":%s USER %s %s %s :%s",
-                                    Client_ID(User), Client_User(User),
-                                    Client_Hostname(User),
-                                    Client_ID(Client_Introducer(User)),
-                                    Client_Info(User));
-               
-       } else {
-               /* RFC 2813 mode: one combined NICK command */
-               return IRC_WriteStrClient(Client, "NICK %s %d %s %s %d +%s :%s",
-                               Client_ID(User), Client_Hops(User) + 1,
-                               Client_User(User), Client_Hostname(User),
-                               Client_MyToken(Client_Introducer(User)),
-                               Client_Modes(User), Client_Info(User));
-       }
-} /* Announce_User */
-
-
 #ifdef IRCPLUS
 
 /**
- * Synchronize invite and ban lists between servers
- * @param Client New server
+ * Synchronize invite, ban, G- and K-Line lists between servers.
+ *
+ * @param Client New server.
+ * @return CONNECTED or DISCONNECTED.
  */
 static bool
 Synchronize_Lists(CLIENT * Client)
@@ -116,6 +167,18 @@ Synchronize_Lists(CLIENT * Client)
 
        assert(Client != NULL);
 
+       /* g-lines */
+       head = Class_GetList(CLASS_GLINE);
+       elem = Lists_GetFirst(head);
+       while (elem) {
+               if (!IRC_WriteStrClient(Client, "GLINE %s %ld :%s",
+                                       Lists_GetMask(elem),
+                                       Lists_GetValidity(elem) - time(NULL),
+                                       Lists_GetReason(elem)))
+                       return DISCONNECTED;
+               elem = Lists_GetNext(elem);
+       }
+
        c = Channel_First();
        while (c) {
                /* ban list */
@@ -158,20 +221,20 @@ Send_CHANINFO(CLIENT * Client, CHANNEL * Chan)
 {
        char *modes, *topic;
        bool has_k, has_l;
-       
+
 #ifdef DEBUG
        Log(LOG_DEBUG, "Sending CHANINFO commands ...");
 #endif
-       
+
        modes = Channel_Modes(Chan);
        topic = Channel_Topic(Chan);
-       
+
        if (!*modes && !*topic)
                return CONNECTED;
-       
-       has_k = strchr(modes, 'k') != NULL;
-       has_l = strchr(modes, 'l') != NULL;
-       
+
+       has_k = Channel_HasMode(Chan, 'k');
+       has_l = Channel_HasMode(Chan, 'l');
+
        /* send CHANINFO */
        if (!has_k && !has_l) {
                if (!*topic) {
@@ -201,11 +264,9 @@ Send_CHANINFO(CLIENT * Client, CHANNEL * Chan)
 GLOBAL bool
 IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req)
 {
-       char str[LINE_LEN];
        int max_hops, i;
-       CLIENT *c, *cl;
+       CLIENT *c;
        CHANNEL *chan;
-       CL2CHAN *cl2chan;
 
        Client_SetType(Client, CLIENT_SERVER);
 
@@ -243,8 +304,9 @@ IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req)
        /* Announce all the users to the new server */
        c = Client_First();
        while (c) {
-               if (Client_Type(c) == CLIENT_USER) {
-                       if (!Announce_User(Client, c))
+               if (Client_Type(c) == CLIENT_USER ||
+                   Client_Type(c) == CLIENT_SERVICE) {
+                       if (!Client_Announce(Client, Client_ThisServer(), c))
                                return DISCONNECTED;
                }
                c = Client_Next(c);
@@ -253,60 +315,37 @@ IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req)
        /* Announce all channels to the new server */
        chan = Channel_First();
        while (chan) {
+               if (Channel_IsLocal(chan)) {
+                       chan = Channel_Next(chan);
+                       continue;
+               }
 #ifdef IRCPLUS
                /* Send CHANINFO if the peer supports it */
-               if (strchr(Client_Flags(Client), 'C')) {
+               if (Client_HasFlag(Client, 'C')) {
                        if (!Send_CHANINFO(Client, chan))
                                return DISCONNECTED;
                }
 #endif
 
-               /* Get all the members of this channel */
-               cl2chan = Channel_FirstMember(chan);
-               snprintf(str, sizeof(str), "NJOIN %s :", Channel_Name(chan));
-               while (cl2chan) {
-                       cl = Channel_GetClient(cl2chan);
-                       assert(cl != NULL);
-
-                       /* Nick name, with modes (if applicable) */
-                       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), 'o'))
-                               strlcat(str, "@", sizeof(str));
-                       strlcat(str, Client_ID(cl), sizeof(str));
-
-                       /* Send the data if the buffer is "full" */
-                       if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 8)) {
-                               if (!IRC_WriteStrClient(Client, "%s", str))
-                                       return DISCONNECTED;
-                               snprintf(str, sizeof(str), "NJOIN %s :",
-                                        Channel_Name(chan));
-                       }
-
-                       cl2chan = Channel_NextMember(chan, cl2chan);
-               }
-
-               /* Data left in the buffer? */
-               if (str[strlen(str) - 1] != ':') {
-                       /* Yes, send it ... */
-                       if (!IRC_WriteStrClient(Client, "%s", str))
-                               return DISCONNECTED;
-               }
+               if (!Announce_Channel(Client, chan))
+                       return DISCONNECTED;
 
                /* Get next channel ... */
                chan = Channel_Next(chan);
        }
 
 #ifdef IRCPLUS
-       if (strchr(Client_Flags(Client), 'L')) {
+       if (Client_HasFlag(Client, 'L')) {
                LogDebug("Synchronizing INVITE- and BAN-lists ...");
                if (!Synchronize_Lists(Client))
                        return DISCONNECTED;
        }
 #endif
 
+       if (!IRC_WriteStrClient(Client, "PING :%s",
+           Client_ID(Client_ThisServer())))
+               return DISCONNECTED;
+
        return CONNECTED;
 } /* IRC_Num_ENDOFMOTD */
 
@@ -332,12 +371,12 @@ IRC_Num_ISUPPORT(CLIENT * Client, REQUEST * Req)
                        if ((unsigned int)atol(value) == Conf_MaxNickLength - 1)
                                continue;
 
-                       /* Nick name length settings are different! */
+                       /* Nickname length settings are different! */
                        Log(LOG_ERR,
-                           "Peer uses incompatible nick name length (%d/%d)! Disconnecting ...",
+                           "Peer uses incompatible nickname length (%d/%d)! Disconnecting ...",
                            Conf_MaxNickLength - 1, atoi(value));
                        Conn_Close(Client_Conn(Client),
-                                  "Incompatible nick name length",
+                                  "Incompatible nickname length",
                                   NULL, false);
                        return DISCONNECTED;
                }