]>
Commit | Line | Data |
---|---|---|
c86edd1d Q |
1 | |
2 | #include <stdio.h> | |
3 | #include "newsearch.h" | |
4 | ||
5 | #include "../irc/irc_config.h" | |
6 | #include "../nick/nick.h" | |
7 | #include "../lib/irc_string.h" | |
8 | #include "../parser/parser.h" | |
9 | #include "../control/control.h" | |
10 | #include "../lib/splitline.h" | |
87698d77 CP |
11 | #include "../lib/version.h" |
12 | ||
09146147 | 13 | MODULE_VERSION("$Id: newsearch.c 786 2007-05-13 20:22:35Z newserv $") |
c86edd1d Q |
14 | |
15 | CommandTree *searchTree; | |
16 | ||
17 | int do_nicksearch(void *source, int cargc, char **cargv); | |
18 | struct searchNode *search_parse(int type, char *input); | |
19 | ||
20 | void registersearchterm(char *term, parseFunc parsefunc); | |
21 | void deregistersearchterm(char *term, parseFunc parsefunc); | |
22 | ||
23 | void *trueval(int type); | |
24 | void *falseval(int type); | |
25 | ||
26 | const char *parseError; | |
27 | ||
28 | void _init() { | |
29 | searchTree=newcommandtree(); | |
30 | ||
31 | /* Boolean operations */ | |
32 | registersearchterm("and",and_parse); | |
33 | registersearchterm("not",not_parse); | |
34 | registersearchterm("or",or_parse); | |
f1903ace | 35 | |
c86edd1d | 36 | registersearchterm("eq",eq_parse); |
f1903ace CP |
37 | |
38 | registersearchterm("lt",lt_parse); | |
39 | registersearchterm("gt",gt_parse); | |
c86edd1d Q |
40 | |
41 | /* String operations */ | |
42 | registersearchterm("match",match_parse); | |
43 | registersearchterm("regex",regex_parse); | |
44 | ||
45 | /* Nickname operations */ | |
46 | registersearchterm("hostmask",hostmask_parse); | |
47 | registersearchterm("realname",realname_parse); | |
48 | registersearchterm("nick",nick_parse); | |
052247fa | 49 | registersearchterm("authname",authname_parse); |
c86edd1d Q |
50 | registersearchterm("ident",ident_parse); |
51 | registersearchterm("host",host_parse); | |
52 | registersearchterm("channel",channel_parse); | |
f1903ace | 53 | registersearchterm("timestamp",timestamp_parse); |
c433958f | 54 | registersearchterm("country",country_parse); |
29161bbe | 55 | registersearchterm("ip",ip_parse); |
c86edd1d Q |
56 | |
57 | /* Nickname / channel operations */ | |
58 | registersearchterm("modes",modes_parse); | |
59 | ||
38cee035 | 60 | registercontrolhelpcmd("nicksearch",NO_OPER,4,do_nicksearch, "Usage: nicksearch <criteria>\nSearches for nicknames with the given criteria."); |
c86edd1d Q |
61 | } |
62 | ||
63 | void _fini() { | |
64 | destroycommandtree(searchTree); | |
65 | deregistercontrolcmd("nicksearch", do_nicksearch); | |
66 | } | |
67 | ||
68 | void registersearchterm(char *term, parseFunc parsefunc) { | |
69 | addcommandtotree(searchTree, term, 0, 0, (CommandHandler) parsefunc); | |
70 | } | |
71 | ||
72 | void deregistersearchterm(char *term, parseFunc parsefunc) { | |
73 | deletecommandfromtree(searchTree, term, (CommandHandler) parsefunc); | |
74 | } | |
75 | ||
76 | void printnick(nick *sender, nick *np) { | |
77 | char hostbuf[HOSTLEN+NICKLEN+USERLEN+4]; | |
78 | ||
79 | controlreply(sender,"%s [%s] (%s) (%s)",visiblehostmask(np,hostbuf), | |
80 | IPtostr(np->ipaddress), printflags(np->umodes, umodeflags), np->realname->name->content); | |
81 | } | |
82 | ||
83 | int do_nicksearch(void *source, int cargc, char **cargv) { | |
84 | nick *sender=source, *np; | |
85 | int i; | |
86 | struct searchNode *search; | |
87 | int limit=500,matches=0; | |
88 | char *ch; | |
89 | int arg=0; | |
90 | ||
38cee035 CP |
91 | if (cargc<1) |
92 | return CMD_USAGE; | |
c86edd1d Q |
93 | |
94 | if (*cargv[0] == '-') { | |
95 | /* options */ | |
96 | arg++; | |
97 | ||
98 | for (ch=cargv[0]+1;*ch;ch++) { | |
99 | switch(*ch) { | |
100 | case 'l': | |
101 | if (cargc<arg) { | |
102 | controlreply(sender,"Error: -l switch requires an argument"); | |
38cee035 | 103 | return CMD_USAGE; |
c86edd1d Q |
104 | } |
105 | limit=strtoul(cargv[arg++],NULL,10); | |
106 | break; | |
107 | ||
108 | default: | |
109 | controlreply(sender,"Unrecognised flag -%c.",*ch); | |
110 | } | |
111 | } | |
112 | } | |
113 | ||
114 | if (arg>=cargc) { | |
115 | controlreply(sender,"No search terms - aborting."); | |
116 | return CMD_ERROR; | |
117 | } | |
118 | ||
119 | if (arg<(cargc-1)) { | |
120 | rejoinline(cargv[arg],cargc-arg); | |
121 | } | |
122 | ||
123 | if (!(search = search_parse(SEARCHTYPE_NICK, cargv[arg]))) { | |
124 | controlreply(sender,"Parse error: %s",parseError); | |
125 | return CMD_ERROR; | |
126 | } | |
127 | ||
128 | for (i=0;i<NICKHASHSIZE;i++) { | |
129 | for (np=nicktable[i];np;np=np->next) { | |
130 | if ((search->exe)(search, RETURNTYPE_BOOL, np)) { | |
131 | if (matches<limit) | |
132 | printnick(sender, np); | |
133 | if (matches==limit) | |
134 | controlreply(sender, "--- More than %d matches, skipping the rest",limit); | |
135 | matches++; | |
136 | } | |
137 | } | |
138 | } | |
139 | ||
140 | (search->free)(search); | |
141 | ||
142 | controlreply(sender,"--- End of list: %d matches", matches); | |
143 | ||
144 | return CMD_OK; | |
145 | } | |
146 | ||
147 | void *trueval(int type) { | |
148 | switch(type) { | |
149 | default: | |
150 | case RETURNTYPE_INT: | |
151 | case RETURNTYPE_BOOL: | |
152 | return (void *)1; | |
153 | ||
154 | case RETURNTYPE_STRING: | |
155 | return "1"; | |
156 | } | |
157 | } | |
158 | ||
159 | void *falseval(int type) { | |
160 | switch (type) { | |
161 | default: | |
162 | case RETURNTYPE_INT: | |
163 | case RETURNTYPE_BOOL: | |
164 | return NULL; | |
165 | ||
166 | case RETURNTYPE_STRING: | |
167 | return ""; | |
168 | } | |
169 | } | |
170 | ||
171 | ||
172 | /* | |
173 | * LITERAL node type: used by the top level parse function | |
174 | */ | |
175 | ||
176 | struct literal_localdata { | |
177 | int intval; | |
178 | int boolval; | |
179 | sstring *stringval; | |
180 | }; | |
181 | ||
182 | void literal_free(struct searchNode *thenode); | |
183 | void *literal_exe(struct searchNode *thenode, int type, void *theinput); | |
184 | ||
185 | /* search_parse: | |
186 | * Given an input string, return a searchNode. | |
187 | */ | |
188 | ||
189 | struct searchNode *search_parse(int type, char *input) { | |
190 | /* OK, we need to split the input into chunks on spaces and brackets.. */ | |
191 | char *argvector[100]; | |
192 | int i,j; | |
193 | char *ch; | |
194 | struct Command *cmd; | |
195 | struct searchNode *thenode; | |
196 | struct literal_localdata *localdata; | |
197 | ||
198 | /* If it starts with a bracket, it's a function call.. */ | |
199 | if (*input=='(') { | |
200 | /* Skip past string */ | |
201 | for (ch=input;*ch;ch++); | |
202 | if (*(ch-1) != ')') { | |
203 | parseError = "Bracket mismatch!"; | |
204 | return NULL; | |
205 | } | |
206 | input++; | |
207 | *(ch-1)='\0'; | |
208 | ||
209 | /* Split further args */ | |
210 | i=-1; /* i = -1 BoW, 0 = inword, 1 = bracket nest depth */ | |
211 | j=0; /* j = current arg */ | |
a33e0d2b | 212 | argvector[0]=""; |
c86edd1d Q |
213 | for (ch=input;*ch;ch++) { |
214 | if (i==-1) { | |
215 | argvector[j]=ch; | |
216 | if (*ch=='(') { | |
217 | i=1; | |
218 | } else if (*ch != ' ') { | |
219 | i=0; | |
220 | } | |
221 | } else if (i==0) { | |
222 | if (*ch==' ') { | |
223 | *ch='\0'; | |
224 | j++; | |
4cd6347c P |
225 | if(j >= (sizeof(argvector) / sizeof(*argvector))) { |
226 | parseError = "Too many arguments"; | |
227 | return NULL; | |
228 | } | |
c86edd1d Q |
229 | i=-1; |
230 | } | |
231 | } else { | |
232 | if (*ch=='(') { | |
233 | i++; | |
234 | } else if (*ch==')') { | |
235 | i--; | |
236 | } | |
237 | } | |
238 | } | |
239 | ||
240 | if (i>0) { | |
241 | parseError = "Bracket mismatch!"; | |
242 | return NULL; | |
243 | } | |
4cd6347c P |
244 | |
245 | if (*(ch-1) == 0) /* if the last character was a space */ | |
246 | j--; /* remove an argument */ | |
c86edd1d Q |
247 | |
248 | if (!(cmd=findcommandintree(searchTree,argvector[0],1))) { | |
249 | parseError = "Unknown command"; | |
250 | return NULL; | |
251 | } else { | |
252 | return ((parseFunc)cmd->handler)(type, j, argvector+1); | |
253 | } | |
254 | } else { | |
255 | /* Literal */ | |
256 | thenode=(struct searchNode *)malloc(sizeof(struct searchNode)); | |
257 | localdata=(struct literal_localdata *)malloc(sizeof (struct literal_localdata)); | |
258 | ||
259 | localdata->stringval=getsstring(input,512); | |
260 | localdata->intval=strtol(input,NULL,10); | |
261 | if (input==NULL || *input=='\0') { | |
262 | localdata->boolval = 0; | |
263 | } else { | |
264 | localdata->boolval = 1; | |
265 | } | |
266 | ||
267 | thenode->localdata = localdata; | |
268 | thenode->returntype = RETURNTYPE_CONST | RETURNTYPE_STRING; | |
269 | thenode->exe = literal_exe; | |
270 | thenode->free = literal_free; | |
271 | ||
272 | return thenode; | |
273 | } | |
274 | } | |
275 | ||
276 | void *literal_exe(struct searchNode *thenode, int type, void *theinput) { | |
277 | struct literal_localdata *localdata; | |
278 | ||
279 | localdata=thenode->localdata; | |
280 | ||
281 | switch (type) { | |
282 | case RETURNTYPE_STRING: | |
283 | return (void *)(localdata->stringval->content); | |
284 | ||
285 | default: | |
286 | case RETURNTYPE_BOOL: | |
287 | return (void *)(localdata->boolval); | |
288 | ||
289 | case RETURNTYPE_INT: | |
290 | return (void *)(localdata->intval); | |
291 | } | |
292 | } | |
293 | ||
294 | void literal_free(struct searchNode *thenode) { | |
295 | struct literal_localdata *localdata; | |
296 | ||
297 | localdata=thenode->localdata; | |
298 | ||
299 | freesstring(localdata->stringval); | |
300 | free(localdata); | |
301 | free(thenode); | |
302 | } |