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

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

1.1     ! tomglok     1: /*
        !             2:  * ngIRCd -- The Next Generation IRC Daemon
        !             3:  * Copyright (c)2001-2014 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: #define __channel_c__
        !            13:
        !            14: #include "portab.h"
        !            15:
        !            16: /**
        !            17:  * @file
        !            18:  * Channel management
        !            19:  */
        !            20:
        !            21: #include <assert.h>
        !            22: #include <stdlib.h>
        !            23: #include <string.h>
        !            24: #include <errno.h>
        !            25: #include <stdio.h>
        !            26: #include <strings.h>
        !            27: #include <time.h>
        !            28:
        !            29: #include "conn-func.h"
        !            30:
        !            31: #include "channel.h"
        !            32:
        !            33: #include "irc-write.h"
        !            34: #include "conf.h"
        !            35: #include "hash.h"
        !            36: #include "log.h"
        !            37: #include "messages.h"
        !            38: #include "match.h"
        !            39: #include "parse.h"
        !            40: #include "irc-mode.h"
        !            41:
        !            42: #define REMOVE_PART 0
        !            43: #define REMOVE_QUIT 1
        !            44: #define REMOVE_KICK 2
        !            45:
        !            46: static CHANNEL *My_Channels;
        !            47: static CL2CHAN *My_Cl2Chan;
        !            48:
        !            49: static CL2CHAN *Get_Cl2Chan PARAMS(( CHANNEL *Chan, CLIENT *Client ));
        !            50: static CL2CHAN *Add_Client PARAMS(( CHANNEL *Chan, CLIENT *Client ));
        !            51: static bool Remove_Client PARAMS(( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer ));
        !            52: static CL2CHAN *Get_First_Cl2Chan PARAMS(( CLIENT *Client, CHANNEL *Chan ));
        !            53: static CL2CHAN *Get_Next_Cl2Chan PARAMS(( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan ));
        !            54: static void Delete_Channel PARAMS(( CHANNEL *Chan ));
        !            55: static void Free_Channel PARAMS(( CHANNEL *Chan ));
        !            56: static void Set_KeyFile PARAMS((CHANNEL *Chan, const char *KeyFile));
        !            57:
        !            58:
        !            59: GLOBAL void
        !            60: Channel_Init( void )
        !            61: {
        !            62:        My_Channels = NULL;
        !            63:        My_Cl2Chan = NULL;
        !            64: } /* Channel_Init */
        !            65:
        !            66:
        !            67: GLOBAL struct list_head *
        !            68: Channel_GetListBans(CHANNEL *c)
        !            69: {
        !            70:        assert(c != NULL);
        !            71:        return &c->list_bans;
        !            72: }
        !            73:
        !            74:
        !            75: GLOBAL struct list_head *
        !            76: Channel_GetListExcepts(CHANNEL *c)
        !            77: {
        !            78:        assert(c != NULL);
        !            79:        return &c->list_excepts;
        !            80: }
        !            81:
        !            82:
        !            83: GLOBAL struct list_head *
        !            84: Channel_GetListInvites(CHANNEL *c)
        !            85: {
        !            86:        assert(c != NULL);
        !            87:        return &c->list_invites;
        !            88: }
        !            89:
        !            90:
        !            91: /**
        !            92:  * Generate predefined persistent channels and &SERVER
        !            93:  */
        !            94: GLOBAL void
        !            95: Channel_InitPredefined( void )
        !            96: {
        !            97:        CHANNEL *new_chan;
        !            98:        REQUEST Req;
        !            99:        const struct Conf_Channel *conf_chan;
        !           100:        char *c;
        !           101:        char modes[COMMAND_LEN], name[CHANNEL_NAME_LEN];
        !           102:        size_t i, n, channel_count = array_length(&Conf_Channels, sizeof(*conf_chan));
        !           103:
        !           104:        conf_chan = array_start(&Conf_Channels);
        !           105:
        !           106:        assert(channel_count == 0 || conf_chan != NULL);
        !           107:
        !           108:        for (i = 0; i < channel_count; i++, conf_chan++) {
        !           109:                if (!conf_chan->name[0])
        !           110:                        continue;
        !           111:                if (!Channel_IsValidName(conf_chan->name)) {
        !           112:                        Log(LOG_ERR,
        !           113:                            "Can't create pre-defined channel: invalid name: \"%s\"",
        !           114:                            conf_chan->name);
        !           115:                        continue;
        !           116:                }
        !           117:
        !           118:                new_chan = Channel_Search(conf_chan->name);
        !           119:                if (new_chan) {
        !           120:                        Log(LOG_INFO,
        !           121:                            "Can't create pre-defined channel \"%s\": name already in use.",
        !           122:                            conf_chan->name);
        !           123:                        Set_KeyFile(new_chan, conf_chan->keyfile);
        !           124:                        continue;
        !           125:                }
        !           126:
        !           127:                new_chan = Channel_Create(conf_chan->name);
        !           128:                if (!new_chan) {
        !           129:                        Log(LOG_ERR, "Can't create pre-defined channel \"%s\"!",
        !           130:                                                        conf_chan->name);
        !           131:                        continue;
        !           132:                }
        !           133:                Channel_ModeAdd(new_chan, 'P');
        !           134:
        !           135:                if (conf_chan->topic[0])
        !           136:                        Channel_SetTopic(new_chan, NULL, conf_chan->topic);
        !           137:
        !           138:                /* Evaluate modes strings with fake requests */
        !           139:                if (conf_chan->modes_num) {
        !           140:                        /* Prepare fake request structure */
        !           141:                        strlcpy(name, conf_chan->name, sizeof(name));
        !           142:                        Log(LOG_INFO, "Evaluating predefined channel modes for \"%s\".", name);
        !           143:                        Req.argv[0] = name;
        !           144:                        Req.prefix = Client_ID(Client_ThisServer());
        !           145:                        Req.command = "MODE";
        !           146:
        !           147:                        /* Iterate over channel modes strings */
        !           148:                        for (n = 0; n < conf_chan->modes_num; n++) {
        !           149:                                Req.argc = 1;
        !           150:                                strlcpy(modes, conf_chan->modes[n], sizeof(modes));
        !           151:                                Log(LOG_DEBUG, "Evaluate \"MODE %s %s\".", name, modes);
        !           152:                                c = strtok(modes, " ");
        !           153:                                while (c && Req.argc < 15) {
        !           154:                                        Req.argv[Req.argc++] = c;
        !           155:                                        c = strtok(0, " ");
        !           156:                                }
        !           157:
        !           158:                                if (Req.argc > 1) {
        !           159:                                        /* Handling of legacy "Key" and "MaxUsers" settings:
        !           160:                                         * Enforce setting the respective mode(s), to support
        !           161:                                         * the legacy "Mode = kl" notation, which was valid but
        !           162:                                         * is an invalid MODE string: key and limit are missing!
        !           163:                                         * So set them manually when "k" or "l" are detected in
        !           164:                                         * the first MODE parameter ... */
        !           165:                                        if (Req.argc > 1 && strchr(Req.argv[1], 'k')) {
        !           166:                                                Channel_SetKey(new_chan, conf_chan->key);
        !           167:                                                Channel_ModeAdd(new_chan, 'k');
        !           168:                                        }
        !           169:                                        if (strchr(Req.argv[1], 'l')) {
        !           170:                                                Channel_SetMaxUsers(new_chan, conf_chan->maxusers);
        !           171:                                                Channel_ModeAdd(new_chan, 'l');
        !           172:                                        }
        !           173:
        !           174:                                        IRC_MODE(Client_ThisServer(), &Req);
        !           175:                                }
        !           176:
        !           177:                                /* Original channel modes srings are no longer needed */
        !           178:                                free(conf_chan->modes[n]);
        !           179:                        }
        !           180:                }
        !           181:
        !           182:                Set_KeyFile(new_chan, conf_chan->keyfile);
        !           183:
        !           184:                Log(LOG_INFO,
        !           185:                    "Created pre-defined channel \"%s\", mode \"%s\" (key \"%s\", limit %d).",
        !           186:                    new_chan->name, new_chan->modes, new_chan->key,
        !           187:                    new_chan->maxusers);
        !           188:        }
        !           189:        if (channel_count)
        !           190:                array_free(&Conf_Channels);
        !           191:
        !           192:        /* Make sure the local &SERVER channel exists */
        !           193:        if (!Channel_Search("&SERVER")) {
        !           194:                new_chan = Channel_Create("&SERVER");
        !           195:                if (new_chan) {
        !           196:                        Channel_SetModes(new_chan, "mnPt");
        !           197:                        Channel_SetTopic(new_chan, Client_ThisServer(),
        !           198:                                         "Server Messages");
        !           199:                } else
        !           200:                        Log(LOG_ERR, "Failed to create \"&SERVER\" channel!");
        !           201:        } else
        !           202:                LogDebug("Required channel \"&SERVER\" already exists, ok.");
        !           203: } /* Channel_InitPredefined */
        !           204:
        !           205:
        !           206: static void
        !           207: Free_Channel(CHANNEL *chan)
        !           208: {
        !           209:        array_free(&chan->topic);
        !           210:        array_free(&chan->keyfile);
        !           211:        Lists_Free(&chan->list_bans);
        !           212:        Lists_Free(&chan->list_excepts);
        !           213:        Lists_Free(&chan->list_invites);
        !           214:
        !           215:        free(chan);
        !           216: }
        !           217:
        !           218:
        !           219: GLOBAL void
        !           220: Channel_Exit( void )
        !           221: {
        !           222:        CHANNEL *c, *c_next;
        !           223:        CL2CHAN *cl2chan, *cl2chan_next;
        !           224:
        !           225:        /* free struct Channel */
        !           226:        c = My_Channels;
        !           227:        while (c) {
        !           228:                c_next = c->next;
        !           229:                Free_Channel(c);
        !           230:                c = c_next;
        !           231:        }
        !           232:
        !           233:        /* Free Channel allocation table */
        !           234:        cl2chan = My_Cl2Chan;
        !           235:        while (cl2chan) {
        !           236:                cl2chan_next = cl2chan->next;
        !           237:                free(cl2chan);
        !           238:                cl2chan = cl2chan_next;
        !           239:        }
        !           240: } /* Channel_Exit */
        !           241:
        !           242:
        !           243: /**
        !           244:  * Join Channel
        !           245:  * This function lets a client join a channel.  First, the function
        !           246:  * checks that the specified channel name is valid and that the client
        !           247:  * isn't already a member.  If the specified channel doesn't exist,
        !           248:  * a new channel is created.  Client is added to channel by function
        !           249:  * Add_Client().
        !           250:  */
        !           251: GLOBAL bool
        !           252: Channel_Join( CLIENT *Client, const char *Name )
        !           253: {
        !           254:        CHANNEL *chan;
        !           255:
        !           256:        assert(Client != NULL);
        !           257:        assert(Name != NULL);
        !           258:
        !           259:        /* Check that the channel name is valid */
        !           260:        if (! Channel_IsValidName(Name)) {
        !           261:                IRC_WriteErrClient(Client, ERR_NOSUCHCHANNEL_MSG,
        !           262:                                   Client_ID(Client), Name);
        !           263:                return false;
        !           264:        }
        !           265:
        !           266:        chan = Channel_Search(Name);
        !           267:        if(chan) {
        !           268:                /* Check if the client is already in the channel */
        !           269:                if (Get_Cl2Chan(chan, Client))
        !           270:                        return false;
        !           271:        } else {
        !           272:                /* If the specified channel does not exist, the channel
        !           273:                 * is now created */
        !           274:                chan = Channel_Create(Name);
        !           275:                if (!chan)
        !           276:                        return false;
        !           277:        }
        !           278:
        !           279:        /* Add user to Channel */
        !           280:        if (! Add_Client(chan, Client))
        !           281:                return false;
        !           282:
        !           283:        return true;
        !           284: } /* Channel_Join */
        !           285:
        !           286:
        !           287: /**
        !           288:  * Part client from channel.
        !           289:  * This function lets a client part from a channel. First, the function checks
        !           290:  * if the channel exists and the client is a member of it and sends out
        !           291:  * appropriate error messages if not. The real work is done by the function
        !           292:  * Remove_Client().
        !           293:  */
        !           294: GLOBAL bool
        !           295: Channel_Part(CLIENT * Client, CLIENT * Origin, const char *Name, const char *Reason)
        !           296: {
        !           297:        CHANNEL *chan;
        !           298:
        !           299:        assert(Client != NULL);
        !           300:        assert(Name != NULL);
        !           301:        assert(Reason != NULL);
        !           302:
        !           303:        /* Check that specified channel exists */
        !           304:        chan = Channel_Search(Name);
        !           305:        if (!chan) {
        !           306:                IRC_WriteErrClient(Client, ERR_NOSUCHCHANNEL_MSG,
        !           307:                                   Client_ID(Client), Name);
        !           308:                return false;
        !           309:        }
        !           310:
        !           311:        /* Check that the client is in the channel */
        !           312:        if (!Get_Cl2Chan(chan, Client)) {
        !           313:                IRC_WriteErrClient(Client, ERR_NOTONCHANNEL_MSG,
        !           314:                                   Client_ID(Client), Name);
        !           315:                return false;
        !           316:        }
        !           317:
        !           318:        if (Conf_MorePrivacy)
        !           319:                Reason = "";
        !           320:
        !           321:        /* Part client from channel */
        !           322:        if (!Remove_Client(REMOVE_PART, chan, Client, Origin, Reason, true))
        !           323:                return false;
        !           324:        else
        !           325:                return true;
        !           326: } /* Channel_Part */
        !           327:
        !           328:
        !           329: /**
        !           330:  * Kick user from Channel
        !           331:  */
        !           332: GLOBAL void
        !           333: Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name,
        !           334:             const char *Reason )
        !           335: {
        !           336:        CHANNEL *chan;
        !           337:        bool can_kick = false;
        !           338:
        !           339:        assert(Peer != NULL);
        !           340:        assert(Target != NULL);
        !           341:        assert(Origin != NULL);
        !           342:        assert(Name != NULL);
        !           343:        assert(Reason != NULL);
        !           344:
        !           345:        /* Check that channel exists */
        !           346:        chan = Channel_Search( Name );
        !           347:        if (!chan) {
        !           348:                IRC_WriteErrClient(Origin, ERR_NOSUCHCHANNEL_MSG,
        !           349:                                   Client_ID(Origin), Name);
        !           350:                return;
        !           351:        }
        !           352:
        !           353:        if (Client_Type(Peer) != CLIENT_SERVER &&
        !           354:            Client_Type(Origin) != CLIENT_SERVICE) {
        !           355:                /* Check that user is on the specified channel */
        !           356:                if (!Channel_IsMemberOf(chan, Origin)) {
        !           357:                        IRC_WriteErrClient(Origin, ERR_NOTONCHANNEL_MSG,
        !           358:                                           Client_ID(Origin), Name);
        !           359:                        return;
        !           360:                }
        !           361:        }
        !           362:
        !           363:        /* Check that the client to be kicked is on the specified channel */
        !           364:        if (!Channel_IsMemberOf(chan, Target)) {
        !           365:                IRC_WriteErrClient(Origin, ERR_USERNOTINCHANNEL_MSG,
        !           366:                                   Client_ID(Origin), Client_ID(Target), Name );
        !           367:                return;
        !           368:        }
        !           369:
        !           370:        if(Client_Type(Peer) == CLIENT_USER) {
        !           371:                /* Channel mode 'Q' and user mode 'q' on target: nobody but
        !           372:                 * IRC Operators and servers can kick the target user */
        !           373:                if ((Channel_HasMode(chan, 'Q')
        !           374:                     || Client_HasMode(Target, 'q')
        !           375:                     || Client_Type(Target) == CLIENT_SERVICE)
        !           376:                    && !Client_HasMode(Origin, 'o')) {
        !           377:                        IRC_WriteErrClient(Origin, ERR_KICKDENY_MSG,
        !           378:                                           Client_ID(Origin), Name,
        !           379:                                           Client_ID(Target));
        !           380:                        return;
        !           381:                }
        !           382:
        !           383:                /* Check if client has the rights to kick target */
        !           384:
        !           385:                /* Owner can kick everyone */
        !           386:                if (Channel_UserHasMode(chan, Peer, 'q'))
        !           387:                        can_kick = true;
        !           388:
        !           389:                /* Admin can't kick owner */
        !           390:                else if (Channel_UserHasMode(chan, Peer, 'a') &&
        !           391:                    !Channel_UserHasMode(chan, Target, 'q'))
        !           392:                        can_kick = true;
        !           393:
        !           394:                /* Op can't kick owner | admin */
        !           395:                else if (Channel_UserHasMode(chan, Peer, 'o') &&
        !           396:                    !Channel_UserHasMode(chan, Target, 'q') &&
        !           397:                    !Channel_UserHasMode(chan, Target, 'a'))
        !           398:                        can_kick = true;
        !           399:
        !           400:                /* Half Op can't kick owner | admin | op */
        !           401:                else if (Channel_UserHasMode(chan, Peer, 'h') &&
        !           402:                    !Channel_UserHasMode(chan, Target, 'q') &&
        !           403:                    !Channel_UserHasMode(chan, Target, 'a') &&
        !           404:                    !Channel_UserHasMode(chan, Target, 'o'))
        !           405:                        can_kick = true;
        !           406:
        !           407:                /* IRC operators & IRCd with OperCanMode enabled
        !           408:                 * can kick anyways regardless of privilege */
        !           409:                else if(Client_HasMode(Origin, 'o') && Conf_OperCanMode)
        !           410:                    can_kick = true;
        !           411:
        !           412:                if(!can_kick) {
        !           413:                        IRC_WriteErrClient(Origin, ERR_CHANOPPRIVTOOLOW_MSG,
        !           414:                                           Client_ID(Origin), Name);
        !           415:                        return;
        !           416:                }
        !           417:        }
        !           418:
        !           419:        /* Kick Client from channel */
        !           420:        Remove_Client( REMOVE_KICK, chan, Target, Origin, Reason, true);
        !           421: } /* Channel_Kick */
        !           422:
        !           423:
        !           424: GLOBAL void
        !           425: Channel_Quit( CLIENT *Client, const char *Reason )
        !           426: {
        !           427:        CHANNEL *c, *next_c;
        !           428:
        !           429:        assert( Client != NULL );
        !           430:        assert( Reason != NULL );
        !           431:
        !           432:        if (Conf_MorePrivacy)
        !           433:                Reason = "";
        !           434:
        !           435:        IRC_WriteStrRelatedPrefix( Client, Client, false, "QUIT :%s", Reason );
        !           436:
        !           437:        c = My_Channels;
        !           438:        while( c )
        !           439:        {
        !           440:                next_c = c->next;
        !           441:                Remove_Client( REMOVE_QUIT, c, Client, Client, Reason, false );
        !           442:                c = next_c;
        !           443:        }
        !           444: } /* Channel_Quit */
        !           445:
        !           446:
        !           447: /**
        !           448:  * Get number of channels this server knows and that are "visible" to
        !           449:  * the given client. If no client is given, all channels will be counted.
        !           450:  *
        !           451:  * @param Client The client to check or NULL.
        !           452:  * @return Number of channels visible to the client.
        !           453:  */
        !           454: GLOBAL unsigned long
        !           455: Channel_CountVisible (CLIENT *Client)
        !           456: {
        !           457:        CHANNEL *c;
        !           458:        unsigned long count = 0;
        !           459:
        !           460:        c = My_Channels;
        !           461:        while(c) {
        !           462:                if (Client) {
        !           463:                        if (!Channel_HasMode(c, 's')
        !           464:                            || Channel_IsMemberOf(c, Client))
        !           465:                                count++;
        !           466:                } else
        !           467:                        count++;
        !           468:                c = c->next;
        !           469:        }
        !           470:        return count;
        !           471: }
        !           472:
        !           473:
        !           474: GLOBAL unsigned long
        !           475: Channel_MemberCount( CHANNEL *Chan )
        !           476: {
        !           477:        CL2CHAN *cl2chan;
        !           478:        unsigned long count = 0;
        !           479:
        !           480:        assert( Chan != NULL );
        !           481:
        !           482:        cl2chan = My_Cl2Chan;
        !           483:        while( cl2chan )
        !           484:        {
        !           485:                if( cl2chan->channel == Chan ) count++;
        !           486:                cl2chan = cl2chan->next;
        !           487:        }
        !           488:        return count;
        !           489: } /* Channel_MemberCount */
        !           490:
        !           491:
        !           492: GLOBAL int
        !           493: Channel_CountForUser( CLIENT *Client )
        !           494: {
        !           495:        /* Count number of channels a user is member of. */
        !           496:
        !           497:        CL2CHAN *cl2chan;
        !           498:        int count = 0;
        !           499:
        !           500:        assert( Client != NULL );
        !           501:
        !           502:        cl2chan = My_Cl2Chan;
        !           503:        while( cl2chan )
        !           504:        {
        !           505:                if( cl2chan->client == Client ) count++;
        !           506:                cl2chan = cl2chan->next;
        !           507:        }
        !           508:
        !           509:        return count;
        !           510: } /* Channel_CountForUser */
        !           511:
        !           512:
        !           513: GLOBAL const char *
        !           514: Channel_Name( const CHANNEL *Chan )
        !           515: {
        !           516:        assert( Chan != NULL );
        !           517:        return Chan->name;
        !           518: } /* Channel_Name */
        !           519:
        !           520:
        !           521: GLOBAL char *
        !           522: Channel_Modes( CHANNEL *Chan )
        !           523: {
        !           524:        assert( Chan != NULL );
        !           525:        return Chan->modes;
        !           526: } /* Channel_Modes */
        !           527:
        !           528:
        !           529: GLOBAL bool
        !           530: Channel_HasMode( CHANNEL *Chan, char Mode )
        !           531: {
        !           532:        assert( Chan != NULL );
        !           533:        return strchr( Chan->modes, Mode ) != NULL;
        !           534: } /* Channel_HasMode */
        !           535:
        !           536:
        !           537: GLOBAL char *
        !           538: Channel_Key( CHANNEL *Chan )
        !           539: {
        !           540:        assert( Chan != NULL );
        !           541:        return Chan->key;
        !           542: } /* Channel_Key */
        !           543:
        !           544:
        !           545: GLOBAL unsigned long
        !           546: Channel_MaxUsers( CHANNEL *Chan )
        !           547: {
        !           548:        assert( Chan != NULL );
        !           549:        return Chan->maxusers;
        !           550: } /* Channel_MaxUsers */
        !           551:
        !           552:
        !           553: GLOBAL CHANNEL *
        !           554: Channel_First( void )
        !           555: {
        !           556:        return My_Channels;
        !           557: } /* Channel_First */
        !           558:
        !           559:
        !           560: GLOBAL CHANNEL *
        !           561: Channel_Next( CHANNEL *Chan )
        !           562: {
        !           563:        assert( Chan != NULL );
        !           564:        return Chan->next;
        !           565: } /* Channel_Next */
        !           566:
        !           567:
        !           568: GLOBAL CHANNEL *
        !           569: Channel_Search( const char *Name )
        !           570: {
        !           571:        /* Search channel structure */
        !           572:
        !           573:        CHANNEL *c;
        !           574:        UINT32 search_hash;
        !           575:
        !           576:        assert( Name != NULL );
        !           577:
        !           578:        search_hash = Hash( Name );
        !           579:        c = My_Channels;
        !           580:        while( c )
        !           581:        {
        !           582:                if( search_hash == c->hash )
        !           583:                {
        !           584:                        /* hash hit */
        !           585:                        if( strcasecmp( Name, c->name ) == 0 ) return c;
        !           586:                }
        !           587:                c = c->next;
        !           588:        }
        !           589:        return NULL;
        !           590: } /* Channel_Search */
        !           591:
        !           592:
        !           593: GLOBAL CL2CHAN *
        !           594: Channel_FirstMember( CHANNEL *Chan )
        !           595: {
        !           596:        assert( Chan != NULL );
        !           597:        return Get_First_Cl2Chan( NULL, Chan );
        !           598: } /* Channel_FirstMember */
        !           599:
        !           600:
        !           601: GLOBAL CL2CHAN *
        !           602: Channel_NextMember( CHANNEL *Chan, CL2CHAN *Cl2Chan )
        !           603: {
        !           604:        assert( Chan != NULL );
        !           605:        assert( Cl2Chan != NULL );
        !           606:        return Get_Next_Cl2Chan( Cl2Chan->next, NULL, Chan );
        !           607: } /* Channel_NextMember */
        !           608:
        !           609:
        !           610: GLOBAL CL2CHAN *
        !           611: Channel_FirstChannelOf( CLIENT *Client )
        !           612: {
        !           613:        assert( Client != NULL );
        !           614:        return Get_First_Cl2Chan( Client, NULL );
        !           615: } /* Channel_FirstChannelOf */
        !           616:
        !           617:
        !           618: GLOBAL CL2CHAN *
        !           619: Channel_NextChannelOf( CLIENT *Client, CL2CHAN *Cl2Chan )
        !           620: {
        !           621:        assert( Client != NULL );
        !           622:        assert( Cl2Chan != NULL );
        !           623:        return Get_Next_Cl2Chan( Cl2Chan->next, Client, NULL );
        !           624: } /* Channel_NextChannelOf */
        !           625:
        !           626:
        !           627: GLOBAL CLIENT *
        !           628: Channel_GetClient( CL2CHAN *Cl2Chan )
        !           629: {
        !           630:        assert( Cl2Chan != NULL );
        !           631:        return Cl2Chan->client;
        !           632: } /* Channel_GetClient */
        !           633:
        !           634:
        !           635: GLOBAL CHANNEL *
        !           636: Channel_GetChannel( CL2CHAN *Cl2Chan )
        !           637: {
        !           638:        assert( Cl2Chan != NULL );
        !           639:        return Cl2Chan->channel;
        !           640: } /* Channel_GetChannel */
        !           641:
        !           642:
        !           643: GLOBAL bool
        !           644: Channel_IsValidName( const char *Name )
        !           645: {
        !           646:        assert( Name != NULL );
        !           647:
        !           648: #ifdef STRICT_RFC
        !           649:        if (strlen(Name) <= 1)
        !           650:                return false;
        !           651: #endif
        !           652:        if (strchr("#&+", Name[0]) == NULL)
        !           653:                return false;
        !           654:        if (strlen(Name) >= CHANNEL_NAME_LEN)
        !           655:                return false;
        !           656:
        !           657:        return Name[strcspn(Name, " ,:\007")] == 0;
        !           658: } /* Channel_IsValidName */
        !           659:
        !           660:
        !           661: GLOBAL bool
        !           662: Channel_ModeAdd( CHANNEL *Chan, char Mode )
        !           663: {
        !           664:        /* set Mode.
        !           665:         * If the channel already had this mode, return false.
        !           666:         * If the channel mode was newly set return true.
        !           667:         */
        !           668:
        !           669:        char x[2];
        !           670:
        !           671:        assert( Chan != NULL );
        !           672:
        !           673:        x[0] = Mode; x[1] = '\0';
        !           674:        if( ! Channel_HasMode( Chan, x[0] ))
        !           675:        {
        !           676:                /* Channel does not have this mode yet, set it */
        !           677:                strlcat( Chan->modes, x, sizeof( Chan->modes ));
        !           678:                return true;
        !           679:        }
        !           680:        else return false;
        !           681: } /* Channel_ModeAdd */
        !           682:
        !           683:
        !           684: GLOBAL bool
        !           685: Channel_ModeDel( CHANNEL *Chan, char Mode )
        !           686: {
        !           687:        /* Delete mode.
        !           688:         * if the mode was removed return true.
        !           689:         * if the channel did not have the mode, return false.
        !           690:        */
        !           691:        char *p;
        !           692:
        !           693:        assert( Chan != NULL );
        !           694:
        !           695:        p = strchr( Chan->modes, Mode );
        !           696:        if( ! p ) return false;
        !           697:
        !           698:        /* Channel has mode -> delete */
        !           699:        while( *p )
        !           700:        {
        !           701:                *p = *(p + 1);
        !           702:                p++;
        !           703:        }
        !           704:        return true;
        !           705: } /* Channel_ModeDel */
        !           706:
        !           707:
        !           708: GLOBAL bool
        !           709: Channel_UserModeAdd( CHANNEL *Chan, CLIENT *Client, char Mode )
        !           710: {
        !           711:        /* Set Channel-User-Mode.
        !           712:         * if mode was newly set, return true.
        !           713:         * if the User already had this channel-mode, return false.
        !           714:         */
        !           715:
        !           716:        CL2CHAN *cl2chan;
        !           717:        char x[2];
        !           718:
        !           719:        assert( Chan != NULL );
        !           720:        assert( Client != NULL );
        !           721:
        !           722:        cl2chan = Get_Cl2Chan( Chan, Client );
        !           723:        assert( cl2chan != NULL );
        !           724:
        !           725:        x[0] = Mode; x[1] = '\0';
        !           726:        if( ! strchr( cl2chan->modes, x[0] ))
        !           727:        {
        !           728:                /* mode not set, -> set it */
        !           729:                strlcat( cl2chan->modes, x, sizeof( cl2chan->modes ));
        !           730:                return true;
        !           731:        }
        !           732:        else return false;
        !           733: } /* Channel_UserModeAdd */
        !           734:
        !           735:
        !           736: GLOBAL bool
        !           737: Channel_UserModeDel( CHANNEL *Chan, CLIENT *Client, char Mode )
        !           738: {
        !           739:        /* Delete Channel-User-Mode.
        !           740:         * If Mode was removed, return true.
        !           741:         * If User did not have the Channel-Mode, return false.
        !           742:         */
        !           743:
        !           744:        CL2CHAN *cl2chan;
        !           745:        char *p;
        !           746:
        !           747:        assert( Chan != NULL );
        !           748:        assert( Client != NULL );
        !           749:
        !           750:        cl2chan = Get_Cl2Chan( Chan, Client );
        !           751:        assert( cl2chan != NULL );
        !           752:
        !           753:        p = strchr( cl2chan->modes, Mode );
        !           754:        if( ! p ) return false;
        !           755:
        !           756:        /* Client has Mode -> delete */
        !           757:        while( *p )
        !           758:        {
        !           759:                *p = *(p + 1);
        !           760:                p++;
        !           761:        }
        !           762:        return true;
        !           763: } /* Channel_UserModeDel */
        !           764:
        !           765:
        !           766: GLOBAL char *
        !           767: Channel_UserModes( CHANNEL *Chan, CLIENT *Client )
        !           768: {
        !           769:        /* return Users' Channel-Modes */
        !           770:
        !           771:        CL2CHAN *cl2chan;
        !           772:
        !           773:        assert( Chan != NULL );
        !           774:        assert( Client != NULL );
        !           775:
        !           776:        cl2chan = Get_Cl2Chan( Chan, Client );
        !           777:        assert( cl2chan != NULL );
        !           778:
        !           779:        return cl2chan->modes;
        !           780: } /* Channel_UserModes */
        !           781:
        !           782:
        !           783: GLOBAL bool
        !           784: Channel_UserHasMode( CHANNEL *Chan, CLIENT *Client, char Mode )
        !           785: {
        !           786:        return strchr(Channel_UserModes(Chan, Client), Mode) != NULL;
        !           787: } /* Channel_UserHasMode */
        !           788:
        !           789:
        !           790: GLOBAL bool
        !           791: Channel_IsMemberOf( CHANNEL *Chan, CLIENT *Client )
        !           792: {
        !           793:        /* Test if Client is on Channel Chan */
        !           794:
        !           795:        assert( Chan != NULL );
        !           796:        assert( Client != NULL );
        !           797:        return Get_Cl2Chan(Chan, Client) != NULL;
        !           798: } /* Channel_IsMemberOf */
        !           799:
        !           800:
        !           801: GLOBAL char *
        !           802: Channel_Topic( CHANNEL *Chan )
        !           803: {
        !           804:        char *ret;
        !           805:        assert( Chan != NULL );
        !           806:        ret = array_start(&Chan->topic);
        !           807:        return ret ? ret : "";
        !           808: } /* Channel_Topic */
        !           809:
        !           810:
        !           811: #ifndef STRICT_RFC
        !           812:
        !           813: GLOBAL unsigned int
        !           814: Channel_TopicTime(CHANNEL *Chan)
        !           815: {
        !           816:        assert(Chan != NULL);
        !           817:        return (unsigned int) Chan->topic_time;
        !           818: } /* Channel_TopicTime */
        !           819:
        !           820:
        !           821: GLOBAL char *
        !           822: Channel_TopicWho(CHANNEL *Chan)
        !           823: {
        !           824:        assert(Chan != NULL);
        !           825:        return Chan->topic_who;
        !           826: } /* Channel_TopicWho */
        !           827:
        !           828:
        !           829: GLOBAL unsigned int
        !           830: Channel_CreationTime(CHANNEL *Chan)
        !           831: {
        !           832:        assert(Chan != NULL);
        !           833:        return (unsigned int) Chan->creation_time;
        !           834: } /* Channel_CreationTime */
        !           835:
        !           836: #endif
        !           837:
        !           838:
        !           839: GLOBAL void
        !           840: Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, const char *Topic)
        !           841: {
        !           842:        size_t len;
        !           843:        assert( Chan != NULL );
        !           844:        assert( Topic != NULL );
        !           845:
        !           846:        len = strlen(Topic);
        !           847:        if (len < array_bytes(&Chan->topic))
        !           848:                array_free(&Chan->topic);
        !           849:
        !           850:        if (len >= COMMAND_LEN || !array_copyb(&Chan->topic, Topic, len+1))
        !           851:                Log(LOG_WARNING, "could not set new Topic \"%s\" on %s: %s",
        !           852:                                        Topic, Chan->name, strerror(errno));
        !           853: #ifndef STRICT_RFC
        !           854:        Chan->topic_time = time(NULL);
        !           855:        if (Client != NULL && Client_Type(Client) != CLIENT_SERVER)
        !           856:                strlcpy(Chan->topic_who, Client_ID(Client),
        !           857:                        sizeof Chan->topic_who);
        !           858:        else
        !           859:                strlcpy(Chan->topic_who, DEFAULT_TOPIC_ID,
        !           860:                        sizeof Chan->topic_who);
        !           861: #else
        !           862:        (void) Client;
        !           863: #endif
        !           864: } /* Channel_SetTopic */
        !           865:
        !           866:
        !           867: GLOBAL void
        !           868: Channel_SetModes( CHANNEL *Chan, const char *Modes )
        !           869: {
        !           870:        assert( Chan != NULL );
        !           871:        assert( Modes != NULL );
        !           872:
        !           873:        strlcpy( Chan->modes, Modes, sizeof( Chan->modes ));
        !           874: } /* Channel_SetModes */
        !           875:
        !           876:
        !           877: GLOBAL void
        !           878: Channel_SetKey( CHANNEL *Chan, const char *Key )
        !           879: {
        !           880:        assert( Chan != NULL );
        !           881:        assert( Key != NULL );
        !           882:
        !           883:        strlcpy( Chan->key, Key, sizeof( Chan->key ));
        !           884:        LogDebug("Channel %s: Key is now \"%s\".", Chan->name, Chan->key );
        !           885: } /* Channel_SetKey */
        !           886:
        !           887:
        !           888: GLOBAL void
        !           889: Channel_SetMaxUsers(CHANNEL *Chan, unsigned long Count)
        !           890: {
        !           891:        assert( Chan != NULL );
        !           892:
        !           893:        Chan->maxusers = Count;
        !           894:        LogDebug("Channel %s: Member limit is now %lu.", Chan->name, Chan->maxusers );
        !           895: } /* Channel_SetMaxUsers */
        !           896:
        !           897:
        !           898: /**
        !           899:  * Check if a client is allowed to send to a specific channel.
        !           900:  *
        !           901:  * @param Chan The channel to check.
        !           902:  * @param From The client that wants to send.
        !           903:  * @return true if the client is allowed to send, false otherwise.
        !           904:  */
        !           905: static bool
        !           906: Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
        !           907: {
        !           908:        bool is_member, has_voice, is_halfop, is_op, is_chanadmin, is_owner;
        !           909:
        !           910:        is_member = has_voice = is_halfop = is_op = is_chanadmin = is_owner = false;
        !           911:
        !           912:        /* The server itself always can send messages :-) */
        !           913:        if (Client_ThisServer() == From)
        !           914:                return true;
        !           915:
        !           916:        if (Channel_IsMemberOf(Chan, From)) {
        !           917:                is_member = true;
        !           918:                if (Channel_UserHasMode(Chan, From, 'v'))
        !           919:                        has_voice = true;
        !           920:                if (Channel_UserHasMode(Chan, From, 'h'))
        !           921:                        is_halfop = true;
        !           922:                if (Channel_UserHasMode(Chan, From, 'o'))
        !           923:                        is_op = true;
        !           924:                if (Channel_UserHasMode(Chan, From, 'a'))
        !           925:                        is_chanadmin = true;
        !           926:                if (Channel_UserHasMode(Chan, From, 'q'))
        !           927:                        is_owner = true;
        !           928:        }
        !           929:
        !           930:        /*
        !           931:         * Is the client allowed to write to channel?
        !           932:         *
        !           933:         * If channel mode n set: non-members cannot send to channel.
        !           934:         * If channel mode m set: need voice.
        !           935:         */
        !           936:        if (Channel_HasMode(Chan, 'n') && !is_member)
        !           937:                return false;
        !           938:
        !           939:        if (Channel_HasMode(Chan, 'M') && !Client_HasMode(From, 'R')
        !           940:            && !Client_HasMode(From, 'o'))
        !           941:                return false;
        !           942:
        !           943:        if (has_voice || is_halfop || is_op || is_chanadmin || is_owner)
        !           944:                return true;
        !           945:
        !           946:        if (Channel_HasMode(Chan, 'm'))
        !           947:                return false;
        !           948:
        !           949:        if (Lists_Check(&Chan->list_excepts, From))
        !           950:                return true;
        !           951:
        !           952:        return !Lists_Check(&Chan->list_bans, From);
        !           953: }
        !           954:
        !           955:
        !           956: GLOBAL bool
        !           957: Channel_Write(CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Command,
        !           958:              bool SendErrors, const char *Text)
        !           959: {
        !           960:        if (!Can_Send_To_Channel(Chan, From)) {
        !           961:                if (! SendErrors)
        !           962:                        return CONNECTED;       /* no error, see RFC 2812 */
        !           963:                if (Channel_HasMode(Chan, 'M'))
        !           964:                        return IRC_WriteErrClient(From, ERR_NEEDREGGEDNICK_MSG,
        !           965:                                                  Client_ID(From), Channel_Name(Chan));
        !           966:                else
        !           967:                        return IRC_WriteErrClient(From, ERR_CANNOTSENDTOCHAN_MSG,
        !           968:                                          Client_ID(From), Channel_Name(Chan));
        !           969:        }
        !           970:
        !           971:        if (Client_Conn(From) > NONE)
        !           972:                Conn_UpdateIdle(Client_Conn(From));
        !           973:
        !           974:        IRC_WriteStrChannelPrefix(Client, Chan, From, true, "%s %s :%s",
        !           975:                                  Command, Channel_Name(Chan), Text);
        !           976:        return CONNECTED;
        !           977: }
        !           978:
        !           979:
        !           980: GLOBAL CHANNEL *
        !           981: Channel_Create( const char *Name )
        !           982: {
        !           983:        /* Create new CHANNEL structure and add it to linked list */
        !           984:        CHANNEL *c;
        !           985:
        !           986:        assert( Name != NULL );
        !           987:
        !           988:        c = (CHANNEL *)malloc( sizeof( CHANNEL ));
        !           989:        if( ! c )
        !           990:        {
        !           991:                Log( LOG_EMERG, "Can't allocate memory! [New_Chan]" );
        !           992:                return NULL;
        !           993:        }
        !           994:        memset( c, 0, sizeof( CHANNEL ));
        !           995:        strlcpy( c->name, Name, sizeof( c->name ));
        !           996:        c->hash = Hash( c->name );
        !           997:        c->next = My_Channels;
        !           998: #ifndef STRICT_RFC
        !           999:        c->creation_time = time(NULL);
        !          1000: #endif
        !          1001:        My_Channels = c;
        !          1002:        LogDebug("Created new channel structure for \"%s\".", Name);
        !          1003:        return c;
        !          1004: } /* Channel_Create */
        !          1005:
        !          1006:
        !          1007: static CL2CHAN *
        !          1008: Get_Cl2Chan( CHANNEL *Chan, CLIENT *Client )
        !          1009: {
        !          1010:        CL2CHAN *cl2chan;
        !          1011:
        !          1012:        assert( Chan != NULL );
        !          1013:        assert( Client != NULL );
        !          1014:
        !          1015:        cl2chan = My_Cl2Chan;
        !          1016:        while( cl2chan )
        !          1017:        {
        !          1018:                if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) return cl2chan;
        !          1019:                cl2chan = cl2chan->next;
        !          1020:        }
        !          1021:        return NULL;
        !          1022: } /* Get_Cl2Chan */
        !          1023:
        !          1024:
        !          1025: static CL2CHAN *
        !          1026: Add_Client( CHANNEL *Chan, CLIENT *Client )
        !          1027: {
        !          1028:        CL2CHAN *cl2chan;
        !          1029:
        !          1030:        assert( Chan != NULL );
        !          1031:        assert( Client != NULL );
        !          1032:
        !          1033:        /* Create new CL2CHAN structure */
        !          1034:        cl2chan = (CL2CHAN *)malloc( sizeof( CL2CHAN ));
        !          1035:        if( ! cl2chan )
        !          1036:        {
        !          1037:                Log( LOG_EMERG, "Can't allocate memory! [Add_Client]" );
        !          1038:                return NULL;
        !          1039:        }
        !          1040:        cl2chan->channel = Chan;
        !          1041:        cl2chan->client = Client;
        !          1042:        strcpy( cl2chan->modes, "" );
        !          1043:
        !          1044:        /* concatenate */
        !          1045:        cl2chan->next = My_Cl2Chan;
        !          1046:        My_Cl2Chan = cl2chan;
        !          1047:
        !          1048:        LogDebug("User \"%s\" joined channel \"%s\".", Client_Mask(Client), Chan->name);
        !          1049:
        !          1050:        return cl2chan;
        !          1051: } /* Add_Client */
        !          1052:
        !          1053:
        !          1054: static bool
        !          1055: Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer )
        !          1056: {
        !          1057:        CL2CHAN *cl2chan, *last_cl2chan;
        !          1058:        CHANNEL *c;
        !          1059:
        !          1060:        assert( Chan != NULL );
        !          1061:        assert( Client != NULL );
        !          1062:        assert( Origin != NULL );
        !          1063:        assert( Reason != NULL );
        !          1064:
        !          1065:        /* Do not inform other servers if the channel is local to this server,
        !          1066:         * regardless of what the caller requested! */
        !          1067:        if(InformServer)
        !          1068:                InformServer = !Channel_IsLocal(Chan);
        !          1069:
        !          1070:        last_cl2chan = NULL;
        !          1071:        cl2chan = My_Cl2Chan;
        !          1072:        while( cl2chan )
        !          1073:        {
        !          1074:                if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) break;
        !          1075:                last_cl2chan = cl2chan;
        !          1076:                cl2chan = cl2chan->next;
        !          1077:        }
        !          1078:        if( ! cl2chan ) return false;
        !          1079:
        !          1080:        c = cl2chan->channel;
        !          1081:        assert( c != NULL );
        !          1082:
        !          1083:        /* maintain cl2chan list */
        !          1084:        if( last_cl2chan ) last_cl2chan->next = cl2chan->next;
        !          1085:        else My_Cl2Chan = cl2chan->next;
        !          1086:        free( cl2chan );
        !          1087:
        !          1088:        switch( Type )
        !          1089:        {
        !          1090:                case REMOVE_QUIT:
        !          1091:                        /* QUIT: other servers have already been notified,
        !          1092:                         * see Client_Destroy(); so only inform other clients
        !          1093:                         * in same channel. */
        !          1094:                        assert( InformServer == false );
        !          1095:                        LogDebug("User \"%s\" left channel \"%s\" (%s).",
        !          1096:                                        Client_Mask( Client ), c->name, Reason );
        !          1097:                        break;
        !          1098:                case REMOVE_KICK:
        !          1099:                        /* User was KICKed: inform other servers (public
        !          1100:                         * channels) and all users in the channel */
        !          1101:                        if( InformServer )
        !          1102:                                IRC_WriteStrServersPrefix( Client_NextHop( Origin ),
        !          1103:                                        Origin, "KICK %s %s :%s", c->name, Client_ID( Client ), Reason);
        !          1104:                        IRC_WriteStrChannelPrefix(Client, c, Origin, false, "KICK %s %s :%s",
        !          1105:                                                        c->name, Client_ID( Client ), Reason );
        !          1106:                        if ((Client_Conn(Client) > NONE) &&
        !          1107:                                        (Client_Type(Client) == CLIENT_USER))
        !          1108:                        {
        !          1109:                                IRC_WriteStrClientPrefix(Client, Origin, "KICK %s %s :%s",
        !          1110:                                                                c->name, Client_ID( Client ), Reason);
        !          1111:                        }
        !          1112:                        LogDebug("User \"%s\" has been kicked off \"%s\" by \"%s\": %s.",
        !          1113:                                Client_Mask( Client ), c->name, Client_ID(Origin), Reason);
        !          1114:                        break;
        !          1115:                default: /* PART */
        !          1116:                        if (Conf_MorePrivacy)
        !          1117:                                Reason = "";
        !          1118:
        !          1119:                        if (InformServer)
        !          1120:                                IRC_WriteStrServersPrefix(Origin, Client, "PART %s :%s", c->name, Reason);
        !          1121:
        !          1122:                        IRC_WriteStrChannelPrefix(Origin, c, Client, false, "PART %s :%s",
        !          1123:                                                                        c->name, Reason);
        !          1124:
        !          1125:                        if ((Client_Conn(Origin) > NONE) &&
        !          1126:                                        (Client_Type(Origin) == CLIENT_USER))
        !          1127:                        {
        !          1128:                                IRC_WriteStrClientPrefix( Origin, Client, "PART %s :%s", c->name, Reason);
        !          1129:                                LogDebug("User \"%s\" left channel \"%s\" (%s).",
        !          1130:                                        Client_Mask(Client), c->name, Reason);
        !          1131:                        }
        !          1132:        }
        !          1133:
        !          1134:        /* When channel is empty and is not pre-defined, delete */
        !          1135:        if( ! Channel_HasMode( Chan, 'P' ))
        !          1136:        {
        !          1137:                if( ! Get_First_Cl2Chan( NULL, Chan )) Delete_Channel( Chan );
        !          1138:        }
        !          1139:
        !          1140:        return true;
        !          1141: } /* Remove_Client */
        !          1142:
        !          1143:
        !          1144: GLOBAL bool
        !          1145: Channel_AddBan(CHANNEL *c, const char *mask, const char *who )
        !          1146: {
        !          1147:        struct list_head *h = Channel_GetListBans(c);
        !          1148:        LogDebug("Adding \"%s\" to \"%s\" ban list", mask, Channel_Name(c));
        !          1149:        return Lists_Add(h, mask, time(NULL), who, false);
        !          1150: }
        !          1151:
        !          1152:
        !          1153: GLOBAL bool
        !          1154: Channel_AddExcept(CHANNEL *c, const char *mask, const char *who )
        !          1155: {
        !          1156:        struct list_head *h = Channel_GetListExcepts(c);
        !          1157:        LogDebug("Adding \"%s\" to \"%s\" exception list", mask, Channel_Name(c));
        !          1158:        return Lists_Add(h, mask, time(NULL), who, false);
        !          1159: }
        !          1160:
        !          1161:
        !          1162: GLOBAL bool
        !          1163: Channel_AddInvite(CHANNEL *c, const char *mask, bool onlyonce, const char *who )
        !          1164: {
        !          1165:        struct list_head *h = Channel_GetListInvites(c);
        !          1166:        LogDebug("Adding \"%s\" to \"%s\" invite list", mask, Channel_Name(c));
        !          1167:        return Lists_Add(h, mask, time(NULL), who, onlyonce);
        !          1168: }
        !          1169:
        !          1170:
        !          1171: static bool
        !          1172: ShowChannelList(struct list_head *head, CLIENT *Client, CHANNEL *Channel,
        !          1173:                char *msg, char *msg_end)
        !          1174: {
        !          1175:        struct list_elem *e;
        !          1176:
        !          1177:        assert (Client != NULL);
        !          1178:        assert (Channel != NULL);
        !          1179:
        !          1180:        e = Lists_GetFirst(head);
        !          1181:        while (e) {
        !          1182:                if (!IRC_WriteStrClient(Client, msg, Client_ID(Client),
        !          1183:                                        Channel_Name(Channel),
        !          1184:                                        Lists_GetMask(e),
        !          1185:                                        Lists_GetReason(e),
        !          1186:                                        Lists_GetValidity(e)))
        !          1187:                        return DISCONNECTED;
        !          1188:                e = Lists_GetNext(e);
        !          1189:        }
        !          1190:
        !          1191:        return IRC_WriteStrClient(Client, msg_end, Client_ID(Client),
        !          1192:                                  Channel_Name(Channel));
        !          1193: }
        !          1194:
        !          1195:
        !          1196: GLOBAL bool
        !          1197: Channel_ShowBans( CLIENT *Client, CHANNEL *Channel )
        !          1198: {
        !          1199:        struct list_head *h;
        !          1200:
        !          1201:        assert( Channel != NULL );
        !          1202:
        !          1203:        h = Channel_GetListBans(Channel);
        !          1204:        return ShowChannelList(h, Client, Channel, RPL_BANLIST_MSG,
        !          1205:                               RPL_ENDOFBANLIST_MSG);
        !          1206: }
        !          1207:
        !          1208:
        !          1209: GLOBAL bool
        !          1210: Channel_ShowExcepts( CLIENT *Client, CHANNEL *Channel )
        !          1211: {
        !          1212:        struct list_head *h;
        !          1213:
        !          1214:        assert( Channel != NULL );
        !          1215:
        !          1216:        h = Channel_GetListExcepts(Channel);
        !          1217:        return ShowChannelList(h, Client, Channel, RPL_EXCEPTLIST_MSG,
        !          1218:                               RPL_ENDOFEXCEPTLIST_MSG);
        !          1219: }
        !          1220:
        !          1221:
        !          1222: GLOBAL bool
        !          1223: Channel_ShowInvites( CLIENT *Client, CHANNEL *Channel )
        !          1224: {
        !          1225:        struct list_head *h;
        !          1226:
        !          1227:        assert( Channel != NULL );
        !          1228:
        !          1229:        h = Channel_GetListInvites(Channel);
        !          1230:        return ShowChannelList(h, Client, Channel, RPL_INVITELIST_MSG,
        !          1231:                               RPL_ENDOFINVITELIST_MSG);
        !          1232: }
        !          1233:
        !          1234:
        !          1235: /**
        !          1236:  * Log a message to the local &SERVER channel, if it exists.
        !          1237:  */
        !          1238: GLOBAL void
        !          1239: Channel_LogServer(const char *msg)
        !          1240: {
        !          1241:        CHANNEL *sc;
        !          1242:        CLIENT *c;
        !          1243:
        !          1244:        assert(msg != NULL);
        !          1245:
        !          1246:        sc = Channel_Search("&SERVER");
        !          1247:        if (!sc)
        !          1248:                return;
        !          1249:
        !          1250:        c = Client_ThisServer();
        !          1251:        Channel_Write(sc, c, c, "PRIVMSG", false, msg);
        !          1252: } /* Channel_LogServer */
        !          1253:
        !          1254:
        !          1255: GLOBAL bool
        !          1256: Channel_CheckKey(CHANNEL *Chan, CLIENT *Client, const char *Key)
        !          1257: {
        !          1258:        char *file_name, line[COMMAND_LEN], *nick, *pass;
        !          1259:        FILE *fd;
        !          1260:
        !          1261:        assert(Chan != NULL);
        !          1262:        assert(Client != NULL);
        !          1263:        assert(Key != NULL);
        !          1264:
        !          1265:        if (!Channel_HasMode(Chan, 'k'))
        !          1266:                return true;
        !          1267:        if (*Key == '\0')
        !          1268:                return false;
        !          1269:        if (strcmp(Chan->key, Key) == 0)
        !          1270:                return true;
        !          1271:
        !          1272:        file_name = array_start(&Chan->keyfile);
        !          1273:        if (!file_name)
        !          1274:                return false;
        !          1275:        fd = fopen(file_name, "r");
        !          1276:        if (!fd) {
        !          1277:                Log(LOG_ERR, "Can't open channel key file \"%s\" for %s: %s",
        !          1278:                    file_name, Chan->name, strerror(errno));
        !          1279:                return false;
        !          1280:        }
        !          1281:
        !          1282:        while (fgets(line, (int)sizeof(line), fd) != NULL) {
        !          1283:                ngt_TrimStr(line);
        !          1284:                if (! (nick = strchr(line, ':')))
        !          1285:                        continue;
        !          1286:                *nick++ = '\0';
        !          1287:                if (!Match(line, Client_User(Client)))
        !          1288:                        continue;
        !          1289:                if (! (pass = strchr(nick, ':')))
        !          1290:                        continue;
        !          1291:                *pass++ = '\0';
        !          1292:                if (!Match(nick, Client_ID(Client)))
        !          1293:                        continue;
        !          1294:                if (strcmp(Key, pass) != 0)
        !          1295:                        continue;
        !          1296:
        !          1297:                fclose(fd);
        !          1298:                return true;
        !          1299:        }
        !          1300:        fclose(fd);
        !          1301:        return false;
        !          1302: } /* Channel_CheckKey */
        !          1303:
        !          1304:
        !          1305: static CL2CHAN *
        !          1306: Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
        !          1307: {
        !          1308:        return Get_Next_Cl2Chan( My_Cl2Chan, Client, Chan );
        !          1309: } /* Get_First_Cl2Chan */
        !          1310:
        !          1311:
        !          1312: static CL2CHAN *
        !          1313: Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Channel )
        !          1314: {
        !          1315:        CL2CHAN *cl2chan;
        !          1316:
        !          1317:        assert( Client != NULL || Channel != NULL );
        !          1318:
        !          1319:        cl2chan = Start;
        !          1320:        while( cl2chan )
        !          1321:        {
        !          1322:                if(( Client ) && ( cl2chan->client == Client )) return cl2chan;
        !          1323:                if(( Channel ) && ( cl2chan->channel == Channel )) return cl2chan;
        !          1324:                cl2chan = cl2chan->next;
        !          1325:        }
        !          1326:        return NULL;
        !          1327: } /* Get_Next_Cl2Chan */
        !          1328:
        !          1329:
        !          1330: /**
        !          1331:  * Remove a channel and free all of its data structures.
        !          1332:  */
        !          1333: static void
        !          1334: Delete_Channel(CHANNEL *Chan)
        !          1335: {
        !          1336:        CHANNEL *chan, *last_chan;
        !          1337:
        !          1338:        last_chan = NULL;
        !          1339:        chan = My_Channels;
        !          1340:        while (chan) {
        !          1341:                if (chan == Chan)
        !          1342:                        break;
        !          1343:                last_chan = chan;
        !          1344:                chan = chan->next;
        !          1345:        }
        !          1346:
        !          1347:        assert(chan != NULL);
        !          1348:        if (!chan)
        !          1349:                return;
        !          1350:
        !          1351:        /* maintain channel list */
        !          1352:        if (last_chan)
        !          1353:                last_chan->next = chan->next;
        !          1354:        else
        !          1355:                My_Channels = chan->next;
        !          1356:
        !          1357:        LogDebug("Freed channel structure for \"%s\".", Chan->name);
        !          1358:        Free_Channel(Chan);
        !          1359: } /* Delete_Channel */
        !          1360:
        !          1361:
        !          1362: static void
        !          1363: Set_KeyFile(CHANNEL *Chan, const char *KeyFile)
        !          1364: {
        !          1365:        size_t len;
        !          1366:
        !          1367:        assert(Chan != NULL);
        !          1368:        assert(KeyFile != NULL);
        !          1369:
        !          1370:        len = strlen(KeyFile);
        !          1371:        if (len < array_bytes(&Chan->keyfile)) {
        !          1372:                Log(LOG_INFO, "Channel key file of %s removed.", Chan->name);
        !          1373:                array_free(&Chan->keyfile);
        !          1374:        }
        !          1375:
        !          1376:        if (len < 1)
        !          1377:                return;
        !          1378:
        !          1379:        if (!array_copyb(&Chan->keyfile, KeyFile, len+1))
        !          1380:                Log(LOG_WARNING,
        !          1381:                    "Could not set new channel key file \"%s\" for %s: %s",
        !          1382:                    KeyFile, Chan->name, strerror(errno));
        !          1383:        else
        !          1384:                Log(LOG_INFO|LOG_snotice,
        !          1385:                    "New local channel key file \"%s\" for %s activated.",
        !          1386:                    KeyFile, Chan->name);
        !          1387: } /* Set_KeyFile */
        !          1388:
        !          1389:
        !          1390: /* -eof- */

CVSweb