· 8 years ago · Jun 13, 2018, 12:08 AM
1#!/usr/bin/perl
2
3use warnings;
4use strict;
5
6################################################################################
7# #
8# operfilter.pl - xchat filter and oper communication script for UnrealdIRCd #
9# users. Helpop ChatOps GlobOps NaChat AdChat LocOps. #
10# #
11# Copyright (C) 2008, 2009 Sergio Luis <sergio at 0xffffff.org> #
12# Jeff Wooldridge <jefferoos at gmail.com> #
13# #
14# operfiler.pl is free software; you can redistribute it and/or modify #
15# it under the terms of the GNU General Public License as published by #
16# the Free Software Foundation; either version 2 of the License, or #
17# (at your option) any later version. #
18# #
19# operfilter.pl is distributed in the hope that it will be useful, #
20# but WITHOUT ANY WARRANTY; without even the implied warranty of #
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
22# GNU General Public License for more details. #
23# #
24# You should have received a copy of the GNU General Public License #
25# along with this program; if not, write to the Free Software #
26# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #
27# #
28################################################################################
29
30
31# Many credits goes to Sergio, and MCM for their help and support.
32
33
34# registering the script withing xchat
35Xchat::register("IRCop Windows/Filter for Xchat", "006", "Script for IRCops or Helpers", \&unload);
36
37# hooking the notices received from the server
38my $server_notice_hook = Xchat::hook_print("Server Notice", \&server_notice_handler);
39
40# hooking any non-command
41Xchat::hook_command("", \&non_command_handler);
42
43Xchat::hook_command("me", \&non_command_handler);
44Xchat::hook_command("notinchan", \¬_in_chan);
45Xchat::hook_command("who", \&who_command_handler);
46
47Xchat::hook_print("Join", \&on_helpop_join);
48
49Xchat::hook_print("Part", \&eat_parts_from_clients);
50Xchat::hook_print("Change Nick", \&eat_quit_on_tab);
51Xchat::hook_print("Quit", \&eat_quit_on_tab);
52Xchat::hook_print("Users On Channel", \&eat_quit_on_tab);
53
54# Used to block annoying errors when fake rooms are created and used.
55Xchat::hook_server("401", \&block_raws);
56Xchat::hook_server("403", \&block_raws);
57Xchat::hook_server("334", \&block_raws);
58
59# If you are a non-oper but recieve helpop messages change the %global_settings to
60# who => "#help", cb => \&helpop_who_handler,
61
62# if you are an oper using -HelpOp change your helpop hash too...
63# who => "+m-m h S", cb => \&std_who_handler,
64
65
66my $time = time();
67
68my %global_settings =
69(
70 helpop => {identifier => "HelpOp", tab => "-HelpOp", command => "helpop", who => "#help", cb => \&helpop_who_handler,},
71 chatops => {identifier => "ChatOps", tab => "-ChatOps", command => "chatops", who => "+m-m oO S", cb => \&std_who_handler,},
72 nachat => {identifier => "NetAdmin.Chat", tab => "-NAChat", command => "nachat", who => "+m-m N S", cb => \&std_who_handler,},
73 locops => {identifier => "LocOps", tab => "-LocOps", command => "locops", who => "+m-m o S", cb => \&std_who_handler,},
74 global => {identifier => "Global", tab => "-GlobOps", command => "globops", who => "+m o", cb => \&std_who_handler,},
75 adchat => {identifier => "AdminChat", tab => "-AdChat", command => "adchat", who => "+m-m aA S", cb => \&std_who_handler,},
76 clients => {identifier => "Client", tab => "-Clients", who => "+n \*", cb => \&std_who_handler,},
77 idle => {tab => "-NotInChan", who => "+i \*", cb => \&idle_who_handler,},
78);
79
80my $nicks_tab = "-NickChange";
81my $globals_tab = "-Global";
82my $services_tab = "-Services";
83my $kills_tab = "-Kills";
84
85
86# this routine deals with the notices received from the server. in our case, we are interested
87# in helpop/chatops notices
88sub server_notice_handler($)
89{
90 my ($notice, $server) = @{$_[0]};
91
92 # Remote and local client connection notices
93 if ($notice =~ s/^\*\*\* Notice -- (Client) (exiting|connecting)(?::|.*?): (.*?) //)
94 {
95 my $identifier = $1;
96 my $exit_connect = $2;
97 my $nick = $3;
98
99 # Gets hash info
100 my $settings = &get_settings_by_key("identifier", $identifier);
101 return Xchat::EAT_NONE if not defined($settings);
102
103 # when the tab on the server isnt found...
104 unless(Xchat::find_context($settings->{tab}, $server))
105 {
106 # Your current nickname on the specified server
107 my $mynick = Xchat::get_info("nick");
108
109 # Opens up a fake channel room and gives it some basic channel modes
110 Xchat::command("recv :$mynick!blah\@blah.net JOIN :$settings->{tab}");
111
112 # Adds a title to the Fake Channel
113 Xchat::command("recv :$server 324 $mynick $settings->{tab} +CLIENTS");
114 Xchat::command("recv :$server 329 $mynick $settings->{tab} 0");
115
116 # Used to make the userlist of the channel
117 Xchat::command("timer 1 who $settings->{who}");
118 }
119
120 # Exiting clients
121 if ($exit_connect eq "exiting")
122 {
123 # local and remote notices are not the same so this was done.
124 my ($nick_, $host) = split(/!/, $nick, 2);
125 &on_client_tab($server, $settings->{tab}, "\cC2\cB[E]\cO", "\cB$nick_\cO $host $notice") if defined ($host);
126 &on_client_tab($server, $settings->{tab}, "\cC2\cB[E]\cO", "\cB$nick_\cO $notice") if not defined ($host);
127
128 # When a client exits the server, Xchat removes the user from -Clients userlist.
129 Xchat::command("recv :$nick_\!meow\@blah.com PART $settings->{tab}");
130 }
131 # Connecting clients
132 else
133 {
134 # Your current nickname on the specified server
135 my $mynick = Xchat::get_info("nick");
136
137 &on_client_tab( $server, $settings->{tab}, "\cC3\cB[C]\cO", "\cB$nick\cO $notice");
138
139 # When a new person connects, adds them to the userlist
140 Xchat::command("recv :$server 353 $mynick = $settings->{tab} :$mynick $nick");
141 }
142 }
143 # prints events from services *** Global -- from NickServ: blah
144 elsif ($notice =~ s/^\*\*\* Global \-\- from (\w+Serv|.*?\.(net|org|com)): //)
145 {
146 my $nickname = $1;
147 &on_query_new_tab_print($server, $services_tab, $nickname, $notice);
148 }
149
150 # Captures numerous forms of Oper communication through Server Notices (Unreal IRCd)
151 elsif ($notice =~ /^\*\*\* (HelpOp|ChatOps|LocOps|Global|NetAdmin.Chat|AdminChat) \-\- from (.*?)(?: \(HelpOp\):|:)\s(.*)$/)
152 {
153 my $identifier = $1;
154 my $nick = $2;
155 my $text = $3;
156
157 # Gets settings depending on what kind of server notice it was.
158 my $settings = &get_settings_by_key("identifier", $identifier);
159
160 # End of routine if the tab settings were not found.
161 return Xchat::EAT_NONE if not defined($settings);
162
163 # Your current nick on that server.
164 my $mynick = Xchat::get_info("nick");
165
166 # creating the tab and some chan modes in case tab does not yet exist
167 unless(Xchat::find_context($settings->{tab}, $server))
168 {
169 Xchat::command("recv :$mynick!blah\@blah.net JOIN :$settings->{tab}");
170 Xchat::command("recv :$server 324 $mynick $settings->{tab} +RAWR");
171 Xchat::command("recv :$server 329 $mynick $settings->{tab} 0");
172 Xchat::command("timer 1 who $settings->{who}");
173 }
174
175 # Tells xchat where you want the channel message to be printed.
176 Xchat::set_context($settings->{tab}, $server);
177
178 &emit_print_handler($nick, $text);
179 }
180
181 # Nick changes and forced nick changes etc...
182 elsif ($notice =~ /^\*\*\* Notice \-\- (.*?) \((.*?)\) has (?:changed his\/her nickname|been forced to change his\/her nickname) to\s(.*)/)
183 {
184 my $nickname = $1;
185 my $hostaddress = $2;
186 my $nickchange = $3;
187
188 # Used to update the -Clients Userlist if a nick is changed.
189 Xchat::command("recv :$nickname!$hostaddress NICK :$nickchange");
190
191 &on_query_new_tab_print($server, $nicks_tab, $nickname, "is now \cB$nickchange\cO $hostaddress");
192 }
193
194 # catches expiring network bans *** Expiring G:Line hostmask blah time or w/e
195 elsif ($notice =~ s/^\*\*\* (Expiring) (Global Z:Line|Shun|G:Line) //)
196 {
197 my $nickname = $1;
198 my $line = $2;
199 &on_query_new_tab_print($server, $globals_tab, $nickname, "\cB$line\cO $notice");
200 }
201
202 elsif ($notice =~ s/^\*\*\* (OperOverride|Flood) \-\- //)
203 {
204 my $nickname = $1;
205 &on_query_new_tab_print($server, $globals_tab, $nickname, $notice);
206 }
207
208 #catches spamfilter event... [Spamfilter] rest of stuff...
209 elsif ($notice =~ /\[Spamfilter\] (.*?)$/)
210 {
211 my $line = $1;
212 &on_query_new_tab_print($server, $globals_tab, "\cBSPAM\cO", $line);
213 }
214 elsif ($notice =~ s/^\*\*\* (Spamfilter) //)
215 {
216 my $nickname = $1;
217 &on_query_new_tab_print( $server, $globals_tab, $nickname, $notice );
218 }
219 # *** G:Line has been added for hostmask reason blah <-- server bans
220 elsif ($notice =~ s/^\*\*\* (.*?) added for //)
221 {
222 my $bantype = $1;
223 &on_query_new_tab_print($server, $globals_tab, "Added", "\cB$bantype\cO for $notice");
224 }
225 elsif ($notice =~ /^Stats \'.*?\' requested by/)
226 {
227 &on_query_new_tab_print($server, $globals_tab, "Stats", $notice);
228 }
229 # When someone does a /whois on you
230 elsif ($notice =~ /^\*\*\* (.*?) \((.*?)\@(.*?)\) did a \/whois on you\./)
231 {
232 my $nick = $1;
233 my $username = $2;
234 my $ip = $3;
235 my $random = &random_whois_msg();
236 Xchat::command("notice $nick $nick: $random you /whois'd me your address is $ip") if ($username !~ /java/i);
237 }
238 # When someone opers up.
239 elsif ($notice =~ /\] is now .*? \((?:O|N|A|a)\)$/)
240 {
241 return Xchat::EAT_XCHAT;
242 }
243 # TS Control
244 elsif ($notice =~ s/^\*\*\* Notice -- (TS Control) - //)
245 {
246 my $nickname = $1;
247 &on_query_new_tab_print($server, $services_tab, $nickname, $notice);
248 }
249 # When an unknown oper attempts to oper up or something.
250 elsif ($notice =~ /^Failed OPER attempt by (.*?) \(.*?(\@.*?)\) \[unknown oper\]$/)
251 {
252 my $nickname = $1;
253 my $ip = $2;
254 my $mynick = Xchat::get_info("nick");
255 Xchat::command("notice $nickname $nickname: Stop Attempting to OPER UP or you will receive consequences. type /msg $mynick SORRY if this was accidental.");
256 }
257 # Regex explains it all
258 elsif ($notice =~ s/^(Forbidding|Failed) //)
259 {
260 my $nickname = $1;
261 &on_query_new_tab_print($server, $globals_tab, $nickname, $notice);
262 }
263 elsif ($notice =~ s/^\*\*\* Notice \-\- (\(link\)|Possible|Link) //)
264 {
265 my $nickname = $1;
266 &on_query_new_tab_print($server, $services_tab, $nickname, $notice);
267 }
268 # If there are any other Services Server notices or soemthing forgotten
269 elsif ($notice =~ s/^(\w+Serv) //)
270 {
271 my $nickname = $1;
272 &on_query_new_tab_print($server, $services_tab, $nickname, $notice);
273 }
274 elsif ($notice =~ s/^\*\*\* Notice \-\- Recieved (KILL) message for (.*?)$//)
275 {
276 my $kill = $1;
277 my $who = $2;
278 &on_query_new_tab_print($server, $kills_tab, $kill, "For \cB$who\cO $notice");
279 }
280 #elsif ($notice =~ /regexhere/ ) {
281 # ...
282 #}
283 else
284 {
285 return Xchat::EAT_NONE;
286 }
287 return Xchat::EAT_XCHAT;
288}
289
290# Basically made so I didnt have to put that into every single elsif statement
291sub on_query_new_tab_print($)
292{
293 # assigns data directly from serv_notice i.e. &on_query_new_tab_print(DATA);
294 my ($server, $tab, $nick, $text) = @_;
295
296 unless (Xchat::find_context($tab, $server))
297 {
298
299 # Command variable "-nofocus" works only on 2.6.6 and up versions of xchat I believe,
300 # remove if you get a -nofocus error
301 Xchat::command("query -nofocus " . $tab);
302 }
303
304 Xchat::set_context($tab, $server);
305 Xchat::emit_print("Channel Message", $nick, $text);
306}
307
308
309sub on_client_tab($)
310{
311 # assigns data directly from serv_notice i.e. &on_query_new_tab_print(DATA);
312 my ($server, $tab, $nick, $text) = @_;
313 Xchat::set_context($tab, $server);
314 Xchat::emit_print("Channel Message", $nick, $text);
315}
316
317# blocks some annoying servernotices after creation of fake channels
318sub block_raws
319{
320 return Xchat::EAT_XCHAT;
321}
322
323####################################################
324# Uses Xchat Settings to properly print messages. #
325####################################################
326sub emit_print_handler
327{
328 my $nick = shift;
329 my $text = shift;
330 my $mynick = Xchat::get_info("nick");
331
332 if ($text =~ s/^me\s//)
333 {
334 if ($nick eq $mynick)
335 {
336 Xchat::emit_print("Your Action", $nick, $text);
337 }
338 elsif (&is_hilight($text) && ¬_to_hilight($nick) || &always_hilight($nick))
339 {
340 Xchat::emit_print("Channel Action Hilight", $nick, $text);
341 }
342 else
343 {
344 Xchat::emit_print("Channel Action", $nick, $text);
345 }
346 }
347 else
348 {
349 if ($nick eq $mynick)
350 {
351 Xchat::emit_print("Your Message", $nick, $text);
352 }
353 elsif ((&is_hilight($text) && ¬_to_hilight($nick)) || &always_hilight($nick))
354 {
355 Xchat::emit_print("Channel Msg Hilight", $nick, $text);
356 }
357 else
358 {
359 Xchat::emit_print("Channel Message", $nick, $text);
360 }
361 }
362}
363
364
365sub is_hilight($)
366{
367 my $text = shift;
368
369 Xchat::strip_code($text);
370
371 my $list = Xchat::get_prefs("irc_extra_hilight");
372 my @words = split(/,/, $list);
373
374 $words[++$#words] = Xchat::get_info("nick");
375
376 for (my $i = 0; $i <= $#words; $i++)
377 {
378 my $found_match = index($text, $words[$i]);
379 return 1 if ($found_match >= 0);
380 }
381
382 return undef;
383}
384
385sub not_to_hilight($)
386{
387 my $nick = shift;
388
389 Xchat::strip_code($nick);
390
391 my $list = Xchat::get_prefs("irc_no_hilight");
392 my @ignored_nicks = split( /,/, $list);
393
394 $ignored_nicks[++$#ignored_nicks] = Xchat::get_info("nick");
395
396 for (my $i = 0; $i <= $#ignored_nicks; $i++)
397 {
398 return undef if ($ignored_nicks[$i] eq $nick);
399 }
400
401 return 1;
402}
403
404sub always_hilight
405{
406 my $nick = shift;
407
408 Xchat::strip_code($nick);
409
410 my $list = Xchat::get_prefs("irc_nick_hilight");
411 my @hilight_nicks = split( /,/, $list);
412
413 for (my $i = 0; $i <= $#hilight_nicks; $i++)
414 {
415 return 1 if ($hilight_nicks[$i] eq $nick);
416 }
417
418 return undef;
419}
420
421
422# this routine deals with any non command. here we are interested in things typed inside the helper/chatops tab.
423sub non_command_handler($$)
424{
425 # getting the text from the 2nd argument of this routine
426 my $text = shift(@{$_[1]});
427
428 my $channel = Xchat::get_info("channel");
429
430 my $settings = &get_settings_by_key("tab", $channel);
431
432 return Xchat::EAT_NONE if not defined($settings);
433
434 # checking whether we are in the helper/chatops tab
435 if (lc($channel) eq lc($settings->{tab}))
436 {
437
438 # sending helpop command to the server
439 Xchat::command($settings->{command} . " :" . $text);
440
441 # prevents xchat from seeing this event
442 return Xchat::EAT_XCHAT;
443 }
444
445 return Xchat::EAT_NONE;
446}
447
448# An auto userlist updater for -HelpOp
449sub on_helpop_join
450{
451 if (lc("#help") ne lc($_[0][1]))
452 {
453 return Xchat::EAT_NONE;
454 }
455
456 if ((time() - $time) < 20)
457 {
458 $time = time();
459 return Xchat::EAT_NONE;
460 }
461 else
462 {
463 $time = time();
464 Xchat::command("who #help");
465 }
466
467 return Xchat::EAT_NONE;
468}
469
470# Command "notinchan" basically the -IDLE tab
471sub not_in_chan($)
472{
473 return Xchat::EAT_NONE if defined ($_[0][1]);
474
475 my $server = Xchat::get_info('server');
476 my $mynick = Xchat::get_info('nick');
477
478 Xchat::command("recv :$mynick!blah\@blah.net JOIN :-NotInChan") unless Xchat::find_context("-NotInChan",$server);
479 Xchat::command("timer 1 who +i \*");
480
481 return Xchat::EAT_XCHAT;
482}
483
484
485# /Who command hooks for special rooms
486my $hook;
487my $unhook;
488my @userlist;
489my @userlist2;
490my @userlistmax;
491# Used to assure correct tabing.
492my $what_tab;
493
494
495# Handles the who commands for the userlists.
496sub who_command_handler($$)
497{
498 my $settings = &get_settings_by_key("who", $_[1][1]);
499
500 return Xchat::EAT_NONE if not defined($settings);
501
502 my $server = Xchat::get_info("server");
503
504 if ($_[1][1] eq $settings->{who})
505 {
506 $what_tab = $settings->{tab};
507
508 $hook = Xchat::hook_server("352", $settings->{cb});
509 $unhook = Xchat::hook_server("315", \&unhook);
510 }
511
512 return Xchat::EAT_NONE;
513}
514
515############################################################
516# These subroutines handle the data from the /who list #
517############################################################
518sub std_who_handler($)
519{
520 my $nick = $_[0][7];
521
522 if ($#userlist2 > 400)
523 {
524 $userlistmax[++$#userlistmax] = $nick;
525 }
526 elsif ($#userlist > 400)
527 {
528 $userlist2[++$#userlist2] = $nick;
529 }
530 else
531 {
532 $userlist[++$#userlist] = $nick;
533 }
534
535 return Xchat::EAT_XCHAT;
536}
537
538sub helpop_who_handler($)
539{
540 # Just checks channel prefixes of the specified room from the /who Helpop command
541 my $nick = $_[0][7];
542 my $prefix = $_[0][8];
543
544 if ($prefix =~ /\@|\%|\&/)
545 {
546 if ($#userlist2 > 400)
547 {
548 $userlistmax[++$#userlistmax] = $nick;
549 }
550 elsif ($#userlist > 400)
551 {
552 $userlist2[++$#userlist2] = $nick;
553 }
554 else
555 {
556 $userlist[++$#userlist] = $nick;
557 }
558 }
559
560 return Xchat::EAT_XCHAT;
561}
562
563sub idle_who_handler($)
564{
565 # Checks if the user is in a room by the /who list!
566 my $nick = $_[0][7];
567 my $channel = $_[0][3];
568
569 if ($channel !~ /^#/)
570 {
571 if ($#userlist2 > 400)
572 {
573 $userlistmax[++$#userlistmax] = $nick;
574 }
575 elsif ($#userlist > 400)
576 {
577 $userlist2[++$#userlist2] = $nick;
578 }
579 else
580 {
581 $userlist[++$#userlist] = $nick;
582 }
583 }
584
585 return Xchat::EAT_XCHAT;
586}
587
588
589# Unhooks created hooks
590sub unhook
591{
592 my $mynick = Xchat::get_info("nick");
593 my $server = Xchat::get_info("server");
594 # Ends the hook of who list
595
596 Xchat::unhook($hook);
597
598 if (@userlist)
599 {
600 Xchat::command("recv :$server 353 $mynick = $what_tab :".join(' ', @userlist));
601 @userlist = ();
602 }
603 if (@userlist2)
604 {
605 Xchat::command("recv :$server 353 $mynick = $what_tab :".join(' ', @userlist2));
606 @userlist2 = ();
607 }
608 if (@userlistmax)
609 {
610 Xchat::command("recv :$server 353 $mynick = $what_tab :".join(' ', @userlistmax));
611 @userlistmax = ();
612 }
613 #Xchat::print("recv :$server 353 $mynick = $what_tab :".$userlist);
614
615 # Stops hook function of server code 315 aka End of /who list.
616 # Unhooks this subroutine.
617 Xchat::unhook($unhook);
618
619 return Xchat::EAT_XCHAT;
620}
621
622
623
624# Stops printing text event "Part" in clients tab
625sub eat_parts_from_clients($)
626{
627 my $channel = $_[0][2];
628
629 return Xchat::EAT_XCHAT if ($channel eq "-Clients");
630
631 return Xchat::EAT_NONE;
632}
633
634sub eat_quit_on_tab()
635{
636
637 return Xchat::EAT_XCHAT if ("-Clients" eq Xchat::get_info("channel"));
638 # pass other events along
639
640 return Xchat::EAT_NONE;
641}
642
643# Server notice toggle.
644sub unhook_server_notice($$)
645{
646 if ($_[1][1] eq "on")
647 {
648 $server_notice_hook = Xchat::hook_print("Server Notice", \&server_notice_handler);
649 }
650 elsif ($_[1][1] eq "off")
651 {
652 Xchat::unhook($server_notice_hook);
653 }
654
655 return Xchat::EAT_XCHAT;
656}
657
658
659# some random arrays
660sub random_whois_msg()
661{
662 my @msg = ("meow", "eek", "grr", "ohai", "O_O", "blargh", "pshhh", "meh", "whoa", "ONOEZ", "quack");
663
664 return $msg [rand scalar @msg];
665}
666sub random_time()
667{
668 my @time = (1 .. 9);
669
670 return $time[rand scalar @time];
671}
672
673
674# Handles the global hashes (Sergio made xD)
675sub get_settings_by_key($)
676{
677 my ($type, $item) = @_;
678
679 foreach my $key (keys %global_settings)
680 {
681 if (defined($type) && defined($item) && (defined($global_settings{$key}->{$type}) && ($global_settings{$key}->{$type} eq $item)))
682 {
683 return $global_settings{$key};
684 }
685 }
686
687 return undef;
688}
689
690
691# Adds a menu :o
692Xchat::command("MENU -p5 ADD Oper");
693Xchat::command("MENU \-k4,101 -t1 ADD \"Oper\/Filter Enabled\" \"filter on\" \"filter off\"");
694Xchat::command("MENU ADD \"Oper/Userlist\"");
695Xchat::command("MENU ADD \"Oper/Userlist/HelpOp\" \"who #help\"");
696Xchat::command("MENU ADD \"Oper/Userlist/ChatOps\" \"who +m-m oO S\"");
697Xchat::command("MENU ADD \"Oper/Userlist/LocOps\" \"who +m-m o S\"");
698Xchat::command("MENU ADD \"Oper/Userlist/GlobOps\" \"who +m o\"");
699Xchat::command("MENU ADD \"Oper/Userlist/AdChat\" \"who +m-m aA S\"");
700Xchat::command("MENU ADD \"Oper/Userlist/NaChat\" \"who +m-m N S\"");
701Xchat::command("MENU ADD \"Oper/Userlist/Clients\" \"who +n \*\"");
702Xchat::command("MENU ADD \"Oper/Userlist/IDLE\" \"notinchan\"");
703
704
705sub unload
706{
707 # Deletes the Oper Menu
708 Xchat::command("MENU -p5 DEL Oper");
709
710 Xchat::print("\cBOper Script unloaded...");
711}
712
713Xchat::print("\cBOper Thingy Loaded..");