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