package HTML::WebMake::CGI::CGIBase; use CGI qw/:standard/; use strict; use HTML::Entities; use HTML::WebMake::Main; use HTML::WebMake::Util; use HTML::WebMake::CGI::RWMetaTable; use File::Basename; use vars qw{ @ISA $BASIC_TMPL_TOP $BASIC_TMPL_REST }; @ISA = qw(); ########################################################################### $BASIC_TMPL_TOP = q{ WebMake: __PAGE_TITLE__

WebMake: __PAGE_HEADER__

}; $BASIC_TMPL_REST = q{ __ERRORS__ __MODULE_OUTPUT__ }; ########################################################################### sub new { my $class = shift; $class = ref($class) || $class; my $self = { 'q', shift, 'file_base', undef, 'template', $BASIC_TMPL_TOP.$BASIC_TMPL_REST, 'info_msgs', '', 'msgs', '' }; $self->{metatable} = new HTML::WebMake::CGI::RWMetaTable (); $self->{cvs_supported} = 0; if (defined $ENV{'CVSROOT'}) { $self->{cvs_supported} = 1; } $self->{cvs} = new HTML::WebMake::CGI::CVS ($self); bless ($self, $class); $self; } sub set_file_base { my ($self, $base) = @_; $self->{file_base} = $base; if (!-d $base) { die ("WebMakeCGI: FILE_BASE setting is invalid: ". "\"$base\" is not a directory.\n"); } # if we have a CVS dir in the file_base, the user has set this # area up with a "cvs login" and "cvs checkout". Good call. if (-f $base."/CVS/Root") { $self->{cvs_supported} = 1; } } ########################################################################### sub txt2html { my $self = shift; my $txt = join ('',@_); $txt =~ s/&/&/gs; $txt =~ s//>/gs; $txt =~ s/\n/
\n/gs; $txt; } sub warn { my ($self, $err) = @_; chomp $err; warn "WebMakeCGI: $err\n"; $self->{msgs} .= "Warning: $err
\n"; } sub info { my ($self, $err) = @_; $self->{info_msgs} .= "Note: $err
\n"; } sub is_media { my ($self, $filename) = @_; return 0 if (!defined $filename); if ($filename =~ /\.(?:gif|jp[eg]+|png|mov|avi|qt|mp[eg]+|ra|ram|gz|Z|zip)$/i || $filename =~ /\.(?:class|jar|cab|db|hist|sys|exe|com|mp3|prc|pdb|dat)$/i) { return 1; } else { return 0; } } # --------------------------------------------------------------------------- sub run { my ($self) = @_; my $q = $self->{q}; $|++; if (!$q->param ('dump')) { print "Content-Type: text/html\r\n\r\n"; } $self->{msgs} = ''; $self->{info_msgs} = ''; my $form = ''; $self->{filename} = ''; if (!is_authorised ($q)) { $self->warn ("This site can only be edited by authenticated users."); goto end; } $self->{wmkfile} = &mksafepath($q->param('wmkf')); # this may be overridden in Site.pm, the module for editing .wmk files # check to see if CVS is available in this subdir my $base = File::Basename::dirname ($self->{wmkfile}); if (-d $self->{file_base}."/".$base."/CVS") { $self->{cvs_supported} = 1; } $self->{cvsadd} = &mksafepathlist($q->param('cvsadd')); $self->{cvsaddbin} = &mksafepathlist($q->param('cvsaddbin')); $self->{cvsrm} = &mksafepathlist($q->param('cvsrm')); $self->{cvsrmdir} = &mksafepathlist($q->param('cvsrmdir')); # if we have a dirprefix parameter, add it to the filename. if ($q->param('dirprefix')) { $self->{filename} = $self->makepath ($q->param('dirprefix'), $q->param('f')); $q->param('dirprefix', ''); $q->param('f', $self->{filename}); } else { $self->{filename} = &mksafepath($q->param('f')); } if (!defined $self->{wmkfile} && !$self->{no_wmkf_needed}) { $self->warn ("No .wmk file specified! Please use the 'wmkf' parameter."); goto end; } if (!$self->{no_filename_needed} && (!defined $self->{filename} || $self->{filename} eq '')) { $self->warn ("No filename provided.\n"); } else { $form = $self->subrun ($q); } end: if (!$q->param ('dump')) { $self->write_html_main ($form); } } # --------------------------------------------------------------------------- sub std_cgi_hidden_items { my ($self, $q) = @_; $self->{cvsadd} ||= ''; $self->{cvsaddbin} ||= ''; $self->{cvsrm} ||= ''; $self->{cvsrmdir} ||= ''; $self->{wmkfile} ||= ''; return $q->hidden(-name=>'wmkf',-value=>$self->{wmkfile}) . $q->hidden(-name=>'cvsadd',-value=>$self->{cvsadd}) . $q->hidden(-name=>'cvsaddbin',-value=>$self->{cvsaddbin}) . $q->hidden(-name=>'cvsrm',-value=>$self->{cvsrm}) . $q->hidden(-name=>'cvsrmdir',-value=>$self->{cvsrmdir}); } # --------------------------------------------------------------------------- sub std_cgi_hidden_items_as_str { my ($self, $q) = @_; $self->{cvsadd} ||= ''; $self->{cvsaddbin} ||= ''; $self->{cvsrm} ||= ''; $self->{cvsrmdir} ||= ''; $self->{wmkfile} ||= ''; return 'wmkf='.$q->escape ($self->{wmkfile}) . '&' . 'cvsadd='.$q->escape ($self->{cvsadd}) . '&' . 'cvsaddbin='.$q->escape ($self->{cvsaddbin}) . '&' . 'cvsrm='.$q->escape ($self->{cvsrm}) . '&' . 'cvsrmdir='.$q->escape ($self->{cvsrmdir}); } # --------------------------------------------------------------------------- sub write_html_main { my ($self, $form) = @_; my $q = $self->{q}; my $txt = $self->{template}; my $user = $q->remote_user(); $user ||= '(nobody)'; my $wmkf = $self->{wmkfile}; $wmkf ||= '(none)'; my $bread = $self->get_breadcrumbs(); if (!$self->{cvs_supported}) { $txt =~ s/.*<\/CVSONLY>//gs; } $txt =~ s/__PAGE_TITLE__/$self->{page_title}/ge; $txt =~ s/__PAGE_HEADER__/$self->{page_header}/ge; $txt =~ s/__BREADCRUMBS__/$bread/gs; $txt =~ s/__ERRORS__/$self->{msgs} $self->{info_msgs}/gs; $txt =~ s/__MODULE_OUTPUT__/${form}/gs; $txt =~ s/__FNAME__/$self->{filename}/gs; $txt =~ s/__USERNAME__/${user}/gs; $txt =~ s/__WMKF__/${wmkf}/gs; $txt =~ s/__WMVER__/${HTML::WebMake::Main::VERSION}/gs; $txt =~ s{__REINVOKE__(\S+?)__}{ $self->reinvoke_with_param(0,$1); }ge; $txt =~ s{__REINVOKEALL__(\S+?)__}{ $self->reinvoke_with_param(1,$1); }ge; print $txt; } # --------------------------------------------------------------------------- sub reinvoke_with_param { my ($self, $keepexisting, $params) = @_; my $q = $self->{q}; my $href = $q->url (-relative=>1, -path=>1) . '?' . $params; my $str; if ($keepexisting) { # keep all CGI parameters (except the ones overridden by new settings) $str = $q->query_string (); } else { # just keep the essentials. namely: the name of the .wmk file, # and cvs operations pending $str = $self->std_cgi_hidden_items_as_str ($q); } my %pkeys = (); foreach my $pkey (split (/[\&\;]/, $params)) { $pkey =~ s/=.*$//; $pkeys{$pkey} = 1; } foreach my $elem (split (/\&/, $str)) { if ($elem =~ /^(.*?)=/) { if (defined $pkeys{$1}) { next; } } $href .= '&'.$elem; } $href; } # --------------------------------------------------------------------------- sub mydirname { my ($self) = @_; return File::Basename::dirname ($self->{filename}); } sub mydirurl { my ($self) = @_; return $self->{q}->escape ($self->mydirname()); } # --------------------------------------------------------------------------- sub makepath { my ($self, $dir, $path) = @_; if (!defined($dir) || $dir eq '' || $dir eq '.') { # ignore it } else { $path = $dir.'/'.$path; } return mksafepath ($path); } ########################################################################### sub cvs_add { my ($self, $fname) = @_; return if (!$self->{cvs_supported}); if ($self->is_media ($fname)) { if ($self->{cvsaddbin}) { $self->{cvsaddbin} .= "|".$fname; } else { $self->{cvsaddbin} = $fname; } } else { if ($self->{cvsadd}) { $self->{cvsadd} .= "|".$fname; } else { $self->{cvsadd} = $fname; } } } sub cvs_delete { my ($self, $fname) = @_; return if (!$self->{cvs_supported}); if (-d $self->{file_base}.$fname) { if ($self->{cvsrmdir}) { $self->{cvsrmdir} .= "|".$fname; } else { $self->{cvsrmdir} = $fname; } } else { if ($self->{cvsrm}) { $self->{cvsrm} .= "|".$fname; } else { $self->{cvsrm} = $fname; } } } ########################################################################### sub read_wmk_file { my ($self, $file) = @_; my $dir = $self->mydirname(); $self->{webmake} = new HTML::WebMake::Main ( { 'base_dir' => $self->{file_base}.'/'.$dir } ); my $cgi = $self->{webmake}->cgi_parse_file ($self->{file_base}.'/'.$file); if (!defined $cgi) { $self->warn ("Failed to parse WebMake file \"$file\""); return 0; } $self->{fulltext} = $cgi->{fulltext}; $self->{items} = $cgi->{items}; 1; } ########################################################################### sub get_breadcrumbs { my ($self) = @_; my $q = $self->{q}; # [edit] Top > main.wmk > contents: data/ > cv.txt [view] $self->{cvsadd} ||= ''; $self->{cvsaddbin} ||= ''; $self->{cvsrm} ||= ''; $self->{cvsrmdir} ||= ''; my $href = $q->url (-relative=>1, -path=>1).'?' . 'cvsadd='.$q->escape ($self->{cvsadd}) . '&' . 'cvsaddbin='.$q->escape ($self->{cvsaddbin}) . '&' . 'cvsrm='.$q->escape ($self->{cvsrm}) . '&' . 'cvsrmdir='.$q->escape ($self->{cvsrmdir}); my $txt = qq{ Top }; #" if (defined $self->{wmkfile}) { $txt .= qq{ » $self->{wmkfile} }; #" } if (defined $self->{task_breadcrumb}) { $txt .= qq{ » $self->{task_breadcrumb} }; #" } $txt .= qq{
}; #" return $txt; } ########################################################################### sub mksafe { local($_) = shift; if (!defined $_) { return undef; } s/\0/_/gs; # strip NULs s/[^-=_+\[\]\@\#,.\/:\~%^\(\)\{\}A-Za-z0-9 ]/_/gs; $_; } sub mksafepath { local($_) = shift; if (!defined $_) { return undef; } $_ = mksafe($_); s/[^-_+\@,.\/\#\=:%A-Za-z0-9 ]/_/gs; s,^\/+,,gs; # //foo -> foo s,\/\/+,/,gs; # foo//bar -> foo/bar 1 while s,^\.\/+,,gs; # strip ./././foo s,[^/]+/+\.\./+,,gs; # strip ..s s,\.\./+,,gs; # strip any leftover ..s s,^\.\.$,.,gs; # ".." = "." $_; } sub mksafepathlist { local($_) = shift; if (!defined $_) { return undef; } my @new = (); foreach my $item (split (/\|/, $_)) { next if ($item eq ''); push (@new, mksafepath ($item)); } return join ('|', @new); } sub is_authorised { my ($q) = @_; my $auth = $q->auth_type(); my $user = $q->remote_user(); if (defined $auth && defined $user) { return 1; } CORE::warn "unauthorised access from ".$q->remote_host()."\n"; return 0; } ########################################################################### sub subst_template { my ($self, $tmpl, $vars) = @_; foreach my $key (keys %{$vars}) { $tmpl =~ s/\{${key}\}/$vars->{$key}/gs; $tmpl =~ s/__${key}__/$vars->{$key}/gs; } return $tmpl; } ########################################################################### 1;