X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc-login.c;h=7ad1cb7823e6cc81d31191a507bcc9d594a5b671;hp=bf3254c985807e62ff24232e46ab1f6babc32752;hb=6bdae55177bf3d8910a77bc0af14c0de3d4fd4c9;hpb=110be707c306683c666bd736a8dcd7aef86d9f21 diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index bf3254c9..7ad1cb78 100644 --- a/src/ngircd/irc-login.c +++ b/src/ngircd/irc-login.c @@ -1,6 +1,6 @@ /* * ngIRCd -- The Next Generation IRC Daemon - * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors. + * Copyright (c)2001-2014 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 @@ -16,13 +16,14 @@ * Login and logout */ -#include "imp.h" #include +#include #include +#include #include +#include #include "conn-func.h" -#include "class.h" #include "conf.h" #include "channel.h" #include "log.h" @@ -30,22 +31,20 @@ #include "messages.h" #include "parse.h" #include "irc.h" -#include "irc-info.h" +#include "irc-macros.h" #include "irc-write.h" -#include "exp.h" #include "irc-login.h" -static void Kill_Nick PARAMS(( char *Nick, char *Reason )); +static void Change_Nick PARAMS((CLIENT * Origin, CLIENT * Target, char *NewNick, + bool InformClient)); /** * Handler for the IRC "PASS" command. * - * See RFC 2813 section 4.1.1, and RFC 2812 section 3.1.1. - * - * @param Client The client from which this command has been received. - * @param Req Request structure with prefix and all parameters. - * @returns CONNECTED or DISCONNECTED. + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_PASS( CLIENT *Client, REQUEST *Req ) @@ -58,7 +57,7 @@ IRC_PASS( CLIENT *Client, REQUEST *Req ) /* Return an error if this is not a local client */ if (Client_Conn(Client) <= NONE) - return IRC_WriteStrClient(Client, ERR_UNKNOWNCOMMAND_MSG, + return IRC_WriteErrClient(Client, ERR_UNKNOWNCOMMAND_MSG, Client_ID(Client), Req->command); if (Client_Type(Client) == CLIENT_UNKNOWN && Req->argc == 1) { @@ -78,15 +77,15 @@ IRC_PASS( CLIENT *Client, REQUEST *Req ) } else if (Client_Type(Client) == CLIENT_UNKNOWN || Client_Type(Client) == CLIENT_UNKNOWNSERVER) { /* Unregistered connection, but wrong number of arguments: */ - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); } else { /* Registered connection, PASS command is not allowed! */ - return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG, + return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG, Client_ID(Client)); } - Client_SetPassword(Client, Req->argv[0]); + Conn_SetPassword(Client_Conn(Client), Req->argv[0]); /* Protocol version */ if (Req->argc >= 2 && strlen(Req->argv[1]) >= 4) { @@ -141,7 +140,7 @@ IRC_PASS( CLIENT *Client, REQUEST *Req ) } else flags = ""; Log(LOG_INFO, - "Peer on conenction %d announces itself as %s-%s using protocol %d.%d/IRC+ (flags: \"%s\").", + "Peer on connection %d announces itself as %s-%s using protocol %d.%d/IRC+ (flags: \"%s\").", Client_Conn(Client), impl, serverver, protohigh, protolow, flags); } else { @@ -162,19 +161,12 @@ IRC_PASS( CLIENT *Client, REQUEST *Req ) return CONNECTED; } /* IRC_PASS */ - /** * Handler for the IRC "NICK" command. * - * See RFC 2812, 3.1.2 "Nick message", and RFC 2813, 4.1.3 "Nick". - * - * This function implements the IRC command "NICK" which is used to register - * with the server, to change already registered nicknames and to introduce - * new users which are connected to other servers. - * - * @param Client The client from which this command has been received. - * @param Req Request structure with prefix and all parameters. - * @returns CONNECTED or DISCONNECTED. + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_NICK( CLIENT *Client, REQUEST *Req ) @@ -199,31 +191,22 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) || (Client_Type(Client) == CLIENT_SERVER && Req->argc == 1)) { /* User registration or change of nickname */ - - /* Wrong number of arguments? */ - if( Req->argc != 1 ) - return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, - Client_ID( Client ), - Req->command ); + _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 1) /* Search "target" client */ - if( Client_Type( Client ) == CLIENT_SERVER ) - { - target = Client_Search( Req->prefix ); - if( ! target ) - return IRC_WriteStrClient( Client, - ERR_NOSUCHNICK_MSG, - Client_ID( Client ), - Req->argv[0] ); - } - else - { + if (Client_Type(Client) == CLIENT_SERVER) { + target = Client_Search(Req->prefix); + if (!target) + return IRC_WriteErrClient(Client, + ERR_NOSUCHNICK_MSG, + Client_ID(Client), + Req->argv[0]); + } else { /* Is this a restricted client? */ - if( Client_HasMode( Client, 'r' )) - return IRC_WriteStrClient( Client, - ERR_RESTRICTED_MSG, - Client_ID( Client )); - + if (Client_HasMode(Client, 'r')) + return IRC_WriteErrClient(Client, + ERR_RESTRICTED_MSG, + Client_ID(Client)); target = Client; } @@ -232,15 +215,14 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) * do anything. This is how the original ircd behaves and some * clients (for example Snak) expect it to be like this. * But I doubt that this is "really the right thing" ... */ - if( strcmp( Client_ID( target ), Req->argv[0] ) == 0 ) + if (strcmp(Client_ID(target), Req->argv[0]) == 0) return CONNECTED; #endif /* Check that the new nickname is available. Special case: * the client only changes from/to upper to lower case. */ - if( strcasecmp( Client_ID( target ), Req->argv[0] ) != 0 ) - { - if( ! Client_CheckNick( target, Req->argv[0] )) + if (strcasecmp(Client_ID(target), Req->argv[0]) != 0) { + if (!Client_CheckNick(target, Req->argv[0])) return CONNECTED; } @@ -256,8 +238,12 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) #ifndef STRICT_RFC if (Conf_AuthPing) { +#ifdef HAVE_ARC4RANDOM + Conn_SetAuthPing(Client_Conn(Client), arc4random()); +#else Conn_SetAuthPing(Client_Conn(Client), rand()); - IRC_WriteStrClient(Client, "PING :%ld", +#endif + Conn_WriteStr(Client_Conn(Client), "PING :%ld", Conn_GetAuthPing(Client_Conn(Client))); LogDebug("Connection %d: sent AUTH PING %ld ...", Client_Conn(Client), @@ -273,40 +259,9 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) Client_SetType( Client, CLIENT_GOTNICK ); } else { /* Nickname change */ - if (Client_Conn(target) > NONE) { - /* Local client */ - Log(LOG_INFO, - "%s \"%s\" changed nick (connection %d): \"%s\" -> \"%s\".", - Client_TypeText(target), Client_Mask(target), - Client_Conn(target), Client_ID(target), - Req->argv[0]); - Conn_UpdateIdle(Client_Conn(target)); - } else { - /* Remote client */ - LogDebug("%s \"%s\" changed nick: \"%s\" -> \"%s\".", - Client_TypeText(target), - Client_Mask(target), Client_ID(target), - Req->argv[0]); - } - - /* Inform all users and servers (which have to know) - * of this nickname change */ - if( Client_Type( Client ) == CLIENT_USER ) - IRC_WriteStrClientPrefix( Client, Client, - "NICK :%s", - Req->argv[0] ); - IRC_WriteStrServersPrefix( Client, target, - "NICK :%s", Req->argv[0] ); - IRC_WriteStrRelatedPrefix( target, target, false, - "NICK :%s", Req->argv[0] ); - - /* Register old nickname for WHOWAS queries */ - Client_RegisterWhowas( target ); - - /* Save new nickname */ - Client_SetID( target, Req->argv[0] ); - - IRC_SetPenalty( target, 2 ); + Change_Nick(Client, target, Req->argv[0], + Client_Type(Client) == CLIENT_USER ? true : false); + IRC_SetPenalty(target, 2); } return CONNECTED; @@ -316,7 +271,7 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) /* Bad number of parameters? */ if (Req->argc != 2 && Req->argc != 7) - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, + return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); if (Req->argc >= 7) { @@ -345,28 +300,33 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) * the new nick is already present on this server: * the new and the old one have to be disconnected now. */ - Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] ); - Kill_Nick( Req->argv[0], "Nick collision" ); - return CONNECTED; + Log(LOG_ERR, + "Server %s introduces already registered nick \"%s\"!", + Client_ID(Client), Req->argv[0]); + return IRC_KillClient(Client, NULL, Req->argv[0], + "Nick collision"); } /* Find the Server this client is connected to */ intr_c = Client_GetFromToken(Client, token); - if( ! intr_c ) - { - Log( LOG_ERR, "Server %s introduces nick \"%s\" on unknown server!?", Client_ID( Client ), Req->argv[0] ); - Kill_Nick( Req->argv[0], "Unknown server" ); - return CONNECTED; + if (!intr_c) { + Log(LOG_ERR, + "Server %s introduces nick \"%s\" on unknown server!?", + Client_ID(Client), Req->argv[0]); + return IRC_KillClient(Client, NULL, Req->argv[0], + "Unknown server"); } c = Client_NewRemoteUser(intr_c, nick, hops, user, hostname, token, modes, info, true); - if( ! c ) - { - /* out of memory, need to disconnect client to keep network state consistent */ - Log( LOG_ALERT, "Can't create client structure! (on connection %d)", Client_Conn( Client )); - Kill_Nick( Req->argv[0], "Server error" ); - return CONNECTED; + if (!c) { + /* Out of memory, we need to disconnect client to keep + * network state consistent! */ + Log(LOG_ALERT, + "Can't create client structure! (on connection %d)", + Client_Conn(Client)); + return IRC_KillClient(Client, NULL, Req->argv[0], + "Server error"); } /* RFC 2813: client is now fully registered, inform all the @@ -382,26 +342,66 @@ IRC_NICK( CLIENT *Client, REQUEST *Req ) return CONNECTED; } - else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client )); + else + return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG, + Client_ID(Client)); } /* IRC_NICK */ +/** + * Handler for the IRC "SVSNICK" command. + * + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. + */ +GLOBAL bool +IRC_SVSNICK(CLIENT *Client, REQUEST *Req) +{ + CLIENT *from, *target; + + assert(Client != NULL); + assert(Req != NULL); + + /* Search the originator */ + from = Client_Search(Req->prefix); + if (!from) + from = Client; + + /* Search the target */ + target = Client_Search(Req->argv[0]); + if (!target || Client_Type(target) != CLIENT_USER) + return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG, + Client_ID(Client), Req->argv[0]); + + if (Client_Conn(target) <= NONE) { + /* We have to forward the message to the server handling + * this user; this is required to make sure all servers + * in the network do follow the nick name change! */ + return IRC_WriteStrClientPrefix(Client_NextHop(target), from, + "SVSNICK %s %s", + Req->argv[0], Req->argv[1]); + } + + /* Make sure that the new nickname is valid */ + if (!Client_CheckNick(from, Req->argv[1])) + return CONNECTED; + + Change_Nick(from, target, Req->argv[1], true); + return CONNECTED; +} /** * Handler for the IRC "USER" command. * - * See RFC 2812, 3.1.3 "User message". - * - * @param Client The client from which this command has been received. - * @param Req Request structure with prefix and all parameters. - * @returns CONNECTED or DISCONNECTED. + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_USER(CLIENT * Client, REQUEST * Req) { CLIENT *c; -#ifdef IDENTAUTH char *ptr; -#endif assert(Client != NULL); assert(Req != NULL); @@ -413,13 +413,29 @@ IRC_USER(CLIENT * Client, REQUEST * Req) Client_Type(Client) == CLIENT_GOTPASS) { /* New connection */ - if (Req->argc != 4) - return IRC_WriteStrClient(Client, - ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), - Req->command); + _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 4) + + /* User name: only alphanumeric characters and limited + punctuation is allowed.*/ + ptr = Req->argv[0]; + while (*ptr) { + if (!isalnum((int)*ptr) && + *ptr != '+' && *ptr != '-' && *ptr != '@' && + *ptr != '.' && *ptr != '_') { + Conn_Close(Client_Conn(Client), NULL, + "Invalid user name", true); + return DISCONNECTED; + } + ptr++; + } - /* User name */ + /* Save the received username for authentication, and use + * it up to the first '@' as default user name (like ircd2.11, + * bahamut, ircd-seven, ...), prefixed with '~', if needed: */ + Client_SetOrigUser(Client, Req->argv[0]); + ptr = strchr(Req->argv[0], '@'); + if (ptr) + *ptr = '\0'; #ifdef IDENTAUTH ptr = Client_User(Client); if (!ptr || !*ptr || *ptr == '~') @@ -427,7 +443,6 @@ IRC_USER(CLIENT * Client, REQUEST * Req) #else Client_SetUser(Client, Req->argv[0], false); #endif - Client_SetOrigUser(Client, Req->argv[0]); /* "Real name" or user info text: Don't set it to the empty * string, the original ircd can't deal with such "real names" @@ -448,14 +463,11 @@ IRC_USER(CLIENT * Client, REQUEST * Req) } else if (Client_Type(Client) == CLIENT_SERVER || Client_Type(Client) == CLIENT_SERVICE) { /* Server/service updating an user */ - if (Req->argc != 4) - return IRC_WriteStrClient(Client, - ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), - Req->command); + _IRC_ARGC_EQ_OR_RETURN_(Client, Req, 4) + c = Client_Search(Req->prefix); if (!c) - return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, + return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->prefix); @@ -475,29 +487,25 @@ IRC_USER(CLIENT * Client, REQUEST * Req) return CONNECTED; } else if (Client_Type(Client) == CLIENT_USER) { /* Already registered connection */ - return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG, + return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG, Client_ID(Client)); } else { /* Unexpected/invalid connection state? */ - return IRC_WriteStrClient(Client, ERR_NOTREGISTERED_MSG, + return IRC_WriteErrClient(Client, ERR_NOTREGISTERED_MSG, Client_ID(Client)); } } /* IRC_USER */ - /** * Handler for the IRC "SERVICE" command. * - * This function implements IRC Services registration using the SERVICE command - * defined in RFC 2812 3.1.6 and RFC 2813 4.1.4. - * * At the moment ngIRCd doesn't support directly linked services, so this * function returns ERR_ERRONEUSNICKNAME when the SERVICE command has not been * received from a peer server. * - * @param Client The client from which this command has been received. - * @param Req Request structure with prefix and all parameters. - * @returns CONNECTED or DISCONNECTED.. + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_SERVICE(CLIENT *Client, REQUEST *Req) @@ -511,45 +519,36 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req) if (Client_Type(Client) != CLIENT_GOTPASS && Client_Type(Client) != CLIENT_SERVER) - return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG, + return IRC_WriteErrClient(Client, ERR_ALREADYREGISTRED_MSG, Client_ID(Client)); - if (Req->argc != 6) - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), Req->command); - if (Client_Type(Client) != CLIENT_SERVER) - return IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, + return IRC_WriteErrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), Req->argv[0]); - /* Bad number of parameters? */ - if (Req->argc != 6) - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), Req->command); - nick = Req->argv[0]; user = NULL; host = NULL; token = atoi(Req->argv[1]); hops = atoi(Req->argv[4]); info = Req->argv[5]; - /* Validate service name ("nick name") */ + /* Validate service name ("nickname") */ c = Client_Search(nick); if(c) { - /* Nick name collission: disconnect (KILL) both clients! */ - Log(LOG_ERR, "Server %s introduces already registered service \"%s\"!", + /* Nickname collision: disconnect (KILL) both clients! */ + Log(LOG_ERR, + "Server %s introduces already registered service \"%s\"!", Client_ID(Client), nick); - Kill_Nick(nick, "Nick collision"); - return CONNECTED; + return IRC_KillClient(Client, NULL, nick, "Nick collision"); } /* Get the server to which the service is connected */ intr_c = Client_GetFromToken(Client, token); if (! intr_c) { - Log(LOG_ERR, "Server %s introduces service \"%s\" on unknown server!?", + Log(LOG_ERR, + "Server %s introduces service \"%s\" on unknown server!?", Client_ID(Client), nick); - Kill_Nick(nick, "Unknown server"); - return CONNECTED; + return IRC_KillClient(Client, NULL, nick, "Unknown server"); } /* Get user and host name */ @@ -578,37 +577,28 @@ IRC_SERVICE(CLIENT *Client, REQUEST *Req) if (! c) { /* Couldn't create client structure, so KILL the service to * keep network status consistent ... */ - Log(LOG_ALERT, "Can't create client structure! (on connection %d)", + Log(LOG_ALERT, + "Can't create client structure! (on connection %d)", Client_Conn(Client)); - Kill_Nick(nick, "Server error"); - return CONNECTED; + return IRC_KillClient(Client, NULL, nick, "Server error"); } Client_Introduce(Client, c, CLIENT_SERVICE); return CONNECTED; } /* IRC_SERVICE */ - /** * Handler for the IRC "WEBIRC" command. * - * See doc/Protocol.txt, section II.4: - * "Update webchat/proxy client information". - * - * @param Client The client from which this command has been received. - * @param Req Request structure with prefix and all parameters. - * @returns CONNECTED or DISCONNECTED. + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_WEBIRC(CLIENT *Client, REQUEST *Req) { - /* Exactly 4 parameters are requited */ - if (Req->argc != 4) - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), Req->command); - if (!Conf_WebircPwd[0] || strcmp(Req->argv[0], Conf_WebircPwd) != 0) - return IRC_WriteStrClient(Client, ERR_PASSWDMISMATCH_MSG, + return IRC_WriteErrClient(Client, ERR_PASSWDMISMATCH_MSG, Client_ID(Client)); LogDebug("Connection %d: got valid WEBIRC command: user=%s, host=%s, ip=%s", @@ -616,34 +606,31 @@ IRC_WEBIRC(CLIENT *Client, REQUEST *Req) Client_SetUser(Client, Req->argv[1], true); Client_SetOrigUser(Client, Req->argv[1]); - Client_SetHostname(Client, Req->argv[2]); + if (Conf_DNS) + Client_SetHostname(Client, Req->argv[2]); + else + Client_SetHostname(Client, Req->argv[3]); + Client_SetIPAText(Client, Req->argv[3]); + return CONNECTED; } /* IRC_WEBIRC */ - /** * Handler for the IRC "QUIT" command. * - * See RFC 2812, 3.1.7 "Quit", and RFC 2813, 4.1.5 "Quit". - * - * @param Client The client from which this command has been received. - * @param Req Request structure with prefix and all parameters. - * @returns CONNECTED or DISCONNECTED. + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_QUIT( CLIENT *Client, REQUEST *Req ) { CLIENT *target; - char quitmsg[LINE_LEN]; + char quitmsg[COMMAND_LEN]; assert(Client != NULL); assert(Req != NULL); - /* Wrong number of arguments? */ - if (Req->argc > 1) - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), Req->command); - if (Req->argc == 1) strlcpy(quitmsg, Req->argv[0], sizeof quitmsg); @@ -658,11 +645,11 @@ IRC_QUIT( CLIENT *Client, REQUEST *Req ) } if (target != Client) { - Client_Destroy(target, "Got QUIT command.", + Client_Destroy(target, "Got QUIT command", Req->argc == 1 ? quitmsg : NULL, true); return CONNECTED; } else { - Conn_Close(Client_Conn(Client), "Got QUIT command.", + Conn_Close(Client_Conn(Client), "Got QUIT command", Req->argc == 1 ? quitmsg : NULL, true); return DISCONNECTED; } @@ -675,14 +662,13 @@ IRC_QUIT( CLIENT *Client, REQUEST *Req ) } /* User, Service, or not yet registered */ - Conn_Close(Client_Conn(Client), "Got QUIT command.", + Conn_Close(Client_Conn(Client), "Got QUIT command", Req->argc == 1 ? quitmsg : NULL, true); return DISCONNECTED; } } /* IRC_QUIT */ - #ifndef STRICT_RFC /** @@ -691,9 +677,9 @@ IRC_QUIT( CLIENT *Client, REQUEST *Req ) * We handle these commands here to avoid the quite long timeout when * some user tries to access this IRC daemon using an web browser ... * - * @param Client The client from which this command has been received. - * @param Req Request structure with prefix and all parameters. - * @returns CONNECTED or DISCONNECTED. + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_QUIT_HTTP( CLIENT *Client, REQUEST *Req ) @@ -705,15 +691,12 @@ IRC_QUIT_HTTP( CLIENT *Client, REQUEST *Req ) #endif - /** * Handler for the IRC "PING" command. * - * See RFC 2812, 3.7.2 "Ping message". - * - * @param Client The client from which this command has been received. - * @param Req Request structure with prefix and all parameters. - * @returns CONNECTED or DISCONNECTED. + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_PING(CLIENT *Client, REQUEST *Req) @@ -724,13 +707,11 @@ IRC_PING(CLIENT *Client, REQUEST *Req) assert(Req != NULL); if (Req->argc < 1) - return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG, + return IRC_WriteErrClient(Client, ERR_NOORIGIN_MSG, Client_ID(Client)); #ifdef STRICT_RFC /* Don't ignore additional arguments when in "strict" mode */ - if (Req->argc > 2) - return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), Req->command); + _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2) #endif if (Req->argc > 1) { @@ -738,7 +719,7 @@ IRC_PING(CLIENT *Client, REQUEST *Req) target = Client_Search(Req->argv[1]); if (!target || Client_Type(target) != CLIENT_SERVER) - return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG, + return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG, Client_ID(Client), Req->argv[1]); if (target != Client_ThisServer()) { @@ -748,7 +729,7 @@ IRC_PING(CLIENT *Client, REQUEST *Req) else from = Client; if (!from) - return IRC_WriteStrClient(Client, + return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG, Client_ID(Client), Req->prefix); @@ -766,7 +747,7 @@ IRC_PING(CLIENT *Client, REQUEST *Req) } else from = Client_ThisServer(); if (!from) - return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG, + return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG, Client_ID(Client), Req->prefix); Log(LOG_DEBUG, "Connection %d: got PING, sending PONG ...", @@ -783,15 +764,12 @@ IRC_PING(CLIENT *Client, REQUEST *Req) #endif } /* IRC_PING */ - /** * Handler for the IRC "PONG" command. * - * See RFC 2812, 3.7.3 "Pong message". - * - * @param Client The client from which this command has been received. - * @param Req Request structure with prefix and all parameters. - * @returns CONNECTED or DISCONNECTED. + * @param Client The client from which this command has been received. + * @param Req Request structure with prefix and all parameters. + * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_PONG(CLIENT *Client, REQUEST *Req) @@ -809,26 +787,20 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) /* Wrong number of arguments? */ if (Req->argc < 1) { if (Client_Type(Client) == CLIENT_USER) - return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG, + return IRC_WriteErrClient(Client, ERR_NOORIGIN_MSG, Client_ID(Client)); else return CONNECTED; } - if (Req->argc > 2) { - if (Client_Type(Client) == CLIENT_USER) - return IRC_WriteStrClient(Client, - ERR_NEEDMOREPARAMS_MSG, - Client_ID(Client), - Req->command); - else - return CONNECTED; + if (Client_Type(Client) == CLIENT_USER) { + _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2) } /* Forward? */ if (Req->argc == 2 && Client_Type(Client) == CLIENT_SERVER) { target = Client_Search(Req->argv[0]); if (!target) - return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG, + return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG, Client_ID(Client), Req->argv[0]); from = Client_Search(Req->prefix); @@ -836,7 +808,7 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) if (target != Client_ThisServer() && target != from) { /* Ok, we have to forward the message. */ if (!from) - return IRC_WriteStrClient(Client, + return IRC_WriteErrClient(Client, ERR_NOSUCHSERVER_MSG, Client_ID(Client), Req->prefix); @@ -874,8 +846,9 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) if (Client_Type(Client) == CLIENT_SERVER && Conn_LastPing(conn) == 0) { Log(LOG_INFO, - "Synchronization with \"%s\" done (connection %d): %ld seconds [%ld users, %ld channels]", + "Synchronization with \"%s\" done (connection %d): %ld second%s [%ld users, %ld channels].", Client_ID(Client), conn, time(NULL) - Conn_GetSignon(conn), + time(NULL) - Conn_GetSignon(conn) == 1 ? "" : "s", Client_UserCount(), Channel_CountVisible(NULL)); Conn_UpdatePing(conn); } else @@ -885,31 +858,43 @@ IRC_PONG(CLIENT *Client, REQUEST *Req) return CONNECTED; } /* IRC_PONG */ - /** - * Kill all users with a specific nick name in the network. + * Change the nickname of a client. * - * @param Nick Nick name. - * @param Reason Reason for the KILL. + * @param Origin The client which caused the nickname change. + * @param Target The client of which the nickname should be changed. + * @param NewNick The new nickname. */ static void -Kill_Nick(char *Nick, char *Reason) +Change_Nick(CLIENT *Origin, CLIENT *Target, char *NewNick, bool InformClient) { - REQUEST r; - - assert (Nick != NULL); - assert (Reason != NULL); - - r.prefix = NULL; - r.argv[0] = Nick; - r.argv[1] = Reason; - r.argc = 2; + if (Client_Conn(Target) > NONE) { + /* Local client */ + Log(LOG_INFO, + "%s \"%s\" changed nick (connection %d): \"%s\" -> \"%s\".", + Client_TypeText(Target), Client_Mask(Target), + Client_Conn(Target), Client_ID(Target), NewNick); + Conn_UpdateIdle(Client_Conn(Target)); + } else { + /* Remote client */ + LogDebug("%s \"%s\" changed nick: \"%s\" -> \"%s\".", + Client_TypeText(Target), + Client_Mask(Target), Client_ID(Target), NewNick); + } - Log(LOG_ERR, "User(s) with nick \"%s\" will be disconnected: %s", - Nick, Reason); + /* Inform all servers and users (which have to know) of the new name */ + if (InformClient) { + IRC_WriteStrClientPrefix(Target, Target, "NICK :%s", NewNick); + IRC_WriteStrServersPrefix(NULL, Target, "NICK :%s", NewNick); + } else + IRC_WriteStrServersPrefix(Origin, Target, "NICK :%s", NewNick); + IRC_WriteStrRelatedPrefix(Target, Target, false, "NICK :%s", NewNick); - IRC_KILL(Client_ThisServer(), &r); -} /* Kill_Nick */ + /* Register old nickname for WHOWAS queries */ + Client_RegisterWhowas(Target); + /* Save new nickname */ + Client_SetID(Target, NewNick); +} /* -eof- */