X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fngircd%2Fnumeric.c;h=0440768c6151ccab7a5d8e3d043c2056e1b6d321;hb=05cc9bf9b064c7048f6b197462a686c5a9100798;hp=d22bf3ae348c3b2ebeccf63dc3fbad1e5f3d56a0;hpb=a60465be3ec6e6960a981c5e2c21846839359653;p=ngircd-alex.git diff --git a/src/ngircd/numeric.c b/src/ngircd/numeric.c index d22bf3ae..0440768c 100644 --- a/src/ngircd/numeric.c +++ b/src/ngircd/numeric.c @@ -7,12 +7,15 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * Please read the file COPYING, README and AUTHORS for more information. - * - * Handlers for IRC numerics sent to the server */ #include "portab.h" +/** + * @file + * Handlers for IRC numerics sent to the server + */ + #include "imp.h" #include #include @@ -20,13 +23,12 @@ #include #include "defines.h" -#include "resolve.h" #include "conn.h" #include "conf.h" #include "conn.h" #include "conn-func.h" -#include "client.h" #include "channel.h" +#include "class.h" #include "irc-write.h" #include "lists.h" #include "log.h" @@ -37,6 +39,77 @@ #include "numeric.h" +/** + * Announce a channel and its users in the network. + */ +static bool +Announce_Channel(CLIENT *Client, CHANNEL *Chan) +{ + CL2CHAN *cl2chan; + CLIENT *cl; + char str[LINE_LEN], *ptr; + bool njoin; + + if (Conn_Options(Client_Conn(Client)) & CONN_RFC1459) + njoin = false; + else + njoin = true; + + /* Get all the members of this channel */ + cl2chan = Channel_FirstMember(Chan); + snprintf(str, sizeof(str), "NJOIN %s :", Channel_Name(Chan)); + while (cl2chan) { + cl = Channel_GetClient(cl2chan); + assert(cl != NULL); + + if (njoin) { + /* RFC 2813: send NJOIN with nick names and modes + * (if user is channel operator or has voice) */ + if (str[strlen(str) - 1] != ':') + strlcat(str, ",", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'v')) + strlcat(str, "+", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'o')) + strlcat(str, "@", sizeof(str)); + strlcat(str, Client_ID(cl), sizeof(str)); + + /* Send the data if the buffer is "full" */ + if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 8)) { + if (!IRC_WriteStrClient(Client, "%s", str)) + return DISCONNECTED; + snprintf(str, sizeof(str), "NJOIN %s :", + Channel_Name(Chan)); + } + } else { + /* RFC 1459: no NJOIN, send JOIN and MODE */ + if (!IRC_WriteStrClientPrefix(Client, cl, "JOIN %s", + Channel_Name(Chan))) + return DISCONNECTED; + ptr = Channel_UserModes(Chan, cl); + while (*ptr) { + if (!IRC_WriteStrClientPrefix(Client, cl, + "MODE %s +%c %s", + Channel_Name(Chan), ptr[0], + Client_ID(cl))) + return DISCONNECTED; + ptr++; + } + } + + cl2chan = Channel_NextMember(Chan, cl2chan); + } + + /* Data left in the buffer? */ + if (str[strlen(str) - 1] != ':') { + /* Yes, send it ... */ + if (!IRC_WriteStrClient(Client, "%s", str)) + return DISCONNECTED; + } + + return CONNECTED; +} /* Announce_Channel */ + + /** * Announce new server in the network * @param Client New server @@ -60,7 +133,7 @@ Announce_Server(CLIENT * Client, CLIENT * Server) if (Client_Hops(Server) == 1) c = Client_ThisServer(); else - c = Client_Introducer(Server); + c = Client_TopServer(Server); /* Inform new server about the one already registered in the network */ return IRC_WriteStrClientPrefix(Client, c, "SERVER %s %d %d :%s", @@ -78,21 +151,39 @@ static bool Announce_User(CLIENT * Client, CLIENT * User) { CONN_ID conn; + char *modes; + conn = Client_Conn(Client); if (Conn_Options(conn) & CONN_RFC1459) { /* RFC 1459 mode: separate NICK and USER commands */ if (! Conn_WriteStr(conn, "NICK %s :%d", Client_ID(User), Client_Hops(User) + 1)) return DISCONNECTED; - return Conn_WriteStr(conn, ":%s USER %s %s %s :%s", + if (! Conn_WriteStr(conn, ":%s USER %s %s %s :%s", Client_ID(User), Client_User(User), Client_Hostname(User), Client_ID(Client_Introducer(User)), - Client_Info(User)); - + Client_Info(User))) + return DISCONNECTED; + modes = Client_Modes(User); + if (modes[0]) { + return Conn_WriteStr(conn, ":%s MODE %s +%s", + Client_ID(User), Client_ID(User), + modes); + } + return CONNECTED; } else { - /* RFC 2813 mode: one combined NICK command */ - return IRC_WriteStrClient(Client, "NICK %s %d %s %s %d +%s :%s", + /* RFC 2813 mode: one combined NICK or SERVICE command */ + if (Client_Type(User) == CLIENT_SERVICE + && strchr(Client_Flags(Client), 'S')) + return IRC_WriteStrClient(Client, + "SERVICE %s %d * +%s %d :%s", Client_Mask(User), + Client_MyToken(Client_Introducer(User)), + Client_Modes(User), Client_Hops(User) + 1, + Client_Info(User)); + else + return IRC_WriteStrClient(Client, + "NICK %s %d %s %s %d +%s :%s", Client_ID(User), Client_Hops(User) + 1, Client_User(User), Client_Hostname(User), Client_MyToken(Client_Introducer(User)), @@ -104,8 +195,10 @@ Announce_User(CLIENT * Client, CLIENT * User) #ifdef IRCPLUS /** - * Synchronize invite and ban lists between servers - * @param Client New server + * Synchronize invite, ban, G- and K-Line lists between servers. + * + * @param Client New server. + * @return CONNECTED or DISCONNECTED. */ static bool Synchronize_Lists(CLIENT * Client) @@ -116,6 +209,18 @@ Synchronize_Lists(CLIENT * Client) assert(Client != NULL); + /* g-lines */ + head = Class_GetList(CLASS_GLINE); + elem = Lists_GetFirst(head); + while (elem) { + if (!IRC_WriteStrClient(Client, "GLINE %s %ld :%s", + Lists_GetMask(elem), + Lists_GetValidity(elem) - time(NULL), + Lists_GetReason(elem))) + return DISCONNECTED; + elem = Lists_GetNext(elem); + } + c = Channel_First(); while (c) { /* ban list */ @@ -158,20 +263,20 @@ Send_CHANINFO(CLIENT * Client, CHANNEL * Chan) { char *modes, *topic; bool has_k, has_l; - + #ifdef DEBUG Log(LOG_DEBUG, "Sending CHANINFO commands ..."); #endif - + modes = Channel_Modes(Chan); topic = Channel_Topic(Chan); - + if (!*modes && !*topic) return CONNECTED; - + has_k = strchr(modes, 'k') != NULL; has_l = strchr(modes, 'l') != NULL; - + /* send CHANINFO */ if (!has_k && !has_l) { if (!*topic) { @@ -201,11 +306,9 @@ Send_CHANINFO(CLIENT * Client, CHANNEL * Chan) GLOBAL bool IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req) { - char str[LINE_LEN]; int max_hops, i; - CLIENT *c, *cl; + CLIENT *c; CHANNEL *chan; - CL2CHAN *cl2chan; Client_SetType(Client, CLIENT_SERVER); @@ -243,7 +346,8 @@ IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req) /* Announce all the users to the new server */ c = Client_First(); while (c) { - if (Client_Type(c) == CLIENT_USER) { + if (Client_Type(c) == CLIENT_USER || + Client_Type(c) == CLIENT_SERVICE) { if (!Announce_User(Client, c)) return DISCONNECTED; } @@ -253,6 +357,10 @@ IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req) /* 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 (strchr(Client_Flags(Client), 'C')) { @@ -261,39 +369,8 @@ IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req) } #endif - /* Get all the members of this channel */ - cl2chan = Channel_FirstMember(chan); - snprintf(str, sizeof(str), "NJOIN %s :", Channel_Name(chan)); - while (cl2chan) { - cl = Channel_GetClient(cl2chan); - assert(cl != NULL); - - /* Nick name, with modes (if applicable) */ - if (str[strlen(str) - 1] != ':') - strlcat(str, ",", sizeof(str)); - if (strchr(Channel_UserModes(chan, cl), 'v')) - strlcat(str, "+", sizeof(str)); - if (strchr(Channel_UserModes(chan, cl), 'o')) - strlcat(str, "@", sizeof(str)); - strlcat(str, Client_ID(cl), sizeof(str)); - - /* Send the data if the buffer is "full" */ - if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 8)) { - if (!IRC_WriteStrClient(Client, "%s", str)) - return DISCONNECTED; - snprintf(str, sizeof(str), "NJOIN %s :", - Channel_Name(chan)); - } - - cl2chan = Channel_NextMember(chan, cl2chan); - } - - /* Data left in the buffer? */ - if (str[strlen(str) - 1] != ':') { - /* Yes, send it ... */ - if (!IRC_WriteStrClient(Client, "%s", str)) - return DISCONNECTED; - } + if (!Announce_Channel(Client, chan)) + return DISCONNECTED; /* Get next channel ... */ chan = Channel_Next(chan);