]> git.xonotic.org Git - xonotic/xonotic.git/blobdiff - server/rcon2irc/rcon2irc.pl
fix typo
[xonotic/xonotic.git] / server / rcon2irc / rcon2irc.pl
index 07de35223a808832e0d9395ebf6bb66ef15f4e89..13d9779126a43e97d40d6b69798759fd15d3c164 100755 (executable)
@@ -28,6 +28,7 @@ our $VERSION = '0.4.2 svn $Revision$';
 # MISC STRING UTILITY ROUTINES to convert between DarkPlaces and IRC conventions
 
 # convert mIRC color codes to DP color codes
+our $color_utf8_enable = 1;
 our @color_irc2dp_table = (7, 0, 4, 2, 1, 1, 6, 1, 3, 2, 5, 5, 4, 6, 7, 7);
 our @color_dp2irc_table = (-1, 4, 9, 8, 12, 11, 13, -1, -1, -1); # not accurate, but legible
 our @color_dp2ansi_table = ("m", "1;31m", "1;32m", "1;33m", "1;34m", "1;36m", "1;35m", "m", "1m", "1m"); # not accurate, but legible
@@ -57,7 +58,7 @@ sub color_irc2dp($)
 }
 
 our @text_qfont_table = ( # ripped from DP console.c qfont_table
-    "\0", '#',  '#',  '#',  '#',  '.',  '#',  '#',
+    '',   '#',  '#',  '#',  '#',  '.',  '#',  '#',
     '#',  9,    10,   '#',  ' ',  13,   '.',  '.',
     '[',  ']',  '0',  '1',  '2',  '3',  '4',  '5',
     '6',  '7',  '8',  '9',  '.',  '<',  '=',  '>',
@@ -90,16 +91,28 @@ our @text_qfont_table = ( # ripped from DP console.c qfont_table
     'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
     'x',  'y',  'z',  '{',  '|',  '}',  '~',  '<'
 );
+sub text_qfont_table($)
+{
+       my ($char) = @_;
+       my $o = ord $char;
+       if($color_utf8_enable)
+       {
+               return (($o & 0xFF00) == 0xE000) ? $text_qfont_table[$o & 0xFF] : $char;
+       }
+       else
+       {
+               return $text_qfont_table[$o];
+       }
+}
 sub text_dp2ascii($)
 {
        my ($message) = @_;
-       $message = join '', map { $text_qfont_table[ord $_] } split //, $message;
+       $message = join '', map { text_qfont_table $_ } split //, $message;
 }
 
 sub color_dp_transform(&$)
 {
        my ($block, $message) = @_;
-
        $message =~ s{(?:(\^\^)|\^x([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])|\^([0-9])|(.))(?=([0-9,]?))}{
                defined $1 ? $block->(char => '^', $7) :
                defined $2 ? $block->(rgb => [hex $2, hex $3, hex $4], $7) :
@@ -119,7 +132,7 @@ sub color_dp2none($)
        {
                my ($type, $data, $next) = @_;
                $type eq 'char'
-                       ? $text_qfont_table[ord $data]
+                       ? text_qfont_table $data
                        : "";
        }
        $message;
@@ -196,7 +209,7 @@ sub color_dp2irc($)
                        $data = color_rgb2basic $data;
                }
 
-               $type eq 'char'  ? $text_qfont_table[ord $data] :
+               $type eq 'char'  ? text_qfont_table $data :
                $type eq 'color' ? do {
                        my $oldcolor = $color;
                        $color = $color_dp2irc_table[$data];
@@ -225,7 +238,7 @@ sub color_dp2ansi($)
                        $data = color_rgb2basic $data;
                }
 
-               $type eq 'char'  ? $text_qfont_table[ord $data] :
+               $type eq 'char'  ? text_qfont_table $data :
                $type eq 'color' ? do {
                        my $oldcolor = $color;
                        $color = $color_dp2ansi_table[$data];
@@ -306,6 +319,7 @@ sub new($$)
                PeerAddr => $remote,
                PeerPort => $defaultport
        ) or die "socket $proto/$local/$remote/$defaultport: $!";
+       binmode $sock;
        $sock->blocking(0);
        my $you = {
                # Mortal fool! Release me from this wretched tomb! I must be set free
@@ -465,6 +479,8 @@ sub join_commands($@)
 sub send($$$)
 {
        my ($self, $line, $nothrottle) = @_;
+       utf8::encode $line
+               if $color_utf8_enable;
        if($self->{secure} > 1)
        {
                $self->{connector}->send("\377\377\377\377getchallenge");
@@ -514,7 +530,7 @@ sub recvchallenge($)
                                        if not defined $s;
                                length $s
                                        or last;
-                               if($s =~ /^\377\377\377\377challenge (.*)$/s)
+                               if($s =~ /^\377\377\377\377challenge (.*?)(?:$|\0)/s)
                                {
                                        return $1;
                                }
@@ -544,7 +560,10 @@ sub recv($)
        my @out = ();
        while($self->{recvbuf} =~ s/^(.*?)(?:\r\n?|\n)//)
        {
-               push @out, $1;
+               my $s = $1;
+               utf8::decode $s
+                       if $color_utf8_enable;
+               push @out, $s;
        }
        return @out;
 }
@@ -611,6 +630,8 @@ sub throttle($$$)
 sub send($$$)
 {
        my ($self, $line, $nothrottle) = @_;
+       utf8::encode $line
+               if $color_utf8_enable;
        my $t = time();
        if(defined $self->{capacity})
        {
@@ -652,7 +673,10 @@ sub recv($)
        my @out = ();
        while($self->{recvbuf} =~ s/^(.*?)(?:\r\n?|\n)//)
        {
-               push @out, $1;
+               my $s = $1;
+               utf8::decode $s
+                       if $color_utf8_enable;
+               push @out, $s;
        }
        return @out;
 }
@@ -716,6 +740,7 @@ our %config = (
        dp_password => undef,
        dp_status_delay => 30,
        dp_server_from_wan => "",
+       dp_utf8_enable => $color_utf8_enable,
        irc_local => "",
 
        irc_admin_password => "",
@@ -729,9 +754,9 @@ our %config = (
 
 
 
-# Nexuiz specific parsing of some server messages
+# Xonotic specific parsing of some server messages
 
-sub nex_slotsstring()
+sub xon_slotsstring()
 {
        my $slotsstr = "";
        if(defined $store{slots_max})
@@ -740,7 +765,7 @@ sub nex_slotsstring()
                my $slots_s = ($slots == 1) ? '' : 's';
                $slotsstr = " ($slots free slot$slots_s)";
                my $s = $config{dp_server_from_wan} || $config{dp_server};
-               $slotsstr .= "; join now: \002nexuiz +connect $s"
+               $slotsstr .= "; join now: \002xonotic +connect $s"
                        if $slots >= 1 and not $store{lms_blocked};
        }
        return $slotsstr;
@@ -769,6 +794,7 @@ my @missing = grep { !defined $config{$_} } keys %config;
 die "The following config items are missing: @missing"
        if @missing;
 
+$color_utf8_enable = $config{dp_utf8_enable};
 
 
 # Create a channel for error messages and other internal status messages...
@@ -862,7 +888,7 @@ sub irc_error()
                        return;
                        # this will keep irc_error_active
                }
-               $channels{irc} = new Channel::Line(new Connection::Socket(tcp => "" => $config{irc_server} => 6667));
+               $channels{irc} = new Channel::Line(new Connection::Socket(tcp => $config{irc_local} => $config{irc_server} => 6667));
                delete $store{$_} for grep { /^irc_/ } keys %store;
                $store{irc_nick} = "";
                schedule sub {
@@ -1104,7 +1130,7 @@ sub cond($)
                        }
                        else
                        {
-                               my $slotsstr = nex_slotsstring();
+                               my $slotsstr = xon_slotsstring();
                                out irc => 0, "PRIVMSG $config{irc_channel} :\001ACTION can be joined again$slotsstr!\001";
                        }
                }
@@ -1293,6 +1319,18 @@ sub cond($)
        [ irc => q{:[^ ]* 001 .*} => sub {
                $store{irc_seen_welcome} = 1;
                $store{irc_nick} = $store{irc_nick_requested};
+               
+               # If users for quakenet are listed, parse them into a hash and schedule a sub to query information
+               if ($config{irc_quakenet_authusers} ne '') {
+                       $store{irc_quakenet_users} = { map { $_ => 1 } split / /, $config{irc_quakenet_authusers} };
+       
+                       schedule sub {
+                               my ($timer) = @_;
+                               out irc => 0, "PRIVMSG Q :users " . $config{irc_channel};
+                               schedule $timer => 300;;
+                       } => 1;
+               }
+
                return irc_joinstage(0);
        } ],
 
@@ -1309,12 +1347,20 @@ sub cond($)
                return irc_joinstage(0);
        } ],
        
-       # Catch joins of people in a channel the bot is in and catch our own joins of a channel
+       # Catch joins of people in a channel the bot is in and catch our own joins of a channel,
+       # detect channel join message and note hostname length to get the maximum allowed line length
        [ irc => q{:(([^! ]*)![^ ]*) JOIN (#.+)} => sub {
                my ($hostmask, $nick, $chan) = @_;
+
+               if ($nick eq $store{irc_nick}) {
+                       $store{irc_maxlen} = 510 - length($hostmask);
+                       $store{irc_joined_channel} = 1;
+                       print "* detected maximum line length for channel messages: $store{irc_maxlen}\n";
+               }
+
                return 0 unless ($store{irc_quakenet_users});
                
-               if ($nick eq $config{irc_nick}) {
+               if ($nick eq $store{irc_nick}) {
                        out irc => 0, "PRIVMSG Q :users $chan"; # get auths for all users
                } else {
                        $store{quakenet_hosts}->{$nick} = $hostmask;
@@ -1383,22 +1429,14 @@ sub cond($)
                return 0;
        } ],
 
-       # detect channel join message and note hostname length to get the maximum allowed line length
-       [ irc => q{(:(?i:(??{$store{irc_nick}}))![^ ]* )(?i:JOIN) :(?i:(??{$config{irc_channel}}))} => sub {
-               $store{irc_maxlen} = 510 - length($1);
-               $store{irc_joined_channel} = 1;
-               print "* detected maximum line length for channel messages: $store{irc_maxlen}\n";
-               return 0;
-       } ],
-
-       # chat: Nexuiz server -> IRC channel
+       # chat: Xonotic server -> IRC channel
        [ dp => q{\001(.*?)\^7: (.*)} => sub {
                my ($nick, $message) = map { color_dp2irc $_ } @_;
                out irc => 0, "PRIVMSG $config{irc_channel} :<$nick\017> $message";
                return 0;
        } ],
 
-       # chat: Nexuiz server -> IRC channel, nick set
+       # chat: Xonotic server -> IRC channel, nick set
        [ dp => q{:join:(\d+):(\d+):([^:]*):(.*)} => sub {
                my ($id, $slot, $ip, $nick) = @_;
                $store{"playernickraw_byid_$id"} = $nick;
@@ -1410,7 +1448,7 @@ sub cond($)
                return 0;
        } ],
 
-       # chat: Nexuiz server -> IRC channel, nick change/set
+       # chat: Xonotic server -> IRC channel, nick change/set
        [ dp => q{:name:(\d+):(.*)} => sub {
                my ($id, $nick) = @_;
                $store{"playernickraw_byid_$id"} = $nick;
@@ -1421,7 +1459,7 @@ sub cond($)
                return 0;
        } ],
 
-       # chat: Nexuiz server -> IRC channel, vote call
+       # chat: Xonotic server -> IRC channel, vote call
        [ dp => q{:vote:vcall:(\d+):(.*)} => sub {
                my ($id, $command) = @_;
                $command = color_dp2irc $command;
@@ -1430,7 +1468,7 @@ sub cond($)
                return 0;
        } ],
 
-       # chat: Nexuiz server -> IRC channel, vote stop
+       # chat: Xonotic server -> IRC channel, vote stop
        [ dp => q{:vote:vstop:(\d+)} => sub {
                my ($id) = @_;
                my $oldnick = $id ? $store{"playernick_byid_$id"} : "(console)";
@@ -1438,7 +1476,7 @@ sub cond($)
                return 0;
        } ],
 
-       # chat: Nexuiz server -> IRC channel, master login
+       # chat: Xonotic server -> IRC channel, master login
        [ dp => q{:vote:vlogin:(\d+)} => sub {
                my ($id) = @_;
                my $oldnick = $id ? $store{"playernick_byid_$id"} : "(console)";
@@ -1446,7 +1484,7 @@ sub cond($)
                return 0;
        } ],
 
-       # chat: Nexuiz server -> IRC channel, master do
+       # chat: Xonotic server -> IRC channel, master do
        [ dp => q{:vote:vdo:(\d+):(.*)} => sub {
                my ($id, $command) = @_;
                $command = color_dp2irc $command;
@@ -1455,7 +1493,7 @@ sub cond($)
                return 0;
        } ],
 
-       # chat: Nexuiz server -> IRC channel, result
+       # chat: Xonotic server -> IRC channel, result
        [ dp => q{:vote:v(yes|no|timeout):(\d+):(\d+):(\d+):(\d+):(-?\d+)} => sub {
                my ($result, $yes, $no, $abstain, $not, $min) = @_;
                my $spam = "$yes:$no" . (($min >= 0) ? " ($min needed)" : "") . ", $abstain didn't care, $not didn't vote";
@@ -1463,7 +1501,7 @@ sub cond($)
                return 0;
        } ],
 
-       # chat: IRC channel -> Nexuiz server
+       # chat: IRC channel -> Xonotic server
        [ irc => q{:([^! ]*)![^ ]* (?i:PRIVMSG) (?i:(??{$config{irc_channel}})) :(?i:(??{$store{irc_nick}}))(?: |: ?|, ?)(.*)} => sub {
                my ($nick, $message) = @_;
                $nick = color_dpfix $nick;
@@ -1505,7 +1543,7 @@ sub cond($)
                $store{map} = $map;
                $store{map_starttime} = time();
                if ($config{irc_announce_mapchange} eq 'always' || ($config{irc_announce_mapchange} eq 'notempty' && $store{slots_active} > 0)) {
-                       my $slotsstr = nex_slotsstring();
+                       my $slotsstr = xon_slotsstring();
                        out irc => 0, "PRIVMSG $config{irc_channel} :\00304" . $map . "\017 has begun$slotsstr";
                }
                delete $store{lms_blocked};
@@ -1518,7 +1556,7 @@ sub cond($)
                return 0;
        } ],
 
-       # scores: Nexuiz server -> IRC channel (start)
+       # scores: Xonotic server -> IRC channel (start)
        [ dp => q{:scores:(.*):(\d+)} => sub {
                my ($map, $time) = @_;
                $store{scores} = {};
@@ -1529,7 +1567,7 @@ sub cond($)
                return 0;
        } ],
 
-       # scores: Nexuiz server -> IRC channel, legacy format
+       # scores: Xonotic server -> IRC channel, legacy format
        [ dp => q{:player:(-?\d+):(\d+):(\d+):(\d+):(\d+):(.*)} => sub {
                my ($frags, $deaths, $time, $team, $id, $name) = @_;
                return if not exists $store{scores};
@@ -1538,7 +1576,7 @@ sub cond($)
                return 0;
        } ],
 
-       # scores: Nexuiz server -> IRC channel (CTF), legacy format
+       # scores: Xonotic server -> IRC channel (CTF), legacy format
        [ dp => q{:teamscores:(\d+:-?\d*(?::\d+:-?\d*)*)} => sub {
                my ($teams) = @_;
                return if not exists $store{scores};
@@ -1546,7 +1584,7 @@ sub cond($)
                return 0;
        } ],
 
-       # scores: Nexuiz server -> IRC channel, new format
+       # scores: Xonotic server -> IRC channel, new format
        [ dp => q{:player:see-labels:(-?\d+)[-0-9,]*:(\d+):(\d+):(\d+):(.*)} => sub {
                my ($frags, $time, $team, $id, $name) = @_;
                return if not exists $store{scores};
@@ -1554,7 +1592,7 @@ sub cond($)
                return 0;
        } ],
 
-       # scores: Nexuiz server -> IRC channel (CTF), new format
+       # scores: Xonotic server -> IRC channel (CTF), new format
        [ dp => q{:teamscores:see-labels:(-?\d+)[-0-9,]*:(\d+)} => sub {
                my ($frags, $team) = @_;
                return if not exists $store{scores};
@@ -1562,7 +1600,7 @@ sub cond($)
                return 0;
        } ],
 
-       # scores: Nexuiz server -> IRC channel
+       # scores: Xonotic server -> IRC channel
        [ dp => q{:end} => sub {
                return if not exists $store{scores};
                my $s = $store{scores};
@@ -1688,17 +1726,6 @@ for my $p(split ' ', $config{plugins})
 }
 
 
-# If users for quakenet are listed, parse them into a hash and schedule a sub to query information
-if ($config{irc_quakenet_authusers} ne '') {
-       $store{irc_quakenet_users} = { map { $_ => 1 } split / /, $config{irc_quakenet_authusers} };
-       
-       schedule sub {
-               my ($timer) = @_;
-               out irc => 0, "PRIVMSG Q :users " . $config{irc_channel};
-               schedule $timer => 300;;
-       } => 1;
-}
-
 
 # verify that the server is up by letting it echo back a string that causes
 # re-initialization of the required aliases
@@ -1726,7 +1753,7 @@ schedule sub {
        my ($timer) = @_;
 
        # log on to IRC when needed
-       if(exists $store{dp_hostname} && !exists $store{irc_logged_in})
+       if(exists $store{dp_hostname} && !exists $store{irc_seen_welcome})
        {
                $store{irc_nick_requested} = $config{irc_nick};
                out irc => 1, "NICK $config{irc_nick}", "USER $config{irc_user} localhost localhost :$store{dp_hostname}";