home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.madoka.org
/
2014.12.ftp.madoka.org.tar
/
ftp.madoka.org
/
pub
/
madoka
/
4.2
/
madoka4.2.6.tar.gz
/
madoka4.2.6.tar
/
madoka4.2
/
madoka.pl
next >
Wrap
Perl Script
|
2002-02-02
|
28KB
|
1,006 lines
#!/bin/perl
#
# madoka-chan ver 4.2
#
# Copyright(c)1998- cookie (cookie@madoka.org)
# The madoka project
# This is free software.
require 5.003;
&init;
exit;
sub mainloop {
local($cl, $cl_no);
my($nf, $rout, $errno, $reason);
for (;;) {
$nf = select($rout=$rin, undef, undef, $interval);
if ($csec != $sec) {
foreach (split(/$;/, $per_sec)) {
next unless $_;
&$_ if defined(&$_);
}
$csec = $sec;
}
if ($nf < 0) {
if ($! == 4) {
$nf = 0;
} else {
$errno = sprintf("%d", $!);
&down("[ERROR] $errno ($!) in select.\n");
}
}
¤t_time;
if ($cmin != $min) {
if ($chour != $hour) {
if ($cday != $mday) {
foreach (split(/$;/, $per_day)) {
next unless $_;
&$_ if defined(&$_);
}
$cday = $mday;
}
foreach (split(/$;/, $per_hour)) {
next unless $_;
&$_ if defined(&$_);
}
$chour = $hour;
}
foreach (split(/$;/, $per_min)) {
next unless $_;
&$_ if defined(&$_);
}
$cmin = $min;
}
if (vec($sv_state, 0, 1)) {
if (time - $sv_tm > $sv_tmout) {
$sv_tm = time;
&close_server($sv_no, 'dead conection');
}
} else {
if (time - $sv_tm_cn > $sv_tmout_cn) {
$sv_tm_cn = $sv_tm = time;
&connect_server;
}
}
next unless $nf;
&init_client(vec($rout, $ln_no4, 1), vec($rout, $ln_no6, 1))
if vec($rout, $ln_no4, 1) || vec($rout, $ln_no6, 1);
for ($cl_no = 0; $cl_no <= $cl_max; $cl_no++) {
next unless (vec($rout, $cl_no, 1) && vec($cl_cn, $cl_no, 1));
$cl = $cl[$cl_no];
unless (sysread($cl, $mes, 4096)) {
$reason = $! ? "$!" : 'closed';
&close_client($cl_no, $reason);
} else {
$cl_buf[$cl_no] .= $mes;
while ((@cl_bufl = split(/\r*\n/, $cl_buf[$cl_no], 2)) == 2) {
$cl_buf[$cl_no] = $cl_bufl[1];
&client($cl_no, $cl_bufl[0]);
}
$cl_buf[$cl_no] = $cl_bufl[0];
}
}
if (vec($rout, $sv_no, 1)) {
unless (sysread(SERVER, $mes, 4096)) {
$reason = $! ? "$!" : 'closed by server';
&send('ccn', "NOTICE $us_nick :" .
&mio('MADOKA_CLOSE', "[CLOSE] $sv[0] ($reason)") . "\n");
&close_server($sv_no, $reason);
} else {
$sv_buf .= $mes;
$sv_tm = time;
while ((@sv_bufl = split(/\r*\n/, $sv_buf, 2)) == 2) {
$sv_buf = $sv_bufl[1] || '';
&server($sv_no, $sv_bufl[0]);
}
$sv_buf = $sv_bufl[0];
}
}
}
}
sub init {
use Config;
use Socket;
eval 'use Socket6';
unshift(@INC, ($0 =~ /^(.*)\/[^\/]+$/ ? "$1/plugin" : './plugin'));
require "version.mpi";
$MDK = $0;
@ARG = @ARGV;
$AF_INET4 = &AF_INET || 2;
$PF_INET4 = &PF_INET || $AF_INET4;
if ($INC{'Socket6.pm'}) {
$AF_INET6 = &AF_INET6 || 24;
$PF_INET6 = &PF_INET6 || $AF_INET6;
} else {
$PF_INET6 = $AF_INET6 = 24;
}
$SOCK_STREAM = &SOCK_STREAM || 1;
$SOL_SOCKET = &SOL_SOCKET;
$SO_REUSEADDR = &SO_REUSEADDR;
$SO_KEEPALIVE = &SO_KEEPALIVE;
$INADDR_ANY4 = &INADDR_ANY || inet_aton('0.0.0.0');
$INADDR_ANY6 = pack('C16', 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0);
$PROT = getprotobyname('tcp') || 6;
$ENV{'LANG'} = 'C';
$ENV{'LC_TIME'} = 'C';
&init_madoka;
unless (vec($us_state, 3, 1)) {
exit if eval { fork };
vec($us_state, 3, 1) = 1 if $@;
}
&read_rc;
open(STDIN, "/dev/null");
&mes("[!] Start: $mdk_label $mdk_version with perl $perl_version\n");
$0 = "$mdk_label($us_nick/$mdk_version)";
&mainloop;
}
sub init_madoka {
if ($^V) {
$perl_version = sprintf("%vd", $^V);
} else {
$perl_version = sprintf("%1.5f", $]);
}
srand(time+$$);
$interval = 1;
$sv_tmout_cn = 90;
$sv_tmout = 900;
$sv_tm = time;
$sv_no = 0;
$cl_max = 256;
$homedir = $ENV{'HOME'};
$rin = '';
$chl_header = '\#\&\+\!\%';
while ($_ = shift(@ARGV)) {
if ($_ eq '-rc') {
$mdk_rc = shift(@ARGV);
$mdk_rc =~ s/^~\//$homedir\//;
&down("[ERROR] Cannot find: $mdk_rc\n") unless -f $mdk_rc;
} elsif ($_ eq '-modes') {
$mdk_modes = shift(@ARGV);
$mdk_modes =~ s/^~\//$homedir\//;
&down("[ERROR] Cannot find: $mdk_modes\n") unless -f $mdk_modes;
} elsif ($_ eq '-nofork') {
vec($us_state, 3, 1) = 1;
}
}
}
sub read_rc {
$mdk_rc = &search_file('madoka.rc') unless $mdk_rc;
return unless &_redo($mdk_rc, 1);
&list_init($per_min) unless $per_min;
&list_add($per_min, 'read_rc');
my $file;
if (open(RC, $mdk_rc)) {
while (<RC>) {
s/\n$//;
next if /^\s*$/ || /^\#/;
if (/^\[([^\]]+)\]$/) {
$rc_section = $1;
next;
} elsif (/^[^=]+=.*/) {
$rc_line = $_;
}
$file = &search_file("rc/$rc_section.mpi");
do $file || print STDERR "[!] $file: [$rc_section] $rc_line\n";
}
close(RC);
} else {
&down("[ERROR] cannot open rc: $mdk_rc\n");
}
$file = &search_file("rc/default.mpi");
do $file;
}
sub init_client {
my @ln = @_;
$cl_seq++;
my $cl = 'C' . $cl_seq;
if ($ln[1] == 1) {
&mes("[init_client] accept: IPv6", 'D');
$ac = accept($cl, LISTEN6);
} elsif ($ln[0] == 1) {
&mes("[init_client] accept: IPv4", 'D');
$ac = accept($cl, LISTEN4);
} else {
&mes("[init_client] accept: strange connection", 'D');
return;
}
select($cl); $| = 1; select(L0);
my $cl_no = fileno($cl);
$cl_max = $cl_no if $cl_no > $cl_max;
$cl[$cl_no] = $cl;
$cl_seq[$cl_no] = $cl_seq;
undef $cl_pass[$cl_no];
vec($rin, $cl_no, 1) = 1;
vec($cl_cn, $cl_no, 1) = 1;
vec($cl_ok, $cl_no, 1) = 0;
foreach (split(/$;/, $chl)) {
next unless $_;
vec($cl_chan{$_}, $cl_no, 1) = 0;
}
my($u, @i, $addr, $ac, $aci);
$ac = getpeername($cl);
&mes("[init_client] aclen: " . length($ac), 'D');
if (length($ac) == 28 || length($ac) == 24) {
($port[$cl_no], $addr) = sockaddr_in6($ac);
$cl_ip[$cl_no] = unpack('N', $addr);
$host[$cl_no] = join(':', unpack('H4 H4 H4 H4 H4 H4 H4 H4', $addr));
$aci = getsockname($cl);
($u, $addr) = sockaddr_in6($aci);
$cl_ifip[$cl_no] = join(':', unpack('H4 H4 H4 H4 H4 H4 H4 H4', $addr));
&mes("[init_client] ifip6: $cl_ifip[$cl_no]\n", 'D');
} else {
($port[$cl_no], $addr) = sockaddr_in($ac);
$cl_ip[$cl_no] = unpack('N', $addr);
$host[$cl_no] = join('.', unpack('C4', $addr));
$aci = getsockname($cl);
($u, $addr) = sockaddr_in($aci);
$cl_ifip[$cl_no] = join('.', unpack('C4', $addr));
&mes("[init_client] ifip: $cl_ifip[$cl_no]\n", 'D');
}
if ($#cl_hosts >= 0 && !&check_host($cl_no, @cl_hosts)) {
&close_client($cl_no, "Denied: $host[$cl_no]($port[$cl_no])");
&plugin('event', 'refuse_client', $host[$cl_no], '');
return;
}
&mes("[!] Connect: $host[$cl_no]($port[$cl_no])/$cl_seq[$cl_no]\n");
&plugin('event', 'connect_client', $host[$cl_no], '');
}
sub connect_server {
local $sv_port = $sv_port[0];
my($that, $l, @l);
if ($sv_port =~ /,/) {
@l = split(/,/, $sv_port[0]);
$sv_port = $l[int(rand($#l+1))];
}
&send('ccn', "NOTICE $us_nick :" .
&mio('MADOKA_CONNECTTRY', "[!] try: connect to $sv[0]($sv_port)") .
"\n");
if ($sv[0] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
$AF_INET = $AF_INET4;
$PF_INET = $PF_INET4;
$INADDR_ANY = $INADDR_ANY4;
vec($sv_state, 3, 1) = 0;
$that = &getaddrinfo6($sv[0], $sv_port);
} elsif ($sv[0] =~ /^[\da-f:]+$/i) {
if ($sv[0] =~ /::.*::/) {
&down("[ERROR] wrong server address in IPv6 format: $sv[0]\n");
} elsif ($sv[0] =~ /::/) {
my $l = $sv[0];
$n = 7 - ($l =~ s/://g);
$l = ':0:';
for ($i = 0; $i < $n; $i++) {
$l .= '0:';
}
$sv[0] =~ s/::/$l/;
}
if ($sv[0] =~ /^([\da-f]*):([\da-f]*):([\da-f]*):([\da-f]*):([\da-f]*):([\da-f]*):([\da-f]*):([\da-f]*)$/i) {
$AF_INET = $AF_INET6;
$PF_INET = $PF_INET6;
$INADDR_ANY = $INADDR_ANY6;
vec($sv_state, 3, 1) = 1;
$that = &getaddrinfo6($sv[0], $sv_port);
} else {
&down("[ERROR] wrong server address in IPv6 format: $sv[0]\n");
}
} else {
$that = &getaddrinfo6($sv[0], $sv_port);
if (length($that) == 28) {
$AF_INET = $AF_INET6;
$PF_INET = $PF_INET6;
vec($sv_state, 3, 1) = 1;
$INADDR_ANY = $INADDR_ANY6;
} else {
$AF_INET = $AF_INET4;
$PF_INET = $PF_INET4;
vec($sv_state, 3, 1) = 0;
$INADDR_ANY = $INADDR_ANY4;
}
}
unless (socket(SERVER, $PF_INET, $SOCK_STREAM, $PROT)) {
&mes("[ERROR] sv/socket: $!\n");
return 0;
}
$sv_no = fileno(SERVER);
select(SERVER); $| = 1; select(L0);
if ($ENV{'OSTYPE'} !~ m/linux/i) {
if (vec($sv_state, 3, 1)) {
$l = pack_sockaddr_in6(0, $INADDR_ANY6);
} else {
$l = pack_sockaddr_in(0, $INADDR_ANY4);
}
unless (bind(SERVER, $l)) {
&mes("[ERROR] sv/bind: $!\n");
return 0;
}
}
$sv_tm_cn = time;
unless (connect(SERVER, $that)) {
&send('ccn', "NOTICE $us_nick :" .
&mio('MADOKA_CONNECTERR', "[!] cannot connect, try again after.") .
"\n");
&send('ccn', "NOTICE $us_nick :" .
&mio('MADOKA_CONNECTERR2',
"[!] if need, type: /server <host> [<port>]") . "\n");
&mes("[!] cannot connect: $sv[0]($sv_port)\n");
&plugin('event', 'refuse_server', $sv[0], $sv_port);
vec($rin, $sv_no, 1) = 0;
$sv_buf = $sv_state = '';
$nickuse = 0;
$nick_try = $us_nick;
push(@sv, shift(@sv));
push(@sv_port, shift(@sv_port));
push(@sv_pass, shift(@sv_pass));
return 0;
}
&mes("[!] server: $sv[0]($sv_port)\n");
&plugin('event', 'connect_server', $sv[0], $sv_port);
vec($rin, $sv_no, 1) = 1;
vec($sv_state, 0, 1) = 1;
®ist_server;
}
sub regist_server {
$nickuse = 0;
@ctcp_queue = ();
$nick_try = $us_nick unless $nick_try;
&send('sv', "PASS $sv_pass[0]\n") if $sv_pass[0];
&send('sv', "USER $us_id * * :$us_name\n");
&send('sv', "NICK $nick_try \n");
&send('sv', "AWAY :$mes_away\n") if $mes_away;
$us_mes_away = $mes_away;
}
sub join_server {
my($joinchannels, $joinchannelskey, $autokeys);
foreach (split(/$;/, $chl_autojoin)) {
next unless $_;
if (&check_chan($_)) {
if ($at_key{$_}) {
$joinchannelskey .= ",$_";
$autokeys .= ",$at_key{$_}";
} else {
$joinchannels .= ",$_";
}
} else {
&send('cch', "NOTICE $us_nick :" .
&mio('MADOKA_JOINERR', "[ERROR] channel name($_)") . "\n");
&mes("[ERROR] channel name($_)\n", 'L');
}
}
$joinchannels =~ s/^,//;
$joinchannelskey =~ s/^,//;
$autokeys =~ s/^,//;
&send('sv', "JOIN $joinchannels \n") if $joinchannels;
&send('sv', "JOIN $joinchannelskey $autokeys \n") if $joinchannelskey;
}
sub close_server {
my($sv_no, $reason) = @_;
close(SERVER);
&mes("[!] close server: $sv[0]($reason)/$sv_no\n");
&plugin('event', 'close_server', $sv[0], $reason);
vec($rin, $sv_no, 1) = 0;
foreach (split(/$;/, $chl)) {
next unless $_;
&send('ccn', ":$us_nick!$machine{$us_nick} PART :$_\n");
}
push(@sv, shift(@sv));
push(@sv_port, shift(@sv_port));
push(@sv_pass, shift(@sv_pass));
&list_init($chl);
vec($rin, $sv_no, 1) = 0;
$sv_buf = '';
$sv_state = '';
$nickuse = 0;
$nick_try = $us_nick;
}
sub close_client {
my($cl_no, $reason) = @_;
&mes("[!] close: $cl_seq[$cl_no] ($reason)\n");
&plugin('event', 'close_client', $host[$cl_no], $reason);
close($cl[$cl_no]);
vec($rin, $cl_no, 1) = 0;
vec($cl_cn, $cl_no, 1) = 0;
vec($cl_ok, $cl_no, 1) = 0;
undef $cl_nick[$cl_no];
undef $cl_user[$cl_no];
undef $cl_code[$cl_no];
my $l = $cl_max;
for ($i = 0, $no_client = 1; $i <= $l; $i++) {
next unless vec($cl_cn, $i, 1);
$cl_max = $i;
$no_client = 0;
}
if ($no_client == 1) {
if ($us_mes_away ne $mes_away) {
&mes("[!] Autoaway: $mes_away\n");
&send('sv', "AWAY :$mes_away\n");
$us_mes_away = $mes_away;
}
vec($at_state, 6, 1) = 1 if vec($dcc_state, 3, 1) && !vec($at_state, 6, 1);
foreach (split(/$;/, $chl_cljoin)) {
next unless $_;
next unless &list_exist($chl, $_);
if ($mes_part) {
&send('sv', "PART $_ :$mes_part\n");
} else {
&send('sv', "PART $_ \n");
}
&mes("[close_client] client PART: $_", 'D');
}
}
}
sub server {
my($sv_no, $line) = @_;
($from, $where, $command, $pr) =
($line =~ /^(:[^! ]*)?(![^ ]*)? *([^ ]+) *:?(.*)$/);
$from =~ s/^:// if $from;
$where =~ s/^!// if $where;
$machine{$from} = $where if $where;
my $com = $command;
$com =~ tr/A-Z/a-z/;
my $sv_cmd = "sv_$com";
&mes("[server] $line /\n", 'D');
if (defined(&$sv_cmd)) {
&$sv_cmd($from, $pr);
} else {
&send('ccn', "$line\n");
}
}
sub client {
my($cl_no, $line) = @_;
my($u, $command, $pr) = ($line =~ /^(:[^ ]*)? *([^ ]+) *:?(.*)$/);
return unless $command;
my $com = $command;
$com =~ tr/A-Z/a-z/;
if ($line =~ /^PASS /i) {
&mes("[client] PASS ******** / seq = $cl_seq[$cl_no]\n", 'D');
} else {
&mes("[client] $line / seq = $cl_seq[$cl_no]\n", 'D');
}
unless (vec($cl_ok, $cl_no, 1)) {
&check_pass($cl_no) if &no_pass($cl_no, $line);
return;
}
$ctcp_cmd_p = '';
$cl_code[$cl_no] = $kanji_lock_code || &kanji_code($pr)
if &list_exist($plugin_list, 'kanji');
my $cl_cmd = "cl_$com";
&mes("[client] cl_cmd = $cl_cmd\n", 'D');
if (defined(&$cl_cmd)) {
&$cl_cmd($pr, $cl_no);
} else {
&send('sv', "$line\n");
}
}
sub no_pass {
my($cl_no, $line) = @_;
my($where, $com, $arg) = ($line =~ /^(:[^ ]*)? *([^ ]+) *:?(.*)$/);
if ($line =~ /^pass/i) {
&mes("[no_pass] $& ********\n", 'D');
} else {
&mes("[no_pass] $line\n", 'D');
}
if ($com =~ /^pass$/i) {
$cl_pass[$cl_no] = $arg;
return 0;
} elsif ($com =~ /^user$/i) {
$cl_user[$cl_no] = $arg;
return 1 if $cl_nick[$cl_no];
return 0;
} elsif ($com =~ /^nick$/i) {
($cl_nick[$cl_no]) = ($arg =~ /^([^\s]+)\s*/);
return 1 if $cl_user[$cl_no];
return 0;
} elsif ($com =~ /^quit$/i) {
&close_client($cl_no, 'I Quit');
return 0;
}
&send('cl', ":$sv[0] 451 * :" .
&mio('MADOKA_REGIST', 'You have not registered.') . "\n", $cl_no);
return 0;
}
sub check_pass {
local $cl_no = $_[0];
if ($cl_pass[$cl_no] ne $us_pass &&
$us_pass ne crypt($cl_pass[$cl_no], substr($us_pass, 0, 2))) {
&send('cl', ":$sv[0] 464 $cl_nick[$cl_no] :" .
&mio('MADOKA_PASSWDERR', 'Password Incorrect.') . "\n");
&send('cl', 'ERROR :' .
&mio('MADOKA_PASSWDCLOSE',
"Closing Link: $cl_nick[$cl_no] (Bad Password)") . "\n");
&close_client($cl_no, 'wrong password');
return;
}
vec($cl_ok, $cl_no, 1) = 1;
&mes("[!] password/$cl_seq[$cl_no]\n");
&plugin('event', 'check_pass', $host[$cl_no], '');
foreach (split(/$;/, $chl_cljoin)) {
next unless $_;
next if &list_exist($chl, $_);
if ($at_key{$_}) {
&send('sv', "JOIN $_ $at_key{$_} \n");
} else {
&send('sv', "JOIN $_ \n");
}
&mes("[check_pass] client JOIN: $_", 'D');
}
my $cl_nick = $cl_nick[$cl_no];
&send('cl', ":$sv[0] 001 $cl_nick :" .
"Welcome to the Internet Relay Network $cl_nick!$machine{$us_nick}\n");
&send('cl', ":$sv[0] 002 $cl_nick :$sv_mes[2]\n") if $sv_mes[2];
&send('cl', ":$sv[0] 003 $cl_nick :$sv_mes[3]\n") if $sv_mes[3];
&send('cl', ":$sv[0] 004 $cl_nick $sv_mes[4]\n") if $sv_mes[4];
&send('cl', ":$sv[0] 375 $cl_nick :- $sv[0] Message of the Day -\n");
&send('cl', ":$sv[0] 376 $cl_nick :End of /MOTD command.\n");
if ($cl_nick ne $us_nick) {
if (defined($machine{$us_nick})) {
&send('cl', ":$cl_nick[$cl_no]!$machine{$us_nick} NICK :$us_nick\n");
} else {
&send('cl', ":$cl_nick[$cl_no] NICK :$us_nick\n");
}
}
if (vec($sv_state, 0, 1)) {
&taillog;
my($l, $ll);
foreach (split(/$;/, $chl)) {
next unless $_;
$ll = '';
&send('cl', ":$us_nick!$machine{$us_nick} JOIN :$_\n");
&send('cl', ":$sv[0] 332 $us_nick $_ :$topic{$_}\n") if $topic{$_};
$l = length(":$sv[0] 353 $us_nick = $_ :");
foreach $name (split(/$;/, $ls_mem{$_})) {
next unless $name;
if ($l + length($name) + 1 > 510) {
&send('cl', ":$sv[0] 353 $us_nick = $_ :$ll\n");
$l = length(":$sv[0] 353 $us_nick = $_ :");
$ll = '';
}
$l += length($name) + 1;
$ll .= "$name ";
}
&send('cl', ":$sv[0] 353 $us_nick = $_ :$ll\n") if $ll;
&send('cl', ":$sv[0] 366 $us_nick $_ :End of /NAMES list.\n");
}
} else {
&send('cl', "NOTICE $us_nick :" .
&mio('MADOKA_NOSERVER', '[!] Now, no server connection.') . "\n");
}
&send('cl', ":$sv[0] 301 $us_nick $us_nick :$us_mes_away\n")
if $us_mes_away;
if ($us_mes_away ne '') {
&mes("[!] Autoaway off\n", 'ALL');
$us_mes_away = '';
&send('sv', "AWAY :\n");
}
vec($at_state, 6, 1) = 0 if vec($dcc_state, 3, 1) && vec($at_state, 6, 1);
}
sub getaddrinfo6 {
my($l, $port) = @_;
if ($INC{'Socket6.pm'}) {
my @l = getaddrinfo($l, $port, 0, $SOCK_STREAM);
return $l[8] || $l[3];
} else {
$l = (gethostbyname($l))[4];
return pack_sockaddr_in($port, $l);
}
}
sub plugin {
foreach (split(/$;/, $plugin_do)) {
next unless $_;
do $_;
}
foreach (split(/$;/, $plugin_sub)) {
next unless $_;
&$_ if defined(&$_);
}
}
sub redo {
local $file = &search_file($_[0]);
&down("[ERROR] Not Found: $file\n") unless -f $file;
local $l = q! do $file;
&mes("plugin new: $file\n") if defined(&listen_client); !;
&_redo($file, $l);
}
sub _redo {
local($file, $l) = @_;
if ($plugin_change{$file}) {
$plugin_change_old{$file} = $plugin_change{$file};
} else {
$plugin_change_old{$file} = 0;
}
$plugin_change{$file} = -M $file;
if ($plugin_change_old{$file} > $plugin_change{$file} ||
$plugin_change_old{$file} == 0) {
eval($l);
&mes("[ERROR] _redo: $@") if $@;
return 1;
}
return 0;
}
sub search_file {
my $file = $_[0];
foreach (@plugindir, './', './plugin/', @INC) {
$_ .= '/' if $_ !~ /\/$/;
if (-r "$_$file") {
$file = "$_$file";
last;
}
}
return $file;
}
sub ctcp {
my($chan, $mes) = @_;
my $com;
($com, $mes) = split(/\s/, $mes, 2);
my($cmd, $ff) = ($com, 0);
my $ctcp_cmd = "ctcp_$com";
$ctcp_cmd =~ tr/A-Z/a-z/;
my($chanr, $chanv) = &alias_chan($chan);
&mes("[ctcp] chan: $chanv\n", 'D') if $chanv;
if ($chanr eq $us_nick) {
&mes("[!] ctcp from $from: $com $mes\n", 'P') if $com;
} else {
&mes("[!] ctcp from $from($chanv): $com $mes\n", 'P') if $com;
}
push(@ctcp_queue, "$ctcp_cmd:$from:$mes") if $ctcp_cmd ne 'ctcp_';
($ctcp_cmd, $from, $mes) = split(/:/, shift(@ctcp_queue), 3);
if (defined(&$ctcp_cmd)) {
&$ctcp_cmd($mes);
if ($t_count < 1) {
$ff = 1 if vec($dcc_state, 3, 1) || $com !~ /^dcc$/i;
} else {
unshift(@ctcp_queue, "$ctcp_cmd:$from:$mes");
}
} else {
&send('cch', "NOTICE $us_nick :$com\@$from: $mes\n") if $com;
$ff = 0;
}
return $ff;
}
sub mes {
my($mes, $chan) = @_;
$mes =~ s/\r*\n$//;
if ($yr_cache && $chan ne 'D') {
push(@cache_mes, $mes);
shift(@cache_mes) if $#cache_mes > $yr_cache;
}
&Log("$mes\n", $chan || 'ALL') if &list_exist($plugin_list, 'log');
}
sub send {
local($com, $mes, $cl_no) = @_;
my $sn_cmd = "sn_$com";
if (defined(&$sn_cmd)) {
&kanji_jis(*mes) if &list_exist($plugin_list, 'kanji');
$mes =~ s/\r*\n$/\r\n/;
&$sn_cmd($mes, $cl_no);
&mes("[send/$com] $mes", 'D');
}
}
sub sn_sv {
return unless vec($sv_state, 0, 1);
local $mes = $_[0];
if ($mes =~ /^[^\001]*\001[^\001]*\001/) {
unshift(@mes_buf, $mes);
} elsif ($mes && $mes ne ' ') {
push(@mes_buf, $mes);
}
$mes = shift(@mes_buf);
if (&list_exist($per_sec, 'flood')) {
&flood_send($mes);
} else {
print SERVER $mes;
my($chan, $pr) = ($mes =~ /^PRIVMSG ([^ ]+) :(.*)/);
my($chanr, $chanv) = &alias_chan($chan);
&mes(">$chanv:$us_nick< $pr\n", $chanr) if $pr;
}
}
sub sn_cl {
return unless $cl;
local($mes, $cl_no) = @_;
my($cl_code, $kanji);
if (&list_exist($plugin_list, 'kanji') && $cl_code[$i]) {
$cl_code = $cl_code[$i];
$kanji = "kanji_$cl_code";
&$kanji(*mes);
}
print $cl $mes;
}
sub sn_ccn {
local($mes, $cl_no) = @_;
my($cc, $cl_code, $kanji);
for ($i = 0; $i <= $cl_max; $i++) {
$cc = $cl[$i];
next unless $cc;
if (vec($cl_ok, $i, 1)) {
if (&list_exist($plugin_list, 'kanji') && $cl_code[$i]) {
$cl_code = $cl_code[$i];
$kanji = "kanji_$cl_code";
&$kanji(*mes);
}
print $cc $mes;
}
}
}
sub sn_cch {
local($mes, $cl_no) = @_;
my($cc, $cl_code, $kanji);
for ($i = 0; $i <= $cl_max; $i++) {
$cc = $cl[$i];
next unless $cc;
if (vec($cl_ok, $i, 1) && !vec($cl_chan, $i, 1)) {
if (&list_exist($plugin_list, 'kanji') && $cl_code[$i]) {
$cl_code = $cl_code[$i];
$kanji = "kanji_$cl_code";
&$kanji(*mes);
}
print $cc $mes;
}
}
}
sub sn_cco {
local($mes, $cl_no) = @_;
my($cc, $cl_code, $kanji);
for ($i = 0; $i <= $cl_max; $i++) {
$cc = $cl[$i];
next unless $cc;
if (vec($cl_ok, $i, 1) && !vec($cl_chan, $i, 1) && $cl_no != $i) {
if (&list_exist($plugin_list, 'kanji') && $cl_code[$i]) {
$cl_code = $cl_code[$i];
$kanji = "kanji_$cl_code";
&$kanji(*mes);
}
print $cc $mes;
}
}
}
sub sendSCL {
local($mes, $chan, $code, $w) = @_;
local($chanr, $chanv) = &alias_chan($chan);
my $cl_code = $cl_code[$cl_no] || 'jis';
my $kanji = "kanji_$cl_code";
&kanji_jis(*mes, $code) if &list_exist($plugin_list, 'kanji');
$mes =~ s/\r*\n$//;
if ($w) {
push(@mes_buf2, "$w $chanr $mes");
} else {
&send('sv', "PRIVMSG $chanr :$mes\r\n");
&$kanji(*mes) if &list_exist($plugin_list, 'kanji');
&send('cch', ":$us_nick!$machine{$us_nick} PRIVMSG $chanr :$mes\r\n");
}
}
sub sendSCL_sec {
return if scalar(@mes_buf2) == 0;
my($i, $w, $chan);
local $mes;
my $cl_code = $cl_code[$cl_no] || 'jis';
my $kanji = "kanji_$cl_code";
for ($i = 0; $i <= scalar(@mes_buf2); $i++) {
($w, $chan, $mes) = split(/ /, shift(@mes_buf2), 3);
if ($w < time) {
&send('sv', "PRIVMSG $chan :$mes\r\n");
&$kanji(*mes) if &list_exist($plugin_list, 'kanji');
&send('cch', ":$us_nick!$machine{$us_nick} PRIVMSG $chan :$mes\r\n");
} else {
push(@mes_buf2, "$w $chan $mes");
}
}
}
sub cached {
my($mes, $chan, $code, $w) = @_;
my($chanr, $chanv) = &alias_chan($chan);
foreach (@cache_mes) {
return if $_ eq ">$chanv:$us_nick< $mes";
}
&sendSCL($mes, $chan, $code, $w);
}
sub list_init {
$_[0] = "$;";
}
sub list_add {
&list_init($_[0]) unless $_[0];
unless (&list_exist(@_)) {
$_[0] .= "$_[1]$;";
return 1;
}
return 0;
}
sub list_del {
local($u, @pr) = @_;
my($f, $l) = (0, '');
foreach (@pr) {
$l = "\Q$_\E";
if ($_[0] =~ /$;$l$;/i) {
substr($_[0], index($_[0], "$;$_$;"), length("$;$_$;")) = "$;";
$f = 1;
}
}
return $f;
}
sub list_exist {
local($u, @pr) = @_;
my $f = 0;
foreach (@pr) {
next unless $_;
$f = 1 if $_[0] =~ /$;(\Q$_\E)$;/i;
}
return $f;
}
sub list_change {
my $pr = "\Q$_[1]\E";
if ($_[0] =~ /$;$pr$;/i) {
substr($_[0], index($_[0], "$;$_[1]$;"), length("$;$_[1]$;")) = "$;$_[2]$;";
return 1;
}
return 0;
}
sub current_time {
($sec, $min, $hour, $mday, $mon, $year) = localtime(time);
$mon++;
$year += 1900;
}
sub alias_chan {
my $chan = my $chanr = my $chanv = &check_chl($_[0]);
return unless $_[0];
if ($chl_mask ne '') {
my $l = "\Q$chl_mask\E";
if ($chan =~ /^\#(.*):$l$/i) {
$chanv = '%' . $1;
}
if ($chan =~ /^%/) {
$chan =~ s/^%/\#/;
$chanr = "$chan:$chl_mask";
}
}
foreach (keys(%chl_alias)) {
if ($_ eq $chanr) {
$chanv = $chl_alias{$_};
last;
} elsif ($chl_alias{$_} eq $chanv) {
$chanr = $_;
last;
}
}
return($chanr, $chanv);
}
sub taillog {
if ($taillog) {
foreach (@tail) {
next unless $_;
&send('cl', "NOTICE $us_nick :$_");
}
&send('cl', "NOTICE $us_nick :" .
&mio('MADOKA_TAILLOG', '[!] end of taillog') . "\n");
}
}
sub check_chan {
$_[0] =~ s/\033\$\@/\033\$B/g;
$_[0] =~ s/\033\(J/\033\(B/g;
return 0 if $_[0] =~ / / || $_[0] =~ /\007/ || $_[0] =~ /^[^$chl_header]/ ||
($_[0] =~ /,/ && scalar(&chl_split($_[0])) > 1);
return 1;
}
sub check_chl {
my $l = my $chan = $_[0];
$l = "\Q$l\E";
if ($chl =~ /$;($l)$;/i || $chl_autojoin =~ /$;($l)$;/i) {
$chan = $1;
}
return $chan;
}
sub chl_split {
my $l = $_[0];
my(@ch, $i, $j, $jis);
$j = $jis = 0;
for ($i = 0; $i < length($l); $i++) {
if (substr($l, $i, 1) eq ',' && $jis == 0) {
$j++;
$i++;
}
$ch[$j] .= substr($l, $i, 1);
if ($jis == 0 && substr($l, $i+1, 3) =~ /^\e\$[\@B]/i) {
$jis = 1;
$ch[$j] .= substr($l, $i+1, 3);
$i += 3;
} elsif ($jis == 1 && substr($l, $i+1, 3) =~ /^\e\([BHJ]/i) {
$jis = 0;
$ch[$j] .= substr($l, $i+1, 3);
$i += 3;
}
}
return @ch;
}
sub check_host {
my($cl_no, @ip) = @_;
my($cl_addr, $netmask, $l);
if ($host[$cl_no] =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
$cl_addr = 2 ** 24 * $1 + 2 ** 16 * $2 + 2 ** 8 * $3 + $4;
&mes("[check_host] host: $host[$cl_no] via IPv4", 'D');
} elsif ($host[$cl_no] =~ /^0000:0000:0000:0000:0000:ffff:([\da-f]{4}:[\da-f]{4})$/i) {
($cl_addr = $1) =~ s/://;
$cl_addr = hex('0x'.$cl_addr);
&mes("[check_host] host: $host[$cl_no] via IPv6 on IPv4 mapped", 'D');
} else {
$cl_addr = "\L$host[$cl_no]\E";
&mes("[check_host] host: $host[$cl_no] via IPv6", 'D');
}
&mes("[check_host] cl_addr: $cl_addr", 'D');
foreach (@ip) {
next unless $_;
&mes("[check_host] iploop: $_", 'D');
if (/^(?:0{0,4}:){1,4}:ffff:([\da-f]{1,4}):([\da-f]{1,4})(?:\/(\d+))?$/i) {
$_ = hex('0x'.sprintf("%04s%04s", $1, $2));
$_ .= sprintf("/%d", $3 - 96) if $3;
}
if ($cl_addr =~ /:/) { # IPv6
my $k = $cl_addr;
if (/^\./) {
my $i = (getaddrinfo($k, 0, $AF_INET6, $SOCK_STREAM))[3];
my $host = (getnameinfo($i, 0))[0];
&mes("[check_host] hostname6: $host", 'D');
return 1 if $host =~ /\Q$_\E$/;
return 0;
} elsif (/^(.+)\/(\d+)$/) {
$l = "\L$1\E";
$netmask = $2/4;
next if $netmask * 4 % 4 > 0; # ignore
} else {
$l = "\L$_\E";
$netmask = 32;
}
my $i = (getaddrinfo($l, 0, $AF_INET6, $SOCK_STREAM))[3];
my($u, $j) = sockaddr_in6($i);
$l = join(':', unpack('H4 H4 H4 H4 H4 H4 H4 H4', $j));
$l =~ s/://g;
$i = (getaddrinfo($k, 0, $AF_INET6, $SOCK_STREAM))[3];
$i = (getnameinfo($i, 0))[0];
$i = (getaddrinfo($i, 0, $AF_INET6, $SOCK_STREAM))[3];
($u, $j) = sockaddr_in6($i);
$k = join(':', unpack('H4 H4 H4 H4 H4 H4 H4 H4', $j));
$k =~ s/://g;
&mes("[check_host] addr: $l / $k / $netmask", 'D');
return 1 if substr($l, 0, $netmask) eq substr($k, 0, $netmask);
} else { # IPv4
if (/^(.+)\/(.+)$/) {
$l = $1;
$netmask = $2;
} else {
$l = $_;
$netmask = 32;
}
if ($l =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
$l = 2 ** 24 * $1 + 2 ** 16 * $2 + 2 ** 8 * $3 + $4;
} else {
$l = unpack('N1', (gethostbyname($l))[4]);
}
if ($netmask =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) {
$netmask = 2 ** 24 * $1 + 2 ** 16 * $2 + 2 ** 8 * $3 + $4;
} else {
$netmask = int((2 ** $netmask - 1) << (32 - $netmask));
}
return 1 if ($cl_addr & $netmask) == ($l & $netmask);
if (/^\./) {
my($port, $addr) = sockaddr_in(getpeername($cl[$cl_no]));
my $host = gethostbyaddr($addr, $AF_INET4);
&mes("[check_host] hostname: $host", 'D');
return 1 if $host =~ /\Q$_\E$/;
}
}
}
return 0;
}
sub mio {
my($_tag, $_mes) = @_;
$mes =~ s/\r*\n$//;
return &Mio($_tag, $_mes) if &list_exist($plugin_list, 'mio');
return $_mes;
}
sub down {
my $mes = $_[0];
$mes .= "\n" if $mes !~ /\n$/;
print STDERR $mes;
exit 0;
}
__END__