]> jfr.im git - irc/quakenet/newserv.git/blame - invalidbans/invalidbans.c
BUILD: add require-all build mode
[irc/quakenet/newserv.git] / invalidbans / invalidbans.c
CommitLineData
ec7f2782
GB
1#include <string.h>
2#include "../core/schedule.h"
3#include "../control/control.h"
4#include "../lib/irc_string.h"
5#include "../localuser/localuserchannel.h"
6#include "../lib/version.h"
7
8MODULE_VERSION("");
9
10static int ib_nickext;
11
12typedef struct ibnick {
13 time_t timeout;
14 void *sched;
15} ibnick;
16
17static void ib_clear_ext(void *arg) {
18 nick *np = arg;
19
20 if (!np->exts[ib_nickext])
21 return;
22
23 free(np->exts[ib_nickext]);
24 np->exts[ib_nickext] = NULL;
25}
26
27static void ib_hook_newnick(int hooknum, void *arg) {
28 nick *np = arg;
29 np->exts[ib_nickext] = NULL;
30}
31
32static void ib_hook_lostnick(int hooknum, void *arg) {
33 nick *np = arg;
34 ibnick *inp = np->exts[ib_nickext];
35
36 if (!inp)
37 return;
38
39 deleteschedule(inp->sched, ib_clear_ext, np);
40 free(np->exts[ib_nickext]);
41}
42
43static void ib_hook_modechange(int hooknum, void *arg) {
44 void **arglist=(void **)arg;
45 channel *cp=(channel *)arglist[0];
46 nick *np=(nick *)arglist[1];
47 long changeflags=(long)arglist[2];
48 chanban *cbp;
49 const char *p;
50 int colons, colonsnext;
51 modechanges changes;
52 ibnick *inp;
53 char *mask, *pos;
54 int slot, i;
55 array bans;
56
d1d92f24 57 if (!np || !(changeflags & MODECHANGE_BANS))
ec7f2782
GB
58 return;
59
60 inp = np->exts[ib_nickext];
61
62 /* Ignore the mode change if the same user has recently
63 * set/unset a channel ban. */
64 if (inp && inp->timeout > time(NULL))
65 return;
66
67 if (inp) {
68 deleteschedule(inp->sched, ib_clear_ext, np);
69 free(inp);
70 np->exts[ib_nickext] = NULL;
71 }
72
73 array_init(&bans, 512);
74
75 for (cbp = cp->bans; cbp; cbp = cbp->next) {
76 if (!cbp->host)
77 continue;
78
79 colons = 0;
80 colonsnext = 0;
81
82 for (p = cbp->host->content; *p; p++) {
83 if (*p == ':') {
84 colons++;
85
86 if (*(p + 1) == ':')
87 colonsnext = 1;
88 }
89 }
90
91 if (colons - colonsnext >= 8) {
92 slot = array_getfreeslot(&bans);
93 mask = ((char *)bans.content) + slot * 512;
94 strncpy(mask, bantostring(cbp), 512);
95 }
96 }
97
98 if (bans.cursi > 0) {
99 localsetmodeinit(&changes, cp, NULL);
100
101 for (i = 0; i < bans.cursi; i++) {
102 mask = ((char *)bans.content) + i * 512;
103
104 pos = strchr(mask, '@');
105
106 if (!pos)
107 continue; /* This should never happen. */
108
109 pos++; /* Skip over the @ sign. */
110
111 for (; *pos; pos++) {
112 if (*pos != ':') {
113 *pos = '?';
114 break;
115 }
116 }
117
118 localdosetmode_ban(&changes, mask, MCB_ADD);
119 }
120
121 localsetmodeflush(&changes, 1);
122
123 /* Ignore the user for a short amount of time. If it's a bot
124 * it'll probably try re-setting the ban immediately. */
125 inp = malloc(sizeof(ibnick));
126 inp->timeout = time(NULL) + 15;
127 inp->sched = scheduleoneshot(inp->timeout + 1, ib_clear_ext, np);
128 np->exts[ib_nickext] = inp;
129 }
130
131 array_free(&bans);
132}
133
134void _init() {
135 registerhook(HOOK_NICK_NEWNICK, &ib_hook_newnick);
136 registerhook(HOOK_NICK_LOSTNICK, &ib_hook_lostnick);
137 registerhook(HOOK_CHANNEL_MODECHANGE, &ib_hook_modechange);
138
139 ib_nickext = registernickext("invalidbans");
140}
141
142void _fini () {
143 deregisterhook(HOOK_NICK_NEWNICK, &ib_hook_newnick);
144 deregisterhook(HOOK_NICK_LOSTNICK, &ib_hook_lostnick);
145 deregisterhook(HOOK_CHANNEL_MODECHANGE, &ib_hook_modechange);
146
147 releasenickext(ib_nickext);
148}
149