Files
note/bin/note
TLINDEN 5b54b5f822 ADDED: "-" works also for --dump, but in the other direction. It causes
note to dump to standard output instead into a file.
ADDED:          you can specify - as filename for use with --import and if you want
                to create a new note. "-" stands for standardinput and it allows you
                tp pipe another commands output to note!
ADDED:          you can now use an environment variable for the passphrase (when using
                encryption). If it is presen, note will not ask for a passphrase. This
                is very usefull in comination with the addition above, for use in
                scripts.
CHANGED:        the interactive help screen is now coloured.
ADDED:          -o commandline switch, which causes note to overwrite an existing
                database when importing data from a previous dump. Very handy if
                you want to re-initialize your db, i.e. if you changed the format.
ADDED:          the long-tree-view (-T) displays now also the note-number of each
                note.
2012-02-10 20:14:24 +01:00

1492 lines
38 KiB
Perl
Executable File

#!/usr/bin/perl
# $Author: thomas $ $Id: note,v 1.22 2000/05/01 18:51:40 thomas Exp thomas $ $Revision: 1.22 $
#
# $Log: note,v $
# 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
#
# Revision 1.2 2000/02/25 10:30:06 tom
# *** empty log message ***
#
#
# 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 <tom@daemon.de>
#
# note is GPL software.
use strict;
use Data::Dumper;
sub usage;
sub find_editor;
sub output;
sub C;
sub uen;
sub ude;
sub num_bereich;
sub getdate;
sub new;
sub edit;
sub del;
sub display;
sub list;
sub help;
sub import;
sub display_tree;
sub tree;
sub print_tree;
my (
$maxlen, $timelen, $TOPIC, $TYPE, $mode, $NOTEDB, $NoteKey, $ImportType, $NewType,
$version, $number, $CurTopic, $CurDepth, $PATH, $CONF, $WantTopic,
$sizeof, $MAX_TIME, $PreferredEditor, %TP, $TopicSep,
$TreeType, $ListType, $searchstring, $dump_file, $ALWAYS_INT, $KEEP_TIMESTAMP,
$BORDERC, $BORDER_COLOR, $_BORDERC, $NOTEC, $NOTE_COLOR,
$NUMC, $NUM_COLOR, $_NUMC, $_NOTEC, $TIMEC, $TIME_COLOR,
$_TIMEC, $TOPICC, $TOPIC_COLOR, $_TOPICC, $SetTitle, $COLOR,
$typedef, $MAX_NOTE, $MAX_TIME, @NumBlock, $ALWAYS_EDIT, $HOME,
$db, $dbname, $dbhost, $DEFAULTDBNAME, $dbuser, $USER, $dbpasswd,
$table, $fnum, $fnote, $fdate, $date, $dbdriver, $libpath, $db,
$USE_CRYPT, $CRYPT_METHOD, $key
);
####################################################################
# 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.3";
if($TOPIC)
{
$CurDepth = 1; # the current depth inside the topic "directory" structure...
}
$USE_CRYPT = "NO";
####################################################################
# 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 "-")
{
$NewType = 1;
$mode = "new";
$ARGV[0] = "";
}
elsif($ARGV[0] eq "-i" || $ARGV[0] eq "--interactive")
{
$mode = "interactive";
$ARGV[0] = "";
}
elsif($ARGV[0] eq "-t" || $ARGV[0] eq "--tree")
{
$mode = "tree";
$ARGV[0] = "";
}
elsif($ARGV[0] eq "-T" || $ARGV[0] eq "--longtree")
{
$mode = "tree";
$TreeType = "LONG";
$ARGV[0] = "";
}
elsif($ARGV[0] eq "-l" || $ARGV[0] eq "--list")
{
$mode = "list";
my @ArgTopics = split /$TopicSep/,$ARGV[1];
$CurDepth += $#ArgTopics + 1 if $ARGV[1];
$CurTopic = $ArgTopics[$#ArgTopics]; # use the last element everytime...
$ARGV[0] = "";
}
elsif($ARGV[0] eq "-L" || $ARGV[0] eq "--longlist")
{
$mode = "list";
$ListType = "LONG";
$CurTopic = $ARGV[1];
$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] = "";
if($dump_file eq "")
{
$dump_file = "note.dump.$$";
print "no dumpfile specified, using $dump_file.\n";
}
}
elsif($ARGV[0] eq "-o" || $ARGV[0] eq "--overwrite")
{
$mode = "import";
$ImportType = $ARGV[0];
if($ARGV[1] eq "-I" || $ARGV[1] eq "--Import") {
$dump_file = $ARGV[2];
}
else {
print "--overwrite is only suitable for use with --import!\n";
exit(1);
}
$ARGV[0] = "";
if($dump_file eq "")
{
print "No dumpfile specified.\n";
exit(1);
}
}
elsif($ARGV[0] eq "-I" || $ARGV[0] eq "--Import" || $ARGV[0] eq "--import")
{
$mode = "import";
if($ARGV[1] eq "-o" || $ARGV[1] eq "-overwrite") {
$dump_file = $ARGV[2];
$ImportType = $ARGV[1];
}
else {
$dump_file = $ARGV[1];
$ImportType = $ARGV[2];
}
$ARGV[0] = "";
if($dump_file eq "")
{
print "No dumpfile specified.\n";
exit(1);
}
}
elsif($ARGV[0] eq "-v" || $ARGV[0] eq "--version")
{
print "This is note $version by Thomas Linden <tom\@daemon.de>.\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 ne "dump" && $mode ne "import")
{
$mode = "interactive";
}
# *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);
}
}
elsif($dbdriver eq "binary") {
eval {
require NOTEDB::binary;
$db = new NOTEDB($dbdriver, $NOTEDB, $MAX_NOTE, $MAX_TIME, $dbdriver);
}
}
else {
print "Unsupported database backend: NOTEDB::$dbdriver!\n";
exit 1;
}
if($@) {
print "backend-error: " . $@;
exit 1;
}
# add the backend version to the note version:
$version .= " " . $db->version();
# calculate some constants...
$BORDERC = "<$BORDER_COLOR>";
$_BORDERC = "</$BORDER_COLOR>";
$NUMC = "<$NUM_COLOR>";
$_NUMC = "</$NUM_COLOR>";
$NOTEC = "<$NOTE_COLOR>";
$_NOTEC = "</$NOTE_COLOR>";
$TIMEC = "<$TIME_COLOR>";
$_TIMEC = "</$TIME_COLOR>";
$TOPICC = "<$TOPIC_COLOR>";
$_TOPICC = "</$TOPIC_COLOR>";
$NoteKey = $TopicSep . "notes" . $TopicSep;
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 </dev/tty");
chomp($key = <TTY>);
print STDERR "\r\n";
system ("stty echo </dev/tty");
close(TTY);
};
if($@) {
$key = <>;
}
}
else {
$key = $ENV{'NOTE_PASSWD'};
}
chomp $key;
$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+?/) {
print "access denied.\n"; # decrypted $date is not a number!
exit(1);
}
} #else empty!
}
else {
$db->no_crypt;
# does: NOTEDB::crypt_supported = 0;
}
# main loop: ###############
if($mode eq "display")
{
&display;
}
elsif($mode eq "search")
{
&search;
}
elsif($mode eq "list")
{
&list;
}
elsif($mode eq "tree")
{
&display_tree;
}
elsif($mode eq "new")
{
&new;
}
elsif($mode eq "delete")
{
del;
}
elsif($mode eq "edit")
{
&edit;
}
elsif($mode eq "dump")
{
&dump;
}
elsif($mode eq "import")
{
&import;
}
elsif($mode eq "interactive")
{
&interactive;
}
else
{
#undefined :-(
}
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)
{
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);
$maxlen += $timelen;
if($searchstring eq "")
{
&usage;
exit(1);
}
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")
{
print "List of all existing notes:\n\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(<E>)
{
$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 (<STDIN>) { $note .= $_; }
}
else
{
print "enter the text of the note, end with .\n";
do
{
$line = <STDIN>;
$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 = $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($maxlen_save, $B, $BB, $menu, $char, @LastTopic);
$maxlen_save = $maxlen;
# create menu:
$B = "<blackI>";
$BB = "</blackI>";
$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!
$maxlen += $timelen;
print "\n";
&list;
undef $SetTitle;
for(;;)
{
$ListType = "";
$maxlen = $maxlen_save;
if($CurDepth > 2)
{
print C $menu . $TOPICC . "../" . $CurTopic . $_TOPICC . ">";
}
else
{
print C $menu . $TOPICC . $CurTopic . $_TOPICC . ">";
}
# endless until user press "Q" or "q"!
$char = <STDIN>;
#$char = $term->readline('');
chomp $char;
if($char =~ /^\d+\s*[\di*?,*?\-*?]*$/)
{
# display notes
$maxlen += $timelen;
$number = $char;
&display;
undef $SetTitle;
}
elsif($char =~ /^n$/i)
{
# create a new one
&new;
}
elsif($char =~ /^l$/ || $char =~ /^$/)
{
# list
print "\n";
$ListType = "";
$maxlen += $timelen;
&list;
undef $SetTitle;
}
elsif($char =~ /^L$/)
{
$ListType = "LONG";
print "\n";
&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 = <STDIN>;
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 = <STDIN>;
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 = <STDIN>;
chomp $char;
$char =~ s/^\n//;
$searchstring = $char;
&search;
}
elsif($char =~ /^q$/i)
{
# schade!!!
print "\n\ngood bye\n";
exit(0);
}
elsif($char =~ /^t$/)
{
&display_tree;
}
elsif($char =~ /^T$/)
{
$TreeType = "LONG";
&display_tree;
$TreeType = "";
}
elsif($char =~ /^\.\.$/ || $char =~ /^cd\s*\.\.$/)
{
$CurDepth-- if ($CurDepth > 1);
$CurTopic = $LastTopic[$CurDepth];
$maxlen += $timelen;
print "\n";
&list;
undef $SetTitle;
}
elsif($char =~ /^l\s+(\w+)$/)
{
# list
$WantTopic = $1;
if(exists $TP{$WantTopic})
{
my %SaveTP = %TP;
$LastTopic[$CurDepth] = $CurTopic;
$CurTopic = $1;
$CurDepth++;
print "\n";
$ListType = "";
$maxlen += $timelen;
&list;
undef $SetTitle;
$CurTopic = $LastTopic[$CurDepth];
$CurDepth--;
%TP = %SaveTP;
}
else
{
print "\nunknown command!\n";
}
}
else
{
# unknown
my $unchar = $char;
$unchar =~ s/^cd //; # you may use cd <topic> now!
if(exists $TP{$char} || exists $TP{$unchar})
{
$char = $unchar if(exists $TP{$unchar});
$LastTopic[$CurDepth] = $CurTopic;
$CurTopic = $char;
$maxlen += $timelen;
$CurDepth++;
print "\n";
&list;
undef $SetTitle;
}
else
{
print "\nunknown command!\n";
}
undef $unchar;
}
}
}
sub usage
{
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 [<topic>] lists all existing notes If no topic were specified,
it will display a list of all existing topics.
-L --longlist [<topic>] 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 <string> searches for <string> trough the notes database
-e --edit <number> edit note with <number>
-d --delete <number> delete note with <number>
-D --Dump [<file> | -] dumps the notes to the textfile <file>. if <file> is simply
a "-" it will printed out to standard output.
-I --Import <file> | - 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 <file>,
which causes note, silently to read in a dump from STDIN.
-o --overwrite only suitable for use with --Import. Overwrites an
existing notedb.
-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.
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.
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.
~;
exit 1;
}
sub find_editor {
return $PreferredEditor || $ENV{"VISUAL"} || $ENV{"EDITOR"} || "vim" || "vi" || "pico";
}
#/
sub output
{
my($SSS, $LINE, $num, $note, $time, $TYPE, $L, $LONGSPC, $R, $PathLen, $SP, $title, $CUTSPACE,
$len, $diff, $Space, $nlen);
($num, $note, $time, $TYPE) = @_;
if($ListType ne "LONG")
{
$SSS = "-" x ($maxlen + 31 - $timelen);
}
else
{
$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)
{
$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);
}
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;
}
$title = "";
$CUTSPACE = " " x $maxlen;
$note =~ s/\n/$CUTSPACE/g;
$len = length($note);
if($len < ($maxlen - 2 - $nlen))
{
$diff = $maxlen - $len;
$Space = " " x $diff;
if($num eq "-")
{
$title = $BORDERC . $TOPICC . "\"" . $note . "\"" . $_TOPICC . $Space . "$_BORDERC";
}
else
{
$title = $BORDERC . $NOTEC . "\"" . $note . "\"" . $_NOTEC . $Space . "$_BORDERC";
}
}
else
{
$title = substr($note,0,($maxlen - 2 - $nlen));
$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;
$Space = " " x ($maxlen - 16);
$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
{
my(%Color, $default, $S, $Col, $NC, $T);
# \033[1m%30s\033[0m
%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
{
my($T);
$T = pack("u", $_[0]);
chomp $T;
return $T;
}
sub ude
{
my($T);
$T = unpack("u", $_[0]);
return $T;
}
sub num_bereich
{
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 getdate
{
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 = "<blackI>";
my $BB = "</blackI>";
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 <enter> 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 command 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);
}
# now that we have build our tree (in %TREE) go on t display it:
print C $BORDERC . "\n[" . $TopicSep . $BORDERC . "]\n";
&print_tree(\%{$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| "));
}
}