#!/usr/bin/perl # this is the small console program "note" (MYSQL version) # It works similar to some well known GUI note programs, # but instead of using X11 it uses the UN*X console. # You can edit existing notes, delete them, create new # ones and, of course display them. # The notes will be stored in a mysql database. Refer to # the README of the desitribution for details about # installation. # It requires a configfile named .noterc in the users home. # If it does not exist, note will create one for you, which # you will have to edit. # # If you find it usefull or find a bug, please let me know: # Thomas Linden # # note is GPL software. use Mysql; ################################## # define some default values. # don't change them, instead use the config file! $maxlen = 20; $timelen = 22; $date = `date +%e\".\"%m\".\"%Y\" \"%T`; chomp $date; $USER = getlogin || getpwuid($<); chomp $USER; $HOME = `echo \$HOME`; chomp $HOME; $CONF = $HOME . "/.noterc"; $DEFAULTDBNAME = $USER . "_note"; # database settings, override them within the config! $dbname = "$DEFAULTDBNAME"; $dbhost = "localhost"; $dbuser = $USER; $dbpasswd = ""; $table = "note"; $fnum = "number"; $fnote = "note"; $fdate = "date"; $COLOR = "NO"; # if $COLOR equals NO, then the following color-definitions # will be replaced by "". $BORDER_COLOR = "BLACK"; $NUM_COLOR = "blue"; $NOTE_COLOR = "magenta"; $TIME_COLOR = "black"; ################################### sub usage; sub find_editor; sub output; sub C; sub uen; sub ude; sub num_bereich; sub new; sub edit; sub del; sub display; sub list; sub help; $version = "0.4 (mysql database)"; # process command line args if($ARGV[0] eq "") { $mode = "new"; } else { while($ARGV[0] ne "" ) { if($ARGV[0] =~ /^\d/) { # first arg is a digit! $number = $ARGV[0]; if($mode eq "") { # change mode only, if started with an option # ($mode will be already set) $mode = "display"; } $ARGV[0] = ""; } elsif($ARGV[0] eq "-i" || $ARGV[0] eq "--interactive") { $mode = "interactive"; $ARGV[0] = ""; } elsif($ARGV[0] eq "-l" || $ARGV[0] eq "--list") { $mode = "list"; $ARGV[0] = ""; } elsif($ARGV[0] eq "-L" || $ARGV[0] eq "--longlist") { $mode = "list"; $ListType = "LONG"; $ARGV[0] = ""; } elsif($ARGV[0] eq "-s" || $ARGV[0] eq "--search") { # searching $mode = "search"; $searchstring = $ARGV[1]; $ARGV[0] = ""; } elsif($ARGV[0] eq "-e" || $ARGV[0] eq "--edit") { if($mode eq "edit") { # note -e -e ! &usage; exit(1); } else { $mode = "edit"; shift; } } elsif($ARGV[0] eq "-d" || $ARGV[0] eq "--delete") { if($mode eq "delete") { &usage; exit(1); } else { $mode = "delete"; shift; } } elsif($ARGV[0] eq "-D" || $ARGV[0] eq "--Dump" || $ARGV[0] eq "--dump") { $mode = "dump"; $dump_file = $ARGV[1]; $ARGV[0] = ""; } elsif($ARGV[0] eq "-v" || $ARGV[0] eq "--version") { print "This is note $version from Thomas Linden .\n"; exit(0); } elsif($ARGV[0] eq "-h" || $ARGV[0] eq "--help") { &usage; exit(0); } else { &usage; exit(0); } } } # open the configfile. if(-e $CONF) { eval `cat $CONF`; } # Always interactive? if($ALWAYS_INT eq "YES") { $mode = "interactive"; } # calculate some constants... $BORDERC = "<$BORDER_COLOR>"; $_BORDERC = ""; $NUMC = "<$NUM_COLOR>"; $_NUMC = ""; $NOTEC = "<$NOTE_COLOR>"; $_NOTEC = ""; $TIMEC = "<$TIME_COLOR>"; $_TIMEC = ""; $time = `date +%d\".\"%m\".\"%Y\" \"%T`; chomp $time; $typedef = "i a$MAX_NOTE a$MAX_TIME"; $sizeof = length pack($typedef, () ); if($ListType ne "LONG") { $maxlen += $timelen; # no time will be displayed! } # ok, if still here, we got it all, now let's connect to the database $db = Mysql->connect($dbhost,$dbname,$dbuser,$dbpasswd) or die "ERROR: $Mysql::dberrstr\n"; # main loop: ############### if($mode eq "display") { &display; } elsif($mode eq "search") { &search; } elsif($mode eq "list") { &list; } elsif($mode eq "new") { &new; } elsif($mode eq "delete") { del; } elsif($mode eq "edit") { &edit; } elsif($mode eq "dump") { &dump; } elsif($mode eq "interactive") { &interactive; } else { #undefined :-( } exit(0); ################## EOP ################ ############################### DISPLAY ################################## sub display { # display a certain note print "\n"; &num_bereich; # get @NumBlock from $numer foreach $N (@NumBlock) { $res = $db->query("SELECT $fnote,$fdate FROM $table WHERE $fnum = $N") or die "ERROR: $Mysql::dberrstr\n"; { output($N, $row[0], $row[1], "SINGLE"); print "\n"; $match = 1; } } if(!$match) { print "no note with that number found!\n"; } } ############################### SEARCH ################################## sub search { $maxlen += $timelen; if($searchstring eq "") { &usage; exit(1); } print "searching the database $dbname for \"$searchstring\"...\n\n"; $sqlstatement = "SELECT DISTINCT $fnum,$fnote,$fdate FROM $table WHERE " . "$fnote LIKE '%$searchstring%'" . " ORDER BY $fnum"; $res = $db->query($sqlstatement) or die "ERROR: $Mysql::dberrstr\n"; while(@row = $res->fetchrow) { output($row[0], $row[1], $row[2]); $match = 1; } if(!$match) { print "no matching note found!\n"; } print "\n"; } ############################### LIST ################################## sub list { # list all available notes (number and firstline) $res = $db->query("SELECT $fnum,$fnote,$fdate FROM $table ORDER BY $fnum") or die "ERROR: $Mysql::dberrstr\n"; while(@row = $res->fetchrow) { output($row[0], $row[1], $row[2]); } print "\n"; } ############################### NEW ################################## sub new { if($ALWAYS_EDIT eq "YES") { $TEMP = "/tmp/note.$$"; # let the user edit it... $editor = &find_editor; if($editor) { system $editor, $TEMP; } else { print "Could not find an editor to use!\n"; exit(0); } # read it in ($note) $note = ""; open E, "<$TEMP" or die "Could not open $TEMP\n"; $c = 0; while() { $_ =~ s/'/\\'/g; $note = $note . $_; } chomp $note; close E; # privacy! system "/bin/rm -f $TEMP"; } else { $note = ""; local $line = ""; #local $num = 0; # create a new note print "enter the text of the note, end with .\n"; do { $line = ; $_ =~ s/'/\\'/g; $note = $note . $line; } until $line eq ".\n"; # remove the . ! chop $note; chop $note; } # since we have not number, look for the next available: $res = $db->query("SELECT max($fnum) FROM $table") or die "ERROR: $Mysql::dberrstr\n"; while(@row = $res->fetchrow) { $number = $row[0]; } $number++; $sqlstatement = "INSERT INTO $table VALUES (0,$number,'$note','$date')"; $db->query($sqlstatement) or die "ERROR: $Mysql::dberrstr\n"; # everything ok until here! print "note stored. it has been assigned the number $number.\n\n"; } ############################### DELETE ################################## sub del { # delete a note &num_bereich; # get @NumBlock from $number foreach $N (@NumBlock) { $sqlstatement = "DELETE FROM $table WHERE $fnum = $N"; $res = $db->query($sqlstatement) or $ERR = $Mysql::dberrstr; # do not exit if an error occurs - good for int mode! if($ERR) { print "no note with number $N found!\n"; } else { print "note number $N has been deleted.\n"; } } # recount the notenumbers: $i = 0; $pos = 0; $sqlstatement = "SELECT id FROM $table ORDER BY id"; $res = $db->query($sqlstatement) or die "ERROR: $Mysql::dberrstr\n"; while(@row = $res->fetchrow) { $count[$i] = $row[0]; $i++; } #have all real id's, now recount it: for($pos=0;$pos<$i;$pos++) { $setnum = $pos +1; $sqlstatement = "UPDATE $table SET $fnum = '$setnum' WHERE id = $count[$pos]"; $db->query($sqlstatement) or die "ERROR: $Mysql::dberrstr\n"; } } ############################### EDIT ################################## sub edit { # edit a note $sqlstatement = "SELECT $fnote FROM $table WHERE $fnum = $number"; $res = $db->query($sqlstatement) or die "ERROR: $Mysql::dberrstr\n"; while(@row = $res->fetchrow) { $note = $row[0]; $match = "yes"; } if($match eq "") { print "no note with that number found!\n\n"; exit(0); } $TEMP = "/tmp/note.$USER.$$"; open NOTE,">$TEMP" or die "Could not open $TEMP\n"; select NOTE; print $note; close NOTE; select STDOUT; $editor = &find_editor; if($editor) { system $editor, $TEMP; } else { print "Could not find an editor to use!\n"; exit(0); } $note = ""; open NOTE,"<$TEMP" or die "Could not open $TEMP\n"; $c = 0; while() { $_ =~ s/'/\\'/g; $note = $note . $_; } chomp $note; close NOTE; system "/bin/rm -f $TEMP"; # we got it, now save to db $sqlstatement = "UPDATE $table SET " . "$fnote = '$note' " . "WHERE $fnum = $number"; $db->query($sqlstatement) or die "ERROR: $Mysql::dberrstr\n"; print "note number $number has been changed.\n"; } sub dump { # $dump_file open (DUMP, ">$dump_file") or die "could not open $dump_file\n"; select DUMP; $res = $db->query("SELECT $fnum,$fnote,$fdate FROM $table ORDER BY $fnum") or die "ERROR: $Mysql::dberrstr\n"; $res = $db->query($sqlstatement) or die "ERROR: $Mysql::dberrstr\n"; print "complete dump of note database from $time.\n\n"; while(@row = $res->fetchrow) { print STDOUT "dumping note number $num to $dump_file\n"; print "#$num\ttime: $t\nnote:\n$n\n---------\n\n"; } print "\n"; close(DUMP); select STDOUT; } sub interactive { $maxlen_save = $maxlen; # create menu: local $B = ""; local $BB = ""; local $menu = "[ " . $B . "L" . $BB . " List " . $B . "N" . $BB . " New " . $B . "D" . $BB . " Delete " . $B . "S" . $BB . " Search " . $B . "E" . $BB . " Edit " . $B . "?" . $BB . " Help " . $B . "Q" . $BB . " Quit ] command> "; # per default let's list all the stuff: for(;;) { #&list; $maxlen = $maxlen_save; print "\n\n\n"; print C $menu; # endless until user press "Q" or "q"! $char = ; chomp $char; if($char =~ /^\d+/) { # display notes $maxlen += $timelen; $number = $char; &display; } elsif($char =~ /^n/i) { # create a new one $time = `date +%d\".\"%m\".\"%Y\" \"%T`; chomp $time; &new; } elsif($char =~ /^l/ || $char =~ /^$/) { # list print "\n"; $ListType = ""; $maxlen += $timelen; &list; undef $SetTitle; } elsif($char =~ /^L/) { $ListType = "LONG"; &list; undef $SetTitle; } elsif($char =~ /^h/i || $char =~ /^\?/) { # zu dumm der Mensch ;-) &help; } elsif($char =~ /^d\s+(\d+\-*\,*\d*)/i) { # delete one! $number = $1; &del; } elsif($char =~ /^d$/i) { # we have to ask her: print "enter number(s) of note(s) you want to delete: "; $char = ; chomp $char; $number = $char; &del; } elsif($char =~ /^e\s+(\d+\-*\,*\d*)/i) { # edit one! $time = `date +%d\".\"%m\".\"%Y\" \"%T`; chomp $time; $number = $1; &edit; } elsif($char =~ /^e$/i) { # we have to ask her: print "enter number of the note you want to edit: "; $char = ; chomp $char; $number = $char; &edit; } elsif($char =~ /^s\s+/i) { # she want's to search #$maxlen += $timelen; $searchstring = $'; chomp $searchstring; &search; } elsif($char =~ /^s$/i) { # we have to ask her: #$maxlen += $timelen; print "enter the string you want to search for: "; $char = ; chomp $char; $char =~ s/^\n//; $searchstring = $char; &search; } elsif($char =~ /^q/i) { # schade!!! print "\n\ngood bye\n"; exit(0); } else { # unknown print "\nunknown command!\n"; } } } sub usage { print qq~ usage: note [-i | --interactive] | [ options ] [ number [,number...]] Options: -h --help displays this help screen -v --version displays the version number -l --list lists all existing notes -L --longlist the same as -l but prints also the timestamp -s --search searches for trough the notes database -e --edit edit note with -d --delete delete note with -D --Dump dumps the notes to the textfile -i --interactive interactive mode o if you specify only a number (i.e. "note 4"), then the note with that number will be displayed. o you can specify more then one number for delete and display, for example: "note -d 3,4" deletes #3 and #4. "note 5-7" displays #5, #6 and #7. o if you run note without any parameter and if \$ALWAYS_INT in the config is not set, then note will create a new note and prompt you for new text. o If it finds \~/.noterc, it will process it. Refer to the manpage for more informations about the configuration. o In interactive mode you can get help at any time by typing "?" or "h" at the prompt. This is the program note $version by Thomas Linden (c) 1999-2000. GPL. ~; exit 1; } sub find_editor { return $ENV{"VISUAL"} || $ENV{"EDITOR"} || "vim" || "vi" || "pico"; } sub output { # 0 = Num, 1 = Note, 2 = Time if($ListType ne "LONG") { $SSS = "-" x ($maxlen + 31 - $timelen); } else { $SSS = "-" x ($maxlen + 31); } local $LINE = "$BORDERC $SSS $_BORDERC\n"; local $num = $_[0]; local $note = $_[1]; local $time = $_[2]; local $TYPE = $_[3]; local $L = $BORDERC . "[" . $_BORDERC; local $LONGSPC = " " x (22 + 3); local $R = $BORDERC . "]" . $_BORDERC; if($TYPE ne "SINGLE") { if(!$SetTitle) { local $SP = ""; # print only if it is the first line! if($ListType ne "LONG") { $SP = " " x ($maxlen-2 - $timelen); } else { $SP = " " x ($maxlen-2); } print C $LINE; print C "$L $NUMC#$_NUMC "; if($ListType eq "LONG") { print C " $TIMEC" . "creation date$_TIMEC "; } else { print $LONGSPC; } print C $NOTEC . "note$_NOTEC$SP$R\n"; print C $LINE; $SetTitle = 1; } local $title = ""; $CUTSPACE = " " x $maxlen; $note =~ s/\n/$CUTSPACE/g; local $len = length($note); if($len < $maxlen-3) { local $diff = $maxlen - $len; local $Space = " " x $diff; $title = $BORDERC . $NOTEC . "\"" . $note . "\"" . $_NOTEC . $Space . "$_BORDERC"; } else { $title = substr($note,0,$maxlen - 3); $title = $BORDERC . $NOTEC . "\"" . $title . "...\"$_NOTEC$_BORDERC"; } # $title should now look as: "A sample note " print C "$L $NUMC$num$_NUMC $R"; if($ListType eq "LONG") { print C "$L$TIMEC" . $time . " $_TIMEC$R"; } print C "$L $NOTEC" . $title . "$_NOTEC $R\n"; print C $LINE; } else { chomp $note; local $Space = " " x ($maxlen - 16); local $SP = " " x ($maxlen + 13); #print C $LINE; #print C "$L $NUMC#$_NUMC " . $TIMEC . "creation date$_TIMEC$SP$R\n"; print C $LINE; print C "$L $NUMC$num$_NUMC $R$L$TIMEC$time$_TIMEC $Space$R\n"; print C $LINE; print C $NOTEC . $note . $_NOTEC . "\n"; print C $LINE; } } sub C { # \033[1m%30s\033[0m local %Color = ( 'black' => '0;30', 'red' => '0;31', 'green' => '0;32', 'yellow' => '0;33', 'blue' => '0;34', 'magenta' => '0;35', 'cyan' => '0;36', 'white' => '0;37', 'B' => '1;30', 'BLACK' => '1;30', 'RED' => '1;31', 'GREEN' => '1;32', 'YELLOW' => '1;33', 'BLUE' => '1;34', 'MAGENTA' => '1;35', 'CYAN' => '1;36', 'WHITE' => '1;37', 'black_' => '4;30', 'red_' => '4;31', 'green_' => '4;32', 'yellow_' => '4;33', 'blue_' => '4;34', 'magenta_' => '4;35', 'cyan_' => '4;36', 'white_' => '4;37', 'blackI' => '7;30', 'redI' => '7;31', 'greenI' => '7;32', 'yellowI' => '7;33', 'blueI' => '7;34', 'magentaI' => '7;35', 'cyanI' => '7;36', 'whiteI' => '7;37' ); $default = "\033[0m"; $S = $_[0]; foreach $Col (%Color) { if ($S =~ /<$Col>/g) { if($COLOR ne "NO") { $NC = "\033[" . $Color{$Col} . "m"; $S =~ s/<$Col>/$NC/g; $S =~ s/<\/$Col>/$default/g; } else { $S =~ s/<$Col>//g; $S =~ s/<\/$Col>//g; } } } return $S; } sub uen { local $T = pack("u", $_[0]); chomp $T; return $T; } sub ude { local $T = unpack("u", $_[0]); return $T; } sub num_bereich { # $number is the one we want to delete! # But does it contain kommas? local $m = 0; if($number =~ /\,/) { # accept -d 3,4,7 @NumBlock = split(/\,/,$number); } elsif($number =~ /^\d+\-\d+$/) { # accept -d 3-9 local @LR = split(/\-/,$number); local @Sorted_LR = sort @LR; for($i=$Sorted_LR[0]; $i<=$Sorted_LR[1]; $i++) { # from 3-6 create @NumBlock (3,4,5,6) $NumBlock[$m] = $i; $m++; } } else { @NumBlock = ($number); } } sub help { print qq~ -------------------------------------------------------------- HELP for interactive note $version The following commands are available: L/l List notes. L=long, with timestamp and l=short without timestamp. You can also just hit for short list. N Create a new note. D Delete a note. You can either hit "d 1" or "d 1-4" or just hit "d". If you don't specify a number, you will be asked for. S Search trough the notes database. Usage is similar to Delete, use a string instead of a number to search for. E Edit a note. Usage is similar to Delete but you can only edit one note a time. ?/H This help screen. Q Exit the program. All commands except the List command are case insensitive. --------------------------------------------------------------- ~; }