[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

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