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