#!/bin/perl -w
#
# reqdir server for XFBB 7.01+
# Author:   Stewart Wilkinson G0LGS
#

#
# Nothing below should need changing (unless it needs fixing :-)
#

# Version Information
##VERSION##
##VERDATE##
$Version="*** REQDIR for XFBB 7.01+ (by G0LGS V${Vers} ${VDate}) ***";

# if NO Args assume script was run from command line
# so display Version information & exit with none 0 status.
if( $#ARGV < 0 ) {
   print "$Version\n";
   exit 1;
}

$Filename = $ARGV[0];

# Where is FBB Setup File
$INIT="/etc/ax25/fbb.conf";

if( defined( $ENV{FBBCONF} ) && "$ENV{FBBCONF}" != "" ){
   $INIT = $ENV{FBBCONF}
}

# Read things we need from Setup File
if(! open(CONFIG, $INIT) ) {
   print STDERR "Unable to open $INIT\n";
   exit 1;
}

while($line = <CONFIG>) {

   chomp($line);

   if( $line =~ /^\s*\#/) {
      next;

   }elsif( $line =~ /^\s*$/) {
      next;

   }else{
      $line =~ /^\s*(\S*)\s*\=\s*(.*)$/;
      $item = $1;
      $value = $2;

      if( $item =~ /^call/ ){
         $value =~ /^(\w*)\.(.*)$/;
         $BBSCALL = $1;
         $BBSHR = $2;

      }elsif( $item =~ /^qral/ ){
         $value =~ /^(\S*)$/;
         $LOC=$1;

      }elsif( $item =~ /^city/ ){
         $value =~ /^(\S*)$/;
         $QTH = $1;

      }elsif( $item =~ /^conf/ ){
         $value =~ /^(\S*)$/;
         $CONF = $1;

      }elsif( $item =~ /^fbbd/ ){
         @DIRS=split( /,/ , $value);

         $DP='A';
         foreach $D (@DIRS) {
            push( @PUBLIC, $D);
            if( ($D !~ /\*/) && ! defined(${PUB}) ){
               ${PUB} = ${D};
               ${DRV} = ${DP};
            }
            $DP++;
         }

      }elsif( $item =~ /^name/ ){
         $value =~ /^(\S*)$/;
         $NAME = $1;

      }elsif( $item =~ /^syso/ ){
         $value =~ /^(\S*)$/;
         $SYSCALL = $1;

      }elsif( $item =~ /^impo/ ){
         $value =~ /^([^\.]\S*)\.(\S*)$/;
         $MAIL = "$1.$2";
         $LOCK = "$1.lck";
 
      }

   }

}

close(CONFIG);

# REQDir Help
${ReqDirHelp}="$CONF/reqdir.help";
${ReqDirErr}="$CONF/reqdir.err";
${ReqDirTail}="$CONF/reqdir.tail";

if( ! open( MSG, "< ${Filename}" ) ){
   printf STDERR "Unable to Read Message\n";
   exit 1;
}

# Ok - Now Read Things we Need from The incoming Message

# Sender
chomp($Sender = <MSG>);

if( $Sender =~ /^SP\s+(\w*)\s+\<\s+(\w*)/ ){
   $To = $1;	# This should be us !
   $From = $2;
}else{
   printf STDERR "REQDIR Error Reading Sender Information\n";
   exit 1;
}

# Subject (Path/FileName [@ BBSCALL])
chomp($Subject = <MSG>);

close(MSG);
#unlink(${Filename});

# Check for Return BBS
if( ${Subject} =~ /^\s*(\S+)\s+\@\s+(.*)$/ ){
   ${Subject} = $1;
   ${Dest} = $2;
}

${REQDIR} = ${Subject};

# change FBBDOS Drive letter to the real Unix path
if( ${REQDIR} =~ /^(\S)\:(\S*)/ ){

   ${DPATH} = ${REQDIR};

   $P = $2;
   ($D = $1) =~ tr/[a-z]/[A-Z]/;
   ${Drv} = ord($D) - 64;

   if( $P =~ /^\\(\S*)/ ){
      $P = $1;
   }

   if( $P =~ /^\/(\S*)/ ){
      $P = $1;
   }

   $d=1;
   foreach $Pub (@PUBLIC) {
      if( ${Drv} == ${d} ){
         if( $Pub =~ /\*/ ) {
            $NoPath = 1;
         }else{
            ${ReqDir} = ${Pub} . ${P};
         }
      }
      $d++;
   }

}else{
      ${ReqDir} = ${PUB} . ${REQDIR};
      ${DPATH} = ${DRV} . ":\\" . ${REQDIR};
}


# Make sure the Path is in '*nix' format

# translate DOS '\' chars to '/' 
${ReqDir} =~ tr /\\/\//;

# Remove any // sequences
while( ${ReqDir} =~ /(.*)\/\/(.*)/ ){
    ${ReqDir} = $1 . "/" . $2;
}

# Check for '../' sequences.
if( ${ReqDir} =~ /.*\.\.\/.*/ ){
   ${NoPath} = 1;
}

# Ok Lets Generate the Relpy Message.

if( open( LOCK, "> ${LOCK}" ) ) {

   printf LOCK "$$";

   if( open(MAIL,">> ${MAIL}" ) ) {

      if( defined(${Dest}) ){
         printf MAIL "#\nSP %s \@ %s < %s\n", ${From}, ${Dest}, ${BBSCALL};
      }else{
         printf MAIL "#\nSP %s < %s\n", ${From}, ${BBSCALL};
      }

      printf MAIL "REQDIR: %s\n", ${Subject};

      # Start the Message Content.
      print MAIL "\n";
      print MAIL "$Version\n\n";

      if( "$Subject" eq "?" ){
         print MAIL "\tREQDIR HELP\n\n";

         # Send the HELP
         if( open(HELP,"<$ReqDirHelp") ){
            print MAIL <HELP>;
            close(HELP);
         }

      }else{

         # Now Add The Dir Listing ?
         print MAIL " Requested directory: $Subject\n\n";

         if( defined($NoPath) ){
            print MAIL "\n\"$Subject\" is an Invalid Path !\n\n";
            # Add any ERROR HELP
            if( open(ERR,"<$ReqDirErr") ){
               print MAIL <ERR>;
               close(ERR);
            }

         }else{

            # Deal with Directory Name
            if( -d "$ReqDir" ){ 

               if( chdir($ReqDir) ){
                  &ShowDir($ReqDir);

               }else{
                  print MAIL "The REQDIR server encountered and unexpected Error while Processing\n";
                  print MAIL "your request - Please inform the Sysop ${SYSCALL}\@${BBSCALL}\n\n";

                  # Add any ERROR HELP
                  if( open(ERR,"<$ReqDirErr") ){
                     print MAIL <ERR>;
                     close(ERR);
                  }
               }

            # Deal with File Name Options
            }else{

               $ReqDir =~ /(.*)\/([^\/]+)$/;
               $NewDir = $1;
               $NewFile = $2;
               if( ! -d "$NewDir" ){
                  $BadPath=1;

               }elsif(chdir($NewDir)){ 

                  &ShowSelectedFiles($NewDir, $NewFile);

               }else{
                  print MAIL "The REQDIR server encountered and unexpected Error while Processing\n";
                  print MAIL "your request - Please inform the Sysop ${SYSCALL}\@${BBSCALL}\n\n";

                  # Add any ERROR HELP
                  if( open(ERR,"<$ReqDirErr") ){
                     print MAIL <ERR>;
                     close(ERR);
                  }
               }
            }

            if( defined($BadPath) ){
               print MAIL "No Such File or Directory \"$Subject\" !\n\n";
               # Add any ERROR HELP
               if( open(ERR,"<$ReqDirErr") ) {
                  print MAIL <ERR>;
                  close(ERR);
               }

            }elsif(defined($Match)){
               print MAIL "\n\n";
 
               # Add any Tail
               if( open(TAIL,"<$ReqDirTail") ){
                  print MAIL <TAIL>;
                  close(TAIL);
               }
            }
         }
      }
      print MAIL "\n\n";

      if( defined(${NAME}) ){
         print MAIL "\n**** 73s ${NAME}";

         if( defined($SYSCALL) ){
            print MAIL " (${SYSCALL})";
         }

         print MAIL " Sysop ${BBSCALL}";

      }else{

         print MAIL "\nFrom ${BBSCALL}\n\n";
      }

      if( defined(${QTH}) ){
         print MAIL " ${QTH}";
      }

      print MAIL " ****\n\n";

      print MAIL "\/EX\n";
      close(MAIL);

   }else{
      printf STDERR "Unable to Open ${MAIL}\n";
   }

   close(LOCK);
   unlink(${LOCK});

}else{

   printf STDERR "Unable to Create Lock '${LOCK}'\n";

}

exit 0;

sub ShowFile{

   local( $file ) = @_;

   ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
   $atime,$mtime,$ctime,$blksize,$blocks)
   = stat($file);

   $T=&DateTime($mtime);

   if( -d "$file" ){
         $Line= sprintf( "   %-20s %-7s %s\n", $file, "<DIR>", $T);
   }else{
      if( $size <= 9999 ){

         $Line= sprintf( "   %-20s %-7d %s\n", $file, $size, $T);
      }elsif( $size <= 999999 ) {

         $size = ($size / 1024) +0.5;
         $S = sprintf( "%dK", $size);
         $Line= sprintf( "   %-20s %-7s %s\n", $file, $S, $T);
      }else{

         $size = (($size / 1024) / 1024) +0.5;
         $S = sprintf( "%dM", $size);
         $Line= sprintf( "   %-20s %-7s %s\n", $file, $S, $T);
      }
   }

   print MAIL $Line;

}

sub ShowDir{

   local( $Dir ) = @_;

   if( opendir(DIR,"$Dir") ) {
      @files=readdir(DIR);
      closedir(DIR);
      shift(@files);
      $num_files=@files;

      foreach $file (sort @files){

         if( ("$file" eq ".") || ("$file" eq "..") || ($file =~ /^\.\S*/) ) {
            next;
         }

         if( -r "$file" ){
            $Match=1;
            &ShowFile($file);
         }
      }

    }else{
       $BadPath=1;     
    }
}

sub ShowSelectedFiles{

   local( $Dir, $Sfiles ) = @_;

   # Lets build a REXPR from the supplied name

   # Replace '.' with '\.'
   if( $Sfiles =~ /.*[^\\]\..*/ ){
      while( $Sfiles =~ /(.*[^\\])\.(.*)/ ){
         $Sfiles = $1 . "\\." . $2;
      }
   }

   # Replace '*' with '|'

   if( $Sfiles =~ /.*\*.*/ ){
      while( $Sfiles =~ /(.*)\*(.*)/ ){
         $Sfiles = $1 . "|" . $2;
      }
   }

   # Replace '|' with '\S*'

   if( $Sfiles =~ /.*\|.*/ ){
      while( $Sfiles =~ /(.*)\|(.*)/ ){
         $Sfiles = $1 . "\\S*" . $2;
      }
   }

   # Replace '?' with '\S{1}'

   if( $Sfiles =~ /.*\?.*/ ){
      while( $Sfiles =~ /(.*)\?(.*)/ ){
         $Sfiles = $1 . "\\S{1}" . $2;
      }
   }


   if( opendir(DIR,"$Dir") ) {
      @files=readdir(DIR);
      closedir(DIR);
      shift(@files);
      $num_files=@files;

      foreach $file (sort @files){

         if( ("$file" eq ".") || ("$file" eq "..") || ($file =~ /^\.\S*/) ) {
            next;
         }

         if( $file !~ /^${Sfiles}/ ){
            next;
         }

         if( -r "$file" ){
            $Match=1;
            &ShowFile($file);
         }
      }

    }else{
       $BadPath=1;     
    }

    if( !defined($Match) ){
       print MAIL "No Matching Files Found !!\n";
    }
}

sub DateTime{

   local( $Ctime ) = @_;

   ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime($Ctime);

   $Yr = $year + 1900;
   $yr = ('00'..'99')[$year % 100];
   $Mt = ( 'Jan','Feb','Mar','Apr','May','Jun',
           'Jul','Aug','Sep','Oct','Nov','Dec')[$mon];
   $Mn = ('01'..'12')[$mon];
   $Dy = ('00'..'31')[$mday];
   $Hr = ('00'..'23')[$hour];
   $Mi = ('00'..'59')[$min];
   $Sc = ('00'..'59')[$sec];

#   $Time = "${Hr}:${Mi} ${Dy}-${Mt}-${Yr}";
   $Time = "${Hr}:${Mi} ${Dy}/${Mn}/${yr}";

   $Time;
}

