commit 6bd35bf090694a77b4a6c13c8fe5bb52e5905ec1 from: Dana Dahlstrom via: Florian Westphal date: Tue Feb 26 22:49:33 2008 UTC Implement RFC 2812 handling of "0" argument to JOIN The students in my software-engineering class are writing IRC clients in Java, and I'm running ngIRCd as a sandbox for them to play in. We noticed ngIRCd doesn't obey the "JOIN 0" command specified in RFC 2812: JOIN 0 ; Leave all currently joined channels. http://tools.ietf.org/html/rfc2812#section-3.2.1 I believe the following patch addresses this. Cheers! [fw@strlen.de: put it into a seperate function] commit - 3022d7cff35118b6651c1165227aa79d759d9bfd commit + 6bd35bf090694a77b4a6c13c8fe5bb52e5905ec1 blob - 1ad48a4e0a8f531ef6153b7ecf02c92f6b784bcb blob + c18df41da05c86885ee254d6a24cd27b91784241 --- ChangeLog +++ ChangeLog @@ -12,6 +12,9 @@ ngIRCd HEAD + - implement RFC 2812 handling of "0" argument to 'JOIN': + must be treated as if the user had sent PART commands + for all channels the user is a member of. (Dana Dahlstrom) - allow NOTICEs to be sent to a channel. (Fabian Schlager) ngIRCd 0.11.0 (2008-01-15) @@ -738,4 +741,4 @@ ngIRCd 0.0.1, 31.12.2001 -- -$Id: ChangeLog,v 1.335 2008/01/15 22:28:15 fw Exp $ +$Id: ChangeLog,v 1.336 2008/02/05 13:31:50 fw Exp $ blob - fcc6e4aadde4e067d183864f30e5a8eb133ff54a blob + 3481e19e66e617cb34039e00f35489cb8cd75dba --- src/ngircd/irc-channel.c +++ src/ngircd/irc-channel.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc-channel.c,v 1.41 2008/01/07 11:42:00 fw Exp $"; +static char UNUSED id[] = "$Id: irc-channel.c,v 1.42 2008/02/05 13:31:50 fw Exp $"; #include "imp.h" #include @@ -38,6 +38,32 @@ static char UNUSED id[] = "$Id: irc-channel.c,v 1.41 2 #include "exp.h" #include "irc-channel.h" + + +/* + * RFC 2812, (3.2.1 Join message Command): + * Note that this message + * accepts a special argument ("0"), which is a special request to leave all + * channels the user is currently a member of. The server will process this + * message as if the user had sent a PART command (See Section 3.2.2) for + * each channel he is a member of. + */ +static bool +part_from_all_channels(CLIENT* client, CLIENT *target) +{ + CL2CHAN *cl2chan = Channel_FirstChannelOf(target); + CHANNEL *chan; + + while (cl2chan) { + chan = Channel_GetChannel(cl2chan); + assert( chan != NULL ); + Channel_Part(target, client, Channel_Name(chan), Client_ID(target)); + + /* next */ + cl2chan = Channel_FirstChannelOf(target); + } + return CONNECTED; +} GLOBAL bool @@ -47,7 +73,7 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req ) bool is_new_chan, is_invited, is_banned; CLIENT *target; CHANNEL *chan; - + assert( Client != NULL ); assert( Req != NULL ); @@ -61,6 +87,10 @@ IRC_JOIN( CLIENT *Client, REQUEST *Req ) else target = Client; if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix ); + /* Is argument "0"? */ + if (Req->argc == 1 && !strncmp("0", Req->argv[0], 2)) + return part_from_all_channels(Client, target); + /* Are channel keys given? */ if (Req->argc > 1) { key = Req->argv[1]; blob - 240abf64bd657b4c2faddaa9f02866727054e08e blob + 16c67ad4a007eeeada1a6f08fedcc9571b2d069a --- src/testsuite/channel-test.e +++ src/testsuite/channel-test.e @@ -1,4 +1,4 @@ -# $Id: channel-test.e,v 1.3 2003/12/27 13:01:12 alex Exp $ +# $Id: channel-test.e,v 1.4 2008/02/05 13:31:51 fw Exp $ spawn telnet localhost 6789 expect { @@ -69,6 +69,36 @@ expect { "@* PART #channel :nick" } +send "join #channel\r" +expect { + timeout { exit 1 } + "@* JOIN :#channel" +} +expect { + timeout { exit 1 } + "366" +} + +send "join #channel2\r" +expect { + timeout { exit 1 } + "@* JOIN :#channel2" +} +expect { + timeout { exit 1 } + "366" +} + +send "join 0\r" +expect { + timeout { exit 1 } + "@* PART #channel2 :nick" +} +expect { + timeout { exit 1 } + "@* PART #channel :nick" +} + send "quit\r" expect { timeout { exit 1 }