HTML-EP-Explorer

 view release on metacpan or  search on metacpan

lib/HTML/EP/Explorer.pm  view on Meta::CPAN

# -*- perl -*-
#
#   HTML::EP::Explorer - A Perl package for browsing filesystems and
#       executing actions on files.
#
#
#   This module is
#
#           Copyright (C) 1999     Jochen Wiedmann
#                                  Am Eisteich 9
#                                  72555 Metzingen
#                                  Germany
#
#                                  Email: joe@ispsoft.de
#
#   All Rights Reserved.
#
#   You may distribute under the terms of either the GNU General Public
#   License or the Artistic License, as specified in the Perl README file.
#
#   $Id: Explorer.pm,v 1.2 1999/11/04 12:24:10 joe Exp $
#

use strict;

use Cwd ();
use File::Spec ();
use HTML::EP ();
use HTML::EP::Locale ();
use HTML::EP::Session ();


package HTML::EP::Explorer;

@HTML::EP::Explorer::ISA = qw(HTML::EP::Session HTML::EP::Locale HTML::EP);
$HTML::EP::Explorer::VERSION = '0.1006';

sub init {
    my $self = shift;
    $self->HTML::EP::Session::init(@_);
    $self->HTML::EP::Locale::init(@_);
}

sub _ep_explorer_init {
    my $self = shift; my $attr = shift;
    return '' if $self->{_ep_explorer_init_done};
    $self->print("_ep_explorer_init: attr = (", join(",", %$attr), ")\n")
	if $self->{'debug'};
    $self->{_ep_explorer_init_done} = 1;
    my $cgi = $self->{'cgi'};
    $attr->{'class'} ||= "HTML::EP::Session::Cookie";
    $attr->{'id'} ||= "explorer-session";
    $attr->{'path'} ||= "/";
    $attr->{'expires'} ||= "+10y";
    eval { $self->_ep_session($attr) };
    my $session = $self->{$attr->{'var'} || 'session'};
    if ($self->{debug}) {
	require Data::Dumper;
	$self->print("Session = ", Data::Dumper::Dumper($session), "\n");
    }
    if (!$attr->{'noprefs'} and
	($@  or  !exists($session->{'prefs'}))) {
	# First time run, open the prefs page.
	my $prefs = $attr->{'prefs_page'} || "prefs.ep";
	my $return_to = $attr->{'return_to'} || $self->{'env'}->{'PATH_INFO'};
	$self->print("_ep_explorer_init: Redirecting to $prefs, returning to $return_to\n")
	    if $self->{'debug'};
	$cgi->param('return_to', $return_to);
	$self->{'_ep_output'} .= $self->_ep_include({file => $prefs});
	$self->_ep_exit({});
    }
    '';
}

sub InitialConfig {
    my $self = shift;
    { 'actions' => [],
      'filetypes' => [
        { 'name' => $self->{'_ep_language'} eq 'de' ?
	  'Alle Dateien (*)' : 'All Files (*)',
	  'icon' => '/icons/unknown.gif',
	  're' => '.*'
	}],
      'directories' => [
	{ 'name' => 'Root-Directory (/)',
	  'dir' => '/'
	}]
    }
}


sub ReadArray {
    my $self = shift;  my $prefix = shift;
    my $cgi = $self->{'cgi'};
    my %hash;
    foreach my $key ($cgi->param()) {
	next unless $key =~ /^$prefix(.*)/;
	$self->print("ReadArray: Found key $key, saving as $1 (",
		     join(",", $cgi->param($key)), "\n") if $self->{'debug'};
	$hash{$1} = [$cgi->param($key)];
    }
    my @array;
    while (@{$hash{'name'}}) {
	my %h;
	while (my($var, $val) = each %hash) {
	    $h{$var} = shift @$val;
	}
	push(@array, \%h) if $h{'name'};
    }
    \@array;
}


sub ReadDirectories {
    my $dirs = shift()->ReadArray('explorer_directory_');
    my $pwd;
    foreach my $dir (@$dirs) {
	# Don't save the name, that the user gave us. Save the physical
	# filesystem path, so that we can later compare it to paths
	# requested by other users, if "Allow access to other directories"
	# is off.
	$pwd = Cwd::cwd() unless $pwd;
	chdir($dir->{'dir'}) or die "Failed to change directory to $dir: $!";
	$dir->{'dir'} = Cwd::cwd();
    }
    chdir $pwd if $pwd;
    $dirs;
}


sub ReadConfig {
    my $self = shift; my $config = shift;
    my $cgi = $self->{'cgi'};

    foreach my $var ($cgi->param()) {
	next unless $var =~ /^explorer_config_(.*)/;
	my $v = $1;
	$config->{$v} = $cgi->param($var);
    }

    $config->{'actions'} = $self->ReadArray('explorer_action_');
    $config->{'status_actions'} = $self->ReadArray('explorer_status_action_');
    $config->{'filetypes'} = $self->ReadArray('explorer_filetype_');
    $config->{'directories'} = $self->ReadDirectories();
    $config;
}


sub _ep_explorer_config {
    my $self = shift;  my $attr = shift;
    my $debug = $self->{'debug'};
    my $cgi = $self->{'cgi'};
    my $file = $attr->{'file'} || "config.pm";
    $self->{'config'} = eval { require $file } || $self->InitialConfig();
    if ($attr->{'maysafe'} && $cgi->param('save')) {
	$self->print("_ep_explorer_config: Saving.\n") if $debug;
	$self->{'config'} = $self->ReadConfig($self->{'config'});
	require Data::Dumper;
	my $fh = Symbol::gensym();
	my $dump = Data::Dumper->new([$self->{'config'}])->Indent(1)->Terse(1);
	$self->print("_ep_explorer_config: Got\n", $dump->Dump(), "\n")
	    if $debug;
	(open($fh, ">$file") and (print $fh $dump->Dump()) and close($fh))
	    or die "Failed to create $file: $!";
    }
    $self->{'actions'} = $self->{'config'}->{'actions'};
    $self->{'status_actions'} = $self->{'config'}->{'status_actions'};
    $self->{'directories'} = $self->{'config'}->{'directories'};
    $self->{'filetypes'} = $self->{'config'}->{'filetypes'};
    $self->{'num_directories'} = @{$self->{'directories'}};
    '';
}

sub ReadPrefs {
    my $self = shift; my $prefs = shift;
    my $cgi = $self->{'cgi'};
    foreach my $var ($cgi->param()) {
	next unless $var =~ /^explorer_prefs_(.*)/;
	my $vr = $1;
	my $val = $cgi->param($var);
	$prefs->{$vr} = $val;
    }
    $prefs;
}

sub _ep_explorer_prefs {
    my $self = shift;  my $attr = shift;
    my $debug = $self->{'debug'};
    $attr->{'noprefs'} = 1;
    $self->_ep_explorer_init($attr);
    my $session = $self->{$attr->{'var'} ||= 'session'};
    my $cgi = $self->{'cgi'};
    my $return;
    if (($return = $cgi->param('save_and_return'))  ||
	 $cgi->param('save')) {
	$self->print("_ep_explorer_prefs: Saving.\n") if $debug;
	$session->{'prefs'} = $self->ReadPrefs($session->{'prefs'});
	if ($debug) {
	    require Data::Dumper;
	    $self->print("_ep_explorer_save: Got\n",
			 Data::Dumper->new([$session->{'prefs'}])
			     ->Indent(1)->Terse(1)->Dump(), "\n");
	}
	$attr->{'locked'} = 1;
	$self->_ep_session_store($attr);
    }
    if ($return  and  (my $return_to = $cgi->param('return_to'))) {
	$self->print("Returning to $return_to\n") if $debug;
	$self->{'_ep_output'} .=
	    $self->_ep_include({'file' => $return_to});
	$self->print("Done including $return_to\n") if $debug;
	$self->_ep_exit({});
    }
    '';
}

sub _ep_explorer_basedir {
    my $self = shift; my $attr = shift;
    return if $self->{'basedir'};
    my $cgi = $self->{'cgi'};
    my $session = $self->{'session'};
    my $debug = $self->{'debug'};
    my $basedir = $cgi->param('basedir') || $session->{'basedir'}
        || $attr->{'basedir'} || $self->{'directories'}->[0]
	|| $ENV{'DOCUMENT_ROOT'};
    $basedir = HTML::EP::Explorer::Dir->new($basedir)->{'dir'};
    chdir($basedir)
	or die "Failed to change directory to $basedir: $!";
    $basedir = Cwd::cwd();
    if (!$session->{'basedir'} or $session->{'basedir'} ne $basedir) {
	$self->{'modified'} = 1;
	$session->{'basedir'} = $basedir;
    }
    foreach my $dir (@{$self->{'directories'}}) {
	$self->print("Checking whether $dir->{'dir'} is $basedir.\n")
	    if $debug;
	if ($dir->{'dir'} eq $basedir) {
	    $self->{'in_top_dir'} = 1;
	    $self->{'in_base_dir'} = $dir;
	    $self->{'display_dir'} = "/";
	    $self->print("Yes, it is.\n") if $debug;
	    last;
	}
    }
    if (!$self->{'in_top_dir'}) {
	$self->{'in_top_dir'} = ($basedir eq File::Spec->rootdir());
	foreach my $dir (@{$self->{'directories'}}) {
	    $self->print("Checking whether $basedir is below $dir->{'dir'}.\n")
		if $debug;
	    if ($basedir =~ /^\Q$dir->{'dir'}\E(\/.*)$/) {
		$self->{'in_base_dir'} = $dir;
		$self->{'display_dir'} = $1;
		$self->print("Yes, it is.\n") if $debug;
		last;
	    }
	}
	if (!$self->{'in_base_dir'}) {
	    die "Directory $basedir is outside of the permitted area."
		if $self->{'config'}->{'dirs_restricted'};
	    $self->{'display_dir'} = $basedir;
	}

lib/HTML/EP/Explorer.pm  view on Meta::CPAN

  Directory for installing HTML files?

If you requested installing the HTML files, you have to choose a
location. By default the program suggests

  F</home/httpd/html/explorer>

which is fine on a Red Hat Linux box. Users of other systems will modify
this to some path below your your web servers root directory.

=item *

  Directory for installing CGI binaries?

If HTML files are installed, you must install some CGI binaries too.
This question allows you to select an installation path, by default
the subdirectory F<cgi> within the directory for installing HTML
files.

Note that you need to configure the httpd so that it treats this
directory as a CGI directory. For example Apache users may add the
following to F<srm.conf>:

  ScriptAlias /home/httpd/html/explorer/cgi

=item *

  UID the httpd is running as?

The explorer scripts need write access to some files, in particular the
configuration created by the site administrator. To enable write access,
these files are owned by the Unix user you enter here, by default the
user I<nobody>.

In most cases this will be the same user that your httpd is running as,
but it might be different, for example if your Apache is using the
suexec feature. Contact your webmaster for details.

=back

If you didn't already do so, configure your web server for feeding
files with extension I<.ep> into the CGI binary I<ep.cgi> or into
the mod_perl module I<Apache::EP>. The README of HTML::EP tells you
how. See L<HTML::EP(3)>.

That's it! Assuming the directory F</home/httpd/html/explorer> is
reachable as F</explorer> in your browser, point it to

  http://localhost/explorer/

You should now see a directory listing. If so, proceed to
L<CONFIGURATION>.


=head1 CONFIGURATION

Besides the questions you already answered when installing the explorer,
the system is configurable via any Web browser. Assuming the Explorer
is reachable below http://localhost/explorer/, Point your browser to

  http://localhost/explorer/admin/prefs.ep


=head2 Security considerations

The first thing you probably notice is that you need not supply a password
for accessing this page. This should be changed. A typical configuration
requests that only the user root can visit this page. For example, with
Apache, you could insert the following into your httpd.conf:

  <Location /explorer/admin>
    AuthUserFile /etc/passwd
    AuthName "Explorer Administration"
    AuthTyoe basic
    require user root
  </Location>

(Of course one can discuss whether this is a secure thing, as it could
allow deducing the root password by using some sort of crack mechanism.
On the systems where I use it there ary typically lots of other
possibilities for doing the same ... :-)


=head2 E-Mail address of the administrator

From time to time the system will use this address for sending emails
to you.


=head2 Actions

This is the explorers heart. Actions are merely shell scripts, to which
the files will be fed, that your users have selected.

To create an action, fill out the following fields:

=over

=item Name

This is some short text that your users will see on the web frontend.
For example, it could be I<Printing on the LaserJet>.

=item Icon

This (optional) entry means that the explorer will use the named image
file to display it instead of the name above. For example, this could
be a small gif with the word I<LaserJet> on it.

You must supply an URL here. If you are using Apache, then a lot of
nice icons are accessible in your httpd's icons directory. See the
README file.

=item Script

This is a shell command that the explorer will execute for performing
the action. The command may use the variables I<file> (the filename)
or I<user> (the users name). For example, one could use

  lpr -Plaserjet -U $user $file

lib/HTML/EP/Explorer.pm  view on Meta::CPAN

Word, then you will by default see only files with extension I<.doc>.

A file type can be created by filling out the following fields:

=over

=item Name

This is a description of the file type, that your users will see. For
example, it could be

  PostScript files (*.ps)

or

  All Files (*)

=item Icon

This is an (optional) icon to use for showing the file type. For
example, it could be

  /icons/ps.gif

or

  /icons/unknown.gif

(Note that these are indeed meaningful settings with any default
Apache installation, because Apache has a lot of icons included.
See the file icons/README from the Apache distribution.)

=item Regular Expression

This is a Perl Regular Expression which files must match in order
to be of this type. For example it could be

  \.ps$
  \.pdf$
  \.(?:ps|pdf)$
  .*

for PostScript files, PDF files, PostScript or PDF files or all files.
See L<perlre(3)> for details on Perl's regular expressions.

=back


=head1 MODIFYING THE EXPLORER

When modifying the explorer, you should know about the following
methods:


=head2 Initializing the Explorer

Probably any HTML page using the explorer system should contain
the following:

  <ep-package name=HTML::EP::Explorer accept="de,en">
  <ep-explorer-init noprefs=0>

The I<_ep_explorer_init> method is initializing the users cookie.
First it verifies, whether the user already has an explorer cookie
set. If not, the user will be redirected to the I<prefs.ep> page,
unless the attribute I<noprefs> is set. This page will allow him
to fix his personal settings and return to the calling page.

The explorer class is a subclass of both I<HTML::EP::Locale> and
I<HTML::EP::Session>. That means that the locale settings are
still valid in the I<ep-package> call (in particular the I<accept>
attribute that tells this page is ready for either german, aka de,
or english). Likewise the attributes of I<ep-session> are valid
in the I<ep-explorer-init> call. L<HTML::EP(3)>.
L<HTML::EP::Session(3)>.


=head2 Reading and/or writing the admin settings

Within F<admin/prefs.ep> and some other pages, you find the following
call:

  <ep-explorer-config file="config.pm" maysafe=0>

which read the admin settings from an external file, by default
F<config.pm>. The settings will instead be read from the CGI
input and saved into the same file, if the CGI variable I<save>
and the attribute I<maysafe> are true. (The latter should happen
within the F<amdin> dirctory only.)

The method will set the following EP variables:

=over

=item $config$

The config hash ref, as read from the file F<config.pm>.

=item $actions$

The list of actions. Shortcut for $config->actions$.
An action looks like

  { 'name' => 'Print to lp',
    'icon' => '/icons/lp.gif', # May be undef
    'script' => 'lpr -Plp -U $user $file'
  }

=item $directories$

The list of directories. Shortcut for
B<$self-E<gt>{'config'}-E<gt>{'directories'}>. A directory looks like

  { 'name' => 'Root directory',
    'dir' => '/'
  }

=item $filetypes$

The list of file types. Shortcut for
B<$self-E<gt>{'config'}-E<gt>{'filetypes'}>. A file type looks like

  { 'name' => 'PostScript files (*.ps)'
    'icon' => '/icons/ps.gif', # May be undef
    're' => '\.ps$'
  }

=item $num_directories$

The number of elements in B<$self-E<gt>{'directories'}>. May be 0.

=back


=head2 Reading and/or writing the users settings

The users settings can be read and/or written by calling

  <ep-explorer-prefs>

This will call I<_ep_explorer_init> internally, by setting the
I<noprefs> attribute to true. If either of the CGI variables
I<save> or I<save_and_return> is set, it will read the users
new settings from the CGI environment by running
B<$self-E<gt>ReadPrefs> and store the session (that is, return
a cookie) by calling I<ep-session-store>.

If the current oage is called from another page (that is, the
CGI variable I<return_to> is set to the calling page) and the
CGI variable I<save_and_return> is set, then the calling page
is included with I<ep-include>.


=head2 Setting the Explorers current directory

The method

  <ep-explorer-basedir>

will read the users current directory from the session or CGI
variable I<basedir>. The current directory will be compared
against the list of initial directories and the following
EP variables will be set:

=over

=item $basedir$

The selected current directory. If this is different from
B<$session->basedir> then the latter will be modified and
B<$modified$> will be set.

=item $in_top_dir$

True, if the current directory is one of the initial directories
or in F</>, False otherwise.

=item $in_base_dir$

If the current directory is below one of the initial directories,
then this variable will contain the associated element from the
directory list. That is $in_base_dir->name$ is set to the name
of this initial directory and $in_base_dir->dir$ the path.

Otherwise the variable is set to undef. If this is the case and
the administrator has set "Allow access outside initial directories"
to True, then a system error is triggered.

=item $display_dir$

If $in_base_dir$ is set, then this variable is set to the current
directories path, relative to the directory from $in_base_dir$.
For example, if you are in F</usr/local/bin> and the initial
directory is F</usr/local>, then the display directory is F</bin>.

=back


=head2 Setting the sorting mode

The method



( run in 1.124 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )