X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=ngircd-alex.git;a=blobdiff_plain;f=src%2Fngircd%2Fnumeric.c;h=3fc8c461bf73f1455731bf21f818a63455cd619d;hp=927989db9923d99567703938a9800ec60b8803ab;hb=48326e061aacd954e24f76c53ded10448cbc28eb;hpb=d93030ad27af9cd6a807de8f672ae73ec0e1dff8 diff --git a/src/ngircd/numeric.c b/src/ngircd/numeric.c index 927989db..3fc8c461 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,84 @@ #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 nicknames 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), 'q')) + strlcat(str, "~", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'a')) + strlcat(str, "&", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'o')) + strlcat(str, "@", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'h')) + strlcat(str, "%", sizeof(str)); + if (strchr(Channel_UserModes(Chan, cl), 'v')) + 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 +140,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 +180,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 +202,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 +216,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 +313,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); @@ -263,6 +364,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')) { @@ -271,39 +376,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); @@ -317,6 +391,10 @@ IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req) } #endif + if (!IRC_WriteStrClient(Client, "PING :%s", + Client_ID(Client_ThisServer()))) + return DISCONNECTED; + return CONNECTED; } /* IRC_Num_ENDOFMOTD */ @@ -342,12 +420,12 @@ IRC_Num_ISUPPORT(CLIENT * Client, REQUEST * Req) if ((unsigned int)atol(value) == Conf_MaxNickLength - 1) continue; - /* Nick name length settings are different! */ + /* Nickname length settings are different! */ Log(LOG_ERR, - "Peer uses incompatible nick name length (%d/%d)! Disconnecting ...", + "Peer uses incompatible nickname length (%d/%d)! Disconnecting ...", Conf_MaxNickLength - 1, atoi(value)); Conn_Close(Client_Conn(Client), - "Incompatible nick name length", + "Incompatible nickname length", NULL, false); return DISCONNECTED; }