RFC 2812 states that the SQUIT command is available to (IRC) operators,
but when any client (IRCop or not) issues an SQUIT command, ngIRCd
replies with ERR_NOTREGISTERED, which is not permitted by the RFC.
Also, quoting from RFC 2812:
The INFO command is REQUIRED to return information describing the
server: its version, when it was compiled, the patchlevel, when it was
started, and any other miscellaneous information which may be
considered to be relevant.
Implementing the SUMMON command is not required, but:
If summon is not enabled in a server, it MUST return the
ERR_SUMMONDISABLED numeric.
Likewise for the USERS command:
If disabled, the correct numeric MUST be returned to indicate this.
The patch below adds a test (called misc-test for lack of a better name)
for these commands and modifies:
* testsuite/Makefile.am to run misc-test;
* parse.c and irc-server.c to make IRC_SQUIT handle client requests; and
* parse.c and irc-info.{h,c} to reply to INFO, SUMMON, and USERS.
It is perhaps worth noting the commands SERVICE, SERVLIST, and SQUERY,
which remain unimplemented, are described in RFC 2812 section 3, which
also states that "All commands described in this section MUST be
implemented by any server for this protocol."
Dana
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/testsuite/misc-test.e 17 Feb 2008 06:47:42 -0000
@@ -0,0 +1,50 @@
+# $Id$
+
+spawn telnet localhost 6789
+expect {
+ timeout { exit 1 }
+ "Connected"
+}
+
+send "nick nick\r"
+send "user user . . :User\r"
+expect {
+ timeout { exit 1 }
+ "376"
+}
+
+send "summon\r"
+expect {
+ timeout { exit 1 }
+ "445"
+}
+
+send "users\r"
+expect {
+ timeout { exit 1 }
+ "446"
+}
+
+send "info\r"
+expect {
+ timeout { exit 1 }
+ "371"
+}
+expect {
+ timeout { exit 1 }
+ "374"
+}
+
+send "squit\r"
+expect {
+ timeout { exit 1 }
+ "481"
+}
+
+send "quit\r"
+expect {
+ timeout { exit 1 }
+ "ERROR"
+}
+
+# -eof-
--- src/testsuite/Makefile.am 17 Feb 2008 00:00:13 -0000 1.17
+++ src/testsuite/Makefile.am 17 Feb 2008 06:47:42 -0000
@@ -21,7 +21,7 @@ EXTRA_DIST = \
start-server.sh stop-server.sh tests.sh stress-server.sh \
test-loop.sh wait-tests.sh \
connect-test.e channel-test.e mode-test.e \
- who-test.e
+ who-test.e misc-test.e
stress-A.e stress-B.e check-idle.e \
ngircd-test.conf
@@ -52,6 +52,10 @@ who-test: tests.sh
rm -f who-test
ln -s $(srcdir)/tests.sh who-test
+misc-test: tests.sh
+ rm -f misc-test
+ ln -s $(srcdir)/tests.sh misc-test
+
mode-test: tests.sh
rm -f mode-test
ln -s $(srcdir)/tests.sh mode-test
@@ -60,6 +64,7 @@ TESTS = start-server.sh \
connect-test \
channel-test \
who-test \
+ misc-test \
mode-test \
stress-server.sh \
stop-server.sh
--- src/ngircd/parse.c 5 Feb 2008 13:07:14 -0000 1.71
+++ src/ngircd/parse.c 17 Feb 2008 06:47:42 -0000
@@ -67,6 +67,7 @@ static COMMAND My_Commands[] =
{ "DISCONNECT", IRC_DISCONNECT, CLIENT_USER, 0, 0, 0 },
{ "ERROR", IRC_ERROR, 0xFFFF, 0, 0, 0 },
{ "HELP", IRC_HELP, CLIENT_USER, 0, 0, 0 },
+ { "INFO", IRC_INFO, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
{ "INVITE", IRC_INVITE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
{ "ISON", IRC_ISON, CLIENT_USER, 0, 0, 0 },
{ "JOIN", IRC_JOIN, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
@@ -91,13 +92,15 @@ static COMMAND My_Commands[] =
{ "REHASH", IRC_REHASH, CLIENT_USER, 0, 0, 0 },
{ "RESTART", IRC_RESTART, CLIENT_USER, 0, 0, 0 },
{ "SERVER", IRC_SERVER, 0xFFFF, 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 },
{ "TOPIC", IRC_TOPIC, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
{ "TRACE", IRC_TRACE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
{ "USER", IRC_USER, 0xFFFF, 0, 0, 0 },
{ "USERHOST", IRC_USERHOST, CLIENT_USER, 0, 0, 0 },
+ { "USERS", IRC_USERS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
{ "VERSION", IRC_VERSION, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
{ "WALLOPS", IRC_WALLOPS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
{ "WHO", IRC_WHO, CLIENT_USER, 0, 0, 0 },
--- src/ngircd/irc-info.h 11 Feb 2008 11:06:31 -0000 1.5
+++ src/ngircd/irc-info.h 17 Feb 2008 06:47:42 -0000
@@ -19,14 +19,17 @@
GLOBAL bool IRC_ADMIN PARAMS(( CLIENT *Client, REQUEST *Req ));
+GLOBAL bool IRC_INFO PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_ISON PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_LINKS PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_LUSERS PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_MOTD PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_NAMES PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_STATS PARAMS(( CLIENT *Client, REQUEST *Req ));
+GLOBAL bool IRC_SUMMON PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_TIME PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_USERHOST PARAMS(( CLIENT *Client, REQUEST *Req ));
+GLOBAL bool IRC_USERS PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_VERSION PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_WHO PARAMS(( CLIENT *Client, REQUEST *Req ));
GLOBAL bool IRC_WHOIS PARAMS(( CLIENT *Client, REQUEST *Req ));
--- src/ngircd/messages.h 11 Dec 2007 11:29:44 -0000 1.74
+++ src/ngircd/messages.h 17 Feb 2008 06:47:42 -0000
@@ -77,6 +77,8 @@
#define RPL_BANLIST_MSG "367 %s %s %s"
#define RPL_ENDOFBANLIST_MSG "368 %s %s :End of channel ban list"
#define RPL_ENDOFWHOWAS_MSG "369 %s %s :End of WHOWAS list"
+#define RPL_INFO_MSG "371 %s :%s"
+#define RPL_ENDOFINFO_MSG "374 %s :End of INFO list"
#define RPL_MOTD_MSG "372 %s :- %s"
#define RPL_MOTDSTART_MSG "375 %s :- %s message of the day"
#define RPL_ENDOFMOTD_MSG "376 %s :End of MOTD command"
@@ -100,6 +102,8 @@
#define ERR_USERNOTINCHANNEL_MSG "441 %s %s %s :They aren't on that channel"
#define ERR_NOTONCHANNEL_MSG "442 %s %s :You are not on that channel"
#define ERR_USERONCHANNEL_MSG "443 %s %s %s :is already on channel"
+#define ERR_SUMMONDISABLED_MSG "445 %s %s :Command disabled"
+#define ERR_USERSDISABLED_MSG "446 %s %s :Command disabled"
#define ERR_NOTREGISTERED_MSG "451 %s :Connection not registered"
#define ERR_NOTREGISTEREDSERVER_MSG "451 %s :Connection not registered as server link"
#define ERR_NEEDMOREPARAMS_MSG "461 %s %s :Syntax error"
--- src/ngircd/irc-server.c 21 Nov 2007 12:16:36 -0000 1.46
+++ src/ngircd/irc-server.c 17 Feb 2008 06:47:42 -0000
@@ -285,6 +285,9 @@ IRC_SQUIT( CLIENT *Client, REQUEST *Req
assert( Client != NULL );
assert( Req != NULL );
+ if (! (Client_OperByMe(Client) || Client_Type(Client) == CLIENT_SERVER))
+ return IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ) );
+
/* Falsche Anzahl Parameter? */
if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
--- src/ngircd/irc-info.c 17 Feb 2008 00:00:12 -0000 1.43
+++ src/ngircd/irc-info.c 17 Feb 2008 06:47:42 -0000
@@ -86,6 +86,71 @@ IRC_ADMIN(CLIENT *Client, REQUEST *Req )
GLOBAL bool
+IRC_INFO( CLIENT *Client, REQUEST *Req )
+{
+ CLIENT *target, *prefix;
+
+ assert( Client != NULL );
+ assert( Req != NULL );
+
+ /* Wrong number of parameters? */
+ if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+
+ /* Look for a target. */
+ if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
+ else target = Client_ThisServer( );
+
+ /* Determine prefix. */
+ if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
+ else prefix = Client;
+ if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
+
+ /* Pass on to another server? */
+ if( target != Client_ThisServer( ))
+ {
+ if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG, Client_ID( prefix ), Req->argv[0] );
+
+ /* forward */
+ IRC_WriteStrClientPrefix( target, prefix, "INFO %s", Req->argv[0] );
+ return CONNECTED;
+ }
+
+ /* Answer with version info. */
+ {
+ char msg[510];
+
+ strlcpy(msg, PACKAGE_NAME, sizeof(msg));
+ strlcat(msg, "-", sizeof(msg));
+ strlcat(msg, PACKAGE_VERSION, sizeof(msg));
+ if( ! IRC_WriteStrClient( Client, RPL_INFO_MSG, Client_ID( prefix ), msg )) return DISCONNECTED;
+
+#ifdef CVSDATE
+ strlcpy(msg, "last revision ", sizeof(msg));
+ strlcat(msg, CVSDATE, sizeof(msg));
+ if( ! IRC_WriteStrClient( Client, RPL_INFO_MSG, Client_ID( prefix ), msg )) return DISCONNECTED;
+#endif
+
+ strlcpy(msg, "compiled ", sizeof(msg));
+ strlcat(msg, __DATE__, sizeof(msg));
+ if( ! IRC_WriteStrClient( Client, RPL_INFO_MSG, Client_ID( prefix ), msg )) return DISCONNECTED;
+
+ strlcpy(msg, "with options ", sizeof(msg));
+ strlcat(msg, NGIRCd_VersionAddition, sizeof(msg));
+ if( ! IRC_WriteStrClient( Client, RPL_INFO_MSG, Client_ID( prefix ), msg )) return DISCONNECTED;
+
+ strlcpy(msg, "started ", sizeof(msg));
+ strlcat(msg, NGIRCd_StartStr, sizeof(msg));
+ if( ! IRC_WriteStrClient( Client, RPL_INFO_MSG, Client_ID( prefix ), msg )) return DISCONNECTED;
+
+ if( ! IRC_WriteStrClient( Client, RPL_ENDOFINFO_MSG, Client_ID( prefix ) )) return DISCONNECTED;
+ }
+
+ IRC_SetPenalty( Client, 1 );
+ return CONNECTED;
+} /* IRC_INFO */
+
+
+GLOBAL bool
IRC_ISON( CLIENT *Client, REQUEST *Req )
{
char rpl[COMMAND_LEN];
@@ -470,6 +535,13 @@ IRC_STATS( CLIENT *Client, REQUEST *Req
GLOBAL bool
+IRC_SUMMON( CLIENT *Client, REQUEST *Req )
+{
+ return IRC_WriteStrClient( Client, ERR_SUMMONDISABLED_MSG, Client_ID( Client ), Req->command );
+} /* IRC_SUMMON */
+
+
+GLOBAL bool
IRC_TIME( CLIENT *Client, REQUEST *Req )
{
CLIENT *from, *target;
@@ -547,6 +619,13 @@ IRC_USERHOST( CLIENT *Client, REQUEST *R
GLOBAL bool
+IRC_USERS( CLIENT *Client, REQUEST *Req )
+{
+ return IRC_WriteStrClient( Client, ERR_USERSDISABLED_MSG, Client_ID( Client ), Req->command );
+} /* IRC_USERS */
+
+
+GLOBAL bool
IRC_VERSION( CLIENT *Client, REQUEST *Req )
{
CLIENT *target, *prefix;