]> jfr.im git - irc/quakenet/newserv.git/blob - newsearch/newsearch.c
Sigh
[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 #include "../lib/version.h"
12
13 MODULE_VERSION("$Id: newsearch.c 663 2006-05-16 17:27:36Z newserv $")
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);
35
36 registersearchterm("eq",eq_parse);
37
38 registersearchterm("lt",lt_parse);
39 registersearchterm("gt",gt_parse);
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);
49 registersearchterm("authname",authname_parse);
50 registersearchterm("ident",ident_parse);
51 registersearchterm("host",host_parse);
52 registersearchterm("channel",channel_parse);
53 registersearchterm("timestamp",timestamp_parse);
54 registersearchterm("country",country_parse);
55
56 /* Nickname / channel operations */
57 registersearchterm("modes",modes_parse);
58
59 registercontrolhelpcmd("nicksearch",NO_OPER,4,do_nicksearch, "Usage: nicksearch <criteria>\nSearches for nicknames with the given criteria.");
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
90 if (cargc<1)
91 return CMD_USAGE;
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");
102 return CMD_USAGE;
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 */
211 argvector[0]="";
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++;
224 if(j >= (sizeof(argvector) / sizeof(*argvector))) {
225 parseError = "Too many arguments";
226 return NULL;
227 }
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 }
243
244 if (*(ch-1) == 0) /* if the last character was a space */
245 j--; /* remove an argument */
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 }