X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fnumeric.c;h=0440768c6151ccab7a5d8e3d043c2056e1b6d321;hp=af1ac027927f5215aa0070f0ca3b1c804f0125e3;hb=164e15b8c6eb86d4ae640d64a849945e0b4395b0;hpb=687784d276feecf3c87735eef180b7df61852823 diff --git a/src/ngircd/numeric.c b/src/ngircd/numeric.c index af1ac027..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", @@ -100,8 +173,17 @@ Announce_User(CLIENT * Client, CLIENT * User) } 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)), @@ -113,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) @@ -125,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 */ @@ -210,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); @@ -252,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; } @@ -262,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')) { @@ -270,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);