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