2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
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.
16 * Handler for IRC capability ("CAP") commands
25 #include "client-cap.h"
26 #include "irc-write.h"
35 * Set CAP negotiation status and mark client as "supports capabilities".
37 * @param Client The client to handle.
40 Set_CAP_Negotiation(CLIENT *Client)
42 assert(Client != NULL);
44 if (Client_Type(Client) != CLIENT_USER)
45 Client_CapAdd(Client, CLIENT_CAP_PENDING);
46 Client_CapAdd(Client, CLIENT_CAP_SUPPORTED);
50 * Parse capability string and return numeric flag value.
52 * @param Args The string containing space-separated capability names.
53 * @return Changed capability flags or 0 on error.
56 Parse_CAP(int Capabilities, char *Args)
58 static char tmp[COMMAND_LEN];
63 strlcpy(tmp, Args, sizeof(tmp));
65 ptr = strtok(tmp, " ");
68 /* drop capabilities */
70 if (strcmp(ptr, "multi-prefix") == 0)
71 Capabilities &= ~CLIENT_CAP_MULTI_PREFIX;
75 /* request capabilities */
76 if (strcmp(ptr, "multi-prefix") == 0)
77 Capabilities |= CLIENT_CAP_MULTI_PREFIX;
81 ptr = strtok(NULL, " ");
88 * Return textual representation of capability flags.
90 * Please note: this function returns a pointer to a global buffer and
91 * therefore isn't thread safe!
93 * @param Capabilities Capability flags (bitmask).
94 * @return Pointer to textual representation.
97 Get_CAP_String(int Capabilities)
99 static char txt[COMMAND_LEN];
103 if (Capabilities & CLIENT_CAP_MULTI_PREFIX)
104 strlcat(txt, "multi-prefix ", sizeof(txt));
110 * Handler for the IRCv3 sub-command "CAP LS".
112 * @param Client The client from which this command has been received.
113 * @param Arg Command argument or NULL.
114 * @return CONNECTED or DISCONNECTED.
117 Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg)
119 assert(Client != NULL);
121 Set_CAP_Negotiation(Client);
123 return IRC_WriteStrClient(Client,
124 "CAP %s LS :multi-prefix",
129 * Handler for the IRCv3 sub-command "CAP LIST".
131 * @param Client The client from which this command has been received.
132 * @param Arg Command argument or NULL.
133 * @return CONNECTED or DISCONNECTED.
136 Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg)
138 assert(Client != NULL);
140 return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client),
141 Get_CAP_String(Client_Cap(Client)));
145 * Handler for the IRCv3 sub-command "CAP REQ".
147 * @param Client The client from which this command has been received.
148 * @param Arg Command argument.
149 * @return CONNECTED or DISCONNECTED.
152 Handle_CAP_REQ(CLIENT *Client, char *Arg)
156 assert(Client != NULL);
159 Set_CAP_Negotiation(Client);
161 new_cap = Parse_CAP(Client_Cap(Client), Arg);
164 return IRC_WriteStrClient(Client, "CAP %s NAK :%s",
165 Client_ID(Client), Arg);
167 Client_CapSet(Client, new_cap);
168 return IRC_WriteStrClient(Client, "CAP %s ACK :%s",
169 Client_ID(Client), Arg);
173 * Handler for the IRCv3 sub-command "CAP ACK".
175 * @param Client The client from which this command has been received.
176 * @param Arg Command argument.
177 * @return CONNECTED or DISCONNECTED.
180 Handle_CAP_ACK(UNUSED CLIENT *Client, UNUSED char *Arg)
182 assert(Client != NULL);
189 * Handler for the IRCv3 sub-command "CAP CLEAR".
191 * @param Client The client from which this command has been received.
192 * @return CONNECTED or DISCONNECTED.
195 Handle_CAP_CLEAR(CLIENT *Client)
199 assert(Client != NULL);
201 cap_old = Client_Cap(Client);
202 if (cap_old & CLIENT_CAP_MULTI_PREFIX)
203 Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX);
205 return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client),
206 Get_CAP_String(cap_old));
210 * Handler for the IRCv3 sub-command "CAP END".
212 * @param Client The client from which this command has been received.
213 * @return CONNECTED or DISCONNECTED.
216 Handle_CAP_END(CLIENT *Client)
218 assert(Client != NULL);
220 if (Client_Type(Client) != CLIENT_USER) {
221 /* User is still logging in ... */
222 Client_CapDel(Client, CLIENT_CAP_PENDING);
224 if (Client_Type(Client) == CLIENT_WAITCAPEND) {
225 /* Only "CAP END" was missing: log in! */
226 return Login_User(Client);
233 /* Global functions */
236 * Handler for the IRCv3 command "CAP".
238 * @param Client The client from which this command has been received.
239 * @param Req Request structure with prefix and all parameters.
240 * @return CONNECTED or DISCONNECTED.
243 IRC_CAP(CLIENT *Client, REQUEST *Req)
245 assert(Client != NULL);
248 LogDebug("Got \"%s %s\" command from \"%s\" ...",
249 Req->command, Req->argv[0], Client_ID(Client));
251 if (Req->argc == 1) {
252 if (strcasecmp(Req->argv[0], "CLEAR") == 0)
253 return Handle_CAP_CLEAR(Client);
254 if (strcasecmp(Req->argv[0], "END") == 0)
255 return Handle_CAP_END(Client);
257 if (Req->argc >= 1 && Req->argc <= 2) {
258 if (strcasecmp(Req->argv[0], "LS") == 0)
259 return Handle_CAP_LS(Client, Req->argv[1]);
260 if (strcasecmp(Req->argv[0], "LIST") == 0)
261 return Handle_CAP_LIST(Client, Req->argv[1]);
263 if (Req->argc == 2) {
264 if (strcasecmp(Req->argv[0], "REQ") == 0)
265 return Handle_CAP_REQ(Client, Req->argv[1]);
266 if (strcasecmp(Req->argv[0], "ACK") == 0)
267 return Handle_CAP_ACK(Client, Req->argv[1]);
270 return IRC_WriteErrClient(Client, ERR_INVALIDCAP_MSG,
271 Client_ID(Client), Req->argv[0]);