#!/usr/bin/perl # Copyright 1993 Frank Adelstein. All Rights Reserved. # # Permission to use, copy, modify, and distribute this # software is hereby granted without fee, provided that # the copyright notice and permission notice are not removed. # # --FNA 8/29/93 # a voyage into Perl and termcaps. Let's see what we can do. # Initial termcap stuff shamelessly stolen from Tom Fine. # Minor updates to support Term::Cap library instead of the old termcap.pl # -- FNA 06/20/09 use Getopt::Std; use Term::Cap; require POSIX; #deal with the options # getopts("f:bc") || die ("usage: $0 [-bc] [-f addressfile] \n where -b enables batch_mode, and -c checks for birthdays and exits"); if (defined($opt_f)) { $abfile = $opt_f; } else { $abfile = $ENV{'HOME'} . "/.addresses"; } if (defined($opt_b)) { $SAVEONEXIT = 1; } else { $SAVEONEXIT = 0; } if (defined($opt_c)) { # skip all the fun stuff, just read in the file # and see if we can find any birthdays. &check_for_birthdays(); exit(); } my $termios = new POSIX::Termios; $termios->getattr; my $ospeed = $termios->getospeed; $terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed }; # require regional scrolling capability and insert/delete $terminal->Trequire(qw/cs al dl/); $HAS_SCROLLING_REGIONS = 1; $HAS_INSERT_DELETE = 1; $SIG{'INT'} = 'sig_int'; $SIG{'TSTP'} = 'sig_stop'; $SIG{'CONT'} = 'sig_cont'; # check out scrolling capability...if we have # scrolling regions, use it, otherwise use # insert and delete line, otherwise, you're screwed. $HAS_SCROLLING_REGIONS = 0; $HAS_INSERT_DELETE = 0; &cbreak; &clearscreen; &readdata; $index = 0; $top = 12; $bottom = $rows - 3; $current = $top; $needsave = 0; &redraw; &mvcurs(0,$rows); &cleartoeol; print "read in $addindex messages"; &mvcurs(0,$top); $c = getc; while ($c ne "q") { if ($c eq "") { $c = getc; if ($c eq "[" || $c eq "O") { $c = getc; if ($c eq "A") {$c = "k"; } elsif ($c eq "B") {$c = "j"; } elsif ($c eq "C") {$c = "l"; } elsif ($c eq "D") {$c = "h"; } } } if ($c eq " ") { &redraw; } elsif ($c eq "k" || $c eq "") { &moveline(-1); } elsif ($c eq "j" || $c eq "") { &moveline(1); } elsif ($c eq "") { &bigmove($bottom-$top); } elsif ($c eq "") { &bigmove($top-$bottom); } elsif ($c eq "\n") { &longdataredraw; &mvcurs(0,$top); } elsif ($c eq "/") { &dosearch; } elsif ($c eq "e") { &doedit(1); &mvcurs(0,$top); } elsif ($c eq "d") { &deleteentry; } elsif ($c eq "a") { &addentry; } else { print ""; } $c = getc; } if ($needsave) { &writedata; } &mvcurs(0,$rows); print "\n"; &reset; exit; sub moveline { if ($_[0] > 0) { if ($_[0] + $index >= $addindex) { print ""; return;} else { &scrollup; &redrawline ($index + 1 + $bottom - $top); } } else { if ($index + $_[0] < 0) { print ""; return;} else { &scrolldown; &redrawline ($index - 1); } } $index += $_[0]; &mvcurs(0,$top); } sub bigmove { if ($_[0] > 0) { if ($_[0] + $index >= $addindex) { print ""; return;} } else { if ($index + $_[0] < 0) { print ""; return;} } $index += $_[0]; &shortdataredraw; &mvcurs(0,$top); } sub readdata { if (! -e $abfile) { #file doesn't exist...yet return; } if (!open(ADDRESSES, $abfile)) { &showmess("Warning: can't open address file for read."); return; } $addindex = 0; while () { chop; $name[$addindex] = $_; $number1[$addindex] = ; $number2[$addindex] = ; $address1[$addindex] = ; $address2[$addindex] = ; $address3[$addindex] = ; $birthday[$addindex] = ; $comment1[$addindex] = ; $comment2[$addindex] = ; $comment3[$addindex] = ; $email[$addindex] = ; chop $number1[$addindex]; chop $number2[$addindex]; chop $address1[$addindex]; chop $address2[$addindex]; chop $address3[$addindex]; chop $birthday[$addindex]; chop $comment1[$addindex]; chop $comment2[$addindex]; chop $comment3[$addindex]; chop $email[$addindex]; $addindex++; } close (ADDRESSES); } sub writedata { if (!&yorn("Save file?", 1)) { return; } if (!open(ADDRESSES, ">$abfile")) { &showmess("Warning: can't open address file for write."); return; } for ($i = 0; $i < $addindex; $i++) { print ADDRESSES $name[$i], "\n"; print ADDRESSES $number1[$i], "\n"; print ADDRESSES $number2[$i], "\n"; print ADDRESSES $address1[$i], "\n"; print ADDRESSES $address2[$i], "\n"; print ADDRESSES $address3[$i], "\n"; print ADDRESSES $birthday[$i], "\n"; print ADDRESSES $comment1[$i], "\n"; print ADDRESSES $comment2[$i], "\n"; print ADDRESSES $comment3[$i], "\n"; print ADDRESSES $email[$i], "\n"; } close ADDRESSES; $needsave = 0; } sub longdataredraw { # long listing of that entry &longdatafield(0,$name[$index]); &longdatafield(1,$number1[$index]); &longdatafield(2,$number2[$index]); &longdatafield(3,$address1[$index]); &longdatafield(4,$address2[$index]); &longdatafield(5,$address3[$index]); &longdatafield(6,$birthday[$index]); &longdatafield(7,$email[$index]); &longdatafield(8,$comment1[$index]); &longdatafield(9,$comment2[$index]); &longdatafield(10,$comment3[$index]); } sub longdatafield { &mvcurs(18,$_[0]); &cleartoeol; print $_[1]; } sub shortdataredraw { # short listing...start at index and go till end of page $linesleft = $bottom - $top + 1; $i = 0; while ($linesleft && $i + $index < $addindex) { &mvcurs(0,$i+$top); &cleartoeol; &redrawline ($i + $index); $linesleft--; $i++; } while ($linesleft) { &mvcurs(0, $i+$top); &cleartoeol; $linesleft--; $i++; } &mvcurs(0,$top); } sub redrawline { if ($_[0] < $addindex) { printf ("%-45s%-15s", $name[$_[0]], $number1[$_[0]]); } } sub redraw { &clearscreen; &mvcurs(0,$top-1); &underlineon; print " ---------thhhhhhhhhhhhhppppppppppt------------ "; &underlineoff; &mvcurs(0,$bottom+1); &standouton; print " ---------thhhhhhhhhhhhhppppppppppt------------ "; &standoutoff; &drawtemplate; &longdataredraw; &shortdataredraw; &mvcurs(0,$top); } sub dosearch { &mvcurs(0, $rows); &cleartoeol; print "/"; $tempstring = ""; $c = getc; while (1) { if ($c eq "" || $c eq "") { print " "; if (length($tempstring)) { chop $tempstring; } else { &mvcurs(0,$top); return; } } elsif ($c eq "\n") { last; } else { print $c; $tempstring .= $c; } $c = getc; } # use the old search string if only was hit if ($tempstring ne "") { $searchstring = $tempstring; } # go ahead and do the searches... # ...first on names then on birthdays $found = 0; &searchmatch($index + 1, $addindex, *name); if (! $found) { &searchmatch(0, $index, *name); } if (! $found) { &searchmatch($index+1, $addindex, *birthday); } if (! $found) { &searchmatch(0, $index, *birthday); } if ($found) { if ($index != $i) { $index = $i; &longdataredraw; &shortdataredraw; &mvcurs(0, $top); } } else { &mvcurs(0,$rows); &cleartoeol; &standouton; print "not found"; &standoutoff; } } sub searchmatch { local(*searchpattern) = $_[2]; for ($i = $_[0]; $i < $_[1]; $i++) { # we're only doing searches on names initially if ($searchpattern[$i]=~ /$searchstring/i) { $found = 1; last; } } } sub check_for_birthdays { #read in the data file &readdata; # check today, tomorrow, the day after, and a week from today foreach $current (0, 1, 2, 7) { # convert it from 'days until event' to 'seconds until event' $newcurrent = time+(60*60*24*$current); #convert to an ascii representation (it handles months, leap years, etc.) local ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($newcurrent); local (@month); @month = ("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"); # #do a search for birthdays today and tomorrow and the day after tomorrow # foreach $searchstring ("$month[$mon].*$mday", # "$month[$mon].*".($mday+1), # "$month[$mon].*".($mday+2)) { $searchstring = "$month[$mon].*$mday"; $i = -1; $found = 1; while ($found == 1) { $found = 0; &searchmatch($i+1, $addindex, *birthday); if ($found) { print $name[$i], " has a birthday $birthday[$i]!!!\n"; } } } } sub doedit { $modified = 0; $needshortredraw = 0; &longdataredraw; #edit name $tn = &editfield(0,$name[$index]); #numbers $tn1 = &editfield(1,$number1[$index]); if ($modified) { $needshortredraw = 1; } $tn2 = &editfield(2,$number2[$index]); #addresses $ta1 = &editfield(3,$address1[$index]); $ta2 = &editfield(4,$address2[$index]); $ta3 = &editfield(5,$address3[$index]); #birthday $tb = &editfield(6,$birthday[$index]); #email $te = &editfield(7,$email[$index]); #comments $tc1 = &editfield(8,$comment1[$index]); $tc2 = &editfield(9,$comment2[$index]); $tc3 = &editfield(10,$comment3[$index]); if ($modified) { $needsave = 1; if (! $_[0] || &yorn("Entry modified -- ok?", 1)) { $name[$index] = $tn; $number1[$index] = $tn1; $number2[$index] = $tn2; $address1[$index] = $ta1; $address2[$index] = $ta2; $address3[$index] = $ta3; $birthday[$index] = $tb; $comment1[$index] = $tc1; $comment2[$index] = $tc2; $comment3[$index] = $tc3; $email[$index] = $te; if ($_[0] && ! $SAVEONEXIT) { &writedata; } if ($needshortredraw && $_[0]) { &shortdataredraw; } } else { &longdataredraw; } } } sub editfield { &mvcurs(18,$_[0]); &cleartoeol; &standouton; print $_[1]; &mvcurs(18,$_[0]); &getstring; if ($tempstring ne "" && $tempstring ne $_[1]) { $modified = 1; &cleartoeol; } else { $tempstring = $_[1]; } &mvcurs(18,$_[0]); &standoutoff; print $tempstring; $tempstring; } sub addentry { $saveindex = $index; $index = $addindex + 1; &doedit(0); &mvcurs(0,$rows); &cleartoeol; print "Add entry (b)efore or (a)fter current entry (or (q)uit) [a/b/q]?"; $c = getc; while ($c ne "b" && $c ne "a" && $c ne "q") { &mvcurs(0,$rows); &cleartoeol; print "Enter b for before, a for after or q to quit"; $c = getc; } if ($c eq "b") { $startmove = $saveindex; } elsif ($c eq "a") { $startmove = $saveindex + 1; } else { &clearentry($index); $index = $saveindex; &longdataredraw; &mvcurs(0,$top); return; } @name[$startmove+1..$addindex] = @name[$startmove..$addindex-1]; @number1[$startmove+1..$addindex] = @number1[$startmove..$addindex-1]; @number2[$startmove+1..$addindex] = @number2[$startmove..$addindex-1]; @address1[$startmove+1..$addindex] = @address1[$startmove..$addindex-1]; @address2[$startmove+1..$addindex] = @address2[$startmove..$addindex-1]; @address3[$startmove+1..$addindex] = @address3[$startmove..$addindex-1]; @birthday[$startmove+1..$addindex] = @birthday[$startmove..$addindex-1]; @comment1[$startmove+1..$addindex] = @comment1[$startmove..$addindex-1]; @comment2[$startmove+1..$addindex] = @comment2[$startmove..$addindex-1]; @comment3[$startmove+1..$addindex] = @comment3[$startmove..$addindex-1]; @email[$startmove+1..$addindex] = @email[$startmove..$addindex-1]; $name[$startmove] = $name[$index]; $number1[$startmove] = $number1[$index]; $number2[$startmove] = $number2[$index]; $address1[$startmove] = $address1[$index]; $address2[$startmove] = $address2[$index]; $address3[$startmove] = $address3[$index]; $birthday[$startmove] = $birthday[$index]; $comment1[$startmove] = $comment1[$index]; $comment2[$startmove] = $comment2[$index]; $comment3[$startmove] = $comment3[$index]; $email[$startmove] = $email[$index]; &clearentry($index); $index = $startmove; $addindex++; $needsave = 1; if (! $SAVEONEXIT) { &writedata; } &longdataredraw; &shortdataredraw; } sub deleteentry { if (&yorn("Confirm: Delete entry for $name[$index]?", 0)) { if ($index != $addindex-1) { @name[$index..$addindex-2] = @name[$index+1..$addindex-1]; @number1[$index..$addindex-2] = @number1[$index+1..$addindex-1]; @number2[$index..$addindex-2] = @number2[$index+1..$addindex-1]; @address1[$index..$addindex-2] = @address1[$index+1..$addindex-1]; @address2[$index..$addindex-2] = @address2[$index+1..$addindex-1]; @address3[$index..$addindex-2] = @address3[$index+1..$addindex-1]; @birthday[$index..$addindex-2] = @birthday[$index+1..$addindex-1]; @comment1[$index..$addindex-2] = @comment1[$index+1..$addindex-1]; @comment2[$index..$addindex-2] = @comment2[$index+1..$addindex-1]; @comment3[$index..$addindex-2] = @comment3[$index+1..$addindex-1]; @email[$index..$addindex-2] = @email[$index+1..$addindex-1]; } else { $index--; } &clearentry($addindex); $addindex--; $needsave = 1; if (! $SAVEONEXIT) { &writedata; } &longdataredraw; &shortdataredraw; } &mvcurs(0,$top); } sub clearentry { $name[$_[0]] = ""; $number1[$_[0]] = ""; $number2[$_[0]] = ""; $address1[$_[0]] = ""; $address2[$_[0]] = ""; $address3[$_[0]] = ""; $birthday[$_[0]] = ""; $comment1[$_[0]] = ""; $comment2[$_[0]] = ""; $comment3[$_[0]] = ""; $email[$_[0]] = ""; } sub drawtemplate { &titlefield(0,"Name:"); &titlefield(1,"Primary Number:"); &titlefield(2,"Secondary Number:"); &titlefield(3,"Address:"); &titlefield(4,""); &titlefield(5,""); &titlefield(6,"Birthday:"); &titlefield(7,"Email:"); &titlefield(8,"Comments:"); &mvcurs(0,9); &cleartoeol; } sub titlefield { &mvcurs(0,$_[0]); &cleartoeol; &mvcurs(17 - length($_[1]), $_[0]); &underlineon; print $_[1]; &underlineoff; } ## These should be moved into a full screen library sub cbreak { open(ROW,"stty size |"); while () { chop; s/ .*//; $rows=$_; if ($rows == 0) { $rows = $TC{'li'}; } last; } close(ROW); open(SV,"stty -g |"); $savetty=; close(SV); chop $savetty; $erase = $savetty; $erase =~ s/([^:]*:){6}([^:]*).*/$2/; $erase = hex ($erase); $|=1; system("stty -icanon min 1 -echo"); } sub reset { system("stty $savetty"); } sub sig_int { &reset; &clearscreen; exit(0); } sub sig_stop { &reset; &clearscreen; kill "STOP",$$; } sub sig_cont { &cbreak; &redraw; } sub showmess { &mvcurs(0,$rows); &cleartoeol; print $_[0], " ('any' key to continue)"; getc; &mvcurs(0,$rows); &cleartoeol; &mvcurs($curscol,$cursrow); } sub yorn { $ret=0; &mvcurs(0,$rows); &cleartoeol; print $_[0], " (y or n)"; $c = getc; while ($_[1] && ($c ne 'y' && $c ne 'n')) { &mvcurs(0,$rows); &cleartoeol; print "", $_[0], " (y or n)"; $c = getc; } &mvcurs(0,$rows); &cleartoeol; if ($c eq "y") { $ret=1; } $ret; } sub getstring { $tempstring = ""; $c = getc; while (1) { if ($c eq "" || $c eq "") { if (length($tempstring)) { print " "; chop $tempstring; } } elsif ($c eq "\n") { last; } else { print $c; $tempstring .= $c; } $c = getc; } } sub standouton { $terminal->Tputs('so',1,*STDOUT); } sub standoutoff { $terminal->Tputs('se',1,*STDOUT); } sub underlineon { $terminal->Tputs('us',1,*STDOUT); } sub underlineoff { $terminal->Tputs('ue',1,*STDOUT); } sub cleartoeol { $terminal->Tputs('ce',1,*STDOUT); } sub clearscreen { $terminal->Tputs('cl',1,*STDOUT); } sub scrolldown { if ($HAS_SCROLLING_REGIONS) { &setregion($top, $bottom); &mvcurs(0,$top); $terminal->Tputs('sr', 1, *STDOUT); &setregion(-1,-1); &mvcurs(0,$top); } else { &mvcurs(0,$bottom); $terminal->Tputs('dl', 1, *STDOUT); &mvcurs(0,$top); $terminal->Tputs('al', 1, *STDOUT); &mvcurs(0,$top); } } sub scrollup { if ($HAS_SCROLLING_REGIONS) { &setregion($top, $bottom); &mvcurs(0, $bottom); $terminal->Tputs('do', 1, *STDOUT); &setregion(-1,-1); &mvcurs(0,$bottom); } else { &mvcurs(0,$top); $terminal->Tputs('dl',1,*STDOUT); &mvcurs(0,$bottom); $terminal->Tputs('al',1,*STDOUT); &mvcurs(0,$bottom); } } sub mvcurs { $terminal->Tgoto('cm',$_[0],$_[1],*STDOUT); } sub setregion { $terminal->Tgoto('cs',$_[1],$_[0], *STDOUT); }