]> jfr.im git - irc/quakenet/newserv.git/blame - newsearch/ns-gline.c
NEWSEARCH: add delayed gline
[irc/quakenet/newserv.git] / newsearch / ns-gline.c
CommitLineData
4278cc14
IB
1/*
2 * GLINE functionality
3 */
4
5#include "newsearch.h"
6
7#include <stdio.h>
8#include <stdlib.h>
96429168 9#include <string.h>
8bab42e7 10#include <stdint.h>
4278cc14 11
0da2a4ae 12#include "../control/control.h"
4278cc14 13#include "../irc/irc.h" /* irc_send() */
f16cabe4 14#include "../lib/irc_string.h" /* IPtostr(), longtoduration(), durationtolong() */
2ba836f2 15#include "../lib/strlfunc.h"
f22229e9 16#include "../core/schedule.h"
324b4e11 17#include "../glines/glines.h"
4278cc14
IB
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 */
219d27f1 21extern nick *senderNSExtern;
2ba836f2 22static const char *defaultreason = "You (%u) have been g-lined for violating our terms of service";
f22229e9
GB
23static int defaultmindelay = 15;
24static int defaultvariance = 15;
4278cc14 25
c8be5183
CP
26void *gline_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput);
27void gline_free(searchCtx *ctx, struct searchNode *thenode);
4278cc14
IB
28
29struct gline_localdata {
30 unsigned int marker;
f16cabe4 31 unsigned int duration;
4278cc14 32 int count;
96429168 33 char reason[NSMAX_REASON_LEN];
f22229e9
GB
34 int mindelay;
35 int maxdelay;
4278cc14
IB
36};
37
f22229e9 38struct searchNode *common_gline_parse(searchCtx *ctx, int argc, char **argv, int withdelay) {
4278cc14
IB
39 struct gline_localdata *localdata;
40 struct searchNode *thenode;
41
9ce4f0be
IB
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 }
4278cc14 46 localdata->count = 0;
a92bb8e1 47 if (ctx->searchcmd == reg_chansearch)
8e257015 48 localdata->marker = nextchanmarker();
a92bb8e1 49 else if (ctx->searchcmd == reg_nicksearch)
8e257015 50 localdata->marker = nextnickmarker();
0eb4cbd3
GB
51 else if (ctx->searchcmd == reg_whowassearch)
52 localdata->marker = nextwhowasmarker();
a92bb8e1 53 else {
31686847 54 free(localdata);
a92bb8e1
P
55 parseError = "gline: invalid search type";
56 return NULL;
57 }
4278cc14 58
31686847
CP
59 /* default duration, default reason */
60 if(argc == 0) {
f16cabe4 61 localdata->duration = NSGLINE_DURATION;
2ba836f2 62 strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
f22229e9 63 } else if(argc > (withdelay ? 4 : 2)) {
31686847
CP
64 free(localdata);
65 parseError = "gline: invalid number of arguments";
66 return NULL;
67 } else {
f22229e9
GB
68 char *argzerop, *reasonp, *durationp, *mindelayp, *maxdelayp;
69 struct searchNode *durationsn, *reasonsn, *mindelaysn, *maxdelaysn, *argzerosn;
31686847
CP
70
71 if (!(argzerosn=argtoconststr("gline", ctx, argv[0], &argzerop))) {
72 free(localdata);
73 return NULL;
74 }
96429168 75
31686847 76 if(argc == 1) {
f22229e9
GB
77 durationp = reasonp = mindelayp = maxdelayp = NULL;
78 durationsn = reasonsn = mindelaysn = maxdelaysn = NULL;
31686847
CP
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;
90323e03 87 }
31686847
CP
88 } else {
89 durationsn = argzerosn;
90 durationp = argzerop;
90323e03 91
31686847
CP
92 if (!(reasonsn=argtoconststr("gline", ctx, argv[1], &reasonp))) {
93 durationsn->free(ctx, durationsn);
94 free(localdata);
95 return NULL;
f22229e9
GB
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 }
96429168 114 }
31686847
CP
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);
96429168 121 }
96429168 122
31686847
CP
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 }
2ba836f2 134 }
f22229e9
GB
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 }
f16cabe4
IB
172 }
173
9ce4f0be
IB
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 }
4278cc14
IB
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
f22229e9
GB
189struct searchNode *gline_parse(searchCtx *ctx, int argc, char **argv) {
190 return common_gline_parse(ctx, argc, argv, 0);
191}
192
193struct searchNode *delaygline_parse(searchCtx *ctx, int argc, char **argv) {
194 return common_gline_parse(ctx, argc, argv, 1);
195}
196
c8be5183 197void *gline_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput) {
4278cc14 198 struct gline_localdata *localdata;
8e257015
IB
199 nick *np;
200 chanindex *cip;
0eb4cbd3 201 whowas *ww;
4278cc14
IB
202
203 localdata = thenode->localdata;
204
a92bb8e1 205 if (ctx->searchcmd == reg_chansearch) {
8e257015
IB
206 cip = (chanindex *)theinput;
207 cip->marker = localdata->marker;
0371d169
GB
208 if (cip->channel != NULL)
209 localdata->count += cip->channel->users->totalusers;
8e257015
IB
210 }
211 else {
212 np = (nick *)theinput;
0eb4cbd3
GB
213 if (ctx->searchcmd == reg_nicksearch)
214 np->marker = localdata->marker;
215 else {
0495c1d1 216 ww = (whowas *)np->next;
0eb4cbd3
GB
217 ww->marker = localdata->marker;
218 }
8e257015
IB
219 localdata->count++;
220 }
4278cc14 221
c7f7a584 222 return (void *)1;
4278cc14
IB
223}
224
324b4e11 225static int glineuser(glinebuf *gbuf, nick *np, struct gline_localdata *localdata, time_t ti) {
90323e03
CP
226 char msgbuf[512];
227 if (!IsOper(np) && !IsService(np) && !IsXOper(np)) {
228 nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
324b4e11 229 glinebufaddbynick(gbuf, np, 0, "newsearch", msgbuf, getnettime() + localdata->duration, getnettime(), getnettime() + localdata->duration);
90323e03
CP
230 return 1;
231 }
232
233 return 0;
234}
235
f22229e9
GB
236static void commitglines(void *arg) {
237 glinebuf *gbuf = (glinebuf *)arg;
238 glinebufcommit(gbuf, 1);
239 free(gbuf);
240}
241
c8be5183 242void gline_free(searchCtx *ctx, struct searchNode *thenode) {
4278cc14
IB
243 struct gline_localdata *localdata;
244 nick *np, *nnp;
8e257015 245 chanindex *cip, *ncip;
0eb4cbd3 246 whowas *ww;
f22229e9 247 int i, j, hits, safe=0, delay;
aace33dc 248 time_t ti = time(NULL);
f22229e9 249 glinebuf *gbuf;
4278cc14
IB
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 ... */
0da2a4ae 255 ctx->reply(senderNSExtern, "Warning: your pattern matches too many users (%d) - nothing done.", localdata->count);
4278cc14
IB
256 free(localdata);
257 free(thenode);
258 return;
259 }
260
f22229e9
GB
261 gbuf = malloc(sizeof(glinebuf));
262 glinebufinit(gbuf, 0);
324b4e11 263
a92bb8e1 264 if (ctx->searchcmd == reg_chansearch) {
8e257015
IB
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]))) {
f22229e9 274 if(!glineuser(gbuf, np, localdata, ti))
2ba836f2 275 safe++;
8e257015
IB
276 }
277 }
278 }
279 }
280 }
0eb4cbd3 281 } else if (ctx->searchcmd == reg_nicksearch) {
8e257015
IB
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) {
f22229e9 286 if(!glineuser(gbuf, np, localdata, ti))
90323e03 287 safe++;
4278cc14 288 }
4278cc14
IB
289 }
290 }
0eb4cbd3 291 } else {
291fdf5f
CP
292 for (i = whowasoffset; i < whowasoffset + whowasmax; i++) {
293 ww = &whowasrecs[i % whowasmax];
0495c1d1
GB
294
295 if (ww->type == WHOWAS_UNUSED)
296 continue;
297
0eb4cbd3 298 if (ww->marker == localdata->marker) {
f22229e9 299 if(!glineuser(gbuf, &ww->nick, localdata, ti))
0eb4cbd3
GB
300 safe++;
301 }
302 }
4278cc14 303 }
324b4e11 304
f22229e9
GB
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 }
324b4e11 314
4278cc14 315 if (safe)
0da2a4ae 316 ctx->reply(senderNSExtern, "Warning: your pattern matched privileged users (%d in total) - these have not been touched.", safe);
f16cabe4 317 /* notify opers of the action */
0da2a4ae 318 ctx->wall(NL_GLINES, "%s/%s glined %d %s via %s for %s [%d untouched].", senderNSExtern->nick, senderNSExtern->authname, (localdata->count - safe),
a92bb8e1 319 (localdata->count - safe) != 1 ? "users" : "user", (ctx->searchcmd == reg_chansearch) ? "chansearch" : "nicksearch", longtoduration(localdata->duration, 1), safe);
4278cc14
IB
320 free(localdata);
321 free(thenode);
322}