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