]> jfr.im git - irc/quakenet/newserv.git/blob - request/request_block.c
merge
[irc/quakenet/newserv.git] / request / request_block.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "../irc/irc.h"
4 #include "../lib/irc_string.h"
5 #include "request_block.h"
6
7 /* array of blocks */
8 array rqblocks;
9
10 /* our anti-flood nick extension */
11 int rqnext;
12
13 /* are we currently loading blocks? */
14 int rq_loading;
15
16 void rqhook_lostnick(int hook, void *arg);
17
18 int rq_initblocks(void) {
19 rqnext = registernickext("request");
20 if(rqnext < 0)
21 return 0;
22
23 array_init(&rqblocks, sizeof(rq_block));
24 array_setlim1(&rqblocks, 5);
25 array_setlim2(&rqblocks, 20);
26
27 rq_loading = 0;
28
29 rq_loadblocks();
30
31 rq_addblock("#qnet*", "Reserved for QuakeNet use only.", "request", 0, 0);
32 rq_addblock("#help*", "Reserved for QuakeNet use only.", "request", 0, 0);
33
34 registerhook(HOOK_NICK_LOSTNICK, &rqhook_lostnick);
35
36 return 1;
37 }
38
39 void rq_finiblocks(void) {
40 int i;
41 rq_block block;
42 nick *nip;
43
44 for (i = 0; i < rqblocks.cursi; i++) {
45 block = ((rq_block*)rqblocks.content)[i];
46
47 freesstring(block.pattern);
48 freesstring(block.reason);
49 freesstring(block.creator);
50 }
51
52 array_free(&rqblocks);
53
54 for (i=0; i<NICKHASHSIZE; i++)
55 for (nip=nicktable[i]; nip; nip=nip->next)
56 free(nip->exts[rqnext]);
57
58 deregisterhook(HOOK_NICK_LOSTNICK, &rqhook_lostnick);
59
60 releasenickext(rqnext);
61 }
62
63 void rqhook_lostnick(int hook, void *arg) {
64 nick *np = (nick*)arg;
65
66 free(np->exts[rqnext]);
67 }
68
69 int rq_isspam(nick *np) {
70 rq_flood *lf;
71
72 if (np->exts[rqnext] == NULL) {
73 np->exts[rqnext] = lf = (rq_flood*)malloc(sizeof(rq_flood));
74
75 lf->count = 1;
76 lf->created = getnettime();
77 lf->expire = 0;
78
79 return 0;
80 } else {
81 lf = np->exts[rqnext];
82
83 lf->count -= (getnettime() - lf->created) / (RQ_SPAMBLOCK / RQ_SPAMCOUNT);
84
85 if (lf->count < 0)
86 lf->count = 0;
87
88 if (lf->count > RQ_SPAMCOUNT && lf->expire > getnettime()) {
89 return 1;
90 } else {
91 lf->count++;
92
93 if (lf->count > RQ_SPAMCOUNT) {
94 lf->expire = getnettime() + RQ_SPAMBLOCK;
95
96 rq_addblock(np->authname, "Flooding the request system.", "request", 0, getnettime() + 3600);
97
98 return 1;
99 }
100
101 return 0;
102 }
103 }
104 }
105
106 time_t rq_blocktime(nick *np) {
107 if (np->exts[rqnext] == NULL)
108 return 0;
109 else
110 return ((rq_flood*)np->exts[rqnext])->expire - getnettime();
111 }
112
113 rq_block *rq_findblock(const char *pattern) {
114 int i;
115 rq_block block;
116
117 for (i = rqblocks.cursi - 1; i >= 0; i--) {
118 block = ((rq_block*)rqblocks.content)[i];
119
120 if (match2strings(block.pattern->content, pattern)) {
121 if (block.expires != 0 && block.expires < getnettime())
122 rq_removeblock(block.pattern->content);
123 else
124 return &(((rq_block*)rqblocks.content)[i]);
125 }
126 }
127
128 return NULL;
129 }
130
131 void rq_addblock(const char *pattern, const char *reason, const char *creator, time_t created, time_t expires) {
132 int slot;
133 rq_block *block;
134
135 if (rq_findblock(pattern) != NULL)
136 return;
137
138 slot = array_getfreeslot(&rqblocks);
139
140 block = &(((rq_block*)rqblocks.content)[slot]);
141
142 block->pattern = getsstring(pattern, CHANNELLEN);
143 block->reason = getsstring(reason, RQ_BLOCKLEN);
144 block->creator = getsstring(creator, ACCOUNTLEN);
145 block->created = created == 0 ? getnettime() : created;
146 block->expires = expires;
147
148 rq_saveblocks();
149 }
150
151 int rq_removeblock(const char *pattern) {
152 int i;
153 rq_block block;
154
155 for (i = 0; i < rqblocks.cursi; i++) {
156 block = ((rq_block*)rqblocks.content)[i];
157
158 if (ircd_strcmp(block.pattern->content, pattern) == 0) {
159 freesstring(block.pattern);
160 freesstring(block.reason);
161 freesstring(block.creator);
162
163 array_delslot(&rqblocks, i);
164
165 rq_saveblocks();
166
167 return 1;
168 }
169 }
170
171 return 0;
172 }
173
174 /* pattern reason creator created expires */
175 int rq_parseline(char *line) {
176 char pattern[CHANNELLEN+1];
177 char reason[RQ_BLOCKLEN+1];
178 char creator[ACCOUNTLEN+1];
179 time_t created, expires;
180
181 if (sscanf(line, "%s %s %lu %lu %[^\n]", pattern, creator, &created, &expires, reason) < 2) /* \n won't be there anyway, but %s won't return the whole string */
182 return 0; /* invalid block */
183
184 /* tell rq_addblock that it should not save the blocks to disk this time */
185 rq_loading = 1;
186 rq_addblock(pattern, reason, creator, created, expires);
187 rq_loading = 0;
188
189 return 1;
190 }
191
192 int rq_loadblocks(void) {
193 char line[4096];
194 FILE *rqdata;
195 int count;
196
197 rqdata = fopen(RQ_BLOCKFILE, "r");
198
199 if (rqdata == NULL)
200 return 0;
201
202 count = 0;
203
204 while (!feof(rqdata)) {
205 if (fgets(line, sizeof(line), rqdata) == NULL)
206 break;
207
208 if (line[strlen(line) - 1] == '\n')
209 line[strlen(line) - 1] = '\0';
210
211 if (line[strlen(line) - 1] == '\r')
212 line[strlen(line) - 1] = '\0';
213
214 if (line[0] != '\0') {
215 if (rq_parseline(line))
216 count++;
217 }
218 }
219
220 fclose(rqdata);
221
222 return count;
223 }
224
225 int rq_saveblocks(void) {
226 FILE *rqdata;
227 int i, count = 0;
228
229 /* don't save the blocks if we're currently loading them from the disk */
230 if (rq_loading)
231 return 0;
232
233 rqdata = fopen(RQ_BLOCKFILE, "w");
234
235 if (rqdata == NULL)
236 return 0;
237
238 rq_block block;
239
240 for (i = 0; i < rqblocks.cursi; i++) {
241 block = ((rq_block*)rqblocks.content)[i];
242
243 fprintf(rqdata, "%s %s %lu %lu %s\n", block.pattern->content, block.creator->content, block.created, block.expires, block.reason->content);
244 }
245
246 fclose(rqdata);
247
248 return count;
249 }