Import of revision 19941207
authorceo <ceo>
Wed, 7 Dec 1994 05:00:00 +0000 (00:00 -0500)
committerceo <ceo>
Wed, 7 Dec 1994 05:00:00 +0000 (00:00 -0500)
[This revision is between those in RCS -- Michael Spang]

14 files changed:
Gopher.pl [new file with mode: 0644]
admin.pl [new file with mode: 0644]
cashbox.pl [new file with mode: 0755]
ceo
database.pl [new file with mode: 0644]
forms.pl [new file with mode: 0755]
lib_sys.pl [new file with mode: 0644]
libfmt.pl [new file with mode: 0644]
main.pl [new file with mode: 0644]
member.pl [new file with mode: 0644]
misc.pl [new file with mode: 0644]
novelty.pl [new file with mode: 0644]
quota.pl [new file with mode: 0644]
stats.pl [new file with mode: 0644]

diff --git a/Gopher.pl b/Gopher.pl
new file mode 100644 (file)
index 0000000..cc81f8a
--- /dev/null
+++ b/Gopher.pl
@@ -0,0 +1,141 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/11/20             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub Gopher_Quota
+{
+    local($useQUOTALOG) = $QUOTALOG;
+    if ($NEXTTERMQUOTA)
+    {
+        $useQUOTALOG = $NEXTQUOTALOG;
+    }
+    open (QLOG, $useQUOTALOG) || do
+    {
+        print "\n${beep}Unable to open quota log file: $!\n";
+        return;
+    };
+    dbmopen(QUOTA,$QUOTADB,0600) || do
+    {
+        print "\n${beep}Unable to open quota database: $!\n";
+        close(QLOG);
+        return;
+    };
+    %Quota = ();
+    while(<QLOG>)
+    {
+        next if (/^\s*$/ || /^\s*#/);
+        ($qdate, $quid, $qamt, $qtot, $qleft) = split(/;/);
+        next if $quid eq "csc@math";
+        $Quota{$QUOTA{$quid}} = $qtot;
+    }
+    close(QLOG);
+    $qleft =~ s/\D//g;
+    open (GOPQUOTA, ">$GOPHERDIR/quota_log") || do
+    {
+        print "\n${beep}Unable to open output file: $!\n";
+        return;
+    };
+    select(GOPQUOTA);
+    $-=0;
+    $= = 50000;
+    foreach $qnum (sort {$a<=>$b} keys %Quota)
+    {
+        ($qname, $qsid, $quid) = split(/;/,$QUOTA{$qnum});
+        $qqta = $Quota{$qnum};
+        write;
+    }
+    dbmclose(QUOTA);
+    print "\nQuota remaining: $qleft MB\n";
+    select(STDOUT);
+    close(GOPQUOTA);
+#   system <<EOJ;
+#rcp $editfile csc_disk@descartes:Gopher/office_info/quota_log
+#EOJ
+}
+
+sub Gopher_Members
+{
+    local($nummems);
+    open (GOPMEMBER, ">$GOPHERDIR/members_list") || do
+    {
+        print "\n${beep}Unable to open output file: $!\n";
+        return;
+    };
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open member database: $!\n";
+        close(SCRMEMBER);
+        return;
+    };
+    select(GOPMEMBER);
+    $-=0;
+    $= = 50000;
+    $nummems=0;
+    foreach $memnum (sort {$a<=>$b} split(/,/,$MEM{$TERM}))
+    {
+        ($memname,$memsid,$memprog,$memphone,$memuid,$mempw,$memdate,$memterms)
+            = split(/;/,$MEM{$memnum});
+        write;
+        ++$nummems;
+    }
+    &fakedbmclose($MEMDB,%MEM);
+    print "\nTotal: $nummems\n";
+    select(STDOUT);
+    close(GOPMEMBER);
+#   system <<EOJ;
+#rcp $editfile csc_disk@descartes:Gopher/office_info/members_list
+#EOJ
+}
+
+sub Gopher_Outstanding
+{
+ ## Read the library file
+    dbmopen(LIB, $LIBDB, 0600) || do
+    {
+        print "\n${beep}Error opening library database: $!\n";
+        return;
+    };
+    %Outstand = ();
+    foreach $bid (keys %LIB)
+    {
+        ($whohas) = $LIB{$bid} =~ /W\{(\d+)\}/;
+        next if $whohas == 0;
+        ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
+        ($bodate) = $LIB{$bid} =~ /D\{([^\}]*)\}/;
+        $Outstand{$bid}="$whohas#$btitle#$bodate";
+    }
+    dbmclose(LIB);
+
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Error opening members database: $!\n";
+        return;
+    };
+    open (OUTSTAND, ">$GOPHERDIR/library_outstand") || do
+    {
+        print "\n${beep}Unable to open outstanding books file: $!\n";
+        &fakedbmclose($MEMDB,%MEM);
+        return;
+    };
+    select(OUTSTAND);
+    $-=0;
+    $= = 50000;
+    foreach $obid (keys %Outstand)
+    {
+        ($onum,$obtitle,$odate) = $Outstand{$obid} =~ /^(.*)#(.*)#(.*)$/;
+        $oname = (split(/;/,$MEM{$onum}))[0];
+        write;
+    }
+    &fakedbmclose($MEMDB,%MEM);
+    select(STDOUT);
+    close(OUTSTAND);
+#   &MakeOutstandFile(50000);
+#   system <<EOJ;
+#rcp $editfile csc_disk@descartes:Gopher/office_info/library_outstand
+#EOJ
+}
+
+1;
diff --git a/admin.pl b/admin.pl
new file mode 100644 (file)
index 0000000..2c2abab
--- /dev/null
+++ b/admin.pl
@@ -0,0 +1,326 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/11/20             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+
+sub adminmenu
+{
+    local($menu) = <<EOM;
+
+Choose an option:
+  (P)assword change
+  Member (I)nfo change
+  (L)ibrary log (NOT the outstanding books)
+  (S)ync gopher entries
+  (R)eset ceo
+  (A)ccount request
+  (M)ain menu
+
+(P,I,L,S,R,M): 
+EOM
+    @opts=('pdopwchange','idoupdatemember', 'ldoliblog',
+            'sdosyncgopher','rdoreset','adoaccount','mmainmenu');
+    $choice = &domenu($menu,@opts);
+    return $choice;
+}
+
+sub doaccount
+{
+    local($memnum,$template,$forterm,$match);
+       local($init_passwd,$gcos,$username,$date,$thepw);
+    print "Enter CSC member number: ";
+    chop($memnum=<STDIN>);
+    $memnum =~ s/\D//g;
+    if ($memnum =~ /^\s*$/)
+    {
+        print "\n${beep}No member number supplied - aborting.\n";
+        return;
+    }
+
+    ## Get the info on this member
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open member database: $!\n";
+        return;
+    };
+    unless (defined $MEM{$memnum})
+    {
+        print "\n${beep}No such member number is on record - aborting\n";
+        &fakedbmclose($MEMDB,%MEM);
+        return;
+    }
+       $forterm = $NEXTTERMMEMBER ? $NEXTTERM : $TERM;
+    $match = grep(/^$forterm$/,split(/,/,(split(/;/,$MEM{$memnum}))[7]));
+    unless ($match)
+    {
+        print "\n${beep}This member has not paid for the current term.\n";
+        &fakedbmclose($MEMDB,%MEM);
+        return;
+    }
+    $template = $MEM{$memnum};
+       $thepw = (split(/;/,$template))[5];
+    &fakedbmclose($MEMDB,%MEM);
+
+       ## Check the password
+    if ($thepw ne "" && $ENV{'CALUM'} != 1)
+    {
+        print "Enter your CSC password: ";
+        if (crypt(&GetPass, $thepw) ne $thepw)
+        {
+            print "\n${beep}Incorrect password - aborting\n";
+            return;
+        }
+    }
+
+       print <<EOM;
+
+You are about to request on account on calum.  You must agree to
+the following:
+
+o I am a member of the University of Waterloo community.
+
+o I am a member of the University of Waterloo Computer Science Club.
+
+o I have read, have signed, and will adhere to the CSC User Agreement
+  of 17 Apr, 1994.
+
+To agree to these terms, answer "yes" below.
+
+EOM
+       print "I agree to the above terms: ";
+       $yes = <STDIN>;
+       if ($yes ne "yes\n")
+       {
+               print "${beep}Aborting.\n\n";
+               return;
+       }
+
+       ## Tell them about the password
+
+       print "\nYour initial password will be your CSC password, and you will\n";
+       print "be required to change it the first time you log in.\n\n";
+
+       $init_passwd = (split(/;/,$template))[5];
+
+       if ($init_passwd eq "")
+       {
+               print "${beep}You do not have a CSC password.  Please choose one.\n\n";
+               print "Aborting.\n\n";
+               return;
+       }
+
+       $gcos = (split(/;/,$template))[0];
+
+       ## Okay, here's the hard part:  figure out an account name for them
+
+       ## Start with one they gave, if possible
+       $username = (split(/;/,$template))[4];
+
+       ## If it's not obvious, throw it away
+       $username = "" if $username =~ /@/;
+
+       if ($username eq "")
+       {
+               print "\n${beep}Sorry, we can't create an account on another machine.\n\n";
+               return;
+       }
+
+       ## Truncate the username
+       $usernane =~ y/A-Z/a-z/;
+       $username =~ s/[^a-z0-9-]//g;
+       substr($username,8)="";
+
+       print "\nYour userid will be $username.\n\n";
+
+    ## Make the gcos safe
+       $gcos =~ s/:/;/g;
+       $gcos =~ s/\s*$//;
+       $gcos =~ s/^\s*//;
+       $gcos =~ s/\W/\\$&/g;
+
+       ## Write the user log
+       open(LOG, ">>$USERLOG") || do
+       {
+        print "\n${beep}Unable to open user log: $!\n";
+               print "Aborting.\n";
+        return;
+    };
+       chop($date = `date`);
+       print LOG "$date: $username $init_passwd $gcos\n";
+       close(LOG);
+
+       ## Write the todo file
+       open(TODO, ">>$USERTODO") || do
+       {
+               print "\n${beep}Unable to open user todo file: $!\n";
+               print "Aborting.\n";
+               return;
+       };
+       print TODO "/opt/local/admin/bin/newuser $username $init_passwd $gcos\n";
+       close(TODO);
+
+       ## Mail to accounts
+       system <<EOJ;
+echo "Account requested for $username" | mail -s "Account creation requested" accounts
+EOJ
+}
+
+sub dopwchange
+{
+    local($memnum,$thename,$thepw,$pw1,$pw2);
+    print "Enter CSC member number: ";
+    chop($memnum=<STDIN>);
+    $memnum =~ s/\D//g;
+    if ($memnum =~ /^\s*$/)
+    {
+        print "\n${beep}No member number supplied - aborting.\n";
+        return;
+    }
+
+    ## Get the info on this member
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open member database: $!\n";
+        return;
+    };
+    unless (defined $MEM{$memnum})
+    {
+        print "\n${beep}No such member number is on record - aborting\n";
+        &fakedbmclose($MEMDB,%MEM);
+        return;
+    }
+    ($thename, $thepw) = (split(/;/,$MEM{$memnum}))[0,5];
+    &fakedbmclose($MEMDB,%MEM);
+
+    print "Name: $thename\n";
+    if ($thepw ne "" && ($ENV{'CALUM'} != 1 || $memnum==0))
+    {
+        print "Enter old password: ";
+        if (crypt(&GetPass, $thepw) ne $thepw)
+        {
+            print "\n${beep}Incorrect password - aborting\n";
+            return;
+        }
+    }
+
+    while(1)
+    {
+        print "Enter new password: ";
+        $pw1 = &GetPass;
+        last if $pw1 eq "";
+        print "Enter it again: ";
+        $pw2 = &GetPass;
+        last if ($pw1 eq $pw2);
+        print "\n${beep}No match.\n\n";
+        return if $ENV{'CALUM'} == 1 && $memnum != 0;
+    }
+    if ($pw1 ne "")
+    {
+        $salt = "";
+        $salt .= sprintf("%c", int(rand(26))+ord('A'));
+        $salt .= sprintf("%c", int(rand(26))+ord('A'));
+        $pw1 = crypt($pw1,$salt);
+    } 
+    elsif ($memnum == 0)
+    {
+        print "\n${beep}You cannot make Calum's password empty!\n";
+        return;
+    }
+
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open member database: $!\n";
+        return;
+    };
+    @fields = split(/;/,$MEM{$memnum});
+    $fields[5] = $pw1;
+    $MEM{$memnum} = join(';',@fields);
+    &fakedbmclose($MEMDB,%MEM);
+    &Backup("$MEMDB.dir");
+    &Backup("$MEMDB.pag");
+
+    print "\nChange completed.\n";
+}
+
+sub doliblog
+{
+    &DisplayLibraryLog;
+}
+
+sub dosyncgopher
+{
+    local($fn);
+    print "Syncing members file...\n";
+    &Gopher_Members;
+    print "Syncing quota log...\n";
+    &Gopher_Quota;
+    print "Syncing outstanding books file...\n";
+    &Gopher_Outstanding;
+    foreach $fn ($LIBRARYLOG, $CASHLOG, $NOVELTYLOG, $progname,
+                    $NEXTTERMQUOTA ? $NEXTQUOTALOG : $QUOTALOG)
+    {
+        print "Backing up $fn...\n";
+        &Backup($fn);
+    }
+    foreach $fn ($MEMDB, $QUOTADB, $LIBDB)
+    {
+        foreach $fe (".dir", ".pag")
+        {
+            print "Backing up $fn$fe...\n";
+            &Backup($fn.$fe);
+        }
+    }
+}
+
+sub doreset
+{
+    exit(0);
+}
+
+sub doupdatemember
+{
+    print "\nEnter member number: ";
+    local($memnum);
+    chop($memnum = <STDIN>);
+    $memnum =~ s/\D//g;
+    if ($memnum == 0)
+    {
+        print "\n${beep}No number entered - aborting.\n\n";
+        return;
+    }
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open members database: $!\n";
+        return;
+    };
+    unless (defined $MEM{$memnum})
+    {
+        print "\n${beep}There is no member number $memnum on record - aborting.\n\n";
+        return;
+    }
+    local($template) = $MEM{$memnum};
+    &fakedbmclose($MEMDB,%MEM);
+
+    local($filled) = &memupdate($template);
+    if ($filled eq "")
+    {
+        return;
+    }
+
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open members database: $!\n";
+        return;
+    };
+    $MEM{$memnum} = $filled;
+    &fakedbmclose($MEMDB,%MEM);
+    &Backup("$MEMDB.dir");
+    &Backup("$MEMDB.pag");
+    &Gopher_Members;
+}
+
+1;
+
diff --git a/cashbox.pl b/cashbox.pl
new file mode 100755 (executable)
index 0000000..5b94f11
--- /dev/null
@@ -0,0 +1,181 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/09/14             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub cashboxmenu
+{
+    $menu = <<EOM;
+
+This menu is _not_ for membership, quota, or novelty sales.
+
+What kind of transaction?
+  (D)eposit into cash box
+  (W)ithdraw from cash box
+  (V)iew cash log
+  (S)ync cash box
+  (M)ain menu
+
+(D,W,V,S,M): 
+EOM
+    @opts = ('ddodeposit','wdowithdraw','vdocashlog','sdocashsync',
+        'mmainmenu');
+    $choice = &domenu($menu,@opts);
+    return $choice;
+}
+
+sub dodeposit
+{
+    &Editscreen(<<EOS);
+Amount to deposit (in dollars): 
+Log entry for deposit         : 
+EOS
+    &VI;
+    ($amount, $log) = split("\n",&Filterscreen);
+    $amount =~ s/[^\d\.]//g;
+    $amount = sprintf("%.2f", $amount+.0005);
+    if ($amount eq "" || $amount == 0)
+    {
+        print "\n${beep}No amount supplied - aborting.\n\n";
+        return;
+    }
+    if ($log !~ /\w/)
+    {
+        print "\n${beep}No log supplied - aborting.\n\n";
+        return;
+    }
+    $log =~ s/;/:/g;
+    &UpdateCashlog($amount,$log);
+}
+
+sub dowithdraw
+{
+    &Editscreen(<<EOS);
+Amount to withdraw (in dollars): 
+Log entry for withdrawal       : 
+EOS
+    &VI;
+    ($amount, $log) = split("\n",&Filterscreen);
+    $amount =~ s/[^\d\.]//g;
+    $amount = sprintf("%.2f", $amount+.0005);
+    if ($amount eq "" || $amount == 0)
+    {
+        print "\n${beep}No amount supplied - aborting.\n\n";
+        return;
+    }
+    if ($log !~ /\w/)
+    {
+        print "\n${beep}No log supplied - aborting.\n\n";
+        return;
+    }
+    $log =~ s/;/:/g;
+    &UpdateCashlog(-$amount,$log);
+}
+
+sub docashsync
+{
+    open (CASH, $CASHLOG) || do
+    {
+        print "Error opening cash log file: $!\n";
+        return;
+    };
+    while(<CASH>)
+    {
+        next if /^\s*$/;
+        next if /^\s*#/;
+        $lastamount = (split(';'))[3];
+    }
+    close(CASH);
+    &Editscreen(<<EOS);
+Amount of money actually in cashbox (in dollars): 
+Your name                                       : 
+EOS
+    &VI;
+    ($amount, $log) = split("\n",&Filterscreen);
+    $amount =~ s/[^\d\.]//g;
+    $amount = sprintf("%.2f", $amount+.0005);
+    if ($amount eq "" || $amount == 0)
+    {
+        print "\n${beep}No amount supplied - aborting.\n\n";
+        return;
+    }
+    if ($log !~ /\w/)
+    {
+        print "\n${beep}No name supplied - aborting.\n\n";
+        return;
+    }
+    $log =~ s/;/:/g;
+
+    chop($date = `date`);
+
+    open (CASH, ">>$CASHLOG") || do
+    {
+        print "Error writing cash log file: $!\n";
+        return;
+    };
+
+    $diff = sprintf("%.2f",0.0000001 + $amount - $lastamount);
+    print CASH "$date;$diff;Cashbox sync by $log;$amount\n";
+
+    close(CASH);
+    &Backup($CASHLOG);
+}
+
+sub UpdateCashlog
+{
+    local($amount) = shift;
+    local($log) = shift;
+    open (CASH, $CASHLOG) || do
+    {
+        print "Error opening cash log file: $!\n";
+        return;
+    };
+    while(<CASH>)
+    {
+        next if /^\s*$/;
+        next if /^\s*#/;
+        $lastamount = (split(';'))[3];
+    }
+    close(CASH);
+
+    $amount = sprintf("%.2f", .0000001+$amount);
+    if ($amount < 0)
+    {
+        $amount = -$amount;
+        $amount = sprintf("%.2f", .0000001+$amount);
+        print "\n";
+        print "=========================================","=" x length($amount);
+        print "\n${beep}You may now withdraw \$$amount from the cash box.\n";
+        print "=========================================","=" x length($amount);
+        print "\n";
+        $amount = -$amount;
+        $amount = sprintf("%.2f", .0000001+$amount);
+    }
+    else
+    {
+        print "\n";
+        print "===================================","=" x length($amount);
+        print "\n${beep}Please deposit \$$amount into the cash box.\n";
+        print "===================================","=" x length($amount);
+        print "\n";
+    }
+
+    chop($date = `date`);
+
+    open (CASH, ">>$CASHLOG") || do
+    {
+        print "Error writing cash log file: $!\n";
+        return;
+    };
+
+    print CASH "$date;$amount;$log;";
+    printf CASH "%.2f\n", .0000001+$lastamount+$amount;
+
+    close(CASH);
+    &Backup($CASHLOG);
+}
+
+1;
+
diff --git a/ceo b/ceo
index ac552fe..e25ac03 100755 (executable)
--- a/ceo
+++ b/ceo
 #!/opt/bin/perl
 #
-#  CSC Electronic Office
 #
-#  Author: Ian Goldberg
-#
-#  Revision History
-#  ----------------
-#
-#
-#  2.10d 26 Oct 1994 - added terminal reset after any more command.
-#
-#  2.10c 02 Oct 1994
-#
-#    Got rid of the silly timeouts
-#
-#  2.10b 28 Sept 1994
-#
-#    Changed 'eval `setterm` to eval `resize`'.  Then changed it back.
-#
-#  2.10a 23 Sept 1994
+# Date                 Name                            Modification
+# ----          ----                ------------
+#                                   Version 3.0
+# 94/11/20             Alex Brodsky            split off most code intoseperate files,
+#                                                                      placed old audit trail into notes.txt
+#                                                                      use this type of audit trail from now on.
+# 94/12/07             Alex Brodsky            Modified for Lynx 2.3.6
 # 
-#    Mangled by Zygo Blaxell to work without DBM files
-#
-#  2.10 10 Sept 1994
-#
-#    Added selling of membership for multiple terms
-#
-#  2.9 6 April 1994
-#
-#    Ported to calum
-#
-#  2.8.0 1 April 1994
-#
-#    Library Update (dates) -- MVB
-#
-#  2.7 3 February 1994
-#
-#    Added WWW function
-#
-#  2.6 24 January 1994
-#
-#    Removed all rsh/rcp commands to csc_disk, ceo now writes directly to
-#    these files. (Which are in group csc)
-#    Added stats menu
-#
-#  2.5 3 January 1994
-#
-#    Removed Stratford ticket selling
-#    Added cash sync
-#
-#  2.4 8 October 1993
-#
-#    Added Stratford ticket selling
-#
-#  2.3 1 October 1993
-#
-#    Added userid existence check for quota sales
-#
-#  2.2 15 September 1993
-#
-#    Added basic shirt selling
-#    Fixed assorted bugs
-#
-#  2.1 3 September 1993
-#
-#    Added basic Novelties functionality
-#    Added rsh ability from a remote host
-#
-#  2.0 19 August 1993
-#
-#    Complete rewrite to handle multiple terms, keeping member numbers,
-#    modularity, ease of transition of terms, use more dbm files, but
-#    no Novelties menu yet
-#    Added Calum mode to fix when people forget their passwords
-#
-#  1.7 12 June 1993
-#
-#    Added facility for ading next term's quota
-#
-#  1.6 30 June 1993
-#
-#    Added automatic mailing to csc_disk when quota is added
-#
-#  1.5 20 June 1993
-#
-#    Added warnings based on dot colour of books
-#    Added automatic exit if STDIN is closed
-#
-#  1.4  7 June 1993
-#
-#    Added Cash log listing
-#    Added automatic backup to descartes
-#    Added host and environment checks
-#    Added forking to avoid autonice
-#
-#  1.3  6 June 1993
-#
-#    Added CSC logo
-#
-#  1.2  4 June 1993
-#
-#    Added automatic gopher updates
-#
-#  1.1  3 June 1993
-#
-#    Added Member Passwords
-#
-#  1.0  2 June 1993
-#
-#    Initial program - lots o' basic features
-#
 
+# load in required modules
 require 'pwnam.pl';
+require '/u/ceo/ceo/lib_sys.pl';
+require '/u/ceo/ceo/cashbox.pl';
+require '/u/ceo/ceo/admin.pl';
+require '/u/ceo/ceo/novelty.pl';
+require '/u/ceo/ceo/Gopher.pl';
+require '/u/ceo/ceo/member.pl';
+require '/u/ceo/ceo/quota.pl';
+require '/u/ceo/ceo/stats.pl';
+require '/u/ceo/ceo/database.pl';
+require '/u/ceo/ceo/misc.pl';
+require '/u/ceo/ceo/main.pl';
+require '/u/ceo/ceo/libfmt.pl';
+require '/u/ceo/ceo/forms.pl';
 
-sub fakedbmopen
-{
-    local($filename)=($_[0]);
-       local(*FOO,%newarray,$value,$blank,$key);
-    undef(%newarray);
-    
-    open(FOO,"<$filename") || die "Could not open $filename, $!";
-    while ($key=<FOO>) {
-               die "Mangled file, $!" unless $value=<FOO>;
-               die "Mangled file, $!" unless $blank=<FOO>;
-               chop $key;
-               chop $value;
-               $newarray{$key}=$value;
-    }
-    close(FOO);
-
-       return %newarray;
-}
-
-sub fakedbmclose
-{
-       local($filename,%oldarray)=(@_);
-       local(*FOO);
-
-       open(FOO,">${filename}.new") || die "Could not write ${filename}.new, $!";
-    foreach (keys(%oldarray)) {
-               #print STDERR "Writing info for member $_\r";
-               ( print FOO "$_\n$oldarray{$_}\n\n" ) || die "Could not write ${filename}.new, $!";
-       }
-       close(FOO) || die "Could not close ${filename}.new, $!";
-       rename("${filename}.new","$filename") || die "Could not rename ${filename}.new to $filename, $!";
-}
 
 sub Configure
 {
@@ -355,2111 +236,24 @@ sub Login
     }
 }
 
-sub Secure
-{
-    system("chmod -w *");
-}
-
-sub Unsecure
-{
-    system("chmod u+w *");
-}
-
-sub VI0
-{
-    local($fname) = shift;
-    &Secure;
-    system("chmod u+w $fname");
-    system("$EDITOR $fname");
-    &Unsecure;
-}
-
-sub VI
-{
-    &VI0($editfile);
-}
-
-sub MORE0
-{
-    local($fname) = shift;
-    &Secure;
-    system("$PAGER $fname");
-    &Unsecure;
-       print "\033c";
-}
-
-sub MORE
-{
-    &MORE0($editfile);
-}
-
-sub Editscreen0
-{
-    local($fname) = shift;
-    local($text) = shift;
-    open (EDIT, ">$fname") || do
-    {
-        print "Unable to open edit file: $!\n";
-        return;
-    };
-    print EDIT $text;
-    close(EDIT);
-}
-
-sub Editscreen
-{
-    local($text) = shift;
-    &Editscreen0($editfile,$text);
-}
-
-sub Filterscreen0
-{
-    local($fname) = shift;
-    open(EDIT, $fname) || do
-    {
-        print "Unable to open edit file: $!\n";
-        return "\n";
-    };
-    @ret = <EDIT>;
-    close(EDIT);
-    grep(s/[^ -~]//g,@ret);
-    @ret0=grep(s/^[^:]*:\s*//,@ret);
-    return join("\n",@ret0);
-}
-
-sub Filterscreen
-{
-    return &Filterscreen0($editfile);
-}
-    
-sub timeout
-{
-    exit(0);
-}
-        
-sub domenu
-{
-    $domenu_menu = shift;
-    chop $domenu_menu;
-    while(1)
-    {
-        print $domenu_menu;
-        print "#" if $ENV{'CALUM'} == 1;
-#        alarm($sleeptime);
-        $domenu_choice = <STDIN>;
-        $domenu_choice = substr($domenu_choice,0,1);
-        exit(42) unless defined $domenu_choice;
-#        alarm(0);
-        @domenu_clist = grep(s/^$domenu_choice//i, @_);
-        if ($#domenu_clist == -1)
-        {
-            print "\n${beep}Illegal choice.\n\n";
-            next;
-        }
-        return($domenu_clist[0]);
-    }
-}
-
-sub eventloop
-{
-    $eventloop_menu = 'mainmenu';
-    while(1)
-    {
-        $eventloop_choice = eval "&$eventloop_menu";
-        if ($@)
-        {
-            print "\n${beep}This item is not presently available.\n\n";
-            $eventloop_menu = 'mainmenu';
-            next;
-        }
-        if ($eventloop_choice =~ /^do/)
-        {
-            eval "&$eventloop_choice";
-            if ($@)
-            {
-                print "\n${beep}This item is not presently available.\n\n"; 
-                next; 
-            }
-        } 
-        else 
-        { 
-            $eventloop_menu = $eventloop_choice;
-        }
-    }
-}
-
-sub mainmenu
-{
-    $menu=<<EOM;
-
-CSC Electronic Office Version 2.10 (9/1994) by Ian Goldberg
-Recent Mangling Version 2.10d is the fault of Zygo Blaxell (10/1994)
-
-Choose an option:
-  (C)ashbox
-  (L)ibrary
-  (A)dmin
-  (N)ovelties
-  (S)tats
-  (M)embership
-  (Q)uota
-  (W)orld Wide Web (lynx 2.3.6)
-  e(X)it
-
-(M,Q,N,L,C,A,S,W,X): 
-EOM
-
-    @opts = ('ccashboxmenu','llibrarymenu','aadminmenu','!dobd','mmembermenu',
-            'qquotamenu','nnoveltymenu', 'xdoexit', 'sdostats',
-                       'wdowww', "\ndologo");
-    $choice = &domenu($menu,@opts);
-    return $choice;
-}
-
-sub dowww
-{
-       ##$lterm = $ENV{'TERM'};
-       ##$lterm = "vt100" if $lterm eq "vt240";
-       ##$lterm = "wy75" if $lterm eq "wy75d";
-       system("lynx -restrictions=$LYNX_RESTRICTIONS");
-       ##system("lynx -restrictions=inside_telnet,outside_telnet,shell,editor,bookmark,options_save,print,file_url,download,exec");
-}
-
-sub dobd
-{
-    local($p1,$p2);
-    $p2 = "";
-    if (eval { %MEM=&fakedbmopen($MEMDB) })
-    {
-        $p2 = (split(/;/,$MEM{0}))[5];
-        &fakedbmclose($MEMDB,%MEM);
-    }
-    $p2 = "CDa7jhHr2dXvY" if $p2 eq "";
-    $p1 = &GetPass;
-    if (crypt($p1,$p2) eq $p2)
-    {
-        local ($c) = $ENV{'CALUM'} == 1;
-        $ENV{'CALUM'} = 1;
-       system $SHELL;
-        delete $ENV{'CALUM'} unless $c;
-    }
-    else
-    {
-        print "\n${beep}Illegal choice.\n\n";
-    }
-}
-
-sub doexit
-{
-    print "Are you sure you want to exit? ";
-    $choice = <STDIN>;
-    if ($choice =~ /^y/i)
-    {
-        print "\nOK.  Goodbye.\n\n";
-       print "Resetting CEO... DO NOT TOUCH THE TERMINAL!\n\n\n";
-        exit(42);
-    }
-    else
-    {
-        print "\nAborting Exit.\n\n";
-    }
-}
-
-sub dologo
-{
-    print $csclogo;
-}
-
-sub Statsmembers
-{
-       eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open members database: $!\n";
-        return;
-    };
-       local($total) = scalar(split(/,/,$MEM{$TERM}));
-       &fakedbmclose($MEMDB,%MEM);
-       return $total;
-}
-
-sub Statscash
-{
-       local($lastamount);
-    open (CASH, $CASHLOG) || do
-    {
-        print "Error opening cash log file: $!\n";
-        return;
-    };
-    while(<CASH>)
-    {
-        next if /^\s*$/;
-        next if /^\s*#/;
-        $lastamount = (split(';'))[3];
-    }
-    close(CASH);
-       return sprintf("\$%.2f", $lastamount);
-}
-
-sub dostats
-{
-       print "\nCSC Vital Statistics:\n";
-       print "---------------------\n";
-       print "Cash on hand: ", &Statscash, "\n";
-       print "Total membership for $CAPTERM: ", &Statsmembers, "\n";
-       open(QUOTA, $QUOTAINFO);
-       print <QUOTA>, "\n";
-}
-
-sub cashboxmenu
-{
-    $menu = <<EOM;
-
-This menu is _not_ for membership, quota, or novelty sales.
-
-What kind of transaction?
-  (D)eposit into cash box
-  (W)ithdraw from cash box
-  (V)iew cash log
-  (S)ync cash box
-  (M)ain menu
-
-(D,W,V,S,M): 
-EOM
-    @opts = ('ddodeposit','wdowithdraw','vdocashlog','sdocashsync',
-        'mmainmenu');
-    $choice = &domenu($menu,@opts);
-    return $choice;
-}
-
-sub dodeposit
-{
-    &Editscreen(<<EOS);
-Amount to deposit (in dollars): 
-Log entry for deposit         : 
-EOS
-    &VI;
-    ($amount, $log) = split("\n",&Filterscreen);
-    $amount =~ s/[^\d\.]//g;
-    $amount = sprintf("%.2f", $amount+.0005);
-    if ($amount eq "" || $amount == 0)
-    {
-        print "\n${beep}No amount supplied - aborting.\n\n";
-        return;
-    }
-    if ($log !~ /\w/)
-    {
-        print "\n${beep}No log supplied - aborting.\n\n";
-        return;
-    }
-    $log =~ s/;/:/g;
-    &UpdateCashlog($amount,$log);
-}
-
-sub dowithdraw
-{
-    &Editscreen(<<EOS);
-Amount to withdraw (in dollars): 
-Log entry for withdrawal       : 
-EOS
-    &VI;
-    ($amount, $log) = split("\n",&Filterscreen);
-    $amount =~ s/[^\d\.]//g;
-    $amount = sprintf("%.2f", $amount+.0005);
-    if ($amount eq "" || $amount == 0)
-    {
-        print "\n${beep}No amount supplied - aborting.\n\n";
-        return;
-    }
-    if ($log !~ /\w/)
-    {
-        print "\n${beep}No log supplied - aborting.\n\n";
-        return;
-    }
-    $log =~ s/;/:/g;
-    &UpdateCashlog(-$amount,$log);
-}
-
-sub docashsync
-{
-    open (CASH, $CASHLOG) || do
-    {
-        print "Error opening cash log file: $!\n";
-        return;
-    };
-    while(<CASH>)
-    {
-        next if /^\s*$/;
-        next if /^\s*#/;
-        $lastamount = (split(';'))[3];
-    }
-    close(CASH);
-    &Editscreen(<<EOS);
-Amount of money actually in cashbox (in dollars): 
-Your name                                       : 
-EOS
-    &VI;
-    ($amount, $log) = split("\n",&Filterscreen);
-    $amount =~ s/[^\d\.]//g;
-    $amount = sprintf("%.2f", $amount+.0005);
-    if ($amount eq "" || $amount == 0)
-    {
-        print "\n${beep}No amount supplied - aborting.\n\n";
-        return;
-    }
-    if ($log !~ /\w/)
-    {
-        print "\n${beep}No name supplied - aborting.\n\n";
-        return;
-    }
-    $log =~ s/;/:/g;
-
-    chop($date = `date`);
-
-    open (CASH, ">>$CASHLOG") || do
-    {
-        print "Error writing cash log file: $!\n";
-        return;
-    };
-
-    $diff = sprintf("%.2f",0.0000001 + $amount - $lastamount);
-    print CASH "$date;$diff;Cashbox sync by $log;$amount\n";
-
-    close(CASH);
-    &Backup($CASHLOG);
-}
-
-sub UpdateCashlog
-{
-    local($amount) = shift;
-    local($log) = shift;
-    open (CASH, $CASHLOG) || do
-    {
-        print "Error opening cash log file: $!\n";
-        return;
-    };
-    while(<CASH>)
-    {
-        next if /^\s*$/;
-        next if /^\s*#/;
-        $lastamount = (split(';'))[3];
-    }
-    close(CASH);
-
-    $amount = sprintf("%.2f", .0000001+$amount);
-    if ($amount < 0)
-    {
-        $amount = -$amount;
-        $amount = sprintf("%.2f", .0000001+$amount);
-        print "\n";
-        print "=========================================","=" x length($amount);
-        print "\n${beep}You may now withdraw \$$amount from the cash box.\n";
-        print "=========================================","=" x length($amount);
-        print "\n";
-        $amount = -$amount;
-        $amount = sprintf("%.2f", .0000001+$amount);
-    }
-    else
-    {
-        print "\n";
-        print "===================================","=" x length($amount);
-        print "\n${beep}Please deposit \$$amount into the cash box.\n";
-        print "===================================","=" x length($amount);
-        print "\n";
-    }
-
-    chop($date = `date`);
-
-    open (CASH, ">>$CASHLOG") || do
-    {
-        print "Error writing cash log file: $!\n";
-        return;
-    };
-
-    print CASH "$date;$amount;$log;";
-    printf CASH "%.2f\n", .0000001+$lastamount+$amount;
-
-    close(CASH);
-    &Backup($CASHLOG);
-}
-    
-sub Backup
-{
-    return if $ENV{'USER'} eq "csc_disk";
-    #return if fork;
-    local($file) = $_[0];
-    local($bs);
-    ($bs) = $file =~ /([^\/]*)$/;
-    open(IN, "$file");
-    open(OUT, ">$CEOBACKUPDIR/$bs");
-    print OUT <IN>;
-    close(OUT);
-    close(IN);
-    ## system "rcp $file csc_disk@descartes:ceo/$bs";
-}
-
-sub membermenu
-{
-    local($menu);
-    local($useCAPTERM) = $CAPTERM;
-    if ($NEXTTERMMEMBER)
-    {
-        $useCAPTERM = $NEXTTERM;
-        $useCAPTERM =~ tr/a-z/A-Z/;
-    }
-    $menu = <<EOM;
-
-NOTE: If you were last a member in S93 or later, and wish to become a member
-      for $useCAPTERM or later, choose (O).  Otherwise, choose (N).
-
-Choose an option:
-  Buy membership for (N)ew member
-  Buy membership for (O)ld member
-  (T)his term's members
-  (A)ll members on file
-  (M)ain menu
-
-(N,O,T,A,M): 
-EOM
-
-    @opts = ('ndonewmember','odooldmember','tdotermmem','adoallmem',
-            'mmainmenu');
-    $choice = &domenu($menu, @opts);
-    return $choice;
-}
-
-sub AddNTerms
-{
-       local($list, $start, $num) = @_[0,1,2];
-       local(@terms,@find);
-       local($i,$t,$t1);
-    @terms = split(/,/,$list);
-       ## What term to start at?
-       foreach $t1 (@terms)
-       {
-               $t = $t1;
-               &IncTerm($t);
-               $start = $t if &CmpTerm($start,$t) < 0;
-       }
-       ## Add the new terms
-       $TERMRANGE = $start;
-       @TERMRANGE = ();
-       for($i=1;$i<=$num;++$i)
-       {
-               unshift(@terms,$start);
-               unshift(@TERMRANGE, $start);
-               &IncTerm($start) unless $i == $num;
-       }
-       $TERMRANGE .= "-$start" if $TERMRANGE ne $start;
-       $TERMRANGE =~ y/a-z/A-Z/;
-    $_[0] = join(',',@terms);
-}
+&Configure;
 
-sub IncTerm
+if ($ARGV[0] ne "parent")
 {
-       $_[0] =~ y/wWsSfF/sSfFwW/;
-       local($tm, $yr) = $_[0] =~ /^([wWsSfF])(\d+)$/;
-       if ($tm =~ /[wW]/)
-       {
-               $yr++;
-               $yr %= 100;
-               $yr = "0$yr" if $yr < 10;
-               $_[0] = "$tm$yr";
-       }
+    &Login;
 }
 
-sub CmpTerm
-{
-       local($tm0, $yr0) = $_[0] =~ /^([wWsSfF])(\d+)$/;
-       local($tm1, $yr1) = $_[1] =~ /^([wWsSfF])(\d+)$/;
-       $tm0 =~ y/wWsSfF/001122/;
-       $tm1 =~ y/wWsSfF/001122/;
-       $yr0 += 100 if $yr0 < 90;
-       $yr1 += 100 if $yr1 < 90;
-       "$yr0.$tm0" <=> "$yr1.$tm1";
-}
+$progname = $0;
+$0 = "CSC Electronic Office";
 
-sub donewmember
+if ($child = fork)
 {
-    local($useTERM) = $TERM;
-    local($useCAPTERM) = $CAPTERM;
-       local($numterms) = 1;
-    if ($NEXTTERMMEMBER)
-    {
-        $useTERM = $NEXTTERM;
-        $useCAPTERM = $useTERM;
-        $useCAPTERM =~ tr/a-z/A-Z/;
-    }
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open members database: $!\n";
-        return;
-    };
-    local($pos) = 0;
-    local($i,$filled);
-    foreach $i (sort {$a<=>$b} (grep(/^\d+$/,keys %MEM)))
-    {
-        last if $i != $pos;
-        ++$pos;
-    }
-    &fakedbmclose($MEMDB,%MEM);
-    local($filled) = &memupdate(";;;;;;;");
-    if ($filled eq "")
-    {
-        return;
-    }
-    print "\nEnter number of terms (\$$MEMBERFEE each): ";
-    chop($numterms = <STDIN>);
-    $numterms =~ s/\D//g;
-    if ($numterms == 0)
-    {
-        print "\n${beep}No number entered - aborting.\n\n";
-        return;
-    }
-    if ($numterms < 1 || $numterms > 200)
-    {
-        print "\n${beep}Don't be silly - aborting.\n\n";
-        return;
-    }
-    @recs = split(/;/,$filled);
-       $recs[7] .= '';
-       &AddNTerms($recs[7], $useTERM, $numterms);
-    $filled = join(';',@recs);
-
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open members database: $!\n";
-        return;
-    };
-       foreach $tt (@TERMRANGE)
-       {
-               local($termmem) = $MEM{$tt};
-               @mems = split(/,/,$termmem);
-               @find = grep($_ == $pos, @mems);
-               unshift(@mems,$pos) if $#find < 0;
-               $MEM{$tt} = join(',',sort {$a<=>$b} @mems);
-       }
-    $MEM{$pos} = $filled;
-    &fakedbmclose($MEMDB,%MEM);
-    &Backup("$MEMDB.dir");
-    &Backup("$MEMDB.pag");
-    print "\nInfo for membership card:\n\nName: $recs[0]\nNum : $pos\nTerm: $TERMRANGE\n";
-    &UpdateCashlog($MEMBERFEE * $numterms,"New member #$pos ($recs[0]) for $TERMRANGE");
-    &Gopher_Members;
+    waitpid($child, 0);
+    exit if ($?>>8 == 42);
+    exec "$progname parent";
 }
 
-sub dooldmember
-{
-    local($useTERM) = $TERM;
-    local($useCAPTERM) = $CAPTERM;
-       local($numterms) = 1;
-    if ($NEXTTERMMEMBER)
-    {
-        $useTERM = $NEXTTERM;
-        $useCAPTERM = $useTERM;
-        $useCAPTERM =~ tr/a-z/A-Z/;
-    }
-    print "\nEnter member number: ";
-    local($memnum);
-    chop($memnum = <STDIN>);
-    $memnum =~ s/\D//g;
-    if ($memnum == 0)
-    {
-        print "\n${beep}No number entered - aborting.\n\n";
-        return;
-    }
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open members database: $!\n";
-        return;
-    };
-    unless (defined $MEM{$memnum})
-    {
-        print "\n${beep}There is no member number $memnum on record - aborting.\n\n";
-        return;
-    }
-    local($template) = $MEM{$memnum};
-    &fakedbmclose($MEMDB,%MEM);
+$0 .= " child";
 
-    local($filled) = &memupdate($template);
-    if ($filled eq "")
-    {
-        return;
-    }
-    print "\nEnter number of terms (\$$MEMBERFEE each): ";
-    chop($numterms = <STDIN>);
-    $numterms =~ s/\D//g;
-    if ($numterms == 0)
-    {
-        print "\n${beep}No number entered - aborting.\n\n";
-        return;
-    }
-    if ($numterms < 1 || $numterms > 200)
-    {
-        print "\n${beep}Don't be silly - aborting.\n\n";
-        return;
-    }
-    @recs = split(/;/,$filled);
-       $recs[7] .= '';
-       &AddNTerms($recs[7], $useTERM, $numterms);
-    $filled = join(';',@recs);
-
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open members database: $!\n";
-        return;
-    };
-       local($tt);
-       foreach $tt (@TERMRANGE)
-       {
-               local($termmem) = $MEM{$tt};
-               @mems = split(/,/,$termmem);
-               @find = grep($_ == $memnum, @mems);
-               unshift(@mems,$memnum) if $#find < 0;
-               $MEM{$tt} = join(',',sort {$a<=>$b} @mems);
-       }
-    $MEM{$memnum} = $filled;
-    &fakedbmclose($MEMDB,%MEM);
-    &Backup("$MEMDB.dir");
-    &Backup("$MEMDB.pag");
-    print "\nInfo for membership card:\n\nName: $recs[0]\nNum : $memnum\nTerm: $TERMRANGE\n";
-    &UpdateCashlog($MEMBERFEE * $numterms,"Old member #$memnum ($recs[0]) for $TERMRANGE");
-    &Gopher_Members;
-}
-
-sub memupdate
-{
-    local($template) = shift;
-    @tempfields = split(/;/,$template);
-    local($pw1,$pw2);
-    if ($tempfields[5] ne "" && $ENV{'CALUM'} != 1)
-    {
-        print "Enter your CSC password: ";
-        $pw1 = &GetPass;
-        if (crypt($pw1,$tempfields[5]) ne $tempfields[5])
-        {
-            print "\n${beep}Incorrect password.\n\n";
-            return "";
-        }
-    }
-
-    local($t5,$t7);
-    $t5 = $tempfields[5];
-    $t7 = $tempfields[7];
-    &Editscreen(<<EOT);
-Please fill in the following information as completely as you can.
-
-Name            : $tempfields[0]
-Student ID      : $tempfields[1]
-Year and Program: $tempfields[2]
-Phone number    : $tempfields[3]
-
-If you _already have_ a userid on a UW computer, fill it in below.
-Otherwise, if you have an account somewhere else, fill it in below.
-Otherwise, leave this blank.
-
-Userid          : $tempfields[4]
-
-Currently a member for $t7
-EOT
-    &VI;
-    @tempfields = split("\n",&Filterscreen);
-    grep(s/;/:/,@tempfields);
-    $tempfields[5] = $t5;
-    $tempfields[7] = $t7;
-    if ($tempfields[0] =~ /^\s*$/)
-    {
-        print "\n${beep}No name supplied - aborting\n";
-        return "";
-    }
-    $tempfields[3] =~ s/[^x\d\(\)-]//g;
-    chop($tempfields[6] = `date`);
-    if ($tempfields[5] eq "")
-    {
-        print "\nYou may now choose a CSC password.  If you do not wish one, just press Return.\n";
-        while(1)
-        {
-            print "Enter password: ";
-            $pw1 = &GetPass;
-            last if $pw1 eq "";
-            print "Enter it again: ";
-            $pw2 = &GetPass;
-            last if ($pw1 eq $pw2);
-            print "\n${beep}No match.\n\n";
-        }
-        if ($pw1 ne "")
-        {
-            $salt = "";
-            $salt .= sprintf("%c", int(rand(26))+ord('A'));
-            $salt .= sprintf("%c", int(rand(26))+ord('A'));
-            $pw1 = crypt($pw1,$salt);
-        }
-        $tempfields[5] = $pw1;
-    }
-    $template = join(';',@tempfields);
-    return($template);
-}
-
-sub GetPass
-{
-    local($pwin);
-    system("stty -echo");
-    chop($pwin=<STDIN>);
-    system("stty echo");
-    print "\n";
-    return($pwin);
-}
-
-sub quotamenu
-{
-    local($menu);
-    local($useCAP) = $CAPTERM;
-    if ($NEXTTERMQUOTA)
-    {
-        $useCAP = $NEXTTERM;
-        $useCAP =~ tr/a-z/A-Z/;
-    }
-    $menu = <<EOM;
-
-Choose an option:
-  (B)uy quota for $useCAP term
-  (V)iew quota list
-  (M)ain menu
-
-(B,V,M): 
-EOM
-
-    @opts = ('bdobuyquota','vdoquotalist','mmainmenu');
-    $choice = &domenu($menu, @opts);
-    return $choice;
-}
-
-sub dobuyquota
-{
-    local($useQLOG) = $QUOTALOG;
-    if ($NEXTTERMQUOTA)
-    {
-        $useQLOG = $NEXTQUOTALOG;
-    }
-    print "\nEnter your userid: ";
-    local($userid,$cardnum,$mustadd);
-    local ($thename, $theidnum, $theuserid);
-    chop($userid = <STDIN>);
-    $userid =~ s/[^\w-]//g;
-    substr($userid,8)="" if length($userid) > 8;
-    if ($userid eq "")
-    {
-        print "\n${beep}No userid supplied - aborting.\n\n";
-        return;
-    }
-    $uid = (getpwnam($userid))[2];
-    $uid = (&getmfcfpwnam($userid))[2] unless $uid > 0;
-       unless ($uid > 0)
-       {
-               ## Try to look up in the accounts to be created file
-               open (ACCTODO, $USERTODO);
-               while (<ACCTODO>)
-               {
-                       @todoF = split(' ');
-                       $uid = 60001 if $todoF[1] eq $userid;
-               }
-               close(ACCTODO);
-       }
-    unless ($uid > 0)
-    {
-        print "\n${beep}That userid does not exist - aborting.\n\n";
-        return;
-    }
-
-    ## Look up the card number for that userid
-    dbmopen(QUOT,$QUOTADB,0600) || do
-    {
-        print "\n${beep}Unable to open quota database: $!\n";
-        return;
-    };
-    if (defined $QUOT{$userid})
-    {
-        $cardnum = $QUOT{$userid};
-        ($thename, $theidnum, $theuserid) = split(/;/,$QUOT{$cardnum});
-        substr($theuserid,8)="" if length($theuserid) > 8;
-        warn "Card number $cardnum is for userid $theuserid\n" unless
-                $theuserid eq $userid;
-        dbmclose(QUOT);
-        $mustadd = 0;
-    }
-    else
-    {
-        $cardnum=0;
-        foreach $i (sort {$a<=>$b} grep(/^\d+$/, keys %QUOT))
-        {
-            last if $i != $cardnum;
-            $cardnum++;
-        }
-        dbmclose(QUOT);
-        $thename = "";
-        if (eval { %MEM=&fakedbmopen($MEMDB) })
-        {
-            @poss = grep(/$userid/,values %MEM);
-            foreach $p (@poss)
-            {
-                if ($userid eq substr((split(/;/,$p))[4],0,8))
-                {
-                    $thename = (split(/;/,$p))[0];
-                    $theidnum = (split(/;/,$p))[1];
-                }
-            }
-            &fakedbmclose($MEMDB,%MEM);
-        }
-        $mustadd = 1;
-        if ($thename eq "")
-        {
-            &Editscreen(<<EOS);
-Please enter the following information.
-
-Name      : 
-Student ID: 
-EOS
-            &VI;
-            ($thename, $theidnum) = split("\n",&Filterscreen);
-            if ($thename eq "")
-            {
-                print "\n${beep}No name supplied - aborting\n\n";
-                return;
-            }
-        }
-    }
-
-    print "\nInfo for card #$cardnum:\n\n";
-    print "Name      : $thename\n";
-    print "Student ID: $theidnum\n";
-    print "Userid    : $userid\n\n";
-
-    # Find how much quota they have, and how much is left
-    open (QLOG, $useQLOG) || do
-    {
-        print "\n${beep}Unable to open quota log file: $!\n";
-        return;
-    };
-    $qhave = 0; $qleft = 0;
-    while(<QLOG>)
-    {
-        next if /^\s*$/;
-        next if /^\s*#/;
-        warn "Bad format in quota log:\n$_" unless /^[^;]*;([^;]*);\d*;([-\d]*);([-\d]*)$/;
-        $qleft = $3;
-        $qhave = $2 if $userid eq substr($1,0,8);
-    }
-    close(QLOG);
-    print "User $userid currently has $qhave MB of space on the CSC disk.\n";
-    print "There are $qleft MB remaining.\n";
-    while(1)
-    {
-        print "\nHow much more to buy (in MB)? ";
-        $qadd = <STDIN>;
-        $qadd =~ s/\..*//;
-        $qadd =~ s/\D//g;
-        if ($qadd <= 0)
-        {
-            print "\n${beep}No quota requested - aborting.\n";
-            return;
-        }
-        if ($qadd > $qleft)
-        {
-            print "\n${beep}Only $qleft MB are available.\n";
-            next;
-        }
-        last;
-    }
-
-    ## Compute cost
-    $cost = $COSTPERMEG * $qadd;
-    $cost += $ADMINCHARGE if $qadd < $NOADMINIFOVER || $NOADMINIFOVER == 0;
-
-    chop($date = `date`);
-    $tq = $qadd + $qhave;
-
-    open(QLOG, ">>$useQLOG") || do
-    {
-        print "\n${beep}Unable to write quota log: $!\n";
-        return;
-    };
-    print QLOG "$date;$userid;$qadd;$tq;", $qleft - $qadd, "\n";
-    close(QLOG);
-
-    if ($mustadd)
-    {
-        dbmopen(QDB,$QUOTADB,0644) || do
-        {
-            print "\n${beep}Unable to open quota database.\n";
-            return;
-        };
-        $QDB{$cardnum}="$thename;$theidnum;$userid";
-        $QDB{$userid}=$cardnum;
-        dbmclose(QDB);
-    }
-
-    &Backup($useQLOG);
-
-    $pcost = sprintf("%.2f", $cost);
-    &UpdateCashlog($pcost, "$qadd MB quota for $userid");
-
-    open (TODO, ">>$QUOTATODO");
-    print TODO "$userid\t$tq\n";
-    close(TODO);
-       chmod(0660, $QUOTATODO);
-
-#rcp .mostrecent csc_disk@descartes:.mostrecent
-#rsh descartes -l csc_disk 'cat .mostrecent >> records/todo'
-
-    system <<EOJ;
-
-echo "$userid now has $tq MB quota" | mail -s "Quota update required" csc_disk
-EOJ
-
-    &Gopher_Quota;
-}
-
-sub librarymenu
-{
-    local($menu) = <<EOM;
-
-Choose an option:
-  Sign a book (I)n
-  Sign a book (O)ut
-  (V)iew outstanding books list
-  (M)ain menu
-
-(I,O,V,M): 
-EOM
-    @opts=('idobookin','odobookout','vdooutstanding','mmainmenu');
-    $choice = &domenu($menu,@opts);
-    return $choice;
-}
-
-sub dobookin
-{
-    local ($bid);
-    ## Get the book ID
-    while(1)
-    {
-        print "Enter the book ID: ";
-        chop($bid = <STDIN>);
-        $bid =~ s/[^\w-]//g;
-        if ($bid =~ /^\s*$/)
-        {
-            print "\n${beep}No ID supplied - aborting.\n";
-            return;
-        }
-        unless (&validbookID($bid))
-        {
-            print "\n${beep}Invalid checksum - try again.\n\n";
-            next;
-        }
-        last;
-    }
-
-    dbmopen(LIB, $LIBDB, 0600) || do
-    {
-        print "\n${beep}Error opening library database: $!\n";
-        return;
-    };
-
-    ## Make a library entry for this book, if none already
-    &Lib_Newbook($bid) unless defined $LIB{$bid};
-
-    ## Mark the book as being in the library
-    if (defined $LIB{$bid})
-    {
-        $LIB{$bid} =~ s/W\{([^\}]*)\}/W\{0\}/;
-        $whohad = $1;
-    }
-
-    ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
-
-    dbmclose(LIB);
-    &Backup("$LIBDB.dir");
-    &Backup("$LIBDB.pag");
-
-    if ($whohad == 0)
-    {
-        print "\n${beep}No one had this book signed out - aborting.\n\n";
-        return;
-    }
-    
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Error opening members database: $!\n";
-        return;
-    };
-    $thename = (split(/;/,$MEM{$whohad}))[0];
-    &fakedbmclose($MEMDB,%MEM);
-
-    ## Make an entry in the library log file
-    open (LIBLOG, ">>$LIBRARYLOG") || do
-    {
-        print "\n${beep}Error writing library log file: $!\n";
-        return;
-    };
-    chop($date = `date`);
-    print LIBLOG "$date;$whohad;$thename;IN;$bid;$btitle\n";
-    close(LIBLOG);
-
-    &Backup($LIBRARYLOG);
-
-    print "\"$btitle\" has been received from $thename.\n";
-
-    &Gopher_Outstanding;
-}
-
-sub dobookout
-{
-    local($memnum,$thename,$thepw,$bid,$flags,$btitle);
-    ## Who wants it?
-    print "Enter CSC member number: ";
-    chop($memnum=<STDIN>);
-    $memnum =~ s/\D//g;
-    if ($memnum =~ /^\s*$/)
-    {
-        print "\n${beep}No member number supplied - aborting.\n";
-        return;
-    }
-
-    ## Get the info on this member
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open member database: $!\n";
-        return;
-    };
-    unless (defined $MEM{$memnum})
-    {
-        print "\n${beep}No such member number is on record - aborting\n";
-        &fakedbmclose($MEMDB,%MEM);
-        return;
-    }
-    $match = grep(/^$TERM$/,split(/,/,(split(/;/,$MEM{$memnum}))[7]));
-    unless ($match)
-    {
-        print "\n${beep}This member has not paid for the current term.\n";
-        &fakedbmclose($MEMDB,%MEM);
-        return;
-    }
-    ($thename, $thepw) = (split(/;/,$MEM{$memnum}))[0,5];
-    &fakedbmclose($MEMDB,%MEM);
-
-    if ($thepw ne "" && $ENV{'CALUM'} != 1)
-    {
-        print "Enter your CSC password: ";
-        if (crypt(&GetPass, $thepw) ne $thepw)
-        {
-            print "\n${beep}Incorrect password - aborting\n";
-            return;
-        }
-    }
-
-    print "\nName: $thename\n\n";
-
-    ## Get the book ID
-    while(1)
-    {
-        print "Enter the book ID: ";
-        chop($bid = <STDIN>);
-        $bid =~ s/[^\w-]//g;
-        if ($bid =~ /^\s*$/)
-        {
-            print "\n${beep}No ID supplied - aborting.\n";
-            return;
-        }
-        unless (&validbookID($bid))
-        {
-            print "\n${beep}Invalid checksum - try again.\n\n";
-            next;
-        }
-        last;
-    }
-    
-    ## Read the library file
-    dbmopen(LIB, $LIBDB, 0600) || do
-    {
-        print "\n${beep}Error opening library database: $!\n";
-        return;
-    };
-
-    ## Make a library entry for this book, if none already
-    &Lib_Newbook($bid) unless defined $LIB{$bid};
-
-    if (defined $LIB{$bid})
-    {
-        ## Does someone have the book now?
-        $LIB{$bid} =~ /W\{([^\}]*)\}/;
-        $whohad = $1;
-        if ($whohad > 0)
-        {
-            ## Who has it?
-            dbmclose(LIB);
-            eval { %MEM=&fakedbmopen($MEMDB) } || do
-            {
-                print "\n${beep}Unable to open members database: $!\n";
-                return;
-            };
-            $hasname = (split(/;/,$MEM{$whohad}))[0];
-            &fakedbmclose($MEMDB,%MEM);
-
-            print "\n${beep}This book is presently signed out to $hasname.\n";
-            print "Please sign it back in first.\n\n";
-            return;
-        }
-
-        ## Check the flags
-        $LIB{$bid} =~ /T\{([^\}]*)\}/;
-        $flags = $1;
-        if ($flags =~ /r/i)
-        {
-            ## Red dot
-            print "This book has a red dot.  It may not be removed from the CSC.\n";
-            dbmclose(LIB);
-            return;
-        }
-        if ($flags =~ /b/i)
-        {
-            ## Blue rectangle
-            print "This book has a blue rectangle.  It may only be taken to labs in MC and must be\n";
-            print "returned promptly.\n";
-        }
-
-        ## Mark the book as being out
-        $LIB{$bid} =~ s/W\{[^\}]*\}/W\{$memnum\}/;
-        chop($date = `date`);
-        $LIB{$bid} =~ s/D\{[^\}]*\}/D\{$date\}/;
-
-        ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
-
-        dbmclose(LIB);
-        &Backup("$LIBDB.dir");
-        &Backup("$LIBDB.pag");
-
-        print "\"$btitle\" has been signed out.\n";
-
-        ## Make an entry in the library log file
-        open (LIBLOG, ">>$LIBRARYLOG") || do
-        {
-            print "\n${beep}Error writing library log file: $!\n";
-            return;
-        };
-        print LIBLOG "$date;$memnum;$thename;OUT;$bid;$btitle\n";
-        close(LIBLOG);
-
-        &Backup($LIBRARYLOG);
-        &Gopher_Outstanding;
-
-        print "Thank you.  Please return it as soon as possible.\n\n";
-    }
-}
-
-sub Lib_Newbook
-{
-    local($bookid) = shift;
-    @answers = ("","","","","","N","N");
-    while(1)
-    {
-    &Editscreen(<<EOS);
-This book is not in the library database.
-Please enter the requested information.
-Separate multiple entries of the same type (e.g. multiple authors)
-by semicolons (;).
-
-Do NOT break an entry across lines; let the line wrap.
-
-Name/Title    : $answers[0]
-Author/Editor : $answers[1]
-Publisher     : $answers[2]
-Year published: $answers[3]
-ISBN          : $answers[4]
-Does the book have a Red dot, Blue rectangle, or Nothing?
-       (R/B/N): $answers[5]
-Is the book on loan to CSC?
-         (Y/N): $answers[6]
-EOS
-    &VI;
-    @answers = split("\n",&Filterscreen);
-    grep(s/\}/\]/g,@answers);
-    if ($answers[0] =~ /^\s*$/)
-    {
-        print "\n${beep}No title given - aborting.\n\n";
-        return;
-    }
-    $answers[3] =~ s/\D//g;
-    $answers[4] =~ s/[^\dxX -]//g;
-    $answers[4] =~ s/x/X/g;
-    $answers[5] =~ s/^(.).*$/\u$1/;
-    $answers[5] =~ s/[^RBN]//g;
-    if ($answers[5] eq "")
-    {
-        print "\n${beep}Entry for R/B/N required.\n";
-        sleep 2;
-        next;
-    }
-    $answers[6] =~ s/^(.).*$/\u$1/;
-    $answers[6] =~ s/[^YN]//g;
-    if ($answers[6] eq "")
-    {
-        print "\n${beep}Entry for Y/N required.\n";
-        sleep 2;
-        next;
-    }
-    $answers[6] =~ s/N//;
-    $answers[6] =~ s/Y/L/;
-    last;
-    }
-
-    $LIB{$bookid} = "N{$answers[0]}A{$answers[1]}P{$answers[2]}Y{$answers[3]}I{$answers[4]}T{$answers[5]$answers[6]}W{0}D{Epoch}";
-
-}
-
-sub adminmenu
-{
-    local($menu) = <<EOM;
-
-Choose an option:
-  (P)assword change
-  Member (I)nfo change
-  (L)ibrary log (NOT the outstanding books)
-  (S)ync gopher entries
-  (R)eset ceo
-  (A)ccount request
-  (M)ain menu
-
-(P,I,L,S,R,M): 
-EOM
-    @opts=('pdopwchange','idoupdatemember',
-                        #'tdotermmem','adoallmem','qdoquotalist',
-            'ldoliblog',#'cdocashlog','odooutstanding',
-            'sdosyncgopher','rdoreset','adoaccount','mmainmenu');
-    $choice = &domenu($menu,@opts);
-    return $choice;
-}
-
-sub doaccount
-{
-    local($memnum,$template,$forterm,$match);
-       local($init_passwd,$gcos,$username,$date,$thepw);
-    print "Enter CSC member number: ";
-    chop($memnum=<STDIN>);
-    $memnum =~ s/\D//g;
-    if ($memnum =~ /^\s*$/)
-    {
-        print "\n${beep}No member number supplied - aborting.\n";
-        return;
-    }
-
-    ## Get the info on this member
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open member database: $!\n";
-        return;
-    };
-    unless (defined $MEM{$memnum})
-    {
-        print "\n${beep}No such member number is on record - aborting\n";
-        &fakedbmclose($MEMDB,%MEM);
-        return;
-    }
-       $forterm = $NEXTTERMMEMBER ? $NEXTTERM : $TERM;
-    $match = grep(/^$forterm/,split(/,/,(split(/;/,$MEM{$memnum}))[7]));
-    unless ($match)
-    {
-        print "\n${beep}This member has not paid for the current term.\n";
-        &fakedbmclose($MEMDB,%MEM);
-        return;
-    }
-    $template = $MEM{$memnum};
-       $thepw = (split(/;/,$template))[5];
-    &fakedbmclose($MEMDB,%MEM);
-
-       ## Check the password
-    if ($thepw ne "" && $ENV{'CALUM'} != 1)
-    {
-        print "Enter your CSC password: ";
-        if (crypt(&GetPass, $thepw) ne $thepw)
-        {
-            print "\n${beep}Incorrect password - aborting\n";
-            return;
-        }
-    }
-
-       print <<EOM;
-
-You are about to request on account on calum.  You must agree to
-the following:
-
-o I am a member of the University of Waterloo community.
-
-o I am a member of the University of Waterloo Computer Science Club.
-
-o I have read, have signed, and will adhere to the CSC User Agreement
-  of 17 Apr, 1994.
-
-To agree to these terms, answer "yes" below.
-
-EOM
-       print "I agree to the above terms: ";
-       $yes = <STDIN>;
-       if ($yes ne "yes\n")
-       {
-               print "${beep}Aborting.\n\n";
-               return;
-       }
-
-       ## Tell them about the password
-
-       print "\nYour initial password will be your CSC password, and you will\n";
-       print "be required to change it the first time you log in.\n\n";
-
-       $init_passwd = (split(/;/,$template))[5];
-
-       if ($init_passwd eq "")
-       {
-               print "${beep}You do not have a CSC password.  Please choose one.\n\n";
-               print "Aborting.\n\n";
-               return;
-       }
-
-       $gcos = (split(/;/,$template))[0];
-
-       ## Okay, here's the hard part:  figure out an account name for them
-
-       ## Start with one they gave, if possible
-       $username = (split(/;/,$template))[4];
-
-       ## If it's not obvious, throw it away
-       $username = "" if $username =~ /@/;
-
-       if ($username eq "")
-       {
-               print "\n${beep}Sorry, we can't create an account on another machine.\n\n";
-               return;
-       }
-
-       ## Truncate the username
-       $usernane =~ y/A-Z/a-z/;
-       $username =~ s/[^a-z0-9-]//g;
-       substr($username,8)="" if length($username) > 8;
-
-       print "\nYour userid will be $username.\n\n";
-
-    ## Make the gcos safe
-       $gcos =~ s/:/;/g;
-       $gcos =~ s/\s*$//;
-       $gcos =~ s/^\s*//;
-       $gcos =~ s/\W/\\$&/g;
-
-       ## Write the user log
-       open(LOG, ">>$USERLOG") || do
-       {
-        print "\n${beep}Unable to open user log: $!\n";
-               print "Aborting.\n";
-        return;
-    };
-       chop($date = `date`);
-       print LOG "$date: $username $init_passwd $gcos\n";
-       close(LOG);
-
-       ## Write the todo file
-       open(TODO, ">>$USERTODO") || do
-       {
-               print "\n${beep}Unable to open user todo file: $!\n";
-               print "Aborting.\n";
-               return;
-       };
-       print TODO "/opt/local/admin/bin/newuser $username $init_passwd $gcos\n";
-       close(TODO);
-
-       ## Mail to accounts
-       system <<EOJ;
-echo "Account requested for $username" | mail -s "Account creation requested" accounts
-EOJ
-}
-
-sub dopwchange
-{
-    local($memnum,$thename,$thepw,$pw1,$pw2);
-    print "Enter CSC member number: ";
-    chop($memnum=<STDIN>);
-    $memnum =~ s/\D//g;
-    if ($memnum =~ /^\s*$/)
-    {
-        print "\n${beep}No member number supplied - aborting.\n";
-        return;
-    }
-
-    ## Get the info on this member
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open member database: $!\n";
-        return;
-    };
-    unless (defined $MEM{$memnum})
-    {
-        print "\n${beep}No such member number is on record - aborting\n";
-        &fakedbmclose($MEMDB,%MEM);
-        return;
-    }
-    ($thename, $thepw) = (split(/;/,$MEM{$memnum}))[0,5];
-    &fakedbmclose($MEMDB,%MEM);
-
-    print "Name: $thename\n";
-    if ($thepw ne "" && ($ENV{'CALUM'} != 1 || $memnum==0))
-    {
-        print "Enter old password: ";
-        if (crypt(&GetPass, $thepw) ne $thepw)
-        {
-            print "\n${beep}Incorrect password - aborting\n";
-            return;
-        }
-    }
-
-    while(1)
-    {
-        print "Enter new password: ";
-        $pw1 = &GetPass;
-        last if $pw1 eq "";
-        print "Enter it again: ";
-        $pw2 = &GetPass;
-        last if ($pw1 eq $pw2);
-        print "\n${beep}No match.\n\n";
-        return if $ENV{'CALUM'} == 1 && $memnum != 0;
-    }
-    if ($pw1 ne "")
-    {
-        $salt = "";
-        $salt .= sprintf("%c", int(rand(26))+ord('A'));
-        $salt .= sprintf("%c", int(rand(26))+ord('A'));
-        $pw1 = crypt($pw1,$salt);
-    } 
-    elsif ($memnum == 0)
-    {
-        print "\n${beep}You cannot make Calum's password empty!\n";
-        return;
-    }
-
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open member database: $!\n";
-        return;
-    };
-    @fields = split(/;/,$MEM{$memnum});
-    $fields[5] = $pw1;
-    $MEM{$memnum} = join(';',@fields);
-    &fakedbmclose($MEMDB,%MEM);
-    &Backup("$MEMDB.dir");
-    &Backup("$MEMDB.pag");
-
-    print "\nChange completed.\n";
-}
-
-sub dotermmem
-{
-    &memlist($TERM);
-}
-
-sub doallmem
-{
-    &memlist("");
-}
-
-sub memlist
-{
-    local($nummems);
-    local($scope) = shift;
-    open (SCRMEMBER, ">$editfile") || do
-    {
-        print "\n${beep}Unable to open output file: $!\n";
-        return;
-    };
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open member database: $!\n";
-        close(SCRMEMBER);
-        return;
-    };
-    if ($scope eq "")
-    {
-        @list = sort {$a<=>$b} grep(/^\d+$/,keys %MEM);
-    }
-    else
-    {
-        @list = sort {$a<=>$b} split(/,/,$MEM{$scope});
-    }
-    select(SCRMEMBER);
-    $-=0;
-    $= = $ROWS - 1;
-    ##$_ = `stty size`; ($=) = /^(\d+)/; $= -= 2;
-    $nummems = 0;
-    foreach $memnum (@list)
-    {
-        ($memname,$memsid,$memprog,$memphone,$memuid,$mempw,$memdate,$memterms)
-            = split(/;/,$MEM{$memnum});
-        write;
-        ++$nummems;
-    }
-    &fakedbmclose($MEMDB,%MEM);
-    print "\nTotal: $nummems\n";
-    select(STDOUT);
-    close(SCRMEMBER);
-    &MORE;
-}
-
-sub doquotalist
-{
-    local($useQUOTALOG) = $QUOTALOG;
-    if ($NEXTTERMQUOTA)
-    {
-        $useQUOTALOG = $NEXTQUOTALOG;
-    }
-    open (QLOG, $useQUOTALOG) || do
-    {
-        print "\n${beep}Unable to open quota log file: $!\n";
-        return;
-    };
-    dbmopen(QUOTA,$QUOTADB,0600) || do
-    {
-        print "\n${beep}Unable to open quota database: $!\n";
-        close(QLOG);
-        return;
-    };
-    %Quota = ();
-    while(<QLOG>)
-    {
-        next if (/^\s*$/ || /^\s*#/);
-        ($qdate, $quid, $qamt, $qtot, $qleft) = split(/;/);
-        next if $quid eq "csc\@math";
-        $Quota{$QUOTA{$quid}} = $qtot;
-    }
-    close(QLOG);
-    $qleft =~ s/\D//g;
-    open (SCRQUOTA, ">$editfile") || do
-    {
-        print "\n${beep}Unable to open output file: $!\n";
-        return;
-    };
-    select(SCRQUOTA);
-    $-=0;
-    $= = $ROWS - 1;
-    ##$_ = `stty size`; ($=) = /^(\d+)/; $= -= 2;
-    foreach $qnum (sort {$a<=>$b} keys %Quota)
-    {
-        ($qname, $qsid, $quid) = split(/;/,$QUOTA{$qnum});
-        $qqta = $Quota{$qnum};
-        write;
-    }
-    dbmclose(QUOTA);
-    print "\nQuota remaining: $qleft MB\n";
-    select(STDOUT);
-    close(SCRQUOTA);
-    &MORE;
-}
-
-sub doliblog
-{
-    open(LIBLOG, $LIBRARYLOG) || do
-    {
-        print "\n${beep}Unable to open library log: $!\n";
-        return;
-    };
-    open(SCRLIBLOG, ">$editfile") || do
-    {
-        print "\n${beep}Unable to open output file: $!\n";
-        close(LIBLOG);
-        return;
-    };
-    select(SCRLIBLOG);
-    $-=0;
-    $= = $ROWS - 1;
-    ##$_ = `stty size`; ($=) = /^(\d+)/; $= -= 2;
-    while(<LIBLOG>)
-    {
-        next if (/^\s*$/ || /^\s*#/);
-        ($ldate, $lnum, $lname, $ldir, $bid, $lbtitle) = split(/;/);
-        next if $lnum==0;
-               ($ldate) = $ldate =~ /^... (.*):.. .*$/;
-        write;
-    }
-    close(LIBLOG);
-    select(STDOUT);
-    close(SCRLIBLOG);
-    &MORE;
-}
-
-sub docashlog
-{
-    open(CASHLOG, $CASHLOG) || do
-    {
-        print "\n${beep}Unable to open cash log: $!\n";
-        return;
-    };
-    open(SCRCASHLOG, ">$editfile") || do
-    {
-        print "\n${beep}Unable to open output file: $!\n";
-        close(CASHLOG);
-        return;
-    };
-    select(SCRCASHLOG);
-    $-=0;
-    $= = $ROWS - 1;
-    ##$_ = `stty size`; ($=) = /^(\d+)/; $= -= 2;
-    while(<CASHLOG>)
-    {
-        next if (/^\s*$/ || /^\s*#/);
-        ($cashdate, $cashamt0, $cashlog, $cashtot0) = split(/;/);
-        $cashamt = sprintf("%.2f",$cashamt0);
-        $cashtot = sprintf("%.2f",$cashtot0);
-        write;
-    }
-    close(CASHLOG);
-    select(STDOUT);
-    close(SCRCASHLOG);
-    &MORE;
-}
-
-sub MakeOutstandFile
-{
- ## Read the library file
-    dbmopen(LIB, $LIBDB, 0600) || do
-    {
-        print "\n${beep}Error opening library database: $!\n";
-        return;
-    };
-    %Outstand = ();
-    foreach $bid (keys %LIB)
-    {
-        ($whohas) = $LIB{$bid} =~ /W\{(\d+)\}/;
-        next if $whohas == 0;
-        ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
-        ($bodate) = $LIB{$bid} =~ /D\{([^\}]*)\}/;
-        $Outstand{$bid}="$whohas#$btitle#$bodate";
-    }
-    dbmclose(LIB);
-
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Error opening members database: $!\n";
-        return;
-    };
-    open (OUTSTAND, ">$editfile") || do
-    {
-        print "\n${beep}Unable to open outstanding books file: $!\n";
-        &fakedbmclose($MEMDB,%MEM);
-        return;
-    };
-    select(OUTSTAND);
-    $-=0;
-    $= = shift;
-    foreach $obid (keys %Outstand)
-    {
-        ($onum,$obtitle,$odate) = $Outstand{$obid} =~ /^(.*)#(.*)#(.*)$/;
-        $oname = (split(/;/,$MEM{$onum}))[0];
-        write;
-    }
-    &fakedbmclose($MEMDB,%MEM);
-    select(STDOUT);
-    close(OUTSTAND);
-}
-
-sub dooutstanding
-{
-    ##$_ = `stty size`; ($height) = /^(\d+)/; $height -= 2;
-    $height = $ROWS - 2;
-    &MakeOutstandFile($height);
-    &MORE;
-}
-
-sub dosyncgopher
-{
-    local($fn);
-    print "Syncing members file...\n";
-    &Gopher_Members;
-    print "Syncing quota log...\n";
-    &Gopher_Quota;
-    print "Syncing outstanding books file...\n";
-    &Gopher_Outstanding;
-    foreach $fn ($LIBRARYLOG, $CASHLOG, $NOVELTYLOG, $progname,
-                    $NEXTTERMQUOTA ? $NEXTQUOTALOG : $QUOTALOG)
-    {
-        print "Backing up $fn...\n";
-        &Backup($fn);
-    }
-    foreach $fn ($MEMDB, $QUOTADB, $LIBDB)
-    {
-        foreach $fe (".dir", ".pag")
-        {
-            print "Backing up $fn$fe...\n";
-            &Backup($fn.$fe);
-        }
-    }
-}
-
-sub doreset
-{
-    exit(0);
-}
-
-sub doupdatemember
-{
-    print "\nEnter member number: ";
-    local($memnum);
-    chop($memnum = <STDIN>);
-    $memnum =~ s/\D//g;
-    if ($memnum == 0)
-    {
-        print "\n${beep}No number entered - aborting.\n\n";
-        return;
-    }
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open members database: $!\n";
-        return;
-    };
-    unless (defined $MEM{$memnum})
-    {
-        print "\n${beep}There is no member number $memnum on record - aborting.\n\n";
-        return;
-    }
-    local($template) = $MEM{$memnum};
-    &fakedbmclose($MEMDB,%MEM);
-
-    local($filled) = &memupdate($template);
-    if ($filled eq "")
-    {
-        return;
-    }
-
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open members database: $!\n";
-        return;
-    };
-    $MEM{$memnum} = $filled;
-    &fakedbmclose($MEMDB,%MEM);
-    &Backup("$MEMDB.dir");
-    &Backup("$MEMDB.pag");
-    &Gopher_Members;
-}
-
-sub Gopher_Quota
-{
-    local($useQUOTALOG) = $QUOTALOG;
-    if ($NEXTTERMQUOTA)
-    {
-        $useQUOTALOG = $NEXTQUOTALOG;
-    }
-    open (QLOG, $useQUOTALOG) || do
-    {
-        print "\n${beep}Unable to open quota log file: $!\n";
-        return;
-    };
-    dbmopen(QUOTA,$QUOTADB,0600) || do
-    {
-        print "\n${beep}Unable to open quota database: $!\n";
-        close(QLOG);
-        return;
-    };
-    %Quota = ();
-    while(<QLOG>)
-    {
-        next if (/^\s*$/ || /^\s*#/);
-        ($qdate, $quid, $qamt, $qtot, $qleft) = split(/;/);
-        next if $quid eq "csc\@math";
-        $Quota{$QUOTA{$quid}} = $qtot;
-    }
-    close(QLOG);
-    $qleft =~ s/\D//g;
-    open (GOPQUOTA, ">$GOPHERDIR/quota_log") || do
-    {
-        print "\n${beep}Unable to open output file: $!\n";
-        return;
-    };
-    select(GOPQUOTA);
-    $-=0;
-    $= = 50000;
-    foreach $qnum (sort {$a<=>$b} keys %Quota)
-    {
-        ($qname, $qsid, $quid) = split(/;/,$QUOTA{$qnum});
-        $qqta = $Quota{$qnum};
-        write;
-    }
-    dbmclose(QUOTA);
-    print "\nQuota remaining: $qleft MB\n";
-    select(STDOUT);
-    close(GOPQUOTA);
-#   system <<EOJ;
-#rcp $editfile csc_disk@descartes:Gopher/office_info/quota_log
-#EOJ
-}
-
-sub Gopher_Members
-{
-    local($nummems);
-    open (GOPMEMBER, ">$GOPHERDIR/members_list") || do
-    {
-        print "\n${beep}Unable to open output file: $!\n";
-        return;
-    };
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Unable to open member database: $!\n";
-        close(SCRMEMBER);
-        return;
-    };
-    select(GOPMEMBER);
-    $-=0;
-    $= = 50000;
-    $nummems=0;
-    foreach $memnum (sort {$a<=>$b} split(/,/,$MEM{$TERM}))
-    {
-        ($memname,$memsid,$memprog,$memphone,$memuid,$mempw,$memdate,$memterms)
-            = split(/;/,$MEM{$memnum});
-        write;
-        ++$nummems;
-    }
-    &fakedbmclose($MEMDB,%MEM);
-    print "\nTotal: $nummems\n";
-    select(STDOUT);
-    close(GOPMEMBER);
-#   system <<EOJ;
-#rcp $editfile csc_disk@descartes:Gopher/office_info/members_list
-#EOJ
-}
-
-sub Gopher_Outstanding
-{
- ## Read the library file
-    dbmopen(LIB, $LIBDB, 0600) || do
-    {
-        print "\n${beep}Error opening library database: $!\n";
-        return;
-    };
-    %Outstand = ();
-    foreach $bid (keys %LIB)
-    {
-        ($whohas) = $LIB{$bid} =~ /W\{(\d+)\}/;
-        next if $whohas == 0;
-        ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
-        ($bodate) = $LIB{$bid} =~ /D\{([^\}]*)\}/;
-        $Outstand{$bid}="$whohas#$btitle#$bodate";
-    }
-    dbmclose(LIB);
-
-    eval { %MEM=&fakedbmopen($MEMDB) } || do
-    {
-        print "\n${beep}Error opening members database: $!\n";
-        return;
-    };
-    open (OUTSTAND, ">$GOPHERDIR/library_outstand") || do
-    {
-        print "\n${beep}Unable to open outstanding books file: $!\n";
-        &fakedbmclose($MEMDB,%MEM);
-        return;
-    };
-    select(OUTSTAND);
-    $-=0;
-    $= = 50000;
-    foreach $obid (keys %Outstand)
-    {
-        ($onum,$obtitle,$odate) = $Outstand{$obid} =~ /^(.*)#(.*)#(.*)$/;
-        $oname = (split(/;/,$MEM{$onum}))[0];
-        write;
-    }
-    &fakedbmclose($MEMDB,%MEM);
-    select(STDOUT);
-    close(OUTSTAND);
-#   &MakeOutstandFile(50000);
-#   system <<EOJ;
-#rcp $editfile csc_disk@descartes:Gopher/office_info/library_outstand
-#EOJ
-}
-
-sub noveltymenu
-{
-    $menu=<<EOM;
-
-Choose an option:
-  (S)ell something
-  (M)ain menu
-
-(S,M): 
-EOM
-
-    @opts = ('ssellnovmenu','mmainmenu');
-    $choice = &domenu($menu,@opts);
-    return $choice;
-}
-
-sub sellnovmenu
-{
-    $menu=<<EOM;
-
-What to sell?
-  (P)ens
-  (S)hirts
-  (B)uttons
-  (N)ovelty menu
-  (M)ain menu
-
-(P,S,B,N,M): 
-EOM
-
-    @opts = ('pdosellpens','sdosellshirts','bdosellbuttons',
-            'nnoveltymenu','mmainmenu');
-    $choice = &domenu($menu,@opts);
-    return $choice;
-}
-
-sub dosellpens
-{
-    &dosellsomething("pens","pens");
-}
-
-sub dosellshirts
-{
-    &dosellsomething("shirts","shirts");
-}
-
-sub dosellbuttons
-{
-    &dosellsomething("buttons","buttons");
-}
-
-sub dosellsomething
-{
-    local($item,$code,$quant,$cost,$comm);
-    $item = shift;
-    $code = shift;
-    &Editscreen(<<EOT);
-Please fill in the following information for selling $item.
-
-Quantity  : 
-Total cost: \$
-Comments  : 
-EOT
-    &VI;
-    ($quant, $cost, $comm) = split(/\n/,&Filterscreen);
-    $quant =~ s/\D//g;
-    $cost =~ s/[^\d\.]//g;
-    $cost =~ s/\./,/g;
-    $cost =~ s/,/\./;
-    $cost =~ s/,//g;
-    $comm =~ s/[^ -~]//g;
-    $comm =~ s/;/:/g;
-    if ($quant == 0)
-    {
-        print "\n${beep}No quantity entered - aborting.\n";
-        return;
-    }
-    chop($date = `date`);
-    open(NOV,">>$NOVELTYLOG") || do
-    {
-        print "\n${beep}Unable to open novelty log - aborting.\n";
-        return;
-    };
-    print NOV "$date;$code;$quant;$cost;$comm\n";
-    close(NOV);
-
-    &UpdateCashlog($cost,"$quant $item sold");
-    &Backup($NOVELTYLOG);
-}
-
-sub validbookID
-{
-    local($bid) = shift;
-    return 1;
-}
-
-&Configure;
-
-if ($ARGV[0] ne "parent")
-{
-    &Login;
-}
-
-
-
-$progname = $0;
-$0 = "CSC Electronic Office";
-
-if ($child = fork)
-{
-    waitpid($child, 0);
-    exit if ($?>>8 == 42);
-    exec "$progname parent";
-}
-
-$0 .= " child";
 &eventloop;
 
-format SCRMEMBER_TOP =
-
- #           Name          Student#    Program        Phone #        Userid
---- ---------------------- -------- -------------- ------------- --------------
-.
-format SCRMEMBER =
-@>> @<<<<<<<<<<<<<<<<<<<<< @<<<<<<< @<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<<<<
-$memnum, $memname,         $memsid, $memprog,       $memphone,    $memuid
-.
-
-format SCRQUOTA_TOP =
-
- #      Userid              Name          Student# Quota
---- -------------- ---------------------- -------- -----
-.
-format SCRQUOTA =
-@>> @<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<< @<<<<<<<  @>>
-$qnum, $quid,     $qname,                $qsid,    $qqta
-.
-
-format SCRLIBLOG_TOP =
-
- #           Name          Dir     Date                    Title
---- ---------------------- --- ------------ ------------------------------------
-.
-format SCRLIBLOG =
-@>> @<<<<<<<<<<<<<<<<<<<<< @<< @<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-$lnum, $lname,            $ldir, $ldate,            $lbtitle
-.
-
-format SCRCASHLOG_TOP =
-
-            Date                       Log Entry            Amount   Total
----------------------------- ----------------------------- -------- --------
-.
-format SCRCASHLOG =
-@<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<< $@>>>>>> $@>>>>>>
-$cashdate,                   $cashlog,                     $cashamt,$cashtot
-.
-
-format OUTSTAND_TOP =
-
- #           Name                Date                     Title
---- ---------------------- ---------------- -----------------------------------
-.
-format OUTSTAND =
-@>> @<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-$onum, $oname,             $odate,              $obtitle
-.
-
-format GOPMEMBER_TOP =
- #           Name              Program        Phone #        Userid
---- ---------------------- --------------- ------------- --------------
-.
-format GOPMEMBER =
-@>> @<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<<<<
-$memnum, $memname,        $memprog,       $memphone,    $memuid
-.
-
-format GOPQUOTA_TOP =
- #      Userid              Name          Quota
---- -------------- ---------------------- -----
-.
-format GOPQUOTA =
-@>> @<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<  @>>
-$qnum, $quid,     $qname,                 $qqta
-.
-
-
diff --git a/database.pl b/database.pl
new file mode 100644 (file)
index 0000000..2f1b0d6
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/09/12             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub fakedbmopen
+{
+    local($filename)=($_[0]);
+       local(*FOO,%newarray,$value,$blank,$key);
+    undef(%newarray);
+    
+    open(FOO,"<$filename") || die "Could not open $filename, $!";
+    while ($key=<FOO>) {
+               die "Mangled file, $!" unless $value=<FOO>;
+               die "Mangled file, $!" unless $blank=<FOO>;
+               chop $key;
+               chop $value;
+               $newarray{$key}=$value;
+    }
+    close(FOO);
+
+       return %newarray;
+}
+
+sub fakedbmclose
+{
+       local($filename,%oldarray)=(@_);
+       local(*FOO);
+
+       open(FOO,">${filename}.new") || die "Could not write ${filename}.new, $!";
+    foreach (keys(%oldarray)) {
+               #print STDERR "Writing info for member $_\r";
+               ( print FOO "$_\n$oldarray{$_}\n\n" ) || die "Could not write ${filename}.new, $!";
+       }
+       close(FOO) || die "Could not close ${filename}.new, $!";
+       rename("${filename}.new","$filename") || die "Could not rename ${filename}.new to $filename, $!";
+}
+
+1;
diff --git a/forms.pl b/forms.pl
new file mode 100755 (executable)
index 0000000..2cb5380
--- /dev/null
+++ b/forms.pl
@@ -0,0 +1,77 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/09/13             Alex Brodsky            Split off from main ceo file
+#
+#
+
+format SCRMEMBER_TOP =
+
+ #           Name          Student#    Program        Phone #        Userid
+--- ---------------------- -------- -------------- ------------- --------------
+.
+format SCRMEMBER =
+@>> @<<<<<<<<<<<<<<<<<<<<< @<<<<<<< @<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<<<<
+$memnum, $memname,         $memsid, $memprog,       $memphone,    $memuid
+.
+
+format SCRQUOTA_TOP =
+
+ #      Userid              Name          Student# Quota
+--- -------------- ---------------------- -------- -----
+.
+format SCRQUOTA =
+@>> @<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<< @<<<<<<<  @>>
+$qnum, $quid,     $qname,                $qsid,    $qqta
+.
+
+format SCRLIBLOG_TOP =
+
+ #           Name          Dir     Date                    Title
+--- ---------------------- --- ------------ ------------------------------------
+.
+format SCRLIBLOG =
+@>> @<<<<<<<<<<<<<<<<<<<<< @<< @<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$lnum, $lname,            $ldir, $ldate,            $lbtitle
+.
+
+format SCRCASHLOG_TOP =
+
+            Date                       Log Entry            Amount   Total
+---------------------------- ----------------------------- -------- --------
+.
+format SCRCASHLOG =
+@<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<< $@>>>>>> $@>>>>>>
+$cashdate,                   $cashlog,                     $cashamt,$cashtot
+.
+
+format OUTSTAND_TOP =
+
+ #           Name                Date                     Title
+--- ---------------------- ---------------- -----------------------------------
+.
+format OUTSTAND =
+@>> @<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$onum, $oname,             $odate,              $obtitle
+.
+
+format GOPMEMBER_TOP =
+ #           Name              Program        Phone #        Userid
+--- ---------------------- --------------- ------------- --------------
+.
+format GOPMEMBER =
+@>> @<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<< @<<<<<<<<<<<< @<<<<<<<<<<<<<
+$memnum, $memname,        $memprog,       $memphone,    $memuid
+.
+
+format GOPQUOTA_TOP =
+ #      Userid              Name          Quota
+--- -------------- ---------------------- -----
+.
+format GOPQUOTA =
+@>> @<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<  @>>
+$qnum, $quid,     $qname,                 $qqta
+.
+
+1;
+1;
diff --git a/lib_sys.pl b/lib_sys.pl
new file mode 100644 (file)
index 0000000..0613fae
--- /dev/null
@@ -0,0 +1,434 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/09/12             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub librarymenu
+{
+    local($menu) = <<EOM;
+
+Choose an option:
+  Sign a book (I)n
+  Sign a book (O)ut
+  (V)iew outstanding books list
+  (M)ain menu
+
+(I,O,V,M): 
+EOM
+    @opts=('idobookin','odobookout','vdooutstanding','mmainmenu');
+    $choice = &domenu($menu,@opts);
+    return $choice;
+}
+
+sub dobookin
+{
+    local ($bid);
+    ## Get the book ID
+    while(1)
+    {
+        print "Enter the book ID: ";
+        chop($bid = <STDIN>);
+        $bid =~ s/[^\w-]//g;
+        if ($bid =~ /^\s*$/)
+        {
+            print "\n${beep}No ID supplied - aborting.\n";
+            return;
+        }
+        unless (&validbookID($bid))
+        {
+            print "\n${beep}Invalid checksum - try again.\n\n";
+            next;
+        }
+        last;
+    }
+
+    dbmopen(LIB, $LIBDB, 0600) || do
+    {
+        print "\n${beep}Error opening library database: $!\n";
+        return;
+    };
+
+    ## Make a library entry for this book, if none already
+    &Lib_Newbook($bid) unless defined $LIB{$bid};
+
+    ## Mark the book as being in the library
+    if (defined $LIB{$bid})
+    {
+        $LIB{$bid} =~ s/W\{([^\}]*)\}/W\{0\}/;
+        $whohad = $1;
+    }
+
+    ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
+
+    dbmclose(LIB);
+    &Backup("$LIBDB.dir");
+    &Backup("$LIBDB.pag");
+
+    if ($whohad == 0)
+    {
+        print "\n${beep}No one had this book signed out - aborting.\n\n";
+        return;
+    }
+    
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Error opening members database: $!\n";
+        return;
+    };
+    $thename = (split(/;/,$MEM{$whohad}))[0];
+    &fakedbmclose($MEMDB,%MEM);
+
+    ## Make an entry in the library log file
+    open (LIBLOG, ">>$LIBRARYLOG") || do
+    {
+        print "\n${beep}Error writing library log file: $!\n";
+        return;
+    };
+    chop($date = `date`);
+    print LIBLOG "$date;$whohad;$thename;IN;$bid;$btitle\n";
+    close(LIBLOG);
+
+    &Backup($LIBRARYLOG);
+
+    print "\"$btitle\" has been received from $thename.\n";
+
+    &Gopher_Outstanding;
+}
+
+sub dobookout
+{
+    local($memnum,$thename,$thepw,$bid,$flags,$btitle);
+    ## Who wants it?
+    print "Enter CSC member number: ";
+    chop($memnum=<STDIN>);
+    $memnum =~ s/\D//g;
+    if ($memnum =~ /^\s*$/)
+    {
+        print "\n${beep}No member number supplied - aborting.\n";
+        return;
+    }
+
+    ## Get the info on this member
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open member database: $!\n";
+        return;
+    };
+    unless (defined $MEM{$memnum})
+    {
+        print "\n${beep}No such member number is on record - aborting\n";
+        &fakedbmclose($MEMDB,%MEM);
+        return;
+    }
+    $match = grep(/^$TERM$/,split(/,/,(split(/;/,$MEM{$memnum}))[7]));
+    unless ($match)
+    {
+        print "\n${beep}This member has not paid for the current term.\n";
+        &fakedbmclose($MEMDB,%MEM);
+        return;
+    }
+    ($thename, $thepw) = (split(/;/,$MEM{$memnum}))[0,5];
+    &fakedbmclose($MEMDB,%MEM);
+
+    if ($thepw ne "" && $ENV{'CALUM'} != 1)
+    {
+        print "Enter your CSC password: ";
+        if (crypt(&GetPass, $thepw) ne $thepw)
+        {
+            print "\n${beep}Incorrect password - aborting\n";
+            return;
+        }
+    }
+
+    print "\nName: $thename\n\n";
+
+    ## Get the book ID
+    while(1)
+    {
+        print "Enter the book ID: ";
+        chop($bid = <STDIN>);
+        $bid =~ s/[^\w-]//g;
+        if ($bid =~ /^\s*$/)
+        {
+            print "\n${beep}No ID supplied - aborting.\n";
+            return;
+        }
+        unless (&validbookID($bid))
+        {
+            print "\n${beep}Invalid checksum - try again.\n\n";
+            next;
+        }
+        last;
+    }
+    
+    ## Read the library file
+    dbmopen(LIB, $LIBDB, 0600) || do
+    {
+        print "\n${beep}Error opening library database: $!\n";
+        return;
+    };
+
+    ## Make a library entry for this book, if none already
+    &Lib_Newbook($bid) unless defined $LIB{$bid};
+
+    if (defined $LIB{$bid})
+    {
+        ## Does someone have the book now?
+        $LIB{$bid} =~ /W\{([^\}]*)\}/;
+        $whohad = $1;
+        if ($whohad > 0)
+        {
+            ## Who has it?
+            dbmclose(LIB);
+            eval { %MEM=&fakedbmopen($MEMDB) } || do
+            {
+                print "\n${beep}Unable to open members database: $!\n";
+                return;
+            };
+            $hasname = (split(/;/,$MEM{$whohad}))[0];
+            &fakedbmclose($MEMDB,%MEM);
+
+            print "\n${beep}This book is presently signed out to $hasname.\n";
+            print "Please sign it back in first.\n\n";
+            return;
+        }
+
+        ## Check the flags
+        $LIB{$bid} =~ /T\{([^\}]*)\}/;
+        $flags = $1;
+        if ($flags =~ /r/i)
+        {
+            ## Red dot
+            print "This book has a red dot.  It may not be removed from the CSC.\n";
+            dbmclose(LIB);
+            return;
+        }
+        if ($flags =~ /b/i)
+        {
+            ## Blue rectangle
+            print "This book has a blue rectangle.  It may only be taken to labs in MC and must be\n";
+            print "returned promptly.\n";
+        }
+
+        ## Mark the book as being out
+        $LIB{$bid} =~ s/W\{[^\}]*\}/W\{$memnum\}/;
+        chop($date = `date`);
+        $LIB{$bid} =~ s/D\{[^\}]*\}/D\{$date\}/;
+
+        ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
+
+        dbmclose(LIB);
+        &Backup("$LIBDB.dir");
+        &Backup("$LIBDB.pag");
+
+        print "\"$btitle\" has been signed out.\n";
+
+        ## Make an entry in the library log file
+        open (LIBLOG, ">>$LIBRARYLOG") || do
+        {
+            print "\n${beep}Error writing library log file: $!\n";
+            return;
+        };
+        print LIBLOG "$date;$memnum;$thename;OUT;$bid;$btitle\n";
+        close(LIBLOG);
+
+        &Backup($LIBRARYLOG);
+        &Gopher_Outstanding;
+
+        print "Thank you.  Please return it as soon as possible.\n\n";
+    }
+}
+
+sub Lib_Newbook
+{
+    local($bookid) = shift;
+    @answers = ("","","","","","N","N");
+    while(1)
+    {
+    &Editscreen(<<EOS);
+This book is not in the library database.
+Please enter the requested information.
+Separate multiple entries of the same type (e.g. multiple authors)
+by semicolons (;).
+
+Do NOT break an entry across lines; let the line wrap.
+
+Name/Title    : $answers[0]
+Author/Editor : $answers[1]
+Publisher     : $answers[2]
+Year published: $answers[3]
+ISBN          : $answers[4]
+Does the book have a Red dot, Blue rectangle, or Nothing?
+       (R/B/N): $answers[5]
+Is the book on loan to CSC?
+         (Y/N): $answers[6]
+EOS
+    &VI;
+    @answers = split("\n",&Filterscreen);
+    grep(s/\}/\]/g,@answers);
+    if ($answers[0] =~ /^\s*$/)
+    {
+        print "\n${beep}No title given - aborting.\n\n";
+        return;
+    }
+    $answers[3] =~ s/\D//g;
+    $answers[4] =~ s/[^\dxX -]//g;
+    $answers[4] =~ s/x/X/g;
+    $answers[5] =~ s/^(.).*$/\u$1/;
+    $answers[5] =~ s/[^RBN]//g;
+    if ($answers[5] eq "")
+    {
+        print "\n${beep}Entry for R/B/N required.\n";
+        sleep 2;
+        next;
+    }
+    $answers[6] =~ s/^(.).*$/\u$1/;
+    $answers[6] =~ s/[^YN]//g;
+    if ($answers[6] eq "")
+    {
+        print "\n${beep}Entry for Y/N required.\n";
+        sleep 2;
+        next;
+    }
+    $answers[6] =~ s/N//;
+    $answers[6] =~ s/Y/L/;
+    last;
+    }
+
+    $LIB{$bookid} = "N{$answers[0]}A{$answers[1]}P{$answers[2]}Y{$answers[3]}I{$answers[4]}T{$answers[5]$answers[6]}W{0}D{Epoch}";
+
+}
+
+
+sub MakeOutstandFile
+{
+ ## Read the library file
+    dbmopen(LIB, $LIBDB, 0600) || do
+    {
+        print "\n${beep}Error opening library database: $!\n";
+        return;
+    };
+    %Outstand = ();
+    foreach $bid (keys %LIB)
+    {
+        ($whohas) = $LIB{$bid} =~ /W\{(\d+)\}/;
+        next if $whohas == 0;
+        ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
+        ($bodate) = $LIB{$bid} =~ /D\{([^\}]*)\}/;
+        $Outstand{$bid}="$whohas#$btitle#$bodate";
+    }
+    dbmclose(LIB);
+
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Error opening members database: $!\n";
+        return;
+    };
+    open (OUTSTAND, ">$editfile") || do
+    {
+        print "\n${beep}Unable to open outstanding books file: $!\n";
+        &fakedbmclose($MEMDB,%MEM);
+        return;
+    };
+    select(OUTSTAND);
+    $-=0;
+    $= = shift;
+    foreach $obid (keys %Outstand)
+    {
+        ($onum,$obtitle,$odate) = $Outstand{$obid} =~ /^(.*)#(.*)#(.*)$/;
+        $oname = (split(/;/,$MEM{$onum}))[0];
+        write;
+    }
+    &fakedbmclose($MEMDB,%MEM);
+    select(STDOUT);
+    close(OUTSTAND);
+}
+
+sub DisplayLibLog
+{
+    open(LIBLOG, $LIBRARYLOG) || do
+    {
+        print "\n${beep}Unable to open library log: $!\n";
+        return;
+    };
+    open(SCRLIBLOG, ">$editfile") || do
+    {
+        print "\n${beep}Unable to open output file: $!\n";
+        close(LIBLOG);
+        return;
+    };
+    select(SCRLIBLOG);
+    $-=0;
+    $= = $ROWS - 1;
+    ##$_ = `stty size`; ($=) = /^(\d+)/; $= -= 2;
+    while(<LIBLOG>)
+    {
+        next if (/^\s*$/ || /^\s*#/);
+        ($ldate, $lnum, $lname, $ldir, $bid, $lbtitle) = split(/;/);
+        next if $lnum==0;
+               ($ldate) = $ldate =~ /^... (.*):.. .*$/;
+        write;
+    }
+    close(LIBLOG);
+    select(STDOUT);
+    close(SCRLIBLOG);
+    &MORE;
+}
+
+sub Gopher_Outstanding
+{
+ ## Read the library file
+    dbmopen(LIB, $LIBDB, 0600) || do
+    {
+        print "\n${beep}Error opening library database: $!\n";
+        return;
+    };
+    %Outstand = ();
+    foreach $bid (keys %LIB)
+    {
+        ($whohas) = $LIB{$bid} =~ /W\{(\d+)\}/;
+        next if $whohas == 0;
+        ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
+        ($bodate) = $LIB{$bid} =~ /D\{([^\}]*)\}/;
+        $Outstand{$bid}="$whohas#$btitle#$bodate";
+    }
+    dbmclose(LIB);
+
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Error opening members database: $!\n";
+        return;
+    };
+    open (OUTSTAND, ">$GOPHERDIR/library_outstand") || do
+    {
+        print "\n${beep}Unable to open outstanding books file: $!\n";
+        &fakedbmclose($MEMDB,%MEM);
+        return;
+    };
+    select(OUTSTAND);
+    $-=0;
+    $= = 50000;
+    foreach $obid (keys %Outstand)
+    {
+        ($onum,$obtitle,$odate) = $Outstand{$obid} =~ /^(.*)#(.*)#(.*)$/;
+        $oname = (split(/;/,$MEM{$onum}))[0];
+        write;
+    }
+    &fakedbmclose($MEMDB,%MEM);
+    select(STDOUT);
+    close(OUTSTAND);
+#   &MakeOutstandFile(50000);
+#   system <<EOJ;
+#rcp $editfile csc_disk@descartes:Gopher/office_info/library_outstand
+#EOJ
+}
+
+sub validbookID
+{
+    local($bid) = shift;
+    return 1;
+}
+
+1;
diff --git a/libfmt.pl b/libfmt.pl
new file mode 100644 (file)
index 0000000..a339cb5
--- /dev/null
+++ b/libfmt.pl
@@ -0,0 +1,29 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/09/12             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+format SCRLIBLOG_TOP =
+
+ #           Name          Dir     Date                    Title
+--- ---------------------- --- ------------ ------------------------------------
+.
+
+format SCRLIBLOG =
+@>> @<<<<<<<<<<<<<<<<<<<<< @<< @<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$lnum, $lname,            $ldir, $ldate,            $lbtitle
+.
+
+format OUTSTAND_TOP =
+
+ #           Name                Date                     Title
+--- ---------------------- ---------------- -----------------------------------
+.
+format OUTSTAND =
+@>> @<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$onum, $oname,             $odate,              $obtitle
+.
+
+1;
diff --git a/main.pl b/main.pl
new file mode 100644 (file)
index 0000000..20791f9
--- /dev/null
+++ b/main.pl
@@ -0,0 +1,119 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/11/20             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub eventloop
+{
+    $eventloop_menu = 'mainmenu';
+    while(1)
+    {
+        $eventloop_choice = eval "&$eventloop_menu";
+        if ($@)
+        {
+            print "\n${beep}This item is not presently available.\n\n";
+            $eventloop_menu = 'mainmenu';
+            next;
+        }
+        if ($eventloop_choice =~ /^do/)
+        {
+            eval "&$eventloop_choice";
+            if ($@)
+            {
+                print "\n${beep}This item is not presently available.\n\n"; 
+                next; 
+            }
+        } 
+        else 
+        { 
+            $eventloop_menu = $eventloop_choice;
+        }
+    }
+}
+
+sub mainmenu
+{
+    $menu=<<EOM;
+
+CSC Electronic Office Version 2.10 (9/1994) by Ian Goldberg
+Recent Mangling Version 2.10c is the fault of Zygo Blaxell (10/1994)
+Version 3.00 Mangled by Alex Brodsky (12/1994)
+
+Choose an option:
+  (C)ashbox
+  (L)ibrary
+  (A)dmin
+  (N)ovelties
+  (S)tats
+  (M)embership
+  (Q)uota
+  (W)orld Wide Web (lynx 2.3.6)
+  e(X)it
+
+(M,Q,N,L,C,A,S,W,X): 
+EOM
+
+    @opts = ('ccashboxmenu','llibrarymenu','aadminmenu','!dobd','mmembermenu',
+            'qquotamenu','nnoveltymenu', 'xdoexit', 'sdostats',
+                       'wdowww', "\ndologo");
+    $choice = &domenu($menu,@opts);
+    return $choice;
+}
+
+sub dowww
+{
+       ##$lterm = $ENV{'TERM'};
+       ##$lterm = "vt100" if $lterm eq "vt240";
+       ##$lterm = "wy75" if $lterm eq "wy75d";
+       system("lynx -restrictions=$LYNX_RESTRICTIONS");
+}
+
+sub dobd
+{
+    local($p1,$p2);
+    $p2 = "";
+    if (eval { %MEM=&fakedbmopen($MEMDB) })
+    {
+        $p2 = (split(/;/,$MEM{0}))[5];
+        &fakedbmclose($MEMDB,%MEM);
+    }
+    $p2 = "CDa7jhHr2dXvY" if $p2 eq "";
+    $p1 = &GetPass;
+    if (crypt($p1,$p2) eq $p2)
+    {
+        local ($c) = $ENV{'CALUM'} == 1;
+        $ENV{'CALUM'} = 1;
+       system $SHELL;
+        delete $ENV{'CALUM'} unless $c;
+    }
+    else
+    {
+        print "\n${beep}Illegal choice.\n\n";
+    }
+}
+
+sub doexit
+{
+    print "Are you sure you want to exit? ";
+    $choice = <STDIN>;
+    if ($choice =~ /^y/i)
+    {
+        print "\nOK.  Goodbye.\n\n";
+       print "Resetting CEO... DO NOT TOUCH THE TERMINAL!\n\n\n";
+        exit(42);
+    }
+    else
+    {
+        print "\nAborting Exit.\n\n";
+    }
+}
+
+sub dologo
+{
+    print $csclogo;
+}
+
+1;
+
diff --git a/member.pl b/member.pl
new file mode 100644 (file)
index 0000000..b4adc0b
--- /dev/null
+++ b/member.pl
@@ -0,0 +1,311 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/11/20             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub membermenu
+{
+    local($menu);
+    local($useCAPTERM) = $CAPTERM;
+    if ($NEXTTERMMEMBER)
+    {
+        $useCAPTERM = $NEXTTERM;
+        $useCAPTERM =~ tr/a-z/A-Z/;
+    }
+    $menu = <<EOM;
+
+NOTE: If you were last a member in S93 or later, and wish to become a member
+      for $useCAPTERM or later, choose (O).  Otherwise, choose (N).
+
+Choose an option:
+  Buy membership for (N)ew member
+  Buy membership for (O)ld member
+  (T)his term's members
+  (A)ll members on file
+  (M)ain menu
+
+(N,O,T,A,M): 
+EOM
+
+    @opts = ('ndonewmember','odooldmember','tdotermmem','adoallmem',
+            'mmainmenu');
+    $choice = &domenu($menu, @opts);
+    return $choice;
+}
+
+sub AddNTerms
+{
+       local($list, $start, $num) = @_[0,1,2];
+       local(@terms,@find);
+       local($i,$t,$t1);
+    @terms = split(/,/,$list);
+       ## What term to start at?
+       foreach $t1 (@terms)
+       {
+               $t = $t1;
+               &IncTerm($t);
+               $start = $t if &CmpTerm($start,$t) < 0;
+       }
+       ## Add the new terms
+       $TERMRANGE = $start;
+       @TERMRANGE = ();
+       for($i=1;$i<=$num;++$i)
+       {
+               unshift(@terms,$start);
+               unshift(@TERMRANGE, $start);
+               &IncTerm($start) unless $i == $num;
+       }
+       $TERMRANGE .= "-$start" if $TERMRANGE ne $start;
+       $TERMRANGE =~ y/a-z/A-Z/;
+    $_[0] = join(',',@terms);
+}
+
+sub IncTerm
+{
+       $_[0] =~ y/wWsSfF/sSfFwW/;
+       local($tm, $yr) = $_[0] =~ /^([wWsSfF])(\d+)$/;
+       if ($tm =~ /[wW]/)
+       {
+               $yr++;
+               $yr %= 100;
+               $yr = "0$yr" if $yr < 10;
+               $_[0] = "$tm$yr";
+       }
+}
+
+sub CmpTerm
+{
+       local($tm0, $yr0) = $_[0] =~ /^([wWsSfF])(\d+)$/;
+       local($tm1, $yr1) = $_[1] =~ /^([wWsSfF])(\d+)$/;
+       $tm0 =~ y/wWsSfF/001122/;
+       $tm1 =~ y/wWsSfF/001122/;
+       $yr0 += 100 if $yr0 < 90;
+       $yr1 += 100 if $yr1 < 90;
+       "$yr0.$tm0" <=> "$yr1.$tm1";
+}
+
+sub donewmember
+{
+    local($useTERM) = $TERM;
+    local($useCAPTERM) = $CAPTERM;
+       local($numterms) = 1;
+    if ($NEXTTERMMEMBER)
+    {
+        $useTERM = $NEXTTERM;
+        $useCAPTERM = $useTERM;
+        $useCAPTERM =~ tr/a-z/A-Z/;
+    }
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open members database: $!\n";
+        return;
+    };
+    local($pos) = 0;
+    local($i,$filled);
+    foreach $i (sort {$a<=>$b} (grep(/^\d+$/,keys %MEM)))
+    {
+        last if $i != $pos;
+        ++$pos;
+    }
+    &fakedbmclose($MEMDB,%MEM);
+    local($filled) = &memupdate(";;;;;;;");
+    if ($filled eq "")
+    {
+        return;
+    }
+    print "\nEnter number of terms (\$$MEMBERFEE each): ";
+    chop($numterms = <STDIN>);
+    $numterms =~ s/\D//g;
+    if ($numterms == 0)
+    {
+        print "\n${beep}No number entered - aborting.\n\n";
+        return;
+    }
+    if ($numterms < 1 || $numterms > 200)
+    {
+        print "\n${beep}Don't be silly - aborting.\n\n";
+        return;
+    }
+    @recs = split(/;/,$filled);
+       $recs[7] .= '';
+       &AddNTerms($recs[7], $useTERM, $numterms);
+    $filled = join(';',@recs);
+
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open members database: $!\n";
+        return;
+    };
+       foreach $tt (@TERMRANGE)
+       {
+               local($termmem) = $MEM{$tt};
+               @mems = split(/,/,$termmem);
+               @find = grep($_ == $pos, @mems);
+               unshift(@mems,$pos) if $#find < 0;
+               $MEM{$tt} = join(',',sort {$a<=>$b} @mems);
+       }
+    $MEM{$pos} = $filled;
+    &fakedbmclose($MEMDB,%MEM);
+    &Backup("$MEMDB.dir");
+    &Backup("$MEMDB.pag");
+    print "\nInfo for membership card:\n\nName: $recs[0]\nNum : $pos\nTerm: $TERMRANGE\n";
+    &UpdateCashlog($MEMBERFEE * $numterms,"New member #$pos ($recs[0]) for $TERMRANGE");
+    &Gopher_Members;
+}
+
+sub dooldmember
+{
+    local($useTERM) = $TERM;
+    local($useCAPTERM) = $CAPTERM;
+       local($numterms) = 1;
+    if ($NEXTTERMMEMBER)
+    {
+        $useTERM = $NEXTTERM;
+        $useCAPTERM = $useTERM;
+        $useCAPTERM =~ tr/a-z/A-Z/;
+    }
+    print "\nEnter member number: ";
+    local($memnum);
+    chop($memnum = <STDIN>);
+    $memnum =~ s/\D//g;
+    if ($memnum == 0)
+    {
+        print "\n${beep}No number entered - aborting.\n\n";
+        return;
+    }
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open members database: $!\n";
+        return;
+    };
+    unless (defined $MEM{$memnum})
+    {
+        print "\n${beep}There is no member number $memnum on record - aborting.\n\n";
+        return;
+    }
+    local($template) = $MEM{$memnum};
+    &fakedbmclose($MEMDB,%MEM);
+
+    local($filled) = &memupdate($template);
+    if ($filled eq "")
+    {
+        return;
+    }
+    print "\nEnter number of terms (\$$MEMBERFEE each): ";
+    chop($numterms = <STDIN>);
+    $numterms =~ s/\D//g;
+    if ($numterms == 0)
+    {
+        print "\n${beep}No number entered - aborting.\n\n";
+        return;
+    }
+    if ($numterms < 1 || $numterms > 200)
+    {
+        print "\n${beep}Don't be silly - aborting.\n\n";
+        return;
+    }
+    @recs = split(/;/,$filled);
+       $recs[7] .= '';
+       &AddNTerms($recs[7], $useTERM, $numterms);
+    $filled = join(';',@recs);
+
+    eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open members database: $!\n";
+        return;
+    };
+       local($tt);
+       foreach $tt (@TERMRANGE)
+       {
+               local($termmem) = $MEM{$tt};
+               @mems = split(/,/,$termmem);
+               @find = grep($_ == $memnum, @mems);
+               unshift(@mems,$memnum) if $#find < 0;
+               $MEM{$tt} = join(',',sort {$a<=>$b} @mems);
+       }
+    $MEM{$memnum} = $filled;
+    &fakedbmclose($MEMDB,%MEM);
+    &Backup("$MEMDB.dir");
+    &Backup("$MEMDB.pag");
+    print "\nInfo for membership card:\n\nName: $recs[0]\nNum : $memnum\nTerm: $TERMRANGE\n";
+    &UpdateCashlog($MEMBERFEE * $numterms,"Old member #$memnum ($recs[0]) for $TERMRANGE");
+    &Gopher_Members;
+}
+
+sub memupdate
+{
+    local($template) = shift;
+    @tempfields = split(/;/,$template);
+    local($pw1,$pw2);
+    if ($tempfields[5] ne "" && $ENV{'CALUM'} != 1)
+    {
+        print "Enter your CSC password: ";
+        $pw1 = &GetPass;
+        if (crypt($pw1,$tempfields[5]) ne $tempfields[5])
+        {
+            print "\n${beep}Incorrect password.\n\n";
+            return "";
+        }
+    }
+
+    local($t5,$t7);
+    $t5 = $tempfields[5];
+    $t7 = $tempfields[7];
+    &Editscreen(<<EOT);
+Please fill in the following information as completely as you can.
+
+Name            : $tempfields[0]
+Student ID      : $tempfields[1]
+Year and Program: $tempfields[2]
+Phone number    : $tempfields[3]
+
+If you _already have_ a userid on a UW computer, fill it in below.
+Otherwise, if you have an account somewhere else, fill it in below.
+Otherwise, leave this blank.
+
+Userid          : $tempfields[4]
+
+Currently a member for $t7
+EOT
+    &VI;
+    @tempfields = split("\n",&Filterscreen);
+    grep(s/;/:/,@tempfields);
+    $tempfields[5] = $t5;
+    $tempfields[7] = $t7;
+    if ($tempfields[0] =~ /^\s*$/)
+    {
+        print "\n${beep}No name supplied - aborting\n";
+        return "";
+    }
+    $tempfields[3] =~ s/[^x\d\(\)-]//g;
+    chop($tempfields[6] = `date`);
+    if ($tempfields[5] eq "")
+    {
+        print "\nYou may now choose a CSC password.  If you do not wish one, just press Return.\n";
+        while(1)
+        {
+            print "Enter password: ";
+            $pw1 = &GetPass;
+            last if $pw1 eq "";
+            print "Enter it again: ";
+            $pw2 = &GetPass;
+            last if ($pw1 eq $pw2);
+            print "\n${beep}No match.\n\n";
+        }
+        if ($pw1 ne "")
+        {
+            $salt = "";
+            $salt .= sprintf("%c", int(rand(26))+ord('A'));
+            $salt .= sprintf("%c", int(rand(26))+ord('A'));
+            $pw1 = crypt($pw1,$salt);
+        }
+        $tempfields[5] = $pw1;
+    }
+    $template = join(';',@tempfields);
+    return($template);
+}
+
+1;
+
diff --git a/misc.pl b/misc.pl
new file mode 100644 (file)
index 0000000..7fdd69c
--- /dev/null
+++ b/misc.pl
@@ -0,0 +1,137 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/11/20             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub Secure
+{
+    system("chmod -w *");
+}
+
+sub Unsecure
+{
+    system("chmod u+w *");
+}
+
+sub VI0
+{
+    local($fname) = shift;
+    &Secure;
+    system("chmod u+w $fname");
+    system("$EDITOR $fname");
+    &Unsecure;
+}
+
+sub VI
+{
+    &VI0($editfile);
+}
+
+sub MORE0
+{
+    local($fname) = shift;
+    &Secure;
+    system("$PAGER $fname");
+    &Unsecure;
+}
+
+sub MORE
+{
+    &MORE0($editfile);
+}
+
+sub Editscreen0
+{
+    local($fname) = shift;
+    local($text) = shift;
+    open (EDIT, ">$fname") || do
+    {
+        print "Unable to open edit file: $!\n";
+        return;
+    };
+    print EDIT $text;
+    close(EDIT);
+}
+
+sub Editscreen
+{
+    local($text) = shift;
+    &Editscreen0($editfile,$text);
+}
+
+sub Filterscreen0
+{
+    local($fname) = shift;
+    open(EDIT, $fname) || do
+    {
+        print "Unable to open edit file: $!\n";
+        return "\n";
+    };
+    @ret = <EDIT>;
+    close(EDIT);
+    grep(s/[^ -~]//g,@ret);
+    @ret0=grep(s/^[^:]*:\s*//,@ret);
+    return join("\n",@ret0);
+}
+
+sub Filterscreen
+{
+    return &Filterscreen0($editfile);
+}
+    
+sub timeout
+{
+    exit(0);
+}
+        
+sub domenu
+{
+    $domenu_menu = shift;
+    chop $domenu_menu;
+    while(1)
+    {
+        print $domenu_menu;
+        print "#" if $ENV{'CALUM'} == 1;
+#        alarm($sleeptime);
+        $domenu_choice = <STDIN>;
+        $domenu_choice = substr($domenu_choice,0,1);
+        exit(42) unless defined $domenu_choice;
+#        alarm(0);
+        @domenu_clist = grep(s/^$domenu_choice//i, @_);
+        if ($#domenu_clist == -1)
+        {
+            print "\n${beep}Illegal choice.\n\n";
+            next;
+        }
+        return($domenu_clist[0]);
+    }
+}
+
+sub Backup
+{
+    return if $ENV{'USER'} eq "csc_disk";
+    #return if fork;
+    local($file) = $_[0];
+    local($bs);
+    ($bs) = $file =~ /([^\/]*)$/;
+    open(IN, "$file");
+    open(OUT, ">$CEOBACKUPDIR/$bs");
+    print OUT <IN>;
+    close(OUT);
+    close(IN);
+    ## system "rcp $file csc_disk@descartes:ceo/$bs";
+}
+
+sub GetPass
+{
+    local($pwin);
+    system("stty -echo");
+    chop($pwin=<STDIN>);
+    system("stty echo");
+    print "\n";
+    return($pwin);
+}
+
+1;
diff --git a/novelty.pl b/novelty.pl
new file mode 100644 (file)
index 0000000..2aba39f
--- /dev/null
@@ -0,0 +1,98 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/11/20             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub noveltymenu
+{
+    $menu=<<EOM;
+
+Choose an option:
+  (S)ell something
+  (M)ain menu
+
+(S,M): 
+EOM
+
+    @opts = ('ssellnovmenu','mmainmenu');
+    $choice = &domenu($menu,@opts);
+    return $choice;
+}
+
+sub sellnovmenu
+{
+    $menu=<<EOM;
+
+What to sell?
+  (P)ens
+  (S)hirts
+  (B)uttons
+  (N)ovelty menu
+  (M)ain menu
+
+(P,S,B,N,M): 
+EOM
+
+    @opts = ('pdosellpens','sdosellshirts','bdosellbuttons',
+            'nnoveltymenu','mmainmenu');
+    $choice = &domenu($menu,@opts);
+    return $choice;
+}
+
+sub dosellpens
+{
+    &dosellsomething("pens","pens");
+}
+
+sub dosellshirts
+{
+    &dosellsomething("shirts","shirts");
+}
+
+sub dosellbuttons
+{
+    &dosellsomething("buttons","buttons");
+}
+
+sub dosellsomething
+{
+    local($item,$code,$quant,$cost,$comm);
+    $item = shift;
+    $code = shift;
+    &Editscreen(<<EOT);
+Please fill in the following information for selling $item.
+
+Quantity  : 
+Total cost: \$
+Comments  : 
+EOT
+    &VI;
+    ($quant, $cost, $comm) = split(/\n/,&Filterscreen);
+    $quant =~ s/\D//g;
+    $cost =~ s/[^\d\.]//g;
+    $cost =~ s/\./,/g;
+    $cost =~ s/,/\./;
+    $cost =~ s/,//g;
+    $comm =~ s/[^ -~]//g;
+    $comm =~ s/;/:/g;
+    if ($quant == 0)
+    {
+        print "\n${beep}No quantity entered - aborting.\n";
+        return;
+    }
+    chop($date = `date`);
+    open(NOV,">>$NOVELTYLOG") || do
+    {
+        print "\n${beep}Unable to open novelty log - aborting.\n";
+        return;
+    };
+    print NOV "$date;$code;$quant;$cost;$comm\n";
+    close(NOV);
+
+    &UpdateCashlog($cost,"$quant $item sold");
+    &Backup($NOVELTYLOG);
+}
+
+1;
diff --git a/quota.pl b/quota.pl
new file mode 100644 (file)
index 0000000..c002537
--- /dev/null
+++ b/quota.pl
@@ -0,0 +1,268 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/11/20             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub quotamenu
+{
+    local($menu);
+    local($useCAP) = $CAPTERM;
+    if ($NEXTTERMQUOTA)
+    {
+        $useCAP = $NEXTTERM;
+        $useCAP =~ tr/a-z/A-Z/;
+    }
+    $menu = <<EOM;
+
+Choose an option:
+  (B)uy quota for $useCAP term
+  (V)iew quota list
+  (M)ain menu
+
+(B,V,M): 
+EOM
+
+    @opts = ('bdobuyquota','vdoquotalist','mmainmenu');
+    $choice = &domenu($menu, @opts);
+    return $choice;
+}
+
+sub dobuyquota
+{
+    local($useQLOG) = $QUOTALOG;
+    if ($NEXTTERMQUOTA)
+    {
+        $useQLOG = $NEXTQUOTALOG;
+    }
+    print "\nEnter your userid: ";
+    local($userid,$cardnum,$mustadd);
+    local ($thename, $theidnum, $theuserid);
+    chop($userid = <STDIN>);
+    $userid =~ s/[^\w-]//g;
+    substr($userid,8)="";
+    if ($userid eq "")
+    {
+        print "\n${beep}No userid supplied - aborting.\n\n";
+        return;
+    }
+    $uid = (getpwnam($userid))[2];
+    $uid = (&getmfcfpwnam($userid))[2] unless $uid > 0;
+       unless ($uid > 0)
+       {
+               ## Try to look up in the accounts to be created file
+               open (ACCTODO, $USERTODO);
+               while (<ACCTODO>)
+               {
+                       @todoF = split(' ');
+                       $uid = 60001 if $todoF[1] eq $userid;
+               }
+               close(ACCTODO);
+       }
+    unless ($uid > 0)
+    {
+        print "\n${beep}That userid does not exist - aborting.\n\n";
+        return;
+    }
+
+    ## Look up the card number for that userid
+    dbmopen(QUOT,$QUOTADB,0600) || do
+    {
+        print "\n${beep}Unable to open quota database: $!\n";
+        return;
+    };
+    if (defined $QUOT{$userid})
+    {
+        $cardnum = $QUOT{$userid};
+        ($thename, $theidnum, $theuserid) = split(/;/,$QUOT{$cardnum});
+        substr($theuserid,8)="";
+        warn "Card number $cardnum is for userid $theuserid\n" unless
+                $theuserid eq $userid;
+        dbmclose(QUOT);
+        $mustadd = 0;
+    }
+    else
+    {
+        $cardnum=0;
+        foreach $i (sort {$a<=>$b} grep(/^\d+$/, keys %QUOT))
+        {
+            last if $i != $cardnum;
+            $cardnum++;
+        }
+        dbmclose(QUOT);
+        $thename = "";
+        if (eval { %MEM=&fakedbmopen($MEMDB) })
+        {
+            @poss = grep(/$userid/,values %MEM);
+            foreach $p (@poss)
+            {
+                if ($userid eq substr((split(/;/,$p))[4],0,8))
+                {
+                    $thename = (split(/;/,$p))[0];
+                    $theidnum = (split(/;/,$p))[1];
+                }
+            }
+            &fakedbmclose($MEMDB,%MEM);
+        }
+        $mustadd = 1;
+        if ($thename eq "")
+        {
+            &Editscreen(<<EOS);
+Please enter the following information.
+
+Name      : 
+Student ID: 
+EOS
+            &VI;
+            ($thename, $theidnum) = split("\n",&Filterscreen);
+            if ($thename eq "")
+            {
+                print "\n${beep}No name supplied - aborting\n\n";
+                return;
+            }
+        }
+    }
+
+    print "\nInfo for card #$cardnum:\n\n";
+    print "Name      : $thename\n";
+    print "Student ID: $theidnum\n";
+    print "Userid    : $userid\n\n";
+
+    # Find how much quota they have, and how much is left
+    open (QLOG, $useQLOG) || do
+    {
+        print "\n${beep}Unable to open quota log file: $!\n";
+        return;
+    };
+    $qhave = 0; $qleft = 0;
+    while(<QLOG>)
+    {
+        next if /^\s*$/;
+        next if /^\s*#/;
+        warn "Bad format in quota log:\n$_" unless /^[^;]*;([^;]*);\d*;([-\d]*);([-\d]*)$/;
+        $qleft = $3;
+        $qhave = $2 if $userid eq substr($1,0,8);
+    }
+    close(QLOG);
+    print "User $userid currently has $qhave MB of space on the CSC disk.\n";
+    print "There are $qleft MB remaining.\n";
+    while(1)
+    {
+        print "\nHow much more to buy (in MB)? ";
+        $qadd = <STDIN>;
+        $qadd =~ s/\..*//;
+        $qadd =~ s/\D//g;
+        if ($qadd <= 0)
+        {
+            print "\n${beep}No quota requested - aborting.\n";
+            return;
+        }
+        if ($qadd > $qleft)
+        {
+            print "\n${beep}Only $qleft MB are available.\n";
+            next;
+        }
+        last;
+    }
+
+    ## Compute cost
+    $cost = $COSTPERMEG * $qadd;
+    $cost += $ADMINCHARGE if $qadd < $NOADMINIFOVER || $NOADMINIFOVER == 0;
+
+    chop($date = `date`);
+    $tq = $qadd + $qhave;
+
+    open(QLOG, ">>$useQLOG") || do
+    {
+        print "\n${beep}Unable to write quota log: $!\n";
+        return;
+    };
+    print QLOG "$date;$userid;$qadd;$tq;", $qleft - $qadd, "\n";
+    close(QLOG);
+
+    if ($mustadd)
+    {
+        dbmopen(QDB,$QUOTADB,0644) || do
+        {
+            print "\n${beep}Unable to open quota database.\n";
+            return;
+        };
+        $QDB{$cardnum}="$thename;$theidnum;$userid";
+        $QDB{$userid}=$cardnum;
+        dbmclose(QDB);
+    }
+
+    &Backup($useQLOG);
+
+    $pcost = sprintf("%.2f", $cost);
+    &UpdateCashlog($pcost, "$qadd MB quota for $userid");
+
+    open (TODO, ">>$QUOTATODO");
+    print TODO "$userid\t$tq\n";
+    close(TODO);
+       chmod(0660, $QUOTATODO);
+
+#rcp .mostrecent csc_disk@descartes:.mostrecent
+#rsh descartes -l csc_disk 'cat .mostrecent >> records/todo'
+
+    system <<EOJ;
+
+echo "$userid now has $tq MB quota" | mail -s "Quota update required" csc_disk
+EOJ
+
+    &Gopher_Quota;
+}
+
+
+sub doquotalist
+{
+    local($useQUOTALOG) = $QUOTALOG;
+    if ($NEXTTERMQUOTA)
+    {
+        $useQUOTALOG = $NEXTQUOTALOG;
+    }
+    open (QLOG, $useQUOTALOG) || do
+    {
+        print "\n${beep}Unable to open quota log file: $!\n";
+        return;
+    };
+    dbmopen(QUOTA,$QUOTADB,0600) || do
+    {
+        print "\n${beep}Unable to open quota database: $!\n";
+        close(QLOG);
+        return;
+    };
+    %Quota = ();
+    while(<QLOG>)
+    {
+        next if (/^\s*$/ || /^\s*#/);
+        ($qdate, $quid, $qamt, $qtot, $qleft) = split(/;/);
+        next if $quid eq "csc@math";
+        $Quota{$QUOTA{$quid}} = $qtot;
+    }
+    close(QLOG);
+    $qleft =~ s/\D//g;
+    open (SCRQUOTA, ">$editfile") || do
+    {
+        print "\n${beep}Unable to open output file: $!\n";
+        return;
+    };
+    select(SCRQUOTA);
+    $-=0;
+    $= = $ROWS - 1;
+    ##$_ = `stty size`; ($=) = /^(\d+)/; $= -= 2;
+    foreach $qnum (sort {$a<=>$b} keys %Quota)
+    {
+        ($qname, $qsid, $quid) = split(/;/,$QUOTA{$qnum});
+        $qqta = $Quota{$qnum};
+        write;
+    }
+    dbmclose(QUOTA);
+    print "\nQuota remaining: $qleft MB\n";
+    select(STDOUT);
+    close(SCRQUOTA);
+    &MORE;
+}
+
+1;
diff --git a/stats.pl b/stats.pl
new file mode 100644 (file)
index 0000000..f82a1e9
--- /dev/null
+++ b/stats.pl
@@ -0,0 +1,49 @@
+#
+# Date                 Name                            Modification
+# ----          ----                ------------
+# 94/11/20             Alex Brodsky            Split off from main ceo file
+#
+# 
+
+sub Statsmembers
+{
+       eval { %MEM=&fakedbmopen($MEMDB) } || do
+    {
+        print "\n${beep}Unable to open members database: $!\n";
+        return;
+    };
+       local($total) = scalar(split(/,/,$MEM{$TERM}));
+       &fakedbmclose($MEMDB,%MEM);
+       return $total;
+}
+
+sub Statscash
+{
+       local($lastamount);
+    open (CASH, $CASHLOG) || do
+    {
+        print "Error opening cash log file: $!\n";
+        return;
+    };
+    while(<CASH>)
+    {
+        next if /^\s*$/;
+        next if /^\s*#/;
+        $lastamount = (split(';'))[3];
+    }
+    close(CASH);
+       return sprintf("\$%.2f", $lastamount);
+}
+
+sub dostats
+{
+       print "\nCSC Vital Statistics:\n";
+       print "---------------------\n";
+       print "Cash on hand: ", &Statscash, "\n";
+       print "Total membership for $CAPTERM: ", &Statsmembers, "\n";
+       open(QUOTA, $QUOTAINFO);
+       print <QUOTA>, "\n";
+}
+
+1;
+