]> jfr.im git - irc/quakenet/newserv.git/blame - chanstats/chansearch.c
Began manual merge.
[irc/quakenet/newserv.git] / chanstats / chansearch.c
CommitLineData
c86edd1d
Q
1
2#include "chanstats.h"
3#include "../parser/parser.h"
4#include "../nick/nick.h"
5#include "../channel/channel.h"
6#include "../control/control.h"
7#include "../lib/flags.h"
8#include "../lib/irc_string.h"
9
10#define MAXTERMS 10
11#define MAXMATCHES 500
12
13CommandTree *searchfilters;
14
15typedef struct {
16 CommandHandler searchfunc;
17 int params;
18 int invert;
19 char **args;
20} filterterm;
21
22void cs_describe(nick *sender, chanindex *cip);
23int numcompare(char *cmp, unsigned int num);
24int cs_exists(void *chan, int cargc, char **cargv);
25int cs_nick(void *chan, int cargc, char **cargv);
26int cs_size(void *chan, int cargc, char **cargv);
27int cs_namelen(void *chan, int cargc, char **cargv);
28int cs_keyed(void *chan, int cargc, char **cargv);
29int cs_secret(void *chan, int cargc, char **cargv);
30int cs_invite(void *chan, int cargc, char **cargv);
31int cs_moderated(void *chan, int cargc, char **cargv);
32int cs_modes(void *chan, int cargc, char **cargv);
33int cs_name(void *chan, int cargc, char **cargv);
34
35void initchansearch() {
36 searchfilters=newcommandtree();
37
38 regchansearchfunc("name", 1, cs_name);
39 regchansearchfunc("exists", 0, cs_exists);
40 regchansearchfunc("nick", 1, cs_nick);
41 regchansearchfunc("size", 1, cs_size);
42 regchansearchfunc("namelen", 1, cs_namelen);
43 regchansearchfunc("keyed", 0, cs_keyed);
44 regchansearchfunc("secret", 0, cs_secret);
45 regchansearchfunc("invite", 0, cs_invite);
46 regchansearchfunc("moderated", 0, cs_moderated);
47 regchansearchfunc("modes", 1, cs_modes);
48
3e3692bf
CP
49 registercontrolhelpcmd("chansearch",NO_OPER,19,&dochansearch,
50 "Usage: chansearch <search terms>\n"
51 " Valid search terms are: name, exists, size, nick, namelen, keyed, secret, invite\n"
52 " Terms can be inverted with !");
c86edd1d
Q
53}
54
55void finichansearch() {
56 deregistercontrolcmd("chansearch",&dochansearch);
57 destroycommandtree(searchfilters);
58}
59
60void regchansearchfunc(const char *name, int args, CommandHandler handler) {
61 addcommandtotree(searchfilters, name, 0, args, handler);
62}
63
64void unregchansearchfunc(const char *name, CommandHandler handler) {
65 deletecommandfromtree(searchfilters, name, handler);
66}
67
68int dochansearch(void *source, int cargc, char **cargv) {
69 nick *sender=(nick *)source;
70 filterterm terms[MAXTERMS];
71 int i,j;
72 int numterms=0;
73 Command *mc;
74 chanindex *cip;
75 int matched=0;
76 int offset;
77 int res;
78
3e3692bf
CP
79 if (cargc<1)
80 return CMD_USAGE;
c86edd1d
Q
81
82 for (i=0;i<cargc;) {
83 if (cargv[i][0]=='!') {
84 offset=1;
85 terms[numterms].invert=1;
86 } else {
87 offset=0;
88 terms[numterms].invert=0;
89 }
90
91 if ((mc=findcommandintree(searchfilters, &cargv[i][offset], 1))==NULL) {
92 controlreply(sender,"Unrecognised search term: %s",cargv[i]);
93 return CMD_ERROR;
94 }
95 if ((cargc-i-1) < mc->maxparams) {
96 controlreply(sender,"Not enough arguments supplied for %s",cargv[i]);
97 return CMD_ERROR;
98 }
99 terms[numterms].searchfunc=mc->handler;
100 terms[numterms].params=mc->maxparams;
101 terms[numterms].args=cargv+i+1;
102 i+=(mc->maxparams+1);
103 numterms++;
104
105 if (numterms==MAXTERMS)
106 break;
107 }
108
109 controlreply(sender,"The following channels match your criteria:");
110
111 for(i=0;i<CHANNELHASHSIZE;i++) {
112 for(cip=chantable[i];cip;cip=cip->next) {
113 for(j=0;j<numterms;j++) {
114 res=(terms[j].searchfunc)((void *)cip,terms[j].params,terms[j].args);
115 if (res==0 && terms[j].invert)
116 break;
117 if (res==1 && !terms[j].invert)
118 break;
119 }
120 if (j==numterms) {
121 if (matched == MAXMATCHES) {
122 controlreply(sender,"--- More than %d matches, truncating list.",MAXMATCHES);
123 }
124 if (matched < MAXMATCHES) {
125 cs_describe(sender, cip);
126 }
127 matched++;
128 }
129 }
130 }
131
132 if (matched==0) {
133 controlreply(sender,"--- No matches found.");
134 } else {
135 controlreply(sender,"--- End of list: %d match(es).",matched);
136 }
137
138 return CMD_OK;
139}
140
141int cs_name(void *chan, int cargc, char **cargv) {
142 chanindex *cip=(chanindex *)chan;
143
144 return !match2strings(cargv[0],cip->name->content);
145}
146
147int cs_exists(void *chan, int cargc, char **cargv) {
148 chanindex *cip=(chanindex *)chan;
149
150 return (cip->channel==NULL);
151}
152
153int cs_nick(void *chan, int cargc, char **cargv) {
154 chanindex *cip=(chanindex *)chan;
155 nick *np;
156
157 if (cip->channel==NULL) {
158 return 1;
159 }
160
161 if ((np=getnickbynick(cargv[0]))==NULL) {
162 return 1;
163 }
164
165 if ((getnumerichandlefromchanhash(cip->channel->users, np->numeric))==NULL) {
166 return 1;
167 }
168
169 return 0;
170}
171
172int cs_size(void *chan, int cargc, char **cargv) {
173 chanindex *cip=(chanindex *)chan;
174
175 if (cip->channel==NULL) {
176 return 1;
177 }
178
179 return numcompare(cargv[0],cip->channel->users->totalusers);
180}
181
182int cs_namelen(void *chan, int cargc, char **cargv) {
183 chanindex *cip=(chanindex *)chan;
184
185 return numcompare(cargv[0],cip->name->length);
186}
187
188int cs_keyed(void *chan, int cargc, char **cargv) {
189 chanindex *cip=(chanindex *)chan;
190
191 if (cip->channel==NULL) {
192 return 1;
193 }
194
195 return !IsKey(cip->channel);
196}
197
198int cs_secret(void *chan, int cargc, char **cargv) {
199 chanindex *cip=(chanindex *)chan;
200
201 if (cip->channel==NULL) {
202 return 1;
203 }
204
205 return !IsSecret(cip->channel);
206}
207
208int cs_invite(void *chan, int cargc, char **cargv) {
209 chanindex *cip=(chanindex *)chan;
210
211 if (cip->channel==NULL) {
212 return 1;
213 }
214
215 return !IsInviteOnly(cip->channel);
216}
217
218int cs_moderated(void *chan, int cargc, char **cargv) {
219 chanindex *cip=(chanindex *)chan;
220
221 if (cip->channel==NULL) {
222 return 1;
223 }
224
225 return !IsModerated(cip->channel);
226}
227
228int cs_modes(void *chan, int cargc, char **cargv) {
229 flag_t flags=0;
230 chanindex *cip=(chanindex *)chan;
231
232 if (cip->channel==NULL) {
233 return 1;
234 }
235
236 setflags(&flags, CHANMODE_ALL, cargv[0], cmodeflags, REJECT_NONE);
237
238 if ((cip->channel->flags & flags)!=flags) {
239 return 1;
240 }
241
242 flags=CHANMODE_ALL;
243 setflags(&flags, CHANMODE_ALL, cargv[0], cmodeflags, REJECT_NONE);
244
245 if ((cip->channel->flags & ~flags)) {
246 return 1;
247 }
248
249 return 0;
250}
251
252int numcompare(char *cmp, unsigned int num) {
253 int sz=strtol(&cmp[1],NULL,10);
254
255 switch(cmp[0]) {
256 case '>': if (num > sz)
257 return 0;
258 break;
259
260 case '<': if (num < sz)
261 return 0;
262 break;
263
264 case '=': if (num == sz)
265 return 0;
266 break;
267
268 default : return 1;
269 }
270
271 return 1;
272}
273
274void cs_describe(nick *sender, chanindex *cip) {
275 int i;
276 int op,voice,peon;
277 int oper,service;
278 nick *np;
279 chanuserhash *cuhp;
280
281 op=voice=peon=oper=service=0;
282
283 if (cip->channel==NULL) {
284 controlreply(sender,"[ Channel currently empty ] %s",cip->name->content);
285 } else {
286 cuhp=cip->channel->users;
287 for (i=0;i<cuhp->hashsize;i++) {
288 if (cuhp->content[i]!=nouser) {
289 if (cuhp->content[i]&CUMODE_OP) {
290 op++;
291 } else if (cuhp->content[i]&CUMODE_VOICE) {
292 voice++;
293 } else {
294 peon++;
295 }
296 if ((np=getnickbynumeric(cuhp->content[i]&CU_NUMERICMASK))!=NULL) {
297 if (IsOper(np)) {
298 oper++;
299 }
300 if (IsService(np)) {
301 service++;
302 }
303 }
304 }
305 }
306 controlreply(sender,"[ %4dU %4d@ %4d+ %4d %4d* %4dk ] %s",cuhp->totalusers,op,voice,peon,oper,service,cip->name->content);
307 }
308}