Commit Diff


commit - 497edbaf3eb51e6c67975713ee5c52d2d1b48105
commit + e3f300d3231f56efe2831fb79f7b484d96d051f5
blob - c3f32b7e8b2516fe383b6482341817ce668269a6
blob + 977fc54666e75ee8e5d753104cd46512f8471382
--- src/ngircd/irc-login.c
+++ 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-2012 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
@@ -39,8 +39,8 @@
 #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 RegisterWhowas));
+static void Change_Nick PARAMS((CLIENT * Origin, CLIENT * Target, char *NewNick,
+				bool InformClient));
 
 
 /**
@@ -278,7 +278,8 @@ IRC_NICK( CLIENT *Client, REQUEST *Req )
 				Client_SetType( Client, CLIENT_GOTNICK );
 		} else {
 			/* Nickname change */
-			Change_Nick(Client, target, Req->argv[0], true);
+			Change_Nick(Client, target, Req->argv[0],
+				    Client_Type(Client) == CLIENT_USER ? true : false);
 			IRC_SetPenalty(target, 2);
 		}
 
@@ -357,8 +358,56 @@ IRC_NICK( CLIENT *Client, REQUEST *Req )
 	}
 	else return IRC_WriteStrClient( 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);
+
+	if (Req->argc != 2)
+		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
+					  Client_ID(Client), Req->command);
+
+	/* 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_WriteStrClient(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.
  *
@@ -904,7 +953,7 @@ Kill_Nick(char *Nick, char *Reason)
  * @param NewNick The new nickname.
  */
 static void
-Change_Nick(CLIENT *Origin, CLIENT *Target, char *NewNick, bool RegisterWhowas)
+Change_Nick(CLIENT *Origin, CLIENT *Target, char *NewNick, bool InformClient)
 {
 	if (Client_Conn(Target) > NONE) {
 		/* Local client */
@@ -921,14 +970,15 @@ Change_Nick(CLIENT *Origin, CLIENT *Target, char *NewN
 	}
 
 	/* Inform all servers and users (which have to know) of the new name */
-	if (Client_Type(Origin) == CLIENT_USER)
-		IRC_WriteStrClientPrefix(Origin, Origin, "NICK :%s", NewNick);
-	IRC_WriteStrServersPrefix(Origin, Target, "NICK :%s", NewNick);
+	if (InformClient) {
+		IRC_WriteStrClientPrefix(Target, Origin, "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);
 
-	/* Register old nickname for WHOWAS queries, if required */
-	if (RegisterWhowas)
-		Client_RegisterWhowas(Target);
+	/* Register old nickname for WHOWAS queries */
+	Client_RegisterWhowas(Target);
 
 	/* Save new nickname */
 	Client_SetID(Target, NewNick);
blob - f3138f6efaa0a8ddb55fa37910aec3f56850f7b3
blob + 15be7b4c56c22f54015a212fc0b055a3151006f6
--- src/ngircd/irc-login.h
+++ src/ngircd/irc-login.h
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2010 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2012 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
@@ -26,6 +26,7 @@ GLOBAL bool IRC_PING PARAMS((CLIENT *Client, REQUEST *
 GLOBAL bool IRC_PONG PARAMS((CLIENT *Client, REQUEST *Req));
 GLOBAL bool IRC_QUIT PARAMS((CLIENT *Client, REQUEST *Req));
 GLOBAL bool IRC_QUIT_HTTP PARAMS((CLIENT *Client, REQUEST *Req));
+GLOBAL bool IRC_SVSNICK PARAMS(( CLIENT *Client, REQUEST *Req ));
 
 #endif
 
blob - f3b04d0c2ee8617ceb21d32ce919859e640b55f4
blob + 446180b523653cf85e5e747026819e03272b531f
--- src/ngircd/parse.c
+++ src/ngircd/parse.c
@@ -99,6 +99,7 @@ static COMMAND My_Commands[] =
 	{ "SQUERY", IRC_SQUERY, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "SQUIT", IRC_SQUIT, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "STATS", IRC_STATS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
+	{ "SVSNICK", IRC_SVSNICK, CLIENT_SERVER, 0, 0, 0 },
 	{ "SUMMON", IRC_SUMMON, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "TIME", IRC_TIME, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "TOPIC", IRC_TOPIC, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },