Annotation of ircnowd/src/ngircd/irc-cap.c, Revision 1.1.1.1
1.1 tomglok 1: /*
2: * ngIRCd -- The Next Generation IRC Daemon
3: * Copyright (c)2001-2014 Alexander Barton (alex@barton.de) and Contributors.
4: *
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.
10: */
11:
12: #include "portab.h"
13:
14: /**
15: * @file
16: * Handler for IRC capability ("CAP") commands
17: */
18:
19: #include <assert.h>
20: #include <string.h>
21: #include <strings.h>
22:
23: #include "conn.h"
24: #include "channel.h"
25: #include "client-cap.h"
26: #include "irc-write.h"
27: #include "log.h"
28: #include "login.h"
29: #include "messages.h"
30: #include "parse.h"
31:
32: #include "irc-cap.h"
33:
34: /* Local functions */
35:
36: /**
37: * Set CAP negotiation status and mark client as "supports capabilities".
38: *
39: * @param Client The client to handle.
40: */
41: static void
42: Set_CAP_Negotiation(CLIENT *Client)
43: {
44: assert(Client != NULL);
45:
46: if (Client_Type(Client) != CLIENT_USER)
47: Client_CapAdd(Client, CLIENT_CAP_PENDING);
48: Client_CapAdd(Client, CLIENT_CAP_SUPPORTED);
49: }
50:
51: /**
52: * Parse capability string and return numeric flag value.
53: *
54: * @param Args The string containing space-separated capability names.
55: * @return Changed capability flags or 0 on error.
56: */
57: static int
58: Parse_CAP(int Capabilities, char *Args)
59: {
60: static char tmp[COMMAND_LEN];
61: char *ptr;
62:
63: assert(Args != NULL);
64:
65: strlcpy(tmp, Args, sizeof(tmp));
66:
67: ptr = strtok(tmp, " ");
68: while (ptr) {
69: if (*ptr == '-') {
70: /* drop capabilities */
71: ptr++;
72: if (strcmp(ptr, "multi-prefix") == 0)
73: Capabilities &= ~CLIENT_CAP_MULTI_PREFIX;
74: else
75: return -1;
76: } else {
77: /* request capabilities */
78: if (strcmp(ptr, "multi-prefix") == 0)
79: Capabilities |= CLIENT_CAP_MULTI_PREFIX;
80: else
81: return -1;
82: }
83: ptr = strtok(NULL, " ");
84: }
85:
86: return Capabilities;
87: }
88:
89: /**
90: * Return textual representation of capability flags.
91: *
92: * Please note: this function returns a pointer to a global buffer and
93: * therefore isn't thread safe!
94: *
95: * @param Capabilities Capability flags (bitmask).
96: * @return Pointer to textual representation.
97: */
98: static char *
99: Get_CAP_String(int Capabilities)
100: {
101: static char txt[COMMAND_LEN];
102:
103: txt[0] = '\0';
104:
105: if (Capabilities & CLIENT_CAP_MULTI_PREFIX)
106: strlcat(txt, "multi-prefix ", sizeof(txt));
107:
108: return txt;
109: }
110:
111: /**
112: * Handler for the IRCv3 sub-command "CAP LS".
113: *
114: * @param Client The client from which this command has been received.
115: * @param Arg Command argument or NULL.
116: * @return CONNECTED or DISCONNECTED.
117: */
118: static bool
119: Handle_CAP_LS(CLIENT *Client, UNUSED char *Arg)
120: {
121: assert(Client != NULL);
122:
123: Set_CAP_Negotiation(Client);
124:
125: return IRC_WriteStrClient(Client,
126: "CAP %s LS :multi-prefix",
127: Client_ID(Client));
128: }
129:
130: /**
131: * Handler for the IRCv3 sub-command "CAP LIST".
132: *
133: * @param Client The client from which this command has been received.
134: * @param Arg Command argument or NULL.
135: * @return CONNECTED or DISCONNECTED.
136: */
137: static bool
138: Handle_CAP_LIST(CLIENT *Client, UNUSED char *Arg)
139: {
140: assert(Client != NULL);
141:
142: return IRC_WriteStrClient(Client, "CAP %s LIST :%s", Client_ID(Client),
143: Get_CAP_String(Client_Cap(Client)));
144: }
145:
146: /**
147: * Handler for the IRCv3 sub-command "CAP REQ".
148: *
149: * @param Client The client from which this command has been received.
150: * @param Arg Command argument.
151: * @return CONNECTED or DISCONNECTED.
152: */
153: static bool
154: Handle_CAP_REQ(CLIENT *Client, char *Arg)
155: {
156: int new_cap;
157:
158: assert(Client != NULL);
159: assert(Arg != NULL);
160:
161: Set_CAP_Negotiation(Client);
162:
163: new_cap = Parse_CAP(Client_Cap(Client), Arg);
164:
165: if (new_cap < 0)
166: return IRC_WriteStrClient(Client, "CAP %s NAK :%s",
167: Client_ID(Client), Arg);
168:
169: Client_CapSet(Client, new_cap);
170: return IRC_WriteStrClient(Client, "CAP %s ACK :%s",
171: Client_ID(Client), Arg);
172: }
173:
174: /**
175: * Handler for the IRCv3 sub-command "CAP ACK".
176: *
177: * @param Client The client from which this command has been received.
178: * @param Arg Command argument.
179: * @return CONNECTED or DISCONNECTED.
180: */
181: static bool
182: Handle_CAP_ACK(UNUSED CLIENT *Client, UNUSED char *Arg)
183: {
184: assert(Client != NULL);
185: assert(Arg != NULL);
186:
187: return CONNECTED;
188: }
189:
190: /**
191: * Handler for the IRCv3 sub-command "CAP CLEAR".
192: *
193: * @param Client The client from which this command has been received.
194: * @return CONNECTED or DISCONNECTED.
195: */
196: static bool
197: Handle_CAP_CLEAR(CLIENT *Client)
198: {
199: int cap_old;
200:
201: assert(Client != NULL);
202:
203: cap_old = Client_Cap(Client);
204: if (cap_old & CLIENT_CAP_MULTI_PREFIX)
205: Client_CapDel(Client, CLIENT_CAP_MULTI_PREFIX);
206:
207: return IRC_WriteStrClient(Client, "CAP %s ACK :%s", Client_ID(Client),
208: Get_CAP_String(cap_old));
209: }
210:
211: /**
212: * Handler for the IRCv3 sub-command "CAP END".
213: *
214: * @param Client The client from which this command has been received.
215: * @return CONNECTED or DISCONNECTED.
216: */
217: static bool
218: Handle_CAP_END(CLIENT *Client)
219: {
220: assert(Client != NULL);
221:
222: if (Client_Type(Client) != CLIENT_USER) {
223: /* User is still logging in ... */
224: Client_CapDel(Client, CLIENT_CAP_PENDING);
225:
226: if (Client_Type(Client) == CLIENT_WAITCAPEND) {
227: /* Only "CAP END" was missing: log in! */
228: return Login_User(Client);
229: }
230: }
231:
232: return CONNECTED;
233: }
234:
235: /* Global functions */
236:
237: /**
238: * Handler for the IRCv3 command "CAP".
239: *
240: * @param Client The client from which this command has been received.
241: * @param Req Request structure with prefix and all parameters.
242: * @return CONNECTED or DISCONNECTED.
243: */
244: GLOBAL bool
245: IRC_CAP(CLIENT *Client, REQUEST *Req)
246: {
247: assert(Client != NULL);
248: assert(Req != NULL);
249:
250: LogDebug("Got \"%s %s\" command from \"%s\" ...",
251: Req->command, Req->argv[0], Client_ID(Client));
252:
253: if (Req->argc == 1) {
254: if (strcasecmp(Req->argv[0], "CLEAR") == 0)
255: return Handle_CAP_CLEAR(Client);
256: if (strcasecmp(Req->argv[0], "END") == 0)
257: return Handle_CAP_END(Client);
258: }
259: if (Req->argc >= 1 && Req->argc <= 2) {
260: if (strcasecmp(Req->argv[0], "LS") == 0)
261: return Handle_CAP_LS(Client, Req->argv[1]);
262: if (strcasecmp(Req->argv[0], "LIST") == 0)
263: return Handle_CAP_LIST(Client, Req->argv[1]);
264: }
265: if (Req->argc == 2) {
266: if (strcasecmp(Req->argv[0], "REQ") == 0)
267: return Handle_CAP_REQ(Client, Req->argv[1]);
268: if (strcasecmp(Req->argv[0], "ACK") == 0)
269: return Handle_CAP_ACK(Client, Req->argv[1]);
270: }
271:
272: return IRC_WriteErrClient(Client, ERR_INVALIDCAP_MSG,
273: Client_ID(Client), Req->argv[0]);
274: }
275:
276: /* -eof- */
CVSweb