]>
Commit | Line | Data |
---|---|---|
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 | 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 !"); | |
53 | } | |
54 | ||
55 | void finichansearch() { | |
56 | deregistercontrolcmd("chansearch",&dochansearch); | |
57 | destroycommandtree(searchfilters); | |
58 | } | |
59 | ||
60 | void regchansearchfunc(const char *name, int args, CommandHandler handler) { | |
61 | addcommandtotree(searchfilters, name, 0, args, handler); | |
62 | } | |
63 | ||
64 | void unregchansearchfunc(const char *name, CommandHandler handler) { | |
65 | deletecommandfromtree(searchfilters, name, handler); | |
66 | } | |
67 | ||
68 | int 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 | ||
79 | if (cargc<1) | |
80 | return CMD_USAGE; | |
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 | ||
141 | int cs_name(void *chan, int cargc, char **cargv) { | |
142 | chanindex *cip=(chanindex *)chan; | |
143 | ||
144 | return !match2strings(cargv[0],cip->name->content); | |
145 | } | |
146 | ||
147 | int cs_exists(void *chan, int cargc, char **cargv) { | |
148 | chanindex *cip=(chanindex *)chan; | |
149 | ||
150 | return (cip->channel==NULL); | |
151 | } | |
152 | ||
153 | int 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 | ||
172 | int 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 | ||
182 | int cs_namelen(void *chan, int cargc, char **cargv) { | |
183 | chanindex *cip=(chanindex *)chan; | |
184 | ||
185 | return numcompare(cargv[0],cip->name->length); | |
186 | } | |
187 | ||
188 | int 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 | ||
198 | int 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 | ||
208 | int 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 | ||
218 | int 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 | ||
228 | int 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 | ||
252 | int 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 | ||
274 | void 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 | } |