3 # This module impliments the user facing command mode for a dx cluster
5 # Copyright (c) 1998 Dirk Koopman G1TLH
10 package DXCommandmode;
18 $last_dir_mtime = 0; # the last time one of the cmd dirs was modified
19 @cmd = undef; # a list of commands+path pairs (in alphabetical order)
21 # this is how a a connection starts, you get a hello message and the motd with
22 # possibly some other messages asking you to set various things up if you are
23 # new (or nearly new and slacking) user.
28 my $user = $self->{user};
29 my $call = $self->{call};
30 my $name = $self->{name};
31 $name = $call if !defined $name;
32 $self->{normal} = \&user_normal; # rfu for now
33 $self->{finish} = \&user_finish;
34 $self->msg('l2',$name);
35 $self->send_file($main::motd) if (-e $main::motd);
36 $self->msg('pr', $call);
37 $self->state('prompt'); # a bit of room for further expansion, passwords etc
38 $self->{priv} = 0; # set the connection priv to 0 - can be upgraded later
42 # This is the normal command prompt driver
47 my $user = $self->{user};
48 my $call = $self->{call};
51 # read in the list of valid commands, note that the commands themselves are cached elsewhere
52 scan_cmd_dirs if (!defined %cmd);
54 # strip out any nasty characters like $@%&|. and double // etc.
55 $cmd =~ s/[%\@\$&\\.`~]//og;
58 # split the command up into parts
59 my @part = split /[\/\b]+/, $cmd;
61 # the bye command - temporary probably
62 if ($part[0] =~ /^b/io) {
68 # first expand out the entry to a command, note that I will accept
69 # anything in any case with any (reasonable) seperator
74 # This is called from inside the main cluster processing loop and is used
75 # for despatching commands that are doing some long processing job
83 # finish up a user context
91 # short cut to output a prompt
97 my $call = $self->{call};
98 $self->msg('pr', $call);
102 # scan the command directories to see if things have changed
104 # If they have remake the command list
106 # There are two command directories a) the standard one and b) the local one
107 # The local one overides the standard one
118 # the persistant execution of things from the command directories
121 # This allows perl programs to call functions dynamically
123 # This has been nicked directly from the perlembed pages
126 #require Devel::Symdump;
130 sub valid_package_name {
132 $string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg;
134 #second pass only for words starting with a digit
135 $string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg;
137 #Dress it up as a real package name
139 return "DXEmbed" . $string;
142 #borrowed from Safe.pm
148 $pkg = "main::$pkg\::"; # expand to full symbol table name
149 ($stem, $leaf) = $pkg =~ m/(.*::)(\w+::)$/;
151 my $stem_symtab = *{$stem}{HASH};
153 delete $stem_symtab->{$leaf};
157 my($self, $path, $cmdname) = @_;
158 my $package = valid_package_name($cmdname);
159 my $filename = "$path/$cmdname";
160 my $mtime = -M $filename;
163 if(defined $Cache{$package}{mtime} && $Cache{$package}{mtime } <= $mtime) {
164 #we have compiled this subroutine already,
165 #it has not been updated on disk, nothing left to do
166 #print STDERR "already compiled $package->handler\n";
170 open FH, $filename or die "open '$filename' $!";
175 #wrap the code into a subroutine inside our unique package
176 my $eval = qq{package $package; sub handler { $sub; }};
178 #hide our variables within this block
179 my($filename,$mtime,$package,$sub);
183 $self->send("Eval err $@ on $package");
184 delete_package($package);
188 #cache it unless we're cleaning out each time
189 $Cache{$package}{mtime} = $mtime;
192 @r = eval {$package->handler;};
194 $self->send("Eval err $@ on cached $package");
195 delete_package($package);
199 #take a look if you want
200 #print Devel::Symdump->rnew($package)->as_string, $/;