2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001-2012 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"
36 bool Handle_CAP_LS PARAMS((CLIENT *Client, char *Arg));
37 bool Handle_CAP_LIST PARAMS((CLIENT *Client, char *Arg));
38 bool Handle_CAP_REQ PARAMS((CLIENT *Client, char *Arg));
39 bool Handle_CAP_ACK PARAMS((CLIENT *Client, char *Arg));
40 bool Handle_CAP_CLEAR PARAMS((CLIENT *Client));
41 bool Handle_CAP_END PARAMS((CLIENT *Client));
43 void Set_CAP_Negotiation PARAMS((CLIENT *Client));
45 int Parse_CAP PARAMS((int Capabilities, char *Args));
46 char *Get_CAP_String PARAMS((int Capabilities));
49 * Handler for the IRCv3 "CAP" command.
51 * @param Client The client from which this command has been received.
52 * @param Req Request structure with prefix and all parameters.
53 * @returns CONNECTED or DISCONNECTED.
56 IRC_CAP(CLIENT *Client, REQUEST *Req)
58 assert(Client != NULL);
61 /* Bad number of prameters? */
62 if (Req->argc < 1 || Req->argc > 2)
63 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
64 Client_ID(Client), Req->command);
66 LogDebug("Got \"%s %s\" command from \"%s\" ...",
67 Req->command, Req->argv[0], Client_ID(Client));
70 if (strcasecmp(Req->argv[0], "CLEAR") == 0)
71 return Handle_CAP_CLEAR(Client);
72 if (strcasecmp(Req->argv[0], "END") == 0)
73 return Handle_CAP_END(Client);
75 if (Req->argc >= 1 && Req->argc <= 2) {
76 if (strcasecmp(Req->argv[0], "LS") == 0)
77 return Handle_CAP_LS(Client, Req->argv[1]);
78 if (strcasecmp(Req->argv[0], "LIST") == 0)
79 return Handle_CAP_LIST(Client, Req->argv[1]);
82 if (strcasecmp(Req->argv[0], "REQ") == 0)
83 return Handle_CAP_REQ(Client, Req->argv[1]);
84 if (strcasecmp(Req->argv[0], "ACK") == 0)
85 return Handle_CAP_ACK(Client, Req->argv[1]);
88 return IRC_WriteStrClient(Client, ERR_INVALIDCAP_MSG,
89 Client_ID(Client), Req->argv[0]);
93 * Handler for the "CAP LS" command.
95 * @param Client The client from which this command has been received.
96 * @param Arg Command argument or NULL.
97 * @returns CONNECTED or DISCONNECTED.
100 Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg)
102 assert(Client != NULL);
104 Set_CAP_Negotiation(Client);
106 return IRC_WriteStrClient(Client,
107 "CAP %s LS :multi-prefix",
112 * Handler for the "CAP LIST" command.
114 * @param Client The client from which this command has been received.
115 * @param Arg Command argument or NULL.
116 * @returns CONNECTED or DISCONNECTED.
119 Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg)
121 assert(Client != NULL);
123 return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client),
124 Get_CAP_String(Client_Cap(Client)));
128 * Handler for the "CAP REQ" command.
130 * @param Client The client from which this command has been received.
131 * @param Arg Command argument.
132 * @returns CONNECTED or DISCONNECTED.
135 Handle_CAP_REQ(CLIENT *Client, char *Arg)
139 assert(Client != NULL);
142 Set_CAP_Negotiation(Client);
144 new_cap = Parse_CAP(Client_Cap(Client), Arg);
147 return IRC_WriteStrClient(Client, "CAP %s NAK :%s",
148 Client_ID(Client), Arg);
150 Client_CapSet(Client, new_cap);
151 return IRC_WriteStrClient(Client, "CAP %s ACK :%s",
152 Client_ID(Client), Arg);
156 * Handler for the "CAP ACK" command.
158 * @param Client The client from which this command has been received.
159 * @param Arg Command argument.
160 * @returns CONNECTED or DISCONNECTED.
163 Handle_CAP_ACK(UNUSED CLIENT *Client, UNUSED char *Arg)
165 assert(Client != NULL);
172 * Handler for the "CAP CLEAR" command.
174 * @param Client The client from which this command has been received.
175 * @returns CONNECTED or DISCONNECTED.
178 Handle_CAP_CLEAR(CLIENT *Client)
182 assert(Client != NULL);
184 cap_old = Client_Cap(Client);
185 if (cap_old & CLIENT_CAP_MULTI_PREFIX)
186 Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX);
188 return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client),
189 Get_CAP_String(cap_old));
193 * Handler for the "CAP END" command.
195 * @param Client The client from which this command has been received.
196 * @returns CONNECTED or DISCONNECTED.
199 Handle_CAP_END(CLIENT *Client)
201 assert(Client != NULL);
203 if (Client_Type(Client) != CLIENT_USER) {
204 /* User is still logging in ... */
205 Client_CapDel(Client, CLIENT_CAP_PENDING);
207 if (Client_Type(Client) == CLIENT_WAITCAPEND) {
208 /* Only "CAP END" was missing: log in! */
209 return Login_User(Client);
217 * Set CAP negotiation status and mark client as "supports capabilities".
219 * @param Client The client to handle.
222 Set_CAP_Negotiation(CLIENT *Client)
224 assert(Client != NULL);
226 if (Client_Type(Client) != CLIENT_USER)
227 Client_CapAdd(Client, CLIENT_CAP_PENDING);
228 Client_CapAdd(Client, CLIENT_CAP_SUPPORTED);
232 * Parse capability string and return numeric flag value.
234 * @param Args The string containing space-separated capability names.
235 * @return Changed capability flags or 0 on error.
238 Parse_CAP(int Capabilities, char *Args)
240 static char tmp[COMMAND_LEN];
243 assert(Args != NULL);
245 strlcpy(tmp, Args, sizeof(tmp));
247 ptr = strtok(tmp, " ");
250 /* drop capabilities */
252 if (strcmp(ptr, "multi-prefix") == 0)
253 Capabilities &= ~CLIENT_CAP_MULTI_PREFIX;
257 /* request capabilities */
258 if (strcmp(ptr, "multi-prefix") == 0)
259 Capabilities |= CLIENT_CAP_MULTI_PREFIX;
263 ptr = strtok(NULL, " ");
270 * Return textual representation of capability flags.
272 * Please note: this function returns a pointer to a global buffer and
273 * therefore isn't thread safe!
275 * @param Capabilities Capability flags (bitmask).
276 * @return Pointer to textual representation.
279 Get_CAP_String(int Capabilities)
281 static char txt[COMMAND_LEN];
285 if (Capabilities & CLIENT_CAP_MULTI_PREFIX)
286 strlcat(txt, "multi-prefix ", sizeof(txt));