]> jfr.im git - irc/quakenet/newserv.git/blob - newsearch/ns-gline.c
Merge pull request #132 from retropc/lua_country
[irc/quakenet/newserv.git] / newsearch / ns-gline.c
1 /*
2 * GLINE functionality
3 */
4
5 #include "newsearch.h"
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdint.h>
11
12 #include "../control/control.h"
13 #include "../irc/irc.h" /* irc_send() */
14 #include "../lib/irc_string.h" /* IPtostr(), longtoduration(), durationtolong() */
15 #include "../lib/strlfunc.h"
16 #include "../core/schedule.h"
17 #include "../glines/glines.h"
18
19 /* used for *_free functions that need to warn users of certain things
20 i.e. hitting too many users in a (kill) or (gline) - declared in newsearch.c */
21 extern nick *senderNSExtern;
22 static const char *defaultreason = "You (%u) have been g-lined for violating our terms of service";
23 static int defaultmindelay = 15;
24 static int defaultvariance = 15;
25
26 void *gline_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput);
27 void gline_free(searchCtx *ctx, struct searchNode *thenode);
28
29 struct gline_localdata {
30 unsigned int marker;
31 unsigned int duration;
32 int count;
33 char reason[NSMAX_REASON_LEN];
34 int mindelay;
35 int maxdelay;
36 };
37
38 struct searchNode *common_gline_parse(searchCtx *ctx, int argc, char **argv, int withdelay) {
39 struct gline_localdata *localdata;
40 struct searchNode *thenode;
41
42 if (!(localdata = (struct gline_localdata *) malloc(sizeof(struct gline_localdata)))) {
43 parseError = "malloc: could not allocate memory for this search.";
44 return NULL;
45 }
46 localdata->count = 0;
47 if (ctx->searchcmd == reg_chansearch)
48 localdata->marker = nextchanmarker();
49 else if (ctx->searchcmd == reg_nicksearch)
50 localdata->marker = nextnickmarker();
51 else if (ctx->searchcmd == reg_whowassearch)
52 localdata->marker = nextwhowasmarker();
53 else {
54 free(localdata);
55 parseError = "gline: invalid search type";
56 return NULL;
57 }
58
59 /* default duration, default reason */
60 if(argc == 0) {
61 localdata->duration = NSGLINE_DURATION;
62 strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
63 } else if(argc > (withdelay ? 4 : 2)) {
64 free(localdata);
65 parseError = "gline: invalid number of arguments";
66 return NULL;
67 } else {
68 char *argzerop, *reasonp, *durationp, *mindelayp, *maxdelayp;
69 struct searchNode *durationsn, *reasonsn, *mindelaysn, *maxdelaysn, *argzerosn;
70
71 if (!(argzerosn=argtoconststr("gline", ctx, argv[0], &argzerop))) {
72 free(localdata);
73 return NULL;
74 }
75
76 if(argc == 1) {
77 durationp = reasonp = mindelayp = maxdelayp = NULL;
78 durationsn = reasonsn = mindelaysn = maxdelaysn = NULL;
79
80 /* if we have a space it's a reason */
81 if(strchr(argzerop, ' ')) {
82 reasonsn = argzerosn;
83 reasonp = argzerop;
84 } else {
85 durationsn = argzerosn;
86 durationp = argzerop;
87 }
88 } else {
89 durationsn = argzerosn;
90 durationp = argzerop;
91
92 if (!(reasonsn=argtoconststr("gline", ctx, argv[1], &reasonp))) {
93 durationsn->free(ctx, durationsn);
94 free(localdata);
95 return NULL;
96 }
97
98 if (withdelay) {
99 mindelayp = maxdelayp = NULL;
100 mindelaysn = maxdelaysn = NULL;
101
102 if (argc > 2 && !(mindelaysn=argtoconststr("gline", ctx, argv[2], &mindelayp))) {
103 mindelaysn->free(ctx, mindelaysn);
104 free(localdata);
105 return NULL;
106 }
107
108 if (argc > 3 && !(maxdelaysn=argtoconststr("gline", ctx, argv[3], &maxdelayp))) {
109 maxdelaysn->free(ctx, maxdelaysn);
110 free(localdata);
111 return NULL;
112 }
113 }
114 }
115
116 if(!reasonp) {
117 strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
118 } else {
119 strlcpy(localdata->reason, reasonp, sizeof(localdata->reason));
120 reasonsn->free(ctx, reasonsn);
121 }
122
123 if(!durationp) {
124 localdata->duration = NSGLINE_DURATION;
125 } else {
126 localdata->duration = durationtolong(durationp);
127 durationsn->free(ctx, durationsn);
128
129 if (localdata->duration == 0) {
130 parseError = "gline duration invalid.";
131 free(localdata);
132 return NULL;
133 }
134 }
135
136 if (withdelay) {
137 if(!mindelayp) {
138 localdata->mindelay = defaultmindelay;
139 } else {
140 localdata->mindelay = durationtolong(mindelayp);
141 mindelaysn->free(ctx, mindelaysn);
142
143 if (localdata->mindelay == 0) {
144 parseError = "gline mindelay invalid.";
145 free(localdata);
146 return NULL;
147 }
148 }
149
150 if(!maxdelayp) {
151 localdata->maxdelay = localdata->mindelay + defaultvariance;
152 } else {
153 localdata->maxdelay = durationtolong(maxdelayp);
154 maxdelaysn->free(ctx, maxdelaysn);
155
156 if (localdata->maxdelay == 0) {
157 parseError = "gline maxdelay invalid.";
158 free(localdata);
159 return NULL;
160 }
161 }
162 } else {
163 localdata->mindelay = 0;
164 localdata->maxdelay = 0;
165 }
166
167 if (localdata->mindelay < 0 || localdata->maxdelay < localdata->mindelay) {
168 parseError = "gline delay invalid.";
169 free(localdata);
170 return NULL;
171 }
172 }
173
174 if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) {
175 /* couldn't malloc() memory for thenode, so free localdata to avoid leakage */
176 parseError = "malloc: could not allocate memory for this search.";
177 free(localdata);
178 return NULL;
179 }
180
181 thenode->returntype = RETURNTYPE_BOOL;
182 thenode->localdata = localdata;
183 thenode->exe = gline_exe;
184 thenode->free = gline_free;
185
186 return thenode;
187 }
188
189 struct searchNode *gline_parse(searchCtx *ctx, int argc, char **argv) {
190 return common_gline_parse(ctx, argc, argv, 0);
191 }
192
193 struct searchNode *delaygline_parse(searchCtx *ctx, int argc, char **argv) {
194 return common_gline_parse(ctx, argc, argv, 1);
195 }
196
197 void *gline_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput) {
198 struct gline_localdata *localdata;
199 nick *np;
200 chanindex *cip;
201 whowas *ww;
202
203 localdata = thenode->localdata;
204
205 if (ctx->searchcmd == reg_chansearch) {
206 cip = (chanindex *)theinput;
207 cip->marker = localdata->marker;
208 if (cip->channel != NULL)
209 localdata->count += cip->channel->users->totalusers;
210 }
211 else {
212 np = (nick *)theinput;
213 if (ctx->searchcmd == reg_nicksearch)
214 np->marker = localdata->marker;
215 else {
216 ww = (whowas *)np->next;
217 ww->marker = localdata->marker;
218 }
219 localdata->count++;
220 }
221
222 return (void *)1;
223 }
224
225 static int glineuser(glinebuf *gbuf, nick *np, struct gline_localdata *localdata, time_t ti) {
226 char msgbuf[512];
227 if (!IsOper(np) && !IsService(np) && !IsXOper(np)) {
228 nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
229 glinebufaddbynick(gbuf, np, 0, "newsearch", msgbuf, getnettime() + localdata->duration, getnettime(), getnettime() + localdata->duration);
230 return 1;
231 }
232
233 return 0;
234 }
235
236 static void commitglines(void *arg) {
237 glinebuf *gbuf = (glinebuf *)arg;
238 glinebufcommit(gbuf, 1);
239 free(gbuf);
240 }
241
242 void gline_free(searchCtx *ctx, struct searchNode *thenode) {
243 struct gline_localdata *localdata;
244 nick *np, *nnp;
245 chanindex *cip, *ncip;
246 whowas *ww;
247 int i, j, hits, safe=0, delay;
248 time_t ti = time(NULL);
249 glinebuf *gbuf;
250
251 localdata = thenode->localdata;
252
253 if (localdata->count > NSMAX_GLINE_LIMIT) {
254 /* need to warn the user that they have just tried to twat half the network ... */
255 ctx->reply(senderNSExtern, "Warning: your pattern matches too many users (%d) - nothing done.", localdata->count);
256 free(localdata);
257 free(thenode);
258 return;
259 }
260
261 gbuf = malloc(sizeof(glinebuf));
262 glinebufinit(gbuf, 0);
263
264 if (ctx->searchcmd == reg_chansearch) {
265 for (i=0;i<CHANNELHASHSIZE;i++) {
266 for (cip=chantable[i];cip;cip=ncip) {
267 ncip = cip->next;
268 if (cip != NULL && cip->channel != NULL && cip->marker == localdata->marker) {
269 for (j=0;j<cip->channel->users->hashsize;j++) {
270 if (cip->channel->users->content[j]==nouser)
271 continue;
272
273 if ((np=getnickbynumeric(cip->channel->users->content[j]))) {
274 if(!glineuser(gbuf, np, localdata, ti))
275 safe++;
276 }
277 }
278 }
279 }
280 }
281 } else if (ctx->searchcmd == reg_nicksearch) {
282 for (i=0;i<NICKHASHSIZE;i++) {
283 for (np=nicktable[i];np;np=nnp) {
284 nnp = np->next;
285 if (np->marker == localdata->marker) {
286 if(!glineuser(gbuf, np, localdata, ti))
287 safe++;
288 }
289 }
290 }
291 } else {
292 for (i = whowasoffset; i < whowasoffset + whowasmax; i++) {
293 ww = &whowasrecs[i % whowasmax];
294
295 if (ww->type == WHOWAS_UNUSED)
296 continue;
297
298 if (ww->marker == localdata->marker) {
299 if(!glineuser(gbuf, &ww->nick, localdata, ti))
300 safe++;
301 }
302 }
303 }
304
305 glinebufcounthits(gbuf, &hits, NULL);
306
307 delay = (rand() % (localdata->maxdelay + 1 - localdata->mindelay)) + localdata->mindelay;
308
309 if (delay > 0) {
310 scheduleoneshot(time(NULL) + delay, commitglines, gbuf);
311 } else {
312 commitglines(gbuf);
313 }
314
315 if (safe)
316 ctx->reply(senderNSExtern, "Warning: your pattern matched privileged users (%d in total) - these have not been touched.", safe);
317 /* notify opers of the action */
318 ctx->wall(NL_GLINES, "%s/%s glined %d %s via %s for %s [%d untouched].", senderNSExtern->nick, senderNSExtern->authname, (localdata->count - safe),
319 (localdata->count - safe) != 1 ? "users" : "user", (ctx->searchcmd == reg_chansearch) ? "chansearch" : "nicksearch", longtoduration(localdata->duration, 1), safe);
320 free(localdata);
321 free(thenode);
322 }