[BACK]Return to numeric.c CVS log [TXT][DIR] Up to [local] / ircnowd / src / ngircd

Annotation of ircnowd/src/ngircd/numeric.c, Revision 1.1

1.1     ! tomglok     1: /*
        !             2:  * ngIRCd -- The Next Generation IRC Daemon
        !             3:  * Copyright (c)2001-2015 Alexander Barton (alex@barton.de) and Contributors.
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify
        !             6:  * it under the terms of the GNU General Public License as published by
        !             7:  * the Free Software Foundation; either version 2 of the License, or
        !             8:  * (at your option) any later version.
        !             9:  * Please read the file COPYING, README and AUTHORS for more information.
        !            10:  */
        !            11:
        !            12: #include "portab.h"
        !            13:
        !            14: /**
        !            15:  * @file
        !            16:  * Handlers for IRC numerics sent to the server
        !            17:  */
        !            18:
        !            19: #include <assert.h>
        !            20: #include <stdio.h>
        !            21: #include <stdlib.h>
        !            22: #include <string.h>
        !            23: #include <time.h>
        !            24:
        !            25: #include "conn-func.h"
        !            26: #include "conf.h"
        !            27: #include "channel.h"
        !            28: #include "class.h"
        !            29: #include "irc-write.h"
        !            30: #include "lists.h"
        !            31: #include "log.h"
        !            32: #include "parse.h"
        !            33:
        !            34: #include "numeric.h"
        !            35:
        !            36: /**
        !            37:  * Announce a channel and its users in the network.
        !            38:  */
        !            39: static bool
        !            40: Announce_Channel(CLIENT *Client, CHANNEL *Chan)
        !            41: {
        !            42:        CL2CHAN *cl2chan;
        !            43:        CLIENT *cl;
        !            44:        char str[COMMAND_LEN], *ptr;
        !            45:        bool njoin, xop;
        !            46:
        !            47:        /* Check features of remote server */
        !            48:        njoin = Conn_Options(Client_Conn(Client)) & CONN_RFC1459 ? false : true;
        !            49:        xop = Client_HasFlag(Client, 'X') ? true : false;
        !            50:
        !            51:        /* Get all the members of this channel */
        !            52:        cl2chan = Channel_FirstMember(Chan);
        !            53:        snprintf(str, sizeof(str), "NJOIN %s :", Channel_Name(Chan));
        !            54:        while (cl2chan) {
        !            55:                cl = Channel_GetClient(cl2chan);
        !            56:                assert(cl != NULL);
        !            57:
        !            58:                if (njoin) {
        !            59:                        /* RFC 2813: send NJOIN with nicknames and modes
        !            60:                         * (if user is channel operator or has voice) */
        !            61:                        if (str[strlen(str) - 1] != ':')
        !            62:                                strlcat(str, ",", sizeof(str));
        !            63:
        !            64:                        /* Prepare user prefix (ChanOp, voiced, ...) */
        !            65:                        if (xop && Channel_UserHasMode(Chan, cl, 'q'))
        !            66:                                strlcat(str, "~", sizeof(str));
        !            67:                        if (xop && Channel_UserHasMode(Chan, cl, 'a'))
        !            68:                                strlcat(str, "&", sizeof(str));
        !            69:                        if (Channel_UserHasMode(Chan, cl, 'o'))
        !            70:                                strlcat(str, "@", sizeof(str));
        !            71:                        if (xop && Channel_UserHasMode(Chan, cl, 'h'))
        !            72:                                strlcat(str, "%", sizeof(str));
        !            73:                        if (Channel_UserHasMode(Chan, cl, 'v'))
        !            74:                                strlcat(str, "+", sizeof(str));
        !            75:
        !            76:                        strlcat(str, Client_ID(cl), sizeof(str));
        !            77:
        !            78:                        /* Send the data if the buffer is "full" */
        !            79:                        if (strlen(str) > (sizeof(str) - CLIENT_NICK_LEN - 8)) {
        !            80:                                if (!IRC_WriteStrClient(Client, "%s", str))
        !            81:                                        return DISCONNECTED;
        !            82:                                snprintf(str, sizeof(str), "NJOIN %s :",
        !            83:                                         Channel_Name(Chan));
        !            84:                        }
        !            85:                } else {
        !            86:                        /* RFC 1459: no NJOIN, send JOIN and MODE */
        !            87:                        if (!IRC_WriteStrClientPrefix(Client, cl, "JOIN %s",
        !            88:                                                Channel_Name(Chan)))
        !            89:                                return DISCONNECTED;
        !            90:                        ptr = Channel_UserModes(Chan, cl);
        !            91:                        while (*ptr) {
        !            92:                                if (!IRC_WriteStrClientPrefix(Client, cl,
        !            93:                                                   "MODE %s +%c %s",
        !            94:                                                   Channel_Name(Chan), ptr[0],
        !            95:                                                   Client_ID(cl)))
        !            96:                                        return DISCONNECTED;
        !            97:                                ptr++;
        !            98:                        }
        !            99:                }
        !           100:
        !           101:                cl2chan = Channel_NextMember(Chan, cl2chan);
        !           102:        }
        !           103:
        !           104:        /* Data left in the buffer? */
        !           105:        if (str[strlen(str) - 1] != ':') {
        !           106:                /* Yes, send it ... */
        !           107:                if (!IRC_WriteStrClient(Client, "%s", str))
        !           108:                        return DISCONNECTED;
        !           109:        }
        !           110:
        !           111:        return CONNECTED;
        !           112: } /* Announce_Channel */
        !           113:
        !           114: /**
        !           115:  * Announce new server in the network
        !           116:  * @param Client New server
        !           117:  * @param Server Existing server in the network
        !           118:  */
        !           119: static bool
        !           120: Announce_Server(CLIENT * Client, CLIENT * Server)
        !           121: {
        !           122:        CLIENT *c;
        !           123:
        !           124:        if (Client_Conn(Server) > NONE) {
        !           125:                /* Announce the new server to the one already registered
        !           126:                 * which is directly connected to the local server */
        !           127:                if (!IRC_WriteStrClient
        !           128:                    (Server, "SERVER %s %d %d :%s", Client_ID(Client),
        !           129:                     Client_Hops(Client) + 1, Client_MyToken(Client),
        !           130:                     Client_Info(Client)))
        !           131:                        return DISCONNECTED;
        !           132:        }
        !           133:
        !           134:        if (Client_Hops(Server) == 1)
        !           135:                c = Client_ThisServer();
        !           136:        else
        !           137:                c = Client_TopServer(Server);
        !           138:
        !           139:        /* Inform new server about the one already registered in the network */
        !           140:        return IRC_WriteStrClientPrefix(Client, c, "SERVER %s %d %d :%s",
        !           141:                Client_ID(Server), Client_Hops(Server) + 1,
        !           142:                Client_MyToken(Server), Client_Info(Server));
        !           143: } /* Announce_Server */
        !           144:
        !           145: #ifdef IRCPLUS
        !           146:
        !           147: /**
        !           148:  * Send a specific list to a remote server.
        !           149:  */
        !           150: static bool
        !           151: Send_List(CLIENT *Client, CHANNEL *Chan, struct list_head *Head, char Type)
        !           152: {
        !           153:        struct list_elem *elem;
        !           154:
        !           155:        elem = Lists_GetFirst(Head);
        !           156:        while (elem) {
        !           157:                if (!IRC_WriteStrClient(Client, "MODE %s +%c %s",
        !           158:                                        Channel_Name(Chan), Type,
        !           159:                                        Lists_GetMask(elem))) {
        !           160:                        return DISCONNECTED;
        !           161:                }
        !           162:                elem = Lists_GetNext(elem);
        !           163:        }
        !           164:        return CONNECTED;
        !           165: }
        !           166:
        !           167: /**
        !           168:  * Synchronize invite, ban, except, and G-Line lists between servers.
        !           169:  *
        !           170:  * @param Client New server.
        !           171:  * @return CONNECTED or DISCONNECTED.
        !           172:  */
        !           173: static bool
        !           174: Synchronize_Lists(CLIENT * Client)
        !           175: {
        !           176:        CHANNEL *c;
        !           177:        struct list_head *head;
        !           178:        struct list_elem *elem;
        !           179:        time_t t;
        !           180:
        !           181:        assert(Client != NULL);
        !           182:
        !           183:        /* g-lines */
        !           184:        head = Class_GetList(CLASS_GLINE);
        !           185:        elem = Lists_GetFirst(head);
        !           186:        while (elem) {
        !           187:                t = Lists_GetValidity(elem) - time(NULL);
        !           188:                if (!IRC_WriteStrClient(Client, "GLINE %s %ld :%s",
        !           189:                                        Lists_GetMask(elem),
        !           190:                                        t > 0 ? (long)t : 0,
        !           191:                                        Lists_GetReason(elem)))
        !           192:                        return DISCONNECTED;
        !           193:                elem = Lists_GetNext(elem);
        !           194:        }
        !           195:
        !           196:        c = Channel_First();
        !           197:        while (c) {
        !           198:                if (!Send_List(Client, c, Channel_GetListExcepts(c), 'e'))
        !           199:                        return DISCONNECTED;
        !           200:                if (!Send_List(Client, c, Channel_GetListBans(c), 'b'))
        !           201:                        return DISCONNECTED;
        !           202:                if (!Send_List(Client, c, Channel_GetListInvites(c), 'I'))
        !           203:                        return DISCONNECTED;
        !           204:                c = Channel_Next(c);
        !           205:        }
        !           206:        return CONNECTED;
        !           207: }
        !           208:
        !           209: /**
        !           210:  * Send CHANINFO commands to a new server (inform it about existing channels).
        !           211:  * @param Client New server
        !           212:  * @param Chan Channel
        !           213:  */
        !           214: static bool
        !           215: Send_CHANINFO(CLIENT * Client, CHANNEL * Chan)
        !           216: {
        !           217:        char *modes, *topic, *key;
        !           218:        bool has_k, has_l;
        !           219:
        !           220: #ifdef DEBUG
        !           221:        Log(LOG_DEBUG, "Sending CHANINFO commands for \"%s\" ...",
        !           222:            Channel_Name(Chan));
        !           223: #endif
        !           224:
        !           225:        modes = Channel_Modes(Chan);
        !           226:        topic = Channel_Topic(Chan);
        !           227:
        !           228:        if (!*modes && !*topic)
        !           229:                return CONNECTED;
        !           230:
        !           231:        has_k = Channel_HasMode(Chan, 'k');
        !           232:        has_l = Channel_HasMode(Chan, 'l');
        !           233:
        !           234:        /* send CHANINFO */
        !           235:        if (!has_k && !has_l) {
        !           236:                if (!*topic) {
        !           237:                        /* "CHANINFO <chan> +<modes>" */
        !           238:                        return IRC_WriteStrClient(Client, "CHANINFO %s +%s",
        !           239:                                                  Channel_Name(Chan), modes);
        !           240:                }
        !           241:                /* "CHANINFO <chan> +<modes> :<topic>" */
        !           242:                return IRC_WriteStrClient(Client, "CHANINFO %s +%s :%s",
        !           243:                                          Channel_Name(Chan), modes, topic);
        !           244:        }
        !           245:        /* "CHANINFO <chan> +<modes> <key> <limit> :<topic>" */
        !           246:        key = Channel_Key(Chan);
        !           247:        return IRC_WriteStrClient(Client, "CHANINFO %s +%s %s %lu :%s",
        !           248:                                  Channel_Name(Chan), modes,
        !           249:                                  has_k ? (key && *key ? key : "*") : "*",
        !           250:                                  has_l ? Channel_MaxUsers(Chan) : 0, topic);
        !           251: } /* Send_CHANINFO */
        !           252:
        !           253: #endif /* IRCPLUS */
        !           254:
        !           255: /**
        !           256:  * Handle ENDOFMOTD (376) numeric and login remote server.
        !           257:  * The peer is either an IRC server (no IRC+ protocol), or we got the
        !           258:  * ENDOFMOTD numeric from an IRC+ server. We have to register the new server.
        !           259:  */
        !           260: GLOBAL bool
        !           261: IRC_Num_ENDOFMOTD(CLIENT * Client, UNUSED REQUEST * Req)
        !           262: {
        !           263:        int max_hops, i;
        !           264:        CLIENT *c;
        !           265:        CHANNEL *chan;
        !           266:
        !           267:        Client_SetType(Client, CLIENT_SERVER);
        !           268:
        !           269:        Log(LOG_NOTICE | LOG_snotice,
        !           270:            "Server \"%s\" registered (connection %d, 1 hop - direct link).",
        !           271:            Client_ID(Client), Client_Conn(Client));
        !           272:
        !           273:        /* Get highest hop count */
        !           274:        max_hops = 0;
        !           275:        c = Client_First();
        !           276:        while (c) {
        !           277:                if (Client_Hops(c) > max_hops)
        !           278:                        max_hops = Client_Hops(c);
        !           279:                c = Client_Next(c);
        !           280:        }
        !           281:
        !           282:        /* Inform the new server about all other servers, and announce the
        !           283:         * new server to all the already registered ones. Important: we have
        !           284:         * to do this "in order" and can't introduce servers of which the
        !           285:         * "toplevel server" isn't known already. */
        !           286:        for (i = 0; i < (max_hops + 1); i++) {
        !           287:                for (c = Client_First(); c != NULL; c = Client_Next(c)) {
        !           288:                        if (Client_Type(c) != CLIENT_SERVER)
        !           289:                                continue;       /* not a server */
        !           290:                        if (Client_Hops(c) != i)
        !           291:                                continue;       /* not actual "nesting level" */
        !           292:                        if (c == Client || c == Client_ThisServer())
        !           293:                                continue;       /* that's us or the peer! */
        !           294:
        !           295:                        if (!Announce_Server(Client, c))
        !           296:                                return DISCONNECTED;
        !           297:                }
        !           298:        }
        !           299:
        !           300:        /* Announce all the users to the new server */
        !           301:        c = Client_First();
        !           302:        while (c) {
        !           303:                if (Client_Type(c) == CLIENT_USER ||
        !           304:                    Client_Type(c) == CLIENT_SERVICE) {
        !           305:                        if (!Client_Announce(Client, Client_ThisServer(), c))
        !           306:                                return DISCONNECTED;
        !           307:                }
        !           308:                c = Client_Next(c);
        !           309:        }
        !           310:
        !           311:        /* Announce all channels to the new server */
        !           312:        chan = Channel_First();
        !           313:        while (chan) {
        !           314:                if (Channel_IsLocal(chan)) {
        !           315:                        chan = Channel_Next(chan);
        !           316:                        continue;
        !           317:                }
        !           318: #ifdef IRCPLUS
        !           319:                /* Send CHANINFO if the peer supports it */
        !           320:                if (Client_HasFlag(Client, 'C')) {
        !           321:                        if (!Send_CHANINFO(Client, chan))
        !           322:                                return DISCONNECTED;
        !           323:                }
        !           324: #endif
        !           325:
        !           326:                if (!Announce_Channel(Client, chan))
        !           327:                        return DISCONNECTED;
        !           328:
        !           329:                /* Get next channel ... */
        !           330:                chan = Channel_Next(chan);
        !           331:        }
        !           332:
        !           333: #ifdef IRCPLUS
        !           334:        if (Client_HasFlag(Client, 'L')) {
        !           335:                LogDebug("Synchronizing INVITE- and BAN-lists ...");
        !           336:                if (!Synchronize_Lists(Client))
        !           337:                        return DISCONNECTED;
        !           338:        }
        !           339: #endif
        !           340:
        !           341:        if (!IRC_WriteStrClient(Client, "PING :%s",
        !           342:            Client_ID(Client_ThisServer())))
        !           343:                return DISCONNECTED;
        !           344:
        !           345:        return CONNECTED;
        !           346: } /* IRC_Num_ENDOFMOTD */
        !           347:
        !           348: /**
        !           349:  * Handle ISUPPORT (005) numeric.
        !           350:  */
        !           351: GLOBAL bool
        !           352: IRC_Num_ISUPPORT(CLIENT * Client, REQUEST * Req)
        !           353: {
        !           354:        int i;
        !           355:        char *key, *value;
        !           356:
        !           357:        for (i = 1; i < Req->argc - 1; i++) {
        !           358:                key = Req->argv[i];
        !           359:                value = strchr(key, '=');
        !           360:                if (value)
        !           361:                        *value++ = '\0';
        !           362:                else
        !           363:                        value = "";
        !           364:
        !           365:                if (strcmp("NICKLEN", key) == 0) {
        !           366:                        if ((unsigned int)atol(value) == Conf_MaxNickLength - 1)
        !           367:                                continue;
        !           368:
        !           369:                        /* Nickname length settings are different! */
        !           370:                        Log(LOG_ERR,
        !           371:                            "Peer uses incompatible nickname length (%d/%d)! Disconnecting ...",
        !           372:                            Conf_MaxNickLength - 1, atoi(value));
        !           373:                        Conn_Close(Client_Conn(Client),
        !           374:                                   "Incompatible nickname length",
        !           375:                                   NULL, false);
        !           376:                        return DISCONNECTED;
        !           377:                }
        !           378:        }
        !           379:
        !           380:        return CONNECTED;
        !           381: } /* IRC_Num_ISUPPORT */
        !           382:
        !           383: /* -eof- */

CVSweb