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

Annotation of ircnowd/src/ngircd/irc-channel.c, Revision 1.1

1.1     ! tomglok     1: /*
        !             2:  * ngIRCd -- The Next Generation IRC Daemon
        !             3:  * Copyright (c)2001-2018 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:  * IRC channel commands
        !            17:  */
        !            18:
        !            19: #include <assert.h>
        !            20: #include <stdlib.h>
        !            21: #include <stdio.h>
        !            22: #include <string.h>
        !            23:
        !            24: #include "conn.h"
        !            25: #include "channel.h"
        !            26: #include "conn-func.h"
        !            27: #include "lists.h"
        !            28: #include "log.h"
        !            29: #include "match.h"
        !            30: #include "messages.h"
        !            31: #include "parse.h"
        !            32: #include "irc.h"
        !            33: #include "irc-info.h"
        !            34: #include "irc-macros.h"
        !            35: #include "irc-write.h"
        !            36: #include "conf.h"
        !            37:
        !            38: #include "irc-channel.h"
        !            39:
        !            40: /**
        !            41:  * Part from all channels.
        !            42:  *
        !            43:  * RFC 2812, (3.2.1 Join message Command):
        !            44:  *  Note that this message accepts a special argument ("0"), which is a
        !            45:  *  special request to leave all channels the user is currently a member of.
        !            46:  *  The server will process this message as if the user had sent a PART
        !            47:  *  command (See Section 3.2.2) for each channel he is a member of.
        !            48:  *
        !            49:  * @param client       Client that initiated the part request
        !            50:  * @param target       Client that should part all joined channels
        !            51:  * @returns            CONNECTED or DISCONNECTED
        !            52:  */
        !            53: static bool
        !            54: part_from_all_channels(CLIENT* client, CLIENT *target)
        !            55: {
        !            56:        CL2CHAN *cl2chan;
        !            57:        CHANNEL *chan;
        !            58:
        !            59:        while ((cl2chan = Channel_FirstChannelOf(target))) {
        !            60:                chan = Channel_GetChannel(cl2chan);
        !            61:                assert( chan != NULL );
        !            62:                Channel_Part(target, client, Channel_Name(chan), Client_ID(target));
        !            63:        }
        !            64:        return CONNECTED;
        !            65: } /* part_from_all_channels */
        !            66:
        !            67: /**
        !            68:  * Check weather a local client is allowed to join an already existing
        !            69:  * channel or not.
        !            70:  *
        !            71:  * @param Client       Client that sent the JOIN command
        !            72:  * @param chan         Channel to check
        !            73:  * @param channame     Name of the channel
        !            74:  * @param key          Provided channel key (or NULL)
        !            75:  * @returns            true if client is allowed to join, false otherwise
        !            76:  */
        !            77: static bool
        !            78: join_allowed(CLIENT *Client, CHANNEL *chan, const char *channame,
        !            79:             const char *key)
        !            80: {
        !            81:        bool is_invited, is_banned, is_exception;
        !            82:
        !            83:        /* Allow IRC operators to overwrite channel limits */
        !            84:        if (Client_HasMode(Client, 'o'))
        !            85:                return true;
        !            86:
        !            87:        is_banned = Lists_Check(Channel_GetListBans(chan), Client);
        !            88:        is_exception = Lists_Check(Channel_GetListExcepts(chan), Client);
        !            89:        is_invited = Lists_Check(Channel_GetListInvites(chan), Client);
        !            90:
        !            91:        if (is_banned && !is_invited && !is_exception) {
        !            92:                /* Client is banned from channel (and not on invite list) */
        !            93:                IRC_WriteErrClient(Client, ERR_BANNEDFROMCHAN_MSG,
        !            94:                                   Client_ID(Client), channame);
        !            95:                return false;
        !            96:        }
        !            97:
        !            98:        if (Channel_HasMode(chan, 'i') && !is_invited) {
        !            99:                /* Channel is "invite-only" and client is not on invite list */
        !           100:                IRC_WriteErrClient(Client, ERR_INVITEONLYCHAN_MSG,
        !           101:                                   Client_ID(Client), channame);
        !           102:                return false;
        !           103:        }
        !           104:
        !           105:        if (!Channel_CheckKey(chan, Client, key ? key : "")) {
        !           106:                /* Channel is protected by a channel key and the client
        !           107:                 * didn't specify the correct one */
        !           108:                IRC_WriteErrClient(Client, ERR_BADCHANNELKEY_MSG,
        !           109:                                   Client_ID(Client), channame);
        !           110:                return false;
        !           111:        }
        !           112:
        !           113:        if (Channel_HasMode(chan, 'l') &&
        !           114:            (Channel_MaxUsers(chan) <= Channel_MemberCount(chan))) {
        !           115:                /* There are more clints joined to this channel than allowed */
        !           116:                IRC_WriteErrClient(Client, ERR_CHANNELISFULL_MSG,
        !           117:                                   Client_ID(Client), channame);
        !           118:                return false;
        !           119:        }
        !           120:
        !           121:        if (Channel_HasMode(chan, 'z') && !Conn_UsesSSL(Client_Conn(Client))) {
        !           122:                /* Only "secure" clients are allowed, but clients doesn't
        !           123:                 * use SSL encryption */
        !           124:                IRC_WriteErrClient(Client, ERR_SECURECHANNEL_MSG,
        !           125:                                   Client_ID(Client), channame);
        !           126:                return false;
        !           127:        }
        !           128:
        !           129:        if (Channel_HasMode(chan, 'O') && !Client_HasMode(Client, 'o')) {
        !           130:                /* Only IRC operators are allowed! */
        !           131:                IRC_WriteErrClient(Client, ERR_OPONLYCHANNEL_MSG,
        !           132:                                   Client_ID(Client), channame);
        !           133:                return false;
        !           134:        }
        !           135:
        !           136:        if (Channel_HasMode(chan, 'R') && !Client_HasMode(Client, 'R')) {
        !           137:                /* Only registered users are allowed! */
        !           138:                IRC_WriteErrClient(Client, ERR_REGONLYCHANNEL_MSG,
        !           139:                                   Client_ID(Client), channame);
        !           140:                return false;
        !           141:        }
        !           142:
        !           143:        return true;
        !           144: } /* join_allowed */
        !           145:
        !           146: /**
        !           147:  * Set user channel modes.
        !           148:  *
        !           149:  * @param chan         Channel
        !           150:  * @param target       User to set modes for
        !           151:  * @param flags                Channel modes to add
        !           152:  */
        !           153: static void
        !           154: join_set_channelmodes(CHANNEL *chan, CLIENT *target, const char *flags)
        !           155: {
        !           156:        if (flags) {
        !           157:                while (*flags) {
        !           158:                        Channel_UserModeAdd(chan, target, *flags);
        !           159:                        flags++;
        !           160:                }
        !           161:        }
        !           162:
        !           163:        /* If the channel is persistent (+P) and client is an IRC op:
        !           164:         * make client chanop, if not disabled in configuration. */
        !           165:        if (Channel_HasMode(chan, 'P') && Conf_OperChanPAutoOp
        !           166:            && Client_HasMode(target, 'o'))
        !           167:                Channel_UserModeAdd(chan, target, 'o');
        !           168: } /* join_set_channelmodes */
        !           169:
        !           170: /**
        !           171:  * Forward JOIN command to a specific server
        !           172:  *
        !           173:  * This function differentiates between servers using RFC 2813 mode that
        !           174:  * support the JOIN command with appended ASCII 7 character and channel
        !           175:  * modes, and servers using RFC 1459 protocol which require separate JOIN
        !           176:  * and MODE commands.
        !           177:  *
        !           178:  * @param To           Forward JOIN (and MODE) command to this peer server
        !           179:  * @param Prefix       Client used to prefix the genrated commands
        !           180:  * @param Data         Parameters of JOIN command to forward, probably
        !           181:  *                     containing channel modes separated by ASCII 7.
        !           182:  */
        !           183: static void
        !           184: cb_join_forward(CLIENT *To, CLIENT *Prefix, void *Data)
        !           185: {
        !           186:        CONN_ID conn;
        !           187:        char str[COMMAND_LEN], *ptr = NULL;
        !           188:
        !           189:        strlcpy(str, (char *)Data, sizeof(str));
        !           190:        conn = Client_Conn(To);
        !           191:
        !           192:        if (Conn_Options(conn) & CONN_RFC1459) {
        !           193:                /* RFC 1459 compatibility mode, appended modes are NOT
        !           194:                 * supported, so strip them off! */
        !           195:                ptr = strchr(str, 0x7);
        !           196:                if (ptr)
        !           197:                        *ptr++ = '\0';
        !           198:        }
        !           199:
        !           200:        IRC_WriteStrClientPrefix(To, Prefix, "JOIN %s", str);
        !           201:        if (ptr && *ptr)
        !           202:                IRC_WriteStrClientPrefix(To, Prefix, "MODE %s +%s %s", str, ptr,
        !           203:                                         Client_ID(Prefix));
        !           204: } /* cb_join_forward */
        !           205:
        !           206: /**
        !           207:  * Forward JOIN command to all servers
        !           208:  *
        !           209:  * This function calls cb_join_forward(), which differentiates between
        !           210:  * protocol implementations (e.g. RFC 2812, RFC 1459).
        !           211:  *
        !           212:  * @param Client       Client used to prefix the genrated commands
        !           213:  * @param target       Forward JOIN (and MODE) command to this peer server
        !           214:  * @param chan         Channel structure
        !           215:  * @param channame     Channel name
        !           216:  */
        !           217: static void
        !           218: join_forward(CLIENT *Client, CLIENT *target, CHANNEL *chan,
        !           219:                                        const char *channame)
        !           220: {
        !           221:        char modes[CHANNEL_MODE_LEN], str[COMMAND_LEN];
        !           222:
        !           223:        /* RFC 2813, 4.2.1: channel modes are separated from the channel
        !           224:         * name with ASCII 7, if any, and not spaces: */
        !           225:        strlcpy(&modes[1], Channel_UserModes(chan, target), sizeof(modes) - 1);
        !           226:        if (modes[1])
        !           227:                modes[0] = 0x7;
        !           228:        else
        !           229:                modes[0] = '\0';
        !           230:
        !           231:        /* forward to other servers (if it is not a local channel) */
        !           232:        if (!Channel_IsLocal(chan)) {
        !           233:                snprintf(str, sizeof(str), "%s%s", channame, modes);
        !           234:                IRC_WriteStrServersPrefixFlag_CB(Client, target, '\0',
        !           235:                                                 cb_join_forward, str);
        !           236:        }
        !           237:
        !           238:        /* tell users in this channel about the new client */
        !           239:        IRC_WriteStrChannelPrefix(Client, chan, target, false,
        !           240:                                  "JOIN :%s",  channame);
        !           241:
        !           242:        /* synchronize channel modes */
        !           243:        if (modes[1]) {
        !           244:                IRC_WriteStrChannelPrefix(Client, chan, target, false,
        !           245:                                          "MODE %s +%s %s", channame,
        !           246:                                          &modes[1], Client_ID(target));
        !           247:        }
        !           248: } /* join_forward */
        !           249:
        !           250: /**
        !           251:  * Acknowledge user JOIN request and send "channel info" numerics.
        !           252:  *
        !           253:  * @param Client       Client used to prefix the genrated commands
        !           254:  * @param target       Forward commands/numerics to this user
        !           255:  * @param chan         Channel structure
        !           256:  * @param channame     Channel name
        !           257:  */
        !           258: static bool
        !           259: join_send_topic(CLIENT *Client, CLIENT *target, CHANNEL *chan,
        !           260:                                        const char *channame)
        !           261: {
        !           262:        const char *topic;
        !           263:
        !           264:        if (Client_Type(Client) != CLIENT_USER)
        !           265:                return true;
        !           266:        /* acknowledge join */
        !           267:        if (!IRC_WriteStrClientPrefix(Client, target, "JOIN :%s", channame))
        !           268:                return false;
        !           269:
        !           270:        /* Send topic to client, if any */
        !           271:        topic = Channel_Topic(chan);
        !           272:        assert(topic != NULL);
        !           273:        if (*topic) {
        !           274:                if (!IRC_WriteStrClient(Client, RPL_TOPIC_MSG,
        !           275:                        Client_ID(Client), channame, topic))
        !           276:                                return false;
        !           277: #ifndef STRICT_RFC
        !           278:                if (!IRC_WriteStrClient(Client, RPL_TOPICSETBY_MSG,
        !           279:                        Client_ID(Client), channame,
        !           280:                        Channel_TopicWho(chan),
        !           281:                        Channel_TopicTime(chan)))
        !           282:                                return false;
        !           283: #endif
        !           284:        }
        !           285:        /* send list of channel members to client */
        !           286:        if (!IRC_Send_NAMES(Client, chan))
        !           287:                return false;
        !           288:        return IRC_WriteStrClient(Client, RPL_ENDOFNAMES_MSG, Client_ID(Client),
        !           289:                                  Channel_Name(chan));
        !           290: } /* join_send_topic */
        !           291:
        !           292: /**
        !           293:  * Handler for the IRC "JOIN" command.
        !           294:  *
        !           295:  * @param Client The client from which this command has been received.
        !           296:  * @param Req Request structure with prefix and all parameters.
        !           297:  * @return CONNECTED or DISCONNECTED.
        !           298:  */
        !           299: GLOBAL bool
        !           300: IRC_JOIN( CLIENT *Client, REQUEST *Req )
        !           301: {
        !           302:        char *channame, *key = NULL, *flags, *lastkey = NULL, *lastchan = NULL;
        !           303:        CLIENT *target;
        !           304:        CHANNEL *chan;
        !           305:
        !           306:        assert (Client != NULL);
        !           307:        assert (Req != NULL);
        !           308:
        !           309:        _IRC_GET_SENDER_OR_RETURN_(target, Req, Client)
        !           310:
        !           311:        /* Is argument "0"? */
        !           312:        if (Req->argc == 1 && !strncmp("0", Req->argv[0], 2))
        !           313:                return part_from_all_channels(Client, target);
        !           314:
        !           315:        /* Are channel keys given? */
        !           316:        if (Req->argc > 1)
        !           317:                key = strtok_r(Req->argv[1], ",", &lastkey);
        !           318:
        !           319:        channame = Req->argv[0];
        !           320:        channame = strtok_r(channame, ",", &lastchan);
        !           321:
        !           322:        /* Make sure that "channame" is not the empty string ("JOIN :") */
        !           323:        if (!channame)
        !           324:                return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
        !           325:                                          Client_ID(Client), Req->command);
        !           326:
        !           327:        while (channame) {
        !           328:                flags = NULL;
        !           329:
        !           330:                /* Did the server include channel-user-modes? */
        !           331:                if (Client_Type(Client) == CLIENT_SERVER) {
        !           332:                        flags = strchr(channame, 0x7);
        !           333:                        if (flags) {
        !           334:                                *flags = '\0';
        !           335:                                flags++;
        !           336:                        }
        !           337:                }
        !           338:
        !           339:                chan = Channel_Search(channame);
        !           340:
        !           341:                /* Local client? */
        !           342:                if (Client_Type(Client) == CLIENT_USER) {
        !           343:                        if (chan) {
        !           344:                                /* Already existing channel: already member? */
        !           345:                                if (Channel_IsMemberOf(chan, Client))
        !           346:                                    goto join_next;
        !           347:                        } else {
        !           348:                                /* Channel must be created */
        !           349:                                if (!strchr(Conf_AllowedChannelTypes, channame[0])) {
        !           350:                                        /* ... but channel type is not allowed! */
        !           351:                                        IRC_WriteErrClient(Client,
        !           352:                                                ERR_NOSUCHCHANNEL_MSG,
        !           353:                                                Client_ID(Client), channame);
        !           354:                                        goto join_next;
        !           355:                                }
        !           356:                        }
        !           357:
        !           358:                        /* Test if the user has reached the channel limit */
        !           359:                        if ((Conf_MaxJoins > 0) &&
        !           360:                            (Channel_CountForUser(Client) >= Conf_MaxJoins)) {
        !           361:                                if (!IRC_WriteErrClient(Client,
        !           362:                                                ERR_TOOMANYCHANNELS_MSG,
        !           363:                                                Client_ID(Client), channame))
        !           364:                                        return DISCONNECTED;
        !           365:                                goto join_next;
        !           366:                        }
        !           367:
        !           368:                        if (chan) {
        !           369:                                /* Already existing channel: check if the
        !           370:                                 * client is allowed to join */
        !           371:                                if (!join_allowed(Client, chan, channame, key))
        !           372:                                        goto join_next;
        !           373:                        } else {
        !           374:                                /* New channel: first user will become channel
        !           375:                                 * operator unless this is a modeless channel */
        !           376:                                if (*channame != '+')
        !           377:                                        flags = "o";
        !           378:                        }
        !           379:
        !           380:                        /* Local client: update idle time */
        !           381:                        Conn_UpdateIdle(Client_Conn(Client));
        !           382:                } else {
        !           383:                        /* Remote server: we don't need to know whether the
        !           384:                         * client is invited or not, but we have to make sure
        !           385:                         * that the "one shot" entries (generated by INVITE
        !           386:                         * commands) in this list become deleted when a user
        !           387:                         * joins a channel this way. */
        !           388:                        if (chan)
        !           389:                                (void)Lists_Check(Channel_GetListInvites(chan),
        !           390:                                                  target);
        !           391:                }
        !           392:
        !           393:                /* Join channel (and create channel if it doesn't exist) */
        !           394:                if (!Channel_Join(target, channame))
        !           395:                        goto join_next;
        !           396:
        !           397:                if (!chan) { /* channel is new; it has been created above */
        !           398:                        chan = Channel_Search(channame);
        !           399:                        assert(chan != NULL);
        !           400:                        if (Channel_IsModeless(chan)) {
        !           401:                                Channel_ModeAdd(chan, 't'); /* /TOPIC not allowed */
        !           402:                                Channel_ModeAdd(chan, 'n'); /* no external msgs */
        !           403:                        }
        !           404:                }
        !           405:                assert(chan != NULL);
        !           406:
        !           407:                join_set_channelmodes(chan, target, flags);
        !           408:
        !           409:                join_forward(Client, target, chan, channame);
        !           410:
        !           411:                if (!join_send_topic(Client, target, chan, channame))
        !           412:                        break; /* write error */
        !           413:
        !           414:        join_next:
        !           415:                /* next channel? */
        !           416:                channame = strtok_r(NULL, ",", &lastchan);
        !           417:                if (channame && key)
        !           418:                        key = strtok_r(NULL, ",", &lastkey);
        !           419:        }
        !           420:        return CONNECTED;
        !           421: } /* IRC_JOIN */
        !           422:
        !           423: /**
        !           424:  * Handler for the IRC "PART" command.
        !           425:  *
        !           426:  * @param Client The client from which this command has been received.
        !           427:  * @param Req Request structure with prefix and all parameters.
        !           428:  * @return CONNECTED or DISCONNECTED.
        !           429:  */
        !           430: GLOBAL bool
        !           431: IRC_PART(CLIENT * Client, REQUEST * Req)
        !           432: {
        !           433:        CLIENT *target;
        !           434:        char *chan;
        !           435:
        !           436:        assert(Client != NULL);
        !           437:        assert(Req != NULL);
        !           438:
        !           439:        _IRC_GET_SENDER_OR_RETURN_(target, Req, Client)
        !           440:
        !           441:        /* Loop over all the given channel names */
        !           442:        chan = strtok(Req->argv[0], ",");
        !           443:
        !           444:        /* Make sure that "chan" is not the empty string ("PART :") */
        !           445:        if (!chan)
        !           446:                return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
        !           447:                                          Client_ID(Client), Req->command);
        !           448:
        !           449:        while (chan) {
        !           450:                Channel_Part(target, Client, chan,
        !           451:                             Req->argc > 1 ? Req->argv[1] : "");
        !           452:                chan = strtok(NULL, ",");
        !           453:        }
        !           454:
        !           455:        /* Update idle time, if local client */
        !           456:        if (Client_Conn(Client) > NONE)
        !           457:                Conn_UpdateIdle(Client_Conn(Client));
        !           458:
        !           459:        return CONNECTED;
        !           460: } /* IRC_PART */
        !           461:
        !           462: /**
        !           463:  * Handler for the IRC "TOPIC" command.
        !           464:  *
        !           465:  * @param Client The client from which this command has been received.
        !           466:  * @param Req Request structure with prefix and all parameters.
        !           467:  * @return CONNECTED or DISCONNECTED.
        !           468:  */
        !           469: GLOBAL bool
        !           470: IRC_TOPIC( CLIENT *Client, REQUEST *Req )
        !           471: {
        !           472:        CHANNEL *chan;
        !           473:        CLIENT *from;
        !           474:        char *topic;
        !           475:        bool r, topic_power;
        !           476:
        !           477:        assert( Client != NULL );
        !           478:        assert( Req != NULL );
        !           479:
        !           480:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
        !           481:
        !           482:        chan = Channel_Search(Req->argv[0]);
        !           483:        if (!chan)
        !           484:                return IRC_WriteErrClient(from, ERR_NOSUCHCHANNEL_MSG,
        !           485:                                          Client_ID(from), Req->argv[0]);
        !           486:
        !           487:        /* Only remote servers and channel members are allowed to change the
        !           488:         * channel topic, and IRC operators when the Conf_OperCanMode option
        !           489:         * is set in the server configuration. */
        !           490:        if (Client_Type(Client) != CLIENT_SERVER) {
        !           491:                topic_power = Client_HasMode(from, 'o');
        !           492:                if (!Channel_IsMemberOf(chan, from)
        !           493:                    && !(Conf_OperCanMode && topic_power))
        !           494:                        return IRC_WriteErrClient(from, ERR_NOTONCHANNEL_MSG,
        !           495:                                                  Client_ID(from), Req->argv[0]);
        !           496:        } else
        !           497:                topic_power = true;
        !           498:
        !           499:        if (Req->argc == 1) {
        !           500:                /* Request current topic */
        !           501:                topic = Channel_Topic(chan);
        !           502:                if (*topic) {
        !           503:                        r = IRC_WriteStrClient(from, RPL_TOPIC_MSG,
        !           504:                                               Client_ID(Client),
        !           505:                                               Channel_Name(chan), topic);
        !           506: #ifndef STRICT_RFC
        !           507:                        if (!r)
        !           508:                                return r;
        !           509:                        r = IRC_WriteStrClient(from, RPL_TOPICSETBY_MSG,
        !           510:                                               Client_ID(Client),
        !           511:                                               Channel_Name(chan),
        !           512:                                               Channel_TopicWho(chan),
        !           513:                                               Channel_TopicTime(chan));
        !           514: #endif
        !           515:                        return r;
        !           516:                }
        !           517:                else
        !           518:                        return IRC_WriteStrClient(from, RPL_NOTOPIC_MSG,
        !           519:                                                  Client_ID(from),
        !           520:                                                  Channel_Name(chan));
        !           521:        }
        !           522:
        !           523:        if (Channel_HasMode(chan, 't')) {
        !           524:                /* Topic Lock. Is the user a channel op or IRC operator? */
        !           525:                if(!topic_power &&
        !           526:                   !Channel_UserHasMode(chan, from, 'h') &&
        !           527:                   !Channel_UserHasMode(chan, from, 'o') &&
        !           528:                   !Channel_UserHasMode(chan, from, 'a') &&
        !           529:                   !Channel_UserHasMode(chan, from, 'q'))
        !           530:                        return IRC_WriteErrClient(from, ERR_CHANOPRIVSNEEDED_MSG,
        !           531:                                                  Client_ID(from),
        !           532:                                                  Channel_Name(chan));
        !           533:        }
        !           534:
        !           535:        LogDebug("%s \"%s\" set topic on \"%s\": %s",
        !           536:                 Client_TypeText(from), Client_Mask(from), Channel_Name(chan),
        !           537:                 Req->argv[1][0] ? Req->argv[1] : "<none>");
        !           538:
        !           539:        if (Conf_OperServerMode)
        !           540:                from = Client_ThisServer();
        !           541:
        !           542:        /* Update channel and forward new topic to other servers */
        !           543:        if (!Channel_IsLocal(chan))
        !           544:                IRC_WriteStrServersPrefix(Client, from, "TOPIC %s :%s",
        !           545:                                          Req->argv[0], Req->argv[1]);
        !           546:
        !           547:        /* Infrom local clients, but only when the topic really changed. */
        !           548:        if (strcmp(Req->argv[1], Channel_Topic(chan)) != 0)
        !           549:                IRC_WriteStrChannelPrefix(Client, chan, from, false,
        !           550:                                            "TOPIC %s :%s", Req->argv[0],
        !           551:                                            Req->argv[1]);
        !           552:
        !           553:        /* Update topic, setter, and timestamp. */
        !           554:        Channel_SetTopic(chan, from, Req->argv[1]);
        !           555:
        !           556:        /* Send confirmation when the local client is a user. */
        !           557:        if (Client_Type(Client) == CLIENT_USER)
        !           558:                return IRC_WriteStrClientPrefix(Client, Client, "TOPIC %s :%s",
        !           559:                                                Req->argv[0], Req->argv[1]);
        !           560:        else
        !           561:                return CONNECTED;
        !           562: } /* IRC_TOPIC */
        !           563:
        !           564: /**
        !           565:  * Handler for the IRC "LIST" command.
        !           566:  *
        !           567:  * @param Client The client from which this command has been received.
        !           568:  * @param Req Request structure with prefix and all parameters.
        !           569:  * @return CONNECTED or DISCONNECTED.
        !           570:  */
        !           571: GLOBAL bool
        !           572: IRC_LIST( CLIENT *Client, REQUEST *Req )
        !           573: {
        !           574:        char *pattern;
        !           575:        CHANNEL *chan;
        !           576:        CLIENT *from, *target;
        !           577:        int count = 0;
        !           578:
        !           579:        assert(Client != NULL);
        !           580:        assert(Req != NULL);
        !           581:
        !           582:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
        !           583:
        !           584:        if (Req->argc > 0)
        !           585:                pattern = strtok(Req->argv[0], ",");
        !           586:        else
        !           587:                pattern = "*";
        !           588:
        !           589:        if (Req->argc == 2) {
        !           590:                /* Forward to other server? */
        !           591:                target = Client_Search(Req->argv[1]);
        !           592:                if (! target || Client_Type(target) != CLIENT_SERVER)
        !           593:                        return IRC_WriteErrClient(from, ERR_NOSUCHSERVER_MSG,
        !           594:                                                  Client_ID(Client),
        !           595:                                                  Req->argv[1]);
        !           596:
        !           597:                if (target != Client_ThisServer()) {
        !           598:                        /* Target is indeed an other server, forward it! */
        !           599:                        return IRC_WriteStrClientPrefix(target, from,
        !           600:                                                        "LIST %s :%s",
        !           601:                                                        Req->argv[0],
        !           602:                                                        Req->argv[1]);
        !           603:                }
        !           604:        }
        !           605:
        !           606:        /* Send list head */
        !           607:        if (!IRC_WriteStrClient(from, RPL_LISTSTART_MSG, Client_ID(from)))
        !           608:                return DISCONNECTED;
        !           609:
        !           610:        while (pattern) {
        !           611:                /* Loop through all the channels */
        !           612:                if (Req->argc > 0)
        !           613:                        ngt_LowerStr(pattern);
        !           614:                chan = Channel_First();
        !           615:                while (chan) {
        !           616:                        /* Check search pattern */
        !           617:                        if (MatchCaseInsensitive(pattern, Channel_Name(chan))) {
        !           618:                                /* Gotcha! */
        !           619:                                if (!Channel_HasMode(chan, 's')
        !           620:                                    || Channel_IsMemberOf(chan, from)
        !           621:                                    || Client_HasMode(from, 'o'))
        !           622:                                {
        !           623:                                        if ((Conf_MaxListSize > 0)
        !           624:                                            && IRC_CheckListTooBig(from, count,
        !           625:                                                                   Conf_MaxListSize,
        !           626:                                                                   "LIST"))
        !           627:                                                break;
        !           628:                                        if (!IRC_WriteStrClient(from,
        !           629:                                             RPL_LIST_MSG, Client_ID(from),
        !           630:                                             Channel_Name(chan),
        !           631:                                             Channel_MemberCount(chan),
        !           632:                                             Channel_Topic( chan )))
        !           633:                                                return DISCONNECTED;
        !           634:                                        count++;
        !           635:                                }
        !           636:                        }
        !           637:                        chan = Channel_Next(chan);
        !           638:                }
        !           639:
        !           640:                /* Get next name ... */
        !           641:                if(Req->argc > 0)
        !           642:                        pattern = strtok(NULL, ",");
        !           643:                else
        !           644:                        pattern = NULL;
        !           645:        }
        !           646:
        !           647:        return IRC_WriteStrClient(from, RPL_LISTEND_MSG, Client_ID(from));
        !           648: } /* IRC_LIST */
        !           649:
        !           650: /**
        !           651:  * Handler for the IRC+ "CHANINFO" command.
        !           652:  *
        !           653:  * @param Client The client from which this command has been received.
        !           654:  * @param Req Request structure with prefix and all parameters.
        !           655:  * @return CONNECTED or DISCONNECTED.
        !           656:  */
        !           657: GLOBAL bool
        !           658: IRC_CHANINFO( CLIENT *Client, REQUEST *Req )
        !           659: {
        !           660:        char modes_add[COMMAND_LEN], l[16];
        !           661:        CLIENT *from;
        !           662:        CHANNEL *chan;
        !           663:        int arg_topic;
        !           664:
        !           665:        assert( Client != NULL );
        !           666:        assert( Req != NULL );
        !           667:
        !           668:        /* Bad number of parameters? */
        !           669:        if (Req->argc < 2 || Req->argc == 4 || Req->argc > 5)
        !           670:                return IRC_WriteErrClient(Client, ERR_NEEDMOREPARAMS_MSG,
        !           671:                                          Client_ID(Client), Req->command);
        !           672:
        !           673:        /* Compatibility kludge */
        !           674:        if (Req->argc == 5)
        !           675:                arg_topic = 4;
        !           676:        else if(Req->argc == 3)
        !           677:                arg_topic = 2;
        !           678:        else
        !           679:                arg_topic = -1;
        !           680:
        !           681:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
        !           682:
        !           683:        /* Search or create channel */
        !           684:        chan = Channel_Search( Req->argv[0] );
        !           685:        if (!chan)
        !           686:                chan = Channel_Create( Req->argv[0] );
        !           687:        if (!chan)
        !           688:                return CONNECTED;
        !           689:
        !           690:        if (Req->argv[1][0] == '+') {
        !           691:                if (!*Channel_Modes(chan)) {
        !           692:                        /* OK, this channel doesn't have modes yet,
        !           693:                         * set the received ones: */
        !           694:                        Channel_SetModes(chan, &Req->argv[1][1]);
        !           695:
        !           696:                        if(Req->argc == 5) {
        !           697:                                if(Channel_HasMode(chan, 'k'))
        !           698:                                        Channel_SetKey(chan, Req->argv[2]);
        !           699:                                if(Channel_HasMode(chan, 'l'))
        !           700:                                        Channel_SetMaxUsers(chan, atol(Req->argv[3]));
        !           701:                        } else {
        !           702:                                /* Delete modes which we never want to inherit */
        !           703:                                Channel_ModeDel(chan, 'l');
        !           704:                                Channel_ModeDel(chan, 'k');
        !           705:                        }
        !           706:
        !           707:                        strcpy(modes_add, "");
        !           708:                        if (Channel_HasMode(chan, 'l'))  {
        !           709:                                snprintf(l, sizeof(l), " %lu",
        !           710:                                         Channel_MaxUsers(chan));
        !           711:                                strlcat(modes_add, l, sizeof(modes_add));
        !           712:                        }
        !           713:                        if (Channel_HasMode(chan, 'k'))  {
        !           714:                                strlcat(modes_add, " ", sizeof(modes_add));
        !           715:                                strlcat(modes_add, Channel_Key(chan),
        !           716:                                        sizeof(modes_add));
        !           717:                        }
        !           718:
        !           719:                        /* Inform members of this channel */
        !           720:                        IRC_WriteStrChannelPrefix(Client, chan, from, false,
        !           721:                                                  "MODE %s +%s%s", Req->argv[0],
        !           722:                                                  Channel_Modes(chan), modes_add);
        !           723:                }
        !           724:        }
        !           725:        else
        !           726:                Log(LOG_WARNING, "CHANINFO: invalid MODE format ignored!");
        !           727:
        !           728:        if (arg_topic > 0) {
        !           729:                /* We got a topic */
        !           730:                if (!*Channel_Topic(chan) && Req->argv[arg_topic][0]) {
        !           731:                        /* OK, there is no topic jet */
        !           732:                        Channel_SetTopic(chan, Client, Req->argv[arg_topic]);
        !           733:                        IRC_WriteStrChannelPrefix(Client, chan, from, false,
        !           734:                             "TOPIC %s :%s", Req->argv[0], Channel_Topic(chan));
        !           735:                }
        !           736:        }
        !           737:
        !           738:        /* Forward CHANINFO to other servers */
        !           739:        if (Req->argc == 5)
        !           740:                IRC_WriteStrServersPrefixFlag(Client, from, 'C',
        !           741:                                              "CHANINFO %s %s %s %s :%s",
        !           742:                                              Req->argv[0], Req->argv[1],
        !           743:                                              Req->argv[2], Req->argv[3],
        !           744:                                              Req->argv[4]);
        !           745:        else if (Req->argc == 3)
        !           746:                IRC_WriteStrServersPrefixFlag(Client, from, 'C',
        !           747:                                              "CHANINFO %s %s :%s",
        !           748:                                              Req->argv[0], Req->argv[1],
        !           749:                                              Req->argv[2]);
        !           750:        else
        !           751:                IRC_WriteStrServersPrefixFlag(Client, from, 'C',
        !           752:                                              "CHANINFO %s %s",
        !           753:                                              Req->argv[0], Req->argv[1]);
        !           754:
        !           755:        return CONNECTED;
        !           756: } /* IRC_CHANINFO */
        !           757:
        !           758: /* -eof- */

CVSweb