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

Annotation of ircnowd/src/ngircd/irc-info.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 info commands
                     17:  */
                     18:
                     19: #include <assert.h>
                     20: #include <stdio.h>
                     21: #include <stdlib.h>
                     22: #include <string.h>
                     23: #include <strings.h>
                     24: #include <time.h>
                     25:
                     26: #include "ngircd.h"
                     27: #include "conn-func.h"
                     28: #include "conn-zip.h"
                     29: #include "channel.h"
                     30: #include "class.h"
                     31: #include "conf.h"
                     32: #include "lists.h"
                     33: #include "messages.h"
                     34: #include "match.h"
                     35: #include "parse.h"
                     36: #include "irc.h"
                     37: #include "irc-macros.h"
                     38: #include "irc-write.h"
                     39: #include "client-cap.h"
                     40: #include "op.h"
                     41:
                     42: #include "irc-info.h"
                     43:
                     44: /* Local functions */
                     45:
                     46: static unsigned int
                     47: t_diff(time_t *t, const time_t d)
                     48: {
                     49:        time_t diff, remain;
                     50:
                     51:        diff = *t / d;
                     52:        remain = diff * d;
                     53:        *t -= remain;
                     54:
                     55:        return (unsigned int)diff;
                     56: }
                     57:
                     58: static unsigned int
                     59: uptime_days(time_t *now)
                     60: {
                     61:        return t_diff(now, 60 * 60 * 24);
                     62: }
                     63:
                     64: static unsigned int
                     65: uptime_hrs(time_t *now)
                     66: {
                     67:        return t_diff(now, 60 * 60);
                     68: }
                     69:
                     70: static unsigned int
                     71: uptime_mins(time_t *now)
                     72: {
                     73:        return t_diff(now, 60);
                     74: }
                     75:
                     76: static bool
                     77: write_whoreply(CLIENT *Client, CLIENT *c, const char *channelname, const char *flags)
                     78: {
                     79:        return IRC_WriteStrClient(Client, RPL_WHOREPLY_MSG, Client_ID(Client),
                     80:                                  channelname, Client_User(c),
                     81:                                  Client_HostnameDisplayed(c),
                     82:                                  Client_ID(Client_Introducer(c)), Client_ID(c),
                     83:                                  flags, Client_Hops(c), Client_Info(c));
                     84: }
                     85:
                     86: /**
                     87:  * Return channel user mode prefix(es).
                     88:  *
                     89:  * @param Client The client requesting the mode prefixes.
                     90:  * @param chan_user_modes String with channel user modes.
                     91:  * @param str String buffer to which the prefix(es) will be appended.
                     92:  * @param len Size of "str" buffer.
                     93:  * @return Pointer to "str".
                     94:  */
                     95: static char *
                     96: who_flags_qualifier(CLIENT *Client, const char *chan_user_modes,
                     97:                    char *str, size_t len)
                     98: {
                     99:        assert(Client != NULL);
                    100:
                    101:        if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
                    102:                if (strchr(chan_user_modes, 'q'))
                    103:                        strlcat(str, "~", len);
                    104:                if (strchr(chan_user_modes, 'a'))
                    105:                        strlcat(str, "&", len);
                    106:                if (strchr(chan_user_modes, 'o'))
                    107:                        strlcat(str, "@", len);
                    108:                if (strchr(chan_user_modes, 'h'))
                    109:                        strlcat(str, "%", len);
                    110:                if (strchr(chan_user_modes, 'v'))
                    111:                        strlcat(str, "+", len);
                    112:
                    113:                return str;
                    114:        }
                    115:
                    116:        if (strchr(chan_user_modes, 'q'))
                    117:                strlcat(str, "~", len);
                    118:        else if (strchr(chan_user_modes, 'a'))
                    119:                strlcat(str, "&", len);
                    120:        else if (strchr(chan_user_modes, 'o'))
                    121:                strlcat(str, "@", len);
                    122:        else if (strchr(chan_user_modes, 'h'))
                    123:                strlcat(str, "%", len);
                    124:        else if (strchr(chan_user_modes, 'v'))
                    125:                strlcat(str, "+", len);
                    126:
                    127:        return str;
                    128: }
                    129:
                    130: /**
                    131:  * Send WHO reply for a "channel target" ("WHO #channel").
                    132:  *
                    133:  * @param Client Client requesting the information.
                    134:  * @param Chan Channel being requested.
                    135:  * @param OnlyOps Only display IRC operators.
                    136:  * @return CONNECTED or DISCONNECTED.
                    137:  */
                    138: static bool
                    139: IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
                    140: {
                    141:        bool is_visible, is_member, is_ircop;
                    142:        CL2CHAN *cl2chan;
                    143:        char flags[10];
                    144:        CLIENT *c;
                    145:        int count = 0;
                    146:
                    147:        assert( Client != NULL );
                    148:        assert( Chan != NULL );
                    149:
                    150:        is_member = Channel_IsMemberOf(Chan, Client);
                    151:
                    152:        /* Secret channel? */
                    153:        if (!is_member && Channel_HasMode(Chan, 's'))
                    154:                return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG,
                    155:                                          Client_ID(Client), Channel_Name(Chan));
                    156:
                    157:        cl2chan = Channel_FirstMember(Chan);
                    158:        for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) {
                    159:                c = Channel_GetClient(cl2chan);
                    160:
                    161:                is_ircop = Client_HasMode(c, 'o');
                    162:                if (OnlyOps && !is_ircop)
                    163:                        continue;
                    164:
                    165:                is_visible = !Client_HasMode(c, 'i');
                    166:                if (is_member || is_visible) {
                    167:                        memset(flags, 0, sizeof(flags));
                    168:
                    169:                        if (Client_HasMode(c, 'a'))
                    170:                                flags[0] = 'G'; /* away */
                    171:                        else
                    172:                                flags[0] = 'H';
                    173:
                    174:                        if (is_ircop)
                    175:                                flags[1] = '*';
                    176:
                    177:                        who_flags_qualifier(Client, Channel_UserModes(Chan, c),
                    178:                                            flags, sizeof(flags));
                    179:
                    180:                        if (!write_whoreply(Client, c, Channel_Name(Chan),
                    181:                                            flags))
                    182:                                return DISCONNECTED;
                    183:                        count++;
                    184:                }
                    185:        }
                    186:
                    187:        /* If there are a lot of clients, increase the penalty a bit */
                    188:        if (count > MAX_RPL_WHO)
                    189:                IRC_SetPenalty(Client, 1);
                    190:
                    191:        return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client),
                    192:                                  Channel_Name(Chan));
                    193: }
                    194:
                    195: /**
                    196:  * Send WHO reply for a "mask target" ("WHO m*sk").
                    197:  *
                    198:  * @param Client Client requesting the information.
                    199:  * @param Mask Mask being requested or NULL for "all" clients.
                    200:  * @param OnlyOps Only display IRC operators.
                    201:  * @return CONNECTED or DISCONNECTED.
                    202:  */
                    203: static bool
                    204: IRC_WHO_Mask(CLIENT *Client, char *Mask, bool OnlyOps)
                    205: {
                    206:        CLIENT *c;
                    207:        CL2CHAN *cl2chan;
                    208:        CHANNEL *chan;
                    209:        bool client_match, is_visible;
                    210:        char flags[3];
                    211:        int count = 0;
                    212:
                    213:        assert (Client != NULL);
                    214:
                    215:        if (Mask)
                    216:                ngt_LowerStr(Mask);
                    217:
                    218:        IRC_SetPenalty(Client, 3);
                    219:        for (c = Client_First(); c != NULL; c = Client_Next(c)) {
                    220:                if (Client_Type(c) != CLIENT_USER)
                    221:                        continue;
                    222:
                    223:                if (OnlyOps && !Client_HasMode(c, 'o'))
                    224:                        continue;
                    225:
                    226:                if (Mask) {
                    227:                        /* Match pattern against user host/server/name/nick */
                    228:                        client_match = MatchCaseInsensitive(Mask,
                    229:                                                            Client_Hostname(c));
                    230:                        if (!client_match)
                    231:                                client_match = MatchCaseInsensitive(Mask,
                    232:                                                                    Client_ID(Client_Introducer(c)));
                    233:                        if (!client_match)
                    234:                                client_match = MatchCaseInsensitive(Mask,
                    235:                                                                    Client_Info(c));
                    236:                        if (!client_match)
                    237:                                client_match = MatchCaseInsensitive(Mask,
                    238:                                                                    Client_ID(c));
                    239:                        if (!client_match)
                    240:                                continue;       /* no match: skip this client */
                    241:                }
                    242:
                    243:                is_visible = !Client_HasMode(c, 'i');
                    244:
                    245:                /* Target client is invisible, but mask matches exactly? */
                    246:                if (!is_visible && Mask && strcasecmp(Client_ID(c), Mask) == 0)
                    247:                        is_visible = true;
                    248:
                    249:                /* Target still invisible, but are both on the same channel? */
                    250:                if (!is_visible) {
                    251:                        cl2chan = Channel_FirstChannelOf(Client);
                    252:                        while (cl2chan && !is_visible) {
                    253:                                chan = Channel_GetChannel(cl2chan);
                    254:                                if (Channel_IsMemberOf(chan, c))
                    255:                                        is_visible = true;
                    256:                                cl2chan = Channel_NextChannelOf(Client, cl2chan);
                    257:                        }
                    258:                }
                    259:
                    260:                if (!is_visible)        /* target user is not visible */
                    261:                        continue;
                    262:
                    263:                if (IRC_CheckListTooBig(Client, count, MAX_RPL_WHO, "WHO"))
                    264:                        break;
                    265:
                    266:                memset(flags, 0, sizeof(flags));
                    267:
                    268:                if (Client_HasMode(c, 'a'))
                    269:                        flags[0] = 'G'; /* away */
                    270:                else
                    271:                        flags[0] = 'H';
                    272:
                    273:                if (Client_HasMode(c, 'o'))
                    274:                        flags[1] = '*';
                    275:
                    276:                if (!write_whoreply(Client, c, "*", flags))
                    277:                        return DISCONNECTED;
                    278:                count++;
                    279:        }
                    280:
                    281:        return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client),
                    282:                                  Mask ? Mask : "*");
                    283: }
                    284:
                    285: /**
                    286:  * Generate WHOIS reply of one actual client.
                    287:  *
                    288:  * @param Client The client from which this command has been received.
                    289:  * @param from The client requesting the information ("originator").
                    290:  * @param c The client of which information should be returned.
                    291:  * @return CONNECTED or DISCONNECTED.
                    292:  */
                    293: static bool
                    294: IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c)
                    295: {
                    296:        char str[COMMAND_LEN];
                    297:        CL2CHAN *cl2chan;
                    298:        CHANNEL *chan;
                    299:
                    300:        assert(Client != NULL);
                    301:        assert(from != NULL);
                    302:        assert(c != NULL);
                    303:
                    304:        /* Nick, user, hostname and client info */
                    305:        if (!IRC_WriteStrClient(from, RPL_WHOISUSER_MSG, Client_ID(from),
                    306:                                Client_ID(c), Client_User(c),
                    307:                                Client_HostnameDisplayed(c), Client_Info(c)))
                    308:                return DISCONNECTED;
                    309:
                    310:        /* Server */
                    311:        if (!IRC_WriteStrClient(from, RPL_WHOISSERVER_MSG, Client_ID(from),
                    312:                                Client_ID(c), Client_ID(Client_Introducer(c)),
                    313:                                Client_Info(Client_Introducer(c))))
                    314:                return DISCONNECTED;
                    315:
                    316:        /* Channels, show only if client has no +I or if from is oper */
                    317:        if(!(Client_HasMode(c, 'I')) || Client_HasMode(from, 'o'))  {
                    318:                snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
                    319:                         Client_ID(from), Client_ID(c));
                    320:                cl2chan = Channel_FirstChannelOf(c);
                    321:                while (cl2chan) {
                    322:                        chan = Channel_GetChannel(cl2chan);
                    323:                        assert(chan != NULL);
                    324:
                    325:                        /* next */
                    326:                        cl2chan = Channel_NextChannelOf(c, cl2chan);
                    327:
                    328:                        /* Secret channel? */
                    329:                        if (Channel_HasMode(chan, 's')
                    330:                            && !Channel_IsMemberOf(chan, Client))
                    331:                                continue;
                    332:
                    333:                        /* Local channel and request is not from a user? */
                    334:                        if (Client_Type(Client) == CLIENT_SERVER
                    335:                            && Channel_IsLocal(chan))
                    336:                                continue;
                    337:
                    338:                        /* Concatenate channel names */
                    339:                        if (str[strlen(str) - 1] != ':')
                    340:                                strlcat(str, " ", sizeof(str));
                    341:
                    342:                        who_flags_qualifier(Client, Channel_UserModes(chan, c),
                    343:                                            str, sizeof(str));
                    344:                        strlcat(str, Channel_Name(chan), sizeof(str));
                    345:
                    346:                        if (strlen(str) > (COMMAND_LEN - CHANNEL_NAME_LEN - 4)) {
                    347:                                /* Line becomes too long: send it! */
                    348:                                if (!IRC_WriteStrClient(Client, "%s", str))
                    349:                                        return DISCONNECTED;
                    350:                                snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
                    351:                                         Client_ID(from), Client_ID(c));
                    352:                        }
                    353:                }
                    354:                if(str[strlen(str) - 1] != ':') {
                    355:                        /* There is data left to send: */
                    356:                        if (!IRC_WriteStrClient(Client, "%s", str))
                    357:                                return DISCONNECTED;
                    358:                }
                    359:        }
                    360:
                    361:        /* IRC-Services? */
                    362:        if (Client_Type(c) == CLIENT_SERVICE &&
                    363:            !IRC_WriteStrClient(from, RPL_WHOISSERVICE_MSG,
                    364:                                Client_ID(from), Client_ID(c)))
                    365:                return DISCONNECTED;
                    366:
                    367:        /* IRC-Operator? */
                    368:        if (Client_Type(c) != CLIENT_SERVICE &&
                    369:            Client_HasMode(c, 'o') &&
                    370:            !IRC_WriteStrClient(from, RPL_WHOISOPERATOR_MSG,
                    371:                                Client_ID(from), Client_ID(c)))
                    372:                return DISCONNECTED;
                    373:
                    374:        /* IRC-Bot? */
                    375:        if (Client_HasMode(c, 'B') &&
                    376:            !IRC_WriteStrClient(from, RPL_WHOISBOT_MSG,
                    377:                                Client_ID(from), Client_ID(c)))
                    378:                return DISCONNECTED;
                    379:
                    380:        /* Connected using SSL? */
                    381:        if (Conn_UsesSSL(Client_Conn(c))) {
                    382:                if (!IRC_WriteStrClient(from, RPL_WHOISSSL_MSG, Client_ID(from),
                    383:                                        Client_ID(c)))
                    384:                        return DISCONNECTED;
                    385:
                    386:                /* Certificate fingerprint? */
                    387:                if (Conn_GetCertFp(Client_Conn(c)) &&
                    388:                    from == c &&
                    389:                    !IRC_WriteStrClient(from, RPL_WHOISCERTFP_MSG,
                    390:                                        Client_ID(from), Client_ID(c),
                    391:                                        Conn_GetCertFp(Client_Conn(c))))
                    392:                        return DISCONNECTED;
                    393:        }
                    394:
                    395:        /* Registered nickname? */
                    396:        if (Client_HasMode(c, 'R') &&
                    397:            !IRC_WriteStrClient(from, RPL_WHOISREGNICK_MSG,
                    398:                                Client_ID(from), Client_ID(c)))
                    399:                return DISCONNECTED;
                    400:
                    401:        /* Account name metadata? */
                    402:        if (Client_AccountName(c) &&
                    403:            !IRC_WriteStrClient(from, RPL_WHOISLOGGEDIN_MSG,
                    404:                                Client_ID(from), Client_ID(c),
                    405:                                Client_AccountName(c)))
                    406:                return DISCONNECTED;
                    407:
                    408:        /* Local client and requester is the user itself or an IRC Op? */
                    409:        if (Client_Conn(c) > NONE &&
                    410:            (from == c || Client_HasMode(from, 'o'))) {
                    411:                /* Client hostname */
                    412:                if (!IRC_WriteStrClient(from, RPL_WHOISHOST_MSG,
                    413:                                        Client_ID(from), Client_ID(c),
                    414:                                        Client_Hostname(c), Client_IPAText(c)))
                    415:                        return DISCONNECTED;
                    416:                /* Client modes */
                    417:                if (!IRC_WriteStrClient(from, RPL_WHOISMODES_MSG,
                    418:                                        Client_ID(from), Client_ID(c), Client_Modes(c)))
                    419:                        return DISCONNECTED;
                    420:        }
                    421:
                    422:        /* Idle and signon time (local clients only!) */
                    423:        if (!Conf_MorePrivacy && Client_Conn(c) > NONE &&
                    424:            !IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
                    425:                                Client_ID(from), Client_ID(c),
                    426:                                (unsigned long)Conn_GetIdle(Client_Conn(c)),
                    427:                                (unsigned long)Conn_GetSignon(Client_Conn(c))))
                    428:                return DISCONNECTED;
                    429:
                    430:        /* Away? */
                    431:        if (Client_HasMode(c, 'a') &&
                    432:            !IRC_WriteStrClient(from, RPL_AWAY_MSG,
                    433:                                Client_ID(from), Client_ID(c), Client_Away(c)))
                    434:                return DISCONNECTED;
                    435:
                    436:        return CONNECTED;
                    437: }
                    438:
                    439: static bool
                    440: WHOWAS_EntryWrite(CLIENT *prefix, WHOWAS *entry)
                    441: {
                    442:        char t_str[60];
                    443:
                    444:        (void)strftime(t_str, sizeof(t_str), "%a %b %d %H:%M:%S %Y",
                    445:                       localtime(&entry->time));
                    446:
                    447:        if (!IRC_WriteStrClient(prefix, RPL_WHOWASUSER_MSG, Client_ID(prefix),
                    448:                                entry->id, entry->user, entry->host, entry->info))
                    449:                return DISCONNECTED;
                    450:
                    451:        return IRC_WriteStrClient(prefix, RPL_WHOISSERVER_MSG, Client_ID(prefix),
                    452:                                  entry->id, entry->server, t_str);
                    453: }
                    454:
                    455: #ifdef SSL_SUPPORT
                    456: static bool
                    457: Show_MOTD_SSLInfo(CLIENT *Client)
                    458: {
                    459:        char buf[COMMAND_LEN];
                    460:        char c_str[128];
                    461:
                    462:        if (Conn_GetCipherInfo(Client_Conn(Client), c_str, sizeof(c_str))) {
                    463:                snprintf(buf, sizeof(buf), "Connected using Cipher %s", c_str);
                    464:                if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG,
                    465:                                        Client_ID(Client), buf))
                    466:                        return false;
                    467:        }
                    468:
                    469:        if (Conn_GetCertFp(Client_Conn(Client))) {
                    470:                snprintf(buf, sizeof(buf),
                    471:                         "Your client certificate fingerprint is: %s",
                    472:                         Conn_GetCertFp(Client_Conn(Client)));
                    473:                if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG,
                    474:                                        Client_ID(Client), buf))
                    475:                        return false;
                    476:        }
                    477:
                    478:        return true;
                    479: }
                    480: #else
                    481: static bool
                    482: Show_MOTD_SSLInfo(UNUSED CLIENT *c)
                    483: {
                    484:        return true;
                    485: }
                    486: #endif
                    487:
                    488: /* Global functions */
                    489:
                    490: /**
                    491:  * Handler for the IRC command "ADMIN".
                    492:  *
                    493:  * @param Client The client from which this command has been received.
                    494:  * @param Req Request structure with prefix and all parameters.
                    495:  * @return CONNECTED or DISCONNECTED.
                    496:  */
                    497: GLOBAL bool
                    498: IRC_ADMIN(CLIENT *Client, REQUEST *Req )
                    499: {
                    500:        CLIENT *target, *prefix;
                    501:
                    502:        assert( Client != NULL );
                    503:        assert( Req != NULL );
                    504:
                    505:        _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
                    506:        _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
                    507:
                    508:        /* Forward? */
                    509:        if(target != Client_ThisServer()) {
                    510:                IRC_WriteStrClientPrefix(target, prefix,
                    511:                                         "ADMIN %s", Client_ID(target));
                    512:                return CONNECTED;
                    513:        }
                    514:
                    515:        if (!IRC_WriteStrClient(Client, RPL_ADMINME_MSG, Client_ID(prefix),
                    516:                                Conf_ServerName))
                    517:                return DISCONNECTED;
                    518:        if (!IRC_WriteStrClient(Client, RPL_ADMINLOC1_MSG, Client_ID(prefix),
                    519:                                Conf_ServerAdmin1))
                    520:                return DISCONNECTED;
                    521:        if (!IRC_WriteStrClient(Client, RPL_ADMINLOC2_MSG, Client_ID(prefix),
                    522:                                Conf_ServerAdmin2))
                    523:                return DISCONNECTED;
                    524:        if (!IRC_WriteStrClient(Client, RPL_ADMINEMAIL_MSG, Client_ID(prefix),
                    525:                                Conf_ServerAdminMail))
                    526:                return DISCONNECTED;
                    527:
                    528:        return CONNECTED;
                    529: } /* IRC_ADMIN */
                    530:
                    531: /**
                    532:  * Handler for the IRC command "INFO".
                    533:  *
                    534:  * @param Client The client from which this command has been received.
                    535:  * @param Req Request structure with prefix and all parameters.
                    536:  * @return CONNECTED or DISCONNECTED.
                    537:  */
                    538: GLOBAL bool
                    539: IRC_INFO(CLIENT * Client, REQUEST * Req)
                    540: {
                    541:        CLIENT *target, *prefix;
                    542:        char msg[510];
                    543:
                    544:        assert(Client != NULL);
                    545:        assert(Req != NULL);
                    546:
                    547:        _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
                    548:        _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
                    549:
                    550:        /* Forward? */
                    551:        if (target != Client_ThisServer()) {
                    552:                IRC_WriteStrClientPrefix(target, prefix, "INFO %s",
                    553:                                         Client_ID(target));
                    554:                return CONNECTED;
                    555:        }
                    556:
                    557:        if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix),
                    558:                                NGIRCd_Version))
                    559:                return DISCONNECTED;
                    560:
                    561: #if defined(BIRTHDATE)
                    562:        char t_str[60];
                    563:        time_t t = BIRTHDATE;
                    564:        (void)strftime(t_str, sizeof(t_str), "%a %b %d %Y at %H:%M:%S (%Z)",
                    565:                        localtime(&t));
                    566:        snprintf(msg, sizeof(msg), "Birth Date: %s", t_str);
                    567:        if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
                    568:                return DISCONNECTED;
                    569: #elif defined(__DATE__) && defined(__TIME__)
                    570:        snprintf(msg, sizeof(msg), "Birth Date: %s at %s", __DATE__, __TIME__);
                    571:        if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
                    572:                return DISCONNECTED;
                    573: #endif
                    574:
                    575:        strlcpy(msg, "On-line since ", sizeof(msg));
                    576:        strlcat(msg, NGIRCd_StartStr, sizeof(msg));
                    577:        if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
                    578:                return DISCONNECTED;
                    579:
                    580:        if (!IRC_WriteStrClient(Client, RPL_ENDOFINFO_MSG, Client_ID(prefix)))
                    581:                return DISCONNECTED;
                    582:
                    583:        return CONNECTED;
                    584: } /* IRC_INFO */
                    585:
                    586: /**
                    587:  * Handler for the IRC "ISON" command.
                    588:  *
                    589:  * @param Client The client from which this command has been received.
                    590:  * @param Req Request structure with prefix and all parameters.
                    591:  * @return CONNECTED or DISCONNECTED.
                    592:  */
                    593: GLOBAL bool
                    594: IRC_ISON( CLIENT *Client, REQUEST *Req )
                    595: {
                    596:        char rpl[COMMAND_LEN];
                    597:        CLIENT *c;
                    598:        char *ptr;
                    599:        int i;
                    600:
                    601:        assert(Client != NULL);
                    602:        assert(Req != NULL);
                    603:
                    604:        strlcpy(rpl, RPL_ISON_MSG, sizeof rpl);
                    605:        for (i = 0; i < Req->argc; i++) {
                    606:                /* "All" ircd even parse ":<x> <y> ..." arguments and split
                    607:                 * them up; so we do the same ... */
                    608:                ptr = strtok(Req->argv[i], " ");
                    609:                while (ptr) {
                    610:                        ngt_TrimStr(ptr);
                    611:                        c = Client_Search(ptr);
                    612:                        if (c && Client_Type(c) == CLIENT_USER) {
                    613:                                strlcat(rpl, Client_ID(c), sizeof(rpl));
                    614:                                strlcat(rpl, " ", sizeof(rpl));
                    615:                        }
                    616:                        ptr = strtok(NULL, " ");
                    617:                }
                    618:        }
                    619:        ngt_TrimLastChr(rpl, ' ');
                    620:
                    621:        return IRC_WriteStrClient(Client, rpl, Client_ID(Client));
                    622: } /* IRC_ISON */
                    623:
                    624: /**
                    625:  * Handler for the IRC "LINKS" command.
                    626:  *
                    627:  * @param Client The client from which this command has been received.
                    628:  * @param Req Request structure with prefix and all parameters.
                    629:  * @return CONNECTED or DISCONNECTED.
                    630:  */
                    631: GLOBAL bool
                    632: IRC_LINKS(CLIENT *Client, REQUEST *Req)
                    633: {
                    634:        CLIENT *target, *from, *c;
                    635:        char *mask;
                    636:
                    637:        assert(Client != NULL);
                    638:        assert(Req != NULL);
                    639:
                    640:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
                    641:
                    642:        /* Get pointer to server mask or "*", if none given */
                    643:        if (Req->argc > 0)
                    644:                mask = Req->argv[Req->argc - 1];
                    645:        else
                    646:                mask = "*";
                    647:
                    648:        /* Forward? */
                    649:        if (Req->argc == 2) {
                    650:                _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
                    651:                if (target != Client_ThisServer()) {
                    652:                        IRC_WriteStrClientPrefix(target, from,
                    653:                                        "LINKS %s %s", Client_ID(target),
                    654:                                        Req->argv[1]);
                    655:                        return CONNECTED;
                    656:                }
                    657:        }
                    658:
                    659:        c = Client_First();
                    660:        while (c) {
                    661:                if (Client_Type(c) == CLIENT_SERVER
                    662:                    && MatchCaseInsensitive(mask, Client_ID(c))) {
                    663:                        if (!IRC_WriteStrClient(from, RPL_LINKS_MSG,
                    664:                                        Client_ID(from), Client_ID(c),
                    665:                                        Client_ID(Client_TopServer(c)
                    666:                                                  ? Client_TopServer(c)
                    667:                                                  : Client_ThisServer()),
                    668:                                        Client_Hops(c), Client_Info(c)))
                    669:                                return DISCONNECTED;
                    670:                }
                    671:                c = Client_Next(c);
                    672:        }
                    673:        return IRC_WriteStrClient(from, RPL_ENDOFLINKS_MSG,
                    674:                                  Client_ID(from), mask);
                    675: } /* IRC_LINKS */
                    676:
                    677: /**
                    678:  * Handler for the IRC "LUSERS" command.
                    679:  *
                    680:  * @param Client The client from which this command has been received.
                    681:  * @param Req Request structure with prefix and all parameters.
                    682:  * @return CONNECTED or DISCONNECTED.
                    683:  */
                    684: GLOBAL bool
                    685: IRC_LUSERS( CLIENT *Client, REQUEST *Req )
                    686: {
                    687:        CLIENT *target, *from;
                    688:
                    689:        assert( Client != NULL );
                    690:        assert( Req != NULL );
                    691:
                    692:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
                    693:        _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
                    694:
                    695:        /* Forward? */
                    696:        if (target != Client_ThisServer()) {
                    697:                IRC_WriteStrClientPrefix(target, from,
                    698:                                         "LUSERS %s %s", Req->argv[0],
                    699:                                         Client_ID(target));
                    700:                return CONNECTED;
                    701:        }
                    702:
                    703:        return IRC_Send_LUSERS(from);
                    704: } /* IRC_LUSERS */
                    705:
                    706: /**
                    707:  * Handler for the IRC command "SERVLIST".
                    708:  *
                    709:  * @param Client The client from which this command has been received.
                    710:  * @param Req Request structure with prefix and all parameters.
                    711:  * @return CONNECTED or DISCONNECTED.
                    712:  */
                    713: GLOBAL bool
                    714: IRC_SERVLIST(CLIENT *Client, REQUEST *Req)
                    715: {
                    716:        CLIENT *c;
                    717:
                    718:        assert(Client != NULL);
                    719:        assert(Req != NULL);
                    720:
                    721:        if (Req->argc < 2 || strcmp(Req->argv[1], "0") == 0) {
                    722:                for (c = Client_First(); c!= NULL; c = Client_Next(c)) {
                    723:                        if (Client_Type(c) != CLIENT_SERVICE)
                    724:                                continue;
                    725:                        if (Req->argc > 0 && !MatchCaseInsensitive(Req->argv[0],
                    726:                                                                  Client_ID(c)))
                    727:                                continue;
                    728:                        if (!IRC_WriteStrClient(Client, RPL_SERVLIST_MSG,
                    729:                                        Client_ID(Client), Client_Mask(c),
                    730:                                        Client_Mask(Client_Introducer(c)), "*",
                    731:                                        0, Client_Hops(c), Client_Info(c)))
                    732:                                return DISCONNECTED;
                    733:                }
                    734:        }
                    735:
                    736:        return IRC_WriteStrClient(Client, RPL_SERVLISTEND_MSG, Client_ID(Client),
                    737:                                  Req->argc > 0 ? Req->argv[0] : "*",
                    738:                                  Req->argc > 1 ? Req->argv[1] : "0");
                    739: } /* IRC_SERVLIST */
                    740:
                    741: /**
                    742:  * Handler for the IRC command "MOTD".
                    743:  *
                    744:  * @param Client The client from which this command has been received.
                    745:  * @param Req Request structure with prefix and all parameters.
                    746:  * @return CONNECTED or DISCONNECTED.
                    747:  */
                    748: GLOBAL bool
                    749: IRC_MOTD( CLIENT *Client, REQUEST *Req )
                    750: {
                    751:        CLIENT *from, *target;
                    752:
                    753:        assert( Client != NULL );
                    754:        assert( Req != NULL );
                    755:
                    756:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
                    757:        _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
                    758:
                    759:        /* Forward? */
                    760:        if (target != Client_ThisServer()) {
                    761:                IRC_WriteStrClientPrefix(target, from, "MOTD %s",
                    762:                                         Client_ID(target));
                    763:                return CONNECTED;
                    764:        }
                    765:
                    766:        return IRC_Show_MOTD(from);
                    767: } /* IRC_MOTD */
                    768:
                    769: /**
                    770:  * Handler for the IRC command "NAMES".
                    771:  *
                    772:  * @param Client The client from which this command has been received.
                    773:  * @param Req Request structure with prefix and all parameters.
                    774:  * @return CONNECTED or DISCONNECTED.
                    775:  */
                    776: GLOBAL bool
                    777: IRC_NAMES( CLIENT *Client, REQUEST *Req )
                    778: {
                    779:        char rpl[COMMAND_LEN], *ptr;
                    780:        CLIENT *target, *from, *c;
                    781:        CHANNEL *chan;
                    782:
                    783:        assert( Client != NULL );
                    784:        assert( Req != NULL );
                    785:
                    786:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
                    787:        _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
                    788:
                    789:        /* Forward? */
                    790:        if (target != Client_ThisServer()) {
                    791:                IRC_WriteStrClientPrefix(target, from, "NAMES %s :%s",
                    792:                                         Req->argv[0], Client_ID(target));
                    793:                return CONNECTED;
                    794:        }
                    795:
                    796:        if (Req->argc > 0) {
                    797:                /* Return NAMES list for specific channels */
                    798:                ptr = strtok(Req->argv[0], ",");
                    799:                while(ptr) {
                    800:                        chan = Channel_Search(ptr);
                    801:                        if (chan && !IRC_Send_NAMES(from, chan))
                    802:                                return DISCONNECTED;
                    803:                        if (!IRC_WriteStrClient(from, RPL_ENDOFNAMES_MSG,
                    804:                                                Client_ID(from), ptr))
                    805:                                return DISCONNECTED;
                    806:                        ptr = strtok( NULL, "," );
                    807:                }
                    808:                return CONNECTED;
                    809:        }
                    810:
                    811:        chan = Channel_First();
                    812:        while (chan) {
                    813:                if (!IRC_Send_NAMES(from, chan))
                    814:                        return DISCONNECTED;
                    815:                chan = Channel_Next(chan);
                    816:        }
                    817:
                    818:        /* Now print all clients which are not in any channel */
                    819:        c = Client_First();
                    820:        snprintf(rpl, sizeof(rpl), RPL_NAMREPLY_MSG, Client_ID(from), "*", "*");
                    821:        while (c) {
                    822:                if (Client_Type(c) == CLIENT_USER
                    823:                    && Channel_FirstChannelOf(c) == NULL
                    824:                    && !Client_HasMode(c, 'i'))
                    825:                {
                    826:                        /* its a user, concatenate ... */
                    827:                        if (rpl[strlen(rpl) - 1] != ':')
                    828:                                strlcat(rpl, " ", sizeof(rpl));
                    829:                        strlcat(rpl, Client_ID(c), sizeof(rpl));
                    830:
                    831:                        if (strlen(rpl) > COMMAND_LEN - CLIENT_NICK_LEN - 4) {
                    832:                                /* Line is gwoing too long, send now */
                    833:                                if (!IRC_WriteStrClient(from, "%s", rpl))
                    834:                                        return DISCONNECTED;
                    835:                                snprintf(rpl, sizeof(rpl), RPL_NAMREPLY_MSG,
                    836:                                         Client_ID(from), "*", "*");
                    837:                        }
                    838:                }
                    839:                c = Client_Next(c);
                    840:        }
                    841:        if (rpl[strlen(rpl) - 1] != ':' && !IRC_WriteStrClient(from, "%s", rpl))
                    842:                return DISCONNECTED;
                    843:
                    844:        return IRC_WriteStrClient(from, RPL_ENDOFNAMES_MSG, Client_ID(from), "*");
                    845: } /* IRC_NAMES */
                    846:
                    847: /**
                    848:  * Handler for the IRC command "STATS".
                    849:  *
                    850:  * @param Client The client from which this command has been received.
                    851:  * @param Req Request structure with prefix and all parameters.
                    852:  * @return CONNECTED or DISCONNECTED.
                    853:  */
                    854: GLOBAL bool
                    855: IRC_STATS( CLIENT *Client, REQUEST *Req )
                    856: {
                    857:        CLIENT *from, *target, *cl;
                    858:        CONN_ID con;
                    859:        char query;
                    860:        COMMAND *cmd;
                    861:        time_t time_now;
                    862:        unsigned int days, hrs, mins;
                    863:        struct list_head *list;
                    864:        struct list_elem *list_item;
                    865:        bool more_links = false;
                    866:
                    867:        assert(Client != NULL);
                    868:        assert(Req != NULL);
                    869:
                    870:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
                    871:        _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
                    872:
                    873:        /* Forward? */
                    874:        if (target != Client_ThisServer()) {
                    875:                IRC_WriteStrClientPrefix(target, from, "STATS %s %s",
                    876:                                         Req->argv[0], Client_ID(target));
                    877:                return CONNECTED;
                    878:        }
                    879:
                    880:        if (Req->argc > 0)
                    881:                query = Req->argv[0][0] ? Req->argv[0][0] : '*';
                    882:        else
                    883:                query = '*';
                    884:
                    885:        switch (query) {
                    886:        case 'g':       /* Network-wide bans ("G-Lines") */
                    887:        case 'G':
                    888:        case 'k':       /* Server-local bans ("K-Lines") */
                    889:        case 'K':
                    890:                if (!Client_HasMode(from, 'o'))
                    891:                    return IRC_WriteErrClient(from, ERR_NOPRIVILEGES_MSG,
                    892:                                              Client_ID(from));
                    893:                if (query == 'g' || query == 'G')
                    894:                        list = Class_GetList(CLASS_GLINE);
                    895:                else
                    896:                        list = Class_GetList(CLASS_KLINE);
                    897:                list_item = Lists_GetFirst(list);
                    898:                while (list_item) {
                    899:                        if (!IRC_WriteStrClient(from, RPL_STATSXLINE_MSG,
                    900:                                                Client_ID(from), query,
                    901:                                                Lists_GetMask(list_item),
                    902:                                                Lists_GetValidity(list_item),
                    903:                                                Lists_GetReason(list_item)))
                    904:                                return DISCONNECTED;
                    905:                        list_item = Lists_GetNext(list_item);
                    906:                }
                    907:                break;
                    908:        case 'L':       /* Link status (servers and user links) */
                    909:                if (!Op_Check(from, Req))
                    910:                        return Op_NoPrivileges(from, Req);
                    911:                more_links = true;
                    912:
                    913:        case 'l':       /* Link status (servers and own link) */
                    914:                time_now = time(NULL);
                    915:                for (con = Conn_First(); con != NONE; con = Conn_Next(con)) {
                    916:                        cl = Conn_GetClient(con);
                    917:                        if (!cl)
                    918:                                continue;
                    919:                        if (Client_Type(cl) == CLIENT_SERVER ||
                    920:                            cl == Client ||
                    921:                            (more_links && Client_Type(cl) == CLIENT_USER)) {
                    922: #ifdef ZLIB
                    923:                                if (Conn_Options(con) & CONN_ZIP) {
                    924:                                        if (!IRC_WriteStrClient
                    925:                                            (from, RPL_STATSLINKINFOZIP_MSG,
                    926:                                             Client_ID(from), Client_Mask(cl),
                    927:                                             Conn_SendQ(con), Conn_SendMsg(con),
                    928:                                             Zip_SendBytes(con),
                    929:                                             Conn_SendBytes(con),
                    930:                                             Conn_RecvMsg(con),
                    931:                                             Zip_RecvBytes(con),
                    932:                                             Conn_RecvBytes(con),
                    933:                                             (long)(time_now - Conn_StartTime(con))))
                    934:                                                return DISCONNECTED;
                    935:                                        continue;
                    936:                                }
                    937: #endif
                    938:                                if (!IRC_WriteStrClient
                    939:                                    (from, RPL_STATSLINKINFO_MSG,
                    940:                                     Client_ID(from), Client_Mask(cl),
                    941:                                     Conn_SendQ(con), Conn_SendMsg(con),
                    942:                                     Conn_SendBytes(con), Conn_RecvMsg(con),
                    943:                                     Conn_RecvBytes(con),
                    944:                                     (long)(time_now - Conn_StartTime(con))))
                    945:                                        return DISCONNECTED;
                    946:                        }
                    947:                }
                    948:                break;
                    949:        case 'm':       /* IRC command status (usage count) */
                    950:        case 'M':
                    951:                cmd = Parse_GetCommandStruct();
                    952:                for (; cmd->name; cmd++) {
                    953:                        if (cmd->lcount == 0 && cmd->rcount == 0)
                    954:                                continue;
                    955:                        if (!IRC_WriteStrClient
                    956:                            (from, RPL_STATSCOMMANDS_MSG, Client_ID(from),
                    957:                             cmd->name, cmd->lcount, cmd->bytes, cmd->rcount))
                    958:                                return DISCONNECTED;
                    959:                }
                    960:                break;
                    961:        case 'u':       /* Server uptime */
                    962:        case 'U':
                    963:                time_now = time(NULL) - NGIRCd_Start;
                    964:                days = uptime_days(&time_now);
                    965:                hrs = uptime_hrs(&time_now);
                    966:                mins = uptime_mins(&time_now);
                    967:                if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from),
                    968:                                       days, hrs, mins, (unsigned int)time_now))
                    969:                        return DISCONNECTED;
                    970:                break;
                    971:        }
                    972:
                    973:        return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG,
                    974:                                  Client_ID(from), query);
                    975: } /* IRC_STATS */
                    976:
                    977: /**
                    978:  * Handler for the IRC command "SUMMON".
                    979:  *
                    980:  * @param Client The client from which this command has been received.
                    981:  * @param Req Request structure with prefix and all parameters.
                    982:  * @return CONNECTED or DISCONNECTED.
                    983:  */
                    984: GLOBAL bool
                    985: IRC_SUMMON(CLIENT * Client, UNUSED REQUEST * Req)
                    986: {
                    987:        assert(Client != NULL);
                    988:
                    989:        return IRC_WriteErrClient(Client, ERR_SUMMONDISABLED_MSG,
                    990:                                  Client_ID(Client));
                    991: } /* IRC_SUMMON */
                    992:
                    993: /**
                    994:  * Handler for the IRC command "TIME".
                    995:  *
                    996:  * @param Client The client from which this command has been received.
                    997:  * @param Req Request structure with prefix and all parameters.
                    998:  * @return CONNECTED or DISCONNECTED.
                    999:  */
                   1000: GLOBAL bool
                   1001: IRC_TIME( CLIENT *Client, REQUEST *Req )
                   1002: {
                   1003:        CLIENT *from, *target;
                   1004:        char t_str[64];
                   1005:        time_t t;
                   1006:
                   1007:        assert(Client != NULL);
                   1008:        assert(Req != NULL);
                   1009:
                   1010:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
                   1011:        _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
                   1012:
                   1013:        /* Forward? */
                   1014:        if (target != Client_ThisServer()) {
                   1015:                IRC_WriteStrClientPrefix(target, from, "TIME %s",
                   1016:                                         Client_ID(target));
                   1017:                return CONNECTED;
                   1018:        }
                   1019:
                   1020:        t = time( NULL );
                   1021:        (void)strftime(t_str, 60, "%A %B %d %Y -- %H:%M %Z", localtime(&t));
                   1022:        return IRC_WriteStrClient(from, RPL_TIME_MSG, Client_ID(from),
                   1023:                                  Client_ID(Client_ThisServer()), t_str);
                   1024: } /* IRC_TIME */
                   1025:
                   1026: /**
                   1027:  * Handler for the IRC command "USERHOST".
                   1028:  *
                   1029:  * @param Client The client from which this command has been received.
                   1030:  * @param Req Request structure with prefix and all parameters.
                   1031:  * @return CONNECTED or DISCONNECTED.
                   1032:  */
                   1033: GLOBAL bool
                   1034: IRC_USERHOST(CLIENT *Client, REQUEST *Req)
                   1035: {
                   1036:        char rpl[COMMAND_LEN];
                   1037:        CLIENT *c;
                   1038:        int max, i;
                   1039:
                   1040:        assert(Client != NULL);
                   1041:        assert(Req != NULL);
                   1042:
                   1043:        if (Req->argc > 5)
                   1044:                max = 5;
                   1045:        else
                   1046:                max = Req->argc;
                   1047:
                   1048:        strlcpy(rpl, RPL_USERHOST_MSG, sizeof rpl);
                   1049:        for (i = 0; i < max; i++) {
                   1050:                c = Client_Search(Req->argv[i]);
                   1051:                if (c && (Client_Type(c) == CLIENT_USER)) {
                   1052:                        /* This Nick is "online" */
                   1053:                        strlcat(rpl, Client_ID(c), sizeof(rpl));
                   1054:                        if (Client_HasMode(c, 'o'))
                   1055:                                strlcat(rpl, "*", sizeof(rpl));
                   1056:                        strlcat(rpl, "=", sizeof(rpl));
                   1057:                        if (Client_HasMode(c, 'a'))
                   1058:                                strlcat(rpl, "-", sizeof(rpl));
                   1059:                        else
                   1060:                                strlcat(rpl, "+", sizeof(rpl));
                   1061:                        strlcat(rpl, Client_User(c), sizeof(rpl));
                   1062:                        strlcat(rpl, "@", sizeof(rpl));
                   1063:                        strlcat(rpl, Client_HostnameDisplayed(c), sizeof(rpl));
                   1064:                        strlcat(rpl, " ", sizeof(rpl));
                   1065:                }
                   1066:        }
                   1067:        ngt_TrimLastChr(rpl, ' ');
                   1068:
                   1069:        return IRC_WriteStrClient(Client, rpl, Client_ID(Client));
                   1070: } /* IRC_USERHOST */
                   1071:
                   1072: /**
                   1073:  * Handler for the IRC command "USERS".
                   1074:  *
                   1075:  * @param Client The client from which this command has been received.
                   1076:  * @param Req Request structure with prefix and all parameters.
                   1077:  * @return CONNECTED or DISCONNECTED.
                   1078:  */
                   1079: GLOBAL bool
                   1080: IRC_USERS(CLIENT * Client, UNUSED REQUEST * Req)
                   1081: {
                   1082:        assert(Client != NULL);
                   1083:
                   1084:        return IRC_WriteErrClient(Client, ERR_USERSDISABLED_MSG,
                   1085:                                  Client_ID(Client));
                   1086: } /* IRC_USERS */
                   1087:
                   1088: /**
                   1089:  * Handler for the IRC command "VERSION".
                   1090:  *
                   1091:  * @param Client The client from which this command has been received.
                   1092:  * @param Req Request structure with prefix and all parameters.
                   1093:  * @return CONNECTED or DISCONNECTED.
                   1094:  */
                   1095: GLOBAL bool
                   1096: IRC_VERSION( CLIENT *Client, REQUEST *Req )
                   1097: {
                   1098:        CLIENT *target, *prefix;
                   1099:
                   1100:        assert( Client != NULL );
                   1101:        assert( Req != NULL );
                   1102:
                   1103:        _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
                   1104:        _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
                   1105:
                   1106:        /* Forward? */
                   1107:        if (target != Client_ThisServer()) {
                   1108:                IRC_WriteStrClientPrefix(target, prefix, "VERSION %s",
                   1109:                                         Client_ID(target));
                   1110:                return CONNECTED;
                   1111:        }
                   1112:
                   1113:        /* send version information */
                   1114:        if (!IRC_WriteStrClient(Client, RPL_VERSION_MSG, Client_ID(prefix),
                   1115:                                PACKAGE_NAME, PACKAGE_VERSION,
                   1116:                                NGIRCd_DebugLevel, Conf_ServerName,
                   1117:                                NGIRCd_VersionAddition))
                   1118:                return DISCONNECTED;
                   1119:
                   1120: #ifndef STRICT_RFC
                   1121:        /* send RPL_ISUPPORT(005) numerics */
                   1122:        if (!IRC_Send_ISUPPORT(prefix))
                   1123:                return DISCONNECTED;
                   1124: #endif
                   1125:
                   1126:        return CONNECTED;
                   1127: } /* IRC_VERSION */
                   1128:
                   1129: /**
                   1130:  * Handler for the IRC "WHO" command.
                   1131:  *
                   1132:  * @param Client The client from which this command has been received.
                   1133:  * @param Req Request structure with prefix and all parameters.
                   1134:  * @return CONNECTED or DISCONNECTED.
                   1135:  */
                   1136: GLOBAL bool
                   1137: IRC_WHO(CLIENT *Client, REQUEST *Req)
                   1138: {
                   1139:        bool only_ops;
                   1140:        CHANNEL *chan;
                   1141:
                   1142:        assert (Client != NULL);
                   1143:        assert (Req != NULL);
                   1144:
                   1145:        only_ops = false;
                   1146:        if (Req->argc == 2) {
                   1147:                if (strcmp(Req->argv[1], "o") == 0)
                   1148:                        only_ops = true;
                   1149: #ifdef STRICT_RFC
                   1150:                else {
                   1151:                        return IRC_WriteErrClient(Client,
                   1152:                                                  ERR_NEEDMOREPARAMS_MSG,
                   1153:                                                  Client_ID(Client),
                   1154:                                                  Req->command);
                   1155:                }
                   1156: #endif
                   1157:        }
                   1158:
                   1159:        if (Req->argc >= 1) {
                   1160:                /* Channel or mask given */
                   1161:                chan = Channel_Search(Req->argv[0]);
                   1162:                if (chan) {
                   1163:                        /* Members of a channel have been requested */
                   1164:                        return IRC_WHO_Channel(Client, chan, only_ops);
                   1165:                }
                   1166:                if (strcmp(Req->argv[0], "0") != 0) {
                   1167:                        /* A mask has been given. But please note this RFC
                   1168:                         * stupidity: "0" is same as no arguments ... */
                   1169:                        return IRC_WHO_Mask(Client, Req->argv[0], only_ops);
                   1170:                }
                   1171:        }
                   1172:
                   1173:        /* No channel or (valid) mask given */
                   1174:        return IRC_WHO_Mask(Client, NULL, only_ops);
                   1175: } /* IRC_WHO */
                   1176:
                   1177: /**
                   1178:  * Handler for the IRC "WHOIS" command.
                   1179:  *
                   1180:  * @param Client The client from which this command has been received.
                   1181:  * @param Req Request structure with prefix and all parameters.
                   1182:  * @return CONNECTED or DISCONNECTED.
                   1183:  */
                   1184: GLOBAL bool
                   1185: IRC_WHOIS( CLIENT *Client, REQUEST *Req )
                   1186: {
                   1187:        CLIENT *from, *target, *c;
                   1188:        unsigned int match_count = 0, found = 0;
                   1189:        bool has_wildcards, is_remote;
                   1190:        bool got_wildcard = false;
                   1191:        char mask[COMMAND_LEN], *query;
                   1192:
                   1193:        assert( Client != NULL );
                   1194:        assert( Req != NULL );
                   1195:
                   1196:        /* Wrong number of parameters? */
                   1197:        if (Req->argc < 1)
                   1198:                return IRC_WriteErrClient(Client, ERR_NONICKNAMEGIVEN_MSG,
                   1199:                                          Client_ID(Client));
                   1200:
                   1201:        _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
                   1202:        _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
                   1203:
                   1204:        /* Get target server for this command */
                   1205:        if (Req->argc > 1) {
                   1206:                _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, Client)
                   1207:        } else
                   1208:                target = Client_ThisServer();
                   1209:
                   1210:        assert(target != NULL);
                   1211:
                   1212:        /* Forward? */
                   1213:        if (target != Client_ThisServer()) {
                   1214:                IRC_WriteStrClientPrefix(target, from, "WHOIS %s :%s",
                   1215:                                         Req->argv[0], Req->argv[1]);
                   1216:                return CONNECTED;
                   1217:        }
                   1218:
                   1219:        is_remote = Client_Conn(from) < 0;
                   1220:        strlcpy(mask, Req->argv[Req->argc - 1], sizeof(mask));
                   1221:        for (query = strtok(ngt_LowerStr(mask), ",");
                   1222:                        query && found < 3;
                   1223:                        query = strtok(NULL, ","), found++)
                   1224:        {
                   1225:                has_wildcards = query[strcspn(query, "*?")] != 0;
                   1226:                /*
                   1227:                 * follows ircd 2.10 implementation:
                   1228:                 *  - handle up to 3 targets
                   1229:                 *  - no wildcards for remote clients
                   1230:                 *  - only one wildcard target per local client
                   1231:                 *
                   1232:                 *  Also, at most MAX_RPL_WHOIS matches are returned.
                   1233:                 */
                   1234:                if (!has_wildcards || is_remote) {
                   1235:                        c = Client_Search(query);
                   1236:                        if (c && (Client_Type(c) == CLIENT_USER
                   1237:                                  || Client_Type(c) == CLIENT_SERVICE)) {
                   1238:                                if (!IRC_WHOIS_SendReply(Client, from, c))
                   1239:                                        return DISCONNECTED;
                   1240:                        } else {
                   1241:                                if (!IRC_WriteErrClient(Client,
                   1242:                                                        ERR_NOSUCHNICK_MSG,
                   1243:                                                        Client_ID(Client),
                   1244:                                                        query))
                   1245:                                        return DISCONNECTED;
                   1246:                        }
                   1247:                        continue;
                   1248:                }
                   1249:                if (got_wildcard) {
                   1250:                        /* we already handled one wildcard query */
                   1251:                        if (!IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
                   1252:                             Client_ID(Client), query))
                   1253:                                return DISCONNECTED;
                   1254:                        continue;
                   1255:                }
                   1256:                got_wildcard = true;
                   1257:                /* Increase penalty for wildcard queries */
                   1258:                IRC_SetPenalty(Client, 3);
                   1259:
                   1260:                for (c = Client_First(); c; c = Client_Next(c)) {
                   1261:                        if (IRC_CheckListTooBig(Client, match_count,
                   1262:                                            MAX_RPL_WHOIS, "WHOIS"))
                   1263:                                break;
                   1264:
                   1265:                        if (Client_Type(c) != CLIENT_USER)
                   1266:                                continue;
                   1267:                        if (!MatchCaseInsensitive(query, Client_ID(c)))
                   1268:                                continue;
                   1269:                        if (!IRC_WHOIS_SendReply(Client, from, c))
                   1270:                                return DISCONNECTED;
                   1271:
                   1272:                        match_count++;
                   1273:                }
                   1274:
                   1275:                if (match_count == 0)
                   1276:                        IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
                   1277:                                           Client_ID(Client),
                   1278:                                           Req->argv[Req->argc - 1]);
                   1279:        }
                   1280:        return IRC_WriteStrClient(from, RPL_ENDOFWHOIS_MSG,
                   1281:                                  Client_ID(from), Req->argv[Req->argc - 1]);
                   1282: } /* IRC_WHOIS */
                   1283:
                   1284: /**
                   1285:  * Handler for the IRC "WHOWAS" command.
                   1286:  *
                   1287:  * @param Client The client from which this command has been received.
                   1288:  * @param Req Request structure with prefix and all parameters.
                   1289:  * @return CONNECTED or DISCONNECTED.
                   1290:  */
                   1291: GLOBAL bool
                   1292: IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
                   1293: {
                   1294:        CLIENT *target, *prefix;
                   1295:        WHOWAS *whowas;
                   1296:        char tok_buf[COMMAND_LEN];
                   1297:        int max, last, count, i, nc;
                   1298:        const char *nick;
                   1299:
                   1300:        assert( Client != NULL );
                   1301:        assert( Req != NULL );
                   1302:
                   1303:        /* Wrong number of parameters? */
                   1304:        if (Req->argc < 1)
                   1305:                return IRC_WriteErrClient(Client, ERR_NONICKNAMEGIVEN_MSG,
                   1306:                                          Client_ID(Client));
                   1307:
                   1308:        _IRC_ARGC_LE_OR_RETURN_(Client, Req, 3)
                   1309:        _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
                   1310:        _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 2, prefix)
                   1311:
                   1312:        /* Do not reveal any info on disconnected users? */
                   1313:        if (Conf_MorePrivacy)
                   1314:                return CONNECTED;
                   1315:
                   1316:        /* Forward? */
                   1317:        if (target != Client_ThisServer()) {
                   1318:                IRC_WriteStrClientPrefix(target, prefix, "WHOWAS %s %s %s",
                   1319:                                         Req->argv[0], Req->argv[1],
                   1320:                                         Client_ID(target));
                   1321:                return CONNECTED;
                   1322:        }
                   1323:
                   1324:        whowas = Client_GetWhowas( );
                   1325:        last = Client_GetLastWhowasIndex( );
                   1326:        if (last < 0)
                   1327:                last = 0;
                   1328:
                   1329:        max = DEF_RPL_WHOWAS;
                   1330:        if (Req->argc > 1) {
                   1331:                max = atoi(Req->argv[1]);
                   1332:                if (max < 1)
                   1333:                        max = MAX_RPL_WHOWAS;
                   1334:        }
                   1335:
                   1336:        /*
                   1337:         * Break up the nick argument into a list of nicks, if applicable
                   1338:         * Can't modify Req->argv[0] because we need it for RPL_ENDOFWHOWAS_MSG.
                   1339:         */
                   1340:        strlcpy(tok_buf, Req->argv[0], sizeof(tok_buf));
                   1341:        nick = strtok(tok_buf, ",");
                   1342:
                   1343:        for (i=last, count=0; nick != NULL ; nick = strtok(NULL, ",")) {
                   1344:                nc = 0;
                   1345:                do {
                   1346:                        /* Used entry? */
                   1347:                        if (whowas[i].time > 0 && strcasecmp(nick, whowas[i].id) == 0) {
                   1348:                                if (!WHOWAS_EntryWrite(prefix, &whowas[i]))
                   1349:                                        return DISCONNECTED;
                   1350:                                nc++;
                   1351:                                count++;
                   1352:                        }
                   1353:                        /* previous entry */
                   1354:                        i--;
                   1355:
                   1356:                        /* "underflow", wrap around */
                   1357:                        if (i < 0)
                   1358:                                i = MAX_WHOWAS - 1;
                   1359:
                   1360:                        if (nc && count >= max)
                   1361:                                break;
                   1362:                } while (i != last);
                   1363:
                   1364:                if (nc == 0 && !IRC_WriteErrClient(prefix, ERR_WASNOSUCHNICK_MSG,
                   1365:                                                Client_ID(prefix), nick))
                   1366:                        return DISCONNECTED;
                   1367:        }
                   1368:        return IRC_WriteStrClient(prefix, RPL_ENDOFWHOWAS_MSG,
                   1369:                                  Client_ID(prefix), Req->argv[0]);
                   1370: } /* IRC_WHOWAS */
                   1371:
                   1372: /**
                   1373:  * Send LUSERS reply to a client.
                   1374:  *
                   1375:  * @param Client The receipient of the information.
                   1376:  * @return CONNECTED or DISCONNECTED.
                   1377:  */
                   1378: GLOBAL bool
                   1379: IRC_Send_LUSERS(CLIENT *Client)
                   1380: {
                   1381:        unsigned long cnt;
                   1382: #ifndef STRICT_RFC
                   1383:        unsigned long max;
                   1384: #endif
                   1385:
                   1386:        assert(Client != NULL);
                   1387:
                   1388:        /* Users, services and servers in the network */
                   1389:        if (!IRC_WriteStrClient(Client, RPL_LUSERCLIENT_MSG, Client_ID(Client),
                   1390:                                Client_UserCount(), Client_ServiceCount(),
                   1391:                                Client_ServerCount()))
                   1392:                return DISCONNECTED;
                   1393:
                   1394:        /* Number of IRC operators */
                   1395:        cnt = Client_OperCount( );
                   1396:        if (cnt > 0) {
                   1397:                if (!IRC_WriteStrClient(Client, RPL_LUSEROP_MSG,
                   1398:                                        Client_ID(Client), cnt))
                   1399:                        return DISCONNECTED;
                   1400:        }
                   1401:
                   1402:        /* Unknown connections */
                   1403:        cnt = Client_UnknownCount( );
                   1404:        if (cnt > 0) {
                   1405:                if (!IRC_WriteStrClient(Client, RPL_LUSERUNKNOWN_MSG,
                   1406:                                        Client_ID(Client), cnt))
                   1407:                        return DISCONNECTED;
                   1408:        }
                   1409:
                   1410:        /* Number of created channels */
                   1411:        if (!IRC_WriteStrClient(Client, RPL_LUSERCHANNELS_MSG,
                   1412:                                Client_ID(Client),
                   1413:                                Channel_CountVisible(Client)))
                   1414:                return DISCONNECTED;
                   1415:
                   1416:        /* Number of local users, services and servers */
                   1417:        if (!IRC_WriteStrClient(Client, RPL_LUSERME_MSG, Client_ID(Client),
                   1418:                                Client_MyUserCount(), Client_MyServiceCount(),
                   1419:                                Client_MyServerCount()))
                   1420:                return DISCONNECTED;
                   1421:
                   1422: #ifndef STRICT_RFC
                   1423:        /* Maximum number of local users */
                   1424:        cnt = Client_MyUserCount();
                   1425:        max = Client_MyMaxUserCount();
                   1426:        if (! IRC_WriteStrClient(Client, RPL_LOCALUSERS_MSG, Client_ID(Client),
                   1427:                        cnt, max, cnt, max))
                   1428:                return DISCONNECTED;
                   1429:        /* Maximum number of users in the network */
                   1430:        cnt = Client_UserCount();
                   1431:        max = Client_MaxUserCount();
                   1432:        if(! IRC_WriteStrClient(Client, RPL_NETUSERS_MSG, Client_ID(Client),
                   1433:                        cnt, max, cnt, max))
                   1434:                return DISCONNECTED;
                   1435:        /* Connection counters */
                   1436:        if (! IRC_WriteStrClient(Client, RPL_STATSCONN_MSG, Client_ID(Client),
                   1437:                        Conn_CountMax(), Conn_CountAccepted()))
                   1438:                return DISCONNECTED;
                   1439: #endif
                   1440:
                   1441:        return CONNECTED;
                   1442: } /* IRC_Send_LUSERS */
                   1443:
                   1444: GLOBAL bool
                   1445: IRC_Show_MOTD( CLIENT *Client )
                   1446: {
                   1447:        const char *line;
                   1448:        size_t len_tot, len_str;
                   1449:
                   1450:        assert( Client != NULL );
                   1451:
                   1452:        len_tot = array_bytes(&Conf_Motd);
                   1453:        if (len_tot == 0 && !Conn_UsesSSL(Client_Conn(Client)))
                   1454:                return IRC_WriteErrClient(Client, ERR_NOMOTD_MSG, Client_ID(Client));
                   1455:
                   1456:        if (!IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG, Client_ID(Client),
                   1457:                                Client_ID(Client_ThisServer())))
                   1458:                return DISCONNECTED;
                   1459:
                   1460:        line = array_start(&Conf_Motd);
                   1461:        while (len_tot > 0) {
                   1462:                len_str = strlen(line) + 1;
                   1463:
                   1464:                assert(len_tot >= len_str);
                   1465:                len_tot -= len_str;
                   1466:
                   1467:                if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID(Client), line))
                   1468:                        return DISCONNECTED;
                   1469:                line += len_str;
                   1470:        }
                   1471:
                   1472:        if (!Show_MOTD_SSLInfo(Client))
                   1473:                return DISCONNECTED;
                   1474:
                   1475:        if (!IRC_WriteStrClient(Client, RPL_ENDOFMOTD_MSG, Client_ID(Client)))
                   1476:                return DISCONNECTED;
                   1477:
                   1478:        if (*Conf_CloakHost)
                   1479:                return IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG,
                   1480:                                          Client_ID(Client),
                   1481:                                          Client_Hostname(Client));
                   1482:
                   1483:        return CONNECTED;
                   1484: } /* IRC_Show_MOTD */
                   1485:
                   1486: /**
                   1487:  * Send NAMES reply for a specific client and channel.
                   1488:  *
                   1489:  * @param Client The client requesting the NAMES information.
                   1490:  * @param Chan The channel
                   1491:  * @return CONNECTED or DISCONNECTED.
                   1492:  */
                   1493: GLOBAL bool
                   1494: IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan)
                   1495: {
                   1496:        bool is_visible, is_member;
                   1497:        char str[COMMAND_LEN];
                   1498:        CL2CHAN *cl2chan;
                   1499:        CLIENT *cl;
                   1500:
                   1501:        assert(Client != NULL);
                   1502:        assert(Chan != NULL);
                   1503:
                   1504:        if (Channel_IsMemberOf(Chan, Client))
                   1505:                is_member = true;
                   1506:        else
                   1507:                is_member = false;
                   1508:
                   1509:        /* Do not print info on channel memberships to anyone that is not member? */
                   1510:        if (Conf_MorePrivacy && !is_member)
                   1511:                return CONNECTED;
                   1512:
                   1513:        /* Secret channel? */
                   1514:        if (!is_member && Channel_HasMode(Chan, 's'))
                   1515:                return CONNECTED;
                   1516:
                   1517:        snprintf(str, sizeof(str), RPL_NAMREPLY_MSG, Client_ID(Client), "=",
                   1518:                 Channel_Name(Chan));
                   1519:        cl2chan = Channel_FirstMember(Chan);
                   1520:        while (cl2chan) {
                   1521:                cl = Channel_GetClient(cl2chan);
                   1522:
                   1523:                if (Client_HasMode(cl, 'i'))
                   1524:                        is_visible = false;
                   1525:                else
                   1526:                        is_visible = true;
                   1527:
                   1528:                if (is_member || is_visible) {
                   1529:                        if (str[strlen(str) - 1] != ':')
                   1530:                                strlcat(str, " ", sizeof(str));
                   1531:
                   1532:                        who_flags_qualifier(Client, Channel_UserModes(Chan, cl),
                   1533:                                            str, sizeof(str));
                   1534:                        strlcat(str, Client_ID(cl), sizeof(str));
                   1535:
                   1536:                        if (strlen(str) > (COMMAND_LEN - CLIENT_NICK_LEN - 4)) {
                   1537:                                if (!IRC_WriteStrClient(Client, "%s", str))
                   1538:                                        return DISCONNECTED;
                   1539:                                snprintf(str, sizeof(str), RPL_NAMREPLY_MSG,
                   1540:                                         Client_ID(Client), "=",
                   1541:                                         Channel_Name(Chan));
                   1542:                        }
                   1543:                }
                   1544:
                   1545:                cl2chan = Channel_NextMember(Chan, cl2chan);
                   1546:        }
                   1547:        if (str[strlen(str) - 1] != ':') {
                   1548:                if (!IRC_WriteStrClient(Client, "%s", str))
                   1549:                        return DISCONNECTED;
                   1550:        }
                   1551:
                   1552:        return CONNECTED;
                   1553: } /* IRC_Send_NAMES */
                   1554:
                   1555: /**
                   1556:  * Send the ISUPPORT numeric (005).
                   1557:  * This numeric indicates the features that are supported by this server.
                   1558:  * See <http://www.irc.org/tech_docs/005.html> for details.
                   1559:  */
                   1560: GLOBAL bool
                   1561: IRC_Send_ISUPPORT(CLIENT * Client)
                   1562: {
                   1563:        if (Conf_Network[0] && !IRC_WriteStrClient(Client, RPL_ISUPPORTNET_MSG,
                   1564:                                                   Client_ID(Client),
                   1565:                                                   Conf_Network))
                   1566:                return DISCONNECTED;
                   1567:        if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
                   1568:                                CHANTYPES, CHANTYPES, Conf_MaxJoins))
                   1569:                return DISCONNECTED;
                   1570:        return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
                   1571:                                  CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
                   1572:                                  COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
                   1573:                                  COMMAND_LEN - 113, MAX_HNDL_MODES_ARG,
                   1574:                                  MAX_HNDL_CHANNEL_LISTS);
                   1575: } /* IRC_Send_ISUPPORT */
                   1576:
                   1577: /* -eof- */

CVSweb