]> jfr.im git - irc/quakenet/newserv.git/blob - newsearch/ns-gline.c
LUA: port luadb to dbapi2 to drop postgres dependency
[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 "../glines/glines.h"
17
18 /* used for *_free functions that need to warn users of certain things
19 i.e. hitting too many users in a (kill) or (gline) - declared in newsearch.c */
20 extern nick *senderNSExtern;
21 static const char *defaultreason = "You (%u) have been g-lined for violating our terms of service";
22
23 void *gline_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput);
24 void gline_free(searchCtx *ctx, struct searchNode *thenode);
25
26 struct gline_localdata {
27 unsigned int marker;
28 unsigned int duration;
29 int count;
30 char reason[NSMAX_REASON_LEN];
31 };
32
33 struct searchNode *gline_parse(searchCtx *ctx, int argc, char **argv) {
34 struct gline_localdata *localdata;
35 struct searchNode *thenode;
36
37 if (!(localdata = (struct gline_localdata *) malloc(sizeof(struct gline_localdata)))) {
38 parseError = "malloc: could not allocate memory for this search.";
39 return NULL;
40 }
41 localdata->count = 0;
42 if (ctx->searchcmd == reg_chansearch)
43 localdata->marker = nextchanmarker();
44 else if (ctx->searchcmd == reg_nicksearch)
45 localdata->marker = nextnickmarker();
46 else if (ctx->searchcmd == reg_whowassearch)
47 localdata->marker = nextwhowasmarker();
48 else {
49 free(localdata);
50 parseError = "gline: invalid search type";
51 return NULL;
52 }
53
54 /* default duration, default reason */
55 if(argc == 0) {
56 localdata->duration = NSGLINE_DURATION;
57 strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
58 } else if(argc > 2) {
59 free(localdata);
60 parseError = "gline: invalid number of arguments";
61 return NULL;
62 } else {
63 char *argzerop, *reasonp, *durationp;
64 struct searchNode *durationsn, *reasonsn, *argzerosn;
65
66 if (!(argzerosn=argtoconststr("gline", ctx, argv[0], &argzerop))) {
67 free(localdata);
68 return NULL;
69 }
70
71 if(argc == 1) {
72 durationp = reasonp = NULL;
73 durationsn = reasonsn = NULL;
74
75 /* if we have a space it's a reason */
76 if(strchr(argzerop, ' ')) {
77 reasonsn = argzerosn;
78 reasonp = argzerop;
79 } else {
80 durationsn = argzerosn;
81 durationp = argzerop;
82 }
83 } else {
84 durationsn = argzerosn;
85 durationp = argzerop;
86
87 if (!(reasonsn=argtoconststr("gline", ctx, argv[1], &reasonp))) {
88 durationsn->free(ctx, durationsn);
89 free(localdata);
90 return NULL;
91 }
92 }
93
94 if(!reasonp) {
95 strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
96 } else {
97 strlcpy(localdata->reason, reasonp, sizeof(localdata->reason));
98 reasonsn->free(ctx, reasonsn);
99 }
100
101 if(!durationp) {
102 localdata->duration = NSGLINE_DURATION;
103 } else {
104 localdata->duration = durationtolong(durationp);
105 durationsn->free(ctx, durationsn);
106
107 if (localdata->duration == 0) {
108 parseError = "gline duration invalid.";
109 free(localdata);
110 return NULL;
111 }
112 }
113 }
114
115 if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) {
116 /* couldn't malloc() memory for thenode, so free localdata to avoid leakage */
117 parseError = "malloc: could not allocate memory for this search.";
118 free(localdata);
119 return NULL;
120 }
121
122 thenode->returntype = RETURNTYPE_BOOL;
123 thenode->localdata = localdata;
124 thenode->exe = gline_exe;
125 thenode->free = gline_free;
126
127 return thenode;
128 }
129
130 void *gline_exe(searchCtx *ctx, struct searchNode *thenode, void *theinput) {
131 struct gline_localdata *localdata;
132 nick *np;
133 chanindex *cip;
134 whowas *ww;
135
136 localdata = thenode->localdata;
137
138 if (ctx->searchcmd == reg_chansearch) {
139 cip = (chanindex *)theinput;
140 cip->marker = localdata->marker;
141 if (cip->channel != NULL)
142 localdata->count += cip->channel->users->totalusers;
143 }
144 else {
145 np = (nick *)theinput;
146 if (ctx->searchcmd == reg_nicksearch)
147 np->marker = localdata->marker;
148 else {
149 ww = (whowas *)np->next;
150 ww->marker = localdata->marker;
151 }
152 localdata->count++;
153 }
154
155 return (void *)1;
156 }
157
158 static int glineuser(glinebuf *gbuf, nick *np, struct gline_localdata *localdata, time_t ti) {
159 char msgbuf[512];
160 if (!IsOper(np) && !IsService(np) && !IsXOper(np)) {
161 nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
162 glinebufaddbynick(gbuf, np, 0, "newsearch", msgbuf, getnettime() + localdata->duration, getnettime(), getnettime() + localdata->duration);
163 return 1;
164 }
165
166 return 0;
167 }
168
169 void gline_free(searchCtx *ctx, struct searchNode *thenode) {
170 struct gline_localdata *localdata;
171 nick *np, *nnp;
172 chanindex *cip, *ncip;
173 whowas *ww;
174 int i, j, hits, safe=0;
175 time_t ti = time(NULL);
176 glinebuf gbuf;
177
178 localdata = thenode->localdata;
179
180 if (localdata->count > NSMAX_GLINE_LIMIT) {
181 /* need to warn the user that they have just tried to twat half the network ... */
182 ctx->reply(senderNSExtern, "Warning: your pattern matches too many users (%d) - nothing done.", localdata->count);
183 free(localdata);
184 free(thenode);
185 return;
186 }
187
188 glinebufinit(&gbuf, 0);
189
190 if (ctx->searchcmd == reg_chansearch) {
191 for (i=0;i<CHANNELHASHSIZE;i++) {
192 for (cip=chantable[i];cip;cip=ncip) {
193 ncip = cip->next;
194 if (cip != NULL && cip->channel != NULL && cip->marker == localdata->marker) {
195 for (j=0;j<cip->channel->users->hashsize;j++) {
196 if (cip->channel->users->content[j]==nouser)
197 continue;
198
199 if ((np=getnickbynumeric(cip->channel->users->content[j]))) {
200 if(!glineuser(&gbuf, np, localdata, ti))
201 safe++;
202 }
203 }
204 }
205 }
206 }
207 } else if (ctx->searchcmd == reg_nicksearch) {
208 for (i=0;i<NICKHASHSIZE;i++) {
209 for (np=nicktable[i];np;np=nnp) {
210 nnp = np->next;
211 if (np->marker == localdata->marker) {
212 if(!glineuser(&gbuf, np, localdata, ti))
213 safe++;
214 }
215 }
216 }
217 } else {
218 for (i = whowasoffset; i < whowasoffset + whowasmax; i++) {
219 ww = &whowasrecs[i % whowasmax];
220
221 if (ww->type == WHOWAS_UNUSED)
222 continue;
223
224 if (ww->marker == localdata->marker) {
225 if(!glineuser(&gbuf, &ww->nick, localdata, ti))
226 safe++;
227 }
228 }
229 }
230
231 glinebufcounthits(&gbuf, &hits, NULL);
232 glinebufcommit(&gbuf, 1);
233
234 if (safe)
235 ctx->reply(senderNSExtern, "Warning: your pattern matched privileged users (%d in total) - these have not been touched.", safe);
236 /* notify opers of the action */
237 ctx->wall(NL_GLINES, "%s/%s glined %d %s via %s for %s [%d untouched].", senderNSExtern->nick, senderNSExtern->authname, (localdata->count - safe),
238 (localdata->count - safe) != 1 ? "users" : "user", (ctx->searchcmd == reg_chansearch) ? "chansearch" : "nicksearch", longtoduration(localdata->duration, 1), safe);
239 free(localdata);
240 free(thenode);
241 }