]> jfr.im git - irc/quakenet/newserv.git/blob - glines/glines_commands.c
glines: Remove redundant account checks.
[irc/quakenet/newserv.git] / glines / glines_commands.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <assert.h>
4 #include "../lib/version.h"
5 #include "../control/control.h"
6 #include "../lib/irc_string.h"
7 #include "../lib/splitline.h"
8 #include "../lib/strlfunc.h"
9 #include "../core/nsmalloc.h"
10 #include "../irc/irc.h"
11 #include "../localuser/localuser.h"
12 #include "../localuser/localuserchannel.h"
13 #include "glines.h"
14 #include "../trusts/trusts.h"
15
16 MODULE_VERSION("");
17
18 static void registercommands(int, void *);
19 static void deregistercommands(int, void *);
20
21 static int parse_gline_flags(nick *sender, const char *flagparam, int *overridesanity, int *overridelimit, int *simulate, int *chase, int *coff) {
22 const char *pos;
23
24 *coff = 0;
25 *overridesanity = 0;
26 *overridelimit = 0;
27 *simulate = 0;
28
29 if (chase)
30 *chase = 0;
31
32 if (flagparam[0] == '-') {
33 *coff = 1;
34
35 for (pos = flagparam + 1; *pos; pos++) {
36 switch (*pos) {
37 case 'f':
38 *overridesanity = 1;
39 break;
40 case 'l':
41 *overridelimit = 1;
42 break;
43 case 'S':
44 *simulate = 1;
45 break;
46 case 'c':
47 if (!chase)
48 goto invalid;
49
50 *chase = 1;
51 break;
52 default:
53 goto invalid;
54 }
55 }
56 }
57
58 return 1;
59
60 invalid:
61 controlreply(sender, "Invalid flag specified: %c", *pos);
62 return 0;
63 }
64
65 static int glines_cmdblock(void *source, int cargc, char **cargv) {
66 nick *sender = source;
67 nick *target, *wnp;
68 whowas *ww;
69 int hits, duration, id;
70 int coff, overridesanity, overridelimit, simulate, chase;
71 char *reason;
72 char creator[128];
73 glinebuf gbuf;
74 int ownww;
75
76 if (cargc < 1)
77 return CMD_USAGE;
78
79 if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, &chase, &coff))
80 return CMD_ERROR;
81
82 if (cargc < 3 + coff)
83 return CMD_USAGE;
84
85 duration = durationtolong(cargv[coff + 1]);
86
87 if (duration <= 0) {
88 controlreply(sender, "Invalid duration specified.");
89 return CMD_ERROR;
90 }
91
92 target = getnickbynick(cargv[coff]);
93
94 if (!target) {
95 ww = whowas_chase(cargv[coff], 1800);
96
97 if (!ww) {
98 controlreply(sender, "Sorry, couldn't find that user.");
99 return CMD_ERROR;
100 }
101
102 ownww = 0;
103
104 controlreply(sender, "Found matching whowas record:");
105 controlreply(sender, "%s", whowas_format(ww));
106 } else {
107 ww = whowas_fromnick(target, 1);
108 ownww = 1;
109 }
110
111 wnp = &ww->nick;
112
113 if (sender != target && (IsService(wnp) || IsOper(wnp) || NickOnServiceServer(wnp))) {
114 controlreply(sender, "Target user '%s' is an oper or a service. Not setting G-Lines.", wnp->nick);
115 return CMD_ERROR;
116 }
117
118 rejoinline(cargv[coff + 2], cargc - coff - 2);
119 reason = cargv[coff + 2];
120
121 snprintf(creator, sizeof(creator), "#%s", sender->authname);
122
123 glinebufinit(&gbuf, 0);
124 glinebufcommentv(&gbuf, "BLOCK", cargc + coff - 1, cargv);
125 glinebufaddbywhowas(&gbuf, ww, 0, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
126
127 glinebufspew(&gbuf, sender);
128
129 if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
130 glinebufabort(&gbuf);
131 if (ownww)
132 whowas_free(ww);
133 controlreply(sender, "G-Lines failed sanity checks. Not setting G-Lines.");
134 return CMD_ERROR;
135 }
136
137 if (simulate) {
138 glinebufabort(&gbuf);
139 if (ownww)
140 whowas_free(ww);
141 controlreply(sender, "Simulation complete. Not setting G-Lines.");
142 return CMD_ERROR;
143 }
144
145 glinebufcounthits(&gbuf, &hits, NULL);
146 id = glinebufcommit(&gbuf, 1);
147
148 controlwall(NO_OPER, NL_GLINES, "%s BLOCK'ed user '%s!%s@%s' for %s with reason '%s' (%d hits)", controlid(sender),
149 wnp->nick, wnp->ident, wnp->host->name->content,
150 longtoduration(duration, 0), reason, hits);
151
152 if (ownww)
153 whowas_free(ww);
154
155 controlreply(sender, "Done. G-Line transaction ID: %d", id);
156
157 return CMD_OK;
158 }
159
160 static int glines_cmdgline(void *source, int cargc, char **cargv) {
161 nick *sender = source;
162 int duration, users, channels, id;
163 char *mask, *reason;
164 char creator[128];
165 int coff, overridesanity, overridelimit, simulate;
166 glinebuf gbuf;
167 #if SNIRCD_VERSION < 140
168 gline *gl;
169 #endif /* SNIRCD_VERSION */
170
171 if (cargc < 1)
172 return CMD_USAGE;
173
174 if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, NULL, &coff))
175 return CMD_ERROR;
176
177 if (cargc < 3 + coff)
178 return CMD_USAGE;
179
180 mask = cargv[coff];
181
182 duration = durationtolong(cargv[coff + 1]);
183
184 if (duration <= 0) {
185 controlreply(sender, "Invalid duration specified.");
186 return CMD_ERROR;
187 }
188
189 rejoinline(cargv[coff + 2], cargc - coff - 2);
190 reason = cargv[coff + 2];
191
192 #if SNIRCD_VERSION < 140
193 gl = findgline(mask);
194
195 if (gl) {
196 /* warn opers that they can't modify this gline */
197 if (gl->flags & GLINE_ACTIVE) {
198 controlreply(sender, "Active G-Line already exists on %s - unable to modify", mask);
199 return CMD_ERROR;
200 }
201
202 controlreply(sender, "Reactivating existing gline on %s", mask);
203 }
204 #endif /* SNIRCD_VERSION */
205
206 snprintf(creator, sizeof(creator), "#%s", sender->authname);
207
208 glinebufinit(&gbuf, 0);
209 glinebufcommentv(&gbuf, "GLINE", cargc + coff - 1, cargv);
210
211 if (!glinebufadd(&gbuf, mask, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration)) {
212 controlreply(sender, "Invalid G-Line mask.");
213 return CMD_ERROR;
214 }
215
216 glinebufspew(&gbuf, sender);
217
218 if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
219 glinebufabort(&gbuf);
220 controlreply(sender, "G-Lines failed sanity checks. Not setting G-Lines.");
221 return CMD_ERROR;
222 }
223
224 if (simulate) {
225 glinebufabort(&gbuf);
226 controlreply(sender, "Simulation complete. Not setting G-Lines.");
227 return CMD_ERROR;
228 }
229
230 glinebufcounthits(&gbuf, &users, &channels);
231 id = glinebufcommit(&gbuf, 1);
232
233 controlwall(NO_OPER, NL_GLINES, "%s GLINE'd mask '%s' for %s with reason '%s' (hits %d users/%d channels)",
234 controlid(sender), mask, longtoduration(duration, 0), reason, users, channels);
235
236 controlreply(sender, "Done. G-Line transaction ID: %d", id);
237
238 return CMD_OK;
239 }
240
241 static int glines_cmdsmartgline(void *source, int cargc, char **cargv) {
242 nick *sender = source;
243 char *origmask;
244 char mask[512];
245 char *p, *user, *host;
246 struct irc_in_addr ip;
247 unsigned char bits;
248 int hits, duration;
249 int coff, overridesanity, overridelimit, simulate, id;
250 char *reason;
251 char creator[128];
252 glinebuf gbuf;
253
254 if (cargc < 1)
255 return CMD_USAGE;
256
257 if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, NULL, &coff))
258 return CMD_ERROR;
259
260 if (cargc < 3 + coff)
261 return CMD_USAGE;
262
263 origmask = cargv[coff];
264
265 if (origmask[0] == '#' || origmask[0] == '&' || origmask[0] == '$') {
266 controlreply(sender, "Please use \"gline\" for badchan or realname glines.");
267 return CMD_ERROR;
268 }
269
270 duration = durationtolong(cargv[coff + 1]);
271
272 if (duration <= 0) {
273 controlreply(sender, "Invalid duration specified.");
274 return CMD_ERROR;
275 }
276
277 rejoinline(cargv[coff + 2], cargc - coff - 2);
278 reason = cargv[coff + 2];
279
280 strncpy(mask, origmask, sizeof(mask));
281
282 if (strchr(mask, '!')) {
283 controlreply(sender, "Use \"gline\" to place nick glines.");
284 return CMD_ERROR;
285 }
286
287 p = strchr(mask, '@');
288
289 if (!p) {
290 controlreply(sender, "Mask must contain a username (e.g. user@ip).");
291 return CMD_ERROR;
292 }
293
294 user = mask;
295 host = p + 1;
296 *p = '\0';
297
298 if (strchr(user, '*') || strchr(user, '?')) {
299 controlreply(sender, "Usernames may not contain wildcards.");
300 return CMD_ERROR;
301 }
302
303 if (!ipmask_parse(host, &ip, &bits)) {
304 controlreply(sender, "Invalid CIDR mask.");
305 return CMD_ERROR;
306 }
307
308 snprintf(creator, sizeof(creator), "#%s", sender->authname);
309
310 glinebufinit(&gbuf, 0);
311 glinebufcommentv(&gbuf, "SMARTGLINE", cargc + coff - 1, cargv);
312 glinebufaddbyip(&gbuf, user, &ip, 128, 0, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
313
314 glinebufspew(&gbuf, sender);
315
316 if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
317 glinebufabort(&gbuf);
318 controlreply(sender, "G-Lines failed sanity checks. Not setting G-Lines.");
319 return CMD_ERROR;
320 }
321
322 if (simulate) {
323 glinebufabort(&gbuf);
324 controlreply(sender, "Simulation complete. Not setting G-Lines.");
325 return CMD_ERROR;
326 }
327
328 glinebufcounthits(&gbuf, &hits, NULL);
329 id = glinebufcommit(&gbuf, 1);
330
331 controlwall(NO_OPER, NL_GLINES, "%s SMARTGLINE'd mask '%s' for %s with reason '%s' (%d hits)",
332 controlid(sender), cargv[0], longtoduration(duration, 0), reason, hits);
333
334 controlreply(sender, "Done. G-Line transaction ID: %d", id);
335
336 return CMD_OK;
337 }
338
339 static int glines_cmdungline(void *source, int cargc, char **cargv) {
340 nick *sender = source;
341 gline *gl;
342
343 if (cargc < 1)
344 return CMD_USAGE;
345
346 gl = findgline(cargv[0]);
347
348 if (!gl) {
349 controlreply(sender, "No such G-Line.");
350 return CMD_ERROR;
351 }
352
353 if (!(gl->flags & GLINE_ACTIVE)) {
354 controlreply(sender, "G-Line was already deactivated.");
355 return CMD_ERROR;
356 }
357
358 gline_deactivate(gl, 0, 1);
359
360 controlwall(NO_OPER, NL_GLINES, "%s UNGLINE'd mask '%s'", controlid(sender), cargv[0]);
361
362 controlreply(sender, "G-Line deactivated.");
363
364 return CMD_OK;
365 }
366
367 static int glines_cmddestroygline(void *source, int cargc, char **cargv) {
368 nick *sender = source;
369 gline *gl;
370
371 if (cargc < 1)
372 return CMD_USAGE;
373
374 gl = findgline(cargv[0]);
375
376 if (!gl) {
377 controlreply(sender, "No such G-Line.");
378 return CMD_ERROR;
379 }
380
381 gline_destroy(gl, 0, 1);
382
383 controlwall(NO_OPER, NL_GLINES, "%s DESTROYGLINE'd mask '%s'", controlid(sender), cargv[0]);
384
385 controlreply(sender, "G-Line destroyed.");
386
387 return CMD_OK;
388 }
389
390 static int glines_cmdclearchan(void *source, int cargc, char **cargv) {
391 nick *sender = source;
392 channel *cp;
393 nick *np;
394 char *reason = "Clearing channel.";
395 int mode, duration, i, slot, hits, id;
396 int coff, overridesanity, overridelimit, simulate;
397 array victims;
398 char creator[128];
399 glinebuf gbuf;
400
401 if (cargc < 1)
402 return CMD_USAGE;
403
404 if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, NULL, &coff))
405 return CMD_ERROR;
406
407 if (cargc < 2 + coff)
408 return CMD_USAGE;
409
410 cp = findchannel(cargv[coff]);
411
412 if (!cp) {
413 controlreply(sender, "Couldn't find that channel.");
414 return CMD_ERROR;
415 }
416
417 if (strcmp(cargv[coff + 1], "kick") == 0)
418 mode = 0;
419 else if (strcmp(cargv[coff + 1], "kill") == 0)
420 mode = 1;
421 else if (strcmp(cargv[coff + 1], "gline") == 0)
422 mode = 2;
423 else if (strcmp(cargv[coff + 1], "glineall") == 0)
424 mode = 3;
425 else
426 return CMD_USAGE;
427
428 if (mode == 0 || mode == 1) {
429 if (cargc >= 3) {
430 rejoinline(cargv[coff + 2], cargc - coff - 2);
431 reason = cargv[coff + 2];
432 }
433 } else {
434 if (cargc < 3 + coff)
435 return CMD_USAGE;
436
437 duration = durationtolong(cargv[coff + 2]);
438
439 if (duration <= 0) {
440 controlreply(sender, "Invalid duration specified.");
441 return CMD_ERROR;
442 }
443
444 if (cargc >= 4 + coff) {
445 rejoinline(cargv[coff + 3], cargc - coff - 3);
446 reason = cargv[coff + 3];
447 }
448 }
449
450 array_init(&victims, sizeof(nick *));
451
452 /* we need to make a list of the channel users here because
453 * kicking/killing them will affect their position in the channel's
454 * user list. */
455 for (i = 0; i < cp->users->hashsize; i++) {
456 if (cp->users->content[i] == nouser)
457 continue;
458
459 np = getnickbynumeric(cp->users->content[i]);
460
461 if (!np)
462 continue;
463
464 if (IsService(np) || IsOper(np) || NickOnServiceServer(np))
465 continue;
466
467 slot = array_getfreeslot(&victims);
468 (((nick **)victims.content)[slot]) = np;
469 }
470
471 snprintf(creator, sizeof(creator), "#%s", sender->authname);
472
473 glinebufinit(&gbuf, 0);
474 glinebufcommentv(&gbuf, "CLEARCHAN", cargc + coff - 1, cargv);
475
476 for (i = 0; i < victims.cursi; i++) {
477 np = ((nick **)victims.content)[i];
478
479 switch (mode) {
480 case 0:
481 if (simulate)
482 controlreply(sender, "user: %s!%s@%s r(%s)", np->nick, np->ident, np->host->name->content, np->realname->name->content);
483 else
484 localkickuser(NULL, cp, np, reason);
485
486 break;
487 case 1:
488 if (simulate)
489 controlreply(sender, "user: %s!%s@%s r(%s)", np->nick, np->ident, np->host->name->content, np->realname->name->content);
490 else
491 killuser(NULL, np, "%s", reason);
492
493 break;
494 case 2:
495 if (IsAccount(np))
496 break;
497 /* fall through */
498 case 3:
499 glinebufaddbynick(&gbuf, np, 0, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
500 break;
501 default:
502 assert(0);
503 }
504 }
505
506 if (mode != 0 && mode != 1) {
507 glinebufspew(&gbuf, sender);
508
509 if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
510 glinebufabort(&gbuf);
511 controlreply(sender, "G-Line failed sanity checks. Not setting G-Line.");
512 return CMD_ERROR;
513 }
514 }
515
516 if (simulate) {
517 glinebufabort(&gbuf);
518 controlreply(sender, "Simulation complete. Not clearing channel.");
519 return CMD_ERROR;
520 }
521
522 glinebufmerge(&gbuf);
523 glinebufcounthits(&gbuf, &hits, NULL);
524 id = glinebufcommit(&gbuf, 1);
525
526 array_free(&victims);
527
528 if (mode == 0 || mode == 1) {
529 controlwall(NO_OPER, NL_GLINES, "%s CLEARCHAN'd channel '%s' with mode '%s' and reason '%s'",
530 controlid(sender), cp->index->name->content, cargv[1], reason);
531 controlreply(sender, "Done.");
532 } else {
533 controlwall(NO_OPER, NL_GLINES, "%s CLEARCHAN'd channel '%s' with mode '%s', duration %s and reason '%s' (%d hits)",
534 controlid(sender), cp->index->name->content, cargv[1], longtoduration(duration, 0), reason, hits);
535 controlreply(sender, "Done. G-Line transaction ID: %d", id);
536 }
537
538 return CMD_OK;
539 }
540
541 static int glines_cmdtrustgline(void *source, int cargc, char **cargv) {
542 nick *sender = source;
543 trustgroup *tg;
544 trusthost *th;
545 int duration, hits;
546 int coff, overridesanity, overridelimit, simulate, id;
547 char *reason;
548 char mask[512];
549 char creator[128];
550 glinebuf gbuf;
551
552 if (cargc < 1)
553 return CMD_USAGE;
554
555 if (!parse_gline_flags(sender, cargv[0], &overridesanity, &overridelimit, &simulate, NULL, &coff))
556 return CMD_ERROR;
557
558 if (cargc < 4 + coff)
559 return CMD_USAGE;
560
561 tg = tg_strtotg(cargv[coff]);
562
563 if (!(tg->flags & TRUST_RELIABLE_USERNAME)) {
564 controlreply(sender, "Sorry, that trust group does not have the \"reliable username\" flag.");
565 return CMD_ERROR;
566 }
567
568 duration = durationtolong(cargv[coff + 2]);
569
570 if (duration <= 0) {
571 controlreply(sender, "Invalid duration specified.");
572 return CMD_ERROR;
573 }
574
575 rejoinline(cargv[coff + 3], cargc - coff - 3);
576 reason = cargv[coff + 3];
577
578 snprintf(creator, sizeof(creator), "#%s", sender->authname);
579
580 glinebufinit(&gbuf, 0);
581 glinebufcommentv(&gbuf, "TRUSTGLINE", cargc + coff - 1, cargv);
582
583 for(th = tg->hosts; th; th = th->next) {
584 snprintf(mask, sizeof(mask), "*!%s@%s", cargv[1], CIDRtostr(th->ip, th->bits));
585 glinebufadd(&gbuf, mask, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
586 }
587
588 glinebufspew(&gbuf, sender);
589
590 if (!glinebufchecksane(&gbuf, sender, overridesanity, overridelimit)) {
591 glinebufabort(&gbuf);
592 controlreply(sender, "G-Line failed sanity checks. Not setting G-Line.");
593 return CMD_ERROR;
594 }
595
596 if (simulate) {
597 glinebufabort(&gbuf);
598 controlreply(sender, "Simulation complete. Not setting G-Lines.");
599 return CMD_ERROR;
600 }
601
602 glinebufcounthits(&gbuf, &hits, NULL);
603 id = glinebufcommit(&gbuf, 1);
604
605 controlwall(NO_OPER, NL_GLINES, "%s TRUSTGLINE'd user '%s' on trust group '%s' for %s with reason '%s' (%d hits)",
606 controlid(sender), cargv[1], tg->name->content, longtoduration(duration, 0), reason, hits);
607
608 controlreply(sender, "Done. G-Line transaction ID: %d", id);
609
610 return CMD_OK;
611 }
612
613 static int glines_cmdtrustungline(void *source, int cargc, char **cargv) {
614 nick *sender = source;
615 trustgroup *tg;
616 trusthost *th;
617 char mask[512];
618 gline *gl;
619 int count;
620
621 if (cargc < 2)
622 return CMD_USAGE;
623
624 tg = tg_strtotg(cargv[0]);
625
626 if (!(tg->flags & TRUST_RELIABLE_USERNAME)) {
627 controlreply(sender, "Sorry, that trust group does not have the \"reliable username\" flag.");
628 return CMD_ERROR;
629 }
630
631 count = 0;
632
633 for (th = tg->hosts; th; th = th->next) {
634 snprintf(mask, sizeof(mask), "*!%s@%s", cargv[1], CIDRtostr(th->ip, th->bits));
635
636 gl = findgline(mask);
637
638 if (gl && (gl->flags & GLINE_ACTIVE)) {
639 gline_deactivate(gl, 0, 1);
640 count++;
641 }
642 }
643
644 controlwall(NO_OPER, NL_GLINES, "%s TRUSTUNGLINE'd user '%s' on trust group '%s' (%d G-Lines deactivated)",
645 controlid(sender), cargv[1], tg->name->content, count);
646
647 controlreply(sender, "Done.");
648
649 return CMD_OK;
650 }
651
652 static int glines_cmdglstats(void *source, int cargc, char **cargv) {
653 nick *sender = (nick*)source;
654 gline *gl, *next;
655 time_t curtime = getnettime();
656 int glinecount = 0, hostglinecount = 0, ipglinecount = 0, badchancount = 0, rnglinecount = 0;
657 int deactivecount = 0, activecount = 0;
658
659 for (gl = glinelist; gl; gl = next) {
660 next = gl->next;
661
662 if (gl->lifetime <= curtime) {
663 removegline(gl);
664 continue;
665 } else if (gl->expire <= curtime) {
666 gl->flags &= ~GLINE_ACTIVE;
667 }
668
669 if (gl->flags & GLINE_ACTIVE) {
670 activecount++;
671 } else {
672 deactivecount++;
673 }
674
675 if (gl->flags & GLINE_IPMASK)
676 ipglinecount++;
677 else if (gl->flags & GLINE_HOSTMASK)
678 hostglinecount++;
679 else if (gl->flags & GLINE_REALNAME)
680 rnglinecount++;
681 else if (gl->flags & GLINE_BADCHAN)
682 badchancount++;
683 glinecount++;
684 }
685
686 controlreply(sender, "Total G-Lines set: %d", glinecount);
687 controlreply(sender, "Hostmask G-Lines: %d", hostglinecount);
688 controlreply(sender, "IPMask G-Lines: %d", ipglinecount);
689 controlreply(sender, "Channel G-Lines: %d", badchancount);
690 controlreply(sender, "Realname G-Lines: %d", rnglinecount);
691
692 controlreply(sender, "Active G-Lines: %d", activecount);
693 controlreply(sender, "Inactive G-Lines: %d", deactivecount);
694
695 /* TODO show top 10 creators here */
696 /* TODO show unique creators count */
697 /* TODO show glines per create %8.1f", ccount?((float)gcount/(float)ccount):0 */
698 return CMD_OK;
699 }
700
701 static int glines_cmdglist(void *source, int cargc, char **cargv) {
702 nick *sender = (nick *)source;
703 gline *gl, *next;
704 time_t curtime = time(NULL);
705 int flags = 0;
706 char *mask;
707 int count = 0;
708 int limit = 500;
709 char expirestr[250], idstr[250];
710
711 if (cargc < 1 || (cargc == 1 && cargv[0][0] == '-')) {
712 controlreply(sender, "Syntax: glist [-flags] <mask>");
713 controlreply(sender, "Valid flags are:");
714 controlreply(sender, "-c: Count G-Lines.");
715 controlreply(sender, "-f: Find G-Lines active on <mask>.");
716 controlreply(sender, "-x: Find G-Lines matching <mask> exactly.");
717 controlreply(sender, "-R: Find G-lines on realnames.");
718 controlreply(sender, "-o: Search for glines by owner.");
719 controlreply(sender, "-r: Search for glines by reason.");
720 controlreply(sender, "-i: Include inactive glines.");
721 return CMD_ERROR;
722 }
723
724 if (cargc > 1) {
725 char* ch = cargv[0];
726
727 for (; *ch; ch++)
728 switch (*ch) {
729 case '-':
730 break;
731
732 case 'c':
733 flags |= GLIST_COUNT;
734 break;
735
736 case 'f':
737 flags |= GLIST_FIND;
738 break;
739
740 case 'x':
741 flags |= GLIST_EXACT;
742 break;
743
744 case 'r':
745 flags |= GLIST_REASON;
746 break;
747 case 'o':
748 flags |= GLIST_OWNER;
749 break;
750
751 case 'R':
752 flags |= GLIST_REALNAME;
753 break;
754
755 case 'i':
756 flags |= GLIST_INACTIVE;
757 break;
758
759 default:
760 controlreply(sender, "Invalid flag '%c'.", *ch);
761 return CMD_ERROR;
762 }
763
764 mask = cargv[1];
765 } else {
766 mask = cargv[0];
767 }
768
769 if ((flags & (GLIST_EXACT|GLIST_FIND)) == (GLIST_EXACT|GLIST_FIND)) {
770 controlreply(sender, "You cannot use -x and -f flags together.");
771 return CMD_ERROR;
772 }
773
774 if (!(flags & GLIST_COUNT))
775 controlreply(sender, "%-50s %-19s %-15s %-25s %s", "Mask:", "Expires in:", "Transaction ID:", "Creator:", "Reason:");
776
777 gline *searchgl = makegline(mask);
778
779 for (gl = glinelist; gl; gl = next) {
780 next = gl->next;
781
782 if (gl->lifetime <= curtime) {
783 removegline(gl);
784 continue;
785 } else if (gl->expire <= curtime) {
786 gl->flags &= ~GLINE_ACTIVE;
787 }
788
789 if (!(gl->flags & GLINE_ACTIVE)) {
790 if (!(flags & GLIST_INACTIVE)) {
791 continue;
792 }
793 }
794
795 if (flags & GLIST_REALNAME) {
796 if (!(gl->flags & GLINE_REALNAME))
797 continue;
798 if (flags & GLIST_EXACT) {
799 if (!glineequal(searchgl, gl))
800 continue;
801 } else if (flags & GLIST_FIND) {
802 if (!gline_match_mask(gl, searchgl))
803 continue;
804 } else {
805 if (!match2strings(mask, glinetostring(gl)))
806 continue;
807 }
808 } else {
809 if (gl->flags & GLINE_REALNAME)
810 continue;
811
812 if (flags & GLIST_REASON) {
813 if (flags & GLIST_EXACT) {
814 if (!gl->reason || ircd_strcmp(mask, gl->reason->content) != 0)
815 continue;
816 } else if (flags & GLIST_FIND) {
817 if (!gl->reason || !match2strings(gl->reason->content, mask))
818 continue;
819 } else if (!gl->reason || !match2strings(mask, gl->reason->content))
820 continue;
821 } else if (flags & GLIST_OWNER) {
822 if (flags & GLIST_EXACT) {
823 if (!gl->creator || ircd_strcmp(mask, gl->creator->content) != 0)
824 continue;
825 } else if (flags & GLIST_FIND) {
826 if (!gl->creator || !match2strings(gl->creator->content, mask))
827 continue;
828 } else if (!gl->creator || !match2strings(mask, gl->creator->content))
829 continue;
830 } else {
831 if (flags & GLIST_EXACT) {
832 if (!glineequal(searchgl, gl))
833 continue;
834 } else if (flags & GLIST_FIND) {
835 if (!gline_match_mask(gl, searchgl))
836 continue;
837 } else {
838 if (!match2strings(mask, glinetostring(gl)))
839 continue;
840 }
841 }
842 }
843
844 if (count == limit && !(flags & GLIST_COUNT))
845 controlreply(sender, "More than %d matches, list truncated.", limit);
846
847 count++;
848
849 if (!(flags & GLIST_COUNT) && count < limit) {
850 snprintf(expirestr, sizeof(expirestr), "%s", glinetostring(gl));
851 snprintf(idstr, sizeof(idstr), "%d", gl->glinebufid);
852 controlreply(sender, "%s%-49s %-19s %-15s %-25s %s",
853 (gl->flags & GLINE_ACTIVE) ? "+" : "-",
854 expirestr,
855 (gl->flags & GLINE_ACTIVE) ? (char*)longtoduration(gl->expire - curtime, 0) : "<inactive>",
856 gl->glinebufid ? idstr : "",
857 gl->creator ? gl->creator->content : "",
858 gl->reason ? gl->reason->content : "");
859 }
860 }
861
862 controlreply(sender, "%s%d G-Line%s found.", (flags & GLIST_COUNT) ? "" : "End of list - ", count, count == 1 ? "" : "s");
863
864 return CMD_OK;
865 }
866
867 static int glines_cmdglinelog(void *source, int cargc, char **cargv) {
868 nick *sender = source;
869 glinebuf *gbl;
870 gline *gl;
871 int i, id, count;
872 char timebuf[30];
873
874 id = 0;
875
876 if (cargc > 0) {
877 id = atoi(cargv[0]);
878
879 if (id == 0) {
880 controlreply(sender, "Invalid log ID.");
881 return CMD_ERROR;
882 }
883 }
884
885 controlreply(sender, "Time ID G-Lines User Hits Channel Hits Comment");
886
887 for (i = 0; i < MAXGLINELOG; i++) {
888 gbl = glinebuflog[(i + glinebuflogoffset + 1) % MAXGLINELOG];
889
890 if (!gbl)
891 continue;
892
893 if (id == 0 || gbl->id == id) {
894 count = 0;
895
896 for (gl = gbl->glines; gl; gl = gl->next)
897 count++;
898
899 strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M:%S", localtime((gbl->amend) ? &gbl->amend : &gbl->commit));
900 strncat(timebuf, (gbl->amend) ? "*" : " ", sizeof(timebuf));
901 controlreply(sender, "%-20s %-10d %-10d %-15d %-15d %s", timebuf, gbl->id, count, gbl->userhits, gbl->channelhits, gbl->comment ? gbl->comment->content : "(no comment)");
902 }
903
904 if (id != 0 && gbl->id == id) {
905 glinebufspew(gbl, sender);
906 controlreply(sender, "Done.");
907 return CMD_OK;
908 }
909 }
910
911 if (id == 0) {
912 controlreply(sender, "Done.");
913 } else {
914 controlreply(sender, "Log entry for ID %d not found.", id);
915 }
916
917 return CMD_OK;
918 }
919
920 static int glines_cmdglineundo(void *source, int cargc, char **cargv) {
921 nick *sender = source;
922 int id;
923
924 if (cargc < 1)
925 return CMD_USAGE;
926
927 id = atoi(cargv[0]);
928
929 if (id == 0 || !glinebufundo(id)) {
930 controlreply(sender, "Invalid log ID.");
931 return CMD_ERROR;
932 }
933
934 controlreply(sender, "Done.");
935
936 return CMD_OK;
937 }
938
939 static int glines_cmdsyncglines(void *source, int cargc, char **cargv) {
940 nick *sender = source;
941 gline *gl;
942 int count;
943
944 count = 0;
945
946 for (gl = glinelist; gl; gl = gl->next) {
947 gline_propagate(gl);
948 count++;
949 }
950
951 controlwall(NO_OPER, NL_GLINES, "%s SYNCGLINE'd %d G-Lines.",
952 controlid(sender), count);
953
954 controlreply(sender, "Done.");
955
956 return CMD_OK;
957 }
958
959 static int glines_cmdcleanupglines(void *source, int cargc, char **cargv) {
960 nick *sender = source;
961 gline **pnext, *gl;
962 int count;
963 time_t now;
964
965 count = 0;
966 time(&now);
967
968 for (pnext = &glinelist; *pnext;) {
969 gl = *pnext;
970
971 /* Remove inactivate glines that have been last changed more than a week ago */
972 if (!(gl->flags & GLINE_ACTIVE) && gl->lastmod < now - 7 * 24 * 60 * 60) {
973 gline_destroy(gl, 0, 1);
974 count++;
975 } else {
976 pnext = &((*pnext)->next);
977 }
978
979 if (!*pnext)
980 break;
981 }
982
983 controlwall(NO_OPER, NL_GLINES, "%s CLEANUPGLINES'd %d G-Lines.",
984 controlid(sender), count);
985
986 controlreply(sender, "Done.");
987
988 return CMD_OK;
989 }
990
991 static int commandsregistered;
992
993 static void registercommands(int hooknum, void *arg) {
994 if (commandsregistered)
995 return;
996 commandsregistered = 1;
997
998 registercontrolhelpcmd("block", NO_OPER, 4, glines_cmdblock, "Usage: block ?flags? <nick> <duration> <reason>\nSets a gline using an appropriate mask given the user's nickname.\nFlags can be one or more of:\n-f - bypass sanity checks\n-l - bypass hit limits\n-S - simulate who the glines would hit\n-c - chase nick across quits/kills/nick changes");
999 registercontrolhelpcmd("gline", NO_OPER, 4, glines_cmdgline, "Usage: gline ?flags? <mask> <duration> <reason>\nSets a gline.\nFlags can be one or more of:\n-f - bypass sanity checks\n-l - bypass hit limits\n-S - simulate who the glines would hit");
1000 registercontrolhelpcmd("smartgline", NO_OPER, 4, glines_cmdsmartgline, "Usage: smartgline ?flags? <user@host> <duration> <reason>\nSets a gline. Automatically adjusts the mask depending on whether the specified mask is trusted.\nFlags can be one or more of:\n-f - bypass sanity checks\n-l - bypass hit limits\n-S - simulate who the glines would hit");
1001 registercontrolhelpcmd("ungline", NO_OPER, 1, glines_cmdungline, "Usage: ungline <mask>\nDeactivates a gline.");
1002 registercontrolhelpcmd("destroygline", NO_DEVELOPER, 1, glines_cmddestroygline, "Usage: destroygline <mask>\nDestroys a gline.");
1003 registercontrolhelpcmd("clearchan", NO_OPER, 5, glines_cmdclearchan, "Usage: clearchan ?flags? <#channel> <how> <duration> ?reason?\nClears a channel.\nhow can be one of:\nkick - Kicks users.\nkill - Kills users.\ngline - Glines non-authed users (using an appropriate mask).\nglineall - Glines users.\nDuration is only valid when glining users. Reason defaults to \"Clearing channel.\".\nFlags (for glines) can be one or more of:\n-f - bypass sanity checks\n-l - bypass hit limits\n-S - simulate who the glines would hit");
1004 registercontrolhelpcmd("trustgline", NO_OPER, 5, glines_cmdtrustgline, "Usage: trustgline ?flags? <#id|name> <user> <duration> <reason>\nSets a gline on the specified username for each host in the specified trust group. The username may contain wildcards.\nFlags can be one or more of:\n-f - bypass sanity checks\n-l - bypass hit limits\n-S - simulate who the glines would hit");
1005 registercontrolhelpcmd("trustungline", NO_OPER, 2, glines_cmdtrustungline, "Usage: trustungline <#id|name> <user>\nRemoves a gline that was previously set with trustgline.");
1006 registercontrolhelpcmd("glstats", NO_OPER, 0, glines_cmdglstats, "Usage: glstat\nShows statistics about G-Lines.");
1007 registercontrolhelpcmd("glist", NO_OPER, 2, glines_cmdglist, "Usage: glist [-flags] <mask>\nLists matching G-Lines.\nValid flags are:\n-c: Count G-Lines.\n-f: Find G-Lines active on <mask>.\n-x: Find G-Lines matching <mask> exactly.\n-R: Find G-lines on realnames.\n-o: Search for glines by owner.\n-r: Search for glines by reason.\n-i: Include inactive glines.");
1008 registercontrolhelpcmd("glinelog", NO_OPER, 1, glines_cmdglinelog, "Usage: glinelog ?id?\nShows information about previous gline transactions.");
1009 registercontrolhelpcmd("glineundo", NO_OPER, 1, glines_cmdglineundo, "Usage: glineundo ?id?\nUndoes a gline transaction.");
1010 registercontrolhelpcmd("syncglines", NO_DEVELOPER, 0, glines_cmdsyncglines, "Usage: syncglines\nSends all G-Lines to all other servers.");
1011 registercontrolhelpcmd("cleanupglines", NO_DEVELOPER, 0, glines_cmdcleanupglines, "Usage: cleanupglines\nDestroys all deactivated G-Lines.");
1012 }
1013
1014 static void deregistercommands(int hooknum, void *arg) {
1015 if (!commandsregistered)
1016 return;
1017 commandsregistered = 0;
1018
1019 deregistercontrolcmd("block", glines_cmdblock);
1020 deregistercontrolcmd("gline", glines_cmdgline);
1021 deregistercontrolcmd("smartgline", glines_cmdsmartgline);
1022 deregistercontrolcmd("ungline", glines_cmdungline);
1023 deregistercontrolcmd("destroygline", glines_cmddestroygline);
1024 deregistercontrolcmd("clearchan", glines_cmdclearchan);
1025 deregistercontrolcmd("trustgline", glines_cmdtrustgline);
1026 deregistercontrolcmd("trustungline", glines_cmdtrustungline);
1027 deregistercontrolcmd("glstats", glines_cmdglstats);
1028 deregistercontrolcmd("glist", glines_cmdglist);
1029 deregistercontrolcmd("glinelog", glines_cmdglinelog);
1030 deregistercontrolcmd("glineundo", glines_cmdglineundo);
1031 deregistercontrolcmd("syncglines", glines_cmdsyncglines);
1032 deregistercontrolcmd("cleanupglines", glines_cmdcleanupglines);
1033 }
1034
1035 void _init(void) {
1036 registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
1037 registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
1038
1039 if (trustsdbloaded)
1040 registercommands(0, NULL);
1041 }
1042
1043 void _fini(void) {
1044 deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
1045 deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
1046
1047 deregistercommands(0, NULL);
1048 }