123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- /*
- * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * Please read the file COPYING, README and AUTHORS for more information.
- */
- #include "portab.h"
- /**
- * @file
- * Handler for IRC capability ("CAP") commands
- */
- #include <assert.h>
- #include <string.h>
- #include <strings.h>
- #include "conn.h"
- #include "channel.h"
- #include "client-cap.h"
- #include "irc-write.h"
- #include "log.h"
- #include "login.h"
- #include "messages.h"
- #include "parse.h"
- #include "irc-cap.h"
- /* Local functions */
- /**
- * Set CAP negotiation status and mark client as "supports capabilities".
- *
- * @param Client The client to handle.
- */
- static void
- Set_CAP_Negotiation(CLIENT *Client)
- {
- assert(Client != NULL);
- if (Client_Type(Client) != CLIENT_USER)
- Client_CapAdd(Client, CLIENT_CAP_PENDING);
- Client_CapAdd(Client, CLIENT_CAP_SUPPORTED);
- }
- /**
- * Parse capability string and return numeric flag value.
- *
- * @param Args The string containing space-separated capability names.
- * @return Changed capability flags or 0 on error.
- */
- static int
- Parse_CAP(int Capabilities, char *Args)
- {
- static char tmp[COMMAND_LEN];
- char *ptr;
- assert(Args != NULL);
- strlcpy(tmp, Args, sizeof(tmp));
- ptr = strtok(tmp, " ");
- while (ptr) {
- if (*ptr == '-') {
- /* drop capabilities */
- ptr++;
- if (strcmp(ptr, "multi-prefix") == 0)
- Capabilities &= ~CLIENT_CAP_MULTI_PREFIX;
- else
- return -1;
- } else {
- /* request capabilities */
- if (strcmp(ptr, "multi-prefix") == 0)
- Capabilities |= CLIENT_CAP_MULTI_PREFIX;
- else
- return -1;
- }
- ptr = strtok(NULL, " ");
- }
- return Capabilities;
- }
- /**
- * Return textual representation of capability flags.
- *
- * Please note: this function returns a pointer to a global buffer and
- * therefore isn't thread safe!
- *
- * @param Capabilities Capability flags (bitmask).
- * @return Pointer to textual representation.
- */
- static char *
- Get_CAP_String(int Capabilities)
- {
- static char txt[COMMAND_LEN];
- txt[0] = '\0';
- if (Capabilities & CLIENT_CAP_MULTI_PREFIX)
- strlcat(txt, "multi-prefix ", sizeof(txt));
- return txt;
- }
- /**
- * Handler for the IRCv3 sub-command "CAP LS".
- *
- * @param Client The client from which this command has been received.
- * @param Arg Command argument or NULL.
- * @return CONNECTED or DISCONNECTED.
- */
- static bool
- Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg)
- {
- assert(Client != NULL);
- Set_CAP_Negotiation(Client);
- return IRC_WriteStrClient(Client,
- "CAP %s LS :multi-prefix",
- Client_ID(Client));
- }
- /**
- * Handler for the IRCv3 sub-command "CAP LIST".
- *
- * @param Client The client from which this command has been received.
- * @param Arg Command argument or NULL.
- * @return CONNECTED or DISCONNECTED.
- */
- static bool
- Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg)
- {
- assert(Client != NULL);
- return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client),
- Get_CAP_String(Client_Cap(Client)));
- }
- /**
- * Handler for the IRCv3 sub-command "CAP REQ".
- *
- * @param Client The client from which this command has been received.
- * @param Arg Command argument.
- * @return CONNECTED or DISCONNECTED.
- */
- static bool
- Handle_CAP_REQ(CLIENT *Client, char *Arg)
- {
- int new_cap;
- assert(Client != NULL);
- assert(Arg != NULL);
- Set_CAP_Negotiation(Client);
- new_cap = Parse_CAP(Client_Cap(Client), Arg);
- if (new_cap < 0)
- return IRC_WriteStrClient(Client, "CAP %s NAK :%s",
- Client_ID(Client), Arg);
- Client_CapSet(Client, new_cap);
- return IRC_WriteStrClient(Client, "CAP %s ACK :%s",
- Client_ID(Client), Arg);
- }
- /**
- * Handler for the IRCv3 sub-command "CAP ACK".
- *
- * @param Client The client from which this command has been received.
- * @param Arg Command argument.
- * @return CONNECTED or DISCONNECTED.
- */
- static bool
- Handle_CAP_ACK(UNUSED CLIENT *Client, UNUSED char *Arg)
- {
- assert(Client != NULL);
- assert(Arg != NULL);
- return CONNECTED;
- }
- /**
- * Handler for the IRCv3 sub-command "CAP CLEAR".
- *
- * @param Client The client from which this command has been received.
- * @return CONNECTED or DISCONNECTED.
- */
- static bool
- Handle_CAP_CLEAR(CLIENT *Client)
- {
- int cap_old;
- assert(Client != NULL);
- cap_old = Client_Cap(Client);
- if (cap_old & CLIENT_CAP_MULTI_PREFIX)
- Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX);
- return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client),
- Get_CAP_String(cap_old));
- }
- /**
- * Handler for the IRCv3 sub-command "CAP END".
- *
- * @param Client The client from which this command has been received.
- * @return CONNECTED or DISCONNECTED.
- */
- static bool
- Handle_CAP_END(CLIENT *Client)
- {
- assert(Client != NULL);
- if (Client_Type(Client) != CLIENT_USER) {
- /* User is still logging in ... */
- Client_CapDel(Client, CLIENT_CAP_PENDING);
- if (Client_Type(Client) == CLIENT_WAITCAPEND) {
- /* Only "CAP END" was missing: log in! */
- return Login_User(Client);
- }
- }
- return CONNECTED;
- }
- /* Global functions */
- /**
- * Handler for the IRCv3 command "CAP".
- *
- * @param Client The client from which this command has been received.
- * @param Req Request structure with prefix and all parameters.
- * @return CONNECTED or DISCONNECTED.
- */
- GLOBAL bool
- IRC_CAP(CLIENT *Client, REQUEST *Req)
- {
- assert(Client != NULL);
- assert(Req != NULL);
- LogDebug("Got \"%s %s\" command from \"%s\" ...",
- Req->command, Req->argv[0], Client_ID(Client));
- if (Req->argc == 1) {
- if (strcasecmp(Req->argv[0], "CLEAR") == 0)
- return Handle_CAP_CLEAR(Client);
- if (strcasecmp(Req->argv[0], "END") == 0)
- return Handle_CAP_END(Client);
- }
- if (Req->argc >= 1 && Req->argc <= 2) {
- if (strcasecmp(Req->argv[0], "LS") == 0)
- return Handle_CAP_LS(Client, Req->argv[1]);
- if (strcasecmp(Req->argv[0], "LIST") == 0)
- return Handle_CAP_LIST(Client, Req->argv[1]);
- }
- if (Req->argc == 2) {
- if (strcasecmp(Req->argv[0], "REQ") == 0)
- return Handle_CAP_REQ(Client, Req->argv[1]);
- if (strcasecmp(Req->argv[0], "ACK") == 0)
- return Handle_CAP_ACK(Client, Req->argv[1]);
- }
- return IRC_WriteErrClient(Client, ERR_INVALIDCAP_MSG,
- Client_ID(Client), Req->argv[0]);
- }
- /* -eof- */
|