Commit Diff


commit - 03b70229eb95e218f56ab22ce30fa6279b3ae91f
commit + 294320ed62bdb7dac546cea43fac3b4c916788a4
blob - b75a34f9834abf6267d5ebb60faae753cff51a17
blob + ca2502dc62414008abdd558a715d458436aa8b2c
--- src/ngircd/irc-server.c
+++ src/ngircd/irc-server.c
@@ -37,6 +37,7 @@
 #include "numeric.h"
 #include "ngircd.h"
 #include "irc-info.h"
+#include "op.h"
 
 #include "exp.h"
 #include "irc-server.h"
@@ -273,21 +274,40 @@ IRC_NJOIN( CLIENT *Client, REQUEST *Req )
 GLOBAL bool
 IRC_SQUIT(CLIENT * Client, REQUEST * Req)
 {
-	CLIENT *target;
-	char msg[LINE_LEN + 64];
+	char msg[COMMAND_LEN], logmsg[COMMAND_LEN];
+	CLIENT *from, *target;
+	CONN_ID con;
 
 	assert(Client != NULL);
 	assert(Req != NULL);
 
+	if (Client_Type(Client) != CLIENT_SERVER
+	    && !Client_HasMode(Client, 'o'))
+		return Op_NoPrivileges(Client, Req);
+
 	/* Bad number of arguments? */
 	if (Req->argc != 2)
 		return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
 					  Client_ID(Client), Req->command);
 
+	if (Client_Type(Client) == CLIENT_SERVER && Req->prefix) {
+		from = Client_Search(Req->prefix);
+		if (Client_Type(from) != CLIENT_SERVER
+		    && !Op_Check(Client, Req))
+			return Op_NoPrivileges(Client, Req);
+	} else
+		from = Client;
+	if (!from)
+		return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+					  Client_ID(Client), Req->prefix);
+
 	Log(LOG_DEBUG, "Got SQUIT from %s for \"%s\": \"%s\" ...",
-	    Client_ID(Client), Req->argv[0], Req->argv[1]);
+	    Client_ID(from), Req->argv[0], Req->argv[1]);
 
 	target = Client_Search(Req->argv[0]);
+	if (Client_Type(Client) != CLIENT_SERVER &&
+	    target == Client_ThisServer())
+		return Op_NoPrivileges(Client, Req);
 	if (!target) {
 		/* The server is (already) unknown */
 		Log(LOG_WARNING,
@@ -296,27 +316,46 @@ IRC_SQUIT(CLIENT * Client, REQUEST * Req)
 		return CONNECTED;
 	}
 
-	if (Req->argv[1][0]) {
-		if (strlen(Req->argv[1]) > LINE_LEN)
-			Req->argv[1][LINE_LEN] = '\0';
-		snprintf(msg, sizeof(msg), "%s (SQUIT from %s).", Req->argv[1],
-			 Client_ID(Client));
-	} else
-		snprintf(msg, sizeof(msg), "Got SQUIT from %s.",
-			 Client_ID(Client));
+	con = Client_Conn(target);
 
-	if (Client_Conn(target) > NONE) {
-		/* We are directly connected to this server */
-		if (Req->argv[1][0])
-			Conn_Close(Client_Conn(target), msg, Req->argv[1],
-				   true);
+	if (Req->argv[1][0])
+		if (Client_NextHop(from) != Client || con > NONE)
+			snprintf(msg, sizeof(msg), "%s (SQUIT from %s)",
+				 Req->argv[1], Client_ID(from));
 		else
-			Conn_Close(Client_Conn(target), msg, NULL, true);
-		return DISCONNECTED;
+			strlcpy(msg, Req->argv[1], sizeof(msg));
+	else
+		snprintf(msg, sizeof(msg), "Got SQUIT from %s",
+			 Client_ID(from));
+
+	if (con > NONE) {
+		/* We are directly connected to the target server, so we
+		 * have to tear down the connection and to inform all the
+		 * other remaining servers in the network */
+		Conn_Close(con, NULL, msg, true);
+		if (con == Client_Conn(Client))
+			return DISCONNECTED;
 	} else {
-		Client_Destroy(target, msg, Req->argv[1], false);
-		return CONNECTED;
+		/* This server is not directly connected, so the SQUIT must
+		 * be forwarded ... */
+		if (Client_Type(from) != CLIENT_SERVER) {
+			/* The origin is not an IRC server, so don't evaluate
+			 * this SQUIT but simply forward it */
+			IRC_WriteStrClientPrefix(Client_NextHop(target),
+			    from, "SQUIT %s :%s", Req->argv[0], Req->argv[1]);
+		} else {
+			/* SQUIT has been generated by another server, so
+			 * remove the target server from the network! */
+			logmsg[0] = '\0';
+			if (!strchr(msg, '('))
+				snprintf(logmsg, sizeof(logmsg),
+					 "%s (SQUIT from %s)", Req->argv[1],
+					 Client_ID(from));
+			Client_Destroy(target, logmsg[0] ? logmsg : msg,
+				       msg, false);
+		}
 	}
+	return CONNECTED;
 } /* IRC_SQUIT */
 
 /* -eof- */
blob - 6d53525b6f2754875eae94a9baa565800156ac0a
blob + 2c28a309a0bebf39076b06450a98ac0d5fdc1265
--- src/ngircd/parse.c
+++ src/ngircd/parse.c
@@ -92,7 +92,7 @@ static COMMAND My_Commands[] =
 	{ "SERVICE", IRC_SERVICE, 0xFFFF, 0, 0, 0 },
 	{ "SERVLIST", IRC_SERVLIST, CLIENT_USER, 0, 0, 0 },
 	{ "SQUERY", IRC_SQUERY, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
-	{ "SQUIT", IRC_SQUIT, 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 },
 	{ "SUMMON", IRC_SUMMON, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
 	{ "TIME", IRC_TIME, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },