[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

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