Annotation of ircnowd/src/ngircd/irc-cap.c, Revision 1.1
1.1 ! tomglok 1: /*
! 2: * ngIRCd -- The Next Generation IRC Daemon
! 3: * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify
! 6: * it under the terms of the GNU General Public License as published by
! 7: * the Free Software Foundation; either version 2 of the License, or
! 8: * (at your option) any later version.
! 9: * Please read the file COPYING, README and AUTHORS for more information.
! 10: */
! 11:
! 12: #include "portab.h"
! 13:
! 14: /**
! 15: * @file
! 16: * 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