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