html/hlbot.pl
1 ###########################################################################
2 #
3 # CopyLeft Veli Mankinen 2002
4 # HL-log/rcon bot irssi script.
5 #
6 #####################
7 #
8 # USAGE:
9 #
10 # 1. copy the script to ~/.irssi/scripts/
11 # 2. Edit the variables below.
12 # 3. load the script: /script load hlbot
13 # 4. Join to the channel you want this script to work on.
14 # 5. Make sure all the users have ops in the channel (security reasons)
15 # 6. say in channel: .rcon logadress <ip> <port>
16 # Where ip is the ip of the machine where this script is running and
17 # the port is the $listen_port you have set below
18 # 7. say in channel: .rcon log on
19 #
20 # The script should now start flooding the channel about things hapening in
21 # the channel. Ofcourse you can and I think you should add those
22 # log -commands to your hl server.cfg.
23 #
24 # You can turn the flooding of by saying: ".log off" and turn it back on
25 # with: ".log off". ".status" tells you whether the log is on or off.
26 # Please note that the logfile is allways on. If you don't want to gather
27 # the log in a file then you should put "/dev/null" to the $logfile below.
28 #
29 #
30 # NOTE: There probably are few stupid things in this script and that is
31 # just because I don't have a clue about making irssi script.
32 #
33 ##
34
35
36 use Socket;
37 use Sys::Hostname;
38 use IO::Handle;
39
40 use Irssi;
41 use Irssi::Irc;
42 use vars qw($VERSION %IRSSI);
43
44 ##########################[ USER VARIABLES ]###########################
45
46 my $listen_port = 10001; # Port to listen to
47 my $logfile = "logi"; # Logfile
48
49 my $hlserver = "123.123.123.123"; # Ip of your half life server
50 my $hlport = "28000"; # Port of your half life server
51 my $rcon_pass = "password"; # Rcon password of your half life server
52
53 my $channel = "#mychan"; # Channel where you want this to work
54
55 #######################################################################
56 ##############[ YOU DON'T NEED TO TOUCH BELOW THIS LINE ]##############
57 #######################################################################
58
59 $VERSION = "1.0";
60 %IRSSI = (
61 authors => "Veli Mankinen",
62 contact => "veli\@piipiip.net",
63 name => "HL-log/rcon -bot",
64 description => "Floods the channel about things that are hapening in your hl -server. Also enables you to send rcon commands to the server from channel.",
65 license => "GPLv2",
66 url => "http://piipiip.net/",
67 );
68
69 #####################
70
71 my $serv_iaddr = inet_aton($hlserver) || die "unknown host: $hlserver\n";
72 my $serv_paddr = sockaddr_in($hlport, $serv_iaddr);
73 my $challenge = "";
74 my $rcon_msg = "";
75 my $log_on = 1;
76
77 #####################
78
79 sub run_bot {
80 my $server = Irssi::active_server();
81
82 ($hispaddr = recv(S, $msg, 1000, 0)) or print "$!\n";
83 ($port, $hisiaddr) = sockaddr_in($hispaddr);
84 $host = inet_ntoa($hisiaddr);
85
86 $msg =~ s/\n.$//s;
87 $msg =~ s/\n..$//s;
88
89 print LOG "$host : $msg\n";
90
91 # Received logline
92 if ($msg =~ s/^ÿÿÿÿlog L \d\d\/\d\d\/\d{4} - \d\d:\d\d:\d\d: //) {
93 # We don't want to see these
94 if ($log_on eq 0 ||
95 $msg =~ /^Server cvar/ ||
96 $msg =~ /^\[META\]/ ||
97 $msg =~ /^Log file/ ||
98 $msg =~ /^\[ADMIN\]/)
99 { return; }
100
101 # FORMAT THE LINE
102 # Don't show the rcon password.
103 $msg =~ s/^(Rcon: "rcon \d* )[^ ]*( .*)/$1*****$2/;
104
105 # Print the logline
106 if ($msg =~ /^"/) {
107 $server->command("/action $channel $msg");
108 } else {
109 $server->send_raw("PRIVMSG $channel :*log* $msg");
110 }
111 }
112
113 # Received challenge rcon reply..
114 elsif ($msg =~ /^ÿÿÿÿchallenge rcon (\d+)$/ && $rcon_msg) {
115 $challenge = $1;
116 $data = "ÿÿÿÿrcon $challenge $rcon_pass $rcon_msg";
117 defined(send(S, $data, 0, $serv_paddr)) or
118 $server->command("/notice $channel Error sending rcon: $!");
119 }
120
121 # Received rcon reply
122 elsif ($msg =~ s/ÿÿÿÿl//) {
123 # Some rcon replies have this annoying log entry in the beginning.
124 $msg =~ s/L \d\d\/\d\d\/\d{4} - \d\d:\d\d:\d\d: //g;
125
126 # FORMAT THE LINE
127
128 # Multiline rcon responses
129 if ($msg =~ /\n/s) {
130 @rows = split /\n/, $msg;
131 foreach $row (@rows) {
132 # We don't want to see these
133 if ($row =~ /^[\t \n]*$/ ||
134 $row =~ /^[ADMIN] Load/ ||
135 $row =~ /^[ADMIN] WARNING/ ||
136 $row =~ /^[ADMIN] Plugins loaded/)
137 { next; }
138
139 $server->command("/notice $channel $row");
140 }
141
142 # Single line rcon responses
143 } else {
144 $server->command("/notice $channel $msg");
145 }
146 }
147
148 }
149
150 ############################
151
152 sub msg_command {
153 my ($server, $data, $nick, $mask, $target) = @_;
154
155 # Is this the right channel?
156 unless ($target =~ /$channel/i) { return; }
157
158 # Does the user have ops?
159 my $CHAN = $server->channel_find($channel);
160 my $NICK = $CHAN->nick_find($nick);
161 if (! $NICK->{op}) { return; }
162
163 # Rcon command.
164 if ($data =~ /^\.rcon (.+)/) {
165 $rcon_msg = $1;
166
167 defined(send(S, "ÿÿÿÿchallenge rcon", 0, $serv_paddr)) or
168 $server->command("/notice $channel Error asking challenge: $!");
169 }
170
171 # log on
172 elsif ($data =~ /^\.log on$/) {
173 $log_on = 1;
174 $server->command("/notice $channel Logging now ON");
175 }
176
177 # log off
178 elsif ($data =~ /^\.log off$/) {
179 $log_on = 0;
180 $server->command("/notice $channel Logging now OFF");
181 }
182
183 # help
184 elsif ($data =~ /^\.help$/) {
185 $server->command("/notice $channel Commands: .rcon <rcon command>, " .
186 ".log <on/off>, .status");
187 }
188
189 # status
190 elsif ($data =~ /^\.status$/) {
191 my $log_status = "";
192 if ($log_on eq 1) { $log_status = "on"; }
193 else { $log_status = "off"; }
194 $server->command("/notice $channel Log: $log_status");
195 }
196
197 }
198
199 #########[ MAIN ]###########
200
201 # Open the logfile.
202 open LOG, ">>$logfile" or die "Cannot open logfile!\n";
203 LOG->autoflush(1);
204
205 # Start listening the socket for udp messages.
206 my $iaddr = gethostbyname(hostname());
207 my $proto = getprotobyname('udp');
208 my $paddr = sockaddr_in($listen_port, $iaddr);
209 socket(S, PF_INET, SOCK_DGRAM, $proto) || die "socket: $!\n";
210 bind(S, $paddr) || die "bind: $!\n";
211 $| = 1;
212
213 # Set input and signals etc. irssi related stuff.
214 Irssi::input_add(fileno(S), INPUT_READ, "run_bot", "");
215 Irssi::signal_add_last('message public', 'msg_command');
216
217