Module: ngircd.git Branch: master Commit: e3f300d3231f56efe2831fb79f7b484d96d051f5 URL: http://ngircd.barton.de/cgi-bin/gitweb.cgi?p=ngircd.git&a=commit;h=e3f30...
Author: Alexander Barton alex@barton.de Date: Fri Nov 2 17:50:31 2012 +0100
Implement SVSNICK command to change remote nicknames
The SVSNICK command allows other servers (and services on "pseudo-servers") to forcefully change nicknames of remote users.
Syntax: ":<from> SVSNICK <oldnick> <newnick>"
The SVSNICK command itself doesn't change the nickname, but it becomes forwarded to the server to which the user is connected to. And then this server initiates the real nickname changing using regular NICK commands.
This allows to still run networks with old servers not supporting the SVSNICK command, because SVSNICK commands for nicknames on such servers are silently ignored and don't cause a desync of the network.
---
src/ngircd/irc-login.c | 72 ++++++++++++++++++++++++++++++++++++++++-------- src/ngircd/irc-login.h | 3 +- src/ngircd/parse.c | 1 + 3 files changed, 64 insertions(+), 12 deletions(-)
diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c index c3f32b7..977fc54 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-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); }
@@ -360,6 +361,54 @@ IRC_NICK( CLIENT *Client, REQUEST *Req )
/** + * 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. * * See RFC 2812, 3.1.3 "User message". @@ -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 *NewNick, bool RegisterWhowas) }
/* 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); diff --git a/src/ngircd/irc-login.h b/src/ngircd/irc-login.h index f3138f6..15be7b4 100644 --- a/src/ngircd/irc-login.h +++ b/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 *Req)); 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
diff --git a/src/ngircd/parse.c b/src/ngircd/parse.c index f3b04d0..446180b 100644 --- a/src/ngircd/parse.c +++ b/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 },
ngircd-commits@lists.barton.de