2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2013 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
26 #include "client-cap.h"
27 #include "irc-macros.h"
28 #include "irc-write.h"
40 * Set CAP negotiation status and mark client as "supports capabilities".
42 * @param Client The client to handle.
45 Set_CAP_Negotiation(CLIENT *Client)
47 assert(Client != NULL);
49 if (Client_Type(Client) != CLIENT_USER)
50 Client_CapAdd(Client, CLIENT_CAP_PENDING);
51 Client_CapAdd(Client, CLIENT_CAP_SUPPORTED);
55 * Parse capability string and return numeric flag value.
57 * @param Args The string containing space-separated capability names.
58 * @return Changed capability flags or 0 on error.
61 Parse_CAP(int Capabilities, char *Args)
63 static char tmp[COMMAND_LEN];
68 strlcpy(tmp, Args, sizeof(tmp));
70 ptr = strtok(tmp, " ");
73 /* drop capabilities */
75 if (strcmp(ptr, "multi-prefix") == 0)
76 Capabilities &= ~CLIENT_CAP_MULTI_PREFIX;
80 /* request capabilities */
81 if (strcmp(ptr, "multi-prefix") == 0)
82 Capabilities |= CLIENT_CAP_MULTI_PREFIX;
86 ptr = strtok(NULL, " ");
93 * Return textual representation of capability flags.
95 * Please note: this function returns a pointer to a global buffer and
96 * therefore isn't thread safe!
98 * @param Capabilities Capability flags (bitmask).
99 * @return Pointer to textual representation.
102 Get_CAP_String(int Capabilities)
104 static char txt[COMMAND_LEN];
108 if (Capabilities & CLIENT_CAP_MULTI_PREFIX)
109 strlcat(txt, "multi-prefix ", sizeof(txt));
115 * Handler for the IRCv3 sub-command "CAP LS".
117 * @param Client The client from which this command has been received.
118 * @param Arg Command argument or NULL.
119 * @return CONNECTED or DISCONNECTED.
122 Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg)
124 assert(Client != NULL);
126 Set_CAP_Negotiation(Client);
128 return IRC_WriteStrClient(Client,
129 "CAP %s LS :multi-prefix",
134 * Handler for the IRCv3 sub-command "CAP LIST".
136 * @param Client The client from which this command has been received.
137 * @param Arg Command argument or NULL.
138 * @return CONNECTED or DISCONNECTED.
141 Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg)
143 assert(Client != NULL);
145 return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client),
146 Get_CAP_String(Client_Cap(Client)));
150 * Handler for the IRCv3 sub-command "CAP REQ".
152 * @param Client The client from which this command has been received.
153 * @param Arg Command argument.
154 * @return CONNECTED or DISCONNECTED.
157 Handle_CAP_REQ(CLIENT *Client, char *Arg)
161 assert(Client != NULL);
164 Set_CAP_Negotiation(Client);
166 new_cap = Parse_CAP(Client_Cap(Client), Arg);
169 return IRC_WriteStrClient(Client, "CAP %s NAK :%s",
170 Client_ID(Client), Arg);
172 Client_CapSet(Client, new_cap);
173 return IRC_WriteStrClient(Client, "CAP %s ACK :%s",
174 Client_ID(Client), Arg);
178 * Handler for the IRCv3 sub-command "CAP ACK".
180 * @param Client The client from which this command has been received.
181 * @param Arg Command argument.
182 * @return CONNECTED or DISCONNECTED.
185 Handle_CAP_ACK(UNUSED CLIENT *Client, UNUSED char *Arg)
187 assert(Client != NULL);
194 * Handler for the IRCv3 sub-command "CAP CLEAR".
196 * @param Client The client from which this command has been received.
197 * @return CONNECTED or DISCONNECTED.
200 Handle_CAP_CLEAR(CLIENT *Client)
204 assert(Client != NULL);
206 cap_old = Client_Cap(Client);
207 if (cap_old & CLIENT_CAP_MULTI_PREFIX)
208 Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX);
210 return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client),
211 Get_CAP_String(cap_old));
215 * Handler for the IRCv3 sub-command "CAP END".
217 * @param Client The client from which this command has been received.
218 * @return CONNECTED or DISCONNECTED.
221 Handle_CAP_END(CLIENT *Client)
223 assert(Client != NULL);
225 if (Client_Type(Client) != CLIENT_USER) {
226 /* User is still logging in ... */
227 Client_CapDel(Client, CLIENT_CAP_PENDING);
229 if (Client_Type(Client) == CLIENT_WAITCAPEND) {
230 /* Only "CAP END" was missing: log in! */
231 return Login_User(Client);
238 /* Global functions */
241 * Handler for the IRCv3 command "CAP".
243 * @param Client The client from which this command has been received.
244 * @param Req Request structure with prefix and all parameters.
245 * @return CONNECTED or DISCONNECTED.
248 IRC_CAP(CLIENT *Client, REQUEST *Req)
250 assert(Client != NULL);
253 LogDebug("Got \"%s %s\" command from \"%s\" ...",
254 Req->command, Req->argv[0], Client_ID(Client));
256 if (Req->argc == 1) {
257 if (strcasecmp(Req->argv[0], "CLEAR") == 0)
258 return Handle_CAP_CLEAR(Client);
259 if (strcasecmp(Req->argv[0], "END") == 0)
260 return Handle_CAP_END(Client);
262 if (Req->argc >= 1 && Req->argc <= 2) {
263 if (strcasecmp(Req->argv[0], "LS") == 0)
264 return Handle_CAP_LS(Client, Req->argv[1]);
265 if (strcasecmp(Req->argv[0], "LIST") == 0)
266 return Handle_CAP_LIST(Client, Req->argv[1]);
268 if (Req->argc == 2) {
269 if (strcasecmp(Req->argv[0], "REQ") == 0)
270 return Handle_CAP_REQ(Client, Req->argv[1]);
271 if (strcasecmp(Req->argv[0], "ACK") == 0)
272 return Handle_CAP_ACK(Client, Req->argv[1]);
275 return IRC_WriteErrClient(Client, ERR_INVALIDCAP_MSG,
276 Client_ID(Client), Req->argv[0]);