static bool Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) { CLIENT *cl, *from; CL2CHAN *cl2chan; CHANNEL *chan; char *currentTarget = Req->argv[0]; char *lastCurrentTarget = NULL; assert(Client != NULL); assert(Req != NULL); if (Req->argc == 0) { if (!SendErrors) return CONNECTED; return IRC_WriteStrClient(Client, ERR_NORECIPIENT_MSG, Client_ID(Client), Req->command); } if (Req->argc == 1) { if (!SendErrors) return CONNECTED; return IRC_WriteStrClient(Client, ERR_NOTEXTTOSEND_MSG, Client_ID(Client)); } if (Req->argc > 2) { if (!SendErrors) return CONNECTED; return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); } 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); /* handle msgtarget = msgto *("," msgto) */ currentTarget = strtok_r(currentTarget, ",", &lastCurrentTarget); ngt_UpperStr(Req->command); while (currentTarget) { /* Check for and handle valid <msgto> of form: * RFC 2812 2.3.1: * msgto = channel / ( user [ "%" host ] "@" servername ) * msgto =/ ( user "%" host ) / targetmask * msgto =/ nickname / ( nickname "!" user "@" host ) */ if (strchr(currentTarget, '!') == NULL) /* nickname */ cl = Client_Search(currentTarget); else cl = NULL; if (cl == NULL) { /* If currentTarget isn't a nickname check for: * user ["%" host] "@" servername * user "%" host * nickname "!" user "@" host */ char target[COMMAND_LEN]; char * nick = NULL; char * user = NULL; char * host = NULL; char * server = NULL; strlcpy(target, currentTarget, COMMAND_LEN); server = strchr(target, '@'); if (server) { *server = '\0'; server++; } host = strchr(target, '%'); if (host) { *host = '\0'; host++; } user = strchr(target, '!'); if (user) { /* msgto form: nick!user@host */ *user = '******'; user++; nick = target; host = server; /* not "@server" but "@host" */ } else { user = target; } for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { if (Client_Type(cl) != CLIENT_USER && Client_Type(cl) != CLIENT_SERVICE) continue; if (nick != NULL && host != NULL) { if (strcasecmp(nick, Client_ID(cl)) == 0 && strcasecmp(user, Client_User(cl)) == 0 && strcasecmp(host, Client_HostnameCloaked(cl)) == 0) break; else continue; } if (strcasecmp(user, Client_User(cl)) != 0) continue; if (host != NULL && strcasecmp(host, Client_HostnameCloaked(cl)) != 0) continue; if (server != NULL && strcasecmp(server, Client_ID(Client_Introducer(cl))) != 0) continue; break; } } if (cl) { /* Target is a user, enforce type */ #ifndef STRICT_RFC if (Client_Type(cl) != ForceType && !(ForceType == CLIENT_USER && (Client_Type(cl) == CLIENT_USER || Client_Type(cl) == CLIENT_SERVICE))) { #else if (Client_Type(cl) != ForceType) { #endif if (SendErrors && !IRC_WriteStrClient( from, ERR_NOSUCHNICK_MSG,Client_ID(from), currentTarget)) return DISCONNECTED; goto send_next_target; } #ifndef STRICT_RFC if (ForceType == CLIENT_SERVICE && (Conn_Options(Client_Conn(Client_NextHop(cl))) & CONN_RFC1459)) { /* SQUERY command but RFC 1459 link: convert * request to PRIVMSG command */ Req->command = "PRIVMSG"; } #endif if (Client_HasMode(cl, 'C')) { cl2chan = Channel_FirstChannelOf(cl); while (cl2chan) { chan = Channel_GetChannel(cl2chan); if (Channel_IsMemberOf(chan, from)) break; cl2chan = Channel_NextChannelOf(cl, cl2chan); } if (!cl2chan) { if (SendErrors && !IRC_WriteStrClient( from, ERR_NOTONSAMECHANNEL_MSG, Client_ID(from), Client_ID(cl))) return DISCONNECTED; goto send_next_target; } } if (SendErrors && (Client_Type(Client) != CLIENT_SERVER) && strchr(Client_Modes(cl), 'a')) { /* Target is away */ if (!IRC_WriteStrClient(from, RPL_AWAY_MSG, Client_ID(from), Client_ID(cl), Client_Away(cl))) return DISCONNECTED; } if (Client_Conn(from) > NONE) { Conn_UpdateIdle(Client_Conn(from)); } if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s", Req->command, Client_ID(cl), Req->argv[1])) return DISCONNECTED; } else if (ForceType != CLIENT_SERVICE && (chan = Channel_Search(currentTarget))) { if (!Channel_Write(chan, from, Client, Req->command, SendErrors, Req->argv[1])) return DISCONNECTED; } else if (ForceType != CLIENT_SERVICE /* $#: server/target mask, RFC 2812, sec. 3.3.1 */ && strchr("$#", currentTarget[0]) && strchr(currentTarget, '.')) { /* targetmask */ if (!Send_Message_Mask(from, Req->command, currentTarget, Req->argv[1], SendErrors)) return DISCONNECTED; } else { if (!SendErrors) return CONNECTED; if (!IRC_WriteStrClient(from, ERR_NOSUCHNICK_MSG, Client_ID(from), currentTarget)) return DISCONNECTED; } send_next_target: currentTarget = strtok_r(NULL, ",", &lastCurrentTarget); if (currentTarget) Conn_SetPenalty(Client_Conn(Client), 1); } return CONNECTED; } /* Send_Message */ static bool Send_Message_Mask(CLIENT * from, char * command, char * targetMask, char * message, bool SendErrors) { CLIENT *cl; bool client_match; char *mask = targetMask + 1; const char *check_wildcards; cl = NULL; if (strchr(Client_Modes(from), 'o') == NULL) { if (!SendErrors) return true; return IRC_WriteStrClient(from, ERR_NOPRIVILEGES_MSG, Client_ID(from)); } /* * RFC 2812, sec. 3.3.1 requires that targetMask have at least one * dot (".") and no wildcards ("*", "?") following the last one. */ check_wildcards = strrchr(targetMask, '.'); assert(check_wildcards != NULL); if (check_wildcards && check_wildcards[strcspn(check_wildcards, "*?")]) { if (!SendErrors) return true; return IRC_WriteStrClient(from, ERR_WILDTOPLEVEL, targetMask); } /* #: hostmask, see RFC 2812, sec. 3.3.1 */ if (targetMask[0] == '#') { for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { if (Client_Type(cl) != CLIENT_USER) continue; client_match = MatchCaseInsensitive(mask, Client_Hostname(cl)); if (client_match) if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s", command, Client_ID(cl), message)) return false; } } else { assert(targetMask[0] == '$'); /* $: server mask, see RFC 2812, sec. 3.3.1 */ for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { if (Client_Type(cl) != CLIENT_USER) continue; client_match = MatchCaseInsensitive(mask, Client_ID(Client_Introducer(cl))); if (client_match) if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s", command, Client_ID(cl), message)) return false; } } return CONNECTED; } /* Send_Message_Mask */
GLOBAL bool IRC_TRACE( CLIENT *Client, REQUEST *Req ) { CLIENT *from, *target, *c; CONN_ID idx, idx2; char user[CLIENT_USER_LEN]; assert( Client != NULL ); assert( Req != NULL ); /* Bad number of arguments? */ if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NORECIPIENT_MSG, Client_ID( Client ), Req->command ); /* Search sender */ 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 ); /* Search target */ if( Req->argc == 1 ) target = Client_Search( Req->argv[0] ); else target = Client_ThisServer( ); /* Forward command to other server? */ if( target != Client_ThisServer( )) { if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] ); /* Send RPL_TRACELINK back to initiator */ idx = Client_Conn( Client ); assert( idx > NONE ); idx2 = Client_Conn( Client_NextHop( target )); assert( idx2 > NONE ); if( ! IRC_WriteStrClient( from, RPL_TRACELINK_MSG, Client_ID( from ), PACKAGE_NAME, PACKAGE_VERSION, Client_ID( target ), Client_ID( Client_NextHop( target )), Option_String( idx2 ), time( NULL ) - Conn_StartTime( idx2 ), Conn_SendQ( idx ), Conn_SendQ( idx2 ))) return DISCONNECTED; /* Forward command */ IRC_WriteStrClientPrefix( target, from, "TRACE %s", Req->argv[0] ); return CONNECTED; } /* Infos about all connected servers */ c = Client_First( ); while( c ) { if( Client_Conn( c ) > NONE ) { /* Local client */ if( Client_Type( c ) == CLIENT_SERVER ) { /* Server link */ strlcpy( user, Client_User( c ), sizeof( user )); if( user[0] == '~' ) strlcpy( user, "unknown", sizeof( user )); if( ! IRC_WriteStrClient( from, RPL_TRACESERVER_MSG, Client_ID( from ), Client_ID( c ), user, Client_Hostname( c ), Client_Mask( Client_ThisServer( )), Option_String( Client_Conn( c )))) return DISCONNECTED; } if(( Client_Type( c ) == CLIENT_USER ) && ( strchr( Client_Modes( c ), 'o' ))) { /* IRC Operator */ if( ! IRC_WriteStrClient( from, RPL_TRACEOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED; } } c = Client_Next( c ); } IRC_SetPenalty( Client, 3 ); return IRC_WriteStrClient( from, RPL_TRACEEND_MSG, Client_ID( from ), Conf_ServerName, PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_DebugLevel ); } /* IRC_TRACE */
/* * Handler for the IRC "TRACE" command. * * @param Client The client from which this command has been received. * @param Req Request structure with prefix and all parameters. * @return CONNECTED or DISCONNECTED. */ GLOBAL bool IRC_TRACE(CLIENT *Client, REQUEST *Req) { CLIENT *from, *target, *c; CONN_ID idx, idx2; char user[CLIENT_USER_LEN]; assert(Client != NULL); assert(Req != NULL); _IRC_GET_SENDER_OR_RETURN_(from, Req, Client) _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from) /* Forward command to other server? */ if (target != Client_ThisServer()) { /* Send RPL_TRACELINK back to initiator */ idx = Client_Conn(Client); assert(idx > NONE); idx2 = Client_Conn(Client_NextHop(target)); assert(idx2 > NONE); if (!IRC_WriteStrClient(from, RPL_TRACELINK_MSG, Client_ID(from), PACKAGE_NAME, PACKAGE_VERSION, Client_ID(target), Client_ID(Client_NextHop(target)), Option_String(idx2), (long)(time(NULL) - Conn_StartTime(idx2)), Conn_SendQ(idx), Conn_SendQ(idx2))) return DISCONNECTED; /* Forward command */ IRC_WriteStrClientPrefix(target, from, "TRACE %s", Req->argv[0]); return CONNECTED; } /* Infos about all connected servers */ c = Client_First(); while (c) { if (Client_Conn(c) > NONE) { /* Local client */ if (Client_Type(c) == CLIENT_SERVER) { /* Server link */ strlcpy(user, Client_User(c), sizeof(user)); if (user[0] == '~') strlcpy(user, "unknown", sizeof(user)); if (!IRC_WriteStrClient(from, RPL_TRACESERVER_MSG, Client_ID(from), Client_ID(c), user, Client_Hostname(c), Client_Mask(Client_ThisServer()), Option_String(Client_Conn(c)))) return DISCONNECTED; } if (Client_Type(c) == CLIENT_USER && Client_HasMode(c, 'o')) { /* IRC Operator */ if (!IRC_WriteStrClient(from, RPL_TRACEOPERATOR_MSG, Client_ID(from), Client_ID(c))) return DISCONNECTED; } } c = Client_Next( c ); } return IRC_WriteStrClient(from, RPL_TRACEEND_MSG, Client_ID(from), Conf_ServerName, PACKAGE_NAME, PACKAGE_VERSION, NGIRCd_DebugLevel); } /* IRC_TRACE */
/** * Get pointer to a static string representing the connection "options". * * @param Idx Connection index. * @return Pointer to static (global) string buffer. */ static char * #if defined(SSL_SUPPORT) || defined(ZLIB) Option_String(CONN_ID Idx) { static char option_txt[8]; UINT16 options; assert(Idx != NONE); options = Conn_Options(Idx); strcpy(option_txt, "F"); /* No idea what this means, but the * original ircd sends it ... */ #ifdef SSL_SUPPORT if(options & CONN_SSL) /* SSL encrypted link */ strlcat(option_txt, "s", sizeof(option_txt)); #endif #ifdef ZLIB if(options & CONN_ZIP) /* zlib compression enabled */ strlcat(option_txt, "z", sizeof(option_txt)); #endif return option_txt; #else Option_String(UNUSED CONN_ID Idx) { return ""; #endif } /* Option_String */ /** * Send a message to target(s). * * This function is used by IRC_{PRIVMSG|NOTICE|SQUERY} to actualy * send the message(s). * * @param Client The client from which this command has been received. * @param Req Request structure with prefix and all parameters. * @param ForceType Required type of the destination of the message(s). * @param SendErrors Whether to report errors back to the client or not. * @return CONNECTED or DISCONNECTED. */ static bool Send_Message(CLIENT * Client, REQUEST * Req, int ForceType, bool SendErrors) { CLIENT *cl, *from; CL2CHAN *cl2chan; CHANNEL *chan; char *currentTarget = Req->argv[0]; char *strtok_last = NULL; char *message = NULL; char *targets[MAX_HNDL_TARGETS]; int i, target_nr = 0; assert(Client != NULL); assert(Req != NULL); if (Req->argc == 0) { if (!SendErrors) return CONNECTED; return IRC_WriteErrClient(Client, ERR_NORECIPIENT_MSG, Client_ID(Client), Req->command); } if (Req->argc == 1) { if (!SendErrors) return CONNECTED; return IRC_WriteErrClient(Client, ERR_NOTEXTTOSEND_MSG, Client_ID(Client)); } if (Req->argc > 2) { if (!SendErrors) return CONNECTED; return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command); } if (Client_Type(Client) == CLIENT_SERVER && Req->prefix) from = Client_Search(Req->prefix); else from = Client; if (!from) return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID(Client), Req->prefix); #ifdef ICONV if (Client_Conn(Client) > NONE) message = Conn_EncodingFrom(Client_Conn(Client), Req->argv[1]); else #endif message = Req->argv[1]; /* handle msgtarget = msgto *("," msgto) */ currentTarget = strtok_r(currentTarget, ",", &strtok_last); ngt_UpperStr(Req->command); /* Please note that "currentTarget" is NULL when the target contains * the separator character only, e. g. "," or ",,,," etc.! */ while (currentTarget) { /* Make sure that there hasn't been such a target already: */ targets[target_nr++] = currentTarget; for(i = 0; i < target_nr - 1; i++) { if (strcasecmp(currentTarget, targets[i]) == 0) goto send_next_target; } /* Check for and handle valid <msgto> of form: * RFC 2812 2.3.1: * msgto = channel / ( user [ "%" host ] "@" servername ) * msgto =/ ( user "%" host ) / targetmask * msgto =/ nickname / ( nickname "!" user "@" host ) */ if (strchr(currentTarget, '!') == NULL) /* nickname */ cl = Client_Search(currentTarget); else cl = NULL; if (cl == NULL) { /* If currentTarget isn't a nickname check for: * user ["%" host] "@" servername * user "%" host * nickname "!" user "@" host */ char target[COMMAND_LEN]; char * nick = NULL; char * user = NULL; char * host = NULL; char * server = NULL; strlcpy(target, currentTarget, COMMAND_LEN); server = strchr(target, '@'); if (server) { *server = '\0'; server++; } host = strchr(target, '%'); if (host) { *host = '\0'; host++; } user = strchr(target, '!'); if (user) { /* msgto form: nick!user@host */ *user = '******'; user++; nick = target; host = server; /* not "@server" but "@host" */ } else { user = target; } for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { if (Client_Type(cl) != CLIENT_USER && Client_Type(cl) != CLIENT_SERVICE) continue; if (nick != NULL && host != NULL) { if (strcasecmp(nick, Client_ID(cl)) == 0 && strcasecmp(user, Client_User(cl)) == 0 && strcasecmp(host, Client_HostnameDisplayed(cl)) == 0) break; else continue; } if (strcasecmp(user, Client_User(cl)) != 0) continue; if (host != NULL && strcasecmp(host, Client_HostnameDisplayed(cl)) != 0) continue; if (server != NULL && strcasecmp(server, Client_ID(Client_Introducer(cl))) != 0) continue; break; } } if (cl) { /* Target is a user, enforce type */ #ifndef STRICT_RFC if (Client_Type(cl) != ForceType && !(ForceType == CLIENT_USER && (Client_Type(cl) == CLIENT_USER || Client_Type(cl) == CLIENT_SERVICE))) { #else if (Client_Type(cl) != ForceType) { #endif if (SendErrors && !IRC_WriteErrClient( from, ERR_NOSUCHNICK_MSG,Client_ID(from), currentTarget)) return DISCONNECTED; goto send_next_target; } #ifndef STRICT_RFC if (ForceType == CLIENT_SERVICE && (Conn_Options(Client_Conn(Client_NextHop(cl))) & CONN_RFC1459)) { /* SQUERY command but RFC 1459 link: convert * request to PRIVMSG command */ Req->command = "PRIVMSG"; } #endif if (Client_HasMode(cl, 'b') && !Client_HasMode(from, 'R') && !Client_HasMode(from, 'o') && !(Client_Type(from) == CLIENT_SERVER) && !(Client_Type(from) == CLIENT_SERVICE)) { if (SendErrors && !IRC_WriteErrClient(from, ERR_NONONREG_MSG, Client_ID(from), Client_ID(cl))) return DISCONNECTED; goto send_next_target; } if (Client_HasMode(cl, 'C') && !Client_HasMode(from, 'o') && !(Client_Type(from) == CLIENT_SERVER) && !(Client_Type(from) == CLIENT_SERVICE)) { cl2chan = Channel_FirstChannelOf(cl); while (cl2chan) { chan = Channel_GetChannel(cl2chan); if (Channel_IsMemberOf(chan, from)) break; cl2chan = Channel_NextChannelOf(cl, cl2chan); } if (!cl2chan) { if (SendErrors && !IRC_WriteErrClient( from, ERR_NOTONSAMECHANNEL_MSG, Client_ID(from), Client_ID(cl))) return DISCONNECTED; goto send_next_target; } } if (SendErrors && (Client_Type(Client) != CLIENT_SERVER) && Client_HasMode(cl, 'a')) { /* Target is away */ if (!IRC_WriteStrClient(from, RPL_AWAY_MSG, Client_ID(from), Client_ID(cl), Client_Away(cl))) return DISCONNECTED; } if (Client_Conn(from) > NONE) { Conn_UpdateIdle(Client_Conn(from)); } if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s", Req->command, Client_ID(cl), message)) return DISCONNECTED; } else if (ForceType != CLIENT_SERVICE && (chan = Channel_Search(currentTarget))) { /* Target is a channel */ if (!Channel_Write(chan, from, Client, Req->command, SendErrors, message)) return DISCONNECTED; } else if (ForceType != CLIENT_SERVICE && strchr("$#", currentTarget[0]) && strchr(currentTarget, '.')) { /* $#: server/host mask, RFC 2812, sec. 3.3.1 */ if (!Send_Message_Mask(from, Req->command, currentTarget, message, SendErrors)) return DISCONNECTED; } else { if (!SendErrors) return CONNECTED; if (!IRC_WriteErrClient(from, ERR_NOSUCHNICK_MSG, Client_ID(from), currentTarget)) return DISCONNECTED; } send_next_target: currentTarget = strtok_r(NULL, ",", &strtok_last); if (!currentTarget) break; Conn_SetPenalty(Client_Conn(Client), 1); if (target_nr >= MAX_HNDL_TARGETS) { /* Too many targets given! */ return IRC_WriteErrClient(Client, ERR_TOOMANYTARGETS_MSG, currentTarget); } } return CONNECTED; } /* Send_Message */ /** * Send a message to "target mask" target(s). * * See RFC 2812, sec. 3.3.1 for details. * * @param from The client from which this command has been received. * @param command The command to use (PRIVMSG, NOTICE, ...). * @param targetMask The "target mask" (will be verified by this function). * @param message The message to send. * @param SendErrors Whether to report errors back to the client or not. * @return CONNECTED or DISCONNECTED. */ static bool Send_Message_Mask(CLIENT * from, char * command, char * targetMask, char * message, bool SendErrors) { CLIENT *cl; bool client_match; char *mask = targetMask + 1; const char *check_wildcards; cl = NULL; if (!Client_HasMode(from, 'o')) { if (!SendErrors) return true; return IRC_WriteErrClient(from, ERR_NOPRIVILEGES_MSG, Client_ID(from)); } /* * RFC 2812, sec. 3.3.1 requires that targetMask have at least one * dot (".") and no wildcards ("*", "?") following the last one. */ check_wildcards = strrchr(targetMask, '.'); if (!check_wildcards || check_wildcards[strcspn(check_wildcards, "*?")]) { if (!SendErrors) return true; return IRC_WriteErrClient(from, ERR_WILDTOPLEVEL_MSG, targetMask); } if (targetMask[0] == '#') { /* #: hostmask, see RFC 2812, sec. 3.3.1 */ for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { if (Client_Type(cl) != CLIENT_USER) continue; client_match = MatchCaseInsensitive(mask, Client_Hostname(cl)); if (client_match) if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s", command, Client_ID(cl), message)) return false; } } else { /* $: server mask, see RFC 2812, sec. 3.3.1 */ assert(targetMask[0] == '$'); for (cl = Client_First(); cl != NULL; cl = Client_Next(cl)) { if (Client_Type(cl) != CLIENT_USER) continue; client_match = MatchCaseInsensitive(mask, Client_ID(Client_Introducer(cl))); if (client_match) if (!IRC_WriteStrClientPrefix(cl, from, "%s %s :%s", command, Client_ID(cl), message)) return false; } } return CONNECTED; } /* Send_Message_Mask */
/** * Handle ENDOFMOTD (376) numeric and login remote server. * The peer is either an IRC server (no IRC+ protocol), or we got the * ENDOFMOTD numeric from an IRC+ server. We have to register the new server. */ GLOBAL bool IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req) { int max_hops, i; CLIENT *c; CHANNEL *chan; Client_SetType(Client, CLIENT_SERVER); Log(LOG_NOTICE | LOG_snotice, "Server \"%s\" registered (connection %d, 1 hop - direct link).", Client_ID(Client), Client_Conn(Client)); /* Get highest hop count */ max_hops = 0; c = Client_First(); while (c) { if (Client_Hops(c) > max_hops) max_hops = Client_Hops(c); c = Client_Next(c); } /* Inform the new server about all other servers, and announce the * new server to all the already registered ones. Important: we have * to do this "in order" and can't introduce servers of which the * "toplevel server" isn't known already. */ for (i = 0; i < (max_hops + 1); i++) { for (c = Client_First(); c != NULL; c = Client_Next(c)) { if (Client_Type(c) != CLIENT_SERVER) continue; /* not a server */ if (Client_Hops(c) != i) continue; /* not actual "nesting level" */ if (c == Client || c == Client_ThisServer()) continue; /* that's us or the peer! */ if (!Announce_Server(Client, c)) return DISCONNECTED; } } /* Announce all the users to the new server */ c = Client_First(); while (c) { if (Client_Type(c) == CLIENT_USER || Client_Type(c) == CLIENT_SERVICE) { if (!Client_Announce(Client, Client_ThisServer(), c)) return DISCONNECTED; } c = Client_Next(c); } /* Announce all channels to the new server */ chan = Channel_First(); while (chan) { if (Channel_IsLocal(chan)) { chan = Channel_Next(chan); continue; } #ifdef IRCPLUS /* Send CHANINFO if the peer supports it */ if (Client_HasFlag(Client, 'C')) { if (!Send_CHANINFO(Client, chan)) return DISCONNECTED; } #endif if (!Announce_Channel(Client, chan)) return DISCONNECTED; /* Get next channel ... */ chan = Channel_Next(chan); } #ifdef IRCPLUS if (Client_HasFlag(Client, 'L')) { LogDebug("Synchronizing INVITE- and BAN-lists ..."); if (!Synchronize_Lists(Client)) return DISCONNECTED; } #endif if (!IRC_WriteStrClient(Client, "PING :%s", Client_ID(Client_ThisServer()))) return DISCONNECTED; return CONNECTED; } /* IRC_Num_ENDOFMOTD */