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

Annotation of ircnowd/src/ngircd/irc-cap.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:  * Handler for IRC capability ("CAP") commands
                     17:  */
                     18:
                     19: #include <assert.h>
                     20: #include <string.h>
                     21: #include <strings.h>
                     22:
                     23: #include "conn.h"
                     24: #include "channel.h"
                     25: #include "client-cap.h"
                     26: #include "irc-write.h"
                     27: #include "log.h"
                     28: #include "login.h"
                     29: #include "messages.h"
                     30: #include "parse.h"
                     31:
                     32: #include "irc-cap.h"
                     33:
                     34: /* Local functions */
                     35:
                     36: /**
                     37:  * Set CAP negotiation status and mark client as "supports capabilities".
                     38:  *
                     39:  * @param Client The client to handle.
                     40:  */
                     41: static void
                     42: Set_CAP_Negotiation(CLIENT *Client)
                     43: {
                     44:        assert(Client != NULL);
                     45:
                     46:        if (Client_Type(Client) != CLIENT_USER)
                     47:                Client_CapAdd(Client, CLIENT_CAP_PENDING);
                     48:        Client_CapAdd(Client, CLIENT_CAP_SUPPORTED);
                     49: }
                     50:
                     51: /**
                     52:  * Parse capability string and return numeric flag value.
                     53:  *
                     54:  * @param Args The string containing space-separated capability names.
                     55:  * @return Changed capability flags or 0 on error.
                     56:  */
                     57: static int
                     58: Parse_CAP(int Capabilities, char *Args)
                     59: {
                     60:        static char tmp[COMMAND_LEN];
                     61:        char *ptr;
                     62:
                     63:        assert(Args != NULL);
                     64:
                     65:        strlcpy(tmp, Args, sizeof(tmp));
                     66:
                     67:        ptr = strtok(tmp, " ");
                     68:        while (ptr) {
                     69:                if (*ptr == '-') {
                     70:                        /* drop capabilities */
                     71:                        ptr++;
                     72:                        if (strcmp(ptr, "multi-prefix") == 0)
                     73:                                Capabilities &= ~CLIENT_CAP_MULTI_PREFIX;
                     74:                        else
                     75:                                return -1;
                     76:                } else {
                     77:                        /* request capabilities */
                     78:                        if (strcmp(ptr, "multi-prefix") == 0)
                     79:                                Capabilities |= CLIENT_CAP_MULTI_PREFIX;
                     80:                        else
                     81:                                return -1;
                     82:                }
                     83:                ptr = strtok(NULL, " ");
                     84:        }
                     85:
                     86:        return Capabilities;
                     87: }
                     88:
                     89: /**
                     90:  * Return textual representation of capability flags.
                     91:  *
                     92:  * Please note: this function returns a pointer to a global buffer and
                     93:  * therefore isn't thread safe!
                     94:  *
                     95:  * @param Capabilities Capability flags (bitmask).
                     96:  * @return Pointer to textual representation.
                     97:  */
                     98: static char *
                     99: Get_CAP_String(int Capabilities)
                    100: {
                    101:        static char txt[COMMAND_LEN];
                    102:
                    103:        txt[0] = '\0';
                    104:
                    105:        if (Capabilities & CLIENT_CAP_MULTI_PREFIX)
                    106:                strlcat(txt, "multi-prefix ", sizeof(txt));
                    107:
                    108:        return txt;
                    109: }
                    110:
                    111: /**
                    112:  * Handler for the IRCv3 sub-command "CAP LS".
                    113:  *
                    114:  * @param Client The client from which this command has been received.
                    115:  * @param Arg Command argument or NULL.
                    116:  * @return CONNECTED or DISCONNECTED.
                    117:  */
                    118: static bool
                    119: Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg)
                    120: {
                    121:        assert(Client != NULL);
                    122:
                    123:        Set_CAP_Negotiation(Client);
                    124:
                    125:        return IRC_WriteStrClient(Client,
                    126:                                  "CAP %s LS :multi-prefix",
                    127:                                  Client_ID(Client));
                    128: }
                    129:
                    130: /**
                    131:  * Handler for the IRCv3 sub-command "CAP LIST".
                    132:  *
                    133:  * @param Client The client from which this command has been received.
                    134:  * @param Arg Command argument or NULL.
                    135:  * @return CONNECTED or DISCONNECTED.
                    136:  */
                    137: static bool
                    138: Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg)
                    139: {
                    140:        assert(Client != NULL);
                    141:
                    142:        return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client),
                    143:                                  Get_CAP_String(Client_Cap(Client)));
                    144: }
                    145:
                    146: /**
                    147:  * Handler for the IRCv3 sub-command "CAP REQ".
                    148:  *
                    149:  * @param Client The client from which this command has been received.
                    150:  * @param Arg Command argument.
                    151:  * @return CONNECTED or DISCONNECTED.
                    152:  */
                    153: static bool
                    154: Handle_CAP_REQ(CLIENT *Client, char *Arg)
                    155: {
                    156:        int new_cap;
                    157:
                    158:        assert(Client != NULL);
                    159:        assert(Arg != NULL);
                    160:
                    161:        Set_CAP_Negotiation(Client);
                    162:
                    163:        new_cap = Parse_CAP(Client_Cap(Client), Arg);
                    164:
                    165:        if (new_cap < 0)
                    166:                return IRC_WriteStrClient(Client, "CAP %s NAK :%s",
                    167:                                          Client_ID(Client), Arg);
                    168:
                    169:        Client_CapSet(Client, new_cap);
                    170:        return IRC_WriteStrClient(Client, "CAP %s ACK :%s",
                    171:                                  Client_ID(Client), Arg);
                    172: }
                    173:
                    174: /**
                    175:  * Handler for the IRCv3 sub-command "CAP ACK".
                    176:  *
                    177:  * @param Client The client from which this command has been received.
                    178:  * @param Arg Command argument.
                    179:  * @return CONNECTED or DISCONNECTED.
                    180:  */
                    181: static bool
                    182: Handle_CAP_ACK(UNUSED CLIENT *Client, UNUSED char *Arg)
                    183: {
                    184:        assert(Client != NULL);
                    185:        assert(Arg != NULL);
                    186:
                    187:        return CONNECTED;
                    188: }
                    189:
                    190: /**
                    191:  * Handler for the IRCv3 sub-command "CAP CLEAR".
                    192:  *
                    193:  * @param Client The client from which this command has been received.
                    194:  * @return CONNECTED or DISCONNECTED.
                    195:  */
                    196: static bool
                    197: Handle_CAP_CLEAR(CLIENT *Client)
                    198: {
                    199:        int cap_old;
                    200:
                    201:        assert(Client != NULL);
                    202:
                    203:        cap_old = Client_Cap(Client);
                    204:        if (cap_old & CLIENT_CAP_MULTI_PREFIX)
                    205:                Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX);
                    206:
                    207:        return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client),
                    208:                                  Get_CAP_String(cap_old));
                    209: }
                    210:
                    211: /**
                    212:  * Handler for the IRCv3 sub-command "CAP END".
                    213:  *
                    214:  * @param Client The client from which this command has been received.
                    215:  * @return CONNECTED or DISCONNECTED.
                    216:  */
                    217: static bool
                    218: Handle_CAP_END(CLIENT *Client)
                    219: {
                    220:        assert(Client != NULL);
                    221:
                    222:        if (Client_Type(Client) != CLIENT_USER) {
                    223:                /* User is still logging in ... */
                    224:                Client_CapDel(Client, CLIENT_CAP_PENDING);
                    225:
                    226:                if (Client_Type(Client) == CLIENT_WAITCAPEND) {
                    227:                        /* Only "CAP END" was missing: log in! */
                    228:                        return Login_User(Client);
                    229:                }
                    230:        }
                    231:
                    232:        return CONNECTED;
                    233: }
                    234:
                    235: /* Global functions */
                    236:
                    237: /**
                    238:  * Handler for the IRCv3 command "CAP".
                    239:  *
                    240:  * @param Client The client from which this command has been received.
                    241:  * @param Req Request structure with prefix and all parameters.
                    242:  * @return CONNECTED or DISCONNECTED.
                    243:  */
                    244: GLOBAL bool
                    245: IRC_CAP(CLIENT *Client, REQUEST *Req)
                    246: {
                    247:        assert(Client != NULL);
                    248:        assert(Req != NULL);
                    249:
                    250:        LogDebug("Got \"%s %s\" command from \"%s\" ...",
                    251:                 Req->command, Req->argv[0], Client_ID(Client));
                    252:
                    253:        if (Req->argc == 1) {
                    254:                if (strcasecmp(Req->argv[0], "CLEAR") == 0)
                    255:                        return Handle_CAP_CLEAR(Client);
                    256:                if (strcasecmp(Req->argv[0], "END") == 0)
                    257:                        return Handle_CAP_END(Client);
                    258:        }
                    259:        if (Req->argc >= 1 && Req->argc <= 2) {
                    260:                if (strcasecmp(Req->argv[0], "LS") == 0)
                    261:                        return Handle_CAP_LS(Client, Req->argv[1]);
                    262:                if (strcasecmp(Req->argv[0], "LIST") == 0)
                    263:                        return Handle_CAP_LIST(Client, Req->argv[1]);
                    264:        }
                    265:        if (Req->argc == 2) {
                    266:                if (strcasecmp(Req->argv[0], "REQ") == 0)
                    267:                        return Handle_CAP_REQ(Client, Req->argv[1]);
                    268:                if (strcasecmp(Req->argv[0], "ACK") == 0)
                    269:                        return Handle_CAP_ACK(Client, Req->argv[1]);
                    270:        }
                    271:
                    272:        return IRC_WriteErrClient(Client, ERR_INVALIDCAP_MSG,
                    273:                                  Client_ID(Client), Req->argv[0]);
                    274: }
                    275:
                    276: /* -eof- */

CVSweb