spider/perl/DXCommandmode.pm

199 lines
4.4 KiB
Perl
Raw Normal View History

#!/usr/bin/perl
#
# This module impliments the user facing command mode for a dx cluster
#
# Copyright (c) 1998 Dirk Koopman G1TLH
#
# $Id$
#
package DXCommandmode;
use DXUtil;
use DXChannel;
use DXUser;
use DXM;
use DXVars;
$last_dir_mtime = 0; # the last time one of the cmd dirs was modified
@cmd = undef; # a list of commands+path pairs (in alphabetical order)
# this is how a a connection starts, you get a hello message and the motd with
# possibly some other messages asking you to set various things up if you are
# new (or nearly new and slacking) user.
sub user_start
{
my $self = shift;
my $user = $self->{user};
my $call = $self->{call};
my $name = $self->{name};
$name = $call if !defined $name;
$self->{normal} = \&user_normal; # rfu for now
$self->{finish} = \&user_finish;
$self->msg('l2',$name);
$self->send_file($main::motd) if (-e $main::motd);
$self->msg('pr', $call);
$self->{state} = 10; # a bit of room for further expansion, passwords etc
$self->{priv} = 0; # set the connection priv to 0 - can be upgraded later
}
#
# This is the normal command prompt driver
#
sub user_normal
{
my $self = shift;
my $user = $self->{user};
my $call = $self->{call};
my $cmd = shift;
# read in the list of valid commands, note that the commands themselves are cached elsewhere
scan_cmd_dirs if (!defined %cmd);
# strip out any nasty characters like $@%&|. and double // etc.
$cmd =~ s/[\%\@\$\&\|\.\`\~]//og;
$cmd =~ s|//|/|og;
# split the command up into parts
my @parts = split |[/\b]+|, $cmd;
# first expand out the entry to a command, note that I will accept
# anything in any case with any (reasonable) seperator
$self->prompt();
}
#
# This is called from inside the main cluster processing loop and is used
# for despatching commands that are doing some long processing job
#
sub user_process
{
}
#
# finish up a user context
#
sub user_finish
{
}
#
# short cut to output a prompt
#
sub prompt
{
my $self = shift;
my $call = $self->{call};
$self->msg('pr', $call);
}
#
# scan the command directories to see if things have changed
#
# If they have remake the command list
#
# There are two command directories a) the standard one and b) the local one
# The local one overides the standard one
#
sub scan_cmd_dirs
{
my $self = shift;
}
#
# the persistant execution of things from the command directories
#
#
# This allows perl programs to call functions dynamically
#
# This has been nicked directly from the perlembed pages
#
#require Devel::Symdump;
use strict;
use vars '%Cache';
sub valid_package_name {
my($string) = @_;
$string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg;
#second pass only for words starting with a digit
$string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg;
#Dress it up as a real package name
$string =~ s|/|::|g;
return "DXEmbed" . $string;
}
#borrowed from Safe.pm
sub delete_package {
my $pkg = shift;
my ($stem, $leaf);
no strict 'refs';
$pkg = "main::$pkg\::"; # expand to full symbol table name
($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/;
my $stem_symtab = *{$stem}{HASH};
delete $stem_symtab->{$leaf};
}
sub eval_file {
my($self, $path, $cmdname) = @_;
my $package = valid_package_name($cmdname);
my $filename = "$path/$cmdname";
my $mtime = -m $filename;
my @r;
if(defined $Cache{$package}{mtime} && $Cache{$package}{mtime } <= $mtime) {
#we have compiled this subroutine already,
#it has not been updated on disk, nothing left to do
#print STDERR "already compiled $package->handler\n";
;
} else {
local *FH;
open FH, $filename or die "open '$filename' $!";
local($/) = undef;
my $sub = <FH>;
close FH;
#wrap the code into a subroutine inside our unique package
my $eval = qq{package $package; sub handler { $sub; }};
{
#hide our variables within this block
my($filename,$mtime,$package,$sub);
eval $eval;
}
if ($@) {
$self->send("Eval err $@ on $package");
delete_package($package);
return undef;
}
#cache it unless we're cleaning out each time
$Cache{$package}{mtime} = $mtime unless $delete;
}
@r = eval {$package->handler;};
if ($@) {
$self->send("Eval err $@ on cached $package");
delete_package($package);
return undef;
}
#take a look if you want
#print Devel::Symdump->rnew($package)->as_string, $/;
return @r;
}
1;
__END__