use Internet;
use Script;
use Net::Telnet;
+use QSL;
+use DB_File;
+use VE7CC;
+use DXXml;
use strict;
-use vars qw(%Cache %cmd_cache $errstr %aliases $scriptbase $maxerrors %nothereslug $maxbadcount);
+use vars qw(%Cache %cmd_cache $errstr %aliases $scriptbase $maxerrors %nothereslug
+ $maxbadcount $msgpolltime $default_pagelth $cmdimportdir);
%Cache = (); # cache of dynamically loaded routine's mod times
%cmd_cache = (); # cache of short names
$scriptbase = "$main::root/scripts"; # the place where all users start scripts go
$maxerrors = 20; # the maximum number of concurrent errors allowed before disconnection
$maxbadcount = 3; # no of bad words allowed before disconnection
-
+$msgpolltime = 3600; # the time between polls for new messages
+$cmdimportdir = "$main::root/cmd_import"; # the base directory for importing command scripts
+ # this does not exist as default, you need to create it manually
+ #
use vars qw($VERSION $BRANCH);
$VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
# ALWAYS output the user
my $ref = Route::User::get($call);
- DXProt::route_pc16($main::me, $main::routeroot, $ref) if $ref;
+ $main::me->route_pc16($main::mycall, undef, $main::routeroot, $ref) if $ref;
return $self;
}
my $name = $user->{name};
# log it
- my $host = $self->{conn}->{peerhost} || "unknown";
- Log('DXCommand', "$call connected from $host");
+ my $host = $self->{conn}->{peerhost};
+ $host ||= "AGW Port #$self->{conn}->{agwport}" if exists $self->{conn}->{agwport};
+ $host ||= "unknown";
+ LogDbg('DXCommand', "$call connected from $host");
$self->{name} = $name ? $name : $call;
$self->send($self->msg('l2',$self->{name}));
$self->state('prompt'); # a bit of room for further expansion, passwords etc
$self->{priv} = $user->priv || 0;
$self->{lang} = $user->lang || $main::lang || 'en';
- $self->{pagelth} = $user->pagelth || 20;
+ my $pagelth = $user->pagelth;
+ $pagelth = $default_pagelth unless defined $pagelth;
+ $self->{pagelth} = $pagelth;
($self->{width}) = $line =~ /width=(\d+)/; $line =~ s/\s*width=\d+\s*//;
$self->{width} = 80 unless $self->{width} && $self->{width} > 80;
$self->{consort} = $line; # save the connection type
# decide which motd to send
- my $motd = "${main::motd}_nor" unless $self->{registered};
+ my $motd;
+ unless ($self->{registered}) {
+ $motd = "${main::motd}_nor_$self->{lang}";
+ $motd = "${main::motd}_nor" unless -e $motd;
+ }
+ $motd = "${main::motd}_$self->{lang}" unless $motd && -e $motd;
$motd = $main::motd unless $motd && -e $motd;
$self->send_file($motd) if -e $motd;
$self->send($self->msg('qll')) if !$user->qra || (!$user->lat && !$user->long);
$self->send($self->msg('hnodee1')) if !$user->qth;
$self->send($self->msg('m9')) if DXMsg::for_me($call);
+ $self->lastmsgpoll($main::systime);
$self->prompt;
}
my @bad;
if (@bad = BadWords::check($l)) {
$self->badcount(($self->badcount||0) + @bad);
- Log('DXCommand', "$self->{call} swore: $l");
+ LogDbg('DXCommand', "$self->{call} swore: $l with words:" . join(',', @bad) . ")");
} else {
for (@{$self->{talklist}}) {
$self->send_talks($_, $l);
my @bad;
if (@bad = BadWords::check($cmdline)) {
$self->badcount(($self->badcount||0) + @bad);
- Log('DXCommand', "$self->{call} swore: $cmdline");
+ LogDbg('DXCommand', "$self->{call} swore: $cmdline with words:" . join(',', @bad) . ")");
} else {
for (@{$self->{talklist}}) {
$self->send_talks($_, $rawline);
# check for excessive swearing
if ($self->{badcount} && $self->{badcount} >= $maxbadcount) {
- Log('DXCommand', "$self->{call} logged out for excessive swearing");
+ LogDbg('DXCommand', "$self->{call} logged out for excessive swearing");
$self->disconnect;
return;
}
return () if length $cmdline == 0;
-
- # strip out //
- $cmdline =~ s|//|/|og;
-
+
+
# split the command line up into parts, the first part is the command
my ($cmd, $args) = split /\s+/, $cmdline, 2;
$args = "" unless defined $args;
if ($cmd) {
-
+ # strip out // on command only
+ $cmd =~ s|//|/|g;
+ $cmd =~ s|^/||g; # no leading / either
+ $cmd =~ s|[^-?\w/]||g; # and no funny characters either
+
my ($path, $fcmd);
dbg("cmd: $cmd") if isdbg('command');
# first expand out the entry to a command
($path, $fcmd) = search($main::localcmd, $cmd, "pl");
- ($path, $fcmd) = search($main::cmd, $cmd, "pl") if !$path || !$fcmd;
+ ($path, $fcmd) = search($main::cmd, $cmd, "pl") unless $path && $fcmd;
if ($path && $cmd) {
dbg("path: $cmd cmd: $fcmd") if isdbg('command');
sub process
{
my $t = time;
- my @dxchan = DXChannel->get_all();
+ my @dxchan = DXChannel::get_all();
my $dxchan;
foreach $dxchan (@dxchan) {
next if $dxchan->sort ne 'U';
+
+ # send a outstanding message prompt if required
+ if ($t >= $dxchan->lastmsgpoll + $msgpolltime) {
+ $dxchan->send($dxchan->msg('m9')) if DXMsg::for_me($dxchan->call);
+ $dxchan->lastmsgpoll($t);
+ }
# send a prompt if no activity out on this channel
if ($t >= $dxchan->t + $main::user_interval) {
delete $nothereslug{$k};
}
}
+
+ import_cmd();
}
#
dbg("B/C PC17 on $main::mycall for: $call") if isdbg('route');
# issue a pc17 to everybody interested
- DXProt::route_pc17($main::me, $main::routeroot, $uref);
+ $main::me->route_pc17($main::mycall, undef, $main::routeroot, $uref);
} else {
confess "trying to disconnect a non existant user $call";
}
# send info to all logged in thingies
$self->tell_login('logoutu');
- Log('DXCommand', "$call disconnected");
+ LogDbg('DXCommand', "$call disconnected");
$self->SUPER::disconnect;
}
sub prompt
{
my $self = shift;
- if ($self->{prompt}) {
- $self->send($self->{prompt});
- } else {
- $self->send($self->msg($self->here ? 'pr' : 'pr2', $self->call, cldate($main::systime), ztime($main::systime)));
- }
+ my $call = $self->call;
+ my $date = cldate($main::systime);
+ my $time = ztime($main::systime);
+ my $prompt = $self->{prompt} || $self->msg('pr');
+
+ $call = "($call)" unless $self->here;
+ $prompt =~ s/\%C/$call/g;
+ $prompt =~ s/\%D/$date/g;
+ $prompt =~ s/\%T/$time/g;
+ $prompt =~ s/\%M/$main::mycall/g;
+
+ $self->send($prompt);
}
# broadcast a message to all users [except those mentioned after buffer]
my $pkg = shift; # ignored
my $s = shift; # the line to be rebroadcast
- foreach my $dxchan (DXChannel->get_all()) {
+ foreach my $dxchan (DXChannel::get_all()) {
next unless $dxchan->{sort} eq 'U'; # only interested in user channels
next if grep $dxchan == $_, @_;
$dxchan->send($s); # send it
# gimme all the users
sub get_all
{
- return grep {$_->{sort} eq 'U'} DXChannel->get_all();
+ return grep {$_->{sort} eq 'U'} DXChannel::get_all();
}
# run a script for this user
my @parts = split '/', $short_cmd;
my $dirfn;
my $curdir = $path;
- my $p;
- my $i;
- my @lparts;
- for ($i = 0; $i < @parts; $i++) {
- my $p = $parts[$i];
- opendir(D, $curdir) or confess "can't open $curdir $!";
- my @ls = readdir D;
- closedir D;
- my $l;
- foreach $l (sort @ls) {
- next if $l =~ /^\./;
- if ($i < $#parts) { # we are dealing with directories
- if ((-d "$curdir/$l") && $p eq substr($l, 0, length $p)) {
- dbg("got dir: $curdir/$l\n") if isdbg('command');
- $dirfn .= "$l/";
- $curdir .= "/$l";
- last;
- }
- } else { # we are dealing with commands
- @lparts = split /\./, $l;
- next if $lparts[$#lparts] ne $suffix; # only look for .$suffix files
- if ($p eq substr($l, 0, length $p)) {
- pop @lparts; # remove the suffix
- $l = join '.', @lparts;
- # chop $dirfn; # remove trailing /
- $dirfn = "" unless $dirfn;
- $cmd_cache{$short_cmd} = join(',', ($path, "$dirfn$l")); # cache it
- dbg("got path: $path cmd: $dirfn$l\n") if isdbg('command');
- return ($path, "$dirfn$l");
- }
- }
- }
- }
+ while (my $p = shift @parts) {
+ opendir(D, $curdir) or confess "can't open $curdir $!";
+ my @ls = readdir D;
+ closedir D;
+
+ # if this isn't the last part
+ if (@parts) {
+ my $found;
+ foreach my $l (sort @ls) {
+ next if $l =~ /^\./;
+ if ((-d "$curdir/$l") && $p eq substr($l, 0, length $p)) {
+ dbg("got dir: $curdir/$l\n") if isdbg('command');
+ $dirfn .= "$l/";
+ $curdir .= "/$l";
+ $found++;
+ last;
+ }
+ }
+ # only proceed if we find the directory asked for
+ return () unless $found;
+ } else {
+ foreach my $l (sort @ls) {
+ next if $l =~ /^\./;
+ next unless $l =~ /\.$suffix$/;
+ if ($p eq substr($l, 0, length $p)) {
+ $l =~ s/\.$suffix$//;
+ $dirfn = "" unless $dirfn;
+ $cmd_cache{$short_cmd} = join(',', ($path, "$dirfn$l")); # cache it
+ dbg("got path: $path cmd: $dirfn$l\n") if isdbg('command');
+ return ($path, "$dirfn$l");
+ }
+ }
+ }
+ }
+
return ();
}
my $self = shift;
my $line = shift;
my $isolate = shift;
- my $to = shift;
my $target = shift;
+ my $to = shift;
my $text = shift;
my ($filter, $hops);
$self->local_send('C', $buf);
}
-# send a dx spot
-sub dx_spot
+sub format_dx_spot
{
my $self = shift;
- my $line = shift;
- my $isolate = shift;
- my ($filter, $hops);
- return unless $self->{dx};
-
- if ($self->{spotsfilter}) {
- ($filter, $hops) = $self->{spotsfilter}->it(@_ );
- return unless $filter;
- }
-
-
- dbg('spot: "' . join('","', @_) . '"') if isdbg('dxspot');
-
my $t = ztime($_[2]);
- my $loc;
+ my $loc = '';
my $clth = $self->{consort} eq 'local' ? 29 : 30;
my $comment = substr $_[3], 0, $clth;
$comment .= ' ' x ($clth - length($comment));
- my $ref = DXUser->get_current($_[4]);
- if ($ref) {
- $loc = $ref->qra || '' if $self->{user}->wantgrid;
- $loc = ' ' . substr($loc, 0, 4) if $loc;
- }
- $loc = "" unless $loc;
+ if ($self->{user}->wantgrid) {
+ my $ref = DXUser->get_current($_[4]);
+ if ($ref) {
+ $loc = $ref->qra || '';
+ $loc = ' ' . substr($loc, 0, 4) if $loc;
+ }
+ }
if ($self->{user}->wantdxitu) {
$loc = ' ' . sprintf("%2d", $_[10]) if defined $_[10];
$comment = substr($comment, 0, $self->{consort} eq 'local' ? 26 : 27) . ' ' . $_[12] if $_[12];
}
- my $buf = sprintf "DX de %-7.7s%11.1f %-12.12s %-s $t$loc", "$_[4]:", $_[0], $_[1], $comment;
-
- $buf .= "\a\a" if $self->{beep};
- $buf =~ s/\%5E/^/g;
+ return sprintf "DX de %-7.7s%11.1f %-12.12s %-s $t$loc", "$_[4]:", $_[0], $_[1], $comment;
+}
+
+# send a dx spot
+sub dx_spot
+{
+ my $self = shift;
+ my $line = shift;
+ my $isolate = shift;
+ return unless $self->{dx};
+
+ my ($filter, $hops);
+
+ if ($self->{spotsfilter}) {
+ ($filter, $hops) = $self->{spotsfilter}->it(@_ );
+ return unless $filter;
+ }
+
+ dbg('spot: "' . join('","', @_) . '"') if isdbg('dxspot');
+
+ my $buf;
+ if ($self->{ve7cc}) {
+ $buf = VE7CC::dx_spot($self, @_);
+ } else {
+ $buf = $self->format_dx_spot(@_);
+ $buf .= "\a\a" if $self->{beep};
+ $buf =~ s/\%5E/^/g;
+ }
+
$self->local_send('X', $buf);
}
return unless $self->{wwv};
if ($self->{wwvfilter}) {
- ($filter, $hops) = $self->{wwvfilter}->it(@_ );
+ ($filter, $hops) = $self->{wwvfilter}->it(@_[7..$#_] );
return unless $filter;
}
{
my $s = shift; # the line to be rebroadcast
- foreach my $dxchan (DXChannel->get_all) {
+ foreach my $dxchan (DXChannel::get_all) {
next unless $dxchan->{enhanced} && $dxchan->{senddbg};
$dxchan->send_later('L', $s);
}
}
+sub do_entry_stuff
+{
+ my $self = shift;
+ my $line = shift;
+ my @out;
+
+ if ($self->state eq 'enterbody') {
+ my $loc = $self->{loc} || confess "local var gone missing" ;
+ if ($line eq "\032" || $line eq '%1A' || uc $line eq "/EX") {
+ no strict 'refs';
+ push @out, &{$loc->{endaction}}($self); # like this for < 5.8.0
+ $self->func(undef);
+ $self->state('prompt');
+ } elsif ($line eq "\031" || uc $line eq "/ABORT" || uc $line eq "/QUIT") {
+ push @out, $self->msg('m10');
+ delete $loc->{lines};
+ delete $self->{loc};
+ $self->func(undef);
+ $self->state('prompt');
+ } else {
+ push @{$loc->{lines}}, length($line) > 0 ? $line : " ";
+ # i.e. it ain't and end or abort, therefore store the line
+ }
+ } else {
+ confess "Invalid state $self->{state}";
+ }
+ return @out;
+}
+sub store_startup_script
+{
+ my $self = shift;
+ my $loc = $self->{loc} || confess "local var gone missing" ;
+ my @out;
+ my $call = $loc->{call} || confess "callsign gone missing";
+ confess "lines array gone missing" unless ref $loc->{lines};
+ my $r = Script::store($call, $loc->{lines});
+ if (defined $r) {
+ if ($r) {
+ push @out, $self->msg('m19', $call, $r);
+ } else {
+ push @out, $self->msg('m20', $call);
+ }
+ } else {
+ push @out, "error opening startup script $call $!";
+ }
+ return @out;
+}
+
+# Import any commands contained in any files in import_cmd directory
+#
+# If the filename has a recogisable callsign as some delimited part
+# of it, then this is the user the command will be run as.
+#
+sub import_cmd
+{
+ # are there any to do in this directory?
+ return unless -d $cmdimportdir;
+ unless (opendir(DIR, $cmdimportdir)) {
+ LogDbg('err', "can\'t open $cmdimportdir $!");
+ return;
+ }
+
+ my @names = readdir(DIR);
+ closedir(DIR);
+ my $name;
+ foreach $name (@names) {
+ next if $name =~ /^\./;
+
+ my $s = Script->new($name, $cmdimportdir);
+ if ($s) {
+ LogDbg('DXCommand', "Run import cmd file $name");
+ my @cat = split /[^A-Za-z0-9]+/, $name;
+ my ($call) = grep {is_callsign(uc $_)} @cat;
+ $call ||= $main::mycall;
+ $call = uc $call;
+ my @out;
+
+
+ $s->inscript(0); # switch off script checks
+
+ if ($call eq $main::mycall) {
+ @out = $s->run($main::me, 1);
+ } else {
+ my $dxchan = DXChannel::get($call);
+ if ($dxchan) {
+ @out = $s->run($dxchan, 1);
+ } else {
+ my $u = DXUser->get($call);
+ if ($u) {
+ $dxchan = $main::me;
+ my $old = $dxchan->{call};
+ my $priv = $dxchan->{priv};
+ my $user = $dxchan->{user};
+ $dxchan->{call} = $call;
+ $dxchan->{priv} = $u->priv;
+ $dxchan->{user} = $u;
+ @out = $s->run($dxchan, 1);
+ $dxchan->{call} = $call;
+ $dxchan->{priv} = $priv;
+ $dxchan->{user} = $user;
+ } else {
+ LogDbg('err', "Trying to run import cmd for non-existant user $call");
+ }
+ }
+ }
+ $s->erase;
+ for (@out) {
+ LogDbg('DXCommand', "Import cmd $name/$call: $_");
+ }
+ } else {
+ LogDbg('err', "Failed to open $cmdimportdir/$name $!");
+ unlink "$cmdimportdir/$name";
+ }
+ }
+}
1;
__END__