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