]>
jfr.im git - irc/quakenet/newserv.git/blob - chansearch/chansearch.c
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"
12 #define MAXMATCHES 500
14 CommandTree
* searchfilters
;
15 CommandTree
* outputfilters
;
17 typedef struct modeflags
{
22 void cs_describe ( nick
* sender
, chanindex
* cip
);
23 void cs_desctopic ( nick
* sender
, chanindex
* cip
);
24 void cs_descservices ( nick
* sender
, chanindex
* cip
);
25 int cs_exists ( void * chan
, int cargc
, char ** cargv
);
26 int cs_services ( void * chan
, int cargc
, char ** cargv
);
27 int cs_nick ( void * chan
, int cargc
, char ** cargv
);
28 int cs_size ( void * chan
, int cargc
, char ** cargv
);
29 int cs_namelen ( void * chan
, int cargc
, char ** cargv
);
30 int cs_modes ( void * chan
, int cargc
, char ** cargv
);
31 int cs_name ( void * chan
, int cargc
, char ** cargv
);
32 int cs_topic ( void * source
, int cargc
, char ** cargv
);
33 int cs_oppct ( void * source
, int cargc
, char ** cargv
);
34 int cs_hostpct ( void * source
, int cargc
, char ** cargv
);
35 int cs_authedpct ( void * source
, int cargc
, char ** cargv
);
37 int dochansearch ( void * source
, int cargc
, char ** cargv
);
40 searchfilters
= newcommandtree ();
41 outputfilters
= newcommandtree ();
43 regchansearchfunc ( "name" , 1 , cs_name
);
44 regchansearchfunc ( "exists" , 0 , cs_exists
);
45 regchansearchfunc ( "services" , 1 , cs_services
);
46 regchansearchfunc ( "nick" , 1 , cs_nick
);
47 regchansearchfunc ( "size" , 1 , cs_size
);
48 regchansearchfunc ( "namelen" , 1 , cs_namelen
);
49 regchansearchfunc ( "modes" , 1 , cs_modes
);
50 regchansearchfunc ( "topic" , 1 , cs_topic
);
51 regchansearchfunc ( "oppercent" , 1 , cs_oppct
);
52 regchansearchfunc ( "uniquehostpct" , 1 , cs_hostpct
);
53 regchansearchfunc ( "authedpct" , 1 , cs_authedpct
);
55 regchansearchdisp ( "default" , cs_describe
);
56 regchansearchdisp ( "topic" , cs_desctopic
);
57 regchansearchdisp ( "services" , cs_descservices
);
59 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." );
63 deregistercontrolcmd ( "chansearch" ,& dochansearch
);
64 destroycommandtree ( searchfilters
);
65 destroycommandtree ( outputfilters
);
68 void regchansearchfunc ( const char * name
, int args
, CommandHandler handler
) {
69 addcommandtotree ( searchfilters
, name
, 0 , args
, handler
);
72 void unregchansearchfunc ( const char * name
, CommandHandler handler
) {
73 deletecommandfromtree ( searchfilters
, name
, handler
);
76 void regchansearchdisp ( const char * name
, DisplayFunc handler
) {
77 addcommandtotree ( outputfilters
, name
, 0 , 0 , ( CommandHandler
) handler
);
80 void unregchansearchdisp ( const char * name
, DisplayFunc handler
) {
81 deletecommandfromtree ( outputfilters
, name
, ( CommandHandler
) handler
);
84 int dochansearch ( void * source
, int cargc
, char ** cargv
) {
85 nick
* sender
=( nick
*) source
;
86 filter terms
[ MAXTERMS
];
96 DisplayFunc df
= cs_describe
;
99 if ( cargc
> 0 && cargv
[ 0 ][ 0 ]== '-' ) {
100 /* We have options, parse them */
102 for ( ch
= cargv
[ 0 ];* ch
; ch
++) {
104 case 'l' : limit
= strtol ( cargv
[ i
++], NULL
, 10 );
107 case 'd' : if (( mc
= findcommandintree ( outputfilters
, cargv
[ i
], 1 ))== NULL
) {
108 controlreply ( sender
, "Invalid display format %s " , cargv
[ i
]);
111 df
=( DisplayFunc
)( mc
-> handler
);
123 Command
* cmdlist
[ 100 ];
127 controlreply ( sender
, "Usage: chansearch [options] (search terms)" );
128 controlreply ( sender
, " Note that all options must be bundled together (-ld 5 default not -l 5 -d default)" );
129 controlreply ( sender
, " Current valid options:" );
130 controlreply ( sender
, " -l <number> Set maximum number of results to return" );
131 controlreply ( sender
, " -d <format> Set output display format" );
133 /* Get list of display formats */
137 n
= getcommandlist ( outputfilters
, cmdlist
, 100 );
139 for ( j
= 0 ; j
< cmdlist
[ i
]-> command
-> length
; j
++) {
140 buf
[ bufpos
++]= ToLower ( cmdlist
[ i
]-> command
-> content
[ j
]);
143 bufpos
+= sprintf (& buf
[ bufpos
], ", " );
146 bufpos
+= sprintf (& buf
[ bufpos
], " ..." );
153 controlreply ( sender
, " Valid display formats: %s " , buf
);
155 /* Get list of search terms */
159 n
= getcommandlist ( searchfilters
, cmdlist
, 100 );
161 for ( j
= 0 ; j
< cmdlist
[ i
]-> command
-> length
; j
++) {
162 buf
[ bufpos
++]= ToLower ( cmdlist
[ i
]-> command
-> content
[ j
]);
165 bufpos
+= sprintf (& buf
[ bufpos
], ", " );
168 bufpos
+= sprintf (& buf
[ bufpos
], " ..." );
174 controlreply ( sender
, " Valid search terms: %s " , buf
);
175 controlreply ( sender
, " Terms can be inverted with !" );
180 if ( cargv
[ i
][ 0 ]== '!' ) {
182 terms
[ numterms
]. invert
= 1 ;
185 terms
[ numterms
]. invert
= 0 ;
187 terms
[ numterms
]. mallocarg
= 0 ;
189 /* Do some sanity checking. Note that the "goto"s allows memory
190 * to be freed if successful filters have already allocated some */
191 if (( mc
= findcommandintree ( searchfilters
, & cargv
[ i
][ offset
], 1 ))== NULL
) {
192 controlreply ( sender
, "Unrecognised search term: %s " , cargv
[ i
]);
195 if (( cargc
- i
- 1 ) < mc
-> maxparams
) {
196 controlreply ( sender
, "Not enough arguments supplied for %s " , cargv
[ i
]);
200 /* Call the setup function. This should fill in the function and argument in the structure */
201 if (( mc
-> handler
)(( void *)& terms
[ numterms
], mc
-> maxparams
, cargv
+ i
+ 1 )) {
202 controlreply ( sender
, "Error setting up filter: %s " , cargv
[ i
]);
205 i
+=( mc
-> maxparams
+ 1 );
208 if ( numterms
== MAXTERMS
)
212 controlreply ( sender
, "The following channels match your criteria:" );
214 for ( i
= 0 ; i
< CHANNELHASHSIZE
; i
++) {
215 for ( cip
= chantable
[ i
]; cip
; cip
= cip
-> next
) {
216 for ( j
= 0 ; j
< numterms
; j
++) {
217 res
=( terms
[ j
]. sf
)( cip
, terms
[ j
]. arg
);
218 if ( res
== 0 && terms
[ j
]. invert
)
220 if ( res
== 1 && ! terms
[ j
]. invert
)
224 if ( matched
== limit
) {
225 controlreply ( sender
, "--- More than %d matches found, truncating list." , limit
);
227 if ( matched
< limit
) {
236 controlreply ( sender
, "--- No matches found." );
238 controlreply ( sender
, "--- End of list: %d match(es)." , matched
);
241 /* GOTO target: here we just free the args if any were malloc()d */
243 for ( i
= 0 ; i
< numterms
; i
++) {
244 if ( terms
[ i
]. mallocarg
) {
253 /* Name search execute function: call match2strings */
254 int cs_nameexe ( chanindex
* cip
, void * arg
) {
255 char * pattern
=( char *) arg
;
257 return ! match2strings ( pattern
, cip
-> name
-> content
);
260 /* Name search setup function: fill in the struct */
262 int cs_name ( void * source
, int cargc
, char ** cargv
) {
263 filter
* thefilter
=( filter
*) source
;
265 thefilter
-> sf
= cs_nameexe
;
266 thefilter
-> arg
=( char *) cargv
[ 0 ];
271 int cs_topicexe ( chanindex
* cip
, void * arg
) {
272 char * pattern
=( char *) arg
;
274 return (( cip
-> channel
== NULL
) ||
275 ( cip
-> channel
-> topic
== NULL
) ||
276 (! match2strings ( pattern
, cip
-> channel
-> topic
-> content
)));
279 int cs_topic ( void * source
, int cargc
, char ** cargv
) {
280 filter
* thefilter
=( filter
*) source
;
282 thefilter
-> sf
= cs_topicexe
;
283 thefilter
-> arg
=( void *) cargv
[ 0 ];
288 /* services - matches if the specified number of services are in the channel */
290 int cs_servicesexe ( chanindex
* cip
, void * arg
) {
295 if ( cip
-> channel
== NULL
)
298 for ( i
= 0 ; i
< cip
-> channel
-> users
-> hashsize
; i
++) {
299 if ( cip
-> channel
-> users
-> content
[ i
]== nouser
)
302 if (!( np
= getnickbynumeric ( cip
-> channel
-> users
-> content
[ i
])))
305 if ( IsService ( np
) && !-- count
)
312 int cs_services ( void * source
, int cargc
, char ** cargv
) {
313 filter
* thefilter
=( filter
*) source
;
315 thefilter
-> sf
= cs_servicesexe
;
316 thefilter
-> arg
=( void *) strtoul ( cargv
[ 0 ], NULL
, 10 );
321 int cs_existsexe ( chanindex
* cip
, void * arg
) {
322 return ( cip
-> channel
== NULL
);
325 int cs_exists ( void * source
, int cargc
, char ** cargv
) {
326 filter
* thefilter
=( filter
*) source
;
328 thefilter
-> sf
= cs_existsexe
;
334 int cs_nickexe ( chanindex
* cip
, void * arg
) {
335 nick
* np
=( nick
*) arg
;
337 return (( cip
-> channel
== NULL
) ||
338 ( getnumerichandlefromchanhash ( cip
-> channel
-> users
, np
-> numeric
)== NULL
));
341 int cs_nick ( void * source
, int cargc
, char ** cargv
) {
342 filter
* thefilter
=( filter
*) source
;
345 if (( np
= getnickbynick ( cargv
[ 0 ]))== NULL
) {
349 thefilter
-> sf
= cs_nickexe
;
350 thefilter
-> arg
=( void *) np
;
355 int cs_sizeexe ( chanindex
* cip
, void * arg
) {
358 return (( cip
-> channel
== NULL
) ||
359 ( cip
-> channel
-> users
-> totalusers
< lim
));
362 int cs_size ( void * source
, int cargc
, char ** cargv
) {
363 filter
* thefilter
=( filter
*) source
;
365 thefilter
-> sf
= cs_sizeexe
;
366 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
371 int cs_namelenexe ( chanindex
* cip
, void * arg
) {
374 return ( cip
-> name
-> length
< lim
);
377 int cs_namelen ( void * source
, int cargc
, char ** cargv
) {
378 filter
* thefilter
=( filter
*) source
;
380 thefilter
-> sf
= cs_namelenexe
;
381 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
386 int cs_oppctexe ( chanindex
* cip
, void * arg
) {
387 int percent
=( int ) arg
;
391 if ( cip
-> channel
== NULL
) {
395 nonop
=( cip
-> channel
-> users
-> totalusers
)-(( cip
-> channel
-> users
-> totalusers
* percent
)/ 100 );
397 for ( i
= 0 ; i
< cip
-> channel
-> users
-> hashsize
; i
++) {
398 if ( cip
-> channel
-> users
-> content
[ i
]!= nouser
) {
399 if (!( cip
-> channel
-> users
-> content
[ i
] & CUMODE_OP
)) {
410 int cs_oppct ( void * source
, int cargc
, char ** cargv
) {
411 filter
* thefilter
=( filter
*) source
;
413 thefilter
-> sf
= cs_oppctexe
;
414 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
419 int cs_hostpctexe ( chanindex
* cip
, void * arg
) {
420 int percent
=( int ) arg
;
426 if ( cip
-> channel
== NULL
) {
430 marker
= nexthostmarker ();
432 hostreq
=( cip
-> channel
-> users
-> totalusers
* percent
) / 100 ;
434 for ( i
= 0 ; i
< cip
-> channel
-> users
-> hashsize
; i
++) {
435 if ( cip
-> channel
-> users
-> content
[ i
]== nouser
)
438 if (!( np
= getnickbynumeric ( cip
-> channel
-> users
-> content
[ i
])))
441 if ( np
-> host
-> marker
!= marker
) {
442 /* new unique host */
443 if (-- hostreq
<= 0 ) {
446 np
-> host
-> marker
= marker
;
453 int cs_hostpct ( void * source
, int cargc
, char ** cargv
) {
454 filter
* thefilter
= source
;
456 thefilter
-> sf
= cs_hostpctexe
;
457 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
462 int cs_authedpctexe ( chanindex
* cip
, void * arg
) {
471 for ( i
= 0 ; i
< cip
-> channel
-> users
-> hashsize
; i
++) {
472 if ( cip
-> channel
-> users
-> content
[ i
]== nouser
)
475 if (( np
= getnickbynumeric ( cip
-> channel
-> users
-> content
[ i
])) && IsAccount ( np
))
479 if ((( j
* 100 ) / cip
-> channel
-> users
-> totalusers
) >= pct
)
485 int cs_authedpct ( void * source
, int cargc
, char ** cargv
) {
486 filter
* thefilter
= source
;
488 thefilter
-> sf
= cs_authedpctexe
;
489 thefilter
-> arg
=( void *) strtol ( cargv
[ 0 ], NULL
, 10 );
494 int cs_modesexe ( chanindex
* cip
, void * arg
) {
495 struct modeflags
* mf
=( struct modeflags
*) arg
;
497 return (( cip
-> channel
== NULL
) ||
498 (( cip
-> channel
-> flags
& mf
-> setflags
) != mf
-> setflags
) ||
499 ( cip
-> channel
-> flags
& mf
-> clearflags
));
502 int cs_modes ( void * source
, int cargc
, char ** cargv
) {
503 filter
* thefilter
=( filter
*) source
;
504 struct modeflags
* mf
;
507 mf
=( void *) malloc ( sizeof ( struct modeflags
));
509 setflags (& flags
, CHANMODE_ALL
, cargv
[ 0 ], cmodeflags
, REJECT_NONE
);
514 setflags (& flags
, CHANMODE_ALL
, cargv
[ 0 ], cmodeflags
, REJECT_NONE
);
516 mf
-> clearflags
=~ flags
;
518 thefilter
-> sf
= cs_modesexe
;
519 thefilter
-> arg
=( void *) mf
;
520 thefilter
-> mallocarg
= 1 ;
525 void cs_describe ( nick
* sender
, chanindex
* cip
) {
528 int oper
, service
, hosts
;
533 op
= voice
= peon
= oper
= service
= hosts
= 0 ;
534 marker
= nexthostmarker ();
536 if ( cip
-> channel
== NULL
) {
537 controlreply ( sender
, "[ Channel currently empty ] %s " , cip
-> name
-> content
);
539 cuhp
= cip
-> channel
-> users
;
540 for ( i
= 0 ; i
< cuhp
-> hashsize
; i
++) {
541 if ( cuhp
-> content
[ i
]!= nouser
) {
542 if ( cuhp
-> content
[ i
]& CUMODE_OP
) {
544 } else if ( cuhp
-> content
[ i
]& CUMODE_VOICE
) {
549 if (( np
= getnickbynumeric ( cuhp
-> content
[ i
]& CU_NUMERICMASK
))!= NULL
) {
556 if ( np
-> host
-> marker
!= marker
) {
557 np
-> host
-> marker
= marker
;
563 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
,
564 cip
-> name
-> content
, printflags ( cip
-> channel
-> flags
, cmodeflags
));
568 void cs_desctopic ( nick
* sender
, chanindex
* cip
) {
569 if ( cip
-> channel
== NULL
) {
570 controlreply ( sender
, "[ empty ] %-30s" , cip
-> name
-> content
);
572 controlreply ( sender
, "[ %4 u users] %s ( %s )" , cip
-> channel
-> users
-> totalusers
, cip
-> name
-> content
, cip
-> channel
-> topic
? cip
-> channel
-> topic
-> content
: "no topic" );
576 void cs_descservices ( nick
* sender
, chanindex
* cip
) {
580 int slpos
= 0 , slfull
= 0 ;
584 if ( cip
-> channel
== NULL
) {
585 controlreply ( sender
, "%-30s empty" , cip
-> name
-> content
);
587 cuhp
= cip
-> channel
-> users
;
588 for ( i
= 0 ; i
< cuhp
-> hashsize
; i
++) {
589 if ( cuhp
-> content
[ i
]!= nouser
) {
590 if (( np
= getnickbynumeric ( cuhp
-> content
[ i
]& CU_NUMERICMASK
))) {
595 slpos
+= sprintf (& servlist
[ slpos
], ", " );
597 slpos
+= sprintf (& servlist
[ slpos
], " %s " , np
-> nick
);
599 sprintf (& servlist
[ slpos
], ", ..." );
608 controlreply ( sender
, "%-30s %5 d user %c %2 d service %c %s%s%s " , cip
-> name
-> content
, cuhp
-> totalusers
,
609 cuhp
-> totalusers
> 1 ? 's' : ' ' , servs
,( servs
== 1 )? ' ' : 's' , servs
? "(" : "" , slpos
? servlist
: "" , servs
? ")" : "" );