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

Annotation of ircnowd/src/ngircd/irc-mode.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: #include "portab.h"
        !            13:
        !            14: /**
        !            15:  * @file
        !            16:  * IRC commands for mode changes (like MODE, AWAY, etc.)
        !            17:  */
        !            18:
        !            19: #include <assert.h>
        !            20: #include <stdio.h>
        !            21: #include <stdlib.h>
        !            22: #include <string.h>
        !            23:
        !            24: #include "conn.h"
        !            25: #include "channel.h"
        !            26: #include "irc-macros.h"
        !            27: #include "irc-write.h"
        !            28: #include "lists.h"
        !            29: #include "log.h"
        !            30: #include "parse.h"
        !            31: #include "messages.h"
        !            32: #include "conf.h"
        !            33:
        !            34: #include "irc-mode.h"
        !            35:
        !            36: static bool Client_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin,
        !            37:                                CLIENT *Target));
        !            38: static bool Channel_Mode PARAMS((CLIENT *Client, REQUEST *Req, CLIENT *Origin,
        !            39:                                 CHANNEL *Channel));
        !            40:
        !            41: static bool Add_To_List PARAMS((char what, CLIENT *Prefix, CLIENT *Client,
        !            42:                                CHANNEL *Channel, const char *Pattern));
        !            43: static bool Del_From_List PARAMS((char what, CLIENT *Prefix, CLIENT *Client,
        !            44:                                  CHANNEL *Channel, const char *Pattern));
        !            45:
        !            46: static bool Send_ListChange PARAMS((const bool IsAdd, const char ModeChar,
        !            47:                                    CLIENT *Prefix, CLIENT *Client,
        !            48:                                    CHANNEL *Channel, const char *Mask));
        !            49:
        !            50: /**
        !            51:  * Handler for the IRC "MODE" command.
        !            52:  *
        !            53:  * This function detects whether user or channel modes should be modified
        !            54:  * and calls the appropriate sub-functions.
        !            55:  *
        !            56:  * @param Client The client from which this command has been received.
        !            57:  * @param Req Request structure with prefix and all parameters.
        !            58:  * @return CONNECTED or DISCONNECTED.
        !            59:  */
        !            60: GLOBAL bool
        !            61: IRC_MODE( CLIENT *Client, REQUEST *Req )
        !            62: {
        !            63:        CLIENT *cl, *origin;
        !            64:        CHANNEL *chan;
        !            65:
        !            66:        assert(Client != NULL);
        !            67:        assert(Req != NULL);
        !            68:
        !            69:        _IRC_GET_SENDER_OR_RETURN_(origin, Req, Client)
        !            70:
        !            71:        /* Test for "fake" MODE commands injected by this local instance,
        !            72:         * for example when handling the "DefaultUserModes" settings.
        !            73:         * This doesn't harm real commands, because prefixes of regular
        !            74:         * clients are checked in Validate_Prefix() and can't be faked. */
        !            75:        if (Req->prefix && Client_Search(Req->prefix) == Client_ThisServer())
        !            76:                Client = Client_Search(Req->prefix);
        !            77:
        !            78:        /* Channel or user mode? */
        !            79:        cl = NULL; chan = NULL;
        !            80:        if (Client_IsValidNick(Req->argv[0]))
        !            81:                cl = Client_Search(Req->argv[0]);
        !            82:        if (Channel_IsValidName(Req->argv[0]))
        !            83:                chan = Channel_Search(Req->argv[0]);
        !            84:
        !            85:        if (cl)
        !            86:                return Client_Mode(Client, Req, origin, cl);
        !            87:        if (chan)
        !            88:                return Channel_Mode(Client, Req, origin, chan);
        !            89:
        !            90:        /* No target found! */
        !            91:        return IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
        !            92:                        Client_ID(Client), Req->argv[0]);
        !            93: } /* IRC_MODE */
        !            94:
        !            95: /**
        !            96:  * Check if the "mode limit" for a client has been reached.
        !            97:  *
        !            98:  * This limit doesn't apply for servers or services!
        !            99:  *
        !           100:  * @param Client The client to check.
        !           101:  * @param Count The number of modes already handled.
        !           102:  * @return true if the limit has been reached.
        !           103:  */
        !           104: static bool
        !           105: Mode_Limit_Reached(CLIENT *Client, int Count)
        !           106: {
        !           107:        if (Client_Type(Client) == CLIENT_SERVER
        !           108:            || Client_Type(Client) == CLIENT_SERVICE)
        !           109:                return false;
        !           110:        if (Count < MAX_HNDL_MODES_ARG)
        !           111:                return false;
        !           112:        return true;
        !           113: }
        !           114:
        !           115: /**
        !           116:  * Handle client mode requests
        !           117:  *
        !           118:  * @param Client The client from which this command has been received.
        !           119:  * @param Req Request structure with prefix and all parameters.
        !           120:  * @param Origin The originator of the MODE command (prefix).
        !           121:  * @param Target The target (client) of this MODE command.
        !           122:  * @return CONNECTED or DISCONNECTED.
        !           123:  */
        !           124: static bool
        !           125: Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
        !           126: {
        !           127:        char the_modes[COMMAND_LEN], x[2], *mode_ptr;
        !           128:        bool ok, set;
        !           129:        bool send_RPL_HOSTHIDDEN_MSG = false;
        !           130:        int mode_arg;
        !           131:        size_t len;
        !           132:
        !           133:        /* Is the client allowed to request or change the modes? */
        !           134:        if (Client_Type(Client) == CLIENT_USER) {
        !           135:                /* Users are only allowed to manipulate their own modes! */
        !           136:                if (Target != Client)
        !           137:                        return IRC_WriteErrClient(Client,
        !           138:                                                  ERR_USERSDONTMATCH_MSG,
        !           139:                                                  Client_ID(Client));
        !           140:        }
        !           141:
        !           142:        /* Mode request: let's answer it :-) */
        !           143:        if (Req->argc == 1)
        !           144:                return IRC_WriteStrClient(Origin, RPL_UMODEIS_MSG,
        !           145:                                          Client_ID(Target),
        !           146:                                          Client_Modes(Target));
        !           147:
        !           148:        mode_arg = 1;
        !           149:        mode_ptr = Req->argv[mode_arg];
        !           150:
        !           151:        /* Initial state: set or unset modes? */
        !           152:        if (*mode_ptr == '+') {
        !           153:                set = true;
        !           154:                strcpy(the_modes, "+");
        !           155:        } else if (*mode_ptr == '-') {
        !           156:                set = false;
        !           157:                strcpy(the_modes, "-");
        !           158:        } else
        !           159:                return IRC_WriteErrClient(Origin, ERR_UMODEUNKNOWNFLAG_MSG,
        !           160:                                          Client_ID(Origin));
        !           161:
        !           162:        x[1] = '\0';
        !           163:        ok = CONNECTED;
        !           164:        while (mode_ptr) {
        !           165:                mode_ptr++;
        !           166:                if (!*mode_ptr) {
        !           167:                        /* Try next argument if there's any */
        !           168:                        mode_arg++;
        !           169:                        if (mode_arg < Req->argc)
        !           170:                                mode_ptr = Req->argv[mode_arg];
        !           171:                        else
        !           172:                                break;
        !           173:                }
        !           174:
        !           175:                switch(*mode_ptr) {
        !           176:                  case '+':
        !           177:                  case '-':
        !           178:                        if ((*mode_ptr == '+' && !set)
        !           179:                            || (*mode_ptr == '-' && set)) {
        !           180:                                /* Action modifier ("+"/"-") must be changed */
        !           181:                                len = strlen(the_modes) - 1;
        !           182:                                if (the_modes[len] == '+'
        !           183:                                    || the_modes[len] == '-') {
        !           184:                                        /* Last character in the "result
        !           185:                                         * string" was an "action", so just
        !           186:                                         * overwrite it with the new action */
        !           187:                                        the_modes[len] = *mode_ptr;
        !           188:                                } else {
        !           189:                                        /* Append new modifier character to
        !           190:                                         * the resulting mode string */
        !           191:                                        x[0] = *mode_ptr;
        !           192:                                        strlcat(the_modes, x,
        !           193:                                                sizeof(the_modes));
        !           194:                                }
        !           195:                                if (*mode_ptr == '+')
        !           196:                                        set = true;
        !           197:                                else
        !           198:                                        set = false;
        !           199:                        }
        !           200:                        continue;
        !           201:                }
        !           202:
        !           203:                /* Validate modes */
        !           204:                x[0] = '\0';
        !           205:                switch (*mode_ptr) {
        !           206:                case 'b': /* Block private msgs */
        !           207:                case 'C': /* Only messages from clients sharing a channel */
        !           208:                case 'i': /* Invisible */
        !           209:                case 'I': /* Hide channel list from WHOIS */
        !           210:                case 's': /* Server messages */
        !           211:                case 'w': /* Wallops messages */
        !           212:                        x[0] = *mode_ptr;
        !           213:                        break;
        !           214:                case 'a': /* Away */
        !           215:                        if (Client_Type(Client) == CLIENT_SERVER) {
        !           216:                                x[0] = 'a';
        !           217:                                Client_SetAway(Origin, DEFAULT_AWAY_MSG);
        !           218:                        } else
        !           219:                                ok = IRC_WriteErrClient(Origin,
        !           220:                                                        ERR_NOPRIVILEGES_MSG,
        !           221:                                                        Client_ID(Origin));
        !           222:                        break;
        !           223:                case 'B': /* Bot */
        !           224:                        if (Client_HasMode(Client, 'r'))
        !           225:                                ok = IRC_WriteErrClient(Origin,
        !           226:                                                        ERR_RESTRICTED_MSG,
        !           227:                                                        Client_ID(Origin));
        !           228:                        else
        !           229:                                x[0] = 'B';
        !           230:                        break;
        !           231:                case 'c': /* Receive connect notices */
        !           232:                case 'q': /* KICK-protected user */
        !           233:                case 'F': /* disable flood protection */
        !           234:                          /* (only settable by IRC operators!) */
        !           235:                        if (!set || Client_Type(Client) == CLIENT_SERVER
        !           236:                            || Client_HasMode(Origin, 'o'))
        !           237:                                x[0] = *mode_ptr;
        !           238:                        else
        !           239:                                ok = IRC_WriteErrClient(Origin,
        !           240:                                                        ERR_NOPRIVILEGES_MSG,
        !           241:                                                        Client_ID(Origin));
        !           242:                        break;
        !           243:                case 'o': /* IRC operator (only unsettable!) */
        !           244:                        if (!set || Client_Type(Client) == CLIENT_SERVER) {
        !           245:                                x[0] = 'o';
        !           246:                        } else
        !           247:                                ok = IRC_WriteErrClient(Origin,
        !           248:                                                        ERR_NOPRIVILEGES_MSG,
        !           249:                                                        Client_ID(Origin));
        !           250:                        break;
        !           251:                case 'r': /* Restricted (only settable) */
        !           252:                        if (set || Client_Type(Client) == CLIENT_SERVER)
        !           253:                                x[0] = 'r';
        !           254:                        else
        !           255:                                ok = IRC_WriteErrClient(Origin,
        !           256:                                                        ERR_RESTRICTED_MSG,
        !           257:                                                        Client_ID(Origin));
        !           258:                        break;
        !           259:                case 'R': /* Registered (not [un]settable by clients) */
        !           260:                        if (Client_Type(Client) == CLIENT_SERVER)
        !           261:                                x[0] = 'R';
        !           262:                        else
        !           263:                                ok = IRC_WriteErrClient(Origin,
        !           264:                                                        ERR_NICKREGISTER_MSG,
        !           265:                                                        Client_ID(Origin));
        !           266:                        break;
        !           267:                case 'x': /* Cloak hostname */
        !           268:                        if (Client_HasMode(Client, 'r'))
        !           269:                                ok = IRC_WriteErrClient(Origin,
        !           270:                                                        ERR_RESTRICTED_MSG,
        !           271:                                                        Client_ID(Origin));
        !           272:                        else if (!set || Conf_CloakHostModeX[0]
        !           273:                                 || Client_Type(Client) == CLIENT_SERVER
        !           274:                                 || Client_HasMode(Origin, 'o')) {
        !           275:                                x[0] = 'x';
        !           276:                                send_RPL_HOSTHIDDEN_MSG = true;
        !           277:                        } else
        !           278:                                ok = IRC_WriteErrClient(Origin,
        !           279:                                                        ERR_NOPRIVILEGES_MSG,
        !           280:                                                        Client_ID(Origin));
        !           281:                        break;
        !           282:                default:
        !           283:                        if (Client_Type(Client) != CLIENT_SERVER) {
        !           284:                                Log(LOG_DEBUG,
        !           285:                                    "Unknown mode \"%c%c\" from \"%s\"!?",
        !           286:                                    set ? '+' : '-', *mode_ptr,
        !           287:                                    Client_ID(Origin));
        !           288:                                ok = IRC_WriteErrClient(Origin,
        !           289:                                                        ERR_UMODEUNKNOWNFLAG2_MSG,
        !           290:                                                        Client_ID(Origin),
        !           291:                                                        set ? '+' : '-',
        !           292:                                                        *mode_ptr);
        !           293:                                x[0] = '\0';
        !           294:                        } else {
        !           295:                                Log(LOG_DEBUG,
        !           296:                                    "Handling unknown mode \"%c%c\" from \"%s\" for \"%s\" ...",
        !           297:                                    set ? '+' : '-', *mode_ptr,
        !           298:                                    Client_ID(Origin), Client_ID(Target));
        !           299:                                x[0] = *mode_ptr;
        !           300:                        }
        !           301:                }
        !           302:
        !           303:                if (!ok)
        !           304:                        break;
        !           305:
        !           306:                /* Is there a valid mode change? */
        !           307:                if (!x[0])
        !           308:                        continue;
        !           309:
        !           310:                if (set) {
        !           311:                        if (Client_ModeAdd(Target, x[0]))
        !           312:                                strlcat(the_modes, x, sizeof(the_modes));
        !           313:                } else {
        !           314:                        if (Client_ModeDel(Target, x[0]))
        !           315:                                strlcat(the_modes, x, sizeof(the_modes));
        !           316:                }
        !           317:        }
        !           318:
        !           319:        /* Are there changed modes? */
        !           320:        if (the_modes[1]) {
        !           321:                /* Remove needless action modifier characters */
        !           322:                len = strlen(the_modes) - 1;
        !           323:                if (the_modes[len] == '+' || the_modes[len] == '-')
        !           324:                        the_modes[len] = '\0';
        !           325:
        !           326:                if (Client_Type(Client) == CLIENT_SERVER) {
        !           327:                        /* Forward modes to other servers */
        !           328:                        if (Client_Conn(Target) != NONE) {
        !           329:                                /* Remote server (service?) changed modes
        !           330:                                 * for one of our clients. Inform it! */
        !           331:                                IRC_WriteStrClientPrefix(Target, Origin,
        !           332:                                                         "MODE %s :%s",
        !           333:                                                         Client_ID(Target),
        !           334:                                                         the_modes);
        !           335:                        }
        !           336:                        IRC_WriteStrServersPrefix(Client, Origin,
        !           337:                                                  "MODE %s :%s",
        !           338:                                                  Client_ID(Target),
        !           339:                                                  the_modes);
        !           340:                } else {
        !           341:                        /* Send reply to client and inform other servers */
        !           342:                        ok = IRC_WriteStrClientPrefix(Client, Origin,
        !           343:                                                      "MODE %s :%s",
        !           344:                                                      Client_ID(Target),
        !           345:                                                      the_modes);
        !           346:                        IRC_WriteStrServersPrefix(Client, Origin,
        !           347:                                                  "MODE %s :%s",
        !           348:                                                  Client_ID(Target),
        !           349:                                                  the_modes);
        !           350:                }
        !           351:
        !           352:                if (send_RPL_HOSTHIDDEN_MSG && Client_Conn(Target) > NONE) {
        !           353:                        /* A new (cloaked) hostname must be announced */
        !           354:                        IRC_WriteStrClientPrefix(Target, Origin,
        !           355:                                                 RPL_HOSTHIDDEN_MSG,
        !           356:                                                 Client_ID(Target),
        !           357:                                                 Client_HostnameDisplayed(Target));
        !           358:
        !           359:                }
        !           360:
        !           361:                LogDebug("%s \"%s\": Mode change, now \"%s\".",
        !           362:                         Client_TypeText(Target), Client_Mask(Target),
        !           363:                         Client_Modes(Target));
        !           364:        }
        !           365:
        !           366:        return ok;
        !           367: } /* Client_Mode */
        !           368:
        !           369: /*
        !           370:  * Reply to a channel mode request.
        !           371:  *
        !           372:  * @param Origin The originator of the MODE command (prefix).
        !           373:  * @param Channel The channel of which the modes should be sent.
        !           374:  * @return CONNECTED or DISCONNECTED.
        !           375:  */
        !           376: static bool
        !           377: Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel)
        !           378: {
        !           379:        char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], argadd[CLIENT_PASS_LEN];
        !           380:        const char *mode_ptr;
        !           381:
        !           382:        if (!Channel_IsMemberOf(Channel, Origin)) {
        !           383:                /* Not a member: "simple" mode reply */
        !           384:                if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
        !           385:                                        Client_ID(Origin), Channel_Name(Channel),
        !           386:                                        Channel_Modes(Channel)))
        !           387:                        return DISCONNECTED;
        !           388:        } else {
        !           389:                /* The sender is a member: generate extended reply */
        !           390:                strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes));
        !           391:                mode_ptr = the_modes;
        !           392:                the_args[0] = '\0';
        !           393:
        !           394:                while(*mode_ptr) {
        !           395:                        switch(*mode_ptr) {
        !           396:                        case 'l':
        !           397:                                snprintf(argadd, sizeof(argadd), " %lu",
        !           398:                                         Channel_MaxUsers(Channel));
        !           399:                                strlcat(the_args, argadd, sizeof(the_args));
        !           400:                                break;
        !           401:                        case 'k':
        !           402:                                strlcat(the_args, " ", sizeof(the_args));
        !           403:                                strlcat(the_args, Channel_Key(Channel),
        !           404:                                        sizeof(the_args));
        !           405:                                break;
        !           406:                        }
        !           407:                        mode_ptr++;
        !           408:                }
        !           409:                if (the_args[0])
        !           410:                        strlcat(the_modes, the_args, sizeof(the_modes));
        !           411:
        !           412:                if (!IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
        !           413:                                        Client_ID(Origin), Channel_Name(Channel),
        !           414:                                        the_modes))
        !           415:                        return DISCONNECTED;
        !           416:        }
        !           417:
        !           418: #ifndef STRICT_RFC
        !           419:        /* Channel creation time */
        !           420:        if (!IRC_WriteStrClient(Origin, RPL_CREATIONTIME_MSG,
        !           421:                                  Client_ID(Origin), Channel_Name(Channel),
        !           422:                                  Channel_CreationTime(Channel)))
        !           423:                return DISCONNECTED;
        !           424: #endif
        !           425:        return CONNECTED;
        !           426: }
        !           427:
        !           428: /**
        !           429:  * Handle channel mode and channel-user mode changes
        !           430:  *
        !           431:  * @param Client The client from which this command has been received.
        !           432:  * @param Req Request structure with prefix and all parameters.
        !           433:  * @param Origin The originator of the MODE command (prefix).
        !           434:  * @param Channel The target channel of this MODE command.
        !           435:  * @return CONNECTED or DISCONNECTED.
        !           436:  */
        !           437: static bool
        !           438: Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
        !           439: {
        !           440:        char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2],
        !           441:            argadd[CLIENT_PASS_LEN], *mode_ptr;
        !           442:        bool connected, set, skiponce, retval, use_servermode,
        !           443:             is_halfop, is_op, is_admin, is_owner, is_machine, is_oper;
        !           444:        int mode_arg, arg_arg, mode_arg_count = 0;
        !           445:        CLIENT *client;
        !           446:        long l;
        !           447:        size_t len;
        !           448:
        !           449:        is_halfop = is_op = is_admin = is_owner = is_machine = is_oper = false;
        !           450:
        !           451:        if (Channel_IsModeless(Channel))
        !           452:                return IRC_WriteErrClient(Client, ERR_NOCHANMODES_MSG,
        !           453:                                Client_ID(Client), Channel_Name(Channel));
        !           454:
        !           455:        /* Mode request: let's answer it :-) */
        !           456:        if (Req->argc <= 1)
        !           457:                return Channel_Mode_Answer_Request(Origin, Channel);
        !           458:
        !           459:        /* Check if origin is oper and opers can use mode */
        !           460:        use_servermode = Conf_OperServerMode;
        !           461:        if(Client_HasMode(Client, 'o') && Conf_OperCanMode) {
        !           462:                is_oper = true;
        !           463:        }
        !           464:
        !           465:        /* Check if client is a server/service */
        !           466:        if(Client_Type(Client) == CLIENT_SERVER ||
        !           467:           Client_Type(Client) == CLIENT_SERVICE) {
        !           468:                is_machine = true;
        !           469:        }
        !           470:
        !           471:        /* Check if client is member of channel or an oper or an server/service */
        !           472:        if(!Channel_IsMemberOf(Channel, Client) && !is_oper && !is_machine)
        !           473:                return IRC_WriteErrClient(Origin, ERR_NOTONCHANNEL_MSG,
        !           474:                                          Client_ID(Origin),
        !           475:                                          Channel_Name(Channel));
        !           476:
        !           477:        mode_arg = 1;
        !           478:        mode_ptr = Req->argv[mode_arg];
        !           479:        if (Req->argc > mode_arg + 1)
        !           480:                arg_arg = mode_arg + 1;
        !           481:        else
        !           482:                arg_arg = -1;
        !           483:
        !           484:        /* Initial state: set or unset modes? */
        !           485:        skiponce = false;
        !           486:        switch (*mode_ptr) {
        !           487:        case '-':
        !           488:                set = false;
        !           489:                break;
        !           490:        case '+':
        !           491:                set = true;
        !           492:                break;
        !           493:        default:
        !           494:                set = true;
        !           495:                skiponce = true;
        !           496:        }
        !           497:
        !           498:        /* Prepare reply string */
        !           499:        strcpy(the_modes, set ? "+" : "-");
        !           500:        the_args[0] = '\0';
        !           501:
        !           502:        x[1] = '\0';
        !           503:        connected = CONNECTED;
        !           504:        while (mode_ptr) {
        !           505:                if (!skiponce)
        !           506:                        mode_ptr++;
        !           507:                if (!*mode_ptr) {
        !           508:                        /* Try next argument if there's any */
        !           509:                        if (arg_arg < 0)
        !           510:                                break;
        !           511:                        if (arg_arg > mode_arg)
        !           512:                                mode_arg = arg_arg;
        !           513:                        else
        !           514:                                mode_arg++;
        !           515:
        !           516:                        if (mode_arg >= Req->argc)
        !           517:                                break;
        !           518:                        mode_ptr = Req->argv[mode_arg];
        !           519:
        !           520:                        if (Req->argc > mode_arg + 1)
        !           521:                                arg_arg = mode_arg + 1;
        !           522:                        else
        !           523:                                arg_arg = -1;
        !           524:                }
        !           525:                skiponce = false;
        !           526:
        !           527:                switch (*mode_ptr) {
        !           528:                case '+':
        !           529:                case '-':
        !           530:                        if (((*mode_ptr == '+') && !set)
        !           531:                            || ((*mode_ptr == '-') && set)) {
        !           532:                                /* Action modifier ("+"/"-") must be changed ... */
        !           533:                                len = strlen(the_modes) - 1;
        !           534:                                if (the_modes[len] == '+' || the_modes[len] == '-') {
        !           535:                                        /* Adjust last action modifier in result */
        !           536:                                        the_modes[len] = *mode_ptr;
        !           537:                                } else {
        !           538:                                        /* Append modifier character to result string */
        !           539:                                        x[0] = *mode_ptr;
        !           540:                                        strlcat(the_modes, x, sizeof(the_modes));
        !           541:                                }
        !           542:                                set = *mode_ptr == '+';
        !           543:                        }
        !           544:                        continue;
        !           545:                }
        !           546:
        !           547:                /* Are there arguments left? */
        !           548:                if (arg_arg >= Req->argc)
        !           549:                        arg_arg = -1;
        !           550:
        !           551:                if(!is_machine && !is_oper) {
        !           552:                        if (Channel_UserHasMode(Channel, Client, 'q'))
        !           553:                                is_owner = true;
        !           554:                        if (Channel_UserHasMode(Channel, Client, 'a'))
        !           555:                                is_admin = true;
        !           556:                        if (Channel_UserHasMode(Channel, Client, 'o'))
        !           557:                                is_op = true;
        !           558:                        if (Channel_UserHasMode(Channel, Client, 'h'))
        !           559:                                is_halfop = true;
        !           560:                }
        !           561:
        !           562:                /* Validate modes */
        !           563:                x[0] = '\0';
        !           564:                argadd[0] = '\0';
        !           565:                client = NULL;
        !           566:                switch (*mode_ptr) {
        !           567:                /* --- Channel modes --- */
        !           568:                case 'R': /* Registered users only */
        !           569:                case 's': /* Secret channel */
        !           570:                case 'z': /* Secure connections only */
        !           571:                        if(!is_oper && !is_machine && !is_owner &&
        !           572:                           !is_admin && !is_op) {
        !           573:                                connected = IRC_WriteErrClient(Origin,
        !           574:                                        ERR_CHANOPRIVSNEEDED_MSG,
        !           575:                                        Client_ID(Origin), Channel_Name(Channel));
        !           576:                                goto chan_exit;
        !           577:                        }
        !           578:                case 'i': /* Invite only */
        !           579:                case 'V': /* Invite disallow */
        !           580:                case 'M': /* Only identified nicks can write */
        !           581:                case 'm': /* Moderated */
        !           582:                case 'n': /* Only members can write */
        !           583:                case 'N': /* Can't change nick while on this channel */
        !           584:                case 'Q': /* No kicks */
        !           585:                case 't': /* Topic locked */
        !           586:                        if(is_oper || is_machine || is_owner ||
        !           587:                           is_admin || is_op || is_halfop)
        !           588:                                x[0] = *mode_ptr;
        !           589:                        else
        !           590:                                connected = IRC_WriteErrClient(Origin,
        !           591:                                        ERR_CHANOPRIVSNEEDED_MSG,
        !           592:                                        Client_ID(Origin), Channel_Name(Channel));
        !           593:                        break;
        !           594:                case 'k': /* Channel key */
        !           595:                        if (Mode_Limit_Reached(Client, mode_arg_count++))
        !           596:                                goto chan_exit;
        !           597:                        if (!set) {
        !           598:                                if (is_oper || is_machine || is_owner ||
        !           599:                                    is_admin || is_op || is_halfop) {
        !           600:                                        x[0] = *mode_ptr;
        !           601:                                        if (Channel_HasMode(Channel, 'k'))
        !           602:                                                strlcpy(argadd, "*", sizeof(argadd));
        !           603:                                        if (arg_arg > mode_arg)
        !           604:                                                arg_arg++;
        !           605:                                } else
        !           606:                                        connected = IRC_WriteErrClient(Origin,
        !           607:                                                ERR_CHANOPRIVSNEEDED_MSG,
        !           608:                                                Client_ID(Origin),
        !           609:                                                Channel_Name(Channel));
        !           610:                                break;
        !           611:                        }
        !           612:                        if (arg_arg > mode_arg) {
        !           613:                                if (is_oper || is_machine || is_owner ||
        !           614:                                    is_admin || is_op || is_halfop) {
        !           615:                                        Channel_ModeDel(Channel, 'k');
        !           616:                                        Channel_SetKey(Channel,
        !           617:                                                       Req->argv[arg_arg]);
        !           618:                                        strlcpy(argadd, Channel_Key(Channel),
        !           619:                                                sizeof(argadd));
        !           620:                                        x[0] = *mode_ptr;
        !           621:                                } else {
        !           622:                                        connected = IRC_WriteErrClient(Origin,
        !           623:                                                ERR_CHANOPRIVSNEEDED_MSG,
        !           624:                                                Client_ID(Origin),
        !           625:                                                Channel_Name(Channel));
        !           626:                                }
        !           627:                                Req->argv[arg_arg][0] = '\0';
        !           628:                                arg_arg++;
        !           629:                        } else {
        !           630: #ifdef STRICT_RFC
        !           631:                                /* Only send error message in "strict" mode,
        !           632:                                 * this is how ircd2.11 and others behave ... */
        !           633:                                connected = IRC_WriteErrClient(Origin,
        !           634:                                        ERR_NEEDMOREPARAMS_MSG,
        !           635:                                        Client_ID(Origin), Req->command);
        !           636: #endif
        !           637:                                goto chan_exit;
        !           638:                        }
        !           639:                        break;
        !           640:                case 'l': /* Member limit */
        !           641:                        if (Mode_Limit_Reached(Client, mode_arg_count++))
        !           642:                                goto chan_exit;
        !           643:                        if (!set) {
        !           644:                                if (is_oper || is_machine || is_owner ||
        !           645:                                    is_admin || is_op || is_halfop)
        !           646:                                        x[0] = *mode_ptr;
        !           647:                                else
        !           648:                                        connected = IRC_WriteErrClient(Origin,
        !           649:                                                ERR_CHANOPRIVSNEEDED_MSG,
        !           650:                                                Client_ID(Origin),
        !           651:                                                Channel_Name(Channel));
        !           652:                                break;
        !           653:                        }
        !           654:                        if (arg_arg > mode_arg) {
        !           655:                                if (is_oper || is_machine || is_owner ||
        !           656:                                    is_admin || is_op || is_halfop) {
        !           657:                                        l = atol(Req->argv[arg_arg]);
        !           658:                                        if (l > 0 && l < 0xFFFF) {
        !           659:                                                Channel_ModeDel(Channel, 'l');
        !           660:                                                Channel_SetMaxUsers(Channel, l);
        !           661:                                                snprintf(argadd, sizeof(argadd),
        !           662:                                                         "%ld", l);
        !           663:                                                x[0] = *mode_ptr;
        !           664:                                        }
        !           665:                                } else {
        !           666:                                        connected = IRC_WriteErrClient(Origin,
        !           667:                                                ERR_CHANOPRIVSNEEDED_MSG,
        !           668:                                                Client_ID(Origin),
        !           669:                                                Channel_Name(Channel));
        !           670:                                }
        !           671:                                Req->argv[arg_arg][0] = '\0';
        !           672:                                arg_arg++;
        !           673:                        } else {
        !           674: #ifdef STRICT_RFC
        !           675:                                /* Only send error message in "strict" mode,
        !           676:                                 * this is how ircd2.11 and others behave ... */
        !           677:                                connected = IRC_WriteErrClient(Origin,
        !           678:                                        ERR_NEEDMOREPARAMS_MSG,
        !           679:                                        Client_ID(Origin), Req->command);
        !           680: #endif
        !           681:                                goto chan_exit;
        !           682:                        }
        !           683:                        break;
        !           684:                case 'O': /* IRC operators only */
        !           685:                        if (set) {
        !           686:                                /* Only IRC operators are allowed to
        !           687:                                 * set the 'O' channel mode! */
        !           688:                                if(is_oper || is_machine)
        !           689:                                        x[0] = 'O';
        !           690:                                else
        !           691:                                        connected = IRC_WriteErrClient(Origin,
        !           692:                                                ERR_NOPRIVILEGES_MSG,
        !           693:                                                Client_ID(Origin));
        !           694:                        } else if(is_oper || is_machine || is_owner ||
        !           695:                                  is_admin || is_op)
        !           696:                                x[0] = 'O';
        !           697:                        else
        !           698:                                connected = IRC_WriteErrClient(Origin,
        !           699:                                        ERR_CHANOPRIVSNEEDED_MSG,
        !           700:                                        Client_ID(Origin),
        !           701:                                        Channel_Name(Channel));
        !           702:                        break;
        !           703:                case 'P': /* Persistent channel */
        !           704:                        if (set) {
        !           705:                                /* Only IRC operators are allowed to
        !           706:                                 * set the 'P' channel mode! */
        !           707:                                if(is_oper || is_machine)
        !           708:                                        x[0] = 'P';
        !           709:                                else
        !           710:                                        connected = IRC_WriteErrClient(Origin,
        !           711:                                                ERR_NOPRIVILEGES_MSG,
        !           712:                                                Client_ID(Origin));
        !           713:                        } else if(is_oper || is_machine || is_owner ||
        !           714:                                  is_admin || is_op)
        !           715:                                x[0] = 'P';
        !           716:                        else
        !           717:                                connected = IRC_WriteErrClient(Origin,
        !           718:                                        ERR_CHANOPRIVSNEEDED_MSG,
        !           719:                                        Client_ID(Origin),
        !           720:                                        Channel_Name(Channel));
        !           721:                        break;
        !           722:                /* --- Channel user modes --- */
        !           723:                case 'q': /* Owner */
        !           724:                case 'a': /* Channel admin */
        !           725:                        if(!is_oper && !is_machine && !is_owner && !is_admin) {
        !           726:                                connected = IRC_WriteErrClient(Origin,
        !           727:                                        ERR_CHANOPPRIVTOOLOW_MSG,
        !           728:                                        Client_ID(Origin),
        !           729:                                        Channel_Name(Channel));
        !           730:                                goto chan_exit;
        !           731:                        }
        !           732:                case 'o': /* Channel operator */
        !           733:                        if(!is_oper && !is_machine && !is_owner &&
        !           734:                           !is_admin && !is_op) {
        !           735:                                connected = IRC_WriteErrClient(Origin,
        !           736:                                        ERR_CHANOPRIVSNEEDED_MSG,
        !           737:                                        Client_ID(Origin),
        !           738:                                        Channel_Name(Channel));
        !           739:                                goto chan_exit;
        !           740:                        }
        !           741:                case 'h': /* Half Op */
        !           742:                        if(!is_oper && !is_machine && !is_owner &&
        !           743:                           !is_admin && !is_op) {
        !           744:                                connected = IRC_WriteErrClient(Origin,
        !           745:                                        ERR_CHANOPRIVSNEEDED_MSG,
        !           746:                                        Client_ID(Origin),
        !           747:                                        Channel_Name(Channel));
        !           748:                                goto chan_exit;
        !           749:                        }
        !           750:                case 'v': /* Voice */
        !           751:                        if (arg_arg > mode_arg) {
        !           752:                                if (is_oper || is_machine || is_owner ||
        !           753:                                    is_admin || is_op || is_halfop) {
        !           754:                                        client = Client_Search(Req->argv[arg_arg]);
        !           755:                                        if (client)
        !           756:                                                x[0] = *mode_ptr;
        !           757:                                        else
        !           758:                                                connected = IRC_WriteErrClient(Origin,
        !           759:                                                        ERR_NOSUCHNICK_MSG,
        !           760:                                                        Client_ID(Origin),
        !           761:                                                        Req->argv[arg_arg]);
        !           762:                                } else {
        !           763:                                        connected = IRC_WriteErrClient(Origin,
        !           764:                                                ERR_CHANOPRIVSNEEDED_MSG,
        !           765:                                                Client_ID(Origin),
        !           766:                                                Channel_Name(Channel));
        !           767:                                }
        !           768:                                Req->argv[arg_arg][0] = '\0';
        !           769:                                arg_arg++;
        !           770:                        } else {
        !           771: #ifdef STRICT_RFC
        !           772:                                /* Report an error to the client, when a user
        !           773:                                 * mode should be changed but no nickname is
        !           774:                                 * given. But don't do it when not in "strict"
        !           775:                                 * mode, because most other servers don't do
        !           776:                                 * it as well and some clients send "wired"
        !           777:                                 * MODE commands like "MODE #chan -ooo nick". */
        !           778:                                connected = IRC_WriteErrClient(Origin,
        !           779:                                        ERR_NEEDMOREPARAMS_MSG,
        !           780:                                        Client_ID(Origin), Req->command);
        !           781: #endif
        !           782:                                goto chan_exit;
        !           783:                        }
        !           784:                        break;
        !           785:                /* --- Channel lists --- */
        !           786:                case 'I': /* Invite lists */
        !           787:                case 'b': /* Ban lists */
        !           788:                case 'e': /* Channel exception lists */
        !           789:                        if (Mode_Limit_Reached(Client, mode_arg_count++))
        !           790:                                goto chan_exit;
        !           791:                        if (arg_arg > mode_arg) {
        !           792:                                /* modify list */
        !           793:                                if (is_oper || is_machine || is_owner ||
        !           794:                                    is_admin || is_op || is_halfop) {
        !           795:                                        connected = set
        !           796:                                           ? Add_To_List(*mode_ptr, Origin,
        !           797:                                                Client, Channel,
        !           798:                                                Req->argv[arg_arg])
        !           799:                                           : Del_From_List(*mode_ptr, Origin,
        !           800:                                                Client, Channel,
        !           801:                                                Req->argv[arg_arg]);
        !           802:                                } else {
        !           803:                                        connected = IRC_WriteErrClient(Origin,
        !           804:                                                ERR_CHANOPRIVSNEEDED_MSG,
        !           805:                                                Client_ID(Origin),
        !           806:                                                Channel_Name(Channel));
        !           807:                                }
        !           808:                                Req->argv[arg_arg][0] = '\0';
        !           809:                                arg_arg++;
        !           810:                        } else {
        !           811:                                switch (*mode_ptr) {
        !           812:                                case 'I':
        !           813:                                        Channel_ShowInvites(Origin, Channel);
        !           814:                                        break;
        !           815:                                case 'b':
        !           816:                                        Channel_ShowBans(Origin, Channel);
        !           817:                                        break;
        !           818:                                case 'e':
        !           819:                                        Channel_ShowExcepts(Origin, Channel);
        !           820:                                        break;
        !           821:                                }
        !           822:                        }
        !           823:                        break;
        !           824:                default:
        !           825:                        if (Client_Type(Client) != CLIENT_SERVER) {
        !           826:                                Log(LOG_DEBUG,
        !           827:                                    "Unknown mode \"%c%c\" from \"%s\" on %s!?",
        !           828:                                    set ? '+' : '-', *mode_ptr,
        !           829:                                    Client_ID(Origin), Channel_Name(Channel));
        !           830:                                connected = IRC_WriteErrClient(Origin,
        !           831:                                        ERR_UNKNOWNMODE_MSG,
        !           832:                                        Client_ID(Origin), *mode_ptr,
        !           833:                                        Channel_Name(Channel));
        !           834:                                x[0] = '\0';
        !           835:                        } else {
        !           836:                                Log(LOG_DEBUG,
        !           837:                                    "Handling unknown mode \"%c%c\" from \"%s\" on %s ...",
        !           838:                                    set ? '+' : '-', *mode_ptr,
        !           839:                                    Client_ID(Origin), Channel_Name(Channel));
        !           840:                                x[0] = *mode_ptr;
        !           841:                        }
        !           842:                }
        !           843:
        !           844:                if (!connected)
        !           845:                        break;
        !           846:
        !           847:                /* Is there a valid mode change? */
        !           848:                if (!x[0])
        !           849:                        continue;
        !           850:
        !           851:                /* Validate target client */
        !           852:                if (client && (!Channel_IsMemberOf(Channel, client))) {
        !           853:                        if (!IRC_WriteErrClient(Origin, ERR_USERNOTINCHANNEL_MSG,
        !           854:                                                Client_ID(Origin),
        !           855:                                                Client_ID(client),
        !           856:                                                Channel_Name(Channel)))
        !           857:                                break;
        !           858:                        continue;
        !           859:                }
        !           860:
        !           861:                if (client) {
        !           862:                        /* Channel-User-Mode */
        !           863:                        retval = set
        !           864:                               ? Channel_UserModeAdd(Channel, client, x[0])
        !           865:                               : Channel_UserModeDel(Channel, client, x[0]);
        !           866:                        if (retval) {
        !           867:                                strlcat(the_args, " ", sizeof(the_args));
        !           868:                                strlcat(the_args, Client_ID(client),
        !           869:                                        sizeof(the_args));
        !           870:                                strlcat(the_modes, x, sizeof(the_modes));
        !           871:                                LogDebug
        !           872:                                    ("User \"%s\": Mode change on %s, now \"%s\"",
        !           873:                                     Client_Mask(client), Channel_Name(Channel),
        !           874:                                     Channel_UserModes(Channel, client));
        !           875:                        }
        !           876:                } else {
        !           877:                        /* Channel-Mode */
        !           878:                        retval = set
        !           879:                               ? Channel_ModeAdd(Channel, x[0])
        !           880:                               : Channel_ModeDel(Channel, x[0]);
        !           881:                        if (retval) {
        !           882:                                strlcat(the_modes, x, sizeof(the_modes));
        !           883:                                LogDebug("Channel %s: Mode change, now \"%s\".",
        !           884:                                         Channel_Name(Channel),
        !           885:                                         Channel_Modes(Channel));
        !           886:                        }
        !           887:                }
        !           888:
        !           889:                /* Are there additional arguments to add? */
        !           890:                if (argadd[0]) {
        !           891:                        strlcat(the_args, " ", sizeof(the_args));
        !           892:                        strlcat(the_args, argadd, sizeof(the_args));
        !           893:                }
        !           894:        }
        !           895:
        !           896:       chan_exit:
        !           897:        /* Are there changed modes? */
        !           898:        if (the_modes[1]) {
        !           899:                /* Clean up mode string */
        !           900:                len = strlen(the_modes) - 1;
        !           901:                if ((the_modes[len] == '+') || (the_modes[len] == '-'))
        !           902:                        the_modes[len] = '\0';
        !           903:
        !           904:                if (Client_Type(Client) == CLIENT_SERVER) {
        !           905:                        /* MODE requests for local channels from other servers
        !           906:                         * are definitely invalid! */
        !           907:                        if (Channel_IsLocal(Channel)) {
        !           908:                                Log(LOG_ALERT, "Got remote MODE command for local channel!? Ignored.");
        !           909:                                return CONNECTED;
        !           910:                        }
        !           911:
        !           912:                        /* Forward mode changes to channel users and all the
        !           913:                         * other remote servers: */
        !           914:                        IRC_WriteStrServersPrefix(Client, Origin,
        !           915:                                "MODE %s %s%s", Channel_Name(Channel),
        !           916:                                the_modes, the_args);
        !           917:                        IRC_WriteStrChannelPrefix(Client, Channel, Origin,
        !           918:                                false, "MODE %s %s%s", Channel_Name(Channel),
        !           919:                                the_modes, the_args);
        !           920:                } else {
        !           921:                        if (use_servermode)
        !           922:                                Origin = Client_ThisServer();
        !           923:                        /* Send reply to client and inform other servers and channel users */
        !           924:                        connected = IRC_WriteStrClientPrefix(Client, Origin,
        !           925:                                        "MODE %s %s%s", Channel_Name(Channel),
        !           926:                                        the_modes, the_args);
        !           927:                        /* Only forward requests for non-local channels */
        !           928:                        if (!Channel_IsLocal(Channel))
        !           929:                                IRC_WriteStrServersPrefix(Client, Origin,
        !           930:                                        "MODE %s %s%s", Channel_Name(Channel),
        !           931:                                        the_modes, the_args);
        !           932:                        IRC_WriteStrChannelPrefix(Client, Channel, Origin,
        !           933:                                false, "MODE %s %s%s", Channel_Name(Channel),
        !           934:                                the_modes, the_args);
        !           935:                }
        !           936:        }
        !           937:
        !           938:        return connected;
        !           939: } /* Channel_Mode */
        !           940:
        !           941: /**
        !           942:  * Handler for the IRC "AWAY" command.
        !           943:  *
        !           944:  * @param Client The client from which this command has been received.
        !           945:  * @param Req Request structure with prefix and all parameters.
        !           946:  * @return CONNECTED or DISCONNECTED.
        !           947:  */
        !           948: GLOBAL bool
        !           949: IRC_AWAY( CLIENT *Client, REQUEST *Req )
        !           950: {
        !           951:        assert (Client != NULL);
        !           952:        assert (Req != NULL);
        !           953:
        !           954:        if (Req->argc == 1 && Req->argv[0][0]) {
        !           955:                Client_SetAway(Client, Req->argv[0]);
        !           956:                Client_ModeAdd(Client, 'a');
        !           957:                IRC_WriteStrServersPrefix(Client, Client, "MODE %s :+a",
        !           958:                                          Client_ID( Client));
        !           959:                return IRC_WriteStrClient(Client, RPL_NOWAWAY_MSG,
        !           960:                                          Client_ID( Client));
        !           961:        } else {
        !           962:                Client_ModeDel(Client, 'a');
        !           963:                IRC_WriteStrServersPrefix(Client, Client, "MODE %s :-a",
        !           964:                                          Client_ID( Client));
        !           965:                return IRC_WriteStrClient(Client, RPL_UNAWAY_MSG,
        !           966:                                          Client_ID( Client));
        !           967:        }
        !           968: } /* IRC_AWAY */
        !           969:
        !           970: /**
        !           971:  * Add entries to channel invite, ban and exception lists.
        !           972:  *
        !           973:  * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list.
        !           974:  * @param Prefix The originator of the command.
        !           975:  * @param Client The sender of the command.
        !           976:  * @param Channel The channel of which the list should be modified.
        !           977:  * @param Pattern The pattern to add to the list.
        !           978:  * @return CONNECTED or DISCONNECTED.
        !           979:  */
        !           980: static bool
        !           981: Add_To_List(char what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel,
        !           982:            const char *Pattern)
        !           983: {
        !           984:        char mask[MASK_LEN];
        !           985:        struct list_head *list = NULL;
        !           986:        long int current_count;
        !           987:
        !           988:        assert(Client != NULL);
        !           989:        assert(Channel != NULL);
        !           990:        assert(Pattern != NULL);
        !           991:        assert(what == 'I' || what == 'b' || what == 'e');
        !           992:
        !           993:        Lists_MakeMask(Pattern, mask, sizeof(mask));
        !           994:        current_count = Lists_Count(Channel_GetListInvites(Channel))
        !           995:                        + Lists_Count(Channel_GetListExcepts(Channel))
        !           996:                        + Lists_Count(Channel_GetListBans(Channel));
        !           997:
        !           998:        switch(what) {
        !           999:                case 'I':
        !          1000:                        list = Channel_GetListInvites(Channel);
        !          1001:                        break;
        !          1002:                case 'b':
        !          1003:                        list = Channel_GetListBans(Channel);
        !          1004:                        break;
        !          1005:                case 'e':
        !          1006:                        list = Channel_GetListExcepts(Channel);
        !          1007:                        break;
        !          1008:        }
        !          1009:
        !          1010:        if (Lists_CheckDupeMask(list, mask))
        !          1011:                return CONNECTED;
        !          1012:        if (Client_Type(Client) == CLIENT_USER &&
        !          1013:            current_count >= MAX_HNDL_CHANNEL_LISTS)
        !          1014:                return IRC_WriteErrClient(Client, ERR_LISTFULL_MSG,
        !          1015:                                          Client_ID(Client),
        !          1016:                                          Channel_Name(Channel), mask,
        !          1017:                                          MAX_HNDL_CHANNEL_LISTS);
        !          1018:
        !          1019:        switch (what) {
        !          1020:                case 'I':
        !          1021:                        if (!Channel_AddInvite(Channel, mask, false, Client_ID(Client)))
        !          1022:                                return CONNECTED;
        !          1023:                        break;
        !          1024:                case 'b':
        !          1025:                        if (!Channel_AddBan(Channel, mask, Client_ID(Client)))
        !          1026:                                return CONNECTED;
        !          1027:                        break;
        !          1028:                case 'e':
        !          1029:                        if (!Channel_AddExcept(Channel, mask, Client_ID(Client)))
        !          1030:                                return CONNECTED;
        !          1031:                        break;
        !          1032:        }
        !          1033:        return Send_ListChange(true, what, Prefix, Client, Channel, mask);
        !          1034: }
        !          1035:
        !          1036: /**
        !          1037:  * Delete entries from channel invite, ban and exception lists.
        !          1038:  *
        !          1039:  * @param what Can be 'I' for invite, 'b' for ban, and 'e' for exception list.
        !          1040:  * @param Prefix The originator of the command.
        !          1041:  * @param Client The sender of the command.
        !          1042:  * @param Channel The channel of which the list should be modified.
        !          1043:  * @param Pattern The pattern to add to the list.
        !          1044:  * @return CONNECTED or DISCONNECTED.
        !          1045:  */
        !          1046: static bool
        !          1047: Del_From_List(char what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel,
        !          1048:              const char *Pattern)
        !          1049: {
        !          1050:        char mask[MASK_LEN];
        !          1051:        struct list_head *list = NULL;
        !          1052:
        !          1053:        assert(Client != NULL);
        !          1054:        assert(Channel != NULL);
        !          1055:        assert(Pattern != NULL);
        !          1056:        assert(what == 'I' || what == 'b' || what == 'e');
        !          1057:
        !          1058:        Lists_MakeMask(Pattern, mask, sizeof(mask));
        !          1059:
        !          1060:        switch (what) {
        !          1061:                case 'I':
        !          1062:                        list = Channel_GetListInvites(Channel);
        !          1063:                        break;
        !          1064:                case 'b':
        !          1065:                        list = Channel_GetListBans(Channel);
        !          1066:                        break;
        !          1067:                case 'e':
        !          1068:                        list = Channel_GetListExcepts(Channel);
        !          1069:                        break;
        !          1070:        }
        !          1071:
        !          1072:        if (!Lists_CheckDupeMask(list, mask))
        !          1073:                return CONNECTED;
        !          1074:        Lists_Del(list, mask);
        !          1075:
        !          1076:        return Send_ListChange(false, what, Prefix, Client, Channel, mask);
        !          1077: }
        !          1078:
        !          1079: /**
        !          1080:  * Send information about changed channel invite/ban/exception lists to clients.
        !          1081:  *
        !          1082:  * @param IsAdd true if the list item has been added, false otherwise.
        !          1083:  * @param ModeChar The mode to use (e. g. 'b' or 'I')
        !          1084:  * @param Prefix The originator of the mode list change.
        !          1085:  * @param Client The sender of the command.
        !          1086:  * @param Channel The channel of which the list has been modified.
        !          1087:  * @param Mask The mask which has been added or removed.
        !          1088:  * @return CONNECTED or DISCONNECTED.
        !          1089:  */
        !          1090: static bool
        !          1091: Send_ListChange(const bool IsAdd, const char ModeChar, CLIENT *Prefix,
        !          1092:                CLIENT *Client, CHANNEL *Channel, const char *Mask)
        !          1093: {
        !          1094:        bool ok = true;
        !          1095:
        !          1096:        /* Send confirmation to the client */
        !          1097:        if (Client_Type(Client) == CLIENT_USER)
        !          1098:                ok = IRC_WriteStrClientPrefix(Client, Prefix, "MODE %s %c%c %s",
        !          1099:                                              Channel_Name(Channel),
        !          1100:                                              IsAdd ? '+' : '-',
        !          1101:                                              ModeChar, Mask);
        !          1102:
        !          1103:        /* to other servers */
        !          1104:        IRC_WriteStrServersPrefix(Client, Prefix, "MODE %s %c%c %s",
        !          1105:                                  Channel_Name(Channel), IsAdd ? '+' : '-',
        !          1106:                                  ModeChar, Mask);
        !          1107:
        !          1108:        /* and local users in channel */
        !          1109:        IRC_WriteStrChannelPrefix(Client, Channel, Prefix, false,
        !          1110:                                  "MODE %s %c%c %s", Channel_Name(Channel),
        !          1111:                                  IsAdd ? '+' : '-', ModeChar, Mask );
        !          1112:
        !          1113:        return ok;
        !          1114: } /* Send_ListChange */
        !          1115:
        !          1116: /* -eof- */

CVSweb