+/**
+ * Handler for the IRC "LIST" command.
+ * This implementation handles the local case as well as the forwarding of the
+ * LIST command to other servers in the IRC network.
+ */
+GLOBAL bool
+IRC_LIST( CLIENT *Client, REQUEST *Req )
+{
+ char *pattern;
+ CHANNEL *chan;
+ CLIENT *from, *target;
+
+ assert( Client != NULL );
+ assert( Req != NULL );
+
+ /* Bad number of prameters? */
+ if( Req->argc > 2 )
+ return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
+ Client_ID( Client ), Req->command );
+
+ if( Req->argc > 0 )
+ pattern = strtok( Req->argv[0], "," );
+ else
+ pattern = "*";
+
+ /* Get sender from prefix, if any */
+ if( Client_Type( Client ) == CLIENT_SERVER )
+ from = Client_Search( Req->prefix );
+ else
+ from = Client;
+
+ if( ! from )
+ return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG,
+ Client_ID( Client ), Req->prefix );
+
+ if( Req->argc == 2 )
+ {
+ /* Forward to other server? */
+ target = Client_Search( Req->argv[1] );
+ if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
+ return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG,
+ Client_ID( Client ), Req->argv[1] );
+
+ if( target != Client_ThisServer( ))
+ {
+ /* Target is indeed an other server, forward it! */
+ return IRC_WriteStrClientPrefix( target, from,
+ "LIST %s :%s", Client_ID( from ),
+ Req->argv[1] );
+ }
+ }
+
+ while( pattern )
+ {
+ /* Loop through all the channels */
+ chan = Channel_First( );
+ while( chan )
+ {
+ /* Check search pattern */
+ if( Match( pattern, Channel_Name( chan )))
+ {
+ /* Gotcha! */
+ if( ! strchr( Channel_Modes( chan ), 's' ) ||
+ Channel_IsMemberOf( chan, from ))
+ {
+ if( ! IRC_WriteStrClient( from,
+ RPL_LIST_MSG, Client_ID( from ),
+ Channel_Name( chan ),
+ Channel_MemberCount( chan ),
+ Channel_Topic( chan )))
+ return DISCONNECTED;
+ }
+ }
+ chan = Channel_Next( chan );
+ }
+
+ /* Get next name ... */
+ if( Req->argc > 0 )
+ pattern = strtok( NULL, "," );
+ else
+ pattern = NULL;
+ }
+
+ return IRC_WriteStrClient( from, RPL_LISTEND_MSG, Client_ID( from ));
+} /* IRC_LIST */
+
+
+GLOBAL bool
+IRC_CHANINFO( CLIENT *Client, REQUEST *Req )
+{
+ char modes_add[COMMAND_LEN], l[16], *ptr;
+ CLIENT *from;
+ CHANNEL *chan;
+ int arg_topic;
+
+ assert( Client != NULL );
+ assert( Req != NULL );
+
+ /* Bad number of parameters? */
+ if(( Req->argc < 2 ) || ( Req->argc == 4 ) || ( Req->argc > 5 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
+
+ /* Compatibility kludge */
+ if( Req->argc == 5 ) arg_topic = 4;
+ else if( Req->argc == 3 ) arg_topic = 2;
+ else arg_topic = -1;
+
+ /* Search origin */
+ from = Client_Search( Req->prefix );
+ if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
+
+ /* Search or create channel */
+ chan = Channel_Search( Req->argv[0] );
+ if( ! chan ) chan = Channel_Create( Req->argv[0] );
+ if( ! chan ) return CONNECTED;
+
+ if( Req->argv[1][0] == '+' )
+ {
+ ptr = Channel_Modes( chan );
+ if( ! *ptr )
+ {
+ /* OK, this channel doesn't have modes jet, set the received ones: */
+ Channel_SetModes( chan, &Req->argv[1][1] );
+
+ if( Req->argc == 5 )
+ {
+ if( strchr( Channel_Modes( chan ), 'k' )) Channel_SetKey( chan, Req->argv[2] );
+ if( strchr( Channel_Modes( chan ), 'l' )) Channel_SetMaxUsers( chan, atol( Req->argv[3] ));
+ }
+ else
+ {
+ /* Delete modes which we never want to inherit */
+ Channel_ModeDel( chan, 'l' );
+ Channel_ModeDel( chan, 'k' );
+ }
+
+ strcpy( modes_add, "" );
+ ptr = Channel_Modes( chan );
+ while( *ptr )
+ {
+ if( *ptr == 'l' )
+ {
+ snprintf( l, sizeof( l ), " %lu", Channel_MaxUsers( chan ));
+ strlcat( modes_add, l, sizeof( modes_add ));
+ }
+ if( *ptr == 'k' )
+ {
+ strlcat( modes_add, " ", sizeof( modes_add ));
+ strlcat( modes_add, Channel_Key( chan ), sizeof( modes_add ));
+ }
+ ptr++;
+ }
+
+ /* Inform members of this channel */
+ IRC_WriteStrChannelPrefix( Client, chan, from, false, "MODE %s +%s%s", Req->argv[0], Channel_Modes( chan ), modes_add );
+ }
+ }
+ else Log( LOG_WARNING, "CHANINFO: invalid MODE format ignored!" );
+
+ if( arg_topic > 0 )
+ {
+ /* We got a topic */
+ ptr = Channel_Topic( chan );
+ if(( ! *ptr ) && ( Req->argv[arg_topic][0] ))
+ {
+ /* OK, there is no topic jet */
+ Channel_SetTopic(chan, Client, Req->argv[arg_topic]);
+ IRC_WriteStrChannelPrefix(Client, chan, from, false,
+ "TOPIC %s :%s", Req->argv[0], Channel_Topic(chan));
+ }
+ }
+
+ /* Forward CHANINFO to other serevrs */
+ if( Req->argc == 5 ) IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s %s %s :%s", Req->argv[0], Req->argv[1], Req->argv[2], Req->argv[3], Req->argv[4] );
+ else if( Req->argc == 3 ) IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s :%s", Req->argv[0], Req->argv[1], Req->argv[2] );
+ else IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s", Req->argv[0], Req->argv[1] );
+
+ return CONNECTED;
+} /* IRC_CHANINFO */