diff --git a/Changelog b/Changelog index ef05d53..f8fafa5 100644 --- a/Changelog +++ b/Changelog @@ -1,5 +1,21 @@ ================================================================================== +1.0.6: +FIXED: there were some odd bugs in commandline parsing, some options were unavailable. +FIXED: Forgot "PreferredEditor" config-option in the new config format. +FIXED: the interactive "cd .." command has ignored the presence of a + "DefaultLong" setting(and search too)... thx to Peter. +CHANGED: Optimized a little bit the output routine, now it is better to read. +ADDED: sub format and appropriate config-option for text formatting capabilities. +CHANGED: changed getconfig regexp, which allows now also to use Option = Param. +FIXED: was not possible to override config-options, which are set by default to + something. +ADDED: note chacks now, if a database os actually really encrypted and exits with + an error if it s and the user turned off encryption. This protects her from + destroying it's own database .. + +================================================================================== + 1.0.5: FIXED: the T (and t respectively) printed nothing out since 1.0.3! It does it now again... diff --git a/README b/README index 1d04c90..d8884c2 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -note 1.0.5 by Thomas Linden, 14/05/2000 +note 1.0.6 by Thomas Linden, 18/05/2000 ======================================= Introduction @@ -292,6 +292,36 @@ Topics + +Formatting of notes +=================== + + Another very nice feature is the possibility to format the note-text (as much as + shell allows it). First, you can use the note-internal "magic-strings" for color- + izing. Those strings looks much like HTML: + "here is a green line of text no more green." + As you see, the beginning of another color starts with a tag(kinda) of the color + and ens with an end tag . + + The following colors are available: + black, red, green, yellow, blue, magenta, cyan and white. + + Beside colorizing text, you can also create bold or underlined text! If you decide + to use this (additional) feature, you need to set the Config-Option "FormatNotes" + to 1 which turns it on. + Usage is very straightforward, if a word (a word is defined as some text with at least + one space surrounded) is between a magic mark-character. Here are the available + things, you can do: + + bold: **word** + underlined: __word__ + inverse: {{word}} + + The text will be formatted using the actually note-color. + + + + Scripting ========= @@ -326,8 +356,8 @@ Scripting Format of the notedb (binary backend) ===================================== - The database where the notes are stored is a binary file of - the following format: + The database where the notes are stored is a binary fixed record length file + of the following format: It consists of three fixed length fields per entry. The fields have the following types: o Number: Integer (1 byte) @@ -484,4 +514,4 @@ Contributors / Credits Last changed ============ - 14/05/2000 + 18/05/2000 diff --git a/VERSION b/VERSION index 90a27f9..af0b7dd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.5 +1.0.6 diff --git a/bin/note b/bin/note index 9d0e5c9..80c1ca3 100755 --- a/bin/note +++ b/bin/note @@ -1,5 +1,5 @@ #!/usr/bin/perl -# $Id: note,v 1.26 2000/05/13 01:05:17 thomas Exp thomas $ +# $Id: note,v 1.27 2000/05/16 23:51:35 thomas Exp thomas $ # # # note - console notes management with database and encryption support. @@ -71,7 +71,7 @@ my ( # options from config file .noterc # $maxlen, $timelen, $TOPIC, $NOTEDB, $MAX_TIME, $PreferredEditor, - $ALWAYS_INT, $KEEP_TIMESTAMP, $COLOR, $ALWAYS_EDIT, $HOME, + $ALWAYS_INT, $KEEP_TIMESTAMP, $COLOR, $ALWAYS_EDIT, $HOME, $FormatText, $BORDER_COLOR, $NOTE_COLOR, $NUM_COLOR, $TOPIC_COLOR, $MAX_NOTE, $USE_CRYPT, $CRYPT_METHOD, $TopicSep, $DEFAULT_LIST, $TIME_COLOR, @@ -126,7 +126,7 @@ $TIME_COLOR = "black"; $TOPIC_COLOR = "BLACK"; $TOPIC = 1; $TopicSep = '/'; -$version = "1.0.5"; +$version = "1.0.6"; if($TOPIC) { $CurDepth = 1; # the current depth inside the topic "directory" structure... @@ -159,11 +159,11 @@ else "delete|d=s" => \$opt_d, # integer, required "search|s=s" => \$opt_s, # string, required "tree|topic|t!" => \$opt_t, # no arg - "long_tree|T!" => \$opt_T, # no arg + "longtopic|T!" => \$opt_T, # no arg "list|l:s" => \$opt_l, # string, optional - "long_list|L:s" => \$opt_L, # string, optional - "dump|D:s" => \$opt_D, # string, optional - "import|I:s" => \$opt_I, # string, optional + "longlist|L:s" => \$opt_L, # string, optional + "dump||Dump|D:s" => \$opt_D, # string, optional + "import|Import|I:s" => \$opt_I, # string, optional "overwrite|o!" => \$opt_o, # no arg "help|h|?!" => \$opt_h, # no arg "version|v!" => \$opt_v # no arg @@ -349,7 +349,7 @@ $NoteKey = $TopicSep . "notes" . $TopicSep; if($ListType ne "LONG" && $mode ne "interactive") { - $maxlen += $timelen; # no time will be displayed! + #$maxlen += $timelen; # no time will be displayed! } @@ -381,9 +381,9 @@ if($USE_CRYPT eq "YES" && $NOTEDB::crypt_supported == 1) { $db->use_crypt($key,$CRYPT_METHOD); undef $key; # verify correctness of passwd - my ($note, $date) = $db->get_single(1); - if($date ne "") { - if($date !~ /^\d+\.\d+?/) { + my ($cnote, $cdate) = $db->get_single(1); + if($cdate ne "") { + if($cdate !~ /^\d+\.\d+?/) { print "access denied.\n"; # decrypted $date is not a number! exit(1); } @@ -391,7 +391,14 @@ if($USE_CRYPT eq "YES" && $NOTEDB::crypt_supported == 1) { } else { $db->no_crypt; - # does: NOTEDB::crypt_supported = 0; + # does: NOTEDB::crypt_supported = 0; + my ($cnote, $cdate) = $db->get_single(1); + if($cdate ne "") { + if($cdate !~ /^\d+\.\d+?/) { + print "$NOTEDB seems to be encrypted!\n"; + exit(1); + } + } } # main loop: ############### @@ -477,7 +484,6 @@ sub display sub search { my($n,$match,$note,$date,$num,%res); - $maxlen += $timelen; if($searchstring eq "") { print "No searchstring specified!\n"; @@ -507,8 +513,11 @@ sub list my(@topic,@RealTopic, $i,$t,$n,$num,@CurItem,$top,$in,%res); if($mode ne "interactive" && !$Raw) { - print "List of all existing notes:\n\n"; + print "\nList of all existing notes:\n\n"; } + else { + print "\n"; + } # list all available notes (number and firstline) %res = $db->get_all(); @@ -858,9 +867,8 @@ sub import sub interactive { - my($maxlen_save, $B, $BB, $menu, $char, @LastTopic, $Channel); + my($B, $BB, $menu, $char, @LastTopic, $Channel); $Channel = $|; - $maxlen_save = $maxlen; # create menu: $B = ""; $BB = ""; @@ -876,14 +884,13 @@ sub interactive . $B . "Q" . $BB . "-Quit] "; # $CurTopic will be empty if $TOPIC is off! # per default let's list all the stuff: # Initially do a list command! - $maxlen += $timelen if($DEFAULT_LIST ne "LONG"); - print "\n"; + $ListType = ($DEFAULT_LIST eq "LONG") ? "LONG" : ""; &list; - undef $SetTitle; + for(;;) { - $ListType = ""; - $maxlen = $maxlen_save; + $ListType = ($DEFAULT_LIST eq "LONG") ? "LONG" : ""; + undef $SetTitle; if($CurDepth > 2) { print C $menu . $TOPICC . "../" . $CurTopic . $_TOPICC . ">"; @@ -899,35 +906,28 @@ sub interactive chomp $char; if($char =~ /^\d+\s*[\di*?,*?\-*?]*$/) { + $ListType = ""; #overrun # display notes - $maxlen += $timelen; $number = $char; &display; - undef $SetTitle; } elsif($char =~ /^n$/i) { # create a new one &new; } - elsif($char =~ /^l$/ || $char =~ /^$/) + elsif($char =~ /^$/) { - # list - print "\n"; - if($DEFAULT_LIST eq "LONG" && $char =~ /^$/) { - $ListType = "LONG"; - } - else { - $ListType = ""; - $maxlen += $timelen; - } &list; - undef $SetTitle; + } + elsif($char =~ /^l$/) + { + $ListType = ""; + &list; } elsif($char =~ /^L$/) { $ListType = "LONG"; - print "\n"; &list; undef $SetTitle; } @@ -1005,10 +1005,7 @@ sub interactive { $CurDepth-- if ($CurDepth > 1); $CurTopic = $LastTopic[$CurDepth]; - $maxlen += $timelen; - print "\n"; &list; - undef $SetTitle; } elsif($char =~ /^l\s+(\w+)$/) { @@ -1020,11 +1017,9 @@ sub interactive $LastTopic[$CurDepth] = $CurTopic; $CurTopic = $1; $CurDepth++; - print "\n"; - $ListType = ""; - $maxlen += $timelen; - &list; - undef $SetTitle; + + &list; + $CurTopic = $LastTopic[$CurDepth]; $CurDepth--; %TP = %SaveTP; @@ -1044,11 +1039,8 @@ sub interactive $char = $unchar if(exists $TP{$unchar}); $LastTopic[$CurDepth] = $CurTopic; $CurTopic = $char; - $maxlen += $timelen; $CurDepth++; - print "\n"; &list; - undef $SetTitle; } else { @@ -1111,23 +1103,49 @@ Options: #print "called from line $line\n"; exit 1; } + sub find_editor { return $PreferredEditor || $ENV{"VISUAL"} || $ENV{"EDITOR"} || "vim" || "vi" || "pico"; } + #/ + +sub format { + # make text bold/underlined/inverse using current $NOTEC + # s/\[([^]]*)\]/$param{$1}/g; + my($note) = @_; + if($FormatText) { + my $BN = uc($NOTEC); + my $_BN = uc($_NOTEC); + my $UN = $NOTEC; + $UN =~ s/<(.*)>/<$1_>/; + my $_UN = $UN; + $_UN =~ s/<(.*)>/<\/$1>/; + my $IN = $NOTEC; my $_IN = $_NOTEC; + $IN =~ s/<(.*)>/<$1I>/; + $_IN =~ s/<(.*)>/<$1I>/; + #$note =~ s/ (\*)(.+)(\*) / $BN$2$_BN /g; + #$note =~ s/ (_)(.+)(_) / $UN$2$_UN /g; + #$note =~ s/ (\/)(.+)(\/) / $IN$2$_IN /g; + $note =~ s/\*\*([^\*^\*]*)\*\*/$BN$1$_BN/g; + $note =~ s/__([^_^_]*)__/$UN$1$_UN/g; + $note =~ s/{{([^}^}]*)}}/$IN$1$_IN/g; + } + $note =~ s/(<\/.*>)/$1$NOTEC/g; + $note; +} + sub output { my($SSS, $LINE, $num, $note, $time, $TYPE, $L, $LONGSPC, $R, $PathLen, $SP, $title, $CUTSPACE, - $len, $diff, $Space, $nlen); + $len, $diff, $Space, $nlen, $txtlen); ($num, $note, $time, $TYPE) = @_; - if($ListType ne "LONG") - { - $SSS = "-" x ($maxlen + 31 - $timelen); - } - else - { - $SSS = "-" x ($maxlen + 31); - } + $txtlen = ($ListType eq "LONG") ? $maxlen : $timelen + $maxlen; + + $note = &format($note); + + $SSS = "-" x ($maxlen + 31); + $nlen = length("$num"); $LINE = "$BORDERC $SSS $_BORDERC\n"; $L = $BORDERC . "[" . $_BORDERC; @@ -1140,14 +1158,7 @@ sub output { $SP = ""; # print only if it is the first line! - if($ListType ne "LONG") - { - $SP = " " x ($maxlen-2 - $timelen - $PathLen); - } - else - { - $SP = " " x ($maxlen-2 - $PathLen); - } + $SP = " " x ($maxlen - 2 - $PathLen); if(!$Raw) { # no title in raw-mode! print C $LINE; @@ -1175,12 +1186,12 @@ sub output $SetTitle = 1; } $title = ""; - $CUTSPACE = " " x $maxlen; + $CUTSPACE = " " x $txtlen; $note =~ s/\n/$CUTSPACE/g; $len = length($note); - if($len < ($maxlen - 2 - $nlen)) + if($len < ($txtlen - 2 - $nlen)) { - $diff = $maxlen - $len; + $diff = $txtlen - $len; $Space = " " x $diff; if(!$Raw) { if($num eq "-") @@ -1198,7 +1209,7 @@ sub output } else { - $title = substr($note,0,($maxlen - 2 - $nlen)); + $title = substr($note,0,($txtlen - 2 - $nlen)); if(!$Raw) { $title = $BORDERC . $NOTEC . "\"" . $title . "...\"$_NOTEC$_BORDERC"; } @@ -1226,10 +1237,7 @@ sub output { # we will not reach this in raw-mode, therefore no decision here! chomp $note; - $Space = " " x ($maxlen - 16); - $SP = " " x ($maxlen + 13); - #print C $LINE; - #print C "$L $NUMC#$_NUMC " . $TIMEC . "creation date$_TIMEC$SP$R\n"; + $Space = " " x (($maxlen + $timelen) - 16); print C $LINE; print C "$L $NUMC$num$_NUMC $R$L$TIMEC$time$_TIMEC $Space$R\n"; print C $LINE; @@ -1496,7 +1504,7 @@ sub getconfig while() { chomp; next if(/^\s*$/ || /^\s*#/); - my ($option,$value) = split /\s\s*/, $_, 2; + my ($option,$value) = split /\s\s*=?\s*/, $_, 2; $value =~ s/\s*$//; $home = $value if (/^Home/); $libpath = $value if (/^LibPath/); @@ -1512,23 +1520,31 @@ sub getconfig $NOTEDB = $value if (/^NoteDb/); $MAX_NOTE = $value if (/^MaxNoteByte/); $MAX_TIME = $value if (/^MaxTimeByte/); + $CRYPT_METHOD = $value if (/^CryptMethod/); $USE_CRYPT = "YES" if (/^UseEncryption/ && $value == 1); - $CRYPT_METHOD = $value if (/^CryptMethod/); + $USE_CRYPT = undef if (/^UseEncryption/ && $value == 0); $ALWAYS_INT = "YES" if (/^AlwaysInteractive/ && $value == 1); + $ALWAYS_INT = undef if (/^AlwaysInteractive/ && $value == 0); $DEFAULT_LIST = "LONG" if (/^DefaultLong/ && $value == 1); + $DEFAULT_LIST = undef if (/^DefaultLong/ && $value == 0); $ALWAYS_EDIT = "YES" if (/^AlwaysEditor/ && $value == 1); + $ALWAYS_EDIT = undef if (/^AlwaysEditor/ && $value == 0); $KEEP_TIMESTAMP = "YES" if (/^KeepTimeStamp/ && $value == 1); + $KEEP_TIMESTAMP = undef if (/^KeepTimeStamp/ && $value == 0); + $COLOR = "YES" if (/^UseColors/ && $value == 1); + $COLOR = "NO" if (/^UseColors/ && $value == 0); $TopicSep = $value if (/^TopicSeparator/); $maxlen = $value if (/^MaxLen/); - $COLOR = "YES" if (/^UseColors/ && $value == 1); $BORDER_COLOR = $value if (/^BorderColor/); $NUM_COLOR = $value if (/^NumberColor/); $NOTE_COLOR = $value if(/^NoteColor/); $TIME_COLOR = $value if (/^TimeColor/); $TOPIC_COLOR = $value if (/^TopicColor/); + $PreferredEditor = $value if (/^PreferredEditor/); + $FormatText = $value if (/^FormatText/); } chomp $home; - $home =~ s/\/*$//; + $home =~ s/\/*$//; # cut eventually / at the end $HOME = eval($home); if($NOTEDB =~ /^(~\/)(.*)$/) { $NOTEDB = "/home/" . $USER . "/" . $2; @@ -1544,6 +1560,9 @@ sub getconfig __END__ # # $Log: note,v $ +# Revision 1.27 2000/05/16 23:51:35 thomas +# fixed many option-parsing related bugd! +# # Revision 1.26 2000/05/13 01:05:17 thomas # changed config format and fixed some bugs # as well as some other additions... diff --git a/config/noterc b/config/noterc index 2c531dd..b396d70 100644 --- a/config/noterc +++ b/config/noterc @@ -1,4 +1,4 @@ -# 1.0.5 -*- sh -*- +# 1.0.6 -*- sh -*- # This is a sample config for the note script # There are useful defaults set in note itself. # @@ -137,6 +137,11 @@ TopicColor BLACK # for inverted color append an "I" (greenI will be inverted green) +# Additional to colors, you can also do a little bit of formatting your +# notes (bold, underlined, italic), see README! +# You need to set this Option to 1, if you decide to make use of this +# capabily +FormatText 1 # That's all about it for now. # If you still have any questiosn, please feel free to contact diff --git a/note b/note index af1bd73..db622a5 100755 --- a/note +++ b/note @@ -1,158 +1,336 @@ #!/usr/bin/perl +# $Id: note,v 1.27 2000/05/16 23:51:35 thomas Exp thomas $ +# # -# this is the small console program "note" version 0.3 -# 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 binary data file (~/.notedb) +# note - console notes management with database and encryption support. +# Copyright (C) 1999-2000 Thomas Linden (see README for details!) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. # -# Previous versions needed a mysql database. This is no more -# the case. -# If there exists a configfile called ~/.noterc then it will -# be processed. You can overwrite some default values of note. +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # -# If you find it usefull or find a bug, please let me know: -# Thomas Linden +# - Thomas Linden +# +# latest version on: +# http://www.daemon.de/software.html +# ftp://www.0x49.org/pub/scip/note/ +# + +use strict; +#use Data::Dumper; +use Getopt::Long; + +# +# prototypes +# +sub usage; # print usage message for us thumb userz :-) +sub find_editor; # returns an external editor for use +sub output; # used by &list and &display +sub C; # print colourized +sub num_bereich; # returns array from "1-4" (1,2,3,4) +sub getdate; # return pretty formatted day +sub new; # crate new note +sub edit; # edit a note +sub del; # delete a note +sub display; # display one or more notes +sub list; # note-listing +sub help; # interactive help screen +sub import; # import from notedb-dump +sub display_tree; # show nice tree-view +sub tree; # build the tree +sub print_tree; # print the tree, contributed by Jens Heunemann . THX! -################################################# -# define some default values. -# You can change them, but be carefull! -# Instead you can define each of them in a configfile -# called ~/.noterc. -$MAX_NOTE = 1024; -$MAX_TIME = 64; +# +# globals +# +my ( + # + # commandline options + # + $opt_, $opt_i, $opt_r, $opt_e, $opt_d, + $opt_s, $opt_t, $opt_T, $opt_l, $opt_L, + $opt_D, $opt_I, $opt_o, $opt_h, $opt_n, $opt_v, -$maxlen = 30; + # + # set from commandline (or interactive) + # + $number, $searchstring, $dump_file, $ImportType, $NewType, $Raw, + + # + # options from config file .noterc + # + $maxlen, $timelen, $TOPIC, $NOTEDB, $MAX_TIME, $PreferredEditor, + $ALWAYS_INT, $KEEP_TIMESTAMP, $COLOR, $ALWAYS_EDIT, $HOME, $FormatText, + $BORDER_COLOR, $NOTE_COLOR, $NUM_COLOR, $TOPIC_COLOR, $MAX_NOTE, + $USE_CRYPT, $CRYPT_METHOD, $TopicSep, $DEFAULT_LIST, $TIME_COLOR, -$HOME = `echo \$HOME`; -chomp $HOME; + # + # db specifics from .noterc + # + $db, $dbname, $dbhost, $dbuser, $dbpasswd, + $table, $fnum, $fnote, $fdate, $date, $dbdriver, $libpath, -$CONF = $HOME . "/.noterc"; - -$NOTEDB = $HOME . "/.notedb"; - -$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"; -################################################# + # + # processed colors + # + $BORDERC, $_BORDERC, $NOTEC, $NUMC, $_NUMC, $_NOTEC, $TIMEC, + $_TIMEC, $TOPICC, $_TOPICC, + + # + # config presets + # + $DEFAULTDBNAME, $USER, $PATH, $CONF, + + # + # internals + # + $TYPE, $mode, $NoteKey, + $version, $number, $CurTopic, $CurDepth, $WantTopic, + $sizeof, %TP, $TreeType, $ListType, $SetTitle, + @ArgTopics, $key, $typedef, @NumBlock, $has_nothing, + ); -sub usage; -sub find_editor; -sub output; -sub C; -sub uen; -sub ude; +# +# DEFAULTS, allows one to use note without a config +# don't change them, instead use the config file! +# +$maxlen = 30; +$timelen = 22; +$date = &getdate; +$USER = getlogin || getpwuid($<); +chomp $USER; +$HOME = $ENV{'HOME'}; +$CONF = $HOME . "/.noterc"; +$dbdriver = "binary"; +$libpath = "/usr/local/lib"; +$NOTEDB = $HOME . "/.notedb"; +$MAX_NOTE = 4096; +$MAX_TIME = 64; +$COLOR = "YES"; +$BORDER_COLOR = "BLACK"; +$NUM_COLOR = "blue"; +$NOTE_COLOR = "green"; +$TIME_COLOR = "black"; +$TOPIC_COLOR = "BLACK"; +$TOPIC = 1; +$TopicSep = '/'; +$version = "1.0.6"; +if($TOPIC) +{ + $CurDepth = 1; # the current depth inside the topic "directory" structure... +} +$USE_CRYPT = "NO"; -use IO::Seekable; -$version = "0.3 (binary database)"; + +# # process command line args +# if($ARGV[0] eq "") { $mode = "new"; } +elsif($#ARGV == 0 && $ARGV[0] eq "-") { + $mode = "new"; + $NewType = 1; # read from STDIN until EOF + shift; + undef $has_nothing; +} else { - while($ARGV[0] ne "" ) - { - if($ARGV[0] =~ /\d+/) - { + Getopt::Long::Configure( qw(no_ignore_case)); + GetOptions ( + "interactive|i!" => \$opt_i, # no arg + "raw|r!" => \$opt_r, # no arg + "edit|e=i" => \$opt_e, # integer, required + "delete|d=s" => \$opt_d, # integer, required + "search|s=s" => \$opt_s, # string, required + "tree|topic|t!" => \$opt_t, # no arg + "long_tree|T!" => \$opt_T, # no arg + "list|l:s" => \$opt_l, # string, optional + "long_list|L:s" => \$opt_L, # string, optional + "dump|D:s" => \$opt_D, # string, optional + "import|I:s" => \$opt_I, # string, optional + "overwrite|o!" => \$opt_o, # no arg + "help|h|?!" => \$opt_h, # no arg + "version|v!" => \$opt_v # no arg + ); + $opt_n = shift; # after that @ARGV contains eventually + # a note-number + # $opt_ is a single dash, in case of existence! + # + # determine mode + # + if($opt_i) { + $mode = "interactive"; + } + elsif(defined $opt_l || defined $opt_L) { + $mode = "list"; + if(defined $opt_l) { + @ArgTopics = split /$TopicSep/, $opt_l; + } + else { + $ListType = "LONG"; + @ArgTopics = split /$TopicSep/, $opt_L; + } + $CurDepth += $#ArgTopics + 1 if($opt_l || $opt_L); + $CurTopic = $ArgTopics[$#ArgTopics]; # use the last element everytime... + } + elsif($opt_t || $opt_T) { + $mode = "tree"; + $TreeType = "LONG" if($opt_T); + } + elsif(defined $opt_s) { + $mode = "search"; + $searchstring = $opt_s; + } + elsif($opt_e) { + $mode = "edit"; + $number = $opt_e; + } + elsif($opt_d) { + $mode = "delete"; + $number = $opt_d; + } + elsif(defined $opt_D) { + $mode = "dump"; + if(!$opt_) { + if($opt_D ne "") { + $dump_file = $opt_D; + } + else { + $dump_file = "note.dump.$$"; + print "no dumpfile specified, using $dump_file.\n"; + } + } + else { + $dump_file = "-"; # use STDIN + } + } + elsif(defined $opt_I) { + $mode = "import"; + if(!$opt_) { + if($opt_I ne "") { + $dump_file = $opt_I; + } + else { + print "Import-error! No dump_file specified!\n"; + exit(1); + } + } + else { + $dump_file = "-"; + } + } + elsif($opt_v) { + print "This is note $version by Thomas Linden .\n"; + exit(0); + } + elsif($opt_h) { + &usage; + } + else { + $has_nothing = 1; + } + ### determine generic options + if($opt_n =~ /^[\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"; + if($mode eq "") { + $number = $opt_n; + $mode = "display"; + undef $has_nothing; + } + else { + print "mode <$mode> does not take a numerical argument!\n"; + exit(1); + } + } + elsif($opt_n ne "") { + print "Unknown option: $opt_n\n"; + &usage; + } + if($opt_r) { + $Raw = 1; + } + if($opt_o) { + $ImportType = "overwrite"; + if(!$opt_I) { + print "--overwrite is only suitable for use with --import!\n"; + exit(1); } - $ARGV[0] = ""; - } - elsif($ARGV[0] eq "-l") - { - $mode = "list"; - $ARGV[0] = ""; - } - elsif($ARGV[0] eq "-s") - { - # searching - $mode = "search"; - $searchstring = $ARGV[1]; - $ARGV[0] = ""; - } - elsif($ARGV[0] eq "-e") - { - if($mode eq "edit") - { - # note -e -e ! - &usage; - exit(1); - } - else - { - $mode = "edit"; - shift; - } - } - elsif($ARGV[0] eq "-d") - { - if($mode eq "delete") - { - &usage; - exit(1); - } - else - { - $mode = "delete"; - shift; - } - } - 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); - } - } + } + ##### +} +if($has_nothing && $mode eq "") +{ + &usage; } -###################### CONFIG ~/.noterc exists? ######################### -# If not, use the predefined Values! + +# read the configfile. if(-e $CONF) { - eval `cat $CONF`; + &getconfig($CONF); } -###################### db exists? ####################################### -# if not, create it! -if(! -e $NOTEDB) +# Always interactive? +if($ALWAYS_INT eq "YES" && $mode ne "dump" && $mode ne "import") { - open(TT,">$NOTEDB") or die "Could not create $NOTEDB: $!\n"; - close (TT); -} -elsif(! -w $NOTEDB) -{ - print "$NOTEDB is not writable!\n"; - exit(1); + $mode = "interactive"; } +# OK ... Long-Listing shall be default ... You wanted it!!! +if($DEFAULT_LIST eq "LONG") +{ + # takes only precedence in commandline mode + $ListType="LONG"; +} + + + +# *if* loading of the config was successful, try to load the +# configured database backend. Currently supported: mysql and binary. +push @INC, $libpath; +#if($dbdriver eq "mysql") { +# eval { +# require NOTEDB::mysql; +# $db = new NOTEDB($dbdriver, $dbname, $dbhost, $dbuser, $dbpasswd, $table, $fnum, $fnote, $fdate); +# } +#} +if($dbdriver eq "binary") { + eval { + require NOTEDB::binary; + $db = new NOTEDB($dbdriver, $NOTEDB, $MAX_NOTE, $MAX_TIME, $dbdriver); + } +} +else { + eval { + require "NOTEDB/$dbdriver.pm"; + $db = new NOTEDB($dbdriver, $dbname, $dbhost, $dbuser, $dbpasswd, $table, $fnum, $fnote, $fdate); + }; +} +if($@) { + print "Unsupported database backend: NOTEDB::$dbdriver!\n"; + print "The following error has occured:\n------------------------\n" . $@ . "\n------------------------\n"; + exit 1; +} + +# add the backend version to the note version: +$version .= " " . $db->version(); # calculate some constants... $BORDERC = "<$BORDER_COLOR>"; @@ -163,213 +341,106 @@ $NOTEC = "<$NOTE_COLOR>"; $_NOTEC = ""; $TIMEC = "<$TIME_COLOR>"; $_TIMEC = ""; +$TOPICC = "<$TOPIC_COLOR>"; +$_TOPICC = ""; -$time = `date +%d\".\"%m\".\"%Y\" \"%T`; -chomp $time; +$NoteKey = $TopicSep . "notes" . $TopicSep; -$typedef = "i a$MAX_NOTE a$MAX_TIME"; -$sizeof = length pack($typedef, () ); -############################### DISPLAY ################################## +if($ListType ne "LONG" && $mode ne "interactive") +{ + #$maxlen += $timelen; # no time will be displayed! +} + + +# check if the user wants to use encryption: +if($USE_CRYPT eq "YES" && $NOTEDB::crypt_supported == 1) { + if($CRYPT_METHOD eq "") { + $CRYPT_METHOD = "Crypt::IDEA"; + } + if(!exists $ENV{'NOTE_PASSWD'}) { + print "password: "; + eval { + local($|) = 1; + local(*TTY); + open(TTY,"/dev/tty"); + system ("stty -echo ); + print STDERR "\r\n"; + system ("stty echo ; + } + } + else { + $key = $ENV{'NOTE_PASSWD'}; + } + chomp $key; + $db->use_crypt($key,$CRYPT_METHOD); + undef $key; + # verify correctness of passwd + my ($cnote, $cdate) = $db->get_single(1); + if($cdate ne "") { + if($cdate !~ /^\d+\.\d+?/) { + print "access denied.\n"; # decrypted $date is not a number! + exit(1); + } + } #else empty! +} +else { + $db->no_crypt; + # does: NOTEDB::crypt_supported = 0; + my ($cnote, $cdate) = $db->get_single(1); + if($cdate ne "") { + if($cdate !~ /^\d+\.\d+?/) { + print "$NOTEDB seems to be encrypted!\n"; + exit(1); + } + } +} + +# main loop: ############### if($mode eq "display") { - $address = ($number -1 ) * $sizeof; - open (NOTE, "+<$NOTEDB") or die "could not open .notedb\n"; - print "displaying note number $number:\n\n"; - seek(NOTE, $address, SEEK_SET); - read(NOTE, $buffer, $sizeof); - ($num, $note, $time) = unpack($typedef, $buffer); - $n = ude($note); - $t = ude($time); - - output($num, $n, $t, "SINGLE"); - print "\n"; - close(NOTE); + &display; } -############################### SEARCH ################################## elsif($mode eq "search") { - if($searchstring eq "") - { - &usage; - exit(1); - } - print "searching the database $NOTEDB for \"$searchstring\"...\n"; - open (NOTE, "+<$NOTEDB") or die "could not open .notedb\n"; - seek(NOTE, 0, 0); # START FROM BEGINNING - while(read(NOTE, $buffer, $sizeof)) - { - ($num, $note, $time) = unpack($typedef, $buffer); - $n = ude($note); - $t = ude($time); - if($n =~ /$searchstring/i) - { - output($num, $n, $t); - $match = 1; - } - } - if(!$match) - { - print "no matching note found!\n"; - } - close(NOTE); - print "\n"; + &search; } -############################### LIST ################################## elsif($mode eq "list") { - open (NOTE, "+<$NOTEDB") or die "could not open .notedb\n"; - seek(NOTE, 0, 0); # START FROM BEGINNING - print "listing all existing notes:\n\n"; - while(read(NOTE, $buffer, $sizeof)) - { - ($num, $note, $time) = unpack($typedef, $buffer); - $n = ude($note); - $t = ude($time); - #print "#$num:\t$t\n---\n$n\n\n"; - output($num, $n, $t); - } - close(NOTE); - print "\n"; + &list; +} +elsif($mode eq "tree") +{ + &display_tree; } -############################### NEW ################################## elsif($mode eq "new") { - local $note = ""; - local $line = ""; - #local $num = 0; - # create a new note - print "\nenter the text of the note, end with .\n"; - do - { - $line = ; - $note = $note . $line; - } until $line eq ".\n"; - # remove the . ! - chop $note; - chop $note; - - open (N, "<$NOTEDB") or die "could not open .notedb\n"; - # since we have not number, look for the next available: - seek(N, 0, 0); # START FROM BEGINNING - while(read(N, $buff, $sizeof)) - { - ($num, $te, $me) = unpack($typedef, $buff); - } - seek(N, 0, 0); - close (N); - $num++; # use the highest plus 1 - - open (NOTE, "+<$NOTEDB") or die "could not open .notedb\n"; - seek(NOTE, 0, SEEK_END); # APPEND - local $n = uen($note); - local $t = uen($time); - $buffer = pack($typedef, $num, $n, $t); - - print NOTE $buffer; - close(NOTE); + &new; } -############################### DELETE ################################## elsif($mode eq "delete") { - # $number is the one we want to delete! - $TEMP = "/tmp/note.$$"; # save temporarily in $TEMP - system("/bin/touch", $TEMP); - open TEMP, "+<$TEMP" or die "Could not open $TEMP($!)\n"; - open (NOTE, "<$NOTEDB") or die "could not open .notedb\n"; - - seek(TEMP, 0, SEEK_END); # APPEND - - $count = 1; - - # read from notedb and write to temp (without number to - # be deleted, and with recounted numbers) - while(read(NOTE, $buff, $sizeof)) - { - ($num, $note, $time) = unpack($typedef, $buff); - if($num != $number) - { - # no keep it - $buffer = pack($typedef, $count, $note, $time); - seek(TEMP, 0, SEEK_END); # APPEND - print TEMP $buffer; - $count++; - } - else - { - # drop it, just ignore the contents. - $droped = 1; - } - } - close(TEMP); - close(NOTE); - - # done, inform the user - if($droped eq 1) - { - # copy the new one over the old one - system("/bin/cp",$TEMP, $NOTEDB); - print "note number $number has been deleted.\n"; - } - else - { - print "no note with that number found!\n"; - } - system "/bin/rm -f $TEMP"; + del; } -############################### EDIT ################################## elsif($mode eq "edit") { - $address = ($number -1 ) * $sizeof; - open (NOTE, "+<$NOTEDB") or die "could not open .notedb\n"; - seek(NOTE, $address, SEEK_SET); - read(NOTE, $buff, $sizeof) or die "no note with that number found!\n"; - ($num, $note, $t) = unpack($typedef, $buff); - $n = ude($note); - # got current enties... - - # now edit them - $TEMP = "/tmp/note.$$"; - open N, ">$TEMP" or die "Could not open $TEMP\n"; - select N; - print $n; # save decoded to $TEMP - close N; - select STDOUT; - - # 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 N, "<$TEMP" or die "Could not open $TEMP\n"; - $c = 0; - while() - { - $note = $note . $_; - } - chomp $note; - close N; - - # privacy! - system "/bin/rm -f $TEMP"; - - # we got it, now save to db - seek(NOTE, $address, SEEK_SET); - $n = ""; - $n = uen($note); - local $t = uen($time); - $buffer = pack($typedef, $number, $n, $t); - print NOTE $buffer; - close(NOTE); + &edit; +} +elsif($mode eq "dump") +{ + &dump; +} +elsif($mode eq "import") +{ + &import; +} +elsif($mode eq "interactive") +{ + &interactive; } else { @@ -377,89 +448,812 @@ else } -# the end. exit(0); +################## EOP ################ + + + +############################### DISPLAY ################################## +sub display +{ + my($N,$match,$note,$date,$num); + # display a certain note + print "\n"; + &num_bereich; # get @NumBlock from $numer + foreach $N (@NumBlock) + { + ($note, $date) = $db->get_single($N); + if($note) + { + if($Raw) { + print "$N\n$date\n$note\n\n"; + } + else { + output($N, $note, $date, "SINGLE"); + print "\n"; + } + $match = 1; + } + } + if(!$match) + { + print "no note with that number found!\n"; + } +} +############################### SEARCH ################################## +sub search +{ + my($n,$match,$note,$date,$num,%res); + if($searchstring eq "") + { + print "No searchstring specified!\n"; + } + else { + print "searching the database $dbname for \"$searchstring\"...\n\n"; + + %res = $db->get_search($searchstring); + + foreach $num (sort { $a <=> $b } keys %res) + { + output($num, $res{$num}->{'note'}, $res{$num}->{'date'}); + $match = 1; + } + if(!$match) + { + print "no matching note found!\n"; + } + print "\n"; + } +} + + +############################### LIST ################################## +sub list +{ + my(@topic,@RealTopic, $i,$t,$n,$num,@CurItem,$top,$in,%res); + if($mode ne "interactive" && !$Raw) + { + print "\nList of all existing notes:\n\n"; + } + else { + print "\n"; + } + + # list all available notes (number and firstline) + %res = $db->get_all(); + + if($TOPIC) + { + undef %TP; + } + + foreach $num (sort { $a <=> $b } keys %res) + { + $n = $res{$num}->{'note'}; + $t = $res{$num}->{'date'}; + if($TOPIC) + { + # this allows us to have multiple topics (subtopics!) + my ($firstline,$dummy) = split /\n/, $n, 2; + if($firstline =~ /^($TopicSep)/) + { + @topic = split(/$TopicSep/,$firstline); + } + else + { + @topic = (); + } + # looks like: "\topic\" + # collect a list of topics under the current topic + if($topic[$CurDepth-1] eq $CurTopic && $topic[$CurDepth] ne "") + { + if(exists $TP{$topic[$CurDepth]}) + { + $TP{$topic[$CurDepth]}++; + } + else + { + # only if the next item *is* a topic! + $TP{$topic[$CurDepth]} = 1 if(($CurDepth) <= $#topic); + } + } + elsif($topic[$CurDepth-1] eq $CurTopic || ($topic[$CurDepth] eq "" && $CurDepth ==1)) + { + # cut the topic off the note-text + if($n =~ /^($TopicSep)/) + { + $CurItem[$i]->{'note'} = $dummy; + } + else + { + $CurItem[$i]->{'note'} = $n; + } + # save for later output() call + $CurItem[$i]->{'num'} = $num; + $CurItem[$i]->{'time'} = $t; + $i++; + # use this note for building the $PATH! + if($RealTopic[0] eq "") + { + @RealTopic = @topic; + } + } + } + else + { + output($num, $n, $t); + } + } + if($TOPIC) + { + if($CurTopic ne "") + { + undef $PATH; + foreach (@RealTopic) + { + $PATH .= $_ . $TopicSep; + last if($_ eq $CurTopic); + } + } + else + { + $PATH = $TopicSep; + } + + # we are at top level, print a list of topics... + foreach $top (sort(keys %TP)) + { + output("-", " => ". $top . "$TopicSep ($TP{$top} notes)", + " Sub Topic "); + } + #print Dumper(@CurItem); + for($in=0;$in<$i;$in++) + { + output( $CurItem[$in]->{'num'}, + $CurItem[$in]->{'note'}, + $CurItem[$in]->{'time'} ); + } + } + + print "\n"; +} + +############################### NEW ################################## +sub new +{ + my($TEMP,$editor, $date, $note, $WARN, $c, $line, $num, @topic); + $date = &getdate; + 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 $WARN = 1; + if($WARN) + { + print "...edit process interupted! No note has been saved.\n"; + undef $WARN; + return; + } + $c = 0; + while() + { + $note = $note . $_; + } + chomp $note; + close E; + # privacy! + unlink $TEMP; + } + else + { + $note = ""; + $line = ""; + # create a new note + if($NewType) + { + # be silent! read from STDIN until EOF. + while () { $note .= $_; } + } + else + { + print "enter the text of the note, end with .\n"; + do + { + $line = ; + $note = $note . $line; + } until $line eq ".\n"; + # remove the . ! + chop $note; + chop $note; + } + } + + # since we have not number, look for the next available: + $number = $db->get_nextnum(); + if($TOPIC && $CurTopic ne "") + { + @topic = split(/$TopicSep/,$note); + if($topic[1] eq "") + { + $note = $PATH . "\n$note"; + } + } + + + $db->set_new($number,$note,$date); + + # everything ok until here! + print "note stored. it has been assigned the number $number.\n\n"; +} + + +############################### DELETE ################################## +sub del +{ + my($i,@count, $setnum, $pos, $ERR); + # delete a note + &num_bereich; # get @NumBlock from $number + foreach $_ (@NumBlock) + { + $ERR = $db->set_del($_); + if($ERR) + { + print "no note with number $_ found!\n"; + } + else + { + print "note number $_ has been deleted.\n"; + } + } + # recount the notenumbers: + $db->set_recountnums(); + + @NumBlock = (); +} + +############################### EDIT ################################## +sub edit +{ + my($keeptime, $date, $editor, $TEMP, $note, $t, $num, $match); + # edit a note + $date = &getdate; + ($note, $keeptime) = $db->get_single($number); + if($keeptime eq "") + { + print "no note with that number found!\n\n"; + exit(0) if($mode ne "interactive"); + } + $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"; + + while() + { + $note = $note . $_; + } + chomp $note; + close NOTE; + + unlink $TEMP; + + if($KEEP_TIMESTAMP eq "YES") + { + $t = $keeptime; + } + else + { + $t = $date; + } + + # we got it, now save to db + $db->set_edit($number, $note, $t); + + print "note number $number has been changed.\n"; +} + + +sub dump +{ + my(%res, $num, $DUMP); + # $dump_file + if($dump_file eq "-") { + $DUMP = *STDOUT; + } + else { + open (DUMPFILE, ">$dump_file") or die "could not open $dump_file\n"; + $DUMP = *DUMPFILE; + } + select $DUMP; + %res = $db->get_all(); + foreach $num (sort { $a <=> $b } keys %res) + { + print STDOUT "dumping note number $num to $dump_file\n" if($dump_file ne "-"); + print "Number: $num\n" + ."Timestamp: $res{$num}->{'date'}\n" + ."$res{$num}->{'note'}\n"; + } + print "\n"; + close(DUMP); + select STDOUT; +} + +sub import +{ + my($num, $start, $complete, $dummi, $note, $date, $time, $number, $stdin, $DUMP); + # open $dump_file and import it into the notedb + $stdin = 1 if($dump_file eq "-"); + if($stdin) { + $DUMP = *STDIN; + } + else { + open (DUMPFILE, "<$dump_file") or die "could not open $dump_file\n"; + $DUMP = *DUMPFILE; + } + $db->set_del_all() if($ImportType ne ""); + $complete=0; + $start = 0; + while(<$DUMP>) + { + chomp $_; + if($_ =~ /^Number:\s\d+/) + { + if($start == 0) + { + # we have no previous record + ($dummi,$number) = split(/\s/,$_); + $start = 1; + } + else + { + # we got a complete record, save it! + $number = $db->get_nextnum(); + $db->set_new($number,$note, $date); + print "note number $number from $dump_file inserted into notedb.\n" if(!$stdin); + $complete = 0; + $note = ""; + $date = ""; + ($dummi,$number) = split(/\s/,$_); + } + } + elsif($_ =~ /^Timestamp:\s\d+/ && $complete == 0) + { + ($dummi,$date,$time) = split(/\s/,$_); + $date = "$date $time"; + $complete = 1; + } + else + { + $note .= $_ . "\n"; + } + } + if($note ne "" && $date ne "") + { + # the last record, if existent + $number = $db->get_nextnum(); + $db->set_new($number,$note, $date); + print "note number $number from $dump_file inserted into notedb.\n" if(!$stdin); + } +} + + + +sub interactive +{ + my($B, $BB, $menu, $char, @LastTopic, $Channel); + $Channel = $|; + # create menu: + $B = ""; + $BB = ""; + $menu = "[" . $B . "L" . $BB . "-List "; + if($TOPIC) { + $menu .= $B . "T" . $BB . "-Topics "; + } + $menu .= $B . "N" . $BB . "-New " + . $B . "D" . $BB . "-Delete " + . $B . "S" . $BB . "-Search " + . $B . "E" . $BB . "-Edit " + . $B . "?" . $BB . "-Help " + . $B . "Q" . $BB . "-Quit] "; # $CurTopic will be empty if $TOPIC is off! + # per default let's list all the stuff: + # Initially do a list command! + $ListType = ($DEFAULT_LIST eq "LONG") ? "LONG" : ""; + &list; + + for(;;) + { + $ListType = ($DEFAULT_LIST eq "LONG") ? "LONG" : ""; + undef $SetTitle; + if($CurDepth > 2) + { + print C $menu . $TOPICC . "../" . $CurTopic . $_TOPICC . ">"; + } + else + { + print C $menu . $TOPICC . $CurTopic . $_TOPICC . ">"; + } + + # endless until user press "Q" or "q"! + $char = ; + #$char = $term->readline(''); + chomp $char; + if($char =~ /^\d+\s*[\di*?,*?\-*?]*$/) + { + $ListType = ""; #overrun + # display notes + $number = $char; + &display; + } + elsif($char =~ /^n$/i) + { + # create a new one + &new; + } + elsif($char =~ /^$/) + { + &list; + } + elsif($char =~ /^l$/) + { + $ListType = ""; + &list; + } + elsif($char =~ /^L$/) + { + $ListType = "LONG"; + &list; + undef $SetTitle; + } + elsif($char =~ /^h$/i || $char =~ /^\?/) + { + # zu dumm der Mensch ;-) + &help; + } + elsif($char =~ /^d\s+([\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! + $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 + $searchstring = $'; + chomp $searchstring; + &search; + } + elsif($char =~ /^s$/i) + { + # we have to ask her: + print "enter the string you want to search for: "; + $char = ; + chomp $char; + $char =~ s/^\n//; + $searchstring = $char; + &search; + } + elsif($char =~ /^q$/i) + { + # schade!!! + $| = $Channel; + print "\n\ngood bye!\n"; + exit(0); + } + elsif($char =~ /^t$/) + { + $TreeType = ""; + &display_tree; + } + elsif($char =~ /^T$/) + { + $TreeType = "LONG"; + &display_tree; + $TreeType = ""; + } + elsif($char =~ /^\.\.$/ || $char =~ /^cd\s*\.\.$/) + { + $CurDepth-- if ($CurDepth > 1); + $CurTopic = $LastTopic[$CurDepth]; + &list; + } + elsif($char =~ /^l\s+(\w+)$/) + { + # list + $WantTopic = $1; + if(exists $TP{$WantTopic}) + { + my %SaveTP = %TP; + $LastTopic[$CurDepth] = $CurTopic; + $CurTopic = $1; + $CurDepth++; + + &list; + + $CurTopic = $LastTopic[$CurDepth]; + $CurDepth--; + %TP = %SaveTP; + } + else + { + print "\nunknown command!\n"; + } + } + else + { + # unknown + my $unchar = $char; + $unchar =~ s/^cd //; # you may use cd now! + if(exists $TP{$char} || exists $TP{$unchar}) + { + $char = $unchar if(exists $TP{$unchar}); + $LastTopic[$CurDepth] = $CurTopic; + $CurTopic = $char; + $CurDepth++; + &list; + } + else + { + print "\nunknown command!\n"; + } + undef $unchar; + } + } +} + + sub usage { - print "\nusage: \nnote [-l | -h | -v] | [-s ] | [-e | -d ] | []\n"; - print "Options: -l lists all existing notes\n"; - print " -h displays this help screen\n"; - print " -v displays the version number\n"; - print " -s searches trough the notes database\n"; - print " -e edit note number \n"; - print " -d delete note number \n"; - print "If you specify only a number (i.e.\"note 4\"), then this note will be\n"; - print "displayed. If you run note without any parameter, it will create a\n"; - print "new note and store it.\n\n"; +print qq~This is the program note $version by Thomas Linden (c) 1999-2000. +It comes with absolutely NO WARRANTY. It is distributed under the +terms of the GNU General Public License. Use it at your own risk :-) +Usage: note [ options ] [ number [,number...]] +Options: +-h --help displays this help screen +-v --version displays the version number +-l --list [] lists all existing notes If no topic were specified, + it will display a list of all existing topics. +-L --longlist [] the same as -l but prints also the timestamp +-t --topic prints a list of all topics as a tree. +-T --longtopc prints the topic-tree with the notes under each topic +-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 . if is simply + a "-" it will printed out to standard output. +-I --Import | - imports a previously dumped textfile into the + note-database. Data will be appended by default. + You can also specify a dash "note -I -" instead of a , + which causes note, silently to read in a dump from STDIN. +-o --overwrite only suitable for use with --Import. Overwrites an + existing notedb. +-r --raw raw mode, output will not be formatted. Works not in interactive + mode, only on cmd-line for list and display. +-i --interactive interactive mode +- if you run note only with one dash: "note -", then it will + read in a new note from STDIN until EOF, this makes it + possible to pipe text into a new note. - exit 1; + 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 "AlwaysInteractive" in the config + set off, 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. + o If encryption support is turned on, note will ask you for a passphrase every + time it runs. You can avoid this behavior by setting the environment-variable + \$NOTE_PASSWD. You will need this for example, if you call note from a script. +~; + #my ($package, $filename, $line) = caller; + #print "called from line $line\n"; + exit 1; } + sub find_editor { - return $ENV{"VISUAL"} || $ENV{"EDITOR"} || "vim" || "vi" || "pico"; + return $PreferredEditor || $ENV{"VISUAL"} || $ENV{"EDITOR"} || "vim" || "vi" || "pico"; +} + +#/ + +sub format { + # make text bold/underlined/inverse using current $NOTEC + # s/\[([^]]*)\]/$param{$1}/g; + my($note) = @_; + if($FormatText) { + my $BN = uc($NOTEC); + my $_BN = uc($_NOTEC); + my $UN = $NOTEC; + $UN =~ s/<(.*)>/<$1_>/; + my $_UN = $UN; + $_UN =~ s/<(.*)>/<\/$1>/; + my $IN = $NOTEC; my $_IN = $_NOTEC; + $IN =~ s/<(.*)>/<$1I>/; + $_IN =~ s/<(.*)>/<$1I>/; + #$note =~ s/ (\*)(.+)(\*) / $BN$2$_BN /g; + #$note =~ s/ (_)(.+)(_) / $UN$2$_UN /g; + #$note =~ s/ (\/)(.+)(\/) / $IN$2$_IN /g; + $note =~ s/\*\*([^\*^\*]*)\*\*/$BN$1$_BN/g; + $note =~ s/__([^_^_]*)__/$UN$1$_UN/g; + $note =~ s/{{([^}^}]*)}}/$IN$1$_IN/g; + } + $note =~ s/(<\/.*>)/$1$NOTEC/g; + $note; } sub output { - # 0 = Num, 1 = Note, 2 = Time - local $S = "-" x ($maxlen + 31); - local $LINE = "$BORDERC $S $_BORDERC\n"; - local $num = $_[0]; - local $note = $_[1]; - local $time = $_[2]; - local $TYPE = $_[3]; - local $L = $BORDERC . "[" . $_BORDERC; - local $R = $BORDERC . "]" . $_BORDERC; + my($SSS, $LINE, $num, $note, $time, $TYPE, $L, $LONGSPC, $R, $PathLen, $SP, $title, $CUTSPACE, + $len, $diff, $Space, $nlen, $txtlen); + ($num, $note, $time, $TYPE) = @_; + $txtlen = ($ListType eq "LONG") ? $maxlen : $timelen + $maxlen; + + $note = &format($note); + + $SSS = "-" x ($maxlen + 31); + + $nlen = length("$num"); + $LINE = "$BORDERC $SSS $_BORDERC\n"; + $L = $BORDERC . "[" . $_BORDERC; + $LONGSPC = " " x (26 - $nlen); + $R = $BORDERC . "]" . $_BORDERC; + $PathLen = length($PATH); # will be ZERO, if not in TOPIC mode! if($TYPE ne "SINGLE") { if(!$SetTitle) { - # print only of it is the first line! - local $SP = " " x ($maxlen-2); - print C $LINE; - print C "$L $NUMC#$_NUMC $TIMEC" . "creation date$_TIMEC " . $NOTEC . "note$_NOTEC$SP$R\n"; - print C $LINE; + $SP = ""; + # print only if it is the first line! + $SP = " " x ($maxlen - 2 - $PathLen); + if(!$Raw) { + # no title in raw-mode! + print C $LINE; + + print C "$L $NUMC#$_NUMC "; + if($ListType eq "LONG") + { + print C " $TIMEC" . "creation date$_TIMEC "; + } + else + { + print $LONGSPC; + } + if($TOPIC) + { + print C $TOPICC . "$PATH $_TOPICC$SP$R\n"; + } + else + { + print C $NOTEC . "note$_NOTEC$SP$R\n"; + } + + print C $LINE; + } $SetTitle = 1; } - local $title = ""; - $CUTSPACE = " " x $maxlen; + $title = ""; + $CUTSPACE = " " x $txtlen; $note =~ s/\n/$CUTSPACE/g; - local $len = length($note); - if($len < $maxlen-3) + $len = length($note); + if($len < ($txtlen - 2 - $nlen)) { - local $diff = $maxlen - $len; - local $Space = " " x $diff; - $title = $BORDERC . $NOTEC . "\"" . $note . "\"" . $_NOTEC . $Space . "$_BORDERC"; + $diff = $txtlen - $len; + $Space = " " x $diff; + if(!$Raw) { + if($num eq "-") + { + $title = $BORDERC . $TOPICC . "\"" . $note . "\"" . $_TOPICC . $Space . "$_BORDERC"; + } + else + { + $title = $BORDERC . $NOTEC . "\"" . $note . "\"" . $_NOTEC . $Space . "$_BORDERC"; + } + } + else { + $title = $note; + } } 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$L$TIMEC" . $time . "$_TIMEC $R$L $NOTEC" . $title . "$_NOTEC $R\n"; - print C $LINE; + $title = substr($note,0,($txtlen - 2 - $nlen)); + if(!$Raw) { + $title = $BORDERC . $NOTEC . "\"" . $title . "...\"$_NOTEC$_BORDERC"; + } + } + if($Raw) { + print "$num "; + print "$time " if($ListType eq "LONG"); + if($title =~ /^ => (.*)$TopicSep (.*)$/) { + $title = "$1$TopicSep $2"; # seems to be a topic! + } + print "$title\n"; + } + else { + # $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 { - local $Space = " " x ($maxlen+6); - local $SP = " " x ($maxlen +13); - print C $LINE; - print C "$L $NUMC#$_NUMC " . $TIMEC . "creation date$_TIMEC$SP$R\n"; + # we will not reach this in raw-mode, therefore no decision here! + chomp $note; + $Space = " " x (($maxlen + $timelen) - 16); 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 { + my(%Color, $default, $S, $Col, $NC, $T); # \033[1m%30s\033[0m - local %Color = ( 'black' => '0;30', + %Color = ( 'black' => '0;30', 'red' => '0;31', 'green' => '0;32', 'yellow' => '0;33', @@ -516,15 +1310,330 @@ sub C } -sub uen + +sub num_bereich { - local $T = pack("u", $_[0]); - chomp $T; - return $T; + my($m,@LR,@Sorted_LR,$i); + # $number is the one we want to delete! + # But does it contain kommas? + @NumBlock = (); #reset + $m = 0; + if($number =~ /\,/) + { + # accept -d 3,4,7 + @NumBlock = split(/\,/,$number); + } + elsif($number =~ /^\d+\-\d+$/) + { + # accept -d 3-9 + @LR = split(/\-/,$number); + @Sorted_LR = (); + + if($LR[0] > $LR[1]) + { + @Sorted_LR = ($LR[1], $LR[0]); + } + elsif($LR[0] == $LR[1]) + { + # 0 and 1 are the same + @Sorted_LR = ($LR[0], $LR[1]); + } + else + { + @Sorted_LR = ($LR[0], $LR[1]); + } + + 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 ude +sub getdate { - local $T = unpack("u", $_[0]); - return $T; + my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); + $year += 1900; + $mon += 1; + $mon =~ s/^(\d)$/0$1/; + $hour =~ s/^(\d)$/0$1/; + $min =~ s/^(\d)$/0$1/; + $sec =~ s/^(\d)$/0$1/; + $mday =~ s/^(\d)$/0$1/; + return "$mday.$mon.$year $hour:$min:$sec"; } + + +sub help +{ +my $B = ""; +my $BB = ""; +my($S, $L, $T, $Q, $H, $N, $D, $E); +$L = $B . "L" . $BB . $NOTEC; +$T = $B . "T" . $BB . $NOTEC; +$Q = $B . "Q" . $BB . $NOTEC; +$H = $B . "?" . $BB . $NOTEC; +$N = $B . "N" . $BB . $NOTEC; +$D = $B . "D" . $BB . $NOTEC; +$E = $B . "E" . $BB . $NOTEC; +$S = $B . "S" . $BB . $NOTEC; + +print C qq~$BORDERC +----------------------------------------------------------------------$_BORDERC $TOPICC +HELP for interactive note $version +$_TOPICC $NOTEC +The following commands are available: +$L List notes. L=long, with timestamp and l=short without timestamp. + You can also just hit for short list. + If you specify a subtopic, then list will display it's contents, + i.e.: "l mytopic" will dislpay notes under mytopic. +$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 note + a time. +$H This help screen. +$Q Exit the program.~; +if($TOPIC) +{ +print C qq~ +$T print a list of all existing topics as a tree. T prints the tree + with all notes under each topic. + + You can change the actual topic by simply typing it's name or by using + the command "cd", i.e. "cd mytopic". You can create a new topic by creating + a new note, the first line must be the topic borderd by slashes, i.e.: + "/newtopic/". The slash is the default topic-sepearator, but you can over- + ride this in the config! If you type just ".." instead of a topic, you will + go one step back in your topic-structure. +~; +} +print C qq~ +$NOTEC +All commands except the List and Topic commands are case insensitive. $_NOTEC $BORDERC +----------------------------------------------------------------------$_BORDERC +~; +} + + +sub display_tree { + # displays a tree of all topics + my(%TREE, %res, $n, $t, $num, @nodes, $firstline, $text, $untext); + %res = $db->get_all(); + foreach $num (keys %res) + { + $n = $res{$num}->{'note'}; + $t = $res{$num}->{'date'}; + # this allows us to have multiple topics (subtopics!) + my ($firstline,$text,$untext) = split /\n/, $n, 3; + if($firstline =~ /^($TopicSep)/) + { + $firstline =~ s/($TopicSep)*$//; #remove TopicSepatator + @nodes = split(/$TopicSep/,$firstline); + } + else + { + @nodes = ();("$TopicSep"); + $text = $firstline; + } + &tree($num, $text, \%TREE, @nodes); + } + #return if ($num == 0); + # now that we have build our tree (in %TREE) go on t display it: + print C $BORDERC . "\n[" . $TopicSep . $BORDERC . "]\n"; + &print_tree(\%{$TREE{''}},"") if(%TREE); + print C $BORDERC . $_BORDERC . "\n"; +} + + +sub tree { + my($num, $text, $LocalTree, $node, @nodes) = @_; + if(@nodes) { + if(! exists $LocalTree->{$node}->{$NoteKey}) { + $LocalTree->{$node}->{$NoteKey} = []; + } + &tree($num, $text, $LocalTree->{$node}, @nodes); + } + else { + if(length($text) > ($maxlen - 5)) { + $text = substr($text, 0, ($maxlen -5)); + } + $text = $text . " (" . $NUMC . "#" . $num . $_NUMC . $NOTEC . ")" . $_NOTEC if($text ne ""); + push @{$LocalTree->{$node}->{$NoteKey}}, $text; + } +} + + +sub print_tree { + # thanks to Jens for his hints and this sub! + my $hashref=shift; + my $prefix=shift; + my @notes=@{$hashref->{$NoteKey}}; + my @subnotes=sort grep { ! /^$NoteKey$/ } keys %$hashref; + if($TreeType eq "LONG") { + for my $note (@notes) { + if($note ne "") { + print C $BORDERC ;# . $prefix. "|\n"; + print C "$prefix+---<" . $NOTEC . $note . $BORDERC . ">" . $_NOTEC . "\n"; + } + } + } + for my $index (0..$#subnotes) { + print C $BORDERC . $prefix. "|\n"; + print C "$prefix+---[" . $TOPICC . $subnotes[$index] . $BORDERC . "]\n"; + &print_tree($hashref->{$subnotes[$index]},($index == $#subnotes?"$prefix ":"$prefix| ")); + } +} + + +sub getconfig +{ + my($configfile) = @_; + my ($home, $value, $option); + # checks are already done, so trust myself and just open it! + open CONFIG, "<$configfile" || die $!; + while() { + chomp; + next if(/^\s*$/ || /^\s*#/); + my ($option,$value) = split /\s\s*=?\s*/, $_, 2; + $value =~ s/\s*$//; + $home = $value if (/^Home/); + $libpath = $value if (/^LibPath/); + $dbdriver = $value if (/^DbDriver/); + $dbhost = $value if (/^DbHost/); + $dbuser = $value if (/^DbUser/); + $dbpasswd = $value if (/^DbPasswd/); + $dbname = $value if (/^DbName/); + $table = $value if (/^DbTable/); + $fnum = $value if (/^FieldNumber/); + $fnote = $value if (/^FieldNote/); + $fdate = $value if (/^FieldDate/); + $NOTEDB = $value if (/^NoteDb/); + $MAX_NOTE = $value if (/^MaxNoteByte/); + $MAX_TIME = $value if (/^MaxTimeByte/); + $CRYPT_METHOD = $value if (/^CryptMethod/); + $USE_CRYPT = "YES" if (/^UseEncryption/ && $value == 1); + $USE_CRYPT = undef if (/^UseEncryption/ && $value == 0); + $ALWAYS_INT = "YES" if (/^AlwaysInteractive/ && $value == 1); + $ALWAYS_INT = undef if (/^AlwaysInteractive/ && $value == 0); + $DEFAULT_LIST = "LONG" if (/^DefaultLong/ && $value == 1); + $DEFAULT_LIST = undef if (/^DefaultLong/ && $value == 0); + $ALWAYS_EDIT = "YES" if (/^AlwaysEditor/ && $value == 1); + $ALWAYS_EDIT = undef if (/^AlwaysEditor/ && $value == 0); + $KEEP_TIMESTAMP = "YES" if (/^KeepTimeStamp/ && $value == 1); + $KEEP_TIMESTAMP = undef if (/^KeepTimeStamp/ && $value == 0); + $COLOR = "YES" if (/^UseColors/ && $value == 1); + $COLOR = "NO" if (/^UseColors/ && $value == 0); + $TopicSep = $value if (/^TopicSeparator/); + $maxlen = $value if (/^MaxLen/); + $BORDER_COLOR = $value if (/^BorderColor/); + $NUM_COLOR = $value if (/^NumberColor/); + $NOTE_COLOR = $value if(/^NoteColor/); + $TIME_COLOR = $value if (/^TimeColor/); + $TOPIC_COLOR = $value if (/^TopicColor/); + $PreferredEditor = $value if (/^PreferredEditor/); + $FormatText = $value if (/^FormatText/); + } + chomp $home; + $home =~ s/\/*$//; # cut eventually / at the end + $HOME = eval($home); + if($NOTEDB =~ /^(~\/)(.*)$/) { + $NOTEDB = "/home/" . $USER . "/" . $2; + } + $libpath =~ s/\/*$//; + + close CONFIG; +} + + + + +__END__ +# +# $Log: note,v $ +# Revision 1.27 2000/05/16 23:51:35 thomas +# fixed many option-parsing related bugd! +# +# Revision 1.26 2000/05/13 01:05:17 thomas +# changed config format and fixed some bugs +# as well as some other additions... +# +# Revision 1.25 2000/05/11 23:42:43 thomas +# --tree changed to --topic +# +# Revision 1.24 2000/05/10 22:59:44 thomas +# updated usage to reflect --raw and build it into output +# and display subs. +# +# Revision 1.23 2000/05/10 22:19:04 thomas +# changed to Getopt::Long, added --raw +# +# Revision 1.22 2000/05/01 18:51:40 thomas +# added "-" to sub dump +# +# Revision 1.21 2000/05/01 00:17:27 thomas +# *** empty log message *** +# +# Revision 1.20 2000/04/30 23:31:38 thomas +# added -o and coloured sub help. +# +# Revision 1.19 2000/04/30 16:07:23 thomas +# *** empty log message *** +# +# Revision 1.18 2000/04/30 14:58:21 thomas +# updated the usage and help subs +# +# Revision 1.17 2000/04/30 14:44:38 thomas +# added colors to the tree functions +# +# Revision 1.16 2000/04/30 14:28:38 thomas +# added the t command, which displays a topic-tree. +# and enhanced the list command in interactive mode +# +# Revision 1.15 2000/03/19 23:41:04 thomas +# changed set_del, now no extra TEMP file is required! +# instead I get it from $this->get_all() ! +# Revision 1.14 2000/03/19 22:51:49 thomas +# Bug in NOTEDB::binary fixed, recount of nubers was +# incorrect. +# +# Revision 1.13 2000/03/19 11:53:32 thomas +# edit bug fixed (ude => uen) +# +# Revision 1.12 2000/03/19 03:06:51 thomas +# backend support completed. +# mysql and binary backends now excluded in separate files +# +# Revision 1.11 2000/03/18 00:16:47 thomas +# added NOTEDB::mysql and changed note to work with that. +# thus, from now on there is only one script to maintain and +# it is possible to provide more bacjends as well as making +# additional scripts upon them, i.e. cgi script... +# +# Revision 1.8 2000/03/13 22:48:43 thomas +# small width bug fixed +# +# Revision 1.7 2000/03/08 23:11:19 tom +# added cd +# +# Revision 1.6 2000/03/08 22:50:41 tom +# Added the $KEEP_TIMESTAMP option and fixed a bug regarding topic names +# and invalid resolution of them in case it started with "1 name". +# +# Revision 1.5 2000/02/25 20:59:30 tom +# corrected small timestamp problem in &edit and &new +# +# Revision 1.4 2000/02/25 13:24:11 tom +# fixed a small bug, that caused to use the last line for a note title instead the 2nd. +# +# Revision 1.3 2000/02/25 11:28:53 tom +# all changes from bin version applied to sql version diff --git a/stresstest.sh b/stresstest.sh new file mode 100755 index 0000000..4913a02 --- /dev/null +++ b/stresstest.sh @@ -0,0 +1,55 @@ +#!/bin/sh +# create notes with topics which then represents the corresponding +# directory structure. Depending on how many files the directory +# contains, the resulting note-database may become very large. +# It will then have thousands of notes! +STARTDIR=$1 +case $STARTDIR in + "") + echo "usage: stresstest.sh " + exit 1 + ;; + *) + LOCPFAD=`echo $STARTDIR | grep "^[a-zA-Z0-9.]"` + case $LOCPFAD in + "") + #echo nix + ;; + *) + STARTDIR=`echo $STARTDIR | sed 's/^\.*//'` + STARTDIR="`pwd`/$STARTDIR" + STARTDIR=`echo $STARTDIR | sed 's/\/\//\//g'` + ;; + esac + ;; +esac + + +stress () +{ + FILES="" + for file in `ls $1|sort` + do + echo "$1/$file" + if [ -d "$1/$file" ] ; then + stress "$1/$file" + else + #echo "$1/" > /tmp/$$ + #echo $file >> /tmp/$$ + #`cat /tmp/$$ | note -` + FILES="$FILES $file" + fi + done + echo "$1/" > /tmp/$$ + echo "$FILES" >> /tmp/$$ + case $FILES in + "") + ;; + *) + RES=`cat /tmp/$$ | note -` + ;; + esac + FILES="" +} + +stress $STARTDIR