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