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