mirror of
git://scm.dxcluster.org/scm/spider
synced 2024-09-22 00:07:10 +00:00
199 lines
4.4 KiB
Perl
199 lines
4.4 KiB
Perl
|
#!/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__
|