Use tie instead of dbmopen for the library database
[mspang/plceo1.git] / lib_sys.pl
1 #
2 # Date                  Name                            Modification
3 # ----          ----                ------------
4 # 94/09/12              Alex Brodsky            Split off from main ceo file
5 # 96/05/17              Nikita Borisov          Added ISBN checks
6 # 96/10/23              Nikita Borisov          Use dbmtie instead of fakedbm
7 # 96/10/24              Nikita Borisov          'use NDBM_File' to make dbmopen
8 #                                                                       use that format.  Should really
9 #                                                                       replace them with 'tie' sometime
10 #                                                                       soon.
11 # 96/10/24              Nikita Borisov          'soon' came sooner than expected
12
13
14 require "/u/ceo/ceo/isbn.pl";
15 use NDBM_File;
16 use Fcntl;
17
18 sub librarymenu
19 {
20     local($menu) = <<EOM;
21
22 Choose an option:
23   Sign a book (I)n
24   Sign a book (O)ut
25   (V)iew outstanding books list
26   (E)dit book list
27   (M)ain menu
28
29 (I,O,V,M): 
30 EOM
31     @opts=('idobookin','odobookout','vdooutstanding','mmainmenu','edoeditdb' );
32     $choice = &domenu($menu,@opts);
33     return $choice;
34 }
35
36 sub dobookin
37 {
38     local ($bid);
39         local ($yes);
40     ## Get the book ID
41     while(1)
42     {
43         print "Enter the book ID: ";
44         chop($bid = <STDIN>);
45         $bid =~ s/[^\w-]//g;
46                 # let people type 0-07-054235-x
47                 $bid =~ tr/x/X/;
48         if ($bid =~ /^\s*$/)
49         {
50             print "\n${beep}No ID supplied - aborting.\n";
51             return;
52         }
53         unless (&validbookID($bid))
54         {
55             print "\n${beep}Invalid checksum - try again.\n\n";
56             next;
57         }
58                 unless (&ISBN_checksum($bid)) {
59                         print "\n${beep}WARNING: Invalid ISBN: $bid.\n",
60                                   "Are you sure this is the right ID? ";
61                         $yes = <STDIN>;
62                         next unless $yes =~ /^y/i;
63                 }
64         last;
65     }
66
67     tie(%LIB, NDBM_File, $LIBDB, O_RDWR, 0600) || do
68     {
69         print "\n${beep}Error opening library database: $!\n";
70         return;
71     };
72
73     ## Make a library entry for this book, if none already
74     &Lib_Newbook($bid) unless defined $LIB{$bid};
75
76     ## Mark the book as being in the library
77     if (defined $LIB{$bid})
78     {
79         $LIB{$bid} =~ s/W\{([^\}]*)\}/W\{0\}/;
80         $whohad = $1;
81     }
82
83     ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
84
85     untie(%LIB);
86     &Backup("$LIBDB.db");
87     &Backup("$LIBDB.dir");
88     &Backup("$LIBDB.pag");
89
90     if ($whohad == 0)
91     {
92         print "\n${beep}No one had this book signed out - aborting.\n\n";
93         return;
94     }
95     
96     eval { dbmtie($MEMDB,\%MEM) } || do
97     {
98         print "\n${beep}Error opening members database: $!\n";
99         return;
100     };
101     $thename = (split(/;/,$MEM{$whohad}))[0];
102     dbmuntie(\%MEM);
103
104     ## Make an entry in the library log file
105     open (LIBLOG, ">>$LIBRARYLOG") || do
106     {
107         print "\n${beep}Error writing library log file: $!\n";
108         return;
109     };
110     chop($date = `date`);
111     print LIBLOG "$date;$whohad;$thename;IN;$bid;$btitle\n";
112     close(LIBLOG);
113
114     Backup($LIBRARYLOG);
115
116     print "\"$btitle\" has been received from $thename.\n";
117
118     &Gopher_Outstanding;
119 }
120
121 sub dobookout
122 {
123     local($memnum,$thename,$thepw,$bid,$flags,$btitle);
124     ## Who wants it?
125     print "Enter CSC member number: ";
126     chop($memnum=<STDIN>);
127     $memnum =~ s/\D//g;
128     if ($memnum =~ /^\s*$/)
129     {
130         print "\n${beep}No member number supplied - aborting.\n";
131         return;
132     }
133
134     ## Get the info on this member
135     eval { dbmtie($MEMDB,\%MEM) } || do
136     {
137         print "\n${beep}Unable to open member database: $!\n";
138         return;
139     };
140     unless (defined $MEM{$memnum})
141     {
142         print "\n${beep}No such member number is on record - aborting\n";
143         dbmuntie(\%MEM);
144         return;
145     }
146     $match = grep(/^$TERM$/,split(/,/,(split(/;/,$MEM{$memnum}))[7]));
147     unless ($match)
148     {
149         print "\n${beep}This member has not paid for the current term.\n";
150         dbmuntie(\%MEM);
151         return;
152     }
153     ($thename, $thepw) = (split(/;/,$MEM{$memnum}))[0,5];
154     dbmuntie(\%MEM);
155
156     if ($thepw ne "" && $ENV{'CALUM'} != 1)
157     {
158         print "Enter your CSC password: ";
159         if (crypt(&GetPass, $thepw) ne $thepw)
160         {
161             print "\n${beep}Incorrect password - aborting\n";
162             return;
163         }
164     }
165
166     print "\nName: $thename\n\n";
167
168     ## Get the book ID
169     while(1)
170     {
171         print "Enter the book ID: ";
172         chop($bid = <STDIN>);
173         $bid =~ s/[^\w-]//g;
174         if ($bid =~ /^\s*$/)
175         {
176             print "\n${beep}No ID supplied - aborting.\n";
177             return;
178         }
179         unless (&validbookID($bid))
180         {
181             print "\n${beep}Invalid checksum - try again.\n\n";
182             next;
183         }
184                 unless (&ISBN_checksum($bid)) {
185                         print "\n${beep}WARNING: Invalid ISBN: $bid.\n",
186                                   "Are you sure this is the right ID? ";
187                         $yes = <STDIN>;
188                         next unless $yes =~ /^y/i;
189                 }
190         last;
191     }
192     
193     ## Read the library file
194     tie(%LIB, NDBM_File, $LIBDB, O_RDWR, 0600) || do
195     {
196         print "\n${beep}Error opening library database: $!\n";
197         return;
198     };
199
200     ## Make a library entry for this book, if none already
201     &Lib_Newbook($bid) unless defined $LIB{$bid};
202
203     if (defined $LIB{$bid})
204     {
205         ## Does someone have the book now?
206         $LIB{$bid} =~ /W\{([^\}]*)\}/;
207         $whohad = $1;
208         if ($whohad > 0)
209         {
210             ## Who has it?
211             untie(%LIB);
212             eval { dbmtie($MEMDB,\%MEM) } || do
213             {
214                 print "\n${beep}Unable to open members database: $!\n";
215                 return;
216             };
217             $hasname = (split(/;/,$MEM{$whohad}))[0];
218             dbmuntie(\%MEM);
219
220             print "\n${beep}This book is presently signed out to $hasname.\n";
221             print "Please sign it back in first.\n\n";
222             return;
223         }
224
225         ## Check the flags
226         $LIB{$bid} =~ /T\{([^\}]*)\}/;
227         $flags = $1;
228         if ($flags =~ /r/i)
229         {
230             ## Red dot
231             print "This book has a red dot.  It may not be removed from the CSC.\n";
232             untie(%LIB);
233             return;
234         }
235         if ($flags =~ /b/i)
236         {
237             ## Blue rectangle
238             print "This book has a blue rectangle.  It may only be taken to labs in MC and must be\n";
239             print "returned promptly.\n";
240         }
241
242         ## Mark the book as being out
243         $LIB{$bid} =~ s/W\{[^\}]*\}/W\{$memnum\}/;
244         chop($date = `date`);
245         $LIB{$bid} =~ s/D\{[^\}]*\}/D\{$date\}/;
246
247         ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
248
249         untie(%LIB);
250         &Backup("$LIBDB.db");
251                 &Backup("$LIBDB.dir");
252                 &Backup("$LIBDB.pag");
253
254         print "\"$btitle\" has been signed out.\n";
255
256         ## Make an entry in the library log file
257         open (LIBLOG, ">>$LIBRARYLOG") || do
258         {
259             print "\n${beep}Error writing library log file: $!\n";
260             return;
261         };
262         print LIBLOG "$date;$memnum;$thename;OUT;$bid;$btitle\n";
263         close(LIBLOG);
264
265         &Backup($LIBRARYLOG);
266         &Gopher_Outstanding;
267
268         print "Thank you.  Please return it as soon as possible.\n\n";
269     }
270 }
271
272 sub Lib_Newbook
273 {
274     local($bookid) = shift;
275     @answers = ("","","","","","N","N");
276     while(1)
277     {
278     &Editscreen(<<EOS);
279 This book is not in the library database.
280 Please enter the requested information.
281 Separate multiple entries of the same type (e.g. multiple authors)
282 by semicolons (;).
283
284 Do NOT break an entry across lines; let the line wrap.
285
286 Name/Title    : $answers[0]
287 Author/Editor : $answers[1]
288 Publisher     : $answers[2]
289 Year published: $answers[3]
290 ISBN          : $answers[4]
291 Does the book have a Red dot, Blue rectangle, or Nothing?
292        (R/B/N): $answers[5]
293 Is the book on loan to CSC?
294          (Y/N): $answers[6]
295 EOS
296     &VI;
297     @answers = split("\n",&Filterscreen);
298     grep(s/\}/\]/g,@answers);
299     if ($answers[0] =~ /^\s*$/)
300     {
301         print "\n${beep}No title given - aborting.\n\n";
302         return;
303     }
304     $answers[3] =~ s/\D//g;
305     $answers[4] =~ s/[^\dxX -]//g;
306     $answers[4] =~ s/x/X/g;
307     $answers[5] =~ s/^(.).*$/\u$1/;
308     $answers[5] =~ s/[^RBN]//g;
309     if ($answers[5] eq "")
310     {
311         print "\n${beep}Entry for R/B/N required.\n";
312         sleep 2;
313         next;
314     }
315     $answers[6] =~ s/^(.).*$/\u$1/;
316     $answers[6] =~ s/[^YN]//g;
317     if ($answers[6] eq "")
318     {
319         print "\n${beep}Entry for Y/N required.\n";
320         sleep 2;
321         next;
322     }
323     $answers[6] =~ s/N//;
324     $answers[6] =~ s/Y/L/;
325     last;
326     }
327
328     $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}";
329
330 }
331
332
333 sub MakeOutstandFile
334 {
335  ## Read the library file
336     tie(%LIB, NDBM_File, $LIBDB, O_RDWR, 0600) || do
337     {
338         print "\n${beep}Error opening library database: $!\n";
339         return;
340     };
341     %Outstand = ();
342     foreach $bid (keys %LIB)
343     {
344         ($whohas) = $LIB{$bid} =~ /W\{(\d+)\}/;
345         next if $whohas == 0;
346         ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
347         ($bodate) = $LIB{$bid} =~ /D\{([^\}]*)\}/;
348                 $bodate =~ s/^[^ ]* (.*):\d* E.T/$1/;
349         $Outstand{$bid}="$whohas#$btitle#$bodate";
350     }
351     untie(%LIB);
352
353     eval { dbmtie($MEMDB,\%MEM) } || do
354     {
355         print "\n${beep}Error opening members database: $!\n";
356         return;
357     };
358     open (OUTSTAND, ">$editfile") || do
359     {
360         print "\n${beep}Unable to open outstanding books file: $!\n";
361         dbmuntie(\%MEM);
362         return;
363     };
364     select(OUTSTAND);
365     $-=0;
366     $= = shift;
367     foreach $obid (keys %Outstand)
368     {
369         ($onum,$obtitle,$odate) = $Outstand{$obid} =~ /^(.*)#(.*)#(.*)$/;
370         $oname = (split(/;/,$MEM{$onum}))[0];
371         write;
372     }
373     dbmuntie(\%MEM);
374     select(STDOUT);
375     close(OUTSTAND);
376 }
377
378 sub DisplayLibLog
379 {
380     open(LIBLOG, $LIBRARYLOG) || do
381     {
382         print "\n${beep}Unable to open library log: $!\n";
383         return;
384     };
385     open(SCRLIBLOG, ">$editfile") || do
386     {
387         print "\n${beep}Unable to open output file: $!\n";
388         close(LIBLOG);
389         return;
390     };
391     select(SCRLIBLOG);
392     $-=0;
393     $= = $ROWS - 1;
394     ##$_ = `stty size`; ($=) = /^(\d+)/; $= -= 2;
395     while(<LIBLOG>)
396     {
397         next if (/^\s*$/ || /^\s*#/);
398         ($ldate, $lnum, $lname, $ldir, $bid, $lbtitle) = split(/;/);
399         next if $lnum==0;
400                 ($ldate) = $ldate =~ /^... (.*):.. .*$/;
401         write;
402     }
403     close(LIBLOG);
404     select(STDOUT);
405     close(SCRLIBLOG);
406     &MORE;
407 }
408
409 sub Gopher_Outstanding
410 {
411  ## Read the library file
412     tie(%LIB, NDBM_File, $LIBDB, O_RDWR, 0600) || do
413     {
414         print "\n${beep}Error opening library database: $!\n";
415         return;
416     };
417     %Outstand = ();
418     foreach $bid (keys %LIB)
419     {
420         ($whohas) = $LIB{$bid} =~ /W\{(\d+)\}/;
421         next if $whohas == 0;
422         ($btitle) = $LIB{$bid} =~ /N\{([^\}]*)\}/;
423         ($bodate) = $LIB{$bid} =~ /D\{([^\}]*)\}/;
424         $Outstand{$bid}="$whohas#$btitle#$bodate";
425     }
426     untie(%LIB);
427
428     eval { dbmtie($MEMDB,\%MEM) } || do
429     {
430         print "\n${beep}Error opening members database: $!\n";
431         return;
432     };
433     open (OUTSTAND, ">$GOPHERDIR/library_outstand") || do
434     {
435         print "\n${beep}Unable to open outstanding books file: $!\n";
436         dbmuntie(\%MEM);
437         return;
438     };
439     select(OUTSTAND);
440     $-=0;
441     $= = 50000;
442     foreach $obid (keys %Outstand)
443     {
444         ($onum,$obtitle,$odate) = $Outstand{$obid} =~ /^(.*)#(.*)#(.*)$/;
445         $oname = (split(/;/,$MEM{$onum}))[0];
446         write;
447     }
448     dbmuntie(\%MEM);
449     select(STDOUT);
450     close(OUTSTAND);
451 #   &MakeOutstandFile(50000);
452 #   system <<EOJ;
453 #rcp $editfile csc_disk@descartes:Gopher/office_info/library_outstand
454 #EOJ
455 }
456
457 sub validbookID
458 {
459     local($bid) = shift;
460     return 1;
461 }
462
463 sub dooutstanding
464 {
465     ##$_ = `stty size`; ($height) = /^(\d+)/; $height -= 2;
466     $height = $ROWS - 2;
467     &MakeOutstandFile($height);
468     &MORE;
469 }
470
471 sub doeditdb
472 {
473     local($memnum,$thename,$thepw,$bid,$flags,$btitle);
474     ## Who wants it?
475     unless ($ENV{'CALUM'} == 1){
476                 print "Enter CSC member number: ";
477                 chop($memnum=<STDIN>);
478                 $memnum =~ s/\D//g;
479                 if ($memnum =~ /^\s*$/)
480                 {
481                         print "\n${beep}No member number supplied - aborting.\n";
482                         return;
483                 }
484                 $match = grep(/^$memnum$/,@oslist);
485                 unless (($match || $cscmem == 0) && $cscmem =~ /\d/)
486                 {
487                         print "Access denied.\n";
488                         return;
489                 }
490
491                 ## Get the info on this member
492                 eval { dbmtie($MEMDB,\%MEM) } || do
493                 {
494                         print "\n${beep}Unable to open member database: $!\n";
495                         return;
496                 };
497                 unless (defined $MEM{$memnum})
498                 {
499                         print "\n${beep}No such member number is on record - aborting\n";
500                         dbmuntie(\%MEM);
501                         return;
502                 }
503                 $match = grep(/^$TERM$/,split(/,/,(split(/;/,$MEM{$memnum}))[7]));
504                 unless ($match)
505                 {
506                         print "\n${beep}This member has not paid for the current term.\n";
507                         dbmuntie(\%MEM);
508                         return;
509                 }
510                 ($thename, $thepw) = (split(/;/,$MEM{$memnum}))[0,5];
511                 dbmuntie(\%MEM);
512
513                 if ($thepw ne "" && $ENV{'CALUM'} != 1)
514                 {
515                         print "Enter your CSC password: ";
516                         if (crypt(&GetPass, $thepw) ne $thepw)
517                         {
518                                 print "\n${beep}Incorrect password - aborting\n";
519                                 return;
520                         }
521                 }
522         }
523
524         if( !open(TMPFILE, ">lib.edit") ){
525         print "\n${beep}Error opening temporary file: $!\n";
526         }
527
528     ## Read the library file
529     tie(%LIB, NDBM_File, $LIBDB, O_RDWR, 0600) || do
530     {
531         print "\n${beep}Error opening library database: $!\n";
532                 close TMPFILE;
533         return;
534     };
535
536         for (keys %LIB){
537                 print TMPFILE "$_#$LIB{$_}\n";
538         }
539
540         close TMPFILE;
541
542         system( "rm -f lib.backup;cp lib.edit lib.backup" );
543         system( "/opt/bin/nvi lib.edit" );
544
545         if( open(TMPFILE, "lib.edit") ){
546                 %LIB = ();
547                 while( $_ = <TMPFILE> ){
548                         chomp $_;
549                         /^([^ ]*)#(.*)$/;
550                         $LIB{$1} = $2;
551                 }
552                 close TMPFILE;
553         } else {
554         print "\n${beep}Error opening temporary file: $!\n";
555         }
556
557         untie(%LIB);
558         &Backup("$LIBDB.db");
559         &Backup("$LIBDB.dir");
560         &Backup("$LIBDB.pag");
561
562         &Gopher_Outstanding;
563 }
564 1;