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