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
35use strict;
36use Socket;
37use Sys::Hostname;
38use IO::Handle;
39
40use Irssi;
41use Irssi::Irc;
42use vars qw($VERSION %IRSSI);
43
44##########################[ USER VARIABLES ]###########################
45
46my $listen_port  = 10001;              # Port to listen to
47my $logfile      = "logi";             # Logfile
48
49my $hlserver     = "123.123.123.123";  # Ip of your half life server
50my $hlport       = "28000";            # Port of your half life server
51my $rcon_pass    = "password";         # Rcon password of your half life server
52
53my $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
71my $serv_iaddr = inet_aton($hlserver)    || die "unknown host: $hlserver\n";
72my $serv_paddr = sockaddr_in($hlport, $serv_iaddr);
73my $challenge = "";
74my $rcon_msg = "";
75my $log_on = 1;
76
77#####################
78
79sub run_bot {
80	my $server = Irssi::active_server();
81	my $msg;
82
83	(my $hispaddr = recv(S, $msg, 1000, 0)) or print "$!\n";
84	my ($port, $hisiaddr) = sockaddr_in($hispaddr);
85	my $host = inet_ntoa($hisiaddr);
86
87	$msg =~ s/\n.$//s;
88	$msg =~ s/\n..$//s;
89
90	print LOG "$host : $msg\n";
91
92	# Received logline
93	if ($msg =~ s/^����log L \d\d\/\d\d\/\d{4} - \d\d:\d\d:\d\d: //) {
94		# We don't want to see these
95		if ($log_on eq 0 ||
96			$msg =~ /^Server cvar/ ||
97			$msg =~ /^\[META\]/ ||
98			$msg =~ /^Log file/ ||
99			$msg =~ /^\[ADMIN\]/)
100			{ return; }
101
102		# FORMAT THE LINE
103		# Don't show the rcon password.
104		$msg =~ s/^(Rcon: "rcon \d* )[^ ]*( .*)/$1*****$2/;
105
106		# Print the logline
107		if ($msg =~ /^"/) {
108			$server->command("/action $channel $msg");
109		} else {
110			$server->send_raw("PRIVMSG $channel :*log* $msg");
111		}
112	}
113
114	# Received challenge rcon reply..
115	elsif ($msg =~ /^����challenge rcon (\d+)$/ && $rcon_msg) {
116		$challenge = $1;
117		my $data = "����rcon $challenge $rcon_pass $rcon_msg";
118		defined(send(S, $data, 0, $serv_paddr)) or
119			$server->command("/notice $channel Error sending rcon: $!");
120	}
121
122	# Received rcon reply
123	elsif ($msg =~ s/����l//) {
124		# Some rcon replies have this annoying log entry in the beginning.
125		$msg =~ s/L \d\d\/\d\d\/\d{4} - \d\d:\d\d:\d\d: //g;
126
127		# FORMAT THE LINE
128
129		# Multiline rcon responses
130		if ($msg =~ /\n/s) {
131			my @rows = split /\n/, $msg;
132			foreach my $row (@rows) {
133				# We don't want to see these
134				if ($row =~ /^[\t \n]*$/ ||
135					$row =~ /^[ADMIN] Load/ ||
136					$row =~ /^[ADMIN] WARNING/ ||
137					$row =~ /^[ADMIN] Plugins loaded/)
138					{ next; }
139
140				$server->command("/notice $channel $row");
141			}
142
143		# Single line rcon responses
144		} else {
145			$server->command("/notice $channel $msg");
146		}
147	}
148
149}
150
151############################
152
153sub msg_command {
154	my ($server, $data, $nick, $mask, $target) = @_;
155
156	# Is this the right channel?
157	unless ($target =~ /$channel/i) { return; }
158
159	# Does the user have ops?
160	my $CHAN = $server->channel_find($channel);
161	my $NICK = $CHAN->nick_find($nick);
162	if (! $NICK->{op}) { return; }
163
164	# Rcon command.
165	if ($data =~ /^\.rcon (.+)/) {
166		$rcon_msg = $1;
167
168        defined(send(S, "����challenge rcon", 0, $serv_paddr)) or
169			$server->command("/notice $channel Error asking challenge: $!");
170	}
171
172	# log on
173	elsif ($data =~ /^\.log on$/) {
174		$log_on = 1;
175		$server->command("/notice $channel Logging now ON");
176	}
177
178	# log off
179	elsif ($data =~ /^\.log off$/) {
180		$log_on = 0;
181		$server->command("/notice $channel Logging now OFF");
182	}
183
184	# help
185	elsif ($data =~ /^\.help$/) {
186		$server->command("/notice $channel Commands: .rcon <rcon command>, " .
187			".log <on/off>, .status");
188	}
189
190	# status
191	elsif ($data =~ /^\.status$/) {
192		my $log_status = "";
193		if ($log_on eq 1) { $log_status = "on"; }
194		else { $log_status = "off"; }
195		$server->command("/notice $channel Log: $log_status");
196	}
197
198}
199
200#########[ MAIN ]###########
201
202# Open the logfile.
203open LOG, ">>", $logfile or die "Cannot open logfile!\n";
204LOG->autoflush(1);
205
206# Start listening the socket for udp messages.
207my $iaddr = gethostbyname(hostname());
208my $proto = getprotobyname('udp');
209my $paddr = sockaddr_in($listen_port, $iaddr);
210socket(S, PF_INET, SOCK_DGRAM, $proto)   || die "socket: $!\n";
211bind(S, $paddr)                          || die "bind: $!\n";
212
213# Set input and signals etc. irssi related stuff.
214Irssi::input_add(fileno(S), INPUT_READ, "run_bot", "");
215Irssi::signal_add_last('message public', 'msg_command');
216
217
218