]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/irc-info.c
Introduce option to configure the maximum nick name lenth in ngircd.conf
[ngircd-alex.git] / src / ngircd / irc-info.c
index cf283b51d90e8a50280dc547099b6873d37884c9..683f7d1b04b8a79f0f3ff04f2d94771c14270ee4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2005 Alexander Barton (alex@barton.de)
  *
  * 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
 
 #include "portab.h"
 
-static char UNUSED id[] = "$Id: irc-info.c,v 1.28 2005/03/19 18:43:48 fw Exp $";
+static char UNUSED id[] = "$Id: irc-info.c,v 1.40 2007/11/21 12:16:36 alex Exp $";
 
 #include "imp.h"
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <strings.h>
 
@@ -97,7 +98,7 @@ IRC_ISON( CLIENT *Client, REQUEST *Req )
        /* Falsche Anzahl Parameter? */
        if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
 
-       strcpy( rpl, RPL_ISON_MSG );
+       strlcpy( rpl, RPL_ISON_MSG, sizeof rpl );
        for( i = 0; i < Req->argc; i++ )
        {
                ptr = strtok( Req->argv[i], " " );
@@ -376,7 +377,7 @@ IRC_STATS( CLIENT *Client, REQUEST *Req )
                        con = Conn_First( );
                        while( con != NONE )
                        {
-                               cl = Client_GetFromConn( con );
+                               cl = Conn_GetClient( con );
                                if( cl && (( Client_Type( cl ) == CLIENT_SERVER ) || ( cl == Client )))
                                {
                                        /* Server link or our own connection */
@@ -466,7 +467,7 @@ IRC_USERHOST( CLIENT *Client, REQUEST *Req )
        if( Req->argc > 5 ) max = 5;
        else max = Req->argc;
 
-       strcpy( rpl, RPL_USERHOST_MSG );
+       strlcpy( rpl, RPL_USERHOST_MSG, sizeof rpl );
        for( i = 0; i < max; i++ )
        {
                c = Client_Search( Req->argv[i] );
@@ -541,7 +542,8 @@ GLOBAL bool
 IRC_WHO( CLIENT *Client, REQUEST *Req )
 {
        bool ok, only_ops;
-       char flags[8], *ptr;
+       char flags[8];
+       const char *ptr;
        CL2CHAN *cl2chan;
        CHANNEL *chan, *cn;
        CLIENT *c;
@@ -705,10 +707,13 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req )
                if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
        }
 
-       /* Idle (only local clients) */
-       if( Client_Conn( c ) > NONE )
-       {
-               if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED;
+       /* Idle and signon time (local clients only!) */
+       if (Client_Conn(c) > NONE ) {
+               if (! IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
+                       Client_ID(from), Client_ID(c),
+                       (unsigned long)Conn_GetIdle(Client_Conn(c)),
+                       (unsigned long)Conn_GetSignon(Client_Conn(c))))
+                               return DISCONNECTED;
        }
 
        /* Away? */
@@ -722,25 +727,119 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req )
 } /* IRC_WHOIS */
 
 
+/**
+ * IRC "WHOWAS" function.
+ * This function implements the IRC command "WHOWHAS". It handles local
+ * requests and request that should be forwarded to other servers.
+ */
 GLOBAL bool
 IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
 {
+       CLIENT *target, *prefix;
+       WHOWAS *whowas;
+       int max, last, count, i;
+       char t_str[60];
+       
        assert( Client != NULL );
        assert( Req != NULL );
 
-       /* Falsche Anzahl Parameter? */
-       if(( Req->argc < 1 ) || ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+       /* Wrong number of parameters? */
+       if(( Req->argc < 1 ) || ( Req->argc > 3 ))
+               return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
+                                          Client_ID( Client ), Req->command );
 
-       /* ... */
+       /* Search taget */
+       if( Req->argc == 3 )
+               target = Client_Search( Req->argv[2] );
+       else
+               target = Client_ThisServer( );
 
-       return CONNECTED;
+       /* Get prefix */
+       if( Client_Type( Client ) == CLIENT_SERVER )
+               prefix = Client_Search( Req->prefix );
+       else
+               prefix = Client;
+
+       if( ! prefix )
+               return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG,
+                                          Client_ID( Client ), Req->prefix );
+
+       /* Forward to other server? */
+       if( target != Client_ThisServer( ))
+       {
+               if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
+                       return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG,
+                                                  Client_ID( prefix ),
+                                                  Req->argv[2] );
+
+               /* Forward */
+               IRC_WriteStrClientPrefix( target, prefix, "WHOWAS %s %s %s",
+                                         Req->argv[0], Req->argv[1],
+                                         Req->argv[2] );
+               return CONNECTED;
+       }
+       
+       whowas = Client_GetWhowas( );
+       last = Client_GetLastWhowasIndex( );
+       if( last < 0 ) last = 0;
+       
+       if( Req->argc > 1 )
+       {
+               max = atoi( Req->argv[1] );
+               if( max < 1 ) max = MAX_WHOWAS;
+       }
+       else
+               max = DEFAULT_WHOWAS;
+       
+       i = last;
+       count = 0;
+       do
+       {
+               /* Used entry? */
+               if( whowas[i].time > 0 &&
+                   strcasecmp( Req->argv[0], whowas[i].id ) == 0 )
+               {
+                       (void)strftime( t_str, sizeof(t_str),
+                                       "%a %b %d %H:%M:%S %Y",
+                                       localtime( &whowas[i].time ));
+               
+                       if( ! IRC_WriteStrClient( prefix, RPL_WHOWASUSER_MSG,
+                                                 Client_ID( prefix ),
+                                                 whowas[i].id,
+                                                 whowas[i].user,
+                                                 whowas[i].host, 
+                                                 whowas[i].info ))
+                               return DISCONNECTED;
+               
+                       if( ! IRC_WriteStrClient( prefix, RPL_WHOISSERVER_MSG,
+                                                 Client_ID( prefix ),
+                                                 whowas[i].id,
+                                                 whowas[i].server, t_str ))
+                               return DISCONNECTED;
+               
+                       count++;
+                       if( count >= max ) break;
+               }
+               
+               /* previos entry */
+               i--;
+
+               /* "underflow", wrap around */
+               if( i < 0 ) i = MAX_WHOWAS - 1;
+       } while( i != last );
+       
+       return IRC_WriteStrClient( prefix, RPL_ENDOFWHOWAS_MSG,
+                                  Client_ID( prefix ), Req->argv[0] );
 } /* IRC_WHOWAS */
 
 
 GLOBAL bool
 IRC_Send_LUSERS( CLIENT *Client )
 {
-       long cnt;
+       unsigned long cnt;
+#ifndef STRICT_RFC
+       unsigned long max;
+#endif
 
        assert( Client != NULL );
 
@@ -769,56 +868,81 @@ IRC_Send_LUSERS( CLIENT *Client )
 
 #ifndef STRICT_RFC
        /* Maximum number of local users */
-       if( ! IRC_WriteStrClient( Client, RPL_LOCALUSERS_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyMaxUserCount( ))) return DISCONNECTED;
+       cnt = Client_MyUserCount();
+       max = Client_MyMaxUserCount();
+       if (! IRC_WriteStrClient(Client, RPL_LOCALUSERS_MSG, Client_ID(Client),
+                       cnt, max, cnt, max))
+               return DISCONNECTED;
        /* Maximum number of users in the network */
-       if( ! IRC_WriteStrClient( Client, RPL_NETUSERS_MSG, Client_ID( Client ), Client_UserCount( ), Client_MaxUserCount( ))) return DISCONNECTED;
+       cnt = Client_UserCount();
+       max = Client_MaxUserCount();
+       if(! IRC_WriteStrClient(Client, RPL_NETUSERS_MSG, Client_ID(Client),
+                       cnt, max, cnt, max))
+               return DISCONNECTED;
 #endif
        
        return CONNECTED;
 } /* IRC_Send_LUSERS */
 
 
+static bool
+Show_MOTD_Start(CLIENT *Client)
+{
+       return IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG,
+               Client_ID( Client ), Client_ID( Client_ThisServer( )));
+}
+
+static bool
+Show_MOTD_Sendline(CLIENT *Client, const char *msg)
+{
+       return IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID( Client ), msg);
+}
+
+static bool
+Show_MOTD_End(CLIENT *Client)
+{
+       return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
+}
+
+
 GLOBAL bool
 IRC_Show_MOTD( CLIENT *Client )
 {
-       bool ok;
        char line[127];
        FILE *fd;
 
        assert( Client != NULL );
 
-       if( Conf_MotdPhrase[0] )
-       {
-               if( ! IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return DISCONNECTED;
-               if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), Conf_MotdPhrase )) return DISCONNECTED;
-               return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
+       if (Conf_MotdPhrase[0]) {
+               if (!Show_MOTD_Start(Client))
+                       return DISCONNECTED;
+               if (!Show_MOTD_Sendline(Client, Conf_MotdPhrase))
+                       return DISCONNECTED;
+
+               return Show_MOTD_End(Client);
        }
 
        fd = fopen( Conf_MotdFile, "r" );
-       if( ! fd )
-       {
+       if( ! fd ) {
                Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
                return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
        }
 
-       if( ! IRC_WriteStrClient( Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return DISCONNECTED;
-       while( true )
-       {
-               if( ! fgets( line, sizeof( line ), fd )) break;
+       if (!Show_MOTD_Start( Client )) {
+               fclose(fd);
+               return false;
+       }
 
+       while (fgets( line, (int)sizeof line, fd )) {
                ngt_TrimLastChr( line, '\n');
 
-               if( ! IRC_WriteStrClient( Client, RPL_MOTD_MSG, Client_ID( Client ), line ))
-               {
+               if( ! Show_MOTD_Sendline( Client, line)) {
                        fclose( fd );
                        return false;
                }
        }
-       ok = IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ) );
-
-       fclose( fd );
-
-       return ok;
+       fclose(fd);
+       return Show_MOTD_End(Client);
 } /* IRC_Show_MOTD */
 
 
@@ -926,4 +1050,22 @@ IRC_Send_WHO( CLIENT *Client, CHANNEL *Chan, bool OnlyOps )
 } /* IRC_Send_WHO */
 
 
+/**
+ * Send the ISUPPORT numeric (005).
+ * This numeric indicates the features that are supported by this server.
+ * See <http://www.irc.org/tech_docs/005.html> for details.
+ */
+GLOBAL bool
+IRC_Send_ISUPPORT PARAMS((CLIENT * Client))
+{
+       if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
+                               Conf_MaxJoins))
+               return DISCONNECTED;
+       return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
+                                 CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
+                                 COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
+                                 COMMAND_LEN - 113);
+} /* IRC_Send_ISUPPORT */
+
+
 /* -eof- */