X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Firc-info.c;h=87ed2ad00c6e7d00037a58c5242731f6629527a0;hp=396d62e9df7f6dcbd3b539b6e76fcaed67a74e72;hb=ddecfcd8310f77974803c9c67431809320646a55;hpb=257312b102df5b66c25c97b803e9e4c78b6be54d diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c index 396d62e9..87ed2ad0 100644 --- a/src/ngircd/irc-info.c +++ b/src/ngircd/irc-info.c @@ -14,7 +14,7 @@ #include "portab.h" -static char UNUSED id[] = "$Id: irc-info.c,v 1.35 2006/10/01 19:13:32 alex Exp $"; +static char UNUSED id[] = "$Id: irc-info.c,v 1.44 2008/02/17 13:26:42 alex Exp $"; #include "imp.h" #include @@ -35,6 +35,7 @@ static char UNUSED id[] = "$Id: irc-info.c,v 1.35 2006/10/01 19:13:32 alex Exp $ #include "defines.h" #include "log.h" #include "messages.h" +#include "match.h" #include "tool.h" #include "parse.h" #include "irc-write.h" @@ -84,6 +85,71 @@ IRC_ADMIN(CLIENT *Client, REQUEST *Req ) } /* IRC_ADMIN */ +/** + * Handler for the IRC command "INFO". + * See RFC 2812 section 3.4.10. + */ +GLOBAL bool +IRC_INFO(CLIENT * Client, REQUEST * Req) +{ + CLIENT *target, *prefix; + char msg[510]; + + 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); + + /* 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); + + /* Look for a target */ + if (Req->argc > 0) + target = Client_Search(Req->argv[0]); + else + target = Client_ThisServer(); + + /* Make sure that the target is a server */ + if (target && Client_Type(target) != CLIENT_SERVER) + target = Client_Introducer(target); + + if (!target) + return IRC_WriteStrClient(prefix, ERR_NOSUCHSERVER_MSG, + Client_ID(prefix), Req->argv[0]); + + /* Pass on to another server? */ + if (target != Client_ThisServer()) { + IRC_WriteStrClientPrefix(target, prefix, "INFO %s", + Req->argv[0]); + return CONNECTED; + } + + if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), + NGIRCd_Version)) + return DISCONNECTED; + + strlcpy(msg, "Server has been 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, 2); + return CONNECTED; +} /* IRC_INFO */ + + GLOBAL bool IRC_ISON( CLIENT *Client, REQUEST *Req ) { @@ -335,6 +401,41 @@ IRC_NAMES( CLIENT *Client, REQUEST *Req ) } /* IRC_NAMES */ +static unsigned int +t_diff(time_t *t, const time_t div) +{ + time_t diff, remain; + + diff = *t / div; + + remain = diff * div; + *t -= remain; + + return diff; +} + + +static unsigned int +uptime_days(time_t *now) +{ + return t_diff(now, 60 * 60 * 24); +} + + +static unsigned int +uptime_hrs(time_t *now) +{ + return t_diff(now, 60 * 60); +} + + +static unsigned int +uptime_mins(time_t *now) +{ + return t_diff(now, 60); +} + + GLOBAL bool IRC_STATS( CLIENT *Client, REQUEST *Req ) { @@ -342,78 +443,110 @@ IRC_STATS( CLIENT *Client, REQUEST *Req ) CONN_ID con; char query; COMMAND *cmd; + time_t time_now; + unsigned int days, hrs, mins; assert( Client != NULL ); assert( Req != NULL ); /* Falsche Anzahl Parameter? */ - if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + if (Req->argc > 2) + return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); /* From aus Prefix ermitteln */ - if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix ); - else from = Client; - if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix ); + if (Client_Type(Client) == CLIENT_SERVER) + from = Client_Search(Req->prefix); + else + from = Client; - if( Req->argc == 2 ) - { + if (! from) + return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix); + + if (Req->argc == 2) { /* an anderen Server forwarden */ target = Client_Search( Req->argv[1] ); - if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] ); + if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) + return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] ); - if( target != Client_ThisServer( )) - { + if( target != Client_ThisServer()) { /* Ok, anderer Server ist das Ziel: forwarden */ return IRC_WriteStrClientPrefix( target, from, "STATS %s %s", Req->argv[0], Req->argv[1] ); } } - if( Req->argc > 0 ) query = Req->argv[0][0] ? Req->argv[0][0] : '*'; - else query = '*'; + if (Req->argc > 0) + query = Req->argv[0][0] ? Req->argv[0][0] : '*'; + else + query = '*'; - switch ( query ) - { + switch (query) { case 'l': /* Links */ case 'L': - con = Conn_First( ); - while( con != NONE ) - { - cl = Conn_GetClient( con ); - if( cl && (( Client_Type( cl ) == CLIENT_SERVER ) || ( cl == Client ))) - { + time_now = time(NULL); + for (con = Conn_First(); con != NONE ;con = Conn_Next(con)) { + cl = Conn_GetClient(con); + if (!cl) + continue; + if ((Client_Type(cl) == CLIENT_SERVER) || (cl == Client)) { /* Server link or our own connection */ #ifdef ZLIB - if( Conn_Options( con ) & CONN_ZIP ) - { - if( ! IRC_WriteStrClient( from, RPL_STATSLINKINFOZIP_MSG, Client_ID( from ), Client_Mask( cl ), Conn_SendQ( con ), Conn_SendMsg( con ), Zip_SendBytes( con ), Conn_SendBytes( con ), Conn_RecvMsg( con ), Zip_RecvBytes( con ), Conn_RecvBytes( con ), (long)( time( NULL ) - Conn_StartTime( con )))) return DISCONNECTED; + if (Conn_Options(con) & CONN_ZIP) { + if (!IRC_WriteStrClient(from, RPL_STATSLINKINFOZIP_MSG, + Client_ID(from), Client_Mask(cl), Conn_SendQ(con), + Conn_SendMsg(con), Zip_SendBytes(con), Conn_SendBytes(con), + Conn_RecvMsg(con), Zip_RecvBytes(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con)))) + return DISCONNECTED; + continue; } - else #endif - { - if( ! IRC_WriteStrClient( from, RPL_STATSLINKINFO_MSG, Client_ID( from ), Client_Mask( cl ), Conn_SendQ( con ), Conn_SendMsg( con ), Conn_SendBytes( con ), Conn_RecvMsg( con ), Conn_RecvBytes( con ), (long)( time( NULL ) - Conn_StartTime( con )))) return DISCONNECTED; - } + if (!IRC_WriteStrClient(from, RPL_STATSLINKINFO_MSG, Client_ID(from), + Client_Mask(cl), Conn_SendQ(con), Conn_SendMsg(con), Conn_SendBytes(con), + Conn_RecvMsg(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con)))) + return DISCONNECTED; } - con = Conn_Next( con ); } break; - case 'm': /* IRC-Befehle */ + case 'm': /* IRC-Commands */ case 'M': cmd = Parse_GetCommandStruct( ); - while( cmd->name ) - { - if( cmd->lcount > 0 || cmd->rcount > 0 ) - { - if( ! IRC_WriteStrClient( from, RPL_STATSCOMMANDS_MSG, Client_ID( from ), cmd->name, cmd->lcount, cmd->bytes, cmd->rcount )) return DISCONNECTED; - } - cmd++; + for (; cmd->name ; cmd++) { + if (cmd->lcount == 0 && cmd->rcount == 0) + continue; + if (!IRC_WriteStrClient(from, RPL_STATSCOMMANDS_MSG, Client_ID(from), + cmd->name, cmd->lcount, cmd->bytes, cmd->rcount)) + return DISCONNECTED; } break; + case 'u': /* server uptime */ + case 'U': + time_now = time(NULL) - NGIRCd_Start; + days = uptime_days(&time_now); + hrs = uptime_hrs(&time_now); + mins = uptime_mins(&time_now); + if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from), + days, hrs, mins, (unsigned int) time_now)) + return DISCONNECTED; + break; } - IRC_SetPenalty( from, 2 ); - return IRC_WriteStrClient( from, RPL_ENDOFSTATS_MSG, Client_ID( from ), query ); + IRC_SetPenalty(from, 2); + return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG, Client_ID(from), query); } /* IRC_STATS */ +/** + * Handler for the IRC command "SUMMON". + * See RFC 2812 section 4.5. ngIRCd doesn't implement this functionality and + * therefore answers with ERR_SUMMONDISABLED. + */ +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 ) { @@ -491,6 +624,18 @@ IRC_USERHOST( CLIENT *Client, REQUEST *Req ) } /* IRC_USERHOST */ +/** + * Handler for the IRC command "USERS". + * See RFC 2812 section 4.6. As suggested there the command is disabled. + */ +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 ) { @@ -538,11 +683,102 @@ IRC_VERSION( CLIENT *Client, REQUEST *Req ) } /* IRC_VERSION */ + +static bool +write_whoreply(CLIENT *Client, CLIENT *c, const char *channelname, const char *flags) +{ + return IRC_WriteStrClient(Client, RPL_WHOREPLY_MSG, Client_ID(Client), channelname, + Client_User(c), Client_Hostname(c), Client_ID(Client_Introducer(c)), Client_ID(c), + flags, Client_Hops(c), Client_Info(c)); +} + + +static const char * +who_flags_status(const char *client_modes) +{ + if (strchr(client_modes, 'a')) + return "G"; /* away */ + return "H"; +} + + +static const char * +who_flags_qualifier(const char *chan_user_modes) +{ + if (strchr(chan_user_modes, 'o')) + return "@"; + else if (strchr(chan_user_modes, 'v')) + return "+"; + return ""; +} + + +static bool +IRC_Send_WHO(CLIENT *Client, CHANNEL *Chan, bool OnlyOps) +{ + bool is_visible, is_member, is_ircop; + CL2CHAN *cl2chan; + const char *client_modes; + const char *chan_user_modes; + char flags[8]; + CLIENT *c; + + assert( Client != NULL ); + assert( Chan != NULL ); + + is_member = Channel_IsMemberOf(Chan, Client); + + /* Secret channel? */ + if (!is_member && strchr(Channel_Modes(Chan), 's')) + return CONNECTED; + + cl2chan = Channel_FirstMember(Chan); + for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) { + c = Channel_GetClient(cl2chan); + + client_modes = Client_Modes(c); + is_ircop = strchr(client_modes, 'o') != NULL; + if (OnlyOps && !is_ircop) + continue; + + is_visible = strchr(client_modes, 'i') == NULL; + if (is_member || is_visible) { + strcpy(flags, who_flags_status(client_modes)); + if (is_ircop) + strlcat(flags, "*", sizeof(flags)); + + chan_user_modes = Channel_UserModes(Chan, c); + strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags)); + + if (!write_whoreply(Client, c, Channel_Name(Chan), flags)) + return DISCONNECTED; + } + } + return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), Channel_Name(Chan)); +} /* IRC_Send_WHO */ + + + +static bool +MatchCaseInsensitive(const char *pattern, const char *searchme) +{ + char haystack[COMMAND_LEN]; + + strlcpy(haystack, searchme, sizeof(haystack)); + + ngt_LowerStr(haystack); + + return Match(pattern, haystack); +} + + GLOBAL bool IRC_WHO( CLIENT *Client, REQUEST *Req ) { - bool ok, only_ops; - char flags[8], *ptr; + bool only_ops, have_arg, client_match; + const char *channelname, *client_modes, *chan_user_modes; + char pattern[COMMAND_LEN]; + char flags[4]; CL2CHAN *cl2chan; CHANNEL *chan, *cn; CLIENT *c; @@ -550,78 +786,102 @@ IRC_WHO( CLIENT *Client, REQUEST *Req ) assert( Client != NULL ); assert( Req != NULL ); - /* Falsche Anzahl Parameter? */ - if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + if (Req->argc > 2) + return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); only_ops = false; - chan = NULL; + have_arg = false; - if( Req->argc == 2 ) - { - /* Nur OPs anzeigen? */ - if( strcmp( Req->argv[1], "o" ) == 0 ) only_ops = true; + if (Req->argc == 2) { + if (strcmp(Req->argv[1], "o") == 0) + only_ops = true; #ifdef STRICT_RFC - else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command ); + else return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); #endif } - if( Req->argc >= 1 ) - { - /* wurde ein Channel oder Nick-Mask angegeben? */ - chan = Channel_Search( Req->argv[0] ); + IRC_SetPenalty(Client, 1); + if (Req->argc >= 1) { /* Channel or Mask. */ + chan = Channel_Search(Req->argv[0]); + if (chan) + return IRC_Send_WHO(Client, chan, only_ops); + if (strcmp(Req->argv[0], "0") != 0) { /* RFC stupidity, same as no arguments */ + have_arg = true; + strlcpy(pattern, Req->argv[0], sizeof(pattern)); + ngt_LowerStr(pattern); + IRC_SetPenalty(Client, 3); + } } - if( chan ) - { - /* User eines Channels ausgeben */ - if( ! IRC_Send_WHO( Client, chan, only_ops )) return DISCONNECTED; - } + for (c = Client_First(); c != NULL; c = Client_Next(c)) { + if (Client_Type(c) != CLIENT_USER) + continue; + /* + * RFC 2812, 3.6.1: + * In the absence of the parameter, all visible (users who aren't + * invisible (user mode +i) and who don't have a common channel + * with the requesting client) are listed. + * + * The same result can be achieved by using a [sic] of "0" + * or any wildcard which will end up matching every visible user. + * + * The [sic] passed to WHO is matched against users' host, server, real name and + * nickname if the channel cannot be found. + */ + client_modes = Client_Modes(c); + if (strchr(client_modes, 'i')) + continue; + + if (only_ops && !strchr(client_modes, 'o')) + continue; + + if (have_arg) { /* match pattern against user host/server/name/nick */ + client_match = MatchCaseInsensitive(pattern, Client_Hostname(c)); /* user's host */ + if (!client_match) + client_match = MatchCaseInsensitive(pattern, Client_ID(Client_Introducer(c))); /* server */ + if (!client_match) + client_match = Match(Req->argv[0], Client_Info(c)); /* realname */ + if (!client_match) + client_match = MatchCaseInsensitive(pattern, Client_ID(c)); /* nick name */ + + if (!client_match) /* This isn't the client you're looking for */ + continue; + } - c = Client_First( ); - while( c ) - { - if(( Client_Type( c ) == CLIENT_USER ) && ( ! strchr( Client_Modes( c ), 'i' ))) - { - ok = false; - if( Req->argc == 0 ) ok = true; - else - { - if( strcasecmp( Req->argv[0], Client_ID( c )) == 0 ) ok = true; - else if( strcmp( Req->argv[0], "0" ) == 0 ) ok = true; - } + strcpy(flags, who_flags_status(client_modes)); - if( ok && (( ! only_ops ) || ( strchr( Client_Modes( c ), 'o' )))) - { - /* Get flags */ - strcpy( flags, "H" ); - if( strchr( Client_Modes( c ), 'o' )) strlcat( flags, "*", sizeof( flags )); - - /* Search suitable channel */ - cl2chan = Channel_FirstChannelOf( c ); - while( cl2chan ) - { - cn = Channel_GetChannel( cl2chan ); - if( Channel_IsMemberOf( cn, Client ) || - ! strchr( Channel_Modes( cn ), 's' )) - { - ptr = Channel_Name( cn ); - break; - } - cl2chan = Channel_NextChannelOf( c, cl2chan ); - } - if( ! cl2chan ) ptr = "*"; + if (strchr(client_modes, 'o')) /* this client is an operator */ + strlcat(flags, "*", sizeof(flags)); - if( ! IRC_WriteStrClient( Client, RPL_WHOREPLY_MSG, Client_ID( Client ), ptr, Client_User( c ), Client_Hostname( c ), Client_ID( Client_Introducer( c )), Client_ID( c ), flags, Client_Hops( c ), Client_Info( c ))) return DISCONNECTED; + /* Search suitable channel */ + cl2chan = Channel_FirstChannelOf(c); + while (cl2chan) { + cn = Channel_GetChannel(cl2chan); + if (Channel_IsMemberOf(cn, Client) || + !strchr(Channel_Modes(cn), 's')) + { + channelname = Channel_Name(cn); + break; } + cl2chan = Channel_NextChannelOf(c, cl2chan); } - - /* naechster Client */ - c = Client_Next( c ); + if (cl2chan) { + chan = Channel_GetChannel(cl2chan); + chan_user_modes = Channel_UserModes(chan, c); + strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags)); + } else + channelname = "*"; + + if (!write_whoreply(Client, c, channelname, flags)) + return DISCONNECTED; } - if( chan ) return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), Channel_Name( chan )); - else if( Req->argc == 0 ) return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), "*" ); - else return IRC_WriteStrClient( Client, RPL_ENDOFWHO_MSG, Client_ID( Client ), Req->argv[0] ); + if (Req->argc > 0) + channelname = Req->argv[0]; + else + channelname = "*"; + + return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), channelname); } /* IRC_WHO */ @@ -706,10 +966,13 @@ IRC_WHOIS( CLIENT *Client, REQUEST *Req ) if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED; } - /* Idle (only local clients) */ - if( Client_Conn( c ) > NONE ) - { - if( ! IRC_WriteStrClient( from, RPL_WHOISIDLE_MSG, Client_ID( from ), Client_ID( c ), Conn_GetIdle( Client_Conn ( c )))) return DISCONNECTED; + /* Idle and signon time (local clients only!) */ + if (Client_Conn(c) > NONE ) { + if (! IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG, + Client_ID(from), Client_ID(c), + (unsigned long)Conn_GetIdle(Client_Conn(c)), + (unsigned long)Conn_GetSignon(Client_Conn(c)))) + return DISCONNECTED; } /* Away? */ @@ -832,9 +1095,9 @@ IRC_WHOWAS( CLIENT *Client, REQUEST *Req ) GLOBAL bool IRC_Send_LUSERS( CLIENT *Client ) { - long cnt; + unsigned long cnt; #ifndef STRICT_RFC - long max; + unsigned long max; #endif assert( Client != NULL ); @@ -881,18 +1144,21 @@ IRC_Send_LUSERS( CLIENT *Client ) } /* IRC_Send_LUSERS */ -static bool Show_MOTD_Start(CLIENT *Client) +static bool +Show_MOTD_Start(CLIENT *Client) { return IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( ))); } -static bool Show_MOTD_Sendline(CLIENT *Client, const char *msg) +static bool +Show_MOTD_Sendline(CLIENT *Client, const char *msg) { return IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID( Client ), msg); } -static bool Show_MOTD_End(CLIENT *Client) +static bool +Show_MOTD_End(CLIENT *Client) { return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client )); } @@ -995,52 +1261,23 @@ IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan ) } /* IRC_Send_NAMES */ + +/** + * Send the ISUPPORT numeric (005). + * This numeric indicates the features that are supported by this server. + * See for details. + */ GLOBAL bool -IRC_Send_WHO( CLIENT *Client, CHANNEL *Chan, bool OnlyOps ) +IRC_Send_ISUPPORT PARAMS((CLIENT * Client)) { - bool is_visible, is_member; - CL2CHAN *cl2chan; - char flags[8]; - CLIENT *c; - - assert( Client != NULL ); - assert( Chan != NULL ); - - if( Channel_IsMemberOf( Chan, Client )) is_member = true; - else is_member = false; - - /* Secret channel? */ - if( ! is_member && strchr( Channel_Modes( Chan ), 's' )) return CONNECTED; - - /* Alle Mitglieder suchen */ - cl2chan = Channel_FirstMember( Chan ); - while( cl2chan ) - { - c = Channel_GetClient( cl2chan ); - - if( strchr( Client_Modes( c ), 'i' )) is_visible = false; - else is_visible = true; - - if( is_member || is_visible ) - { - /* Flags zusammenbasteln */ - strcpy( flags, "H" ); - if( strchr( Client_Modes( c ), 'o' )) strlcat( flags, "*", sizeof( flags )); - if( strchr( Channel_UserModes( Chan, c ), 'o' )) strlcat( flags, "@", sizeof( flags )); - else if( strchr( Channel_UserModes( Chan, c ), 'v' )) strlcat( flags, "+", sizeof( flags )); - - /* ausgeben */ - if(( ! OnlyOps ) || ( strchr( Client_Modes( c ), 'o' ))) - { - if( ! IRC_WriteStrClient( Client, RPL_WHOREPLY_MSG, Client_ID( Client ), Channel_Name( Chan ), Client_User( c ), Client_Hostname( c ), Client_ID( Client_Introducer( c )), Client_ID( c ), flags, Client_Hops( c ), Client_Info( c ))) return DISCONNECTED; - } - } - - /* naechstes Mitglied suchen */ - cl2chan = Channel_NextMember( Chan, cl2chan ); - } - return CONNECTED; -} /* IRC_Send_WHO */ + if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client), + Conf_MaxJoins)) + return DISCONNECTED; + return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client), + CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1, + COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1, + COMMAND_LEN - 113); +} /* IRC_Send_ISUPPORT */ /* -eof- */