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