#!/usr/bin/perl
#
# Reads an old reqmap (mapping file for patched ifcico) and an old 
# noreq (list of files in pubdir, which should not inserted to reqmap)
# and generates a new reqmap.new and noreq.new and an additional 
# reqmap.add, which keeps all new files and a first try of a 8+3-conversion.
# The admin should merge reqmap.add to reqmap.new.
#
# $Id: genreqmap,v 2.3 1997/05/14 22:29:11 roland Exp $
#
# Copyright (C) 1996-97 Roland Rosenfeld <roland@spinnaker.rhein.de> 2:2450/42
# 
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
# 
# Many thanks to Franz Ratzinger (2:2487/5012), who added support for 
# files.bbs and sorting and structuring the filelist.
#
# Some small parts of this script are stolen from FidoGate 4.0beta1
# the famous gatewaysoftware written by Martin Junius <mj@fido.de>
#
#############################################################################

$fnet      = "/usr/local/lib/fnet";
$reqmap    = "$fnet/reqmap";
$noreq     = "$fnet/noreq";
$newreqmap = "$reqmap.new";
$newnoreq  = "$noreq.new";
$reqmapadd = "$reqmap.add";
$oldreqmap = "$reqmap.old";
$oldnoreq  = "$noreq.old";
$pubdir    = "/home/ftp/pub/";
$files     = "$pubdir/2450-42.lst";
$filesnew  = "$files.new";
$filesold  = "$files.old";
$fileszip  = "$pubdir/2450-42.zip";
$fileshead = "$fnet/filelist.head";
$filesbbs  = "files.bbs";
$admin     = "news";
$report    = "| /bin/mail -s 'New Fido-Requestmap and generated!' $admin";
$zip       = "/usr/local/bin/zip -kjq";
$nl        = "\r\n";   # End of lines in filelist: 
                       # \r\n for DOS CRLF, \n for Unix LF.

#############################################################################

require "ctime.pl";

#############################################################################

#
# Generating report:
#
open (REPORT, $report) || die "Can't generate $report: $!\n";
print REPORT "===============================================================";
print REPORT "\nNote the following inconsistencies:\n\n";

#
# Read old reqmap and store it into %longtoshort
#
open (REQMAP, $reqmap) || die "Can't open $reqmap: $!\n";
while (<REQMAP>) {
    chop;
    ($shortname,$longname) = split (/\s+/, $_, 2);
    $longname =~ s/$pubdir//;
    $longtoshort{$longname} .= "$shortname ";
}
close (REQMAP);

#
# Read old noreq and store it into %longtoshort as "-"
#
open (NOREQ, $noreq) || die "Can't open $noreq: $!\n";
while (<NOREQ>) {
    chop;
    s/$pubdir//;
    if (!$longtoshort{$_}) {
        $longtoshort{$_} = "-";
    } else {
        print REPORT "File defined in reqmap and noreq: $_\n";
    }
}
close (NOREQ);

#
# Read subdirs of pubdir
#
open (AREAS, "find $pubdir -type d -print|") 
     || die "Can't open find to pipe\n";
while (<AREAS>) {
   chop;
   push (@areas,$_);
}
close (AREAS);
@areas = sort (@areas);

open (NEWREQMAP, ">$newreqmap") || die "Can't open $newreqmap for writing\n";
open (NEWNOREQ, ">$newnoreq") || die "Can't open $newnoreq for writing\n";
open (REQMAPADD, ">$reqmapadd") || die "Can't open $reqmapadd for writing\n";
open (FILESNEW, ">$filesnew") || die "Can't open $filesnew for writing\n";

#
# Generate Filelist-Header
#
open (FILESHEAD, "$fileshead") || die "Can't open $fileshead for reading\n";
while (<FILESHEAD>) {
    chop;
    print FILESNEW "$_$nl";
}
close (FILESHEAD);
print FILESNEW "$nl"."Generated: ";
print FILESNEW &ctime(time),"$nl";

#
# Search in every directory
#
foreach $i (@areas) {
   @files = ();

   open (FIND, "find $i -maxdepth 1 -type f -print|") 
        || die "Can't open find to pipe\n";

   #
   # Find out, which files really exist
   # (Files in $pubdir first!)
   #
   while (<FIND>) {
      chop;
      if ( /\/files.bbs$/ ) {
         # %filesbbs = ();
         open (FILESBBS, "$_") || die "Cant't open files.bbs\n";
	 while (<FILESBBS>) {
	    chop;
	    ($filename, $remainder) = split (/\s+/, $_, 2);
	    $remainder =~ s/^\s+//;
            $remainder =~ s/\r+$//;
            $remainder = &wrapdescription($remainder);
            $filesbbs{$filename} = $remainder;
	 }
	 close FILESBBS;
	 next;
      }
      elsif (/\/files.new$/) {
         next;
      }
      push (@files,$_);
    }
    
    foreach (@filesbbs) {
       print "$_\n";
    }
    
    close FIND;
    
    @files = sort (@files);

    $a = @files;
    if (!$a) {
       next;
    }

   $i =~ s/$pubdir//;
   print FILESNEW "$nl";
   print FILESNEW "=========================================================";
   print FILESNEW "$nl~/$i$nl";
   print FILESNEW "=========================================================";
   print FILESNEW "$nl";

    foreach (@files) {
       s/$pubdir//;
       $longname = $_;
       if (!$longtoshort{$longname}) {
          print REQMAPADD &translate($longname) . "\t$longname\n";
       } else {
          if ($longtoshort{$longname} eq "-") {
             print NEWNOREQ "$longname\n";
          } else {
             foreach $oneshort (split (/ /, $longtoshort{$longname})) {
                $oneshort =~ tr/A-Z/a-z/;
                print NEWREQMAP "$oneshort\t$longname\n";
                $shorttolong{$oneshort} .= "$longname ";
                ($x,$x,$x,$x,$x,$x,$x,$size,$x,$time,$x,$x,$x) 
                    = stat("$pubdir/$longname");
                printf(FILESNEW "%-12s %s %s ~/%s$nl", 
                       &toupper($oneshort), &ascdate($time), &ksize($size),
                       $longname);
		$index = $longname;
		$index =~ s/(.*)\/(.*)/\2/;
		if ($filesbbs{$index}) {
		   print FILESNEW "$filesbbs{$index}";
		}
             }
          }
          delete $longtoshort{$longname};
       }
    }
}

# 
# Now test the other files:
#
foreach $longname (sort keys(%longtoshort)) {
    if ( -f $longname ) {
        if ($longtoshort{$longname} =~ /^-$/) {
            print REPORT "removing $longname from noreq-Liste\n";
        } else {
            foreach $oneshort (split (/ /, $longtoshort{$longname})) {
                print NEWREQMAP "$oneshort\t$longname\n";
                $shorttolong{$oneshort} .= "$longname ";
                ($x,$x,$x,$x,$x,$x,$x,$size,$x,$time,$x,$x,$x) 
                    = stat("$longname");
                printf(FILESNEW "%-12s %s %s %s$nl", 
                       &toupper($oneshort), &ascdate($time), &ksize($size),
                       $longname);
            }
        }
    } else {
        print REPORT "$longname no longer exists\n";
    }
}

close NEWREQMAP;
close NEWNOREQ;
close REQMAPADD;

$rcsfile ='$RCSfile: genreqmap,v $';
$rcsfile =~ s/^\$RCSfile: genreqmap,v $$/$1/; 
$revision ='$Revision: 2.3 $';
$revision =~ s/\$Revision: 2.3 $$/$1/;

print FILESNEW "$nl$nl"."Filelist generated by $rcsfile $revision$nl";
print FILESNEW "written by Roland Rosenfeld <roland\@spinnaker.rhein.de> ";
print FILESNEW "2:2450/42$nl";
print FILESNEW "adapted by Franz Ratzinger 2:2487/5012$nl";

close FILESNEW;

print REPORT "\n\n\n";
print REPORT "===============================================================";

print REPORT "\n\nThere may be some duplicate names in the (old) mapfile:\n\n";

foreach $short (sort keys(%shorttolong)) {
    if ($shorttolong{$short} =~ / .* /) { 
        @longlist = split (/ /, $shorttolong{$short});
        foreach $long (@longlist) {
            print REPORT "$short\t$long\n";
        }
    }
}

print REPORT "\n\n\n";
print REPORT "===============================================================";

print REPORT "\n\nGenerated $newreqmap and $newnoreq\n";
print REPORT "from $reqmap and $noreq.\n\n";

print REPORT "The following files seem to be new in your archive, please add";
print REPORT "\nthem to your reqmap.\n\n";

open (REQMAPADD, $reqmapadd) || die "Can't open $reqmapadd for reading\n";
while (<REQMAPADD>) {
    print REPORT $_;
}
close (REQMAPADD);

close REPORT;

rename ($reqmap, $oldreqmap);
rename ($newreqmap, $reqmap);
rename ($noreq, $oldnoreq);
rename ($newnoreq, $noreq);
rename ($files, $filesold);
rename ($filesnew, $files);

system ("$zip $fileszip $files");

exit(0);



#############################################################################

sub translate {
    local($long) = @_;
    local($name,$ext);

    $long =~ s/^.*\///;

    $long =~ s/\.tar.gz/.tgz/;
    $long =~ s/-tar.gz/.tgz/;
    $long =~ s/\.tar.z/.tgz/;
    $long =~ s/\.tar.Z/.taz/;
    $long =~ s/\.ps.gz/.pgz/;
    $long =~ s/\.doc.gz/.dgz/;
    $long =~ s/\.diff.gz/.dgz/;
    $long =~ s/\.patch.gz/.pgz/;
    $long =~ s/\.el.gz/.egz/;
    $long =~ s/\-mini-HOWTO.gz/.h2z/;
    $long =~ s/\-HOWTO.gz/.h2z/;
    
    $name = $long;
    $ext = "";
    if( $long =~ /^(.*)\.([^.]*)$/ ) {
        $name = $1;
        $ext  = $2;
    }

    $name =~ tr/A-Z/a-z/;
    $ext  =~ tr/A-Z/a-z/;
    
    $name =~ s/\.//g;
    if (length($name)>8) {
        $name =~ s/[^a-z0-9]//g;
    }
    if (length($ext)>3) {
        $ext =~ s/[^a-z0-9]//g;
    }

    $ext =~ s/^(...).*$/$1/;
    
    while ( (length($name)>8) && ($name =~ /[a-z]/) ) {
        $name =~ s/[a-z]([0-9]*)$/$1/;     # remove last character
    }
    
    $name =~ s/^(.{8}).*$/$1/;
    
    return ($ext ? "$name.$ext" : $name);
}


sub ascdate {
    local($time) = @_;

    if($time eq "") {
        return "        ";
    } else {
        local($yr, $mn, $dy, $h, $m, $s, $xx);
        ($s,$m,$h,$dy,$mn,$yr,$xx,$xx,$xx) = localtime($time);
        
        return sprintf("%02d.%02d.%02d", $dy,$mn+1,$yr, $h,$m);
    }
}


sub ksize {
    local($size) = @_;
    local($k);

    if($size eq "") {
        return "   N/A";
    }
    else {
        if($size == 0) {
            $k = 0;
        } elsif($size <= 1024) {
            $k = 1;
        } elsif($size < (1024*10000)) {
            $k = $size / 1024;
        } else {
            # if file > 9999K, write "12.3M":
            return sprintf ("%4.1fM", $size/(1024*1024));
        }
        return sprintf("%4dK", $k);
    }
}


sub toupper {
    local($name) = @_;
    $name =~ tr/a-z/A-Z/;
    return $name;
}

sub dos2ascii {
    # convert DOS umlauts to 7bit ASCII
    local($line) = @_;
    $line =~ s/\x84/ae/g;
    $line =~ s/\x94/oe/g;
    $line =~ s/\x81/ue/g;
    $line =~ s/\x8e/Ae/g;
    $line =~ s/\x99/Oe/g;
    $line =~ s/\x9a/Ue/g;
    $line =~ s/\xe1/ss/g;
    return $line;
}

sub wrapdescription {
    local($description) = @_;
    local($blanks) = "                            ";
    local($result) = "";
    local($prefix, $pos, $tempstring);

    $description = &dos2ascii($description);

    while ( length ($description) > 0 ){
       $prefix = substr ($description, 0, 50);

       if (length($prefix) == 50) { # continue wrapping
          $pos = int (rindex ($prefix," "));
          $tempstring = substr ($description,0,$pos);
          $description = substr ($description,$pos);
       } else { # done
          $pos = length($prefix);
          $tempstring = substr ($description,0,$pos);
          $description = "";
       }

       $result = sprintf ("%s%s%s$nl",$result,$blanks,$tempstring);
       $description =~ s/^[\s\r]+//;
    }
    return $result;
}

#############################################################################
#
# ToDo:
# 
# - remove duplicates from files.bbs
# - find new files and announce them via news or mail
#
