#!/opt/bin/perl require 5; use strict; =head1 copyright Genesis Web Authoring System Copyright 1997-2001 by Zoltan Milosevic. Please adhere to the copyright notice and conditions of use, described in the attached help file and hosted at the URL below. For the latest version and help files, visit: http://www.xav.com/scripts/genesis/ This search engine is managed from the web; the default username/password is webmaster/658uwantit: http://www.teachabletech.com/genesis/index.cgi =cut use vars qw( $VERSION %params ); $VERSION = '2.1.0.0009'; my $all_code = <<'END_OF_CODE'; #changed 0008 $ENV{'PATH'} = &query_env('PATH'); foreach ('IFS','CDPATH','ENV','BASH_ENV') { delete $ENV{$_} if (defined($ENV{$_})); } use vars qw( %security $auth %const @lang_strings %STATE @user_attribs_ro @user_attribs_rw @user_attribs_internal ); @user_attribs_internal = ('_BUILD', '_VERSION', 'Username', 'LastLogin', 'LastLoginFrom', 'AccountCreated'); @user_attribs_ro = ('Quota', 'Author:UseQuota', 'Author:UserFolder', 'Author:UserURL', 'allow_cgi'); @user_attribs_rw = ('shell', 'full_name', 'email_address', 'DiskUse', 'Warn', 'ShowTips', 'ShowDirSize', 'Sort', 'multi_upload_count', 'Rows', 'Cols', 'TextWrap', 'TextUpload', 'Concise', 'FontSize', 'Sound'); #changed 0008 - mac compat: sub onetru_path(@); sub onetru_path(@) { my $fullpath = join('/',@_); if (($^O) and ($^O =~ m!mac!i)) { $fullpath =~ s!:!/!sg; } elsif (($^O) and ($^O =~ m!(win|dos)!i)) { $fullpath =~ s!\\!/!sg; } $fullpath =~ s!/+!/!sg; return $fullpath; } sub native_path($); sub native_path($) { my $fullpath = defined($_[0]) ? $_[0] : ''; if (($^O) and ($^O =~ m!mac!i)) { $fullpath =~ s!/!:!sg; } elsif (($^O) and ($^O =~ m!(win|dos)!i)) { $fullpath =~ s!/!\\!sg; } return $fullpath; } #end changes my $err_msg = ''; Err: { my $script_name = &query_env( 'SCRIPT_NAME', 'index.cgi' ); my @paths = (); ($err_msg, @paths) = &where_tf(); next Err if ($err_msg); unless (chdir($paths[1])) { $err_msg = "unable to chdir to '$paths[1]' - $!"; next Err; } %const = ( 'help file' => 'http://www.xav.com/scripts/genesis/help/', 'full_script_url' => $paths[3], 'super user' => 'webmaster', 'script_url' => $script_name, 'admin_url' => "$script_name?", 'cwd_line' => '', 'crypt_pass_line' => '', 'http' => "$paths[4]/web_pages/", 'image url' => "$paths[4]/web_pages/images/", ); $const{'path'} = "$paths[1]/web_pages"; $const{'preferences folder'} = "$paths[1]/script_data"; $const{'event log'} = $const{'preferences folder'} . '/event.log'; # Pull in the language settings: my $file = $const{'preferences folder'} . "/templates/english/strings.txt"; @lang_strings = (''); # Initialize with a null element unless (open(FILE, "<$file")) { $err_msg = "unable to read from file '$file' - $!"; next Err; } binmode(FILE); while () { chomp; push(@lang_strings, $_); } close(FILE); if ($lang_strings[1] =~ m!^VERSION (\d+\.\d+\.\d+\.\d+)$!) { my $strings_version = $1; if ($strings_version ne $VERSION) { $err_msg = "strings '$file' is version $strings_version, but this script is version $VERSION. Versions much match"; next Err; } } %security = ( 'Base Folder' => $const{'path'}, 'Base URL' => $const{'http'}, 'Images URL' => $const{'image url'}, 'Mail Server' => '', 'Permission - Folder' => '0777', 'Permission - Normal Files' => '0766', 'Permission - CGI Scripts' => '0777', 'Min Password Length' => 4, 'Allow Only Known Types' => 0, 'CGI Types' => " pl cgi sh exe php asp bat cmd idq stm shtml shtm ", 'Known Types' => " css js txt html htm jpg gif wav mid midi au ra zip tar hqx null tmp ", 'Forbid Types' => " htaccess ", 'RegKey' => '', 'mode' => 1, ); $const{'code_validate'} = sub { my $p_decode = sub { local $_; my $code = defined($_[0]) ? $_[0] : ''; my %map = (); my $i = 0; foreach (48..57,65..90,97..122) { $map{chr($_)} = $i % 16; $i++; } $code =~ s!\s|\r|\n|\015|\012!!sg; my $text = ''; my $frag = ''; $i = 0; while ($frag = substr($code, $i, 2)) { $i += 2; my $chn = 16 * $map{substr($frag,0,1)}; $chn += $map{substr($frag,1,1)}; my $ch = chr($chn); $text .= $ch; } $text = unpack('u',$text); return $text; }; local $_; my $code = defined($_[0]) ? $_[0] : ''; return 0 unless ($code); my $is_valid = 0; $code =~ s!BEGIN LICENSE!!sg; $code =~ s!END LICENSE!!sg; if ($code =~ m!^\s*(.*)\s*\-\s*(.*?)\s*$!s) { my ($pub, $pri) = ($1,$2); $pri = &$p_decode($pri); $pub =~ s!(\s|\r|\n)!!sg; $pri =~ s!(\s|\r|\n)!!sg; if ($pub eq $pri) { $is_valid = 1; } } return $is_valid; }; my $text = ''; ($err_msg, $text) = &ReadFile( "$const{'preferences folder'}/security.txt" ); next Err if ($err_msg); foreach (split(m!\r?\n!, $text)) { next unless (m!^(.+)\==(.*)$!); my ($name, $value) = ($1, $2); next unless (defined($security{$name})); $value =~ s!\\CRLF!\015\012!sg; $security{$name} = $value; } #changed 0006 - strip trailing slashes: $security{'Base Folder'} =~ s!/$!!o; $security{'Base URL'} =~ s!/$!!o; $security{'Images URL'} =~ s!/$!!o; $const{'preferences folder'} =~ s!/$!!o; # $const{'mode'} # 0 => is_demo; cannot save data # 1 => shareware / evaluation mode # 2 => shareware / registered # 3 => freeware # user can set it to whatever he wants. # BUT he can't be 2/registered unless he has a valid regkey (we'll kick him down to shareware) # AND nobody can be anything but demo if the "is_demo" file has been touched $const{'mode'} = $security{'mode'}; if (($const{'mode'} == 2) and (not ($security{'RegKey'}))) { $const{'mode'} = 1; } if (-e "$const{'preferences folder'}/is_demo") { $const{'mode'} = 0; } #changed 0003 - Make the permissions value octal instead of text: undef($@); foreach ('Permission - Folder', 'Permission - Normal Files', 'Permission - CGI Scripts') { my $mode = $security{$_}; next unless ($mode =~ m!^0\d\d\d$!); eval "\$security{\"\$_ - eval\"} = $mode;"; if ($@) { $err_msg = "unable to evaluate command - $@"; next Err; } } %params = (); my %upload_files = (); &standard_binmode(); $err_msg = &WebForm( \%params, \%upload_files, "$const{'preferences folder'}/temp" ); next Err if ($err_msg); # Initialize certain form fields: foreach ('CWD', 'Stop') { $params{$_} = '' unless ($params{$_}); } $auth = &web_auth_new( 'make_starter_accounts' => 1, 'data_folder' => "$const{'preferences folder'}/accounts/", 'lang_strings' => \@lang_strings, ); my ($is_auth, $private_token, $auth_username, $is_cookies_aware) = $auth->Challenge( \%params ); last Err unless ($is_auth); unless ($is_cookies_aware) { $const{'admin_url'} .= "web_auth_cp=$private_token&"; $const{'crypt_pass_line'} = ""; } # Below is a mammoth procedure which handles all authentication methods, and reads # in this user's preferences to populate the $STATE array. Authentication errors # below will redirect to the &Challenge procedure: # Okay, user is authenticated, input is parsed, it's time to do some editing... my $action = ''; if ($params{'Action'}) { $action = $params{'Action'}; } if ($action eq 'LogOut') { $auth->logout(); last Err; } %STATE = (); $const{'home_dir_err_msg'} = &GetUserPrefs( $auth_username, \%STATE ); my $title = ''; if ($action eq 'Main') { $title = 'Administer Genesis'; } elsif ($action eq 'SS') { $title = 'Switch Sort Method'; } elsif ($action eq 'Delete') { $title = "Delete Files"; } elsif ($action eq 'Rename') { $title = "Rename Files"; } elsif ($action eq 'Copy') { $title = "Copy Files"; } elsif ($action eq 'PR') { $title = 'Show Preferences'; } elsif ($action eq 'save_prefs') { $title = 'Saving Preferences'; } elsif ($action eq 'BT') { $title = 'Build Template'; } elsif ($action eq 'VT') { $title = 'Save Template'; } elsif ($action eq 'Edit') { $title = "

Editing file '$params{'FH'}'.

"; } elsif ($action eq 'Write') { $title = "Save $params{FH}"; } elsif ($action eq 'upload') { $title = "Upload File $params{'FH'}"; } elsif ($action eq 'makedir') { $title = "Make Folder $params{'directory'}"; } elsif ($action eq 'ListFiles') { $title = 'List Files and Folders'; } elsif ($action eq 'ListTemplates') { $title = 'Template Editor'; } elsif (($const{'mode'} != 3) and ($action eq 'multi-upload')) { $title = "Upload Files"; } elsif (($const{'mode'} != 3) and ($action eq 'image-review')) { $title = "Review Images"; } elsif ($STATE{'Username'} ne $const{'super user'}) { $title = ''; } elsif ($action eq 'EventLog') { $title = 'Manage Event Log'; } elsif ($action eq 'SY') { $title = 'Manage System Settings'; } elsif ($action eq 'UC') { $title = 'Register Genesis Script'; } elsif (($const{'mode'} != 3) and ($action eq 'UA')) { $title = 'User Administration'; } my %replace_values = %const; $replace_values{'cpfooter'} = "

The Genesis Web Authoring System v$VERSION is copyright 2001 by Zoltan Milosevic.

"; $replace_values{'title'} = $title; my ($header_text, $footer_text) = ('', ''); my $template_text = &PrintTemplateEx( 1, 'template.html', "$const{'preferences folder'}/templates/english", \%replace_values ); if ($template_text =~ m!^(.*)\%script_output\%(.*)$!is) { ($header_text, $footer_text) = ($1, $2); } print "Content-Type: text/html\015\012\015\012"; print $header_text; &StartHTML(); if ($action eq '') { &user_shell(); } elsif ($action eq 'Main') { &ui_Admin(); } elsif ($action eq 'SS') { &SwitchSort(); &ui_ListFiles(); } elsif ($action eq 'Delete') { &ui_Delete( $STATE{'file_path'} ); } elsif ($action eq 'Rename') { &ui_Rename(); } elsif ($action eq 'Copy') { &ui_Copy(); } elsif ($action eq 'PR') { &ShowSettings( $STATE{'Username'}, 1, 0 ); } elsif ($action eq 'save_prefs') { &Save_Preferences( $STATE{'Username'}, 1 ); } elsif ($action eq 'BT') { &BuildTemplate(); } elsif ($action eq 'VT') { &SaveTemplate; } elsif ($action eq 'Edit') { &ui_Edit( $params{'FH'} ); } elsif ($action eq 'Write') { &ui_Write( $params{'FH'}, $params{'file'} ); &ui_ListFiles(); } elsif ($action eq 'upload') { &ui_Upload( \%upload_files ); } elsif ($action eq 'makedir') { &create_folder( $params{'directory'} ); &ui_ListFiles(); } elsif ($action eq 'ListFiles') { &ui_ListFiles(); } elsif ($action eq 'ListTemplates') { &ui_ListTemplates(); } # These features are not available in the freeware version: elsif (($const{'mode'} != 3) and ($action eq 'multi-upload')) { &form_BulkUpload(); } elsif (($const{'mode'} != 3) and ($action eq 'image-review')) { &form_ImageReview(); } elsif (($const{'mode'} != 3) and ($action eq 'html-review')) { &form_HTML_Review(); } #end # If a user doesn't enter a $params{'Action'}, then he goes through the default # &ListFiles routine defined above. Otherwise, he enters this IF/ELSE block # and proceeds until he finds a match for his $Action. Every possible user # action (except LogOut) has been offered above. Thus, if he makes it this # far, he is either trying to log out, he has an invalid $Action, or he is a # super-user. To keep things safe and secure, at this point we are just going # to log the user out unless he is the super-user: elsif ($STATE{'Username'} ne $const{'super user'}) { &user_shell(); } # Okay, he's made it through - time to start offering super-user actions: # Basic admin actions: elsif ($action eq 'EventLog') { &ui_ManageLog(); } elsif ($action eq 'SY') { &ui_SystemSettings(); } elsif ($action eq 'UC') { &ui_UpdateLicense(); } # Admin actions regarding management of user accounts; not available in freeware mode==3 elsif (($const{'mode'} != 3) and ($action eq 'UA')) { &ui_ManageUsers(); } # Default action: else { &user_shell(); } &ReportFreeSpace() if $STATE{'DiskUse'}; print $footer_text; last Err; } continue { print "Content-Type: text/html\015\012\015\12"; print "

Error: $err_msg.

"; } # Finished re-directing to the proper subprocedures. The script is # now finished executing. # # __________________________________________________________________ # see perldoc perlsec sub query_env { my ($name,$default) = @_; if (($ENV{$name}) and ($ENV{$name} =~ m!^(.*)$!s)) { return $1; } elsif (defined($default)) { return $default; } else { return ''; } } sub user_shell { if ($STATE{'shell'} == 1) { &ui_ListTemplates(); } elsif ($STATE{'shell'} == 2) { &ui_ListFiles(); } else { &ui_Admin(); } } sub save_system_settings { local $_; my $text = ''; $security{'Images URL'} = &Trim($security{'Images URL'}); foreach (sort keys %security) { my $value = $security{$_}; $value =~ s!(\r|\n)+!\\CRLF!sg; $text .= "$_==$value\n"; } return &WriteFile( "$const{'preferences folder'}/security.txt", $text ); } sub ui_SystemSettings { my $err_msg = ''; Err: { print <<"EOM";

Main / System Settings / EOM my @order = ( 'Images URL', 'Mail Server', 'Permission - Folder', 'Permission - Normal Files', 'Permission - CGI Scripts', 'Min Password Length', 'Forbid Types', 'CGI Types', 'Allow Only Known Types', 'Known Types', ); my %desc_security = ( 'Images URL' => "The web folder holding all the images used in the UI. You may use http://www.xav.com/scripts/genesis/images if you like.", 'Mail Server' => "The address of an SMTP server for sending mail. If one is not supplied, the script will try to auto-detect one whenever it needs to send mail.", 'Permission - Folder' => "File permissions for all folders.", 'Permission - Normal Files' => "File permissions for all normall files.", 'Permission - CGI Scripts' => "File permissions for CGI scripts.", 'Min Password Length' => "Minimum password length", 'Allow Only Known Types' => "If set to 1, only file extensions in the 'Known Types' group will be allowed (CGI scripts will also be allowed for any users that you give the 'allow_cgi' privilege to). Alternately, when set to 0, any file extension will be permitted *unless* it has been specifically outlawed in the Forbid Types list.", 'CGI Types' => "All files with these extensions will be considered CGI scripts. List all extensions together, in lowercase, separated by spaces.", 'Known Types' => "These are familiar, friendly file extensions. Files with these extensions will be allowed. List all extensions together, in lowercase, separated by spaces.", 'Forbid Types' => "Any files with these extensions will be forbidden. List all extensions together, in lowercase, separated by spaces.", ); if ($params{'subaction'} eq 'write') { print ' Save Data

'; if ($const{'mode'} == 0) { $err_msg = $lang_strings[45]; next Err; } my $text = ''; foreach (@order) { $security{$_} = $params{$_}; } $err_msg = &save_system_settings(); next Err if ($err_msg); printf( $lang_strings[4], "saved security settings" ); last Err; } else { print ' Overview

'; } print <<"EOM";

Note: the settings "Base Folder" and "Base URL" have migrated to a per-user setting.

$const{'cwd_line'} $const{'crypt_pass_line'} EOM my $text = ''; foreach (@order) { my $desc = $desc_security{$_}; $text .= "

$_:

$desc_security{$_}

\n"; } print &SetDefaults(<<"EOM", \%security ); $text

EOM last Err; } continue { printf( $lang_strings[2], $err_msg ); } } sub ui_UpdateLicense { my $err_msg = ''; Err: { print "

Main / Update License / "; if ($params{'subaction'} eq 'write') { print "Save Data

"; if ($const{'mode'} == 0) { $err_msg = $lang_strings[45]; next Err; } if ($params{'RegKey'}) { my $virtual = $const{'code_validate'}; unless (&$virtual($params{'RegKey'})) { #should not happen $err_msg = "the registration code you entered is not valid - please contact the vendor"; next Err; } } if (($params{'RegKey'}) and ('' eq $security{'RegKey'})) { $security{'mode'} = 2; } else { $security{'mode'} = $params{'mode'}; } $security{'RegKey'} = $params{'RegKey'}; $err_msg = &save_system_settings(); next Err if ($err_msg); printf( $lang_strings[4], "saved licensing information" ); last Err; } else { print "Overview

"; } my %defaults = ( 'mode' => $const{'mode'}, 'RegKey' => $security{'RegKey'}, ); print &SetDefaults(<<"EOM", \%defaults);
$const{'cwd_line'} $const{'crypt_pass_line'}
License Mode Features
Freeware
Version
Basic functionality - single user HTML and template editing.
Trial
Shareware
Extended functionality for a reasonable trial period. Allows multiple user accounts, user settings updated over web, multiple file upload, etc.
Registered
Shareware
All features, permanent. You receive the right to remove publicly-viewable copyright.

Registration key:

To make inquiries or to acquire a new registration key, visit www.xav.com/scripts/genesis.

Your support will help get new features added, and will help with bug fixes and performance improvements.

EOM last Err; } continue { printf( $lang_strings[2], $err_msg ); } } sub ui_Admin { if ($STATE{'Username'} eq $const{'super user'}) { print '

Admin Options

EOM } print <<"EOM";

Authoring Options

EOM } sub ui_Rename { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my @Files = (); my ($name, $value) = (); while (($name, $value) = each %params) { next unless ($name =~ m!^FH\:(.*)$!); push(@Files, $1); } if ($params{'Confirmed'}) { my ($err_msg, $is_cgi) = (); foreach (reverse sort @Files) { my $old_file = $_; my $new_file = $params{"FH:$_"}; ($err_msg, $is_cgi) = &CheckName( $new_file ); if ($err_msg) { printf( $lang_strings[2], $err_msg ); next; } my $old_abs_file = "$STATE{'file_path'}/$old_file"; my $new_abs_file = "$STATE{'file_path'}/$new_file"; unless (rename($old_abs_file, $new_abs_file)) { $err_msg = sprintf( $lang_strings[14], $old_file, $new_file, $! ); printf( $lang_strings[2], $err_msg ); next; } printf( $lang_strings[4], sprintf( $lang_strings[20], $old_file, $new_file ) ); } } else { print <<"EOM";

Rename Files:

$const{'cwd_line'} $const{'crypt_pass_line'} EOM my $relfile = (); foreach $relfile (@Files) { print <<"EOM"; EOM } print <<"EOM";
Original File New File Name
$relfile

EOM } last Err; } continue { printf($lang_strings[2], $err_msg); } } sub ui_Copy { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my @Files = (); my ($name, $value) = (); while (($name, $value) = each %params) { next unless ($name =~ m!^FH\:(.*)$!); push(@Files, $1); } if ($params{'Confirmed'}) { foreach (reverse sort @Files) { my ($err_msg, $is_cgi) = (); Err: { my $old_file = $_; my $new_file = $params{"FH:$_"}; ($err_msg, $is_cgi) = &CheckName( $new_file ); next Err if ($err_msg); my $old_abs_file = "$STATE{'file_path'}/$old_file"; my $new_abs_file = "$STATE{'file_path'}/$new_file"; my $contents = ''; ($err_msg, $contents) = &ReadFile( $old_abs_file ); next Err if ($err_msg); ($err_msg) = &WriteFile( $new_abs_file, $contents ); next Err if ($err_msg); &Mask( $new_abs_file, $is_cgi ); printf( $lang_strings[4], sprintf( $lang_strings[16], $new_file ) ); last Err; } continue { printf( $lang_strings[2], $err_msg ); } } } else { print <<"EOM";

Copy Files:

$const{'cwd_line'} $const{'crypt_pass_line'} EOM my $rel_file = (); foreach $rel_file (@Files) { my $abs_file = "$STATE{'file_path'}/$rel_file"; if (-d $abs_file) { print <<"EOM"; EOM } else { print <<"EOM"; EOM } } print <<"EOM";
Original File New File Name
$rel_file Cannot copy folders - only files
$rel_file

EOM } last Err; } continue { printf($lang_strings[2], $err_msg); } } sub ui_Delete { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my ($base_dir) = @_; my $qm_base_dir = quotemeta("$base_dir/"); my @Files = (); my ($name, $value) = (); while (($name, $value) = each %params) { next unless ($name =~ m!^FH\:(.*)$!); next unless ($value); my $relfile = $1; next if ($relfile =~ m!\.\.!); push(@Files, $relfile); } if ($params{'Confirmed'}) { foreach (reverse sort @Files) { my $relfile = $_; my $abs_file = &clean_path("$base_dir/$_"); unless ($abs_file =~ m!^$qm_base_dir!i) { printf( $lang_strings[2], "file name '$abs_file' doesn't pattern match to base dir '$base_dir'" ); next; } unless ($abs_file =~ m!/([^/]+)$!) { printf( $lang_strings[2], "cannot extract base name from '$abs_file'" ); next; } my $basename = $1; my $file_err = (&CheckName($basename))[0]; if ($file_err) { printf( $lang_strings[2], $file_err ); next; } if (-d $abs_file) { &Mask( $abs_file, 0 ); if (rmdir($abs_file)) { printf( $lang_strings[4], sprintf( $lang_strings[27], $relfile ) ); } else { printf( $lang_strings[2], sprintf( $lang_strings[23], $relfile, $! ) ); } } else { &Mask( $abs_file, 0 ); if (unlink($abs_file)) { printf( $lang_strings[4], sprintf( $lang_strings[19], $relfile ) ); } else { printf( $lang_strings[2], sprintf( $lang_strings[13], $relfile, $! ) ); } } } } else { print <<"EOM";

Confirm Delete:

$const{'cwd_line'} $const{'crypt_pass_line'} EOM my $relfile = (); foreach $relfile (@Files) { my $file = "$base_dir/$relfile"; my $file_err_msg = ''; FileErr: { my $abs_file = &clean_path($file); unless ($abs_file =~ m!^$qm_base_dir!i) { $file_err_msg = "file name '$abs_file' doesn't pattern match to base dir '$base_dir'"; next FileErr; } unless ($abs_file =~ m!/([^/]+)$!) { $file_err_msg = "cannot extract base name from '$abs_file'"; next FileErr; } my $basename = $1; my $file_err = (&CheckName($basename))[0]; if ($file_err) { $file_err_msg = $file_err; next FileErr; } if ($basename eq '.is_user_dir') { $file_err_msg = "is user home directory"; next FileErr; } print "

$relfile

\n"; last FileErr; } continue { print "

$relfile - cannot delete - $file_err_msg.

\n"; } if (-d $file) { &ui_Delete_FolderContents( $file, $relfile ); } } print <<"EOM";

EOM } last Err; } continue { printf($lang_strings[2], $err_msg); } } sub ui_Delete_FolderContents { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my ($abs_path, $rel_path) = @_; my $qm_base_dir = quotemeta("$abs_path/"); my $base_dir = $abs_path; if (opendir(DIR, $abs_path)) { my @items = readdir(DIR); closedir(DIR); print "\n"; } last Err; } continue { printf($lang_strings[2], $err_msg); } } sub StartHTML { print <<"EOM";
Main - Template Editor - HTML Editor - My Account Sign Out - Help

EOM if ($STATE{'ShowTips'}) { my %replace_values = %const; my $tips = &PrintTemplateEx( 1, 'tips.txt', "$const{'preferences folder'}/templates/english", \%replace_values ); my @tips = split(m!\r?\n!, $tips); my $N = scalar @tips; $N = int(rand($N)); print "Tip: $tips[$N]

\n"; } } sub ui_ListTemplates { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } print <<"EOM";

Web Templates:

Templates allow you to create a complete website, without using HTML.

$const{'cwd_line'} $const{'crypt_pass_line'} EOM my $sample_folder = "$const{'preferences folder'}/sample_sites"; unless (opendir(DIR, $sample_folder)) { $err_msg = sprintf( $lang_strings[22], $sample_folder, $! ); next Err; } my $checked = ' CHECKED'; foreach (readdir(DIR)) { next unless (m!(.*)\.template$!); my $public_name = $1; $public_name =~ s!_! !g; print "

$public_name

\n"; $checked = ''; } closedir(DIR); print <<"EOM";

EOM last Err; } continue { printf( $lang_strings[2], $err_msg ); } } sub ui_ListFiles { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } unless (opendir(DIR, '.')) { $err_msg = sprintf( $lang_strings[22], $STATE{'file_path'}, $! ); next Err; } my ($s1, $s2) = (1, 1); while ($s1++) { last unless (-e "index$s1.html"); } while ($s2++) { last unless (-e "folder$s2"); } my %SIZE = (); my %DATE = (); my %sort_hash = (); my @subfolders = (); my ($file_size, $file_date) = (0, 0); foreach (readdir(DIR)) { next if (m!^\.\.?$!); next if (m!^\.!); ($file_size, $file_date) = (0, 0); if (-d $_) { push(@subfolders, $_); if ($STATE{'ShowDirSize'}) { $file_size = &FolderSize($_); } } else { $file_size = -s $_; } $file_date = (stat($_))[9]; if ($STATE{'Sort'} =~ m!s!i) { # sort by size $sort_hash{ (10E9 + $file_size) . $_} = $_; } elsif ($STATE{'Sort'} =~ m!n!i) { # sort by name $sort_hash{$_} = $_; } elsif ($STATE{'Sort'} =~ m!d!i) { # sort by date $sort_hash{ (10E9 + $file_date) . $_} = $_; } elsif (-d $_) { # sort by type (== file extension) $sort_hash{"-\.$_"} = $_; # folders have type "-" } elsif (m!(.*)\.(.*?)!) { my $extension = lc($2); $sort_hash{"$extension.$_"} = $_; # files with an extension use it: } else { $sort_hash{"_\.$_"} = $_; # files with no extension use "_" } $SIZE{$_} = $file_size; $DATE{$_} = $file_date; } closedir(DIR); print <<"EOM";
$const{'crypt_pass_line'} Folder:
$const{'cwd_line'} $const{'crypt_pass_line'} EOM if ($params{'CWD'}) { $params{'CWD'} =~ s!/+$!!g; my $newdir = ''; $newdir = $1 if ($params{'CWD'} =~ m!^(.*)/!); my $admin_url = $const{'admin_url'}; $admin_url =~ s!CWD=([^\&]*)!!g; printf("\n", $admin_url); } my @Files = sort keys %sort_hash; unless ($STATE{'Sort'} =~ m![A-Z]!) { @Files = reverse @Files; } my $i = 0; my %icon_by_extension = ( '' => 'generic', 'mp3' => 'music', 'wav' => 'sound', 'html' => 'html', 'htm' => 'html', 'shtml' => 'html', 'hqx' => 'hqx', 'txt' => 'text', 'text' => 'text', 'zip' => 'zip', 'gz' => 'zip', 'tar' => 'tar', 'pl' => 'pl', 'pdf' => 'pdf', ); foreach (@Files) { my $FH = $sort_hash{$_}; my $size = &FormatNumber( $SIZE{$FH}, 0, 0, 0, 1 ); my $last_modified = &FormatDateTime($DATE{$FH}, 0, 0); my $image = "icon_image.gif"; my $extension = ''; if ($FH =~ m!\.([^\.]+)$!) { $extension = lc($1); } if ($icon_by_extension{$extension}) { $image = "icon_$icon_by_extension{$extension}.gif"; } my $action = '
'; if (-T $FH) { $action = "edit"; } elsif (-d $FH) { $image = "icon_dir.gif"; if (-e "$FH/.is_user_dir") { $image = "icon_dir_secure.gif"; } my $newdir = ''; $newdir = "$params{'CWD'}/" if ($params{'CWD'}); $newdir .= $FH; my $admin_url = $const{'admin_url'}; $admin_url =~ s!CWD=([^\&]*)!!g; $action = "chdir"; } my $bgcolor = ''; $i++; if ($i % 2) { $bgcolor = ' BGCOLOR=#eeeeee'; } $image = ""; print <<"EOM"; EOM } print <<"EOM";
Name . Type Size Last Modified Actions

Parent Directory

updir
$image$FH $size $last_modified $action delete

  Checked Items => - -


$const{'cwd_line'} $const{'crypt_pass_line'} $const{'cwd_line'} $const{'crypt_pass_line'} $const{'cwd_line'} $const{'crypt_pass_line'}
Create HTML File:
Create Folder:
Upload File:
EOM print <<"EOM" if ($const{'mode'} != 3);

See Also: Multiple File Upload - Review Images - Review/Validate HTML

EOM print '


'; last Err; } continue { printf( $lang_strings[2], $err_msg ); } } =item form_ImageReview() Usage: &form_ImageReview(); =cut sub form_ImageReview { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } print <<"EOM";

Review All Images

EOM my @ImageFiles = &GetFiles( $STATE{'file_path'}, "\.(jpg|jpeg|bmp|gif)\$" ); foreach (sort @ImageFiles) { my ($err_msg, $x, $y, $filesize) = &image_size( $_ ); my $rel_path = $_; $rel_path =~ s!^$STATE{'file_path'}/!!o; if ($err_msg) { print <<"EOM"; EOM } else { my $html = &html_encode( "" ); $filesize = &FormatNumber( $filesize, 0, 0, 0, 1 ); print <<"EOM";
Path: $rel_path
Size: $filesize bytes
Width: $x
pixels
Height: $y
pixels
Commands: Rename - Copy - Delete
HTML:

$rel_path

EOM } } print "
"; last Err; } continue { printf( $lang_strings[2], $err_msg ); } } =item form_HTML_Review() Usage: &form_HTML_Review(); =cut sub form_HTML_Review { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } print <<"EOM";

Review All HTML Pages

EOM my @ImageFiles = &GetFiles( $STATE{'file_path'}, "\.(html|htm|shtml|stm)\$" ); foreach (sort @ImageFiles) { my $rel_path = $_; my $size = &FormatNumber(-s $rel_path, 0, 0, 0, 1); $rel_path =~ s!^$STATE{'file_path'}/!!o; my $url = $STATE{'web_path'} . '/' . $rel_path; my $urlurl = &url_encode($url); if ($err_msg) { print <<"EOM"; EOM } else { print <<"EOM"; EOM } } print "
Path Size Actions
$rel_path $size Validate HTML
"; last Err; } continue { printf( $lang_strings[2], $err_msg ); } } =item form_BulkUpload Usage: &form_BulkUpload(); =cut sub form_BulkUpload { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my $field_count = $STATE{'multi_upload_count'}; if ($params{'multi_upload_count'}) { $field_count = $params{'multi_upload_count'}; my %overrides = ( 'multi_upload_count' => $field_count, ); my $err_msg = &SaveUserPrefs( $STATE{'Username'}, \%overrides, 1 ); if ($err_msg) { &Report( sprintf( $lang_strings[2], $err_msg ) ); } } print <<"EOM";
$const{'cwd_line'} $const{'crypt_pass_line'}

Upload Files

EOM for (1..$field_count) { print "

File:

\n"; } print &SetDefaults(<<"EOM", \%STATE);




$const{'cwd_line'} $const{'crypt_pass_line'}

Allow files to be uploaded.

EOM last Err; } continue { printf( $lang_strings[2], $err_msg ); } } sub BuildTemplate { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my $FILE = $const{'preferences folder'} . '/sample_sites/' . $params{'Template'}; my $text = ''; # Has this template been used before? my %replace_values = (); if (-e ".$params{'Template'}") { ($err_msg, $text) = &ReadFile( ".$params{'Template'}" ); foreach (split(m!\n!, $text)) { next unless (m!^(.*)\=(.*)$!); $replace_values{lc($1)} = $2; } } ($err_msg, $text) = &ReadFile( $FILE ); next Err if ($err_msg); print <<"EOM";
$const{'cwd_line'} $const{'crypt_pass_line'}

Fill out the form below, and then click "Build Web Site".


EOM my $ready = 0; Line: foreach (split(m!\n!, $text)) { last if (m!!i); next if (m!^\#!); if (m!!i) { $ready = 1; next; } next unless ($ready); if (m!^(.*)

This template creates the following files:

    EOM foreach (split(m!!si, $text)) { next unless (m!(.*)!si); my ($file) = ($1); if (-e $file) { print "
  • $file - will overwrite your existing file\n"; } else { print "
  • $file\n"; } } print <<"EOM";
EOM last Err; } continue { printf( $lang_strings[2], $err_msg ); } } sub SaveTemplate { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my %replace_values = (); my $text = ''; my ($name, $value) = (); while (($name, $value) = each %params) { $value =~ s!(\r|\n|\015|\012)!!g; $name =~ s!\=!!g; $replace_values{$name} = $value; $text .= "$name=$value\n"; } $err_msg = &WriteFile( ".$params{'Template'}", $text ); next Err if ($err_msg); ($err_msg, $text) = &ReadFile( "$const{'preferences folder'}/sample_sites/$params{'Template'}" ); next Err if ($err_msg); my @temp_errors = (); my $temp_err_msg = ''; my $prime_file = ''; my $prime_complete = 0; foreach (split(m!\n!, $text)) { next unless (m!!i); my ($rel_old_file, $new_file) = ($1, $2); my $abs_old_file = "$const{'preferences folder'}/sample_sites/$rel_old_file"; my $is_cgi = 0; ($temp_err_msg, $is_cgi) = &CheckName( $new_file ); if ($temp_err_msg) { push(@temp_errors, $temp_err_msg); next; } my $contents = ''; ($temp_err_msg, $contents) = &ReadFile( $abs_old_file ); if ($temp_err_msg) { push(@temp_errors, $temp_err_msg); next; } ($temp_err_msg) = &WriteFile( $new_file, $contents ); if ($temp_err_msg) { push(@temp_errors, $temp_err_msg); next; } } #changed 0009 - map \n =>
\n my $key = (); foreach $key (keys %params) { # don't map if the sample contains HTML tags itself next if ($params{$key} =~ m!\<.*\>!s); # don't map if the key is a noconvert_ key next if ($key =~ m!^noconvert_!); $params{$key} =~ s!\cM!!sg; $params{$key} =~ s!\n!
\n!sg; } #end changes foreach (split(m!!si, $text)) { next unless (m!(.*)!si); my ($file, $text) = ($1, $2); my $is_cgi = 0; ($temp_err_msg, $is_cgi) = &CheckName( $file ); if ($temp_err_msg) { push(@temp_errors, $temp_err_msg); next; } $prime_file = $file unless ($prime_file); my $key = (); foreach $key (reverse sort keys %params) { $text =~ s!\%$key\%!$params{$key}!sig; } $text =~ s!\cM!!sg; my $file_size = length($text); $file_size -= (-s $file) if (-s $file); unless (($file_size < 0) || (&CheckFreeSpace($file_size))) { push(@temp_errors, sprintf( $lang_strings[9], $file, $lang_strings[29] )); last; } $temp_err_msg = &WriteFile( $file, $text ); if ($temp_err_msg) { push(@temp_errors, $temp_err_msg); next; } if ($file eq $prime_file) { $prime_complete = 1; } } foreach (@temp_errors) { &Report( sprintf( $lang_strings[2], $_ ) ); } print "

Your template web site is complete.

\n"; last Err; } continue { &Report( sprintf( $lang_strings[2], $err_msg ) ); } } =item ui_Edit($) Usage: &Edit( $file ); Creates an HTML form displaying the contents of $file for editing. =cut sub ui_Edit { my ($file) = @_; my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my $is_cgi = 0; ($err_msg, $is_cgi) = &CheckName( $file ); next Err if ($err_msg); my $readthis = $file; if (-e ".ssi.$file") { $readthis = ".ssi.$file"; } my $text = ''; if (-e $readthis) { ($err_msg, $text) = &ReadFile( $readthis ); next Err if ($err_msg); $text = &html_encode($text); } else { ($err_msg, $text) = &ReadFile( "$const{'preferences folder'}/sample_sites/default_html_page.txt" ); next Err if ($err_msg); $text = &html_encode($text); } unless ($STATE{'Concise'}) { if ($text) { print "

Modify $file as needed:

\n"; } else { print "

This is a new file. Input your text below:

\n"; } } my $wrap_tag = ''; if ($STATE{'TextWrap'}) { $wrap_tag = ' WRAP="virtual"'; } print <<"EOM";

$const{'cwd_line'} $const{'crypt_pass_line'}

-

EOM if ($STATE{'allow_cgi'}) { my $c = ($file eq $readthis) ? '' : 'CHECKED'; print <<"EOM";

Parse server-side include statements.

EOM } print <<"EOM";

Entering an alternate filename will leave file '$file' untouched, and will place the above text into a file with the alternate name, overwriting the existing contents if the file already exists.

EOM last Err; } continue { &Report( sprintf( $lang_strings[2], $err_msg ) ); } } =item ui_Write($$) Usage: &ui_Write( $file, $text ); Dependencies: &CheckName &CheckFreeSpace &Mask &Report =cut sub ui_Write { my ($file, $text) = @_; my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my $is_cgi = 0; ($err_msg, $is_cgi) = &CheckName( $file ); next Err if ($err_msg); &Mask( $file, $is_cgi ) if (-e $file); my $SIZE = length($text); $SIZE -= (-s $file) if (-e $file); unless (($SIZE < 0) or (&CheckFreeSpace(length($SIZE)))) { $err_msg = sprintf( $lang_strings[9], $file, $lang_strings[29] ); next Err; } $text =~ s!\cM\n!\n!g; if (($STATE{'allow_cgi'}) and ($params{'parse_ssi'})) { my $shadow_file = '.ssi.' . $file; $err_msg = &WriteFile( $shadow_file, $text ); next Err if ($err_msg); my $parsed_text = &PrintTemplateEx( 1, $shadow_file, '.' ); $err_msg = &WriteFile( $file, $parsed_text ); next Err if ($err_msg); } else { $err_msg = &WriteFile( $file, $text ); next Err if ($err_msg); } &Mask( $file, $is_cgi ); &Report( sprintf( $lang_strings[4], sprintf( $lang_strings[16], $file ) ) ); last Err; } continue { &Report( sprintf( $lang_strings[2], $err_msg ) ); } } =item ui_Upload() Usage: &ui_Upload( \%upload_files ); =cut sub ui_Upload { my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my ($p_upload_files) = @_; my $upload_success = 0; my ($name, $p_data) = (); while (($name, $p_data) = each %$p_upload_files) { my $file = $$p_data{'client file name'}; next unless ($file); $file = $3 if ($file =~ m!^(.*)(\\|/)(.*?)$!); $file =~ s! !_!g; my $is_cgi = 0; ($err_msg, $is_cgi) = &CheckName( $file ); next Err if ($err_msg); &Mask( $file, $is_cgi ) if (-e $file); my $SIZE = $$p_data{'size'}; if (($SIZE > 0) and (not &CheckFreeSpace($SIZE))) { $err_msg = sprintf( $lang_strings[9], $file, $lang_strings[29] ); next Err; } my $FullText = ''; my $TempFile = $$p_data{'temp file'}; my $MODE = 'binary'; if ((-T $TempFile) and ($STATE{'TextUpload'})) { $MODE = 'ascii/text'; } unless (open(FILE, ">$file")) { $err_msg = sprintf( $lang_strings[9], $file, $! ); next Err; } unless (binmode(FILE)) { $err_msg = sprintf( $lang_strings[12], $file, $! ); next Err; } unless (open(TEMP, "<$TempFile")) { $err_msg = sprintf( $lang_strings[8], $TempFile, $! ); next Err; } unless (binmode(TEMP)) { $err_msg = sprintf( $lang_strings[12], $TempFile, $! ); next Err; } if ($MODE eq 'ascii/text') { while () { s!\cM\n!\n!sg; s!\015\012!\012!sg; print FILE; } } else { while () { print FILE; } } close(FILE); close(TEMP); &Mask( $file, $is_cgi ); &Report( sprintf( $lang_strings[4], "file '$file' has been uploaded in $MODE mode" ) ); $upload_success++; } if (($STATE{'Sound'}) and ($upload_success)) { printf( '', $security{'Images URL'} ); } last Err; } continue { &Report( sprintf( $lang_strings[2], $err_msg ) ); } } =item create_folder($) Usage: &create_folder( $folder ); =cut sub create_folder { my ($file) = @_; my $err_msg = ''; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my $is_cgi = 0; ($err_msg, $is_cgi) = &CheckName( $file ); next Err if ($err_msg); unless (mkdir($file, 0777)) { $err_msg = sprintf( $lang_strings[21], $file, $! ); next Err; } &Mask( $file, 0 ); &Report( sprintf( $lang_strings[4], sprintf( $lang_strings[25], $file ) ) ); last Err; } continue { &Report( sprintf( $lang_strings[2], $err_msg ) ); } } =item FolderSize($) Usage: $bytes = &FolderSize( $folder_name ); =cut sub FolderSize { my $size = 0; Err: { if ($const{'home_dir_err_msg'}) { $err_msg = $const{'home_dir_err_msg'}; next Err; } my ($DIR) = @_; $DIR =~ s!\\!/!g; $DIR =~ s!/$!!o; next Err unless (opendir(DIR, $DIR)); my @Files = readdir(DIR); closedir(DIR); foreach (@Files) { next if (m!^\.\.?$!); my $abs_path = "$DIR/$_"; if (-d $abs_path) { $size += &FolderSize( $abs_path ); } else { $size += (-s $abs_path); } } } return $size; } sub ui_Confirmed { my ($object_name) = @_; if (($params{'Y'}) and ($params{'Y'} eq 'Y1')) { delete $params{'Y'}; return 1; } print <<"EOM";

Are you sure you want to delete '$object_name'?

EOM my ($name, $value); while (($name, $value) = each %params) { next if ($name =~ m!^(cwd|web_auth_cp|y|sw)$!i); printf( '', &html_encode($name), &html_encode($value)); } print <<"EOM"; $const{'cwd_line'} $const{'crypt_pass_line'}

EOM return 0; } sub ui_ManageUsers { my $err_msg = ''; Err: { print <<"EOM";

Main / Manage Users / EOM my $subaction = $params{'sa'} || ''; if ($subaction eq 'DU') { print " Delete User

"; my $username = $params{'UN'}; last Err unless &ui_Confirmed($username); my $warnings = 0; my %TMP = (); &LoadUserPrefs( $username, \%TMP ); my $UserDIR = $TMP{'Author:UserFolder:parsed'}; my $file = "$UserDIR/.is_user_dir"; if ((-e $file) and (not (unlink($file)))) { $err_msg = sprintf( $lang_strings[13], $file, $! ); &Report( sprintf( $lang_strings[3], $err_msg ) ); $warnings++; } my $UserFile = "$const{'preferences folder'}/accounts/$username.txt"; if ((-e $UserFile) and (not (unlink($UserFile)))) { $err_msg = sprintf( $lang_strings[13], $UserFile, $! ); &Report( sprintf( $lang_strings[3], $err_msg ) ); $warnings++; } $err_msg = $auth->DeleteUser($username); if ($err_msg) { &Report( sprintf( $lang_strings[3], $err_msg ) ); $warnings++; } if ($warnings) { &Report( sprintf( $lang_strings[4], "finished trying to remove user account '$username' - some steps did not complete successfully" ) ); } else { &Report( sprintf( $lang_strings[4], "removed user account '$username'" ) ); } print "

All files in the user's home folder '$UserDIR' are still present. Deleting files must be done separately.

\n"; last Err; } elsif ($subaction eq 'EP') { print "Account '$params{'UN'}' / Overview

"; &ShowSettings( $params{'UN'}, 0, 0); last Err; } elsif ($subaction eq 'NA') { print " New Account

"; &ShowSettings( '', 0, 1); last Err; } elsif ($subaction eq 'SP') { print "Account '$params{'UN'}' / Save Data

"; &Save_Preferences( $params{'UN'}, 0 ); last Err; } elsif ($subaction eq 'CU') { print " Create User

"; &CreateUser(); last Err; } elsif ($subaction eq 'RP') { print " Reset Password

"; &Give_Password(); last Err; } elsif ($subaction eq 'SA') { print " Reset Password / Save Data

"; if ($const{'super user'} eq $params{'UN'}) { &Save_Password( $params{'UN'}, $params{'OldPass'}, $params{'NewPass'}, $params{'NewPass2'}, 1 ); } else { &Save_Password( $params{'UN'}, '', $params{'NewPass'}, $params{'NewPass2'}, 0 ); } last Err; } else { print " Overview

"; } my $accounts_dir = "$const{'preferences folder'}/accounts"; unless (opendir(DIR, $accounts_dir)) { $err_msg = sprintf( $lang_strings[22], $accounts_dir, $! ); next Err; } print <<"EOM"; EOM my %userdata = (); my $i = 1; foreach (sort readdir(DIR)) { next unless (m!(.*)\.txt$!i); my $User = $1; next if ($User eq $const{'super user'}); next if ($User eq '_default'); my $bgcolor = ' BGCOLOR=#eeeeee'; $i++; $bgcolor = '' if ($i % 2); &LoadUserPrefs( $User, \%userdata ); my $date_created_str = &FormatDateTime( $userdata{'AccountCreated'}, 14, 0 ); my $time_str = 'never'; if ($userdata{'LastLogin'}) { my $age = time() - $userdata{'LastLogin'}; if ($age > (2 * 86400)) { $time_str = int($age / 86400) . ' days ago'; } elsif ($age > (100 * 60)) { $time_str = int($age / 3600) . ' hours ago'; } else { $time_str = int($age / 60) . ' min ago'; } } print <<"EOM"; EOM } closedir(DIR); print <<"EOM";
Username Account Created Last Accessed Actions
$const{'super user'}

Edit Profile

_default

Edit Profile

$User $date_created_str $time_str Edit Profile Reset Password Delete

[ New Account ]

EOM last Err; } continue { &Report( sprintf( $lang_strings[2], $err_msg ) ); } } sub Give_Password { print <<"EOM";
$const{'cwd_line'} $const{'crypt_pass_line'}

Assigning new password for user '$params{'UN'}':

Password:
Confirm:

EOM } sub Report { my ($message, $do_not_print_to_screen) = @_; print $message unless ($do_not_print_to_screen); if (-e $const{'event log'}) { if (open(LOG, ">>$const{'event log'}")) { my $time = time(); $message =~ s!<.*?>!!g; $message =~ s!\,!!g; my $remote_addr = &query_env('REMOTE_ADDR'); print LOG "$remote_addr , $STATE{'Username'},$time,$message\n"; close(LOG); } else { printf( $lang_strings[2], sprintf( $lang_strings[10], $const{'event log'}, $! ) ); } } } =item ui_ManageLog() Manages admin options related to the log - viewing it, resetting it, and deleting. =cut sub ui_ManageLog { my $err_msg = ''; Err: { print "

Main / Event Log / "; if ($params{'Stop'}) { print " Stop

"; unless (unlink($const{'event log'})) { $err_msg = sprintf( $lang_strings[13], $const{'event log'}, $! ); next Err; } printf( $lang_strings[4], sprintf( $lang_strings[19], $const{'event log'} ) ); last Err; } elsif ($params{'CMD'} eq 'Start') { print " Start

"; unless (-e $const{'event log'}) { $err_msg = &WriteFile( $const{'event log'}, '' ); next Err if ($err_msg); } &Report( sprintf( $lang_strings[4], "logging has been started" ) ); last Err; } elsif ($params{'CMD'}) { print " Reset

"; $err_msg = &WriteFile( $const{'event log'}, '' ); next Err if ($err_msg); &Report( sprintf( $lang_strings[4], "the event log has been cleared" ) ); last Err; } else { print " Overview

"; } unless (-e $const{'event log'}) { print <<"EOM";
$const{'cwd_line'} $const{'crypt_pass_line'}

Logging is currently disabled. To turn it on, click the button above.

EOM } else { unless (open(FILE, "<$const{'event log'}")) { $err_msg = sprintf( $lang_strings[8], $const{'event log'}, $! ); next Err; } unless (binmode(FILE)) { $err_msg = sprintf( $lang_strings[12], $const{'event log'}, $! ); next Err; } print <<"EOM";

Listing all events, from oldest to newest.

EOM my $i = 0; while () { my ($ip, $user, $time, $event) = split(m!\,!); $i++; if ($i % 2) { print ""; } else { print ""; } print "\n"; } close(FILE); print <<"EOM";
User IP Username Time Event
$ip$user" . &FormatDateTime($time, 14, 0) . "" . &html_encode($event) . "
$const{'cwd_line'} $const{'crypt_pass_line'}
Stop Logging Process

The option to stop logging deletes the event log completely - to get it started again, you may need to manually log on to this server.

EOM } last Err; } continue { &Report( sprintf( $lang_strings[2], $err_msg ) ); } } sub CreateUser { my $err_msg = ''; Err: { # Create User makes an entry (username.txt) in the preferences directory, # and creates a home directory for the new user. The format is # &CreateUser with $params{$Name} = $Value defined. This procedure exits, # with an error code, if directory or userfile already exist. my $is_cgi = 0; ($err_msg, $is_cgi) = &CheckName( $params{'Username'} ); next Err if ($err_msg); foreach ($const{'super user'}, '_default') { if ($params{'Username'} eq $_) { $err_msg = "username '$_' is reserverd"; next Err; } } my $UserFile = "$const{'preferences folder'}/accounts/$params{'Username'}.txt"; if (-e $UserFile) { $err_msg = "user file '$UserFile' already exists"; next Err; } my $UserDIR = $params{'Author:UserFolder'}; $UserDIR =~ s!\%username\%!$params{'Username'}!ig; $UserDIR =~ s!/$!!o; if (-e $UserDIR) { $err_msg = "user home folder '$UserDIR' already exists"; printf( $lang_strings[3], $err_msg ); } else { unless (mkdir($UserDIR, 0777)) { $err_msg = sprintf( $lang_strings[21], $UserDIR, $! ); next Err; } } &Mask( $UserDIR, 0 ); $err_msg = &WriteFile( "$UserDIR/.is_user_dir", $params{'Username'} ); if ($err_msg) { printf( $lang_strings[3], $err_msg ); } &Mask( "$UserDIR/.is_user_dir", 0 ); &Save_Preferences( $params{'Username'}, 0 ); &Mask( $UserFile, 0 ); my $password = ''; if (($params{'NewPass'}) and ($params{'NewPass'} eq $params{'NewPass2'})) { $password = $params{'NewPass'}; } else { $password = $auth->InventPassword(); } $err_msg = $auth->SetPassword( $params{'Username'}, $password ); next Err if ($err_msg); # Parse the welcome message up here - some fields will be deleted inside &SaveUserPrefs my %replace_values = %const; foreach (keys %params) { $replace_values{$_} = $params{$_}; } my %webmaster_info = (); &LoadUserPrefs( $const{'super user'}, \%webmaster_info ); foreach (keys %webmaster_info) { my $name = "webmaster_" . $_; $replace_values{$name} = $webmaster_info{$_}; } $replace_values{'password'} = $password; my $welcome_message = &PrintTemplateEx( 1, 'welcome_email.txt', "$const{'preferences folder'}/templates/english", \%replace_values ); &Report( sprintf( $lang_strings[4], "created new user '$params{'Username'}'" ) ); my $start_site_dir = "$const{'preferences folder'}/sample_sites/start_site"; if (opendir(DIR, $start_site_dir)) { foreach (readdir(DIR)) { my $abs_old_file = "$start_site_dir/$_"; my $abs_new_file = "$UserDIR/$_"; next if (-e $abs_new_file); my ($err_msg_x, $contents) = &ReadFile( $abs_old_file ); ($err_msg_x) = &WriteFile( $abs_new_file, $contents ); } closedir(DIR); } if ($params{'email_address'}) { my $trace = ''; my $from_addr = $webmaster_info{'email_address'} || $params{'email_address'}; ($err_msg, $trace) = &SendMailEx( 'host' => $security{'Mail Server'}, 'to' => $params{'email_address'}, 'to name' => $params{'full_name'}, 'from' => $webmaster_info{'email_address'}, 'from name' => $webmaster_info{'full_name'}, 'subject' => "New web authoring account created", 'message' => $welcome_message, ); next Err if ($err_msg); &Report( sprintf( $lang_strings[4], "sent account information with initial password to '$params{'email_address'}'" ) ); } else { print "

Set initial account password to '$password'.

\n"; } last Err; } continue { &Report( sprintf( $lang_strings[2], $err_msg ) ); } } # ------------------------------------------------------------------- # # Security and Error Reporting Procedures # # ------------------------------------------------------------------- # # Below are the all-important permission controls for every file # controlled by Genesis. Forgive the poorly legible code - the first # permission, 0600, is for your preference files - those should only # be readable and writable by this script. The next permission, 0755, # applies to all directories - you could probably get away with 0700 # here. The third permission, 0755, is for CGI scripts, *if* they're # enabled in certain directories. Again, 0700 will probably work. The # final permissions number, 0644, is for standard files. 0600 will # probably work. Remember, the minimal file permissions are always # best!! =item Mask Usage: &Mask( $abs_file, $is_cgi ); Attempts to set file permissions on Unix machine. Dependencies: %security =cut sub Mask { my ($abs_file, $is_cgi) = @_; if (-d $abs_file) { chmod( $security{'Permission - Folder - eval'}, $abs_file); } elsif (($is_cgi) and ($const{'mode'} != 0)) { chmod( $security{'Permission - CGI Scripts - eval'}, $abs_file ); } else { chmod( $security{'Permission - Normal Files - eval'}, $abs_file); } } =item CheckFreeSpace($) Accepts length in bytes of a file. Compares it to the amount of free space. Returns whether if that would kick it over the limit. Dependencies: &FolderSize $security{'Base Folder'} $STATE{'Username'} $STATE{'Quota'} =cut sub CheckFreeSpace { my ($del_size) = @_; my $is_allowed = 1; Err: { if ($const{'home_dir_err_msg'}) { $is_allowed = 0; next Err; } last Err unless ($STATE{'Author:UseQuota'}); my $Quota = $STATE{'Quota'}; my $DiskBytes = &FolderSize($STATE{'Author:UserFolder:parsed'}); my $DiskKB = int($DiskBytes/1000); my $FreeKB = $Quota - $DiskKB; $is_allowed = (($FreeKB * 1000) > $del_size) ? 1 : 0; } return $is_allowed; } =item ReportFreeSpace Prints the amount of space used, and the amount remaining. =cut sub ReportFreeSpace { return if ($const{'home_dir_err_msg'}); my $DiskBytes = &FolderSize($STATE{'Author:UserFolder:parsed'}); my $Quota = $STATE{'Quota'}; my $DiskKB = int($DiskBytes/1000); my $FreeKB = $Quota - $DiskKB; my $percent = &FormatNumber( ( 100 * ($DiskBytes / 1000) / $Quota ), 1, 0, 0, 1 ); my $width1 = int( 200 * ($DiskBytes / 1000) / $Quota ); $width1 = 1 unless ($width1); $width1 = 199 if ($width1 > 199); my $width2 = 200 - $width1; $DiskKB = &FormatNumber( $DiskKB, 0, 0, 0, 1 ); $FreeKB = &FormatNumber( $FreeKB, 0, 0, 0, 1 ); $Quota = &FormatNumber( $Quota, 0, 0, 0, 1 ); print <<"EOM";
Disk Use: $percent%
Using $DiskKB kb of $Quota kb quota - $FreeKB kb free
EOM } =item CheckName($) Usage: ($err_msg, $is_cgi) = &CheckName( $file ); Dependencies: %security %STATE =cut sub CheckName { my ($file) = @_; my $is_cgi = 0; my $max_file_len = 120; my $err_msg = ''; Err: { unless ($file) { $err_msg = "cannot be blank"; next Err; } if (length($file) > $max_file_len) { $err_msg = "maximum allowed length is $max_file_len characters"; next Err; } if ($file =~ m! !) { $err_msg = "blank spaces are not allowed"; next Err; } if ($file =~ m!\.\.!) { $err_msg = "adjacent dots are not allowed"; next Err; } if (($file =~ m!^\.!) and ($file !~ m!\.template$!)) { $err_msg = "cannot begin with a dot"; #but those .x.template files are ok next Err; } my $V = ''; ($V = $file) =~ s/\w//g; $V =~ s/\.//g; $V =~ s/\-//g; if ($V) { $err_msg = "contains illegal characters - $V"; next Err; } my $extension = 'null'; if ($file =~ m!(.*)\.(.*?)$!) { $extension = lc($2); } my $qm_ext = quotemeta( $extension ); my $html_ext = &html_encode( $extension ); $is_cgi = (" $security{'CGI Types'} " =~ m! $qm_ext !i) ? 1 : 0; if (" $security{'Forbid Types'} " =~ m! $qm_ext !i) { $err_msg = "extension '$html_ext' is forbidden"; next Err; } if (($is_cgi) and (not $STATE{'allow_cgi'})) { $err_msg = "CGI extension '$html_ext' is not allowed"; next Err; } elsif ($security{'Allow Only Known Types'}) { if (" $security{'Known Types'} " =~ m! $qm_ext !i) { # okay } else { $err_msg = "extension '$html_ext' is not among the declared 'Known Types'"; next Err; } } } if ($err_msg) { $err_msg = "filename '$file' is invalid - $err_msg"; } return ($err_msg, $is_cgi); } # ------------------------------------------------------------------- # # Initialization, Authentication and Preferences Procedures # # ------------------------------------------------------------------- # =item LoadUserPrefs($$) Usage: &LoadUserPrefs( $username, \%prefs ); =cut sub LoadUserPrefs { my ($username, $p_prefs) = @_; my $err_msg = ''; Err: { my $UserFile = "$const{'preferences folder'}/accounts/$username.txt"; # Default state: %$p_prefs = ( 'Username' => $username, ); &LoadDefaults( $p_prefs ); my $text = ''; ($err_msg, $text) = &ReadFile( $UserFile ); # For now, it'll just be okay if the file doesn't exist: #next Err if ($err_msg); $err_msg = ''; foreach (split(m!\r?\n!, $text)) { next unless (m!^(.*?)=(.*?)=!); $$p_prefs{$1} = $2; } #reverse compat - added for build 0006 unless ($$p_prefs{'_BUILD'}) { $$p_prefs{'Author:UseQuota'} = 1; if ($username eq $const{'super user'}) { $$p_prefs{'Author:UserFolder'} = $security{'Base Folder'}; $$p_prefs{'Author:UserURL'} = $security{'Base URL'}; } else { $$p_prefs{'Author:UserFolder'} = "$security{'Base Folder'}/%username%"; $$p_prefs{'Author:UserURL'} = "$security{'Base URL'}/%username%"; } } #/reverse compat $$p_prefs{'Author:UserFolder:parsed'} = $$p_prefs{'Author:UserFolder'}; $$p_prefs{'Author:UserFolder:parsed'} =~ s!\%username\%!$username!ig; $$p_prefs{'Author:UserFolder:parsed'} =~ s!/$!!o; $$p_prefs{'Author:UserURL:parsed'} = $$p_prefs{'Author:UserURL'}; $$p_prefs{'Author:UserURL:parsed'} =~ s!\%username\%!$username!ig; $$p_prefs{'Author:UserURL:parsed'} =~ s!/$!!o; } } =item SaveUserPrefs($$$) Usage: my $err_msg = &SaveUserPrefs( $username, \%overrides, $is_login ); =cut sub SaveUserPrefs { my ($username, $p_overrides, $is_login) = @_; my $err_msg = ''; Err: { my $warn_msg = ''; my $UserFile = "$const{'preferences folder'}/accounts/$username.txt"; # Default state: my %prefs = (); &LoadDefaults( \%prefs ); my $text = ''; ($err_msg, $text) = &ReadFile( $UserFile ); # For now, it'll just be okay if the file doesn't exist: #next Err if ($err_msg); $err_msg = ''; foreach (split(m!\r?\n!, $text)) { next unless (m!^(.*?)=(.*?)=!); $prefs{$1} = $2; } # Mix in the overrides: foreach (keys %$p_overrides) { # don't destroy the demo if (($const{'mode'} == 0) and (m!^(allow_cgi|quota|author:)!i)) { $warn_msg = "some fields cannot be updated while in demo mode"; next; } $prefs{$_} = $$p_overrides{$_}; } if ($const{'mode'} == 0) { $prefs{'Author:UseQuota'} = 1; $prefs{'Quota'} = 10000; $prefs{'allow_cgi'} = 0; if ($username eq $const{'super user'}) { $prefs{'Author:UserFolder'} = $security{'Base Folder'}; $prefs{'Author:UserURL'} = $security{'Base URL'}; } else { $prefs{'Author:UserFolder'} = "$security{'Base Folder'}/%username%"; $prefs{'Author:UserURL'} = "$security{'Base URL'}/%username%"; } } # Remove any fields which are not part of the schema: my %schema = (); foreach (@user_attribs_ro, @user_attribs_rw, @user_attribs_internal) { $schema{$_}++; } my @existing_fields = keys %prefs; foreach (@existing_fields) { next if ($schema{$_}); delete $prefs{$_}; } # Set internal properties: $prefs{'Username'} = $username; my $build = 1; if ($VERSION =~ m!(\d+)$!) { $build = 1 * $1; } $prefs{'_BUILD'} = $build; $prefs{'_VERSION'} = $VERSION; if ($is_login) { $prefs{'LastLogin'} = time(); $prefs{'LastLoginFrom'} = &query_env('REMOTE_ADDR'); } $prefs{'AccountCreated'} = time() unless ($prefs{'AccountCreated'}); # Write to disk $text = ''; foreach (sort keys %prefs) { $text .= "$_=$prefs{$_}=\n"; } $err_msg = &WriteFile( $UserFile, $text ); next Err if ($err_msg); $err_msg = $warn_msg if ($warn_msg); } return $err_msg; } =item GetUserPrefs($$) Usage: my $err_msg = &GetUserPrefs( $username, \%STATE ); =cut sub GetUserPrefs { my ($username, $p_STATE) = @_; my $err_msg = ''; Err: { &LoadUserPrefs( $username, $p_STATE ); # Initialize: $$p_STATE{'web_path'} = $$p_STATE{'Author:UserURL:parsed'}; $$p_STATE{'file_path'} = $$p_STATE{'Author:UserFolder:parsed'}; if ($params{'CWD'}) { if ($params{'CWD'} !~ m!\.\.!) { $$p_STATE{'file_path'} .= "/$params{'CWD'}"; $$p_STATE{'web_path'} .= "/$params{'CWD'}"; $const{'admin_url'} .= "CWD=$params{'CWD'}&"; $const{'cwd_line'} = ""; } } unless (chdir($$p_STATE{'file_path'})) { #changed 0007 - reset CWD if error during chdir $params{'CWD'} = ''; $const{'admin_url'} =~ s!(\W)CWD=.*?(\&|$)!$1CWD=$2!os; $const{'cwd_line'} = ""; $err_msg = sprintf( $lang_strings[38], $$p_STATE{'file_path'}, $! ); next Err; } # This code saves LastLogin every hour. It also saves if LastLogin is undef: if ((not $$p_STATE{'LastLogin'}) or (3600 > (time() - $$p_STATE{'LastLogin'}))) { &SaveUserPrefs( $username, $p_STATE, 1 ); } last Err; } return $err_msg; } =item SwitchSort Switch sort method. =cut sub SwitchSort { my %SortTypes = ( 'N' => 'filename', 'n' => 'reverse filename', 'S' => 'size', 's' => 'reverse size', 'D' => 'last modified time', 'd' => 'reverse last modified time', 'T' => 'file type', 't' => 'reverse file type', ); if ($STATE{'Sort'} eq $params{'SortType'}) { $STATE{'Sort'} = lc($params{'SortType'}); } else { $STATE{'Sort'} = $params{'SortType'}; } my %overrides = ( 'Sort' => $STATE{'Sort'}, ); my $err_msg = &SaveUserPrefs( $STATE{'Username'}, \%overrides, 1 ); if ($err_msg) { &Report( sprintf( $lang_strings[2], $err_msg ) ); } else { &Report( sprintf( $lang_strings[4], "now sorting by $SortTypes{$STATE{'Sort'}}" ) ); } } =item LoadDefaults($) Usage: &LoadDefaults( \%STATE ); =cut sub LoadDefaults { my ($p_STATE) = @_; $$p_STATE{'Author:UseQuota'} = 0; $$p_STATE{'Author:UserFolder'} = ''; $$p_STATE{'Author:UserURL'} = ''; $$p_STATE{'Quota'} = 10000; $$p_STATE{'allow_cgi'} = 0; $$p_STATE{'Sort'} = 'Type'; $$p_STATE{'Rows'} = 18; $$p_STATE{'Cols'} = 83; $$p_STATE{'FontSize'} = 10; $$p_STATE{'shell'} = 0; $$p_STATE{'Sound'} = 1; $$p_STATE{'Warn'} = 1; $$p_STATE{'ShowTips'} = 1; $$p_STATE{'ShowDirSize'} = 1; $$p_STATE{'DiskUse'} = 1; $$p_STATE{'TextWrap'} = 1; $$p_STATE{'TextUpload'} = 1; $$p_STATE{'AccountCreated'} = 0; $$p_STATE{'LastLogin'} = 0; $$p_STATE{'LastLoginFrom'} = ''; } =item ShowSettings($$$) Usage: &ShowSettings($username, $is_self, $is_new_user); This function is used to display and edit personal account settings. Non-webmaster users can edit their own settings. Webmaster users can edit their own settings or other's settings. This screen is also used when creating a new user account. =cut sub ShowSettings { my ($username, $is_self, $is_new_user) = @_; my $err_msg = ''; Err: { local $_; my %TMP = (); if ($is_new_user) { &LoadUserPrefs( '_default', \%TMP ); } else { &LoadUserPrefs( $username, \%TMP ); } my $misc_options = ''; my %BooleanPrefs = ( 'Concise' => 'Use Minimal Header Information', 'ShowDirSize' => 'Show Folder Sizes', 'ShowTips' => 'Show Tips and Links', 'DiskUse' => 'Always Show Disk Space', 'Warn' => 'Always Warn Before Deleting', 'Sound' => 'Allow Embedded Sound Clips', ); foreach (keys %BooleanPrefs) { $misc_options .= sprintf('%s', $_, $BooleanPrefs{$_}); } my $sort_options = ''; my %SortTypes = ( 'N' => 'filename', 'n' => 'reverse filename', 'S' => 'size', 's' => 'reverse size', 'D' => 'last modified time', 'd' => 'reverse last modified time', 'T' => 'file type', 't' => 'reverse file type', ); foreach (keys %SortTypes) { $sort_options .= sprintf('