]>
jfr.im git - irc/quakenet/newserv.git/blob - chansearch/chansearch.c
a871a5e1055cd01010d1e9f1e83b47199824ea84
1 #include "chansearch.h"
2 #include "../parser/parser.h"
3 #include "../nick/nick.h"
4 #include "../channel/channel.h"
5 #include "../control/control.h"
6 #include "../lib/flags.h"
7 #include "../lib/irc_string.h"
8 #include "../lib/version.h"
15 #define MAXMATCHES 500
17 CommandTree
* searchfilters
;
18 CommandTree
* outputfilters
;
20 typedef struct modeflags
{
25 void cs_describe ( nick
* sender
, chanindex
* cip
);
26 void cs_desctopic ( nick
* sender
, chanindex
* cip
);
27 void cs_descservices ( nick
* sender
, chanindex
* cip
);
28 int cs_exists ( void * chan
, int cargc
, char ** cargv
);
29 int cs_services ( void * chan
, int cargc
, char ** cargv
);
30 int cs_nick ( void * chan
, int cargc
, char ** cargv
);
31 int cs_size ( void * chan
, int cargc
, char ** cargv
);
32 int cs_namelen ( void * chan
, int cargc
, char ** cargv
);
33 int cs_modes ( void * chan
, int cargc
, char ** cargv
);
34 int cs_name ( void * chan
, int cargc
, char ** cargv
);
35 int cs_topic ( void * source
, int cargc
, char ** cargv
);
36 int cs_oppct ( void * source
, int cargc
, char ** cargv
);
37 int cs_hostpct ( void * source
, int cargc
, char ** cargv
);
38 int cs_authedpct ( void * source
, int cargc
, char ** cargv
);
40 int dochansearch ( void * source
, int cargc
, char ** cargv
);
43 searchfilters
= newcommandtree ();
44 outputfilters
= newcommandtree ();
46 regchansearchfunc ( "name" , 1 , cs_name
);
47 regchansearchfunc ( "exists" , 0 , cs_exists
);
48 regchansearchfunc ( "services" , 1 , cs_services
);
49 regchansearchfunc ( "nick" , 1 , cs_nick
);
50 regchansearchfunc ( "size" , 1 , cs_size
);
51 regchansearchfunc ( "namelen" , 1 , cs_namelen
);
52 regchansearchfunc ( "modes" , 1 , cs_modes
);
53 regchansearchfunc ( "topic" , 1 , cs_topic
);
54 regchansearchfunc ( "oppercent" , 1 , cs_oppct
);
55 regchansearchfunc ( "uniquehostpct" , 1 , cs_hostpct
);
56 regchansearchfunc ( "authedpct" , 1 , cs_authedpct
);
58 regchansearchdisp ( "default" , cs_describe
);
59 regchansearchdisp ( "topic" , cs_desctopic
);
60 regchansearchdisp ( "services" , cs_descservices
);
62 registercontrolhelpcmd ( "chansearch" , NO_OPER
, 19 ,& dochansearch
, "Usage: chansearch <criteria> \n Searches for channels with specified criteria. \n Send chanstats with no arguments for more information." );
66 deregistercontrolcmd ( "chansearch" ,& dochansearch
);
67 destroycommandtree ( searchfilters
);
68 destroycommandtree ( outputfilters
);
71 void regchansearchfunc ( const char * name
, int args
, CommandHandler handler
) {
72 addcommandtotree ( searchfilters
, name
, 0 , args
, handler
);
75 void unregchansearchfunc ( const char * name
, CommandHandler handler
) {
76 deletecommandfromtree ( searchfilters
, name
, handler
);
79 void regchansearchdisp ( const char * name
, DisplayFunc handler
) {
80 addcommandtotree ( outputfilters
, name
, 0 , 0 , ( CommandHandler
) handler
);
83 void unregchansearchdisp ( const char * name
, DisplayFunc handler
) {
84 deletecommandfromtree ( outputfilters
, name
, ( CommandHandler
) handler
);
87 int dochansearch ( void * source
, int cargc
, char ** cargv
) {
88 nick
* sender
=( nick
*) source
;
89 filter terms
[ MAXTERMS
];
99 DisplayFunc df
= cs_describe
;
102 if ( cargc
> 0 && cargv
[ 0 ][ 0 ]== '-' ) {
103 /* We have options, parse them */
105 for ( ch
= cargv
[ 0 ];* ch
; ch
++) {
107 case 'l' : limit
= strtol ( cargv
[ i
++], NULL
, 10 );
110 case 'd' : if (( mc
= findcommandintree ( outputfilters
, cargv
[ i
], 1 ))== NULL
) {
111 controlreply ( sender
, "Invalid display format %s " , cargv
[ i
]);
114 df
=( DisplayFunc
)( mc
-> handler
);
126 Command
* cmdlist
[ 100 ];
130 controlreply ( sender
, "Usage: chansearch [options] (search terms)" );
131 controlreply ( sender
, " Note that all options must be bundled together (-ld 5 default not -l 5 -d default)" );
132 controlreply ( sender
, " Current valid options:" );
133 controlreply ( sender
, " -l <number> Set maximum number of results to return" );
134 controlreply ( sender
, " -d <format> Set output display format" );
136 /* Get list of display formats */
140 n
= getcommandlist ( outputfilters
, cmdlist
, 100 );
142 for ( j
= 0 ; j
< cmdlist
[ i
]-> command
-> length
; j
++) {
143 buf
[ bufpos
++]= ToLower ( cmdlist
[ i
]-> command
-> content
[ j
]);
146 bufpos
+= sprintf (& buf
[ bufpos
], ", " );
149 bufpos
+= sprintf (& buf
[ bufpos
], " ..." );
156 controlreply ( sender
, " Valid display formats: %s " , buf
);
158 /* Get list of search terms */
162 n
= getcommandlist ( searchfilters
, cmdlist
, 100 );
164 for ( j
= 0 ; j
< cmdlist
[ i
]-> command
-> length
; j
++) {
165 buf
[ bufpos
++]= ToLower ( cmdlist
[ i
]-> command
-> content
[ j
]);
168 bufpos
+= sprintf (& buf
[ bufpos
], ", " );
171 bufpos
+= sprintf (& buf
[ bufpos
], " ..." );
177 controlreply ( sender
, " Valid search terms: %s " , buf
);
178 controlreply ( sender
, " Terms can be inverted with !" );
183 if ( cargv
[ i
][ 0 ]== '!' ) {
185 terms
[ numterms
]. invert
= 1 ;
188 terms
[ numterms
]. invert
= 0 ;
190 terms
[ numterms
]. mallocarg
= 0 ;
192 /* Do some sanity checking. Note that the "goto"s allows memory
193 * to be freed if successful filters have already allocated some */
194 if (( mc
= findcommandintree ( searchfilters
, & cargv
[ i
][ offset
], 1 ))== NULL
) {
195 controlreply ( sender
, "Unrecognised search term: %s " , cargv
[ i
]);
198 if (( cargc
- i
- 1 ) < mc
-> maxparams
) {
199 controlreply ( sender
, "Not enough arguments supplied for %s " , cargv
[ i
]);
203 /* Call the setup function. This should fill in the function and argument in the structure */
204 if (( mc
-> handler
)(( void *)& terms
[ numterms
], mc
-> maxparams
, cargv
+ i
+ 1 )) {
205 controlreply ( sender
, "Error setting up filter: %s " , cargv
[ i
]);
208 i
+=( mc
-> maxparams
+ 1 );
211 if ( numterms
== MAXTERMS
)
215 controlreply ( sender
, "The following channels match your criteria:" );
217 for ( i
= 0 ; i
< CHANNELHASHSIZE
; i
++) {
218 for ( cip
= chantable
[ i
]; cip
; cip
= cip
-> next
) {
219 for ( j
= 0 ; j
< numterms
; j
++) {
220 res
=( terms
[ j
]. sf
)( cip
, terms
[ j
]. arg
);
221 if ( res
== 0 && terms
[ j
]. invert
)
223 if ( res
== 1 && ! terms
[ j
]. invert
)
227 if ( matched
== limit
) {
228 controlreply ( sender
, "--- More than %d matches found, truncating list." , limit
);
230 if ( matched
< limit
) {
239 controlreply ( sender
, "--- No matches found." );
241 controlreply ( sender
, "--- End of list: %d match(es)." , matched
);
244 /* GOTO target: here we just free the args if any were malloc()d */
246 for ( i
= 0 ; i
< numterms
; i
++) {
247 if ( terms
[ i
]. mallocarg
) {
256 /* Name search execute function: call match2strings */
257 int cs_nameexe ( chanindex
* cip
, void * arg
) {
258 char * pattern
=( char *) arg
;
260 return ! match2strings ( pattern
, cip
-> name
-> content
);
263 /* Name search setup function: fill in the struct */
265 int cs_name ( void * source
, int cargc
, char ** cargv
) {
266 filter
* thefilter
=( filter
*) source
;
268 thefilter
-> sf
= cs_nameexe
;
269 thefilter
-> arg
=( char *) cargv
[ 0 ];
274 int cs_topicexe ( chanindex
* cip
, void * arg
) {
275 char * pattern
=( char *) arg
;
277 return (( cip
-> channel
== NULL
) ||
278 ( cip
-> channel
-> topic
== NULL
) ||
279 (! match2strings ( pattern
, cip
-> channel
-> topic
-> content
)));
282 int cs_topic ( void * source
, int cargc
, char ** cargv
) {
283 filter
* thefilter
=( filter
*) source
;
285 thefilter
-> sf
= cs_topicexe
;
286 thefilter
-> arg
=( void *) cargv
[ 0 ];
291 /* services - matches if the specified number of services are in the channel */
293 int cs_servicesexe ( chanindex
* cip
, void * arg
) {
298 if ( cip
-> channel
== NULL
)
301 for ( i
= 0 ; i
< cip
-> channel
-> users
-> hashsize
; i
++) {
302 if ( cip
-> channel
-> users
-> content
[ i
]== nouser
)
305 if (!( np
= getnickbynumeric ( cip
-> channel
-> users
-> content
[ i
])))
308 if ( IsService ( np
) && !-- count
)
315 int cs_services ( void * source
, int cargc
, char ** cargv
) {
316 filter
* thefilter
=( filter
*) source
;
318 thefilter
-> sf
= cs_servicesexe
;
319 thefilter
-> arg
=( void *) strtoul ( cargv
[ 0 ], NULL
, 10 );
324 int cs_existsexe ( chanindex
* cip
, void * arg
) {
325 return ( cip
-> channel
== NULL
);
328 int cs_exists ( void * source
, int cargc
, char ** cargv
) {
329 filter
* thefilter
=( filter
*) source
;
331 thefilter
-> sf
= cs_existsexe
;
337 int cs_nickexe ( chanindex
* cip
, void * arg
) {
338 nick
* np
=( nick
*) arg
;
340 return (( cip
-> channel
== NULL
) ||
341 ( getnumerichandlefromchanhash ( cip
-> channel
-> users
, np
-> numeric
)== NULL
));
344 int cs_nick ( void * source
, int cargc
, char ** cargv
) {
345 filter
* thefilter
=( filter
*) source
;
348 if (( np
= getnickbynick ( cargv
[ 0 ]))== NULL
) {
352 thefilter
-> sf
= cs_nickexe
;
353 thefilter
-> arg
=( void *) np
;
358 int cs_sizeexe ( chanindex
* cip
, void * arg
) {
361 return (( cip
-> channel
== NULL
) ||
362 ( cip
-> channel
-> users
-> totalusers
< lim
));
365 int cs_size ( void * source
, int cargc
, char ** cargv
) {
366 filter
* thefilter
=( filter
*) source
;
368 thefilter
-> sf
= cs_sizeexe
;
369 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
374 int cs_namelenexe ( chanindex
* cip
, void * arg
) {
377 return ( cip
-> name
-> length
< lim
);
380 int cs_namelen ( void * source
, int cargc
, char ** cargv
) {
381 filter
* thefilter
=( filter
*) source
;
383 thefilter
-> sf
= cs_namelenexe
;
384 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
389 int cs_oppctexe ( chanindex
* cip
, void * arg
) {
390 int percent
=( int ) arg
;
394 if ( cip
-> channel
== NULL
) {
398 nonop
=( cip
-> channel
-> users
-> totalusers
)-(( cip
-> channel
-> users
-> totalusers
* percent
)/ 100 );
400 for ( i
= 0 ; i
< cip
-> channel
-> users
-> hashsize
; i
++) {
401 if ( cip
-> channel
-> users
-> content
[ i
]!= nouser
) {
402 if (!( cip
-> channel
-> users
-> content
[ i
] & CUMODE_OP
)) {
413 int cs_oppct ( void * source
, int cargc
, char ** cargv
) {
414 filter
* thefilter
=( filter
*) source
;
416 thefilter
-> sf
= cs_oppctexe
;
417 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
422 int cs_hostpctexe ( chanindex
* cip
, void * arg
) {
423 int percent
=( int ) arg
;
429 if ( cip
-> channel
== NULL
) {
433 marker
= nexthostmarker ();
435 hostreq
=( cip
-> channel
-> users
-> totalusers
* percent
) / 100 ;
437 for ( i
= 0 ; i
< cip
-> channel
-> users
-> hashsize
; i
++) {
438 if ( cip
-> channel
-> users
-> content
[ i
]== nouser
)
441 if (!( np
= getnickbynumeric ( cip
-> channel
-> users
-> content
[ i
])))
444 if ( np
-> host
-> marker
!= marker
) {
445 /* new unique host */
446 if (-- hostreq
<= 0 ) {
449 np
-> host
-> marker
= marker
;
456 int cs_hostpct ( void * source
, int cargc
, char ** cargv
) {
457 filter
* thefilter
= source
;
459 thefilter
-> sf
= cs_hostpctexe
;
460 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
465 int cs_authedpctexe ( chanindex
* cip
, void * arg
) {
474 for ( i
= 0 ; i
< cip
-> channel
-> users
-> hashsize
; i
++) {
475 if ( cip
-> channel
-> users
-> content
[ i
]== nouser
)
478 if (( np
= getnickbynumeric ( cip
-> channel
-> users
-> content
[ i
])) && IsAccount ( np
))
482 if ((( j
* 100 ) / cip
-> channel
-> users
-> totalusers
) >= pct
)
488 int cs_authedpct ( void * source
, int cargc
, char ** cargv
) {
489 filter
* thefilter
= source
;
491 thefilter
-> sf
= cs_authedpctexe
;
492 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
497 int cs_modesexe ( chanindex
* cip
, void * arg
) {
498 struct modeflags
* mf
=( struct modeflags
*) arg
;
500 return (( cip
-> channel
== NULL
) ||
501 (( cip
-> channel
-> flags
& mf
-> setflags
) != mf
-> setflags
) ||
502 ( cip
-> channel
-> flags
& mf
-> clearflags
));
505 int cs_modes ( void * source
, int cargc
, char ** cargv
) {
506 filter
* thefilter
=( filter
*) source
;
507 struct modeflags
* mf
;
510 mf
=( void *) malloc ( sizeof ( struct modeflags
));
512 setflags (& flags
, CHANMODE_ALL
, cargv
[ 0 ], cmodeflags
, REJECT_NONE
);
517 setflags (& flags
, CHANMODE_ALL
, cargv
[ 0 ], cmodeflags
, REJECT_NONE
);
519 mf
-> clearflags
=~ flags
;
521 thefilter
-> sf
= cs_modesexe
;
522 thefilter
-> arg
=( void *) mf
;
523 thefilter
-> mallocarg
= 1 ;
528 void cs_describe ( nick
* sender
, chanindex
* cip
) {
531 int oper
, service
, hosts
;
536 op
= voice
= peon
= oper
= service
= hosts
= 0 ;
537 marker
= nexthostmarker ();
539 if ( cip
-> channel
== NULL
) {
540 controlreply ( sender
, "[ Channel currently empty ] %s " , cip
-> name
-> content
);
542 cuhp
= cip
-> channel
-> users
;
543 for ( i
= 0 ; i
< cuhp
-> hashsize
; i
++) {
544 if ( cuhp
-> content
[ i
]!= nouser
) {
545 if ( cuhp
-> content
[ i
]& CUMODE_OP
) {
547 } else if ( cuhp
-> content
[ i
]& CUMODE_VOICE
) {
552 if (( np
= getnickbynumeric ( cuhp
-> content
[ i
]& CU_NUMERICMASK
))!= NULL
) {
559 if ( np
-> host
-> marker
!= marker
) {
560 np
-> host
-> marker
= marker
;
566 controlreply ( sender
, "[ %4 dU %4 d@ %4 d+ %4 d %4 d* %4 dk %4 dH ] %s ( %s )" , cuhp
-> totalusers
, op
, voice
, peon
, oper
, service
, hosts
,
567 cip
-> name
-> content
, printflags ( cip
-> channel
-> flags
, cmodeflags
));
571 void cs_desctopic ( nick
* sender
, chanindex
* cip
) {
572 if ( cip
-> channel
== NULL
) {
573 controlreply ( sender
, "[ empty ] %-30s" , cip
-> name
-> content
);
575 controlreply ( sender
, "[ %4 u users] %s ( %s )" , cip
-> channel
-> users
-> totalusers
, cip
-> name
-> content
, cip
-> channel
-> topic
? cip
-> channel
-> topic
-> content
: "no topic" );
579 void cs_descservices ( nick
* sender
, chanindex
* cip
) {
583 int slpos
= 0 , slfull
= 0 ;
587 if ( cip
-> channel
== NULL
) {
588 controlreply ( sender
, "%-30s empty" , cip
-> name
-> content
);
590 cuhp
= cip
-> channel
-> users
;
591 for ( i
= 0 ; i
< cuhp
-> hashsize
; i
++) {
592 if ( cuhp
-> content
[ i
]!= nouser
) {
593 if (( np
= getnickbynumeric ( cuhp
-> content
[ i
]& CU_NUMERICMASK
))) {
598 slpos
+= sprintf (& servlist
[ slpos
], ", " );
600 slpos
+= sprintf (& servlist
[ slpos
], " %s " , np
-> nick
);
602 sprintf (& servlist
[ slpos
], ", ..." );
611 controlreply ( sender
, "%-30s %5 d user %c %2 d service %c %s%s%s " , cip
-> name
-> content
, cuhp
-> totalusers
,
612 cuhp
-> totalusers
> 1 ? 's' : ' ' , servs
,( servs
== 1 )? ' ' : 's' , servs
? "(" : "" , slpos
? servlist
: "" , servs
? ")" : "" );