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-write.h"
39 * Set CAP negotiation status and mark client as "supports capabilities".
41 * @param Client The client to handle.
44 Set_CAP_Negotiation(CLIENT *Client)
46 assert(Client != NULL);
48 if (Client_Type(Client) != CLIENT_USER)
49 Client_CapAdd(Client, CLIENT_CAP_PENDING);
50 Client_CapAdd(Client, CLIENT_CAP_SUPPORTED);
54 * Parse capability string and return numeric flag value.
56 * @param Args The string containing space-separated capability names.
57 * @return Changed capability flags or 0 on error.
60 Parse_CAP(int Capabilities, char *Args)
62 static char tmp[COMMAND_LEN];
67 strlcpy(tmp, Args, sizeof(tmp));
69 ptr = strtok(tmp, " ");
72 /* drop capabilities */
74 if (strcmp(ptr, "multi-prefix") == 0)
75 Capabilities &= ~CLIENT_CAP_MULTI_PREFIX;
79 /* request capabilities */
80 if (strcmp(ptr, "multi-prefix") == 0)
81 Capabilities |= CLIENT_CAP_MULTI_PREFIX;
85 ptr = strtok(NULL, " ");
92 * Return textual representation of capability flags.
94 * Please note: this function returns a pointer to a global buffer and
95 * therefore isn't thread safe!
97 * @param Capabilities Capability flags (bitmask).
98 * @return Pointer to textual representation.
101 Get_CAP_String(int Capabilities)
103 static char txt[COMMAND_LEN];
107 if (Capabilities & CLIENT_CAP_MULTI_PREFIX)
108 strlcat(txt, "multi-prefix ", sizeof(txt));
114 * Handler for the IRCv3 sub-command "CAP LS".
116 * @param Client The client from which this command has been received.
117 * @param Arg Command argument or NULL.
118 * @return CONNECTED or DISCONNECTED.
121 Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg)
123 assert(Client != NULL);
125 Set_CAP_Negotiation(Client);
127 return IRC_WriteStrClient(Client,
128 "CAP %s LS :multi-prefix",
133 * Handler for the IRCv3 sub-command "CAP LIST".
135 * @param Client The client from which this command has been received.
136 * @param Arg Command argument or NULL.
137 * @return CONNECTED or DISCONNECTED.
140 Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg)
142 assert(Client != NULL);
144 return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client),
145 Get_CAP_String(Client_Cap(Client)));
149 * Handler for the IRCv3 sub-command "CAP REQ".
151 * @param Client The client from which this command has been received.
152 * @param Arg Command argument.
153 * @return CONNECTED or DISCONNECTED.
156 Handle_CAP_REQ(CLIENT *Client, char *Arg)
160 assert(Client != NULL);
163 Set_CAP_Negotiation(Client);
165 new_cap = Parse_CAP(Client_Cap(Client), Arg);
168 return IRC_WriteStrClient(Client, "CAP %s NAK :%s",
169 Client_ID(Client), Arg);
171 Client_CapSet(Client, new_cap);
172 return IRC_WriteStrClient(Client, "CAP %s ACK :%s",
173 Client_ID(Client), Arg);
177 * Handler for the IRCv3 sub-command "CAP ACK".
179 * @param Client The client from which this command has been received.
180 * @param Arg Command argument.
181 * @return CONNECTED or DISCONNECTED.
184 Handle_CAP_ACK(UNUSED CLIENT *Client, UNUSED char *Arg)
186 assert(Client != NULL);
193 * Handler for the IRCv3 sub-command "CAP CLEAR".
195 * @param Client The client from which this command has been received.
196 * @return CONNECTED or DISCONNECTED.
199 Handle_CAP_CLEAR(CLIENT *Client)
203 assert(Client != NULL);
205 cap_old = Client_Cap(Client);
206 if (cap_old & CLIENT_CAP_MULTI_PREFIX)
207 Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX);
209 return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client),
210 Get_CAP_String(cap_old));
214 * Handler for the IRCv3 sub-command "CAP END".
216 * @param Client The client from which this command has been received.
217 * @return CONNECTED or DISCONNECTED.
220 Handle_CAP_END(CLIENT *Client)
222 assert(Client != NULL);
224 if (Client_Type(Client) != CLIENT_USER) {
225 /* User is still logging in ... */
226 Client_CapDel(Client, CLIENT_CAP_PENDING);
228 if (Client_Type(Client) == CLIENT_WAITCAPEND) {
229 /* Only "CAP END" was missing: log in! */
230 return Login_User(Client);
237 /* Global functions */
240 * Handler for the IRCv3 command "CAP".
242 * @param Client The client from which this command has been received.
243 * @param Req Request structure with prefix and all parameters.
244 * @return CONNECTED or DISCONNECTED.
247 IRC_CAP(CLIENT *Client, REQUEST *Req)
249 assert(Client != NULL);
252 /* Bad number of prameters? */
253 if (Req->argc < 1 || Req->argc > 2)
254 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
255 Client_ID(Client), Req->command);
257 LogDebug("Got \"%s %s\" command from \"%s\" ...",
258 Req->command, Req->argv[0], Client_ID(Client));
260 if (Req->argc == 1) {
261 if (strcasecmp(Req->argv[0], "CLEAR") == 0)
262 return Handle_CAP_CLEAR(Client);
263 if (strcasecmp(Req->argv[0], "END") == 0)
264 return Handle_CAP_END(Client);
266 if (Req->argc >= 1 && Req->argc <= 2) {
267 if (strcasecmp(Req->argv[0], "LS") == 0)
268 return Handle_CAP_LS(Client, Req->argv[1]);
269 if (strcasecmp(Req->argv[0], "LIST") == 0)
270 return Handle_CAP_LIST(Client, Req->argv[1]);
272 if (Req->argc == 2) {
273 if (strcasecmp(Req->argv[0], "REQ") == 0)
274 return Handle_CAP_REQ(Client, Req->argv[1]);
275 if (strcasecmp(Req->argv[0], "ACK") == 0)
276 return Handle_CAP_ACK(Client, Req->argv[1]);
279 return IRC_WriteStrClient(Client, ERR_INVALIDCAP_MSG,
280 Client_ID(Client), Req->argv[0]);