1 |
/* |
2 |
* m_flags.c: Implements comstud-style mode flags. |
3 |
* |
4 |
* Copyright 2002 by W. Campbell and the ircd-hybrid development team |
5 |
* |
6 |
* Redistribution and use in source and binary forms, with or without |
7 |
* modification, are permitted provided that the following conditions are |
8 |
* met: |
9 |
* |
10 |
* 1.Redistributions of source code must retain the above copyright notice, |
11 |
* this list of conditions and the following disclaimer. |
12 |
* 2.Redistributions in binary form must reproduce the above copyright |
13 |
* notice, this list of conditions and the following disclaimer in the |
14 |
* documentation and/or other materials provided with the distribution. |
15 |
* 3.The name of the author may not be used to endorse or promote products |
16 |
* derived from this software without specific prior written permission. |
17 |
* |
18 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 |
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, |
22 |
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
24 |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
26 |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
27 |
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
28 |
* POSSIBILITY OF SUCH DAMAGE. |
29 |
* |
30 |
* $Id: m_flags.c 801 2006-08-30 16:54:25Z adx $ |
31 |
*/ |
32 |
|
33 |
/* List of ircd includes from ../include/ */ |
34 |
#include "stdinc.h" |
35 |
#include "conf/conf.h" |
36 |
#include "handlers.h" |
37 |
#include "client.h" |
38 |
#include "common.h" /* FALSE bleah */ |
39 |
#include "ircd.h" |
40 |
#include "numeric.h" |
41 |
#include "server.h" |
42 |
#include "send.h" |
43 |
#include "msg.h" |
44 |
#include "parse.h" |
45 |
#include "user.h" /* send_umode_out() */ |
46 |
|
47 |
static void m_flags(struct Client *, struct Client *, int, char *[]); |
48 |
static void mo_flags(struct Client *, struct Client *, int, char *[]); |
49 |
|
50 |
static char *set_flags_to_string(struct Client *); |
51 |
static char *unset_flags_to_string(struct Client *); |
52 |
|
53 |
struct Message flags_msgtab = { |
54 |
"FLAGS", 0, 0, 0, 0, MFLG_SLOW, 0, |
55 |
{m_unregistered, m_flags, m_ignore, m_ignore, mo_flags, m_ignore} |
56 |
}; |
57 |
|
58 |
INIT_MODULE(m_flags, "$Revision: 801 $") |
59 |
{ |
60 |
mod_add_cmd(&flags_msgtab); |
61 |
} |
62 |
|
63 |
CLEANUP_MODULE |
64 |
{ |
65 |
mod_del_cmd(&flags_msgtab); |
66 |
} |
67 |
|
68 |
/* FLAGS requires it's own mini parser, since the last parameter in it can |
69 |
* contain a number of FLAGS. CS handles FLAGS mode1 mode2 OR |
70 |
* FLAGS :mode1 mode2, but not both mixed. |
71 |
* |
72 |
* The best way to match a flag to a mode is with a simple table |
73 |
*/ |
74 |
|
75 |
static struct FlagTable |
76 |
{ |
77 |
const char *name; |
78 |
unsigned int mode; |
79 |
int oper; |
80 |
} flag_table[] = { |
81 |
/* name mode it represents oper only? */ |
82 |
{ "OWALLOPS", UMODE_OPERWALL, 1 }, |
83 |
{ "SWALLOPS", UMODE_WALLOP, 0 }, |
84 |
{ "STATSNOTICES", UMODE_SPY, 1 }, |
85 |
/* We don't have a separate OKILL and SKILL modes */ |
86 |
{ "OKILLS", UMODE_SKILL, 0 }, |
87 |
{ "SKILLS", UMODE_SKILL, 0 }, |
88 |
{ "SNOTICES", UMODE_SERVNOTICE, 0 }, |
89 |
/* We don't have separate client connect and disconnect modes */ |
90 |
{ "CLICONNECTS", UMODE_CCONN, 1 }, |
91 |
{ "CLIDISCONNECTS", UMODE_CCONN, 1 }, |
92 |
/* I'm taking a wild guess here... */ |
93 |
{ "THROTTLES", UMODE_REJ, 1 }, |
94 |
#if 0 |
95 |
/* This one is special...controlled via an oper block option */ |
96 |
{ "NICKCHANGES", UMODE_NCHANGE, 1 }, |
97 |
/* NICKCHANGES must be checked for separately */ |
98 |
#endif |
99 |
/* I'm assuming this is correct... */ |
100 |
{ "IPMISMATCHES", UMODE_UNAUTH, 1 }, |
101 |
{ "LWALLOPS", UMODE_LOCOPS, 1 }, |
102 |
/* These aren't separate on Hybrid */ |
103 |
{ "CONNECTS", UMODE_EXTERNAL, 1 }, |
104 |
{ "SQUITS", UMODE_EXTERNAL, 1 }, |
105 |
/* Now we have our Hybrid specific flags */ |
106 |
{ "FULL", UMODE_FULL, 1 }, |
107 |
/* Not in CS, but we might as well put it here */ |
108 |
{ "INVISIBLE", UMODE_INVISIBLE, 0 }, |
109 |
{ "BOTS", UMODE_BOTS, 1 }, |
110 |
{ "CALLERID", UMODE_CALLERID, 0 }, |
111 |
{ "UNAUTH", UMODE_UNAUTH, 1 }, |
112 |
{ "DEBUG", UMODE_DEBUG, 1 }, |
113 |
{ NULL, 0, 0 } |
114 |
}; |
115 |
|
116 |
/* We won't control CALLERID or INVISIBLE in here */ |
117 |
|
118 |
#define FL_ALL_USER_FLAGS (UMODE_WALLOP | UMODE_SKILL | UMODE_SERVNOTICE ) |
119 |
|
120 |
/* and we don't control NCHANGES here either */ |
121 |
|
122 |
#define FL_ALL_OPER_FLAGS (FL_ALL_USER_FLAGS | UMODE_CCONN | UMODE_REJ |\ |
123 |
UMODE_FULL | UMODE_SPY | UMODE_DEBUG |\ |
124 |
UMODE_OPERWALL | UMODE_BOTS | UMODE_EXTERNAL |\ |
125 |
UMODE_UNAUTH | UMODE_LOCOPS ) |
126 |
|
127 |
/* m_flags() |
128 |
* |
129 |
* parv[0] = sender prefix |
130 |
* parv[1] = parameter |
131 |
*/ |
132 |
static void |
133 |
m_flags(struct Client *client_p, struct Client *source_p, |
134 |
int parc, char *parv[]) |
135 |
{ |
136 |
int i,j; |
137 |
int isadd; |
138 |
int isgood; |
139 |
unsigned int setflags; |
140 |
char *p; |
141 |
char *flag; |
142 |
|
143 |
if (parc < 2) |
144 |
{ |
145 |
/* Generate a list of what flags you have and what you are missing, |
146 |
** and send it to the user |
147 |
*/ |
148 |
sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", |
149 |
me.name, parv[0], set_flags_to_string(source_p)); |
150 |
sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", |
151 |
me.name, parv[0], unset_flags_to_string(source_p)); |
152 |
return; |
153 |
} |
154 |
|
155 |
/* Preserve the current flags */ |
156 |
setflags = source_p->umodes; |
157 |
|
158 |
/* XXX - change this to support a multiple last parameter like ISON */ |
159 |
|
160 |
for (i = 1; i < parc; i++) |
161 |
{ |
162 |
for (flag = strtoken(&p, parv[i], " "); flag; |
163 |
flag = strtoken(&p, NULL, " ")) |
164 |
{ |
165 |
/* We default to being in ADD mode */ |
166 |
isadd = 1; |
167 |
|
168 |
/* We default to being in BAD mode */ |
169 |
isgood = 0; |
170 |
|
171 |
if (!isalpha(*flag)) |
172 |
{ |
173 |
if (*flag == '-') |
174 |
isadd = 0; |
175 |
else if (*flag == '+') |
176 |
isadd = 1; |
177 |
++flag; |
178 |
} |
179 |
|
180 |
/* support ALL here */ |
181 |
if (!irccmp(flag, "ALL")) |
182 |
{ |
183 |
if (isadd) |
184 |
source_p->umodes |= FL_ALL_USER_FLAGS; |
185 |
else |
186 |
source_p->umodes &= ~FL_ALL_USER_FLAGS; |
187 |
sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", |
188 |
me.name, parv[0], set_flags_to_string(source_p)); |
189 |
sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", |
190 |
me.name, parv[0], unset_flags_to_string(source_p)); |
191 |
send_umode_out(client_p, source_p, setflags); |
192 |
return; |
193 |
} |
194 |
|
195 |
for (j = 0; flag_table[j].name; j++) |
196 |
{ |
197 |
if (!flag_table[j].oper && !irccmp(flag, flag_table[j].name)) |
198 |
{ |
199 |
if (isadd) |
200 |
source_p->umodes |= flag_table[j].mode; |
201 |
else |
202 |
source_p->umodes &= ~flag_table[j].mode; |
203 |
isgood = 1; |
204 |
continue; |
205 |
} |
206 |
} |
207 |
/* This for ended without matching a valid FLAG, here is where |
208 |
* I want to operate differently than ircd-comstud, and just ignore |
209 |
* the invalid flag, send a warning and go on. |
210 |
*/ |
211 |
if (!isgood) |
212 |
sendto_one(source_p, ":%s NOTICE %s :Invalid FLAGS: %s (IGNORING)", |
213 |
me.name, parv[0], flag); |
214 |
} |
215 |
} |
216 |
|
217 |
/* All done setting the flags, print the notices out to the user |
218 |
* telling what flags they have and what flags they are missing |
219 |
*/ |
220 |
sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", |
221 |
me.name, parv[0], set_flags_to_string(source_p)); |
222 |
sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", |
223 |
me.name, parv[0], unset_flags_to_string(source_p)); |
224 |
|
225 |
send_umode_out(client_p, source_p, setflags); |
226 |
} |
227 |
|
228 |
/* mo_flags() |
229 |
* |
230 |
* parv[0] = sender prefix |
231 |
* parv[1] = parameter |
232 |
*/ |
233 |
static void |
234 |
mo_flags(struct Client *client_p, struct Client *source_p, |
235 |
int parc, char *parv[]) |
236 |
{ |
237 |
int i,j; |
238 |
int isadd; |
239 |
int isgood; |
240 |
unsigned int setflags; |
241 |
char *p; |
242 |
char *flag; |
243 |
|
244 |
if (parc < 2) |
245 |
{ |
246 |
/* Generate a list of what flags you have and what you are missing, |
247 |
** and send it to the user |
248 |
*/ |
249 |
sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", |
250 |
me.name, parv[0], set_flags_to_string(source_p)); |
251 |
sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", |
252 |
me.name, parv[0], unset_flags_to_string(source_p)); |
253 |
return; |
254 |
} |
255 |
|
256 |
/* Preserve the current flags */ |
257 |
setflags = source_p->umodes; |
258 |
|
259 |
/* XXX - change this to support a multiple last parameter like ISON */ |
260 |
|
261 |
for (i = 1; i < parc; i++) |
262 |
{ |
263 |
for (flag = strtoken(&p, parv[i], " "); flag; |
264 |
flag = strtoken(&p, NULL, " ")) |
265 |
{ |
266 |
/* We default to being in ADD mode */ |
267 |
isadd = 1; |
268 |
|
269 |
/* We default to being in BAD mode */ |
270 |
isgood = 0; |
271 |
|
272 |
if (!isalpha(*flag)) |
273 |
{ |
274 |
if (*flag == '-') |
275 |
isadd = 0; |
276 |
else if (*flag == '+') |
277 |
isadd = 1; |
278 |
++flag; |
279 |
} |
280 |
|
281 |
/* support ALL here */ |
282 |
if (!irccmp(flag, "ALL")) |
283 |
{ |
284 |
if (isadd) |
285 |
source_p->umodes |= FL_ALL_OPER_FLAGS; |
286 |
else |
287 |
source_p->umodes &= ~FL_ALL_OPER_FLAGS; |
288 |
sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", |
289 |
me.name, parv[0], set_flags_to_string(source_p)); |
290 |
sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", |
291 |
me.name, parv[0], unset_flags_to_string(source_p)); |
292 |
send_umode_out(client_p, source_p, setflags); |
293 |
return; |
294 |
} |
295 |
|
296 |
if (!irccmp(flag, "NICKCHANGES")) |
297 |
{ |
298 |
if (!IsOperN(source_p)) |
299 |
{ |
300 |
sendto_one(source_p, |
301 |
":%s NOTICE %s :*** You have no nick_changes flag;", |
302 |
me.name,parv[0]); |
303 |
continue; |
304 |
} |
305 |
if (isadd) |
306 |
source_p->umodes |= UMODE_NCHANGE; |
307 |
else |
308 |
source_p->umodes &= ~UMODE_NCHANGE; |
309 |
isgood = 1; |
310 |
continue; |
311 |
} |
312 |
|
313 |
for (j = 0; flag_table[j].name; j++) |
314 |
{ |
315 |
if (!irccmp(flag, flag_table[j].name)) |
316 |
{ |
317 |
if (isadd) |
318 |
source_p->umodes |= flag_table[j].mode; |
319 |
else |
320 |
source_p->umodes &= ~ (flag_table[j].mode); |
321 |
isgood = 1; |
322 |
continue; |
323 |
} |
324 |
} |
325 |
/* This for ended without matching a valid FLAG, here is where |
326 |
* I want to operate differently than ircd-comstud, and just ignore |
327 |
* the invalid flag, send a warning and go on. |
328 |
*/ |
329 |
if (!isgood) |
330 |
sendto_one(source_p, ":%s NOTICE %s :Invalid FLAGS: %s (IGNORING)", |
331 |
me.name, parv[0], flag); |
332 |
} |
333 |
} |
334 |
|
335 |
/* All done setting the flags, print the notices out to the user |
336 |
** telling what flags they have and what flags they are missing |
337 |
*/ |
338 |
sendto_one(source_p, ":%s NOTICE %s :Current flags:%s", |
339 |
me.name, parv[0], set_flags_to_string(source_p)); |
340 |
sendto_one(source_p, ":%s NOTICE %s :Current missing flags:%s", |
341 |
me.name, parv[0], unset_flags_to_string(source_p)); |
342 |
|
343 |
send_umode_out(client_p, source_p, setflags); |
344 |
} |
345 |
|
346 |
static char * |
347 |
set_flags_to_string(struct Client *client_p) |
348 |
{ |
349 |
/* XXX - list all flags that we have set on the client */ |
350 |
static char setflags[IRCD_BUFSIZE + 1]; |
351 |
int i; |
352 |
|
353 |
/* Clear it to begin with, we'll be doing a lot of ircsprintf's */ |
354 |
setflags[0] = '\0'; |
355 |
|
356 |
/* Unlike unset_flags_to_string(), we don't have to care about oper |
357 |
** flags and not showing them |
358 |
*/ |
359 |
|
360 |
for (i = 0; flag_table[i].name; i++) |
361 |
{ |
362 |
if (client_p->umodes & flag_table[i].mode) |
363 |
{ |
364 |
ircsprintf(setflags, "%s %s", setflags, flag_table[i].name); |
365 |
} |
366 |
} |
367 |
|
368 |
#if 0 |
369 |
if (IsOper(client_p) && IsOperN(client_p)) |
370 |
{ |
371 |
#endif |
372 |
/* You can only be set +NICKCHANGES if you are an oper and |
373 |
* IsOperN(client_p) is true |
374 |
*/ |
375 |
if (client_p->umodes & UMODE_NCHANGE) |
376 |
{ |
377 |
ircsprintf(setflags, "%s %s", setflags, "NICKCHANGES"); |
378 |
} |
379 |
#if 0 |
380 |
} |
381 |
#endif |
382 |
return setflags; |
383 |
} |
384 |
|
385 |
static char * |
386 |
unset_flags_to_string(struct Client *client_p) |
387 |
{ |
388 |
/* Inverse of above */ |
389 |
/* XXX - list all flags that we do NOT have set on the client */ |
390 |
static char setflags[IRCD_BUFSIZE + 1]; |
391 |
int i, isoper; |
392 |
|
393 |
/* Clear it to begin with, we'll be doing a lot of ircsprintf's */ |
394 |
setflags[0] = '\0'; |
395 |
|
396 |
isoper = IsOper(client_p) != 0; |
397 |
|
398 |
for (i = 0; flag_table[i].name; i++) |
399 |
{ |
400 |
if (!(client_p->umodes & flag_table[i].mode)) |
401 |
{ |
402 |
if (!isoper && flag_table[i].oper) |
403 |
continue; |
404 |
|
405 |
ircsprintf(setflags, "%s %s", setflags, |
406 |
flag_table[i].name); |
407 |
} |
408 |
} |
409 |
|
410 |
if (IsOper(client_p) && IsOperN(client_p)) |
411 |
{ |
412 |
if (!(client_p->umodes & UMODE_NCHANGE)) |
413 |
{ |
414 |
ircsprintf(setflags, "%s %s", setflags, "NICKCHANGES"); |
415 |
} |
416 |
} |
417 |
|
418 |
return setflags; |
419 |
} |