2001-12-14 09:13:43 +01:00
/*
* ngIRCd - - The Next Generation IRC Daemon
2003-03-19 22:16:53 +01:00
* Copyright ( c ) 2001 - 2003 by Alexander Barton ( alex @ barton . de )
2001-12-14 09:13:43 +01:00
*
2002-12-12 13:24:18 +01:00
* 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
* 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 .
2001-12-14 09:13:43 +01:00
*
2002-12-12 13:24:18 +01:00
* IRC commands
2002-02-28 00:26:36 +01:00
*/
2001-12-26 04:21:46 +01:00
2002-03-12 15:37:51 +01:00
# include "portab.h"
2002-02-11 16:15:53 +01:00
2003-04-29 14:19:20 +02:00
static char UNUSED id [ ] = " $Id: irc.c,v 1.121 2003/04/29 12:19:20 alex Exp $ " ;
2002-12-12 13:24:18 +01:00
2002-03-12 15:37:51 +01:00
# include "imp.h"
2002-02-28 00:26:36 +01:00
# include <assert.h>
2002-12-12 12:40:41 +01:00
# include <stdio.h>
2002-02-28 00:26:36 +01:00
# include <string.h>
2001-12-26 04:21:46 +01:00
2003-01-13 19:56:30 +01:00
# include "ngircd.h"
# include "conn.h"
# include "resolve.h"
# include "conf.h"
2002-12-30 18:15:42 +01:00
# include "conn-func.h"
2002-02-28 00:26:36 +01:00
# include "client.h"
2002-05-27 15:09:26 +02:00
# include "channel.h"
2002-11-30 18:39:56 +01:00
# include "defines.h"
2002-02-28 00:26:36 +01:00
# include "irc-write.h"
# include "log.h"
# include "messages.h"
2002-05-27 15:09:26 +02:00
# include "parse.h"
2002-02-11 02:03:20 +01:00
2002-03-12 15:37:51 +01:00
# include "exp.h"
2002-02-28 00:26:36 +01:00
# include "irc.h"
2001-12-26 04:21:46 +01:00
2003-03-19 22:16:53 +01:00
LOCAL CHAR * Option_String PARAMS ( ( CONN_ID Idx ) ) ;
2002-05-27 15:09:26 +02:00
GLOBAL BOOLEAN
IRC_ERROR ( CLIENT * Client , REQUEST * Req )
2002-01-02 03:44:36 +01:00
{
assert ( Client ! = NULL ) ;
assert ( Req ! = NULL ) ;
2002-01-04 02:21:47 +01:00
if ( Req - > argc < 1 ) Log ( LOG_NOTICE , " Got ERROR from \" %s \" ! " , Client_Mask ( Client ) ) ;
else Log ( LOG_NOTICE , " Got ERROR from \" %s \" : %s! " , Client_Mask ( Client ) , Req - > argv [ 0 ] ) ;
2002-01-02 03:44:36 +01:00
return CONNECTED ;
} /* IRC_ERROR */
2001-12-31 03:18:51 +01:00
2002-05-27 15:09:26 +02:00
GLOBAL BOOLEAN
IRC_KILL ( CLIENT * Client , REQUEST * Req )
2002-02-23 22:39:48 +01:00
{
CLIENT * prefix , * c ;
2002-12-06 18:02:39 +01:00
CHAR reason [ COMMAND_LEN ] ;
2002-12-31 17:09:55 +01:00
CONN_ID my_conn , conn ;
2002-11-30 18:39:56 +01:00
2002-02-23 22:39:48 +01:00
assert ( Client ! = NULL ) ;
assert ( Req ! = NULL ) ;
2002-12-26 19:41:00 +01:00
/* Is the user an IRC operator? */
2002-12-06 18:02:39 +01:00
if ( ( Client_Type ( Client ) ! = CLIENT_SERVER ) & & ( ! Client_OperByMe ( Client ) ) ) return IRC_WriteStrClient ( Client , ERR_NOPRIVILEGES_MSG , Client_ID ( Client ) ) ;
2002-12-26 19:41:00 +01:00
/* Bad number of parameters? */
2002-02-23 22:39:48 +01:00
if ( ( Req - > argc ! = 2 ) ) return IRC_WriteStrClient ( Client , ERR_NEEDMOREPARAMS_MSG , Client_ID ( Client ) , Req - > command ) ;
2002-12-06 18:02:39 +01:00
if ( Req - > prefix ) prefix = Client_Search ( Req - > prefix ) ;
else prefix = Client ;
2002-02-23 22:39:48 +01:00
if ( ! prefix )
{
Log ( LOG_WARNING , " Got KILL with invalid prefix: \" %s \" ! " , Req - > prefix ) ;
prefix = Client_ThisServer ( ) ;
}
2002-11-30 18:39:56 +01:00
2003-01-08 23:27:13 +01:00
if ( Client ! = Client_ThisServer ( ) ) Log ( LOG_NOTICE | LOG_snotice , " Got KILL command from \" %s \" for \" %s \" : %s " , Client_Mask ( prefix ) , Req - > argv [ 0 ] , Req - > argv [ 1 ] ) ;
2002-12-06 18:02:39 +01:00
2002-12-26 19:41:00 +01:00
/* Build reason string */
2002-12-26 18:14:48 +01:00
if ( Client_Type ( Client ) = = CLIENT_USER ) snprintf ( reason , sizeof ( reason ) , " KILLed by %s: %s " , Client_ID ( Client ) , Req - > argv [ 1 ] ) ;
2002-12-26 18:04:54 +01:00
else strlcpy ( reason , Req - > argv [ 1 ] , sizeof ( reason ) ) ;
2002-11-30 18:39:56 +01:00
2002-12-26 19:41:00 +01:00
/* Inform other servers */
2002-12-06 18:02:39 +01:00
IRC_WriteStrServersPrefix ( Client , prefix , " KILL %s :%s " , Req - > argv [ 0 ] , reason ) ;
2002-02-23 22:39:48 +01:00
2002-12-31 17:09:55 +01:00
/* Save ID of this connection */
my_conn = Client_Conn ( Client ) ;
2002-12-26 19:41:00 +01:00
/* Do we host such a client? */
2002-03-25 18:04:02 +01:00
c = Client_Search ( Req - > argv [ 0 ] ) ;
2002-07-25 13:37:01 +02:00
if ( c )
{
2002-12-27 14:17:04 +01:00
/* Yes, there is such a client -- but is it a valid user? */
2003-04-29 14:19:20 +02:00
if ( Client_Type ( c ) = = CLIENT_SERVER )
{
if ( Client ! = Client_ThisServer ( ) ) IRC_WriteStrClient ( Client , ERR_CANTKILLSERVER_MSG , Client_ID ( Client ) ) ;
else
{
/* Oops, I should kill another server!? */
Log ( LOG_ERR , " Can't KILL server \" %s \" ! " , Req - > argv [ 0 ] ) ;
conn = Client_Conn ( Client_NextHop ( c ) ) ;
assert ( conn > NONE ) ;
Conn_Close ( conn , NULL , " Nick collision for server!? " , TRUE ) ;
}
}
else if ( Client_Type ( c ) ! = CLIENT_USER )
{
if ( Client ! = Client_ThisServer ( ) ) IRC_WriteStrClient ( Client , ERR_NOPRIVILEGES_MSG , Client_ID ( Client ) ) ;
else
{
/* Oops, what sould I close?? */
Log ( LOG_ERR , " Can't KILL \" %s \" : invalid client type! " , Req - > argv [ 0 ] ) ;
conn = Client_Conn ( Client_NextHop ( c ) ) ;
assert ( conn > NONE ) ;
Conn_Close ( conn , NULL , " Collision for invalid client type!? " , TRUE ) ;
}
}
2002-12-27 14:17:04 +01:00
else
{
/* Kill user NOW! */
conn = Client_Conn ( c ) ;
Client_Destroy ( c , NULL , reason , FALSE ) ;
2003-01-08 23:07:34 +01:00
if ( conn ! = NONE ) Conn_Close ( conn , NULL , reason , TRUE ) ;
2002-12-27 14:17:04 +01:00
}
2002-07-25 13:37:01 +02:00
}
else Log ( LOG_NOTICE , " Client with nick \" %s \" is unknown here. " , Req - > argv [ 0 ] ) ;
2002-12-26 19:41:00 +01:00
/* Are we still connected or were we killed, too? */
2003-01-08 23:27:13 +01:00
if ( ( my_conn > NONE ) & & ( Client_GetFromConn ( my_conn ) ) ) return CONNECTED ;
2002-12-26 19:41:00 +01:00
else return DISCONNECTED ;
2002-02-23 22:39:48 +01:00
} /* IRC_KILL */
2002-09-16 11:14:45 +02:00
GLOBAL BOOLEAN
2002-11-30 18:39:56 +01:00
IRC_NOTICE ( CLIENT * Client , REQUEST * Req )
2002-09-16 11:14:45 +02:00
{
2002-11-30 18:39:56 +01:00
CLIENT * to , * from ;
2002-09-16 11:14:45 +02:00
assert ( Client ! = NULL ) ;
assert ( Req ! = NULL ) ;
2002-11-30 18:39:56 +01:00
if ( ( Client_Type ( Client ) ! = CLIENT_USER ) & & ( Client_Type ( Client ) ! = CLIENT_SERVER ) ) return CONNECTED ;
2002-11-24 19:45:53 +01:00
/* Falsche Anzahl Parameter? */
2002-11-30 18:39:56 +01:00
if ( Req - > argc ! = 2 ) return CONNECTED ;
2002-11-24 19:45:53 +01:00
if ( Client_Type ( Client ) = = CLIENT_SERVER ) from = Client_Search ( Req - > prefix ) ;
else from = Client ;
2002-11-30 18:39:56 +01:00
if ( ! from ) return IRC_WriteStrClient ( Client , ERR_NOSUCHNICK_MSG , Client_ID ( Client ) , Req - > prefix ) ;
2001-12-26 23:48:53 +01:00
2002-11-30 18:39:56 +01:00
to = Client_Search ( Req - > argv [ 0 ] ) ;
if ( ( to ) & & ( Client_Type ( to ) = = CLIENT_USER ) )
2001-12-26 23:48:53 +01:00
{
2002-11-30 18:39:56 +01:00
/* Okay, Ziel ist ein User */
return IRC_WriteStrClientPrefix ( to , from , " NOTICE %s :%s " , Client_ID ( to ) , Req - > argv [ 1 ] ) ;
2001-12-26 23:48:53 +01:00
}
2002-11-30 18:39:56 +01:00
else return CONNECTED ;
} /* IRC_NOTICE */
2002-02-23 22:39:48 +01:00
2002-01-04 02:21:47 +01:00
2002-05-27 15:09:26 +02:00
GLOBAL BOOLEAN
2002-11-30 18:39:56 +01:00
IRC_PRIVMSG ( CLIENT * Client , REQUEST * Req )
2002-01-28 14:05:48 +01:00
{
2002-11-30 18:39:56 +01:00
CLIENT * cl , * from ;
CHANNEL * chan ;
2002-01-28 14:05:48 +01:00
assert ( Client ! = NULL ) ;
2002-11-30 18:39:56 +01:00
assert ( Req ! = NULL ) ;
2002-03-03 20:44:30 +01:00
2002-11-30 18:39:56 +01:00
/* Falsche Anzahl Parameter? */
if ( Req - > argc = = 0 ) return IRC_WriteStrClient ( Client , ERR_NORECIPIENT_MSG , Client_ID ( Client ) , Req - > command ) ;
if ( Req - > argc = = 1 ) return IRC_WriteStrClient ( Client , ERR_NOTEXTTOSEND_MSG , Client_ID ( Client ) ) ;
if ( Req - > argc > 2 ) return IRC_WriteStrClient ( Client , ERR_NEEDMOREPARAMS_MSG , Client_ID ( Client ) , Req - > command ) ;
2002-03-03 20:44:30 +01:00
2002-11-30 18:39:56 +01:00
if ( Client_Type ( Client ) = = CLIENT_SERVER ) from = Client_Search ( Req - > prefix ) ;
else from = Client ;
if ( ! from ) return IRC_WriteStrClient ( Client , ERR_NOSUCHNICK_MSG , Client_ID ( Client ) , Req - > prefix ) ;
2002-03-03 20:44:30 +01:00
2002-11-30 18:39:56 +01:00
cl = Client_Search ( Req - > argv [ 0 ] ) ;
if ( cl )
2002-03-03 20:44:30 +01:00
{
2002-11-30 18:39:56 +01:00
/* Okay, Ziel ist ein Client. Aber ist es auch ein User? */
if ( Client_Type ( cl ) ! = CLIENT_USER ) return IRC_WriteStrClient ( from , ERR_NOSUCHNICK_MSG , Client_ID ( from ) , Req - > argv [ 0 ] ) ;
2002-03-03 20:44:30 +01:00
2002-11-30 18:39:56 +01:00
/* Okay, Ziel ist ein User */
if ( ( Client_Type ( Client ) ! = CLIENT_SERVER ) & & ( strchr ( Client_Modes ( cl ) , ' a ' ) ) )
2002-03-03 20:44:30 +01:00
{
2002-11-30 18:39:56 +01:00
/* Ziel-User ist AWAY: Meldung verschicken */
if ( ! IRC_WriteStrClient ( from , RPL_AWAY_MSG , Client_ID ( from ) , Client_ID ( cl ) , Client_Away ( cl ) ) ) return DISCONNECTED ;
2002-03-03 20:44:30 +01:00
}
2002-11-30 18:39:56 +01:00
/* Text senden */
if ( Client_Conn ( from ) > NONE ) Conn_UpdateIdle ( Client_Conn ( from ) ) ;
return IRC_WriteStrClientPrefix ( cl , from , " PRIVMSG %s :%s " , Client_ID ( cl ) , Req - > argv [ 1 ] ) ;
2002-02-14 00:05:29 +01:00
}
2002-11-30 18:39:56 +01:00
chan = Channel_Search ( Req - > argv [ 0 ] ) ;
if ( chan ) return Channel_Write ( chan , from , Client , Req - > argv [ 1 ] ) ;
2002-02-14 00:05:29 +01:00
2002-11-30 18:39:56 +01:00
return IRC_WriteStrClient ( from , ERR_NOSUCHNICK_MSG , Client_ID ( from ) , Req - > argv [ 0 ] ) ;
} /* IRC_PRIVMSG */
2002-02-25 18:46:27 +01:00
2003-01-13 19:56:30 +01:00
GLOBAL BOOLEAN
IRC_TRACE ( CLIENT * Client , REQUEST * Req )
{
2003-03-19 22:16:53 +01:00
CLIENT * from , * target , * c ;
2003-01-13 19:56:30 +01:00
CONN_ID idx , idx2 ;
assert ( Client ! = NULL ) ;
assert ( Req ! = NULL ) ;
/* Bad number of arguments? */
if ( Req - > argc > 1 ) return IRC_WriteStrClient ( Client , ERR_NORECIPIENT_MSG , Client_ID ( Client ) , Req - > command ) ;
/* Search sender */
if ( Client_Type ( Client ) = = CLIENT_SERVER ) from = Client_Search ( Req - > prefix ) ;
else from = Client ;
if ( ! from ) return IRC_WriteStrClient ( Client , ERR_NOSUCHNICK_MSG , Client_ID ( Client ) , Req - > prefix ) ;
/* Search target */
if ( Req - > argc = = 1 ) target = Client_Search ( Req - > argv [ 0 ] ) ;
else target = Client_ThisServer ( ) ;
/* Forward command to other server? */
if ( target ! = Client_ThisServer ( ) )
{
if ( ( ! target ) | | ( Client_Type ( target ) ! = CLIENT_SERVER ) ) return IRC_WriteStrClient ( from , ERR_NOSUCHSERVER_MSG , Client_ID ( from ) , Req - > argv [ 0 ] ) ;
/* Send RPL_TRACELINK back to initiator */
idx = Client_Conn ( Client ) ; assert ( idx > NONE ) ;
idx2 = Client_Conn ( Client_NextHop ( target ) ) ; assert ( idx2 > NONE ) ;
2003-03-31 17:54:21 +02:00
if ( ! IRC_WriteStrClient ( from , RPL_TRACELINK_MSG , Client_ID ( from ) , PACKAGE_NAME , PACKAGE_VERSION , Client_ID ( target ) , Client_ID ( Client_NextHop ( target ) ) , Option_String ( idx2 ) , time ( NULL ) - Conn_StartTime ( idx2 ) , Conn_SendQ ( idx ) , Conn_SendQ ( idx2 ) ) ) return DISCONNECTED ;
2003-01-13 19:56:30 +01:00
/* Forward command */
IRC_WriteStrClientPrefix ( target , from , " TRACE %s " , Req - > argv [ 0 ] ) ;
return CONNECTED ;
}
2003-03-19 22:16:53 +01:00
/* Infos about all connected servers */
c = Client_First ( ) ;
while ( c )
{
if ( Client_Conn ( c ) > NONE )
{
/* Local client */
if ( Client_Type ( c ) = = CLIENT_SERVER )
{
/* Server link */
if ( ! IRC_WriteStrClient ( from , RPL_TRACESERVER_MSG , Client_ID ( from ) , Client_ID ( c ) , Client_Mask ( c ) , Option_String ( Client_Conn ( c ) ) ) ) return DISCONNECTED ;
}
if ( ( Client_Type ( c ) = = CLIENT_USER ) & & ( strchr ( Client_Modes ( c ) , ' o ' ) ) )
{
/* IRC Operator */
if ( ! IRC_WriteStrClient ( from , RPL_TRACEOPERATOR_MSG , Client_ID ( from ) , Client_ID ( c ) ) ) return DISCONNECTED ;
}
}
c = Client_Next ( c ) ;
}
/* Some information about us */
if ( ! IRC_WriteStrClient ( from , RPL_TRACESERVER_MSG , Client_ID ( from ) , Conf_ServerName , Client_Mask ( Client_ThisServer ( ) ) , Option_String ( Client_Conn ( Client ) ) ) ) return DISCONNECTED ;
2003-03-31 17:54:21 +02:00
return IRC_WriteStrClient ( from , RPL_TRACEEND_MSG , Client_ID ( from ) , Conf_ServerName , PACKAGE_NAME , PACKAGE_VERSION , NGIRCd_DebugLevel ) ;
2003-01-13 19:56:30 +01:00
} /* IRC_TRACE */
2003-01-15 14:49:20 +01:00
GLOBAL BOOLEAN
IRC_HELP ( CLIENT * Client , REQUEST * Req )
{
COMMAND * cmd ;
assert ( Client ! = NULL ) ;
assert ( Req ! = NULL ) ;
/* Bad number of arguments? */
if ( Req - > argc > 0 ) return IRC_WriteStrClient ( Client , ERR_NORECIPIENT_MSG , Client_ID ( Client ) , Req - > command ) ;
cmd = Parse_GetCommandStruct ( ) ;
while ( cmd - > name )
{
if ( ! IRC_WriteStrClient ( Client , " NOTICE %s :%s " , Client_ID ( Client ) , cmd - > name ) ) return DISCONNECTED ;
cmd + + ;
}
return CONNECTED ;
} /* IRC_HELP */
2003-03-19 22:16:53 +01:00
LOCAL CHAR *
Option_String ( CONN_ID Idx )
{
STATIC CHAR option_txt [ 8 ] ;
INT options ;
options = Conn_Options ( Idx ) ;
strcpy ( option_txt , " F " ) ; /* No idea what this means but the original ircd sends it ... */
# ifdef USE_ZLIB
if ( options & CONN_ZIP ) strcat ( option_txt , " z " ) ;
# endif
return option_txt ;
} /* Option_String */
2001-12-14 09:13:43 +01:00
/* -eof- */