$Data::Dumper::Sortkeys
= 1;
no
warnings
qw(uninitialized)
;
our
$VERSION
= (
split
(
' '
,
'$Revision: 472 $'
) )[1];
sub
init {
my
$self
=
shift
;
%$self
= (
%$self
,
'Nick'
=>
'NetDCBot'
,
'port'
=> 411,
'host'
=>
'localhost'
,
'Pass'
=>
''
,
'key'
=>
'zzz'
,
'supports_avail'
=> [
qw(
NoGetINFO
NoHello
UserIP2
UserCommand
TTHSearch
OpPlus
Feed
MCTo
HubTopic
)
],
'search_every'
=> 10,
'search_every_min'
=> 10,
'auto_connect'
=> 1,
'NoGetINFO'
=> 1,
'NoHello'
=> 1,
'UserIP2'
=> 1,
'Version'
=>
'1,0091'
,
'auto_GetNickList'
=> 1,
'follow_forcemove'
=> 1,
@_
,
'incomingclass'
=>
'Net::DirectConnect::clicli'
,
'periodic'
=>
sub
{
$self
->cmd(
'search_buffer'
, )
if
$self
->{
'socket'
}; },
);
$self
->baseinit();
$self
->{
'parse'
} ||= {
'chatline'
=>
sub
{
my
(
$nick
,
$text
) =
$_
[0] =~ /^(?:<|\* )(.+?)>? (.+)$/s;
$self
->
log
(
'warn'
,
"[$nick] oper: already in the hub [$self->{'Nick'}]"
),
$self
->cmd(
'nick_generate'
),
$self
->reconnect(),
if
( ( !
keys
%{
$self
->{
'NickList'
} } or
$self
->{
'NickList'
}->{
$nick
}{
'oper'
} )
and
$text
eq
'You are already in the hub.'
);
if
(
$self
->{
'NickList'
}->{
$nick
}{
'oper'
} or
$nick
eq
'Hub-Security'
) {
if
(
$text
=~ /^(?:Minimum search interval is|Ìèíèìàëüíûé èíòåðâàë ïîèñêà):(\d+)s/
or
$text
=~ /Search ignored\. Please leave at least (\d+) seconds between search attempts\./
)
{
$self
->
log
(
'warn'
,
"[$nick] oper: set min interval = $1"
);
$self
->{
'search_every'
} =
int
$1 ||
$self
->{
'search_every_min'
};
$self
->search_retry();
}
if
(
$text
=~ /Ïîæàëóéñòà ïîäîæäèòå (\d+) ñåêóíä ïåðåä ñëåäóþùèì ïîèñêîì\./
or
$text
eq
'Ïîæàëóéñòà íå èñïîëüçóéòå ïîèñê òàê ÷àñòî!'
)
{
$self
->
log
(
'warn'
,
"[$nick] oper: increase min interval +="
,
int
$1 ||
$self
->{
'search_every_min'
} ),
$self
->{
'search_every'
} +=
int
$1 ||
$self
->{
'search_every_min'
};
$self
->search_retry();
}
}
$self
->search_retry(),
if
$self
->{
'NickList'
}->{
$nick
}{
'oper'
} and
$text
eq
'Sorry Hub is busy now, no search, try later..'
;
},
'welcome'
=>
sub
{
my
(
$nick
,
$text
) =
$_
[0] =~ /^(?:<|\* )(.+?)>? (.+)$/s;
if
( ( !
keys
%{
$self
->{
'NickList'
} } or !
exists
$self
->{
'NickList'
}->{
$nick
} or
$self
->{
'NickList'
}->{
$nick
}{
'oper'
} )
and
$text
=~ /^Bad nickname: unallowed characters,
use
these (\S+)/ )
{
my
$try
=
$self
->{
'Nick'
};
$try
=~ s/[^\Q$1\E]//g;
$self
->
log
(
'warn'
,
"CHNICK $self->{'Nick'} -> $try"
);
$self
->{
'Nick'
} =
$try
if
length
$try
;
}
},
'Lock'
=>
sub
{
$self
->
log
(
"lockparse"
,
@_
);
$self
->{
'sendbuf'
} = 1;
$self
->cmd(
'Supports'
);
$_
[0] =~ /^(.+?)(\s+Pk=.+)?\s*$/is;
print
"lock[$1]\n"
;
$self
->cmd(
'Key'
,
$self
->lock2key($1) );
$self
->{
'sendbuf'
} = 0;
$self
->cmd(
'ValidateNick'
);
},
'Hello'
=>
sub
{
return
unless
$_
[0] eq
$self
->{
'Nick'
};
$self
->{
'sendbuf'
} = 1;
$self
->cmd(
'Version'
);
$self
->{
'sendbuf'
} = 0
unless
$self
->{
'auto_GetNickList'
};
$self
->cmd(
'MyINFO'
);
$self
->{
'sendbuf'
} = 0,
$self
->cmd(
'GetNickList'
)
if
$self
->{
'auto_GetNickList'
};
$self
->{
'status'
} =
'connected'
;
$self
->cmd(
'make_hub'
);
},
'Supports'
=>
sub
{
$self
->supports_parse(
$_
[0],
$self
);
},
'ValidateDenide'
=>
sub
{
$self
->cmd(
'nick_generate'
);
$self
->cmd(
'ValidateNick'
);
},
'To'
=>
sub
{
$self
->
log
(
'msg'
,
"Private message to"
,
@_
);
},
'MyINFO'
=>
sub
{
my
(
$nick
,
$info
) =
$_
[0] =~ /\S+\s+(\S+)\s+(.*)/;
$self
->{
'NickList'
}->{
$nick
}{
'Nick'
} =
$nick
;
$self
->info_parse(
$info
,
$self
->{
'NickList'
}{
$nick
} );
$self
->{
'NickList'
}->{
$nick
}{
'online'
} = 1;
},
'UserIP'
=>
sub
{
/(\S+)\s+(\S+)/,
$self
->{
'NickList'
}{$1}{
'ip'
} = $2,
$self
->{
'IpList'
}{$2} =
$self
->{
'NickList'
}{$1},
$self
->{
'IpList'
}{$2}{
'port'
} =
$self
->{
'PortList'
}{$2}
for
grep
$_
,
split
/\$\$/,
$_
[0];
},
'HubName'
=>
sub
{
$self
->{
'HubName'
} =
$_
[0];
},
'HubTopic'
=>
sub
{
$self
->{
'HubTopic'
} =
$_
[0];
},
'NickList'
=>
sub
{
$self
->{
'NickList'
}->{
$_
}{
'online'
} = 1
for
grep
$_
,
split
/\$\$/,
$_
[0];
},
'OpList'
=>
sub
{
$self
->{
'NickList'
}->{
$_
}{
'oper'
} = 1
for
grep
$_
,
split
/\$\$/,
$_
[0];
},
'ForceMove'
=>
sub
{
$self
->
log
(
'warn'
,
"ForceMove to $_[0]"
);
$self
->disconnect();
sleep
(1);
$self
->
connect
(
@_
)
if
$self
->{
'follow_forcemove'
} and
@_
;
},
'Quit'
=>
sub
{
$self
->{
'NickList'
}->{
$_
[0] }{
'online'
} = 0;
},
'ConnectToMe'
=>
sub
{
my
(
$nick
,
$host
,
$port
) =
$_
[0] =~ /\s*(\S+)\s+(\S+)\:(\S+)/;
$self
->{
'PortList'
}->{
$host
} =
$port
;
return
if
$self
->{
'clients'
}{
$host
.
':'
.
$port
}->{
'socket'
};
$self
->{
'clients'
}{
$host
.
':'
.
$port
} = Net::DirectConnect::clicli->new(
%$self
,
$self
->clear(),
'host'
=>
$host
,
'port'
=>
$port
,
'want'
=> \%{
$self
->{
'want'
} },
'NickList'
=> \%{
$self
->{
'NickList'
} },
'IpList'
=> \%{
$self
->{
'IpList'
} },
'PortList'
=> \%{
$self
->{
'PortList'
} },
'handler'
=> \%{
$self
->{
'handler'
} },
'auto_connect'
=> 1,
);
},
'RevConnectToMe'
=>
sub
{
my
(
$to
,
$from
) =
split
/\s+/,
$_
[0];
$self
->cmd(
'ConnectToMe'
,
$to
)
if
$from
eq
$self
->{
'Nick'
};
},
'GetPass'
=>
sub
{
$self
->cmd(
'MyPass'
);
},
'BadPass'
=>
sub
{
},
'LogedIn'
=>
sub
{
},
'Search'
=>
sub
{
my
$search
=
$_
[0];
$self
->cmd(
'make_hub'
);
my
%s
= (
'time'
=>
int
(
time
() ),
'hub'
=>
$self
->{
'hub'
}, );
(
$s
{
'who'
},
$s
{
'cmds'
} ) =
split
/\s+/,
$search
;
$s
{
'cmd'
} = [
split
/\?/,
$s
{
'cmds'
} ];
if
(
$s
{
'who'
} =~ /^Hub:(.+)$/ ) {
$s
{
'nick'
} = $1; }
else
{ (
$s
{
'ip'
},
$s
{
'port'
} ) =
split
/:/,
$s
{
'who'
}; }
if
(
$s
{
'cmd'
}[4] =~ /^TTH:([0-9A-Z]{39})$/ ) {
$s
{
'tth'
} = $1; }
else
{
$s
{
'string'
} =
$s
{
'cmd'
}[4]; }
$s
{
'string'
} =~
tr
/$/ /;
return
\
%s
;
},
'SR'
=>
sub
{
$self
->cmd(
'make_hub'
);
my
%s
= (
'time'
=>
int
(
time
() ),
'hub'
=>
$self
->{
'hub'
}, );
(
$s
{
'nick'
},
$s
{
'str'
} ) =
split
/ /,
$_
[0], 2;
$s
{
'str'
} = [
split
/\x05/,
$s
{
'str'
} ];
$s
{
'file'
} =
shift
@{
$s
{
'str'
} };
(
$s
{
'filename'
} ) =
$s
{
'file'
} =~ m{([^\\]+)$};
(
$s
{
'ext'
} ) =
$s
{
'filename'
} =~ m{[^.]+\.([^.]+)$};
(
$s
{
'size'
},
$s
{
'slots'
} ) =
split
/ /,
shift
@{
$s
{
'str'
} };
(
$s
{
'tth'
},
$s
{
'ipport'
} ) =
split
/ /,
shift
@{
$s
{
'str'
} };
(
$s
{
'target'
} ) =
shift
@{
$s
{
'str'
} };
(
$s
{
'ipport'
},
$s
{
'ip'
},
$s
{
'port'
} ) =
$s
{
'ipport'
} =~ /\(((\S+):(\d+))\)/;
delete
$s
{
'str'
};
(
$s
{
'slotsopen'
},
$s
{
'S'
} ) =
split
/\//,
$s
{
'slots'
};
$s
{
'slotsfree'
} =
$s
{
'S'
} -
$s
{
'slotsopen'
};
$s
{
'string'
} =
$self
->{
'search_last_string'
};
$self
->{
'NickList'
}{
$s
{
'nick'
} }{
$_
} =
$s
{
$_
}
for
qw(S ip port)
;
$self
->{
'PortList'
}->{
$s
{
'ip'
} } =
$s
{
'port'
};
$self
->{
'IpList'
}->{
$s
{
'ip'
} } =
$self
->{
'NickList'
}{
$s
{
'nick'
} };
return
\
%s
;
},
'UserCommand'
=>
sub
{
},
'ISUP'
=>
sub
{ },
'ISID'
=>
sub
{
$self
->{
'sid'
} =
$_
[0] },
'IINF'
=>
sub
{
$self
->cmd(
'BINF'
) },
'IQUI'
=>
sub
{ },
'ISTA'
=>
sub
{
$self
->
log
(
'dcerr'
,
@_
) },
};
$self
->{
'cmd'
} = {
'chatline'
=>
sub
{
for
(
@_
) {
if
(
$self
->{
'min_chat_delay'
} and (
time
-
$self
->{
'last_chat_time'
} <
$self
->{
'min_chat_delay'
} ) ) {
$self
->
log
(
'dbg'
,
'sleep'
,
$self
->{
'min_chat_delay'
} -
time
+
$self
->{
'last_chat_time'
} );
$self
->wait_sleep(
$self
->{
'min_chat_delay'
} -
time
+
$self
->{
'last_chat_time'
} );
}
$self
->{
'last_chat_time'
} =
time
;
$self
->
log
(
'dcdmp'
,
"($self->{'number'}) we send ["
,
"<$self->{'Nick'}> $_|"
,
"]:"
,
$self
->{
'socket'
}->
send
(
"<$self->{'Nick'}> $_|"
), $!
);
}
},
'To'
=>
sub
{
my
$to
=
shift
;
$self
->sendcmd(
'To:'
,
$to
,
"From: $self->{'Nick'} \$<$self->{'Nick'}> $_"
)
for
(
@_
);
},
'Key'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
$self
->sendcmd(
'Key'
,
$_
[0] );
},
'ValidateNick'
=>
sub
{
$self
->sendcmd(
'ValidateNick'
,
$self
->{
'Nick'
} );
},
'Version'
=>
sub
{
$self
->sendcmd(
'Version'
,
$self
->{
'Version'
} );
},
'MyINFO'
=>
sub
{
$self
->sendcmd(
'MyINFO'
,
'$ALL'
,
$self
->myinfo() );
},
'GetNickList'
=>
sub
{
$self
->sendcmd(
'GetNickList'
);
},
'GetINFO'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
@_
=
grep
{
$self
->{
'NickList'
}{
$_
}{
'online'
} and !
$self
->{
'NickList'
}{
$_
}{
'info'
} }
keys
%{
$self
->{
'NickList'
} }
unless
@_
;
local
$self
->{
'sendbuf'
} = 1;
$self
->sendcmd(
'GetINFO'
,
$_
,
$self
->{
'Nick'
} )
for
@_
;
$self
->sendcmd();
},
'ConnectToMe'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
return
if
$self
->{
'M'
} eq
'P'
and !
$self
->{
'allow_passive_ConnectToMe'
};
$self
->
log
(
'err'
,
"please define myip"
),
return
unless
$self
->{
'myip'
};
$self
->sendcmd(
'ConnectToMe'
,
$_
[0],
"$self->{'myip'}:$self->{'myport'}"
);
},
'RevConnectToMe'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
$self
->
log
(
"send"
, (
'RevConnectToMe'
,
$self
->{
'Nick'
},
$_
[0] ),
ref
$_
[0] );
$self
->sendcmd(
'RevConnectToMe'
,
$self
->{
'Nick'
},
$_
[0] );
},
'MyPass'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
my
$pass
= (
$_
[0] or
$self
->{
'Pass'
} );
$self
->sendcmd(
'MyPass'
,
$pass
)
if
$pass
;
},
'Supports'
=>
sub
{
$self
->sendcmd(
'Supports'
,
$self
->supports() ||
return
);
},
'Quit'
=>
sub
{
$self
->sendcmd(
'Quit'
,
$self
->{
'Nick'
} );
$self
->disconnect();
},
'Search'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
$self
->sendcmd(
'Search'
, (
$self
->{
'M'
} eq
'P'
?
"Hub:$self->{'Nick'}"
:
"$self->{'myip'}:$self->{'myport_udp'}"
),
join
'?'
,
@_
);
},
'search_buffer'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
push
( @{
$self
->{
'search_todo'
} }, [
@_
] )
if
@_
;
return
unless
@{
$self
->{
'search_todo'
} ||
return
};
return
if
time
() -
$self
->{
'search_last_time'
} <
$self
->{
'search_every'
} + 2;
$self
->{
'search_last'
} =
shift
( @{
$self
->{
'search_todo'
} } );
$self
->{
'search_todo'
} =
undef
unless
@{
$self
->{
'search_todo'
} };
$self
->sendcmd(
'Search'
,
$self
->{
'M'
} eq
'P'
?
'Hub:'
.
$self
->{
'Nick'
} :
"$self->{'myip'}:$self->{'myport'}"
,
join
'?'
, @{
$self
->{
'search_last'
} } );
$self
->{
'search_last_time'
} =
time
();
},
'search_tth'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
$self
->{
'search_last_string'
} =
undef
;
$self
->cmd(
'search_buffer'
,
'F'
,
'T'
,
'0'
,
'9'
,
'TTH:'
.
$_
[0] );
},
'search_string'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
my
$string
=
$_
[0];
$self
->{
'search_last_string'
} =
$string
;
$string
=~
tr
/ /$/;
$self
->cmd(
'search_buffer'
,
'F'
,
'T'
,
'0'
,
'1'
,
$string
);
},
'search'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
return
$self
->cmd(
'search_tth'
,
@_
)
if
length
$_
[0] == 39 and
$_
[0] =~ /^[0-9A-Z]+$/;
return
$self
->cmd(
'search_string'
,
@_
)
if
length
$_
[0];
},
'search_retry'
=>
sub
{
my
$self
=
shift
if
ref
$_
[0];
unshift
( @{
$self
->{
'search_todo'
} },
$self
->{
'search_last'
} )
if
ref
$self
->{
'search_last'
} eq
'ARRAY'
;
$self
->{
'search_last'
} =
undef
;
},
'make_hub'
=>
sub
{
$self
->{
'hub'
} ||=
$self
->{
'host'
} . ( (
$self
->{
'port'
} and
$self
->{
'port'
} != 411 ) ?
':'
.
$self
->{
'port'
} :
''
);
},
'nick_generate'
=>
sub
{
$self
->{
'nick_base'
} ||=
$self
->{
'Nick'
};
$self
->{
'Nick'
} =
$self
->{
'nick_base'
} .
int
(
rand
(
$self
->{
'nick_random'
} || 100 ) );
},
'connect_aft'
=>
sub
{
$self
->cmd(
'HSUP'
)
if
$self
->{
'protocol'
} eq
'adc'
},
'HSUP'
=>
sub
{
$self
->{
'SUPADS'
} ||= [
qw(BAS0 BASE TIGR UCM0 BLO0)
];
$self
->{
'SUPAD'
} ||= {
map
{
$_
=> 1 } @{
$self
->{
'SUPADS'
} } };
$self
->sendcmd(
'HSUP'
, (
map
{
'AD'
.
$_
} @{
$self
->{
'SUPADS'
} } ), (
map
{
'RM'
.
$_
}
keys
%{
$self
->{
'SUPRM'
} } ), );
},
'BINF'
=>
sub
{
$self
->{
'BINFS'
} ||= [
qw(ID PD NI SL SS SF HN HR HO VE US SU)
];
$self
->{
'NI'
} ||=
$self
->{
'Nick'
} ||
'perlAdcDev'
;
sub
hash {
local
(
$_
) =
@_
;
eval
"use MIME::Base32 qw( RFC ); use Digest::Tiger;"
;
MIME::Base32::encode( Digest::Tiger::hash(
$_
) );
}
$self
->{
'PD'
} ||= hash(
'perl'
.
$self
->{
'myip'
} .
$self
->{
'NI'
} .
time
);
$self
->{
'ID'
} ||= hash(
$self
->{
'PD'
} );
$self
->{
'SL'
} ||=
$self
->{
'S'
} ||
'2'
;
$self
->{
'SS'
} ||=
$self
->{
'sharesize'
} || 20025693588;
$self
->{
'SF'
} ||= 30999;
$self
->{
'HN'
} ||=
$self
->{
'H'
} || 1;
$self
->{
'HR'
} ||=
$self
->{
'R'
} || 0;
$self
->{
'HO'
} ||=
$self
->{
'O'
} || 0;
$self
->{
'VE'
} ||=
$self
->{
'V'
} ||
'++\s0.706'
;
$self
->{
'US'
} ||= 10000;
$self
->{
'SU'
} ||=
'ADC0'
;
$self
->sendcmd(
'BINF'
,
$self
->{
'sid'
},
map
{
$_
.
$self
->{
$_
} }
grep
{
$self
->{
$_
} } @{
$self
->{
'BINFS'
} } );
}
};
if
(
$self
->{
'M'
} eq
'A'
) {
$self
->
log
(
'dev'
,
"making listeners: tcp"
);
$self
->{
'clients'
}{
'listener_tcp'
} =
$self
->{
'incomingclass'
}->new(
%$self
,
$self
->clear(),
'want'
=> \%{
$self
->{
'want'
} },
'NickList'
=> \%{
$self
->{
'NickList'
} },
'IpList'
=> \%{
$self
->{
'IpList'
} },
'PortList'
=> \%{
$self
->{
'PortList'
} },
'handler'
=> \%{
$self
->{
'handler'
} },
'auto_listen'
=> 1,
);
$self
->{
'myport'
} =
$self
->{
'myport_tcp'
} =
$self
->{
'clients'
}{
'listener_tcp'
}{
'myport'
};
$self
->
log
(
'err'
,
"cant listen tcp (file transfers)"
)
unless
$self
->{
'myport_tcp'
};
$self
->
log
(
'dev'
,
"making listeners: udp"
);
$self
->{
'clients'
}{
'listener_udp'
} =
$self
->{
'incomingclass'
}->new(
%$self
,
$self
->clear(),
'Proto'
=>
'udp'
,
'handler'
=> \%{
$self
->{
'handler'
} },
'parse'
=> {
'SR'
=>
$self
->{
'parse'
}{
'SR'
},
'UPSR'
=>
sub
{
},
},
'auto_listen'
=> 1,
);
$self
->{
'myport_udp'
} =
$self
->{
'clients'
}{
'listener_udp'
}{
'myport'
};
$self
->
log
(
'err'
,
"cant listen udp (search repiles)"
)
unless
$self
->{
'myport_udp'
};
}
}
1;