#!/usr/bin/perl # # stopwatch.pl # # Usage: # # % perl stopwatch.pl [ OPTIONS ] DIRECTORY # # -v,--version Print version and exit. # -h,--help Prints this text. # -V,--verbose Displays more information while running. # -p,--port NUMBER Sets the server port (default 2020). # -s,--seconds NUMBER Sets the timelimit to NUMBER seconds. # -m,--minutes NUMBER Sets the timelimit to NUMBER minutes. # -g,--generate Generates index.html in the DIRECTORY. # -F,--ftp Sets the server type to FTP. # -H,--http Sets the server type to HTTP (the default). # use strict; use warnings; use POE; use POE::Component::Server::FTP; use POE::Component::Server::HTTPServer; use Filesys::Virtual; use Proc::Simple; use File::Basename; use Getopt::Mixed "nextOption"; my $option; my $value; # FTP Settings my $FTPD_DOMAIN = 'localhost'; my $FTPD_VERSION = "$0"; my $DOWNLOAD_LIMIT = 50; # In kb/s my $UPLOAD_LIMIT = 100; my $TIMEOUT = 120; my $ANONYMOUS = 'allow'; # General Settings my $VERSION = "0.1"; my $APPNAME = "Stopwatch"; my $SETTINGS_PORT = 2020; my $TIMELIMIT = 300; my $MODE = 2; # 1=FTP, 2=HTTP my $VERBOSE = 0; my $GENERATE_INDEX = 0; # =========== # MAIN SCRIPT # =========== Getopt::Mixed::init( "v version>v h help>h d p=i port>p s=i seconds>s m=i minutes>m F ftp>F H http>H V verbose>V g generate>g" ); while ( ( $option, $value ) = nextOption() ) { if ( $option =~ /v/ ) { print "$VERSION\n"; exit; } if ( $option =~ /p/ ) { $SETTINGS_PORT = $value; } if ( $option =~ /s/ ) { $TIMELIMIT = $value; } if ( $option =~ /m/ ) { $TIMELIMIT = $value * 60; } if ( $option =~ /F/ ) { $MODE = 1; } if ( $option =~ /H/ ) { $MODE = 2; } if ( $option =~ /V/ ) { $VERBOSE = 1; } if ( $option =~ /g/ ) { $GENERATE_INDEX = 1; } if ( $option =~ /h/ ) { Usage(); } } Getopt::Mixed::cleanup(); if ( $#ARGV != 0 ) { print "ERROR: No directory named.\n"; exit; } my $HOSTED_DIRECTORY = $ARGV[0]; if ( !( -e $HOSTED_DIRECTORY ) ) { print "ERROR: Directory doesn't exist.\n"; exit; } if ( ( -f $HOSTED_DIRECTORY ) ) { print "ERROR: Directory expected, file found.\n"; exit; } Print_Verbose("$APPNAME $VERSION\n"); if ( $MODE == 1 ) { # FTP Mode Print_Verbose("Starting FTP daemon on port $SETTINGS_PORT..."); my $ftpd_proc = Proc::Simple->new(); $ftpd_proc->start( \&ftpd, $HOSTED_DIRECTORY, $SETTINGS_PORT ); Print_Verbose("done!\nLifetime set to $TIMELIMIT seconds.\nRunning..."); sleep $TIMELIMIT; Print_Verbose("done!\nShutting down daemon..."); $ftpd_proc->kill(); Print_Verbose("done!\n"); } elsif ( $MODE == 2 ) { if ( $GENERATE_INDEX == 1 ) { Print_Verbose("Generating $HOSTED_DIRECTORY/index.html..."); GenerateIndex($HOSTED_DIRECTORY); Print_Verbose("done!\n"); } Print_Verbose("Starting HTTP daemon on port $SETTINGS_PORT..."); my $httpd_proc = Proc::Simple->new(); $httpd_proc->start( \&httpd, $HOSTED_DIRECTORY, $SETTINGS_PORT ); Print_Verbose("done!\nLifetime set to $TIMELIMIT seconds.\nRunning..."); sleep $TIMELIMIT; Print_Verbose("done!\nShutting down daemon..."); $httpd_proc->kill(); Print_Verbose("done!\n"); } exit; # ============ # SUPPORT SUBS # ============ sub Usage { print "$0 [ OPTIONS ] DIRECTORY\n\n"; print "-v,--version Print version and exit.\n"; print "-h,--help Prints this text.\n"; print "-V,--verbose Displays more information while running.\n"; print "-p,--port NUMBER Sets the server port (default 2020).\n"; print "-s,--seconds NUMBER Sets the timelimit to NUMBER seconds.\n"; print "-m,--minutes NUMBER Sets the timelimit to NUMBER minutes.\n"; print "-g,--generate Generates index.html in the DIRECTORY.\n"; print "-F,--ftp Sets the server type to FTP.\n"; print "-H,--http Sets the server type to HTTP (the default).\n"; print "\n"; print "The default timelimit is 5 minutes (300 seconds).\n"; print "Generated index.html will OVERWRITE any index.html in\n"; print "the target directory.\n"; exit; } sub Print_Verbose { my ($text) = @_; if ( $VERBOSE == 1 ) { print $text; } } sub ftpd { my ( $directory, $port ) = @_; POE::Component::Server::FTP->spawn( Alias => 'ftpd', ListenPort => $port, Domain => $FTPD_DOMAIN, Version => $FTPD_VERSION, AnonymousLogin => $ANONYMOUS, FilesystemClass => 'Filesys::Virtual::Plain', FilesystemArgs => { 'root_path' => $directory, 'cwd' => '/', 'home_path' => '/', }, # use 0 to disable these Limits DownloadLimit => ( $DOWNLOAD_LIMIT * 1024 ), UploadLimit => ( $UPLOAD_LIMIT * 1024 ), LimitSceme => 'ip', LogLevel => 1, # 4=debug, 3=less info, 2=quiet, 1=really quiet TimeOut => $TIMEOUT, ); $poe_kernel->run(); } sub httpd { my ( $directory, $port ) = @_; my $server = POE::Component::Server::HTTPServer->new(); $server->port($port); $server->handlers( [ '/' => new_handler( 'StaticHandler', $directory ), ] ); my $svc = $server->create_server(); $poe_kernel->run(); } sub GenerateIndex { my ($directory) = @_; open( FILE, ">$directory/index.html" ) or die "Error creating index"; print FILE BuildIndex($directory); close FILE; } sub BuildIndex { my ($directory) = @_; my @f = GetFileList($directory); my $index = "HTTPD - $0 - " . basename($directory) . "\n"; $index .= "

Contents of " . basename($directory) . "

\n"; $index .= "\n"; $index .= "Created automatically by $0
\n"; $index .= "\n"; return $index; } sub GetFileList { my ($directory_name) = @_; my @file_list = (); opendir( TDIR, "$directory_name" ) or die "Error opening directory $directory_name."; my @tdir = grep { -f "$directory_name/$_" } readdir(TDIR); closedir(TDIR); foreach my $ent (@tdir) { if ( $ent =~ /index.html/ ) { } else { push( @file_list, "$ent" ); } } return @file_list; }