]> jfr.im git - irc/quakenet/newserv.git/blob - glines/glines_commands.c
c3f32560e2dd3ccdc105d7f472fedcc59c8c8d0b
[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 glines_cmdblock(void *source, int cargc, char **cargv) {
22 nick *sender = source;
23 nick *target;
24 int hits, duration;
25 char *reason;
26 char creator[32];
27 glinebuf gbuf;
28
29 if (cargc < 3)
30 return CMD_USAGE;
31
32 target = getnickbynick(cargv[0]);
33
34 if (!target) {
35 controlreply(sender, "Sorry, couldn't find that user.");
36 return CMD_ERROR;
37 }
38
39 duration = durationtolong(cargv[1]);
40
41 if (duration <= 0) {
42 controlreply(sender, "Invalid duration specified.");
43 return CMD_ERROR;
44 }
45
46 if (duration > MAXUSERGLINEDURATION) {
47 controlreply(sender, "Sorry, glines may not last longer than %s.", longtoduration(MAXUSERGLINEDURATION, 0));
48 return CMD_ERROR;
49 }
50
51 reason = cargv[2];
52
53 if (strlen(reason) < MINUSERGLINEREASON) {
54 controlreply(sender, "Please specify a proper gline reason.");
55 return CMD_ERROR;
56 }
57
58 snprintf(creator, sizeof(creator), "#%s", sender->authname);
59
60 glinebufinit(&gbuf, 1);
61 glinebufaddbynick(&gbuf, target, 0, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
62 glinebufcounthits(&gbuf, &hits, NULL);
63 glinebufflush(&gbuf, 1);
64
65 controlwall(NO_OPER, NL_GLINES, "%s BLOCK'ed user '%s!%s@%s' for %s with reason '%s' (%d hits)", controlid(sender), target->nick, target->ident, target->host->name->content, longtoduration(duration, 0), reason, hits);
66
67 controlreply(sender, "Done.");
68
69 return CMD_OK;
70 }
71
72 static int glines_gline_helper(void *source, int cargc, char **cargv, int sanitychecks) {
73 nick *sender = source;
74 int duration, users, channels;
75 char *mask, *reason;
76 char creator[32];
77 glinebuf gbuf;
78 #if SNIRCD_VERSION < 140
79 gline *gl;
80 #endif
81
82 if (cargc < 3)
83 return CMD_USAGE;
84
85 mask = cargv[0];
86
87 duration = durationtolong(cargv[1]);
88
89 if (duration <= 0) {
90 controlreply(sender, "Invalid duration specified.");
91 return CMD_ERROR;
92 }
93
94 if (duration > MAXUSERGLINEDURATION) {
95 controlreply(sender, "Sorry, glines may not last longer than %s.", longtoduration(MAXUSERGLINEDURATION, 0));
96 return CMD_ERROR;
97 }
98
99 reason = cargv[2];
100
101 if (strlen(reason) < MINUSERGLINEREASON) {
102 controlreply(sender, "Please specify a proper gline reason.");
103 return CMD_ERROR;
104 }
105
106 #if SNIRCD_VERSION < 140
107 gl = findgline(mask);
108
109 if (gl) {
110 /* warn opers that they can't modify this gline */
111 if (gl->flags & GLINE_ACTIVE) {
112 controlreply(sender, "Active G-Line already exists on %s - unable to modify", cargv[0]);
113 return CMD_ERROR;
114 }
115
116 controlreply(sender, "Reactivating existing gline on %s", mask);
117 }
118 #endif
119
120 snprintf(creator, sizeof(creator), "#%s", sender->authname);
121
122 glinebufinit(&gbuf, 1);
123
124 if (!glinebufadd(&gbuf, mask, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration)) {
125 controlreply(sender, "Invalid G-Line mask.");
126 return CMD_ERROR;
127 }
128
129 glinebufcounthits(&gbuf, &users, &channels);
130
131 if (channels > MAXUSERGLINECHANNELHITS) {
132 glinebufabandon(&gbuf);
133 controlreply(sender, "G-Line on '%s' would hit %d channels. Limit is %d. Not setting G-Line.", mask, channels, MAXUSERGLINECHANNELHITS);
134 return CMD_ERROR;
135 } else if (users > MAXUSERGLINEUSERHITS) {
136 glinebufabandon(&gbuf);
137 controlreply(sender, "G-Line on '%s' would hit %d users. Limit is %d. Not setting G-Line.", mask, users, MAXUSERGLINEUSERHITS);
138 return CMD_ERROR;
139 }
140
141 if (sanitychecks && glinebufsanitize(&gbuf) > 0) {
142 glinebufabandon(&gbuf);
143 controlreply(sender, "G-Line failed sanity checks. Not setting G-Line.");
144 return CMD_ERROR;
145 }
146
147 glinebufflush(&gbuf, 1);
148
149 controlwall(NO_OPER, NL_GLINES, "%s %sGLINE'd mask '%s' for %s with reason '%s' (hits %d users/%d channels)",
150 controlid(sender),
151 sanitychecks ? "" : "RAW",
152 mask, longtoduration(duration, 0),
153 reason, users, channels);
154
155 controlreply(sender, "Done.");
156
157 return CMD_OK;
158 }
159
160 static int glines_cmdrawgline(void *source, int cargc, char **cargv) {
161 return glines_gline_helper(source, cargc, cargv, 0);
162 }
163
164 static int glines_cmdgline(void *source, int cargc, char **cargv) {
165 return glines_gline_helper(source, cargc, cargv, 1);
166 }
167
168 static int glines_cmdrawglinesimulate(void *source, int cargc, char **cargv) {
169 nick *sender = source;
170 char *mask;
171 glinebuf gbuf;
172 int users, channels;
173 char creator[32];
174
175 if (cargc < 1)
176 return CMD_USAGE;
177
178 mask = cargv[0];
179
180 snprintf(creator, sizeof(creator), "#%s", sender->authname);
181
182 glinebufinit(&gbuf, 0);
183
184 if (!glinebufadd(&gbuf, mask, creator, "Simulate", getnettime(), getnettime(), getnettime())) {
185 glinebufabandon(&gbuf);
186 controlreply(sender, "Invalid G-Line mask.");
187 return CMD_ERROR;
188 }
189
190 glinebufcounthits(&gbuf, &users, &channels);
191 glinebufabandon(&gbuf);
192
193 controlreply(sender, "G-Line on '%s' would hit %d users/%d channels.", mask, users, channels);
194
195 return CMD_OK;
196 }
197
198 static int glines_cmdsmartgline(void *source, int cargc, char **cargv) {
199 nick *sender = source;
200 char *origmask;
201 char mask[512];
202 char *p, *user, *host;
203 struct irc_in_addr ip;
204 unsigned char bits;
205 int hits, duration;
206 char *reason;
207 char creator[32];
208 glinebuf gbuf;
209
210 if (cargc < 3)
211 return CMD_USAGE;
212
213 origmask = cargv[0];
214
215 if (origmask[0] == '#' || origmask[0] == '&') {
216 controlreply(sender, "Please use rawgline for badchans and regex glines.");
217 return CMD_ERROR;
218 }
219
220 duration = durationtolong(cargv[1]);
221
222 if (duration <= 0) {
223 controlreply(sender, "Invalid duration specified.");
224 return CMD_ERROR;
225 }
226
227 if (duration > MAXUSERGLINEDURATION) {
228 controlreply(sender, "Sorry, glines may not last longer than %s.", longtoduration(MAXUSERGLINEDURATION, 0));
229 return CMD_ERROR;
230 }
231
232 reason = cargv[2];
233
234 if (strlen(reason) < MINUSERGLINEREASON) {
235 controlreply(sender, "Please specify a proper gline reason.");
236 return CMD_ERROR;
237 }
238
239 strncpy(mask, origmask, sizeof(mask));
240
241 if (strchr(mask, '!')) {
242 controlreply(sender, "Use rawgline to place nick glines.");
243 return CMD_ERROR;
244 }
245
246 p = strchr(mask, '@');
247
248 if (!p) {
249 controlreply(sender, "Mask must contain a username (e.g. user@ip).");
250 return CMD_ERROR;
251 }
252
253 user = mask;
254 host = p + 1;
255 *p = '\0';
256
257 if (strchr(user, '*') || strchr(user, '?')) {
258 controlreply(sender, "Usernames may not contain wildcards.");
259 return CMD_ERROR;
260 }
261
262 if (!ipmask_parse(host, &ip, &bits)) {
263 controlreply(sender, "Invalid CIDR mask.");
264 return CMD_ERROR;
265 }
266
267 snprintf(creator, sizeof(creator), "#%s", sender->authname);
268
269 glinebufinit(&gbuf, 1);
270 glinebufaddbyip(&gbuf, user, &ip, 128, 0, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
271 glinebufcounthits(&gbuf, &hits, NULL);
272 glinebufflush(&gbuf, 1);
273
274 controlwall(NO_OPER, NL_GLINES, "%s GLINE'd mask '%s' for %s with reason '%s' (%d hits)",
275 controlid(sender), cargv[0], longtoduration(duration, 0), reason, hits);
276
277 controlreply(sender, "Done.");
278
279 return CMD_OK;
280 }
281
282 static int glines_cmdungline(void *source, int cargc, char **cargv) {
283 nick *sender = source;
284 gline *gl;
285
286 if (cargc < 1)
287 return CMD_USAGE;
288
289 gl = findgline(cargv[0]);
290
291 if (!gl) {
292 controlreply(sender, "No such G-Line.");
293 return CMD_ERROR;
294 }
295
296 if (!(gl->flags & GLINE_ACTIVE)) {
297 controlreply(sender, "G-Line was already deactivated.");
298 return CMD_ERROR;
299 }
300
301 gline_deactivate(gl, 0, 1);
302
303 controlwall(NO_OPER, NL_GLINES, "%s UNGLINE'd mask '%s'", controlid(sender), cargv[0]);
304
305 controlreply(sender, "G-Line deactivated.");
306
307 return CMD_OK;
308 }
309
310 static int glines_cmdclearchan(void *source, int cargc, char **cargv) {
311 nick *sender = source;
312 channel *cp;
313 nick *np;
314 char *reason = "Clearing channel.";
315 int mode, duration, i, slot, hits;
316 array victims;
317 char creator[32];
318 glinebuf gbuf;
319
320 if (cargc < 2)
321 return CMD_USAGE;
322
323 cp = findchannel(cargv[0]);
324
325 if (!cp) {
326 controlreply(sender, "Couldn't find that channel.");
327 return CMD_ERROR;
328 }
329
330 if (strcmp(cargv[1], "kick") == 0)
331 mode = 0;
332 else if (strcmp(cargv[1], "kill") == 0)
333 mode = 1;
334 else if (strcmp(cargv[1], "gline") == 0)
335 mode = 2;
336 else if (strcmp(cargv[1], "glineall") == 0)
337 mode = 3;
338 else
339 return CMD_USAGE;
340
341 if (mode == 0 || mode == 1) {
342 if (cargc >= 3) {
343 rejoinline(cargv[2], cargc - 2);
344 reason = cargv[2];
345 }
346 } else {
347 if (cargc < 3)
348 return CMD_USAGE;
349
350 duration = durationtolong(cargv[2]);
351
352 if (duration <= 0) {
353 controlreply(sender, "Invalid duration specified.");
354 return CMD_ERROR;
355 }
356
357 if (duration > MAXUSERGLINEDURATION) {
358 controlreply(sender, "Sorry, glines may not last longer than %s.", longtoduration(MAXUSERGLINEDURATION, 0));
359 return CMD_ERROR;
360 }
361
362 if (cargc >= 4)
363 reason = cargv[3];
364 }
365
366 array_init(&victims, sizeof(nick *));
367
368 /* we need to make a list of the channel users here because
369 * kicking/killing them will affect their position in the channel's
370 * user list. */
371 for (i = 0; i < cp->users->hashsize; i++) {
372 if (cp->users->content[i] == nouser)
373 continue;
374
375 np = getnickbynumeric(cp->users->content[i]);
376
377 if (!np)
378 continue;
379
380 if (IsService(np) || IsOper(np) || NickOnServiceServer(np))
381 continue;
382
383 slot = array_getfreeslot(&victims);
384 (((nick **)victims.content)[slot]) = np;
385 }
386
387 snprintf(creator, sizeof(creator), "#%s", sender->authname);
388
389 glinebufinit(&gbuf, 1);
390
391 for (i = 0; i < victims.cursi; i++) {
392 np = ((nick **)victims.content)[i];
393
394 switch (mode) {
395 case 0:
396 localkickuser(NULL, cp, np, reason);
397 break;
398 case 1:
399 killuser(NULL, np, "%s", reason);
400 break;
401 case 2:
402 if (IsAccount(np))
403 break;
404 /* fall through */
405 case 3:
406 glinebufaddbynick(&gbuf, np, 0, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
407 break;
408 default:
409 assert(0);
410 }
411 }
412
413 glinebufcounthits(&gbuf, &hits, NULL);
414 glinebufflush(&gbuf, 1);
415
416 array_free(&victims);
417
418 if (mode == 0 || mode == 1)
419 controlwall(NO_OPER, NL_GLINES, "%s CLEARCHAN'd channel '%s' with mode '%s' and reason '%s'",
420 controlid(sender), cp->index->name->content, cargv[1], reason);
421 else
422 controlwall(NO_OPER, NL_GLINES, "%s CLEARCHAN'd channel '%s' with mode '%s', duration %s and reason '%s' (%d hits)",
423 controlid(sender), cp->index->name->content, cargv[1], longtoduration(duration, 0), reason, hits);
424
425 controlreply(sender, "Done.");
426
427 return CMD_OK;
428 }
429
430 static int glines_cmdtrustgline(void *source, int cargc, char **cargv) {
431 nick *sender = source;
432 trustgroup *tg;
433 trusthost *th;
434 int duration, hits;
435 char *reason;
436 char mask[512];
437 char creator[32];
438 glinebuf gbuf;
439
440 if (cargc < 4)
441 return CMD_USAGE;
442
443 tg = tg_strtotg(cargv[0]);
444
445 if (!(tg->flags & TRUST_RELIABLE_USERNAME)) {
446 controlreply(sender, "Sorry, that trust group does not have the \"reliable username\" flag.");
447 return CMD_ERROR;
448 }
449
450 duration = durationtolong(cargv[2]);
451
452 if (duration <= 0 || duration > MAXUSERGLINEDURATION) {
453 controlreply(sender, "Sorry, glines may not last longer than %s.", longtoduration(MAXUSERGLINEDURATION, 0));
454 return CMD_ERROR;
455 }
456
457 reason = cargv[3];
458
459 if (strlen(reason) < MINUSERGLINEREASON) {
460 controlreply(sender, "Please specify a proper gline reason.");
461 return CMD_ERROR;
462 }
463
464 snprintf(creator, sizeof(creator), "#%s", sender->authname);
465
466 glinebufinit(&gbuf, 0);
467
468 for(th = tg->hosts; th; th = th->next) {
469 snprintf(mask, sizeof(mask), "*!%s@%s", cargv[1], trusts_cidr2str(&th->ip, th->bits));
470 glinebufadd(&gbuf, mask, creator, reason, getnettime() + duration, getnettime(), getnettime() + duration);
471 }
472
473 glinebufcounthits(&gbuf, &hits, NULL);
474 glinebufflush(&gbuf, 1);
475
476 controlwall(NO_OPER, NL_GLINES, "%s TRUSTGLINE'd user '%s' on trust group '%s' for %s with reason '%s' (%d hits)",
477 controlid(sender), cargv[1], tg->name->content, longtoduration(duration, 0), reason, hits);
478
479 controlreply(sender, "Done.");
480
481 return CMD_OK;
482 }
483
484 static int glines_cmdtrustungline(void *source, int cargc, char **cargv) {
485 nick *sender = source;
486 trustgroup *tg;
487 trusthost *th;
488 char mask[512];
489 gline *gl;
490 int count;
491
492 if (cargc < 2)
493 return CMD_USAGE;
494
495 tg = tg_strtotg(cargv[0]);
496
497 if (!(tg->flags & TRUST_RELIABLE_USERNAME)) {
498 controlreply(sender, "Sorry, that trust group does not have the \"reliable username\" flag.");
499 return CMD_ERROR;
500 }
501
502 count = 0;
503
504 for (th = tg->hosts; th; th = th->next) {
505 snprintf(mask, sizeof(mask), "*!%s@%s", cargv[1], trusts_cidr2str(&th->ip, th->bits));
506
507 gl = findgline(mask);
508
509 if (gl && (gl->flags & GLINE_ACTIVE)) {
510 gline_deactivate(gl, 0, 1);
511 count++;
512 }
513 }
514
515 controlwall(NO_OPER, NL_GLINES, "%s TRUSTUNGLINE'd user '%s' on trust group '%s' (%d G-Lines deactivated)",
516 controlid(sender), cargv[1], tg->name->content, count);
517
518 controlreply(sender, "Done.");
519
520 return CMD_OK;
521 }
522
523 static int glines_cmdglstats(void *source, int cargc, char **cargv) {
524 nick *sender = (nick*)source;
525 gline *gl, *next;
526 time_t curtime = getnettime();
527 int glinecount = 0, hostglinecount = 0, ipglinecount = 0, badchancount = 0, rnglinecount = 0;
528 int deactivecount = 0, activecount = 0;
529
530 for (gl = glinelist; gl; gl = next) {
531 next = gl->next;
532
533 if (gl->lifetime <= curtime) {
534 removegline(gl);
535 continue;
536 } else if (gl->expire <= curtime) {
537 gl->flags &= ~GLINE_ACTIVE;
538 }
539
540 if (gl->flags & GLINE_ACTIVE) {
541 activecount++;
542 } else {
543 deactivecount++;
544 }
545
546 if (gl->flags & GLINE_IPMASK)
547 ipglinecount++;
548 else if (gl->flags & GLINE_HOSTMASK)
549 hostglinecount++;
550 else if (gl->flags & GLINE_REALNAME)
551 rnglinecount++;
552 else if (gl->flags & GLINE_BADCHAN)
553 badchancount++;
554 glinecount++;
555 }
556
557 controlreply(sender, "Total G-Lines set: %d", glinecount);
558 controlreply(sender, "Hostmask G-Lines: %d", hostglinecount);
559 controlreply(sender, "IPMask G-Lines: %d", ipglinecount);
560 controlreply(sender, "Channel G-Lines: %d", badchancount);
561 controlreply(sender, "Realname G-Lines: %d", rnglinecount);
562
563 controlreply(sender, "Active G-Lines: %d", activecount);
564 controlreply(sender, "Inactive G-Lines: %d", deactivecount);
565
566 /* TODO show top 10 creators here */
567 /* TODO show unique creators count */
568 /* TODO show glines per create %8.1f", ccount?((float)gcount/(float)ccount):0 */
569 return CMD_OK;
570 }
571
572 static int glines_cmdglist(void *source, int cargc, char **cargv) {
573 nick *sender = (nick *)source;
574 gline *gl, *next;
575 time_t curtime = time(NULL);
576 int flags = 0;
577 char *mask;
578 int count = 0;
579 int limit = 500;
580 char tmp[250];
581
582 if (cargc < 1 || (cargc == 1 && cargv[0][0] == '-')) {
583 controlreply(sender, "Syntax: glist [-flags] <mask>");
584 controlreply(sender, "Valid flags are:");
585 controlreply(sender, "-c: Count G-Lines.");
586 controlreply(sender, "-f: Find G-Lines active on <mask>.");
587 controlreply(sender, "-x: Find G-Lines matching <mask> exactly.");
588 controlreply(sender, "-R: Find G-lines on realnames.");
589 controlreply(sender, "-o: Search for glines by owner.");
590 controlreply(sender, "-r: Search for glines by reason.");
591 controlreply(sender, "-i: Include inactive glines.");
592 return CMD_ERROR;
593 }
594
595 mask = cargv[0];
596
597 if (cargc > 1) {
598 char* ch = cargv[0];
599
600 for (; *ch; ch++)
601 switch (*ch) {
602 case '-':
603 break;
604
605 case 'c':
606 flags |= GLIST_COUNT;
607 break;
608
609 case 'f':
610 flags |= GLIST_FIND;
611 break;
612
613 case 'x':
614 flags |= GLIST_EXACT;
615 break;
616
617 case 'r':
618 flags |= GLIST_REASON;
619 break;
620 case 'o':
621 flags |= GLIST_OWNER;
622 break;
623
624 case 'R':
625 flags |= GLIST_REALNAME;
626 break;
627
628 case 'i':
629 flags |= GLIST_INACTIVE;
630 break;
631
632 default:
633 controlreply(sender, "Invalid flag '%c'.", *ch);
634 return CMD_ERROR;
635 }
636
637 mask = cargv[1];
638 } else {
639 mask = cargv[0];
640 }
641
642 if ((flags & (GLIST_EXACT|GLIST_FIND)) == (GLIST_EXACT|GLIST_FIND)) {
643 controlreply(sender, "You cannot use -x and -f flags together.");
644 return CMD_ERROR;
645 }
646
647 if (!(flags & GLIST_COUNT))
648 controlreply(sender, "%-50s %-19s %-25s %s", "Mask:", "Expires in:", "Creator:", "Reason:");
649
650 gline *searchgl = makegline(mask);
651
652 for (gl = glinelist; gl; gl = next) {
653 next = gl->next;
654
655 if (gl->lifetime <= curtime) {
656 removegline(gl);
657 continue;
658 } else if (gl->expire <= curtime) {
659 gl->flags &= ~GLINE_ACTIVE;
660 }
661
662 if (!(gl->flags & GLINE_ACTIVE)) {
663 if (!(flags & GLIST_INACTIVE)) {
664 continue;
665 }
666 }
667
668 if (flags & GLIST_REALNAME) {
669 if (!(gl->flags & GLINE_REALNAME))
670 continue;
671 if (flags & GLIST_EXACT) {
672 if (!glineequal(searchgl, gl)) {
673 continue;
674 }
675 } else if (flags & GLIST_FIND) {
676 if (!gline_match_mask(searchgl, gl)) {
677 continue;
678 }
679 }
680 } else {
681 if (gl->flags & GLINE_REALNAME)
682 continue;
683
684 if (flags & GLIST_REASON) {
685 if (flags & GLIST_EXACT) {
686 if (!gl->reason || ircd_strcmp(mask, gl->reason->content) != 0)
687 continue;
688 } else if (flags & GLIST_FIND) {
689 if (!gl->reason || match(gl->reason->content, mask))
690 continue;
691 } else if (!gl->reason || match(mask, gl->reason->content))
692 continue;
693 } else if (flags & GLIST_OWNER) {
694 if (flags & GLIST_EXACT) {
695 if (!gl->creator || ircd_strcmp(mask, gl->creator->content) != 0)
696 continue;
697 } else if (flags & GLIST_FIND) {
698 if (!gl->creator || match(gl->creator->content, mask))
699 continue;
700 } else if (!gl->creator || match(mask, gl->creator->content))
701 continue;
702 } else {
703 if (flags & GLIST_EXACT) {
704 if (!glineequal(searchgl, gl)) {
705 continue;
706 }
707 } else if (flags & GLIST_FIND) {
708 if (!gline_match_mask(searchgl, gl)) {
709 continue;
710 }
711 }
712 }
713 }
714
715 if (count == limit && !(flags & GLIST_COUNT))
716 controlreply(sender, "More than %d matches, list truncated.", limit);
717
718 count++;
719
720 if (!(flags & GLIST_COUNT) && count < limit) {
721 snprintf(tmp, 249, "%s", glinetostring(gl));
722 controlreply(sender, "%s%-49s %-19s %-25s %s",
723 (gl->flags & GLINE_ACTIVE) ? "+" : "-",
724 tmp,
725 (gl->flags & GLINE_ACTIVE) ? (char*)longtoduration(gl->expire - curtime, 0) : "<inactive>",
726 gl->creator ? gl->creator->content : "",
727 gl->reason ? gl->reason->content : "");
728 }
729 }
730
731 controlreply(sender, "%s%d G-Line%s found.", (flags & GLIST_COUNT) ? "" : "End of list - ", count, count == 1 ? "" : "s");
732
733 return CMD_OK;
734 }
735
736 static int glines_cmdcleanupglines(void *source, int cargc, char **cargv) {
737 nick *sender = source;
738 gline **pnext, *gl;
739 int count;
740
741 count = 0;
742
743 for (pnext = &glinelist; *pnext; pnext = &((*pnext)->next)) {
744 gl = *pnext;
745
746 if (!(gl->flags & GLINE_ACTIVE)) {
747 gline_destroy(gl, 0, 1);
748 count++;
749 }
750
751 if (!*pnext)
752 break;
753 }
754
755 controlwall(NO_OPER, NL_GLINES, "%s CLEANUPGLINES'd %d G-Lines.",
756 controlid(sender), count);
757
758 controlreply(sender, "Done.");
759
760 return CMD_OK;
761 }
762
763 static int glines_cmdsyncglines(void *source, int cargc, char **cargv) {
764 nick *sender = source;
765 gline *gl;
766 int count;
767
768 count = 0;
769
770 for (gl = glinelist; gl; gl = gl->next) {
771 gline_propagate(gl);
772 count++;
773 }
774
775 controlwall(NO_OPER, NL_GLINES, "%s SYNCGLINE'd %d G-Lines.",
776 controlid(sender), count);
777
778 controlreply(sender, "Done.");
779
780 return CMD_OK;
781 }
782
783 static int glines_cmdsaveglines(void *source, int cargc, char **cargv) {
784 nick *sender = source;
785 int count;
786
787 count = glstore_save();
788
789 if (count < 0)
790 controlreply(sender, "An error occured while saving G-Lines.");
791 else
792 controlreply(sender, "Saved %d G-Line%s.", count, (count == 1) ? "" : "s");
793
794 return CMD_OK;
795 }
796
797 static int glines_cmdloadglines(void *source, int cargc, char **cargv) {
798 nick *sender = source;
799 int count;
800
801 count = glstore_load();
802
803 if (count < 0)
804 controlreply(sender, "An error occured while loading the G-Lines file.");
805 else
806 controlreply(sender, "Loaded %d G-Line%s.", count, (count == 1) ? "" : "s");
807
808 return CMD_OK;
809 }
810
811 static int commandsregistered;
812
813 static void registercommands(int hooknum, void *arg) {
814 if (commandsregistered)
815 return;
816 commandsregistered = 1;
817
818 registercontrolhelpcmd("block", NO_OPER, 3, glines_cmdblock, "Usage: block <nick> <duration> <reason>\nSets a gline using an appropriate mask given the user's nickname.");
819 registercontrolhelpcmd("rawgline", NO_OPER, 3, glines_cmdrawgline, "Usage: rawgline <mask> <duration> <reason>\nSets a gline. Does fewer sanity checks than \"gline\". Use with care.");
820 registercontrolhelpcmd("rawglinesimulate", NO_OPER, 1, glines_cmdrawglinesimulate, "Usage: rawglinesimulate <mask>\nSimulates what happens when a gline is set.");
821 registercontrolhelpcmd("gline", NO_OPER, 3, glines_cmdgline, "Usage: rawgline <mask> <duration> <reason>\nSets a gline.");
822 registercontrolhelpcmd("smartgline", NO_OPER, 3, glines_cmdsmartgline, "Usage: gline <user@host> <duration> <reason>\nSets a gline. Automatically adjusts the mask so as not to hit unrelated trusted users.");
823 registercontrolhelpcmd("ungline", NO_OPER, 1, glines_cmdungline, "Usage: ungline <mask>\nDeactivates a gline.");
824 registercontrolhelpcmd("clearchan", NO_OPER, 4, glines_cmdclearchan, "Usage: clearchan <#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.\".");
825 registercontrolhelpcmd("trustgline", NO_OPER, 4, glines_cmdtrustgline, "Usage: trustgline <#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.");
826 registercontrolhelpcmd("trustungline", NO_OPER, 2, glines_cmdtrustungline, "Usage: trustungline <#id|name> <user>\nRemoves a gline that was previously set with trustgline.");
827 registercontrolhelpcmd("glstats", NO_OPER, 0, glines_cmdglstats, "Usage: glstat\nShows statistics about G-Lines.");
828 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.");
829 registercontrolhelpcmd("cleanupglines", NO_OPER, 0, glines_cmdcleanupglines, "Usage: cleanupglines\nDestroys all deactivated G-Lines.");
830 registercontrolhelpcmd("syncglines", NO_DEVELOPER, 0, glines_cmdsyncglines, "Usage: syncglines\nSends all G-Lines to all other servers.");
831 registercontrolhelpcmd("loadglines", NO_DEVELOPER, 0, glines_cmdloadglines, "Usage: loadglines\nForce load of glines.");
832 registercontrolhelpcmd("saveglines", NO_DEVELOPER, 0, glines_cmdsaveglines, "Usage: saveglines\nForce save of glines.");
833 }
834
835 static void deregistercommands(int hooknum, void *arg) {
836 if (!commandsregistered)
837 return;
838 commandsregistered = 0;
839
840 deregistercontrolcmd("block", glines_cmdblock);
841 deregistercontrolcmd("rawgline", glines_cmdrawgline);
842 deregistercontrolcmd("rawglinesimulate", glines_cmdrawglinesimulate);
843 deregistercontrolcmd("gline", glines_cmdgline);
844 deregistercontrolcmd("smartgline", glines_cmdsmartgline);
845 deregistercontrolcmd("ungline", glines_cmdungline);
846 deregistercontrolcmd("clearchan", glines_cmdclearchan);
847 deregistercontrolcmd("trustgline", glines_cmdtrustgline);
848 deregistercontrolcmd("trustungline", glines_cmdtrustungline);
849 deregistercontrolcmd("glstats", glines_cmdglstats);
850 deregistercontrolcmd("glist", glines_cmdglist);
851 deregistercontrolcmd("cleanupglines", glines_cmdcleanupglines);
852 deregistercontrolcmd("syncglines", glines_cmdsyncglines);
853 deregistercontrolcmd("loadglines", glines_cmdloadglines);
854 deregistercontrolcmd("saveglines", glines_cmdsaveglines);
855 }
856
857 void _init(void) {
858 registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
859 registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
860
861 if (trustsdbloaded)
862 registercommands(0, NULL);
863 }
864
865 void _fini(void) {
866 deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
867 deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
868
869 deregistercommands(0, NULL);
870 }