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