mirror of
https://codeberg.org/scip/note.git
synced 2025-12-16 20:21:04 +01:00
moved to codeberg
This commit is contained in:
715
Changelog
715
Changelog
@@ -1,715 +0,0 @@
|
||||
-*-text-*-
|
||||
1.4.1:
|
||||
Fixed https://rt.cpan.org/Ticket/Display.html?id=155578:
|
||||
|
||||
Feeding a new entry into note from STDIN didn't work correctly
|
||||
anymore. Using the default builtin config and no config file it didn't
|
||||
work at all. Now it works as one would expect. A bare - as argument
|
||||
ALWAYS reads a new entry from STDIN. The same happens if one uses -n
|
||||
-. In addition note now prints a message if it attempts to read from
|
||||
STDIN to avoid confusion.
|
||||
|
||||
The parameter -n has been added to be able to force note to create a
|
||||
new entry directly from commandline, regardless of any configuration.
|
||||
|
||||
Fixed regex to check if a note has been specified as argument. Now it
|
||||
does not match a bare - anymore.
|
||||
|
||||
Reorganized a little code.
|
||||
|
||||
|
||||
1.4.1:
|
||||
Fixed https://codeberg.org/scip/note/issues/11:
|
||||
|
||||
Every backend now uses a different default file extension and the
|
||||
default config file has it configured the same way.
|
||||
|
||||
The error message about an encrypted file when expecting an
|
||||
unencrypted one has been adjusted to be more understandable by new
|
||||
users.
|
||||
|
||||
Documentation updates.
|
||||
|
||||
Deprecation Warning: binary and text backend support will be removed
|
||||
in the upcoming version 1.5.0.
|
||||
|
||||
|
||||
|
||||
1.4.0:
|
||||
Added support for JSON encoded export files instead of YAML.
|
||||
Currently this is just an option, which can be set in the config
|
||||
with UseJSON or commandline -j. The old export format is now
|
||||
being considered deprecated (a warning will be shown) and will
|
||||
be removed in 1.5. Fixes https://codeberg.org/scip/note/issues/10.
|
||||
|
||||
A helper script has been added to help to combine two notedb's
|
||||
into one: contrib/sync-combine-two-yaml-exports-into-one.pl. It is
|
||||
still using YAML mode, JSON support will be added in the future.
|
||||
|
||||
|
||||
|
||||
1.3.26:
|
||||
fixed installer, on newer perls NOTEDB/* is being ignored
|
||||
|
||||
|
||||
|
||||
1.3.25:
|
||||
fixed indents
|
||||
|
||||
|
||||
|
||||
1.3.24:
|
||||
removed bashism in mysql installer.
|
||||
|
||||
|
||||
|
||||
1.3.23:
|
||||
defect distritbution. do not use.
|
||||
|
||||
|
||||
|
||||
1.3.22:
|
||||
fixed bug in mysql backend.
|
||||
added retry feature for NOTEDB::pwsafe3 backend save() password
|
||||
entering. bails out after 5 retries.
|
||||
|
||||
|
||||
|
||||
1.3.21:
|
||||
Changed note id generation in NOTEDB::pwsafe3::_uuid(), again.
|
||||
Instead of crc checksums and the loop to avoid duplicates, I just
|
||||
use a counter and sort the entries by ctime, so that older entries
|
||||
keep their note id. Also this should fix a rare bug, where the
|
||||
code hangs because of said loop.
|
||||
|
||||
|
||||
|
||||
1.3.20:
|
||||
fixed bug in NOTEDB::pwsafe3::_retrieve(), it iterated over the
|
||||
records unsorted which resulted in different note ids each time
|
||||
the program runs.
|
||||
|
||||
|
||||
|
||||
1.3.19:
|
||||
revert fix in NOTEDB::pwsafe3::filechanged(), use > again.
|
||||
|
||||
|
||||
|
||||
1.3.18:
|
||||
fixed unit tests and added more (lots of them)
|
||||
fixed several bugs in backend modules, which I found during
|
||||
writing of the unit tests.
|
||||
|
||||
|
||||
|
||||
1.3.17:
|
||||
applied patch by Bill Carlson, which fixes string length issues
|
||||
in non-interactive search mode.
|
||||
fixed usage text (-h) so that it now contains the available
|
||||
options.
|
||||
|
||||
|
||||
|
||||
1.3.16:
|
||||
fixed checking of encrypted notes when encryption is turned off.
|
||||
instead of checking note id 1, we now check the first entry,
|
||||
whatever id it may have.
|
||||
|
||||
|
||||
|
||||
1.3.15:
|
||||
fixed bug in NOTEDB::pwsafe3 backend, it converted the date
|
||||
of a note entry into the wrong formatted timestamp.
|
||||
|
||||
|
||||
|
||||
1.3.14:
|
||||
fixed bug in NOTEDB::pwsafe3 backend, it used lockging on the
|
||||
database file for reading, which is wrong.
|
||||
|
||||
|
||||
|
||||
1.3.13:
|
||||
ADDED: new config parameter 'motd', a note entry which will be shown
|
||||
on startup (if exists).
|
||||
CHANGED: the prompt will now show if the current instance is running
|
||||
in readonly mode.
|
||||
|
||||
|
||||
|
||||
1.3.12:
|
||||
FIXED: NOTEDB::general data backend module did overwrite records if
|
||||
there were some deleted ones in the database.
|
||||
|
||||
|
||||
|
||||
1.3.11:
|
||||
FIXED: NOTEDB::pwsafe3 contained the old python stuff in delete code.
|
||||
|
||||
|
||||
|
||||
1.3.10:
|
||||
FIXED: the YAML export/import change were missing too. grml...
|
||||
FIXED: NOTEDB::general backend fixed loading Config::General
|
||||
|
||||
|
||||
|
||||
1.3.9:
|
||||
FIXED: bin/note were missing. for whatever reason, I don't know.
|
||||
|
||||
|
||||
|
||||
1.3.8:
|
||||
ADDED: New backend added: NOTEDB::pwsafe3, which adds support to store
|
||||
notes in a Password Safe v3 database.
|
||||
FIXED: -d didn't work, because of a typo in mode assignment.
|
||||
|
||||
|
||||
|
||||
1.3.7:
|
||||
ADDED: added ticket feature, which adds a unique id to each
|
||||
new note, which persists during imports/exports. the
|
||||
id is a randomly generated string.
|
||||
|
||||
|
||||
|
||||
1.3.6:
|
||||
ADDED: Added test cases for "make test"
|
||||
ADDED: Added test for optional and required perl modules in
|
||||
Makefile.PL
|
||||
FIXED: NOTEDB::dumper version string were wrong, therefore
|
||||
cpan didn't index is properly.
|
||||
|
||||
|
||||
|
||||
1.3.5:
|
||||
FIXED: Applied patch by Elmar Loos which fixes misbehavior for
|
||||
-t and -T (identical output)
|
||||
FIXED: Fixed import bug which omitted the timestamp of the last
|
||||
entry, supmitted by Bill Barnard.
|
||||
FIXED: Fixed another import "bug" (or design flaw) which caused
|
||||
imported notes to get new numbering after importing them.
|
||||
Submitted by Bill Barnard.
|
||||
CHANGED: Until 1.3.4 missing Crypt:: modules lead to unencrypted
|
||||
fallback by note. From 1.3.5 on this will no more happen,
|
||||
it croaks now until you install the desired modules
|
||||
or modify your configuration to use no encryption.
|
||||
CHANGED: default config and default settings without config have
|
||||
been changed. They are now simpler, no colours or anything
|
||||
so that it works better out of the box in any terminal
|
||||
window or shell (e.g. on dark ones or the like).
|
||||
ADDED: New interactive mode command: "c". It is now possible to
|
||||
change note's behavior at runtime. No database related
|
||||
parameters can be modified.
|
||||
|
||||
|
||||
|
||||
1.3.4:
|
||||
ADDED: Each note now contains a "ticket number" which identifies
|
||||
it against other notes. Those tickets are not changing when
|
||||
notes will be reorganized.
|
||||
ADDED: added support for less to view note entries instead of
|
||||
just printing it to STDOUT. (interactive mode).
|
||||
|
||||
|
||||
|
||||
1.3.3:
|
||||
ADDED: new configfile parameter PrintLines (default: YES), which
|
||||
controls wether listings are separated by horizontal lines.
|
||||
|
||||
|
||||
|
||||
1.3.2:
|
||||
FIXED: NOTEDB::mysql backend parameter fixed (dbtype)
|
||||
FIXED: NOTEDB::mysql didn't fetch topics correctly
|
||||
FIXED: NOTEDB::text didn't correctly return last highest note id
|
||||
|
||||
|
||||
|
||||
1.3.1:
|
||||
FIXED: most config variables not related to drivers had
|
||||
invalid sentence in note, so the new ones of the new config
|
||||
were ignored.
|
||||
FIXED: added version to NOTEDB::text.
|
||||
FIXED: fixed handling of NOTEDB::crypt_supported, now encryption
|
||||
works again.
|
||||
ADDED: NOTEDB::text now supports internal caching too.
|
||||
CHANGED: lock() sets the umask internally to 022, so that other
|
||||
users are able to read the lockfile.
|
||||
|
||||
|
||||
|
||||
1.3.0:
|
||||
ADDED: new config option: ReadOnly
|
||||
ADDED: new database backend: NOTEDB::text, which uses the Storable
|
||||
module.
|
||||
CHANGED: the data import will now written to db once.
|
||||
CHANGED: added global database locking support, which is usually
|
||||
useful in multiuser environments.
|
||||
ADDED: new database backend: NOTEDB::general, which uses the
|
||||
Config::General module.
|
||||
CLEANUP: almost everywhere
|
||||
CHANGED: noterc config format changed! especially the config for
|
||||
backend drivers has changed a lot.
|
||||
CHANGED: the configuration variables are now stored in a hash, this
|
||||
saved some global variables, the driver variables are stored
|
||||
in an extra hash, which contains one key per driver, this
|
||||
hash gets supplied to the driver backend module 1:1.
|
||||
CHANGED: the libpath variable has been removed, it didnt't work either.
|
||||
use now .. instead, so that a local installation for a non
|
||||
root user is still possible.
|
||||
|
||||
|
||||
|
||||
1.2.6:
|
||||
FIXED: the binary driver (NOTEDB::binary) encounters now if a note
|
||||
entry is bigger then MaxNoteByte. It prints the overlapping
|
||||
part to STDERR, and a warning message and finally saves
|
||||
the complete, unchanged note entry to an external text file.
|
||||
|
||||
|
||||
|
||||
1.2.5:
|
||||
FIXED: removed any file/path actions using '/'. replaced by portable
|
||||
functions by using File::Spec. This makes it possible to run
|
||||
note unchanged on win32 (and possibly any other) environments.
|
||||
FIXED: added a whitespace to the prompt in interactive mode to
|
||||
circumvent a bug in the win32 Term::ReadLine module which causes
|
||||
the cursor to be displayed on the left side (column 0) of
|
||||
the screen.
|
||||
FIXED: added "or die" code to some commands which are running inside
|
||||
an eval{} block to fetch errors. Without the "or die"s no
|
||||
error could ever catched.
|
||||
CHANGED: removed HOME variable support of the noterc. in fact, if it
|
||||
exists, no error will occur, but it will no longer be used.
|
||||
It didn't work in older versions anyway.
|
||||
ADDED: It is now possible to quit note using CTRL-D (or: EOF)
|
||||
|
||||
|
||||
|
||||
1.2.4:
|
||||
CHANGED: in the function find_editor() the alternatives vim and pico
|
||||
has been removed because they would never had a match.
|
||||
FIXED: applied patch by Bill Barnard <bill@barnard-engineering.com>
|
||||
which fixes a bug in the sub format() which features bold
|
||||
hidden or underlined text. Now its possible to use a ^ char
|
||||
in hidden texts too. I applied the same for the other regexps.
|
||||
ADDED: if the config variable FormatText is set to 'simple' then
|
||||
only one * _ { or / will make the text tagged with them to
|
||||
be displayed formatted, instead of two.
|
||||
ADDED: added Term::ReadLine support (auto-completion and history).
|
||||
|
||||
|
||||
|
||||
1.2.3:
|
||||
ADDED: if FormatText is enabled one can now use a new special format
|
||||
tag: //. If a text is surrounded by two slashes, i.e.: //blah//
|
||||
then it appears "invisible" by using blue forground and blue
|
||||
background color for displaying. This is handy for passwords
|
||||
since no nobody can grab you password by looking at your
|
||||
monitor, but you can copy&paste it.
|
||||
|
||||
|
||||
|
||||
1.2.2:
|
||||
FIXED: oneliner note entries caused breaked displaying in interactive
|
||||
mode.
|
||||
FIXED: list displaying in interactiv mode corrected. the width of the
|
||||
note number will now correctly used.
|
||||
CHANGED: the default setting of note will now be to use an external
|
||||
editor instead of stdin.
|
||||
CHANGED: the unneccessary apostrophes in listings has been removed.
|
||||
ADDED: the note version will be displayed in the titlebar of interactive
|
||||
mode.
|
||||
ADDED: new config variable AutoClear, which is turned on by default,
|
||||
which controls wether the screen shall be cleared after each
|
||||
item (display, list and so on).
|
||||
|
||||
|
||||
|
||||
1.2.1:
|
||||
CHANGED: added the correct installation instructions to the README file.
|
||||
REMOVED: removed the usage guidelines from te README file. This information
|
||||
were redundant because its also contained in the manpage.
|
||||
FIXED: on FreeBSD the setting of MaxLen to 'auto' had no effect because the
|
||||
output of 'stty -a' which I use in note to determine the actual
|
||||
size of the terminal, is different from that on linux.
|
||||
ADDED: topics can now be abbreviated in interactive mode, which
|
||||
avoids typing. abbreviation works only if an explicit
|
||||
match could be found, otherwise the available topics that
|
||||
matches will be suggested.
|
||||
|
||||
|
||||
|
||||
1.2.0:
|
||||
CHANGED: using Makemaker instead of self-written code in Makefile.PL
|
||||
for installation. No more dependency checks built-in because
|
||||
note runs out-of-the-box without additional modules, as a matter fact.
|
||||
ADDED: if a search matches exactly on one note it will be displayed
|
||||
directly, which avoids typing.
|
||||
CHANGED: the main if-else contruct for calling the several subs has
|
||||
been replaced by a simple closure call.
|
||||
CHANGED: notes will now displayed in a slightly simpler fashion in interactive
|
||||
mode, without the separator line between the title and the note.
|
||||
ADDED: note can now determine automatically the width and height of
|
||||
the terminal window it runs in (in interactive mode only) and
|
||||
sets the width/height of what it prints accordingly. the config
|
||||
variable "MaxLen" must be set to "auto" (which is the default
|
||||
from now on) to get this to work.
|
||||
ADDED: any interactive command will now clear the screen before it does
|
||||
anything. this look much more uncluttered.
|
||||
ADDED: if multiple notes are printed at once (i.e. note 1,2) then the
|
||||
separator line between them will no more being printed because
|
||||
every notes title is preceded by a line anyway.
|
||||
CHANGED: by default the default operation mode is now interactive mode,
|
||||
which is somewhat kindlier to new users.
|
||||
CHANGED: changed to order which editor note tries to find. vi got now
|
||||
higher precedence, because it is likely installed on almost
|
||||
any unix system.
|
||||
CHANGED: cosmetics.
|
||||
NOTE: increased minor version number from 1 to 2 to indicate that
|
||||
development begun after 2 1/2 years pause again :-)
|
||||
|
||||
|
||||
|
||||
1.1.2:
|
||||
FIXED: Empty notes will no longer stored.
|
||||
ADDED: A new config option which allows you to specify a time format
|
||||
other than the default one which is used by note.
|
||||
|
||||
|
||||
|
||||
1.1.1:
|
||||
FIXED: Some odd typos in README and note.pod.
|
||||
FIXED: if ShortCd was on and one used "cd 3" and after that "cd .."
|
||||
then the current topic was wrong (empty $PATH).
|
||||
FIXED: if the current topic contained no notes and one created a new
|
||||
note without specifying a topic, then note did not add a
|
||||
proper topic (also because of empty $PATH).
|
||||
CHANGED: the default colors are now visible both on black and white
|
||||
backgrounds, see next entry.
|
||||
ADDED: two more color values: <white_black> and <bold>.
|
||||
CHANGED: the color hash is now in ::main instead of ::C.
|
||||
|
||||
|
||||
|
||||
1.1.0:
|
||||
CHANGED: does no more use the external touch command to create a new
|
||||
file, use perls open() instead.
|
||||
CHANGED: excluded some of the help texts from the usage message and the
|
||||
interactive help command to a manpage.
|
||||
ADDED: new commandline flag "--encrypt" which one can use to encrypt
|
||||
the mysql database password. This will be decrypted before
|
||||
connecting to the db. There is also a new config file option
|
||||
"encrypt_passwd" which indicates an encrypted db-password.
|
||||
ADDED: another new config option "ShortCd", which can be set to "yes"
|
||||
or 1 and if set, then a command like "cd 13" would jump
|
||||
directly to the topic of the note with the number 13.
|
||||
ADDED: now you can at any time cd back to the "root" of the
|
||||
topic-structure using the command "cd /".
|
||||
CHANGED: mysql.pm does now only do a table-lock on single write
|
||||
accesses, no more on the whole session. This allows one to
|
||||
access the same db twice or more.
|
||||
FIXED: Changed README and Changelog for readability on 80 by 25
|
||||
displays. And changed indentation of the note script itself.
|
||||
ADDED: NOTEDB.pm - a generic module, which holds some methods, which
|
||||
are used by binary.pm, mysql.pm and dbm.pm.
|
||||
ADDED: NOTEDB.pm generate_search(), which allows one to
|
||||
use AND, OR and various combinations of them using ( and ).
|
||||
ADDED: a search does now return the 2nd line of a note if a matching
|
||||
note's first line is a topic.
|
||||
CHANGED: use "unshift" instead of push to add $libpath to @INC.
|
||||
ADDED: a new feature, Caching of notes. supported by binary.pm and
|
||||
mysql.pm. To turn it on, one need to set "Cache" in the config
|
||||
to a true value.
|
||||
CHANGED: oop-ized and re-indented the modules dbm.pm, mysql.pm and
|
||||
binary.pm.
|
||||
ADDED: You can now specify a port for the mysql backend ("DbPort").
|
||||
|
||||
|
||||
|
||||
1.0.9: jumped directly to 1.1.0, too many additions.
|
||||
|
||||
|
||||
|
||||
1.0.8:
|
||||
FIXED: typo in noterc shipped with package may caused confusion
|
||||
(BLOWFISH instead of Blowfish).
|
||||
CHANGED: changed the way note manages temporary filez. It uses now a
|
||||
random string instead of just it's own PID. It does also change
|
||||
it's umask to 077 and, if applicable (on ext2 filesystems)
|
||||
issues "chattr +s" which will cause the ext2 inodes to be
|
||||
zero'd after file deletion.
|
||||
ADDED: A new config option allows the user to specify her own
|
||||
temp-directory. The default is still /tmp.
|
||||
|
||||
|
||||
|
||||
1.0.7:
|
||||
FIXED: there was a bug in the search expression, use now \Q and \E.
|
||||
ADDED: --config <file> allows one to use another config than the
|
||||
default.
|
||||
|
||||
|
||||
|
||||
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 checks 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...
|
||||
ADDED: a new database backend added, NOTEDB::dbm, which uses DBM
|
||||
files for storage.
|
||||
FIXED: &display-tree returns now, if there is no note, otherwise it
|
||||
would die because of an undefined refernce.
|
||||
CHANGED: Changed the config file format completely. It is now no more
|
||||
a perl file, instead it is a simple plain text file which note
|
||||
parses.
|
||||
CHANGED: Changed the way, note loads it database backend. It uses now
|
||||
the $dbdriver variable as module-name, which makes it possible
|
||||
easily to write your own backend without the need to change
|
||||
note itself.
|
||||
FIXED: Removed Getopt::Long option "bundling", causes errors with perl
|
||||
5.6.0 and is not senceful.
|
||||
FIXED: Added the Getopt::Long option "no_ignore_case". In 1.0.4 options
|
||||
were case insensitive causing -i to be interpreted as --import
|
||||
instead of --interactive ;-(((
|
||||
Thanks to Peter Palmreuter for the following fixed/additions:
|
||||
ADDED: a new config option $DEFAULT_LIST, which causes note,
|
||||
if turned to "LONG", to use long-listing as default.
|
||||
But it will still be able to use short-listing if you
|
||||
explicit specify that.
|
||||
FIXED: sub search prints now an appropriate error-message in
|
||||
case no searchstring was given instead of jumping to
|
||||
usage.
|
||||
CHANGED: Changed the text in the interactive help to reflect
|
||||
changes of verion 1.0.3 (t and T).
|
||||
|
||||
|
||||
|
||||
1.0.4:
|
||||
CHANGED: Moved from @ARGV-parsing to Getopt::Long, adding options is now
|
||||
much easier and I do now understand my own code ;-)
|
||||
ADDED: --raw, the "Raw Mode", which turns off any formatting of output.
|
||||
|
||||
|
||||
|
||||
1.0.3:
|
||||
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 to pipe another commands output to note!
|
||||
ADDED: you can now use an environment variable for the passphrase
|
||||
(when using encryption). If it is present, note will not ask
|
||||
for a passphrase. This is very useful 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.
|
||||
|
||||
|
||||
|
||||
1.0.2:
|
||||
ADDED: Topic-Tree overview command (-t or -T).
|
||||
ADDED: Enhanced list command in interactive mode, you can now specify
|
||||
a topic which notes you want to see.
|
||||
CHANGED: updated the help and usage sections to reflect the additions
|
||||
above.
|
||||
|
||||
|
||||
|
||||
1.0.1:
|
||||
FIXED: fixed bug in NOTEDB::mysql, which caused note to store NULL
|
||||
values in db, if encryption was off. A really dump failure :-(
|
||||
|
||||
|
||||
|
||||
1.0.0:
|
||||
CHANGED: removed install.sh. use now a Makefile for installation.
|
||||
ADDED: Encryption support. Note can now encrypt notes using IDEA
|
||||
or DES as encryption-protocols(symetric).
|
||||
|
||||
|
||||
|
||||
0.9:
|
||||
FIXED: There were many new bugs after my last changes *grrrrr*. fixed.
|
||||
Works now properly, with both backends!
|
||||
FIXED: and another bug: recounting of numbers did not take care about
|
||||
the existing order! If you deleted note #12, then note #13
|
||||
became not neccessarily #12! Instead it becames any other
|
||||
number (kind of randomly...).
|
||||
CHANGED: NOTEDB::binary set_del function changed, it does no more require
|
||||
a temporary file for number recount. Instead it uses get_all and
|
||||
stores all notes in RAM and then rewrites the database.
|
||||
FIXED: fixed the set_new call within note. It used 0 as the first param
|
||||
(number) which is not useful since we dont have support for
|
||||
autoincrement from all database backends.
|
||||
FIXED: fixed the function set_recountnum in NITEDB::mysql, it was also
|
||||
incorrect :-((( 0.8 seemed to be a very bad early alpha...
|
||||
FIXED: there was a bug in NOTEDB::binary which caused not to recount
|
||||
note numbers after deleting one :-(
|
||||
|
||||
|
||||
|
||||
0.8:
|
||||
ADDED: NOTEDB::binary. so now 0.8 is ready for shipping !
|
||||
FIXED: regexp bug fixed. It was only possible to delete 2 items
|
||||
together
|
||||
separated by comma ("d 1,2,3,4" deleted only 1,2!).
|
||||
ADDED: Some new config options which reflects the new module structure.
|
||||
So you can change your database backend without the need to
|
||||
replace the note script itself.
|
||||
FIXED: the previously added feature "cd <topic>" didn't really work :-(
|
||||
ADDED: NOTEDB::mysql added. Perlmodule, which I will use within
|
||||
note from now on instead of buildin functions for accessing the
|
||||
database. From now on I only need to maintain one version of
|
||||
note, since the module interface will be identical between the
|
||||
bin and sql version.
|
||||
CHANGED: The SQL code does not use Mysql.pm anymore. Instead it is coded
|
||||
using the more portable DBI module. This allows one easily to
|
||||
switch to anther database, which is supported by DBI.
|
||||
CHANGED: Locking. The db-table will now be locked before note accesses
|
||||
it.
|
||||
FIXED: width of listings is now always the same independent of the
|
||||
stringlength of a certain note.
|
||||
|
||||
|
||||
|
||||
0.7:
|
||||
ADDED: one can now use the unix-like "cd" command to change to another
|
||||
topic, thus use "cd topicname" instead just typing "topicname"!
|
||||
FIXED: there was a smal regex bug which maked it impossible to use
|
||||
such topics: "4 test", in such a case note just displayed note
|
||||
number 4 instead of cd'ing to topic "4 test".
|
||||
ADDED: a new config option "$KEEP_TIMESTAMP" allows a user to disable
|
||||
note's default behavior of updating the timestamp of a note
|
||||
after editing it.
|
||||
|
||||
|
||||
|
||||
0.6:
|
||||
FIXED: oops - the new suptopic feature confused the commandline-mode of
|
||||
note! quickly corrected! so subtopics also available from
|
||||
commandline.
|
||||
FIXED: a small bug fiyed, it was impossible to use -D or -I from
|
||||
commandline, if $ALWAYS_INT was turned on, now it is.
|
||||
FIXED: fixed problem with local/global variable $time, which confused
|
||||
the script under certain circumstances, now $time is no more
|
||||
global, it will be read in (using &getdate) locally by &new
|
||||
and &edit.
|
||||
CHANGED: The Topic separator is no longer hardcoded, one can customize
|
||||
it using the $TopicSep variable, the default is now /, the
|
||||
backslash will no more work!
|
||||
CHANGED: use perl buildin localtime() function instead of
|
||||
GNU date, which is possibly not installed on every target
|
||||
system (i.e. win32), therefore better portability!
|
||||
CHANGED: use now the strict module
|
||||
ADDED: Support for subtopics added (and sub-sub-..-topics).
|
||||
CHANGED: Removed the "T" command, it is now obsolete.
|
||||
CHANGED: behavior of list command changed, now shows topics as well as
|
||||
notes under the current topic(if there are some).
|
||||
CHANGED: The ".." command takes you now one level higher in your topic-
|
||||
structure.
|
||||
ADDED: A new config option $PreferredEditor, which you can use to
|
||||
specify your own choice of editor.
|
||||
FIXED: A bug at line 769 causing single note where smaller than note-
|
||||
listings
|
||||
|
||||
|
||||
|
||||
0.5:
|
||||
ADDED: Topic support(requested). You can sort the various notes under
|
||||
different topics now.
|
||||
FIXED: There was another bug, which caused the list command to display
|
||||
the notes with a too high value of $maxlen.
|
||||
|
||||
|
||||
|
||||
0.4.2:
|
||||
ADDED: If run in interactive mode, note will at first do a list
|
||||
command.
|
||||
FIXED: A bug caused note to save bogus timestamps after editing a note.
|
||||
CHANGED: It does no more print 3 newlines before the menu in interactive
|
||||
mode.
|
||||
FIXED: Some more vars will be resetted during each loop in interactive
|
||||
mode. $ListType.
|
||||
|
||||
|
||||
|
||||
0.4.1:
|
||||
ADDED: The install.sh script for the mysql version is no able to
|
||||
install the required Mysql module directly from CPAN, thanks
|
||||
to David A. Bandel!
|
||||
FIXED: The mysql version did not display notes (i.e.: "note 3" did
|
||||
nothing)
|
||||
CHANGED: Again, the sql-format of the mysql database has been changed.
|
||||
Now there are only 3 fields, the number filed is the primary
|
||||
key, the id field in previous versions was a waste of
|
||||
diskspace...
|
||||
CHANGED: The format of the dump-output has been changed.
|
||||
ADDED: It is now possible to import previously dumped notes into the
|
||||
notedb
|
||||
(dumps from both versions are compatible with each other)
|
||||
FIXED: the function num_bereich() had a bug, which caused ot to ignore under
|
||||
some circumstances one number (i.e. "note -d 4-13" did nothing).
|
||||
|
||||
|
||||
|
||||
0.4:
|
||||
CHANGED: ok, mysql support is back again (upon requests). therefore there
|
||||
are two different version of the script in the same time with
|
||||
the same features, one for mysql and the other one for the
|
||||
binary database.
|
||||
ADDED: Dump to textfile capability. Later on I want to dump it into a
|
||||
palm readable format, any help is welcome!
|
||||
ADDED: interactive mode.
|
||||
CHANGED: Better modularity, better code.
|
||||
CHANGED: note can now run without the need of a config file. If does not
|
||||
exist, it will try to work with default values.
|
||||
ADDED: sub num_bereich(), which allows one to specify more then one
|
||||
number for deletion or displaying (i.e.: "-d 1,4,7" or "-d 4-9")
|
||||
|
||||
|
||||
|
||||
0.3:
|
||||
CHANGED: it uses no more a mysql database, but a binary file instead.
|
||||
This is much faster!
|
||||
ADDED: note can display the notes with colors, it is turned off by
|
||||
default
|
||||
|
||||
|
||||
|
||||
0.2:
|
||||
FIXED: now any occurence of ' will be masked with \' before storage
|
||||
to the mysql database.
|
||||
FIXED: now numbers of notes will be recounted, if one delete one note,
|
||||
so the list of notes will everytime start with 1,2,3,...
|
||||
CHANGED: the look of the list output has been changed, similar to a table
|
||||
|
||||
|
||||
|
||||
0.1:
|
||||
INITIAL RELEASE.
|
||||
28
MANIFEST
28
MANIFEST
@@ -1,28 +0,0 @@
|
||||
MANIFEST
|
||||
bin/stresstest.sh
|
||||
bin/note
|
||||
mysql/permissions
|
||||
mysql/sql
|
||||
mysql/install.sh
|
||||
mysql/README
|
||||
VERSION
|
||||
config/rc
|
||||
config/noterc
|
||||
README
|
||||
UPGRADE
|
||||
note.pod
|
||||
TODO
|
||||
t/run.t
|
||||
lib/NOTEDB/mysql.pm
|
||||
lib/NOTEDB/text.pm
|
||||
lib/NOTEDB/dumper.pm
|
||||
lib/NOTEDB/pwsafe3.pm
|
||||
lib/NOTEDB/dbm.pm
|
||||
lib/NOTEDB/README
|
||||
lib/NOTEDB/binary.pm
|
||||
lib/NOTEDB/general.pm
|
||||
lib/NOTEDB.pm
|
||||
Changelog
|
||||
Makefile.PL
|
||||
META.yml
|
||||
META.json
|
||||
41
Makefile.PL
41
Makefile.PL
@@ -1,41 +0,0 @@
|
||||
use ExtUtils::MakeMaker;
|
||||
|
||||
my %optional = (
|
||||
'Crypt::CBC' => "Required by encryption support",
|
||||
'Crypt::Rijndael' => "Required by encryption support",
|
||||
'Data::Dumper' => "Required by dumper DB backend",
|
||||
'MIME::Base64' => "Required by varios optional backends",
|
||||
'Storable' => "Required by text DB backend",
|
||||
'Config::General' => "Required by general DB backend",
|
||||
'DB_File' => "Required by dbm DB backend",
|
||||
'DBI' => "Required by mysql DB backend",
|
||||
'DBD::mysql' => "Required by mysql DB backend",
|
||||
'Crypt::PWSafe3' => "Required by Password Safe v3 backend"
|
||||
);
|
||||
|
||||
foreach my $module (sort keys %optional) {
|
||||
eval "require $module";
|
||||
if ($@) {
|
||||
warn("Optional module $module not installed, $optional{$module}\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WriteMakefile(
|
||||
'NAME' => 'note',
|
||||
'VERSION_FROM' => 'bin/note', # finds $VERSION
|
||||
'EXE_FILES' => [ 'bin/note' ],
|
||||
'PREREQ_PM' => {
|
||||
'IO::File' => 0,
|
||||
'FileHandle' => 0,
|
||||
'File::Spec' => 0,
|
||||
'File::Glob' => 0,
|
||||
'FileHandle' => 0,
|
||||
'Getopt::Long' => 0,
|
||||
'Fcntl' => 0,
|
||||
'IO::Seekable' => 0,
|
||||
'YAML' => 0,
|
||||
},
|
||||
($ExtUtils::MakeMaker::VERSION ge '6.31'? ('LICENSE' => 'perl', ) : ()),
|
||||
'clean' => { FILES => 't/*.out t/test.cfg *~ */*~' }
|
||||
);
|
||||
@@ -1,5 +1,8 @@
|
||||
# note - a perl script for maintaining notes.
|
||||
|
||||
> [!CAUTION]
|
||||
> This software is now being maintained on [Codeberg](https://codeberg.org/scip/note/).
|
||||
|
||||
This is the perl script 'note' in version 1.4.2 from 24/09/2024.
|
||||
|
||||
## Introduction
|
||||
|
||||
6
TODO
6
TODO
@@ -1,6 +0,0 @@
|
||||
- &output() has to be rewritten, its a historically
|
||||
growed mutant.
|
||||
|
||||
- ncurses support
|
||||
|
||||
|
||||
73
UPGRADE
73
UPGRADE
@@ -1,73 +0,0 @@
|
||||
1.0.5 important note upgrade information
|
||||
========================================
|
||||
|
||||
If you are upgrading from previous versions of note, you
|
||||
will need to create a new config file, since the format of
|
||||
that file has completely changed!
|
||||
|
||||
Take a look at the sample in config/noterc for details.
|
||||
|
||||
note will NOT work with an existing database and an old config.
|
||||
You have to create a new config based on your old settings.
|
||||
|
||||
|
||||
Please don't forget to make a backup of your database before
|
||||
upgrading! I am not responsible for data loss!
|
||||
|
||||
I told ya...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Thomas Linden <tom@daemon.de>
|
||||
READ THIS FILE, IF YOU ARE UPGRADING FROM 0.9 TO 1.0.x
|
||||
======================================================
|
||||
|
||||
|
||||
In any case: BACKUP your existing note database!!!!!!!
|
||||
The format has not changed, but some default values
|
||||
(see the new config file-sample). Use this command
|
||||
to save your note database with your *old* version
|
||||
of note:
|
||||
"note -D"
|
||||
This works with both the mysql and the binary version.
|
||||
|
||||
You need to reedit your configfile. Please refer to the
|
||||
sample config in config/noterc.
|
||||
|
||||
======================================================
|
||||
|
||||
This version of note has now encryption support build in.
|
||||
If you decide to use it, you need to re-initialize your
|
||||
note database. That's why, because your current database
|
||||
is unencrypted and *if* you want to secure your data, you
|
||||
need to secure everything. That means, your existing data
|
||||
must be encrypted before you can use this new capability!
|
||||
|
||||
Follow this steps:
|
||||
o backup existing db:
|
||||
$ note -D
|
||||
o backup the db:
|
||||
$ cp .notedb .notedb.save
|
||||
or (for mysql users!):
|
||||
$ cp -r /usr/local/mysql/data/notedb ~/notedb.mysql.save
|
||||
o go into note and delete all existing notes:
|
||||
$ note -d 1-20 (or however)
|
||||
o now upgrade your note installation:
|
||||
$ perl Makefile.PL; make install
|
||||
o re-configure note. Turn $USE_CRYPT on by setting it
|
||||
to "YES".
|
||||
o re-initialize your database:
|
||||
$ note -I note.dump.2323 (or whatever)
|
||||
note will prompt you for a passphrase. It will be used
|
||||
by Crypt::CBC for encrypting your data.
|
||||
From now on, your data is encrypted. You will need the passphrase
|
||||
you set above for decrypting it! So - don't forget it!
|
||||
|
||||
======================================================
|
||||
|
||||
AGAIN: YOU HAVE BEEN WARNED! DO NOT UPGRADE WITHOUT MADE A
|
||||
BACKUP OF YOUR DATABASE! I AM NOT RESPONSIBLE IF YOU
|
||||
LOOSE DATA!
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#!/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 <directory>"
|
||||
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
|
||||
280
config/noterc
280
config/noterc
@@ -1,280 +0,0 @@
|
||||
# note 1.4.1 -*- conf -*-
|
||||
#
|
||||
# This is a sample config for the note script There are useful
|
||||
# defaults set in note itself.
|
||||
#
|
||||
# Copy it to your $HOME as .noterc
|
||||
#
|
||||
# Comments start with #, empty lines will be ignored.
|
||||
#
|
||||
# To turn on an option, set it to: 1, on or yes
|
||||
# To turn off an option, set it to: 0, off or no
|
||||
#
|
||||
# An option consists of an atribute-value pair separated by minimum
|
||||
# one space (more spaces and/or tabs are allowed) and an optional
|
||||
# equal sign in between.
|
||||
#
|
||||
# Variable names are case in-sensitive.
|
||||
#
|
||||
# Refer to the manpage to learn more about the config
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# you need to decide which database backend you want to use. Please
|
||||
# refer to the corresponding documentation for closer information
|
||||
# about the certain backend! Currently supported types: "binary",
|
||||
# "dbm", "mysql", "general", "dumper", "pwsafe3" or "text". You must
|
||||
# also edit/uncomment one section below for the backend you want to
|
||||
# use!
|
||||
dbdriver = binary
|
||||
|
||||
|
||||
|
||||
#
|
||||
# BINARY backend (the default)
|
||||
binary::dbname = ~/.notedb # filename
|
||||
binary::MaxNoteByte = 4096 # max bytes per note entry
|
||||
binary::MaxTimeByte = 64 # max bytes for the date
|
||||
|
||||
|
||||
|
||||
#
|
||||
# MYSQL backend
|
||||
mysql::dbhost = localhost # hostname
|
||||
mysql::dbport = 3306 # tcp port
|
||||
mysql::dbuser = you # db login
|
||||
mysql::dbpasswd = # db password
|
||||
mysql::dbname = # database name (default: note)
|
||||
mysql::encrypt_passwd = 0 # mysql::dbpasswd is
|
||||
# encrypted (note --encrypt)
|
||||
|
||||
|
||||
#
|
||||
# DBM backend
|
||||
dbm::directory = ~/.notedb.dbm
|
||||
|
||||
|
||||
|
||||
#
|
||||
# GENERAL backend
|
||||
general::dbname = ~/.notedb.txt
|
||||
|
||||
|
||||
#
|
||||
# TEXT backend
|
||||
text::dbname = ~/.notedb.storable
|
||||
|
||||
|
||||
#
|
||||
# DUMPER backend
|
||||
dumper::dbname = ~/.notedb.dumper
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Password Safe v3 backend Some notes on this one: This backend
|
||||
# maintains encryption itself, which is mandatory as well. So you'll
|
||||
# have to disable encryption (UseEncryption = NO)!
|
||||
#
|
||||
# The Password Safe v3 file has its own fields for password and
|
||||
# username, which note doesn't have. To be compatible, the pwsafe3
|
||||
# backend parses the note text for those fields and stores them
|
||||
# accordignly to the db:
|
||||
#
|
||||
# For username field: user|username|login|account|benutzer
|
||||
# For passwd field: password|pass|passwd|kennwort|pw
|
||||
#
|
||||
# If it doesn't find it, it will put empty strings into the pwsafe3
|
||||
# database.
|
||||
#
|
||||
# The pwsafe3 database can be accessed by Password Safe (see:
|
||||
# http://passwordsafe.sourceforge.net/) or other tools which support
|
||||
# the format (see:
|
||||
# http://passwordsafe.sourceforge.net/relatedprojects.shtml)
|
||||
pwsafe3::dbname = ~/.notedb.psafe3
|
||||
|
||||
|
||||
#
|
||||
# You can use encryption with note, that means notes and timestamps
|
||||
# will be stored encrypted. This is supported by every db-backend, but
|
||||
# not the pwsafe3 backend because this one has builtin encryption
|
||||
# support.
|
||||
UseEncryption = NO
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Specify the encryption protocol. The appropriate perl module needs
|
||||
# to be installed. Possible velues are IDEA, DES or Blowfish, the
|
||||
# default is IDEA.
|
||||
CryptMethod = IDEA
|
||||
|
||||
|
||||
|
||||
#
|
||||
# You can run note always in interactive mode by simply
|
||||
# typing "note". The default is: YES.
|
||||
AlwaysInteractive = YES
|
||||
|
||||
|
||||
|
||||
#
|
||||
# In interactive mode, note issues a list command if you simply hit
|
||||
# enter. By turning this on, it will issue a longlist command instead
|
||||
# if you hit just enter. The default is: NO
|
||||
DefaultLong = NO
|
||||
|
||||
|
||||
|
||||
#
|
||||
# You can use an external editor everytime from note instead of STDIN
|
||||
# for creating new notes. The default is: YES
|
||||
AlwaysEditor = YES
|
||||
|
||||
|
||||
|
||||
#
|
||||
# By default, note looks in the environment for a variable $EDITOR or,
|
||||
# if this is not the case, for $VISUAL and as fallback it uses 'vi'.
|
||||
# You can override this by setting this variable here.
|
||||
PreferredEditor =
|
||||
|
||||
|
||||
|
||||
#
|
||||
# If you don't prefer that note updates the timestamp of a note after
|
||||
# editing, turn this on. It will keep the original timestamp if this
|
||||
# option is set. The default is: NO
|
||||
KeepTimeStamp = NO
|
||||
|
||||
|
||||
|
||||
#
|
||||
# You can specify your own topic separator here. The default topic
|
||||
# separator is a normal slash: "/"
|
||||
TopicSeparator = /
|
||||
|
||||
|
||||
|
||||
#
|
||||
# The maximum width for displaying a note, in CHARS. Depends on your
|
||||
# screen-size. You can set it to "auto", if you wish that note should
|
||||
# determine the available size automatically.
|
||||
MaxLen = auto
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Turn this off if you dont want note to automatically clear the
|
||||
# screen after displaying something and after exit. The default is: NO
|
||||
AutoClear = NO
|
||||
|
||||
|
||||
|
||||
#
|
||||
# note can use colors for output, turn this of, if you don't like it,
|
||||
# or if your terminal does not support it. The default is: YES
|
||||
UseColors = NO
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Color-definitions of the various items. Will only take effect, if
|
||||
# "UseColors" is turned on!
|
||||
#
|
||||
# The following colors are available: black, red, green, yellow, blue,
|
||||
# magenta, cyan and white.
|
||||
#
|
||||
# For bold color write it uppercase (BLACK will be bold black). For
|
||||
# underlined color append an underscore (blue_ will be underlined
|
||||
# blue). For inverted color append an "I" (greenI will be inverted
|
||||
# green).
|
||||
BorderColor BLACK
|
||||
NumberColor blue
|
||||
NoteColor green
|
||||
TimeColor black
|
||||
TopicColor BLACK
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Additional to colors, you can also do a little bit of formatting
|
||||
# your notes (bold, underlined, italic) text. The default is: YES.
|
||||
FormatText = NO
|
||||
|
||||
|
||||
|
||||
#
|
||||
# You might specify your own directory for temporary files. note
|
||||
# needs to create some temp files during editing of notes. You could
|
||||
# protect this directory using the command: chmod 700 directory. The
|
||||
# default is: /tmp
|
||||
TempDirectory = ~/tmp
|
||||
|
||||
|
||||
|
||||
#
|
||||
# You can jump to a topic by typing "cd 13" in interactive mode. The
|
||||
# deault is: NO
|
||||
ShortCd = YES
|
||||
|
||||
|
||||
|
||||
#
|
||||
# note can use a cached copy of the note database for list/tree/search
|
||||
# this is currently only supported by the binary and the mysql
|
||||
# backends, the general and text backends have an internal cache. The
|
||||
# default is: NO
|
||||
Cache = NO
|
||||
|
||||
|
||||
|
||||
#
|
||||
# You can define your very own time format for time stamps
|
||||
# YY - the last 2 digits of a year
|
||||
# YYYY - year
|
||||
# MM - month
|
||||
# DD - day
|
||||
# hh - hours
|
||||
# mm - minutes
|
||||
# ss - seconds
|
||||
# This is the default: (18.10.2000 21:32:08)
|
||||
TimeFormat = DD.MM.YYYY hh:mm:ss
|
||||
|
||||
|
||||
|
||||
#
|
||||
# You can make note readonly which is useful for database copies The
|
||||
# default is: NO
|
||||
ReadOnly = NO
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Note may separate titles and topics using horizontal lines when
|
||||
# listing them. You can turn on this behavior by setting PrintLines to
|
||||
# YES. The default is: NO
|
||||
PrintLines = NO
|
||||
|
||||
|
||||
|
||||
#
|
||||
# Add a hash to identify notes. Such a hash will persist several
|
||||
# importy/export cycles and makes each single note unique.
|
||||
AddTicket = NO
|
||||
|
||||
|
||||
#
|
||||
# Show an entry on startup. If you want it, create such an entry and
|
||||
# supply its number here
|
||||
motd =
|
||||
|
||||
|
||||
#
|
||||
# Enable JSON formatted backups. The option will be removed in version
|
||||
# 1.5 and become the only available option. In earlier versions: if
|
||||
# unset or set to NO, YAML will be used.
|
||||
UseJSON = YES
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
use warnings;
|
||||
use strict;
|
||||
no strict "refs";
|
||||
|
||||
use IO::All;
|
||||
use Encode;
|
||||
# only YAML::XS is able to properly load our data (others fail
|
||||
# invariably)
|
||||
use YAML::XS qw(Load);
|
||||
# only YAML is able to properly Dump the data YAML::XS generates
|
||||
# various kinds of multiline entries like "line\nline2\nline3" end up
|
||||
# literally in the generated yaml, which note is then unable to
|
||||
# feed. So, the pure perl version is better as it always generates
|
||||
# multiline entries for data containing newlines
|
||||
use YAML qw(Dump);
|
||||
use Data::Dumper;
|
||||
use Term::ANSIColor;
|
||||
|
||||
my ($yf1, $yf2, $outfile) = @ARGV;
|
||||
|
||||
|
||||
# read both input files and parse yaml into data structure, fix
|
||||
# non-printables
|
||||
my $badutf81 < io $yf1;
|
||||
my $yaml1 = decode( 'UTF-8', $badutf81 =~ s/[^\x00-\x7F]+//gr );
|
||||
my $y1 = Load $yaml1 or die "Could not load $yf1: $!";
|
||||
|
||||
my $badutf82 < io $yf2;
|
||||
my $yaml2 = decode( 'UTF-8', $badutf82 =~ s/[^\x00-\x7F]+//gr );
|
||||
my $y2 = Load $yaml2 or die "Could not load $yf2: $!";
|
||||
|
||||
# convert to comparable hashes with unique keys
|
||||
my $hash1 = &hashify($y1);
|
||||
my $hash2 = &hashify($y2);
|
||||
|
||||
# diff and recombine the two into a new one
|
||||
my $combinedhash = &hash2note(&diff($hash1, $hash2));
|
||||
|
||||
#print Dumper($combinedhash); exit;
|
||||
|
||||
# turn into yaml
|
||||
my $combindedyaml = Dump($combinedhash);
|
||||
|
||||
# perl uses scalars as hash keys (read: strings) so we need to unquote
|
||||
# them here to make note happy
|
||||
$combindedyaml =~ s/^'(\d+)':/$1:/gm;
|
||||
|
||||
# done
|
||||
my $out = io $outfile;
|
||||
$combindedyaml > $out;
|
||||
|
||||
|
||||
print "\nDone. Wrote combined hashes to $outfile\n";
|
||||
|
||||
sub hash2note {
|
||||
# convert given hash into note format with number as key
|
||||
my $hash = shift;
|
||||
my $new;
|
||||
my $i = 0;
|
||||
|
||||
foreach my $path (sort keys %{$hash}) {
|
||||
$new->{++$i} = $hash->{$path};
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
sub diff {
|
||||
# diff the two hashes, create a new combined one
|
||||
my($hash1, $hash2) = @_;
|
||||
my $new;
|
||||
|
||||
# iterate over hash1, store duplicates and remove them in hash2,
|
||||
# store different entries and remove in both,
|
||||
# store those missing in hash2 and delete them in hash1
|
||||
foreach my $path (sort keys %{$hash1}) {
|
||||
if (exists $hash2->{$path}) {
|
||||
if ($hash2->{$path}->{body} eq $hash1->{$path}->{body}) {
|
||||
#printf STDERR "%s => %s is duplicate\n", $path, $hash1->{$path}->{title};
|
||||
$new->{$path} = delete $hash2->{$path};
|
||||
delete $hash1->{$path};
|
||||
}
|
||||
else {
|
||||
printf STDERR "%s => %s is different\n", $path, $hash1->{$path}->{title};
|
||||
my $which = &askdiff($hash1->{$path}->{body}, $hash2->{$path}->{body}, $hash1->{$path}->{title});
|
||||
|
||||
if ($which eq 'l') {
|
||||
# use left
|
||||
$new->{$path} = delete $hash1->{$path};
|
||||
delete $hash2->{$path};
|
||||
}
|
||||
elsif ($which eq 'r') {
|
||||
# use right
|
||||
$new->{$path} = delete $hash2->{$path};
|
||||
delete $hash1->{$path};
|
||||
}
|
||||
else {
|
||||
# both
|
||||
$new->{$path} = delete $hash1->{$path};
|
||||
$new->{$path . 2} = delete $hash2->{$path};
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
#printf STDERR "%s => %s is missing in hash2\n", $path, $hash1->{$path}->{title};
|
||||
$new->{$path} = delete $hash1->{$path};
|
||||
}
|
||||
}
|
||||
|
||||
# store any lefovers of hash1
|
||||
foreach my $path (sort keys %{$hash1}) {
|
||||
#printf STDERR "%s => %s is left in hash1\n", $path, $hash1->{$path}->{title};
|
||||
$new->{$path} = $hash1->{$path};
|
||||
}
|
||||
|
||||
# store any lefovers of hash2
|
||||
foreach my $path (sort keys %{$hash2}) {
|
||||
#printf STDERR "%s => %s is left in hash2\n", $path, $hash2->{$path}->{title};
|
||||
$new->{$path} = $hash2->{$path};
|
||||
}
|
||||
|
||||
return $new
|
||||
}
|
||||
|
||||
sub askdiff {
|
||||
my ($left, $right, $title) = @_;
|
||||
$left > io("/tmp/$$-body-left");
|
||||
$right > io("/tmp/$$-body-right");
|
||||
my $diff = `diff --side-by-side /tmp/$$-body-left /tmp/$$-body-right`;
|
||||
|
||||
print color ('bold');
|
||||
print "\n\nEntry $title exists in both hashes but differ. Diff:\n";
|
||||
print color ('reset');
|
||||
|
||||
print "$diff\n";
|
||||
|
||||
print color ('bold');
|
||||
print "keep [l]eft, keep [r]ight, keep [b]oth? ";
|
||||
print color ('reset');
|
||||
|
||||
my $answer = <STDIN>;
|
||||
chomp $answer;
|
||||
|
||||
system("rm -f /tmp/$$-body-left /tmp/$$-body-right");
|
||||
|
||||
if ($answer !~ /^[blr]$/) {
|
||||
print "Wrong answer $answer, using [b]oth!\n";
|
||||
return 'b';
|
||||
}
|
||||
|
||||
return $answer;
|
||||
}
|
||||
|
||||
sub hashify {
|
||||
# create new hash with path+title as key instead of id's
|
||||
my $data = shift;
|
||||
my $new = {};
|
||||
|
||||
foreach my $id (keys %{$data} ) {
|
||||
my $path = $data->{$id}->{path} . '|' . $data->{$id}->{title};
|
||||
if (exists $new->{$path}) {
|
||||
die "$path already exists!\n";
|
||||
}
|
||||
else {
|
||||
$new->{$path} = $data->{$id};
|
||||
}
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
306
lib/NOTEDB.pm
306
lib/NOTEDB.pm
@@ -1,306 +0,0 @@
|
||||
#
|
||||
# this is a generic module, used by note database
|
||||
# backend modules.
|
||||
#
|
||||
# Copyright (c) 2000-2017 T.v.Dein <tlinden@cpan.org>
|
||||
|
||||
|
||||
package NOTEDB;
|
||||
|
||||
use Exporter ();
|
||||
use vars qw(@ISA @EXPORT $crypt_supported);
|
||||
|
||||
$NOTEDB::VERSION = "1.45";
|
||||
|
||||
BEGIN {
|
||||
# make sure, it works, otherwise encryption
|
||||
# is not supported on this system!
|
||||
eval { require Crypt::CBC; };
|
||||
if($@) {
|
||||
$NOTEDB::crypt_supported = 0;
|
||||
}
|
||||
else {
|
||||
$NOTEDB::crypt_supported = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub no_crypt {
|
||||
$NOTEDB::crypt_supported = 0;
|
||||
}
|
||||
|
||||
|
||||
sub use_crypt {
|
||||
my($this,$key,$method) = @_;
|
||||
my($cipher);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$cipher = new Crypt::CBC($key, $method);
|
||||
};
|
||||
if($@) {
|
||||
print "warning: Crypt::$method not supported by system!\n";
|
||||
$NOTEDB::crypt_supported = 0;
|
||||
}
|
||||
else {
|
||||
$this->{cipher} = $cipher;
|
||||
}
|
||||
}
|
||||
else{
|
||||
print "warning: Crypt::CBC not supported by system!\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub use_cache {
|
||||
#
|
||||
# this sub turns on cache support
|
||||
#
|
||||
my $this = shift;
|
||||
$this->{use_cache} = 1;
|
||||
$this->{changed} = 1;
|
||||
}
|
||||
|
||||
sub cache {
|
||||
#
|
||||
# store the whole db as hash
|
||||
# if use_cache is turned on
|
||||
#
|
||||
my $this = shift;
|
||||
if ($this->{use_cache}) {
|
||||
my %res = @_;
|
||||
%{$this->{cache}} = %res;
|
||||
}
|
||||
}
|
||||
|
||||
sub unchanged {
|
||||
#
|
||||
# return true if $this->{changed} is true, this will
|
||||
# be set to true by writing subs using $this->changed().
|
||||
#
|
||||
my $this = shift;
|
||||
return 0 if(!$this->{use_cache});
|
||||
if ($this->{changed}) {
|
||||
$this->{changed} = 0;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
print "%\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
sub changed {
|
||||
#
|
||||
# turn on $this->{changed}
|
||||
# this will be used by update or create subs.
|
||||
#
|
||||
my $this = shift;
|
||||
$this->{changed} = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
sub generate_search {
|
||||
#
|
||||
# get user input and create perlcode ready for eval
|
||||
# sample input:
|
||||
# "ann.a OR eg???on AND u*do$"
|
||||
# resulting output:
|
||||
# "$match = 1 if(/ann\.a/i or /eg...on/i and /u.*do\$/i );
|
||||
#
|
||||
my($this, $string) = @_;
|
||||
|
||||
my $case = "i";
|
||||
|
||||
if ($string =~ /^\/.+?\/$/) {
|
||||
return $string;
|
||||
}
|
||||
elsif (!$string) {
|
||||
return "/^/";
|
||||
}
|
||||
|
||||
# we will get a / in front of the first word too!
|
||||
$string = " " . $string . " ";
|
||||
|
||||
# check for apostrophs
|
||||
$string =~ s/(?<=\s)(\(??)("[^"]+"|\S+)(\)??)(?=\s)/$1 . $this->check_exact($2) . $3/ge;
|
||||
|
||||
# remove odd spaces infront of and after <20>and<6E> and <20>or<6F>
|
||||
$string =~ s/\s\s*(AND|OR)\s\s*/ $1 /g;
|
||||
|
||||
# remove odd spaces infront of <20>(<28> and after <20>)<29>
|
||||
$string =~ s/(\s*\()/\(/g;
|
||||
$string =~ s/(\)\s*)/\)/g;
|
||||
|
||||
# remove first and last space so it will not masked!
|
||||
$string =~ s/^\s//;
|
||||
$string =~ s/\s$//;
|
||||
|
||||
# mask spaces if not infront of or after <20>and<6E> and <20>or<6F>
|
||||
$string =~ s/(?<!AND)(?<!OR)(\s+?)(?!AND|OR)/'\s' x length($1)/ge;
|
||||
|
||||
# add first space again
|
||||
$string = " " . $string;
|
||||
|
||||
# lowercase AND and OR
|
||||
$string =~ s/(\s??OR\s??|\s??AND\s??)/\L$1\E/g;
|
||||
|
||||
# surround brackets with at least one space
|
||||
$string =~ s/(?<!\\)(\)|\()/ $1 /g;
|
||||
|
||||
# surround strings with slashes
|
||||
$string =~ s/(?<=\s)(\S+)/ $this->check_or($1, $case) /ge;
|
||||
|
||||
# remove slashes on <20>and<6E> and <20>or<6F>
|
||||
$string =~ s/\/(and|or)\/$case/$1/g;
|
||||
|
||||
# remove spaces inside /string/ constructs
|
||||
$string =~ s/(?<!and)(?<!or)\s*\//\//g;
|
||||
|
||||
$string =~ s/\/\s*(?!and|or)/\//g;
|
||||
|
||||
#my $res = qq(\$match = 1 if($string););
|
||||
return qq(\$match = 1 if($string););
|
||||
#print $res . "\n";
|
||||
#return $res;
|
||||
}
|
||||
|
||||
sub check_or {
|
||||
#
|
||||
# surrounds string with slashes if it is not
|
||||
# <20>and<6E> or <20>or<6F>
|
||||
#
|
||||
my($this, $str, $case) = @_;
|
||||
if ($str =~ /^\s*(or|and)\s*$/) {
|
||||
return " $str ";
|
||||
}
|
||||
elsif ($str =~ /(?<!\\)[)(]/) {
|
||||
return $str;
|
||||
}
|
||||
else {
|
||||
return " \/$str\/$case ";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub check_exact {
|
||||
#
|
||||
# helper for generate_search()
|
||||
# masks special chars if string
|
||||
# not inside ""
|
||||
#
|
||||
my($this, $str) = @_;
|
||||
|
||||
my %wildcards = (
|
||||
'*' => '.*',
|
||||
'?' => '.',
|
||||
'[' => '[',
|
||||
']' => ']',
|
||||
'+' => '\+',
|
||||
'.' => '\.',
|
||||
'$' => '\$',
|
||||
'@' => '\@',
|
||||
'/' => '\/',
|
||||
'|' => '\|',
|
||||
'}' => '\}',
|
||||
'{' => '\{',
|
||||
);
|
||||
|
||||
my %escapes = (
|
||||
'*' => '\*',
|
||||
'?' => '\?',
|
||||
'[' => '[',
|
||||
']' => ']',
|
||||
'+' => '\+',
|
||||
'.' => '\.',
|
||||
'$' => '\$',
|
||||
'@' => '\@',
|
||||
'(' => '\(',
|
||||
')' => '\)',
|
||||
'/' => '\/',
|
||||
'|' => '\|',
|
||||
'}' => '\}',
|
||||
'{' => '\{',
|
||||
);
|
||||
|
||||
# mask backslash
|
||||
$str =~ s/\\/\\\\/g;
|
||||
|
||||
|
||||
if ($str =~ /^"/ && $str =~ /"$/) {
|
||||
# mask bracket-constructs
|
||||
$str =~ s/(.)/$escapes{$1} || "$1"/ge;
|
||||
}
|
||||
else {
|
||||
$str =~ s/(.)/$wildcards{$1} || "$1"/ge;
|
||||
}
|
||||
|
||||
$str =~ s/^"//;
|
||||
$str =~ s/"$//;
|
||||
|
||||
# mask spaces
|
||||
$str =~ s/\s/\\s/g;
|
||||
return $str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sub lock {
|
||||
my ($this) = @_;
|
||||
|
||||
if (-e $this->{LOCKFILE}) {
|
||||
open LOCK, "<$this->{LOCKFILE}" or die "could not open $this->{LOCKFILE}: $!\n";
|
||||
my $data = <LOCK>;
|
||||
close LOCK;
|
||||
chomp $data;
|
||||
print "-- waiting for lock by $data --\n";
|
||||
print "-- remove the lockfile if you are sure: \"$this->{LOCKFILE}\" --\n";
|
||||
}
|
||||
|
||||
my $timeout = 60;
|
||||
|
||||
eval {
|
||||
local $SIG{ALRM} = sub { die "timeout" };
|
||||
local $SIG{INT} = sub { die "interrupted" };
|
||||
alarm $timeout - 2;
|
||||
while (1) {
|
||||
if (! -e $this->{LOCKFILE}) {
|
||||
umask 022;
|
||||
open LOCK, ">$this->{LOCKFILE}" or die "could not open $this->{LOCKFILE}: $!\n";
|
||||
flock LOCK, LOCK_EX;
|
||||
|
||||
my $now = scalar localtime();
|
||||
print LOCK "$ENV{USER} since $now (PID: $$)\n";
|
||||
|
||||
flock LOCK, LOCK_UN;
|
||||
close LOCK;
|
||||
alarm 0;
|
||||
return 0;
|
||||
}
|
||||
printf " %0d\r", $timeout;
|
||||
$timeout--;
|
||||
sleep 1;
|
||||
}
|
||||
};
|
||||
if($@) {
|
||||
if ($@ =~ /^inter/) {
|
||||
print " interrupted\n";
|
||||
}
|
||||
else {
|
||||
print $@;
|
||||
print " timeout\n";
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub unlock {
|
||||
my ($this) = @_;
|
||||
unlink $this->{LOCKFILE};
|
||||
}
|
||||
|
||||
|
||||
|
||||
1;
|
||||
@@ -1,7 +0,0 @@
|
||||
perl modules for note used as database backends.
|
||||
the install.sh script will install both of them,
|
||||
although you may only need one backend. Perhaps
|
||||
other users on your system have other ideas in mind...
|
||||
|
||||
Therefore, please ignore these file. There is nothing
|
||||
to edit or to do. Simply leave this directory :-)
|
||||
@@ -1,496 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
# $Id: binary.pm,v 1.3 2000/08/11 00:05:58 zarahg Exp $
|
||||
# Perl module for note
|
||||
# binary database backend. see docu: perldoc NOTEDB::binary
|
||||
#
|
||||
package NOTEDB::binary;
|
||||
|
||||
$NOTEDB::binary::VERSION = "1.13";
|
||||
|
||||
use strict;
|
||||
use IO::Seekable;
|
||||
use File::Spec;
|
||||
use FileHandle;
|
||||
use Fcntl qw(LOCK_EX LOCK_UN);
|
||||
|
||||
use NOTEDB;
|
||||
use Exporter ();
|
||||
use vars qw(@ISA @EXPORT);
|
||||
@ISA = qw(NOTEDB Exporter);
|
||||
|
||||
|
||||
|
||||
|
||||
sub new {
|
||||
my($this, %param) = @_;
|
||||
|
||||
my $class = ref($this) || $this;
|
||||
my $self = {};
|
||||
bless($self,$class);
|
||||
|
||||
$self->{NOTEDB} = $self->{dbname} = $param{dbname} || File::Spec->catfile($ENV{HOME}, ".notedb");
|
||||
my $MAX_NOTE = $param{MaxNoteByte} || 4096;
|
||||
my $MAX_TIME = $param{MaxTimeByte} || 64;
|
||||
|
||||
if(! -e $self->{NOTEDB}) {
|
||||
open(TT,">$self->{NOTEDB}") or die "Could not create $self->{NOTEDB}: $!\n";
|
||||
close (TT);
|
||||
}
|
||||
elsif(! -w $self->{NOTEDB}) {
|
||||
print "$self->{NOTEDB} is not writable!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
my $TYPEDEF = "i a$MAX_NOTE a$MAX_TIME";
|
||||
my $SIZEOF = length pack($TYPEDEF, () );
|
||||
|
||||
$self->{sizeof} = $SIZEOF;
|
||||
$self->{typedef} = $TYPEDEF;
|
||||
$self->{maxnote} = $MAX_NOTE;
|
||||
$self->{LOCKFILE} = $self->{NOTEDB} . "~LOCK";
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub DESTROY
|
||||
{
|
||||
# clean the desk!
|
||||
}
|
||||
|
||||
sub version {
|
||||
my $this = shift;
|
||||
return $NOTEDB::binary::VERSION;
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub set_del_all
|
||||
{
|
||||
my $this = shift;
|
||||
unlink $this->{NOTEDB};
|
||||
open(TT,">$this->{NOTEDB}") or die "Could not create $this->{NOTEDB}: $!\n";
|
||||
close (TT);
|
||||
}
|
||||
|
||||
|
||||
sub get_single {
|
||||
my($this, $num) = @_;
|
||||
my($address, $note, $date, $n, $t, $buffer, );
|
||||
|
||||
open NOTE, "+<$this->{NOTEDB}" or die "could not open $this->{NOTEDB}\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
|
||||
$address = ($num-1) * $this->{sizeof};
|
||||
seek(NOTE, $address, IO::Seekable::SEEK_SET);
|
||||
read(NOTE, $buffer, $this->{sizeof});
|
||||
($num, $n, $t) = unpack($this->{typedef}, $buffer);
|
||||
|
||||
$note = $this->ude($n);
|
||||
$date = $this->ude($t);
|
||||
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
return $note, $date;
|
||||
}
|
||||
|
||||
|
||||
sub get_all
|
||||
{
|
||||
my $this = shift;
|
||||
my($num, $note, $date, %res);
|
||||
|
||||
if ($this->unchanged) {
|
||||
return %{$this->{cache}};
|
||||
}
|
||||
open NOTE, "+<$this->{NOTEDB}" or die "could not open $this->{NOTEDB}\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
my($buffer, $t, $n);
|
||||
seek(NOTE, 0, 0); # START FROM BEGINNING
|
||||
while(read(NOTE, $buffer, $this->{sizeof})) {
|
||||
($num, $note, $date) = unpack($this->{typedef}, $buffer);
|
||||
$t = $this->ude($date);
|
||||
$n = $this->ude($note);
|
||||
$res{$num}->{'note'} = $n;
|
||||
$res{$num}->{'date'} = $t;
|
||||
}
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
$this->cache(%res);
|
||||
return %res;
|
||||
}
|
||||
|
||||
sub import_data {
|
||||
my ($this, $data) = @_;
|
||||
foreach my $num (sort keys %{$data}) {
|
||||
my $pos = $this->get_nextnum();
|
||||
$this->set_edit($pos, $data->{$num}->{note}, $data->{$num}->{date});
|
||||
}
|
||||
}
|
||||
|
||||
sub get_nextnum
|
||||
{
|
||||
my $this = shift;
|
||||
my($num, $te, $me, $buffer);
|
||||
|
||||
if ($this->unchanged) {
|
||||
$num = 1;
|
||||
foreach (keys %{$this->{cache}}) {
|
||||
$num++;
|
||||
}
|
||||
return $num;
|
||||
}
|
||||
open NOTE, "+<$this->{NOTEDB}" or die "could not open $this->{NOTEDB}\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
|
||||
seek(NOTE, 0, 0); # START FROM BEGINNING
|
||||
while(read(NOTE, $buffer, $this->{sizeof})) {
|
||||
($num, $te, $me) = unpack($this->{typedef}, $buffer);
|
||||
}
|
||||
$num += 1;
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
return $num;
|
||||
}
|
||||
|
||||
sub get_search
|
||||
{
|
||||
my($this, $searchstring) = @_;
|
||||
my($buffer, $num, $note, $date, %res, $t, $n, $match);
|
||||
|
||||
my $regex = $this->generate_search($searchstring);
|
||||
eval $regex;
|
||||
if ($@) {
|
||||
print "invalid expression: \"$searchstring\"!\n";
|
||||
return;
|
||||
}
|
||||
$match = 0;
|
||||
|
||||
if ($this->unchanged) {
|
||||
foreach my $num (keys %{$this->{cache}}) {
|
||||
$_ = $this->{cache}{$num}->{note};
|
||||
eval $regex;
|
||||
if ($match) {
|
||||
$res{$num}->{note} = $this->{cache}{$num}->{note};
|
||||
$res{$num}->{date} = $this->{cache}{$num}->{date}
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
return %res;
|
||||
}
|
||||
|
||||
open NOTE, "+<$this->{NOTEDB}" or die "could not open $this->{NOTEDB}\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
|
||||
seek(NOTE, 0, 0); # START FROM BEGINNING
|
||||
while(read(NOTE, $buffer, $this->{sizeof})) {
|
||||
($num, $note, $date) = unpack($this->{typedef}, $buffer);
|
||||
$n = $this->ude($note);
|
||||
$t = $this->ude($date);
|
||||
$_ = $n;
|
||||
eval $regex;
|
||||
if($match)
|
||||
{
|
||||
$res{$num}->{'note'} = $n;
|
||||
$res{$num}->{'date'} = $t;
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
return %res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sub set_edit {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
|
||||
$this->warn_if_too_big($note, $num);
|
||||
|
||||
my $address = ($num -1 ) * $this->{sizeof};
|
||||
|
||||
open NOTE, "+<$this->{NOTEDB}" or die "could not open $this->{NOTEDB}\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
|
||||
seek(NOTE, $address, IO::Seekable::SEEK_SET);
|
||||
my $n = $this->uen($note);
|
||||
my $t = $this->uen($date);
|
||||
|
||||
my $buffer = pack($this->{typedef}, $num, $n, $t);
|
||||
print NOTE $buffer;
|
||||
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
$this->changed;
|
||||
}
|
||||
|
||||
|
||||
sub set_new {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
|
||||
$this->warn_if_too_big($note, $num);
|
||||
|
||||
open NOTE, "+<$this->{NOTEDB}" or die "could not open $this->{NOTEDB}\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
|
||||
seek(NOTE, 0, IO::Seekable::SEEK_END); # APPEND
|
||||
my $n = $this->uen($note);
|
||||
my $t = $this->uen($date);
|
||||
my $buffer = pack($this->{typedef}, $num, $n, $t);
|
||||
print NOTE $buffer;
|
||||
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
$this->changed;
|
||||
}
|
||||
|
||||
|
||||
sub set_del
|
||||
{
|
||||
my($this, $num) = @_;
|
||||
my(%orig, $note, $date, $T, $setnum, $buffer, $n, $N, $t);
|
||||
|
||||
$setnum = 1;
|
||||
|
||||
%orig = $this->get_all();
|
||||
return "ERROR" if (! exists $orig{$num});
|
||||
|
||||
delete $orig{$num};
|
||||
|
||||
# overwrite, but keep number!
|
||||
open NOTE, ">$this->{NOTEDB}" or die "could not open $this->{NOTEDB}\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
seek(NOTE, 0, 0); # START FROM BEGINNING
|
||||
foreach $N (keys %orig) {
|
||||
$n = $this->uen($orig{$N}->{'note'});
|
||||
$t = $this->uen($orig{$N}->{'date'});
|
||||
$buffer = pack( $this->{typedef}, $N, $n, $t);
|
||||
# keep orig number, note have to call recount!
|
||||
print NOTE $buffer;
|
||||
seek(NOTE, 0, IO::Seekable::SEEK_END);
|
||||
$setnum++;
|
||||
}
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
$this->changed;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub set_recountnums
|
||||
{
|
||||
my($this) = @_;
|
||||
my(%orig, $note, $date, $T, $setnum, $buffer, $n, $N, $t);
|
||||
|
||||
$setnum = 1;
|
||||
%orig = $this->get_all();
|
||||
|
||||
open NOTE, ">$this->{NOTEDB}" or die "could not open $this->{NOTEDB}\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
seek(NOTE, 0, 0); # START FROM BEGINNING
|
||||
|
||||
foreach $N (sort {$a <=> $b} keys %orig) {
|
||||
$n = $this->uen($orig{$N}->{'note'});
|
||||
$t = $this->uen($orig{$N}->{'date'});
|
||||
$buffer = pack( $this->{typedef}, $setnum, $n, $t);
|
||||
print NOTE $buffer;
|
||||
seek(NOTE, 0, IO::Seekable::SEEK_END);
|
||||
$setnum++;
|
||||
}
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
$this->changed;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub uen
|
||||
{
|
||||
my $this = shift;
|
||||
my($T);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$T = pack("u", $this->{cipher}->encrypt($_[0]));
|
||||
};
|
||||
}
|
||||
else {
|
||||
$T = pack("u", $_[0]);
|
||||
}
|
||||
chomp $T;
|
||||
|
||||
return $T;
|
||||
}
|
||||
|
||||
sub ude
|
||||
{
|
||||
my $this = shift;
|
||||
my($T);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$T = $this->{cipher}->decrypt(unpack("u",$_[0]));
|
||||
};
|
||||
}
|
||||
else {
|
||||
$T = unpack("u", $_[0]);
|
||||
}
|
||||
return $T;
|
||||
}
|
||||
|
||||
|
||||
sub warn_if_too_big {
|
||||
my ($this, $note, $num) = @_;
|
||||
|
||||
my $len = length($this->uen($note));
|
||||
|
||||
if ($len > $this->{maxnote}) {
|
||||
# calculate the 30% uuencoding overhead
|
||||
my $overhead = int(($this->{maxnote} / 100) * 28);
|
||||
|
||||
# fetch what's left by driver
|
||||
my $left = substr $note, $this->{maxnote} - $overhead;
|
||||
|
||||
$left = "\n$left\n";
|
||||
$left =~ s/\n/\n> /gs;
|
||||
|
||||
print STDERR "*** WARNING $this->{version} WARNING ***\n"
|
||||
."The driver encountered a string length problem with your\n"
|
||||
."note entry number $num. The entry is too long. Either shorten\n"
|
||||
."the entry or resize the database field for entries.\n\n"
|
||||
."The following data has been cut off the entry:\n"
|
||||
."\n$left\n\n";
|
||||
|
||||
my $copy = File::Spec->catfile($ENV{'HOME'}, "entry-$num.txt");
|
||||
open N, ">$copy" or die "Could not open $copy: $!\n";
|
||||
print N $note;
|
||||
close N;
|
||||
|
||||
print "*** Wrote the complete note entry number $num to file: $copy ***\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub _retrieve {
|
||||
my ($this) = @_;
|
||||
my $file = $this->{dbname};
|
||||
if (-s $file) {
|
||||
if ($this->changed() || $this->{unread}) {
|
||||
open NOTE, "+<$this->{NOTEDB}" or die "could not open $this->{NOTEDB}\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
my($buffer, $t, $n, %res);
|
||||
seek(NOTE, 0, 0); # START FROM BEGINNING
|
||||
while(read(NOTE, $buffer, $this->{sizeof})) {
|
||||
my ($num, $note, $date) = unpack($this->{typedef}, $buffer);
|
||||
$t = $this->ude($date);
|
||||
$n = $this->ude($note);
|
||||
$res{$num}->{'note'} = $n;
|
||||
$res{$num}->{'date'} = $t;
|
||||
}
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
$this->cache(%res);
|
||||
return %res;
|
||||
}
|
||||
else {
|
||||
return %{$this->{data}};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
sub _store {
|
||||
# compatibility dummy
|
||||
return 1;
|
||||
}
|
||||
|
||||
1; # keep this!
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
NOTEDB::binary - module lib for accessing a notedb from perl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# include the module
|
||||
use NOTEDB;
|
||||
|
||||
# create a new NOTEDB object
|
||||
$db = new NOTEDB("binary", "/home/tom/.notedb", 4096, 24);
|
||||
|
||||
# decide to use encryption
|
||||
# $key is the cipher to use for encryption
|
||||
# $method must be either Crypt::IDEA or Crypt::DES
|
||||
# you need Crypt::CBC, Crypt::IDEA and Crypt::DES to have installed.
|
||||
$db->use_crypt($key,$method);
|
||||
|
||||
# do not use encryption
|
||||
# this is the default
|
||||
$db->no_crypt;
|
||||
|
||||
# get a single note
|
||||
($note, $date) = $db->get_single(1);
|
||||
|
||||
# search for a certain note
|
||||
%matching_notes = $db->get_search("somewhat");
|
||||
# format of returned hash:
|
||||
#$matching_notes{$numberofnote}->{'note' => 'something', 'date' => '23.12.2000 10:33:02'}
|
||||
|
||||
# get all existing notes
|
||||
%all_notes = $db->get_all();
|
||||
# format of returns hash like the one from get_search above
|
||||
|
||||
# get the next noteid available
|
||||
$next_num = $db->get_nextnum();
|
||||
|
||||
# modify a certain note
|
||||
$db->set_edit(1, "any text", "23.12.2000 10:33:02");
|
||||
|
||||
# create a new note
|
||||
$db->set_new(5, "any new text", "23.12.2000 10:33:02");
|
||||
|
||||
# delete a certain note
|
||||
$db->set_del(5);
|
||||
|
||||
# turn on encryption. CryptMethod must be IDEA, DES or BLOWFISH
|
||||
$db->use_crypt("passphrase", "CryptMethod");
|
||||
|
||||
# turn off encryption. This is the default.
|
||||
$db->no_crypt();
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
You can use this module for accessing a note database. There are currently
|
||||
two versions of this module, one version for a SQL database and one for a
|
||||
binary file (note's own database-format).
|
||||
However, both versions provides identical interfaces, which means, you do
|
||||
not need to change your code, if you want to switch to another database format.
|
||||
|
||||
Currently, NOTEDB module is only used by note itself. But feel free to use it
|
||||
within your own project! Perhaps someone want to implement a web interface to
|
||||
note...
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
please see the section SYNOPSIS, it says it all.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Thomas Linden <tom@daemon.de>.
|
||||
|
||||
|
||||
=cut
|
||||
@@ -1,269 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
# $Id: dbm.pm,v 1.3 2000/08/11 00:05:58 zarahg Exp $
|
||||
# Perl module for note
|
||||
# DBM database backend. see docu: perldoc NOTEDB::dbm
|
||||
#
|
||||
|
||||
package NOTEDB::dbm;
|
||||
|
||||
$NOTEDB::dbm::VERSION = "1.42";
|
||||
|
||||
use DB_File;
|
||||
use NOTEDB;
|
||||
use strict;
|
||||
use Exporter ();
|
||||
use vars qw(@ISA @EXPORT %note %date);
|
||||
@ISA = qw(NOTEDB Exporter);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sub new
|
||||
{
|
||||
my($this, %param) = @_;
|
||||
my $class = ref($this) || $this;
|
||||
my $self = {};
|
||||
bless($self,$class);
|
||||
|
||||
my $notefile = "note.dbm";
|
||||
my $timefile = "date.dbm";
|
||||
my $dbm_dir = $self->{dbname} = $param{dbname} || File::Spec->catfile($ENV{HOME}, ".notedb.dbm");
|
||||
|
||||
if (! -d $dbm_dir) {
|
||||
# try to make it
|
||||
mkdir $dbm_dir || die "Could not create $dbm_dir: $!\n";
|
||||
}
|
||||
|
||||
tie %note, "DB_File", "$dbm_dir/$notefile" || die "Could not tie $dbm_dir/$notefile: $!\n";
|
||||
tie %date, "DB_File", "$dbm_dir/$timefile" || die "Could not tie $dbm_dir/$timefile: $!\n";
|
||||
|
||||
$self->{LOCKFILE} = $param{dbname} . "~LOCK";
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub DESTROY
|
||||
{
|
||||
# clean the desk!
|
||||
untie %note, %date;
|
||||
}
|
||||
|
||||
sub version {
|
||||
my $this = shift;
|
||||
return $this->{version};
|
||||
}
|
||||
|
||||
|
||||
sub get_single
|
||||
{
|
||||
my($this, $num) = @_;
|
||||
my($note, $date);
|
||||
return $this->ude ($note{$num}), $this->ude($date{$num});
|
||||
}
|
||||
|
||||
|
||||
sub get_all
|
||||
{
|
||||
my $this = shift;
|
||||
my($num, $note, $date, %res, $real);
|
||||
foreach $num (sort {$a <=> $b} keys %date) {
|
||||
$res{$num}->{'note'} = $this->ude($note{$num});
|
||||
$res{$num}->{'date'} = $this->ude($date{$num});
|
||||
}
|
||||
return %res;
|
||||
}
|
||||
|
||||
sub import_data {
|
||||
my ($this, $data) = @_;
|
||||
foreach my $num (keys %{$data}) {
|
||||
my $pos = $this->get_nextnum();
|
||||
$note{$pos} = $this->ude($note{$num}->{note});
|
||||
$date{$pos} = $this->ude($date{$num}->{date});
|
||||
}
|
||||
}
|
||||
|
||||
sub get_nextnum
|
||||
{
|
||||
my($this, $num);
|
||||
foreach (sort {$a <=> $b} keys %date) {
|
||||
$num = $_;
|
||||
}
|
||||
$num++;
|
||||
return $num;
|
||||
}
|
||||
|
||||
sub get_search
|
||||
{
|
||||
my($this, $searchstring) = @_;
|
||||
my($num, $note, $date, %res, $match);
|
||||
|
||||
my $regex = $this->generate_search($searchstring);
|
||||
eval $regex;
|
||||
if ($@) {
|
||||
print "invalid expression: \"$searchstring\"!\n";
|
||||
return;
|
||||
}
|
||||
$match = 0;
|
||||
foreach $num (sort {$a <=> $b} keys %date) {
|
||||
$_ = $this->ude($note{$num});
|
||||
eval $regex;
|
||||
if ($match) {
|
||||
$res{$num}->{'note'} = $this->ude($note{$num});
|
||||
$res{$num}->{'date'} = $this->ude($date{$num});
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
|
||||
return %res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub set_recountnums
|
||||
{
|
||||
my $this = shift;
|
||||
my(%Note, %Date, $num, $setnum);
|
||||
$setnum = 1;
|
||||
foreach $num (sort {$a <=> $b} keys %note) {
|
||||
$Note{$setnum} = $note{$num};
|
||||
$Date{$setnum} = $date{$num};
|
||||
$setnum++;
|
||||
}
|
||||
%note = %Note;
|
||||
%date = %Date;
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub set_edit
|
||||
{
|
||||
my($this, $num, $note, $date) = @_;
|
||||
$note{$num} = $this->uen($note);
|
||||
$date{$num} = $this->uen($date);
|
||||
}
|
||||
|
||||
|
||||
sub set_new
|
||||
{
|
||||
my($this, $num, $note, $date) = @_;
|
||||
$this->set_edit($num, $note, $date); # just the same thing
|
||||
}
|
||||
|
||||
|
||||
sub set_del
|
||||
{
|
||||
my($this, $num) = @_;
|
||||
my($note, $date, $T);
|
||||
($note, $date) = $this->get_single($num);
|
||||
return "ERROR" if ($date !~ /^\d/);
|
||||
delete $note{$num};
|
||||
delete $date{$num};
|
||||
}
|
||||
|
||||
sub set_del_all
|
||||
{
|
||||
my($this) = @_;
|
||||
%note = ();
|
||||
%date = ();
|
||||
return;
|
||||
}
|
||||
|
||||
sub uen
|
||||
{
|
||||
my $this = shift;
|
||||
my($T);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$T = pack("u", $this->{cipher}->encrypt($_[0]));
|
||||
};
|
||||
}
|
||||
else {
|
||||
$T = $_[0];
|
||||
}
|
||||
chomp $T;
|
||||
return $T;
|
||||
}
|
||||
|
||||
sub ude
|
||||
{
|
||||
my $this = shift;
|
||||
my($T);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$T = $this->{cipher}->decrypt(unpack("u",$_[0]))
|
||||
};
|
||||
return $T;
|
||||
}
|
||||
else {
|
||||
return $_[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
1; # keep this!
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
NOTEDB::dbm - module lib for accessing a notedb from perl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# include the module
|
||||
use NOTEDB;
|
||||
|
||||
# create a new NOTEDB object (the last 4 params are db table/field names)
|
||||
$db = new NOTEDB("mysql","note","/home/user/.notedb/");
|
||||
|
||||
# get a single note
|
||||
($note, $date) = $db->get_single(1);
|
||||
|
||||
# search for a certain note
|
||||
%matching_notes = $db->get_search("somewhat");
|
||||
# format of returned hash:
|
||||
#$matching_notes{$numberofnote}->{'note' => 'something', 'date' => '23.12.2000 10:33:02'}
|
||||
|
||||
# get all existing notes
|
||||
%all_notes = $db->get_all();
|
||||
# format of returns hash like the one from get_search above
|
||||
|
||||
# get the next noteid available
|
||||
$next_num = $db->get_nextnum();
|
||||
|
||||
# recount all noteids starting by 1 (useful after deleting one!)
|
||||
$db->set_recountnums();
|
||||
|
||||
# modify a certain note
|
||||
$db->set_edit(1, "any text", "23.12.2000 10:33:02");
|
||||
|
||||
# create a new note
|
||||
$db->set_new(5, "any new text", "23.12.2000 10:33:02");
|
||||
|
||||
# delete a certain note
|
||||
$db->set_del(5);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
You can use this module for accessing a note database. This is the dbm module.
|
||||
It uses the DB_FILE module to store it's data and it uses DBM files for tis purpose.
|
||||
|
||||
Currently, NOTEDB module is only used by note itself. But feel free to use it
|
||||
within your own project! Perhaps someone want to implement a web interface to
|
||||
note...
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
please see the section SYNOPSIS, it says it all.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Thomas Linden <tom@daemon.de>.
|
||||
|
||||
|
||||
|
||||
=cut
|
||||
@@ -1,371 +0,0 @@
|
||||
# Perl module for note
|
||||
# text database backend. see docu: perldoc NOTEDB::text
|
||||
# using Storable as backend.
|
||||
|
||||
package NOTEDB::dumper;
|
||||
|
||||
$NOTEDB::dumper::VERSION = "1.03";
|
||||
|
||||
use strict;
|
||||
use Data::Dumper;
|
||||
use File::Spec;
|
||||
use MIME::Base64;
|
||||
|
||||
use NOTEDB;
|
||||
|
||||
use Fcntl qw(LOCK_EX LOCK_UN);
|
||||
|
||||
use Exporter ();
|
||||
use vars qw(@ISA @EXPORT);
|
||||
@ISA = qw(NOTEDB Exporter);
|
||||
|
||||
|
||||
|
||||
|
||||
sub new {
|
||||
my($this, %param) = @_;
|
||||
|
||||
my $class = ref($this) || $this;
|
||||
my $self = {};
|
||||
bless($self,$class);
|
||||
|
||||
$self->{NOTEDB} = $self->{dbname} = $param{dbname} || File::Spec->catfile($ENV{HOME}, ".notedb.dumper");
|
||||
|
||||
if(! -e $param{dbname}) {
|
||||
open(TT,">$param{dbname}") or die "Could not create $param{dbname}: $!\n";
|
||||
close (TT);
|
||||
}
|
||||
elsif(! -w $param{dbname}) {
|
||||
print "$param{dbname} is not writable!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$self->{LOCKFILE} = $param{dbname} . "~LOCK";
|
||||
$self->{mtime} = $self->get_stat();
|
||||
$self->{unread} = 1;
|
||||
$self->{data} = {};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub DESTROY
|
||||
{
|
||||
# clean the desk!
|
||||
}
|
||||
|
||||
sub version {
|
||||
my $this = shift;
|
||||
return $NOTEDB::text::VERSION;
|
||||
}
|
||||
|
||||
sub get_stat {
|
||||
my ($this) = @_;
|
||||
my $mtime = (stat($this->{dbname}))[9];
|
||||
return $mtime;
|
||||
}
|
||||
|
||||
|
||||
sub set_del_all {
|
||||
my $this = shift;
|
||||
unlink $this->{NOTEDB};
|
||||
open(TT,">$this->{NOTEDB}") or die "Could not create $this->{NOTEDB}: $!\n";
|
||||
close (TT);
|
||||
}
|
||||
|
||||
|
||||
sub get_single {
|
||||
my($this, $num) = @_;
|
||||
my($address, $note, $date, $n, $t, $buffer, );
|
||||
|
||||
my %data = $this->get_all();
|
||||
return ($data{$num}->{note}, $data{$num}->{date});
|
||||
}
|
||||
|
||||
|
||||
sub get_all {
|
||||
my $this = shift;
|
||||
my($num, $note, $date, %res);
|
||||
|
||||
if ($this->unchanged) {
|
||||
return %{$this->{cache}};
|
||||
}
|
||||
|
||||
my %data = $this->_retrieve();
|
||||
foreach my $num (keys %data) {
|
||||
$res{$num}->{note} = $this->ude($data{$num}->{note});
|
||||
$res{$num}->{date} = $this->ude($data{$num}->{date});
|
||||
}
|
||||
|
||||
$this->cache(%res);
|
||||
return %res;
|
||||
}
|
||||
|
||||
sub import_data {
|
||||
my ($this, $data) = @_;
|
||||
my %res = $this->_retrieve();
|
||||
my $pos = (scalar keys %res) + 1;
|
||||
foreach my $num (keys %{$data}) {
|
||||
$res{$pos}->{note} = $this->uen($data->{$num}->{note});
|
||||
$res{$pos}->{date} = $this->uen($data->{$num}->{date});
|
||||
$pos++;
|
||||
}
|
||||
$this->_store(\%res);
|
||||
}
|
||||
|
||||
sub get_nextnum {
|
||||
my $this = shift;
|
||||
my($num, $te, $me, $buffer);
|
||||
|
||||
if ($this->unchanged) {
|
||||
$num = 1;
|
||||
foreach (keys %{$this->{cache}}) {
|
||||
$num++;
|
||||
}
|
||||
return $num;
|
||||
}
|
||||
|
||||
my %data = $this->get_all();
|
||||
my $size = scalar keys %data;
|
||||
$num = $size + 1;
|
||||
return $num;
|
||||
}
|
||||
|
||||
sub get_search {
|
||||
my($this, $searchstring) = @_;
|
||||
my($buffer, $num, $note, $date, %res, $t, $n, $match);
|
||||
|
||||
my $regex = $this->generate_search($searchstring);
|
||||
eval $regex;
|
||||
if ($@) {
|
||||
print "invalid expression: \"$searchstring\"!\n";
|
||||
return;
|
||||
}
|
||||
$match = 0;
|
||||
|
||||
if ($this->unchanged) {
|
||||
foreach my $num (keys %{$this->{cache}}) {
|
||||
$_ = $this->{cache}{$num}->{note};
|
||||
eval $regex;
|
||||
if ($match) {
|
||||
$res{$num}->{note} = $this->{cache}{$num}->{note};
|
||||
$res{$num}->{date} = $this->{cache}{$num}->{date}
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
return %res;
|
||||
}
|
||||
|
||||
my %data = $this->get_all();
|
||||
|
||||
foreach my $num(sort keys %data) {
|
||||
$_ = $data{$num}->{note};
|
||||
eval $regex;
|
||||
if($match)
|
||||
{
|
||||
$res{$num}->{note} = $data{$num}->{note};
|
||||
$res{$num}->{date} = $data{$num}->{data};
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
|
||||
return %res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sub set_edit {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
|
||||
my %data = $this->_retrieve();
|
||||
|
||||
$data{$num} = {
|
||||
note => $this->uen($note),
|
||||
date => $this->uen($date)
|
||||
};
|
||||
|
||||
$this->_store(\%data);
|
||||
|
||||
$this->changed;
|
||||
}
|
||||
|
||||
|
||||
sub set_new {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
$this->set_edit($num, $note, $date);
|
||||
}
|
||||
|
||||
|
||||
sub set_del {
|
||||
my($this, $num) = @_;
|
||||
my(%data, $note, $date, $T, $setnum, $buffer, $n, $N, $t);
|
||||
|
||||
$setnum = 1;
|
||||
|
||||
%data = $this->_retrieve();
|
||||
return "ERROR" if (! exists $data{$num});
|
||||
|
||||
delete $data{$num};
|
||||
|
||||
$this->_store(\%data);
|
||||
|
||||
$this->changed;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub set_recountnums {
|
||||
my($this) = @_;
|
||||
my(%orig, %data, $note, $date, $T, $setnum, $buffer, $n, $N, $t);
|
||||
|
||||
$setnum = 1;
|
||||
%orig = $this->_retrieve();
|
||||
|
||||
foreach $N (sort {$a <=> $b} keys %orig) {
|
||||
$data{$setnum} = {
|
||||
note => $orig{$N}->{note},
|
||||
date => $orig{$N}->{date}
|
||||
};
|
||||
$setnum++;
|
||||
}
|
||||
|
||||
$this->_store(\%data);
|
||||
|
||||
$this->changed;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub uen {
|
||||
my ($this, $raw) = @_;
|
||||
my($crypted);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$crypted = $this->{cipher}->encrypt($raw);
|
||||
return encode_base64($crypted);
|
||||
};
|
||||
}
|
||||
else {
|
||||
return $raw;
|
||||
}
|
||||
}
|
||||
|
||||
sub ude {
|
||||
my ($this, $crypted) = @_;
|
||||
my($raw);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$raw = $this->{cipher}->decrypt(decode_base64($crypted));
|
||||
};
|
||||
return $raw;
|
||||
}
|
||||
else {
|
||||
return $crypted;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub _store {
|
||||
my ($this, $data) = @_;
|
||||
open N, ">$this->{NOTEDB}" or die "Could not open db: $!\n";
|
||||
print N Data::Dumper->Dump([$data], [qw(*data)]);
|
||||
close N;
|
||||
}
|
||||
|
||||
sub _retrieve {
|
||||
my $this = shift;
|
||||
if (-s $this->{NOTEDB}) {
|
||||
if ($this->changed() || $this->{unread}) {
|
||||
open N, "<$this->{NOTEDB}" or die "Could not open db: $!\n";
|
||||
my $content = join "", <N>;
|
||||
close N;
|
||||
my %data;
|
||||
eval $content; # creates %data
|
||||
$this->{unread} = 0;
|
||||
$this->{data} = \%data;
|
||||
return %data;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1; # keep this!
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
NOTEDB::text - module lib for accessing a notedb from perl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# include the module
|
||||
use NOTEDB;
|
||||
|
||||
# create a new NOTEDB object
|
||||
$db = new NOTEDB("text", "/home/tom/.notedb", 4096, 24);
|
||||
|
||||
# decide to use encryption
|
||||
# $key is the cipher to use for encryption
|
||||
# $method must be either Crypt::IDEA or Crypt::DES
|
||||
# you need Crypt::CBC, Crypt::IDEA and Crypt::DES to have installed.
|
||||
$db->use_crypt($key,$method);
|
||||
|
||||
# do not use encryption
|
||||
# this is the default
|
||||
$db->no_crypt;
|
||||
|
||||
# get a single note
|
||||
($note, $date) = $db->get_single(1);
|
||||
|
||||
# search for a certain note
|
||||
%matching_notes = $db->get_search("somewhat");
|
||||
# format of returned hash:
|
||||
#$matching_notes{$numberofnote}->{'note' => 'something', 'date' => '23.12.2000 10:33:02'}
|
||||
|
||||
# get all existing notes
|
||||
%all_notes = $db->get_all();
|
||||
# format of returns hash like the one from get_search above
|
||||
|
||||
# get the next noteid available
|
||||
$next_num = $db->get_nextnum();
|
||||
|
||||
# modify a certain note
|
||||
$db->set_edit(1, "any text", "23.12.2000 10:33:02");
|
||||
|
||||
# create a new note
|
||||
$db->set_new(5, "any new text", "23.12.2000 10:33:02");
|
||||
|
||||
# delete a certain note
|
||||
$db->set_del(5);
|
||||
|
||||
# turn on encryption. CryptMethod must be IDEA, DES or BLOWFISH
|
||||
$db->use_crypt("passphrase", "CryptMethod");
|
||||
|
||||
# turn off encryption. This is the default.
|
||||
$db->no_crypt();
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
You can use this module for accessing a note database. This backend uses
|
||||
a text file for storage and Storable for accessing the file.
|
||||
|
||||
Currently, NOTEDB module is only used by note itself. But feel free to use it
|
||||
within your own project! Perhaps someone want to implement a web interface to
|
||||
note...
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
please see the section SYNOPSIS, it says it all.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Thomas Linden <tom@daemon.de>.
|
||||
|
||||
|
||||
=cut
|
||||
@@ -1,412 +0,0 @@
|
||||
# Perl module for note
|
||||
# general database backend. see docu: perldoc NOTEDB::general
|
||||
# using Config::General as backend.
|
||||
|
||||
package NOTEDB::general;
|
||||
|
||||
$NOTEDB::general::VERSION = "1.05";
|
||||
|
||||
use strict;
|
||||
#use Data::Dumper;
|
||||
use File::Spec;
|
||||
use Config::General qw(ParseConfig SaveConfig SaveConfigString);
|
||||
use MIME::Base64;
|
||||
use FileHandle;
|
||||
use NOTEDB;
|
||||
|
||||
use Fcntl qw(LOCK_EX LOCK_UN);
|
||||
|
||||
use Exporter ();
|
||||
use vars qw(@ISA @EXPORT);
|
||||
@ISA = qw(NOTEDB Exporter);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sub new {
|
||||
my($this, %param) = @_;
|
||||
|
||||
my $class = ref($this) || $this;
|
||||
my $self = {};
|
||||
bless($self,$class);
|
||||
|
||||
$self->{dbname} = $param{dbname} || File::Spec->catfile($ENV{HOME}, ".notedb.txt");
|
||||
|
||||
if(! -e $param{dbname}) {
|
||||
open(TT,">$param{dbname}") or die "Could not create $param{dbname}: $!\n";
|
||||
close (TT);
|
||||
}
|
||||
elsif(! -w $param{dbname}) {
|
||||
print "$param{dbname} is not writable!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$self->{mtime} = $self->get_stat();
|
||||
$self->{unread} = 1;
|
||||
$self->{changed} = 1;
|
||||
$self->{data} = {};
|
||||
$self->{LOCKFILE} = $param{dbname} . "~LOCK";
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub DESTROY {
|
||||
# clean the desk!
|
||||
}
|
||||
|
||||
sub version {
|
||||
my $this = shift;
|
||||
return $NOTEDB::general::VERSION;
|
||||
}
|
||||
|
||||
sub get_stat {
|
||||
my ($this) = @_;
|
||||
my $mtime = (stat($this->{dbname}))[9];
|
||||
return $mtime;
|
||||
}
|
||||
|
||||
sub changed {
|
||||
my ($this) = @_;
|
||||
my $current = $this->get_stat();
|
||||
if ($current > $this->{mtime}) {
|
||||
$this->{mtime} = $current;
|
||||
return $current;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub set_del_all {
|
||||
my $this = shift;
|
||||
unlink $this->{dbname};
|
||||
open(TT,">$this->{dbname}") or die "Could not create $this->{dbname}: $!\n";
|
||||
close (TT);
|
||||
}
|
||||
|
||||
|
||||
sub get_single {
|
||||
my($this, $num) = @_;
|
||||
my($address, $note, $date, $n, $t, $buffer, );
|
||||
|
||||
my %data = $this->get_all();
|
||||
|
||||
return ($data{$num}->{note}, $data{$num}->{date});
|
||||
}
|
||||
|
||||
|
||||
sub get_all {
|
||||
my $this = shift;
|
||||
my($num, $note, $date, %res);
|
||||
|
||||
if ($this->unchanged) {
|
||||
return %{$this->{cache}};
|
||||
}
|
||||
|
||||
my %data = $this->_retrieve();
|
||||
|
||||
foreach my $num (keys %data) {
|
||||
$res{$num}->{note} = $this->ude($data{$num}->{note});
|
||||
$res{$num}->{date} = $this->ude($data{$num}->{date});
|
||||
}
|
||||
|
||||
$this->cache(%res);
|
||||
return %res;
|
||||
}
|
||||
|
||||
sub import_data {
|
||||
my ($this, $data) = @_;
|
||||
my %res = $this->_retrieve();
|
||||
my $pos = (scalar keys %res) + 1;
|
||||
foreach my $num (keys %{$data}) {
|
||||
$res{$pos}->{note} = $this->uen($data->{$num}->{note});
|
||||
$res{$pos}->{date} = $this->uen($data->{$num}->{date});
|
||||
$pos++;
|
||||
}
|
||||
$this->_store(\%res);
|
||||
}
|
||||
|
||||
sub get_nextnum {
|
||||
my $this = shift;
|
||||
my($num, $te, $me, $buffer);
|
||||
|
||||
if ($this->unchanged) {
|
||||
$num = 1;
|
||||
foreach (keys %{$this->{cache}}) {
|
||||
$num++;
|
||||
}
|
||||
return $num;
|
||||
}
|
||||
|
||||
my %data = $this->get_all();
|
||||
my @numbers = sort { $a <=> $b } keys %data;
|
||||
$num = pop @numbers;
|
||||
$num++;
|
||||
|
||||
return $num;
|
||||
}
|
||||
|
||||
sub get_search {
|
||||
my($this, $searchstring) = @_;
|
||||
my($buffer, $num, $note, $date, %res, $t, $n, $match);
|
||||
|
||||
my $regex = $this->generate_search($searchstring);
|
||||
eval $regex;
|
||||
if ($@) {
|
||||
print "invalid expression: \"$searchstring\"!\n";
|
||||
return;
|
||||
}
|
||||
$match = 0;
|
||||
|
||||
if ($this->unchanged) {
|
||||
foreach my $num (keys %{$this->{cache}}) {
|
||||
$_ = $this->{cache}{$num}->{note};
|
||||
eval $regex;
|
||||
if ($match) {
|
||||
$res{$num}->{note} = $this->{cache}{$num}->{note};
|
||||
$res{$num}->{date} = $this->{cache}{$num}->{date}
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
return %res;
|
||||
}
|
||||
|
||||
my %data = $this->get_all();
|
||||
|
||||
foreach my $num(sort keys %data) {
|
||||
$_ = $data{$num}->{note};
|
||||
eval $regex;
|
||||
if($match)
|
||||
{
|
||||
$res{$num}->{note} = $data{$num}->{note};
|
||||
$res{$num}->{date} = $data{$num}->{data};
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
|
||||
return %res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sub set_edit {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
|
||||
my %data = $this->_retrieve();
|
||||
|
||||
$data{$num} = {
|
||||
note => $this->uen($note),
|
||||
date => $this->uen($date)
|
||||
};
|
||||
|
||||
$this->_store(\%data);
|
||||
|
||||
$this->changed;
|
||||
}
|
||||
|
||||
|
||||
sub set_new {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
$this->set_edit($num, $note, $date);
|
||||
}
|
||||
|
||||
|
||||
sub set_del {
|
||||
my($this, $num) = @_;
|
||||
my(%data, $note, $date, $T, $setnum, $buffer, $n, $N, $t);
|
||||
|
||||
$setnum = 1;
|
||||
|
||||
%data = $this->_retrieve();
|
||||
return "ERROR" if (! exists $data{$num});
|
||||
|
||||
delete $data{$num};
|
||||
|
||||
$this->_store(\%data);
|
||||
|
||||
$this->changed;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub set_recountnums {
|
||||
my($this) = @_;
|
||||
my(%orig, %data, $note, $date, $T, $setnum, $buffer, $n, $N, $t);
|
||||
|
||||
$setnum = 1;
|
||||
%orig = $this->_retrieve();
|
||||
|
||||
foreach $N (sort {$a <=> $b} keys %orig) {
|
||||
$data{$setnum} = {
|
||||
note => $orig{$N}->{note},
|
||||
date => $orig{$N}->{date}
|
||||
};
|
||||
$setnum++;
|
||||
}
|
||||
|
||||
$this->_store(\%data);
|
||||
|
||||
$this->changed;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub uen {
|
||||
my ($this, $raw) = @_;
|
||||
my($crypted);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$crypted = $this->{cipher}->encrypt($raw);
|
||||
};
|
||||
print $@;
|
||||
}
|
||||
else {
|
||||
$crypted = $raw;
|
||||
}
|
||||
my $coded = encode_base64($crypted);
|
||||
chomp $coded;
|
||||
return $coded;
|
||||
}
|
||||
|
||||
sub ude {
|
||||
my ($this, $crypted) = @_;
|
||||
my($raw);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$raw = $this->{cipher}->decrypt(decode_base64($crypted));
|
||||
};
|
||||
}
|
||||
else {
|
||||
$raw = decode_base64($crypted)
|
||||
}
|
||||
return $raw;
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub _store {
|
||||
my ($this, $data) = @_;
|
||||
open NOTE, ">$this->{dbname}" or die "could not open $this->{dbname}: $!\n";
|
||||
flock NOTE, LOCK_EX;
|
||||
|
||||
if (%{$data}) {
|
||||
my $content = SaveConfigString($data) or die "could not serialize data: $!\n";
|
||||
print NOTE $content;
|
||||
}
|
||||
else {
|
||||
print NOTE "";
|
||||
}
|
||||
|
||||
flock NOTE, LOCK_UN;
|
||||
close NOTE;
|
||||
|
||||
# finally re-read the db, so that we always have the latest data
|
||||
$this->_retrieve();
|
||||
}
|
||||
|
||||
sub _retrieve {
|
||||
my ($this) = @_;
|
||||
my $file = $this->{dbname};
|
||||
if (-s $file) {
|
||||
if ($this->{changed} || $this->{unread}) {
|
||||
my $fh = new FileHandle "<$this->{dbname}" or die "could not open $this->{dbname}\n";
|
||||
flock $fh, LOCK_EX;
|
||||
|
||||
my %data = ParseConfig(-ConfigFile => $fh) or die "could not read to database: $!\n";
|
||||
|
||||
flock $fh, LOCK_UN;
|
||||
$fh->close();
|
||||
|
||||
$this->{unread} = 0;
|
||||
$this->{data} = \%data;
|
||||
return %data;
|
||||
}
|
||||
else {
|
||||
return %{$this->{data}};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1; # keep this!
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
NOTEDB::general - module lib for accessing a notedb from perl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# include the module
|
||||
use NOTEDB;
|
||||
|
||||
# create a new NOTEDB object
|
||||
$db = new NOTEDB("text", "/home/tom/.notedb", 4096, 24);
|
||||
|
||||
# decide to use encryption
|
||||
# $key is the cipher to use for encryption
|
||||
# $method must be either Crypt::IDEA or Crypt::DES
|
||||
# you need Crypt::CBC, Crypt::IDEA and Crypt::DES to have installed.
|
||||
$db->use_crypt($key,$method);
|
||||
|
||||
# do not use encryption
|
||||
# this is the default
|
||||
$db->no_crypt;
|
||||
|
||||
# get a single note
|
||||
($note, $date) = $db->get_single(1);
|
||||
|
||||
# search for a certain note
|
||||
%matching_notes = $db->get_search("somewhat");
|
||||
# format of returned hash:
|
||||
#$matching_notes{$numberofnote}->{'note' => 'something', 'date' => '23.12.2000 10:33:02'}
|
||||
|
||||
# get all existing notes
|
||||
%all_notes = $db->get_all();
|
||||
# format of returns hash like the one from get_search above
|
||||
|
||||
# get the next noteid available
|
||||
$next_num = $db->get_nextnum();
|
||||
|
||||
# modify a certain note
|
||||
$db->set_edit(1, "any text", "23.12.2000 10:33:02");
|
||||
|
||||
# create a new note
|
||||
$db->set_new(5, "any new text", "23.12.2000 10:33:02");
|
||||
|
||||
# delete a certain note
|
||||
$db->set_del(5);
|
||||
|
||||
# turn on encryption. CryptMethod must be IDEA, DES or BLOWFISH
|
||||
$db->use_crypt("passphrase", "CryptMethod");
|
||||
|
||||
# turn off encryption. This is the default.
|
||||
$db->no_crypt();
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
You can use this module for accessing a note database. This backend uses
|
||||
a text file for storage and Config::General for accessing the file.
|
||||
|
||||
Currently, NOTEDB module is only used by note itself. But feel free to use it
|
||||
within your own project! Perhaps someone want to implement a web interface to
|
||||
note...
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
please see the section SYNOPSIS, it says it all.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Thomas Linden <tom@daemon.de>.
|
||||
|
||||
|
||||
=cut
|
||||
@@ -1,425 +0,0 @@
|
||||
#
|
||||
# Perl module for note
|
||||
# mysql database backend. see docu: perldoc NOTEDB::mysql
|
||||
#
|
||||
|
||||
|
||||
package NOTEDB::mysql;
|
||||
|
||||
$NOTEDB::mysql::VERSION = "1.51";
|
||||
|
||||
use DBI;
|
||||
use strict;
|
||||
#use Data::Dumper;
|
||||
use NOTEDB;
|
||||
|
||||
use Exporter ();
|
||||
use vars qw(@ISA @EXPORT);
|
||||
@ISA = qw(NOTEDB Exporter);
|
||||
|
||||
|
||||
|
||||
|
||||
sub new {
|
||||
my($this, %param) = @_;
|
||||
|
||||
my $class = ref($this) || $this;
|
||||
my $self = {};
|
||||
bless($self,$class);
|
||||
|
||||
my $dbname = $param{dbname} || "note";
|
||||
my $dbhost = $param{dbhost} || "localhost";
|
||||
my $dbuser = $param{dbuser} || "";
|
||||
my $dbpasswd = $param{dbpasswd} || "";
|
||||
my $dbport = $param{dbport} || "";
|
||||
my $fnum = "number";
|
||||
my $fnote = "note";
|
||||
my $fdate = "date";
|
||||
my $ftopic = "topic";
|
||||
|
||||
my $database;
|
||||
if ($dbport) {
|
||||
$database = "DBI:mysql:$dbname;host=$dbhost:$dbport";
|
||||
}
|
||||
else {
|
||||
$database = "DBI:mysql:$dbname;host=$dbhost";
|
||||
}
|
||||
|
||||
$self->{table} = "note";
|
||||
|
||||
$self->{sql_getsingle} = "SELECT $fnote,$fdate,$ftopic FROM $self->{table} WHERE $fnum = ?";
|
||||
$self->{sql_all} = "SELECT $fnum,$fnote,$fdate,$ftopic FROM $self->{table}";
|
||||
$self->{sql_nextnum} = "SELECT max($fnum) FROM $self->{table}";
|
||||
$self->{sql_incrnum} = "SELECT $fnum FROM $self->{table} ORDER BY $fnum";
|
||||
$self->{sql_setnum} = "UPDATE $self->{table} SET $fnum = ? WHERE $fnum = ?";
|
||||
$self->{sql_edit} = "UPDATE $self->{table} SET $fnote = ?, $fdate = ?, $ftopic = ? WHERE $fnum = ?";
|
||||
$self->{sql_insertnew} = "INSERT INTO $self->{table} VALUES (?, ?, ?, ?)";
|
||||
$self->{sql_del} = "DELETE FROM $self->{table} WHERE $fnum = ?";
|
||||
$self->{sql_del_all} = "DELETE FROM $self->{table}";
|
||||
|
||||
$self->{DB} = DBI->connect($database, $dbuser, $dbpasswd) or die DBI->errstr();
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub DESTROY
|
||||
{
|
||||
# clean the desk!
|
||||
my $this = shift;
|
||||
$this->{DB}->disconnect;
|
||||
}
|
||||
|
||||
|
||||
sub lock {
|
||||
my($this) = @_;
|
||||
# LOCK the database!
|
||||
my $lock = $this->{DB}->prepare("LOCK TABLES $this->{table} WRITE")
|
||||
|| die $this->{DB}->errstr();
|
||||
$lock->execute() || die $this->{DB}->errstr();
|
||||
}
|
||||
|
||||
|
||||
sub unlock {
|
||||
my($this) = @_;
|
||||
my $unlock = $this->{DB}->prepare("UNLOCK TABLES") || die $this->{DB}->errstr;
|
||||
$unlock->execute() || die $this->{DB}->errstr();
|
||||
}
|
||||
|
||||
|
||||
sub version {
|
||||
my $this = shift;
|
||||
return $this->{version};
|
||||
}
|
||||
|
||||
|
||||
sub get_single {
|
||||
my($this, $num) = @_;
|
||||
|
||||
my($note, $date, $topic);
|
||||
my $statement = $this->{DB}->prepare($this->{sql_getsingle}) || die $this->{DB}->errstr();
|
||||
|
||||
$statement->execute($num) || die $this->{DB}->errstr();
|
||||
$statement->bind_columns(undef, \($note, $date, $topic)) || die $this->{DB}->errstr();
|
||||
|
||||
while($statement->fetch) {
|
||||
$note = $this->ude($note);
|
||||
if ($topic) {
|
||||
$note = "$topic\n" . $note;
|
||||
}
|
||||
return $note, $this->ude($date);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub get_all
|
||||
{
|
||||
my $this = shift;
|
||||
my($num, $note, $date, %res, $topic);
|
||||
|
||||
if ($this->unchanged) {
|
||||
return %{$this->{cache}};
|
||||
}
|
||||
|
||||
my $statement = $this->{DB}->prepare($this->{sql_all}) or die $this->{DB}->errstr();
|
||||
|
||||
$statement->execute or die $this->{DB}->errstr();
|
||||
$statement->bind_columns(undef, \($num, $note, $date, $topic)) or die $this->{DB}->errstr();
|
||||
|
||||
while($statement->fetch) {
|
||||
$res{$num}->{'note'} = $this->ude($note);
|
||||
$res{$num}->{'date'} = $this->ude($date);
|
||||
if ($topic) {
|
||||
$res{$num}->{'note'} = "$topic\n" . $res{$num}->{'note'};
|
||||
}
|
||||
}
|
||||
|
||||
$this->cache(%res);
|
||||
return %res;
|
||||
}
|
||||
|
||||
|
||||
sub get_nextnum
|
||||
{
|
||||
my $this = shift;
|
||||
my($num);
|
||||
if ($this->unchanged) {
|
||||
$num = 1;
|
||||
foreach (keys %{$this->{cache}}) {
|
||||
$num++;
|
||||
}
|
||||
return $num;
|
||||
}
|
||||
|
||||
my $statement = $this->{DB}->prepare($this->{sql_nextnum}) || die $this->{DB}->errstr();
|
||||
|
||||
$statement->execute || die $this->{DB}->errstr();
|
||||
$statement->bind_columns(undef, \($num)) || die $this->{DB}->errstr();
|
||||
|
||||
while($statement->fetch) {
|
||||
return $num+1;
|
||||
}
|
||||
}
|
||||
|
||||
sub get_search
|
||||
{
|
||||
my($this, $searchstring) = @_;
|
||||
my($num, $note, $date, %res, $match, $use_cache, $topic);
|
||||
|
||||
my $regex = $this->generate_search($searchstring);
|
||||
eval $regex;
|
||||
if ($@) {
|
||||
print "invalid expression: \"$searchstring\"!\n";
|
||||
return;
|
||||
}
|
||||
$match = 0;
|
||||
|
||||
if ($this->unchanged) {
|
||||
foreach my $num (keys %{$this->{cache}}) {
|
||||
$_ = $this->{cache}{$num}->{note};
|
||||
eval $regex;
|
||||
if ($match) {
|
||||
$res{$num}->{note} = $this->{cache}{$num}->{note};
|
||||
$res{$num}->{date} = $this->{cache}{$num}->{date}
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
return %res;
|
||||
}
|
||||
|
||||
my $statement = $this->{DB}->prepare($this->{sql_all}) or die $this->{DB}->errstr();
|
||||
|
||||
$statement->execute or die $this->{DB}->errstr();
|
||||
$statement->bind_columns(undef, \($num, $note, $date, $topic)) or die $this->{DB}->errstr();
|
||||
|
||||
while($statement->fetch) {
|
||||
$note = $this->ude($note);
|
||||
$date = $this->ude($date);
|
||||
if ($topic) {
|
||||
$note = "$topic\n" . $note;
|
||||
}
|
||||
$_ = $note;
|
||||
eval $regex;
|
||||
if($match) {
|
||||
$res{$num}->{'note'} = $note;
|
||||
$res{$num}->{'date'} = $date;
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
return %res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sub set_edit
|
||||
{
|
||||
my($this, $num, $note, $date) = @_;
|
||||
|
||||
$this->lock;
|
||||
my $statement = $this->{DB}->prepare($this->{sql_edit}) or die $this->{DB}->errstr();
|
||||
$note =~ s/'/\'/g;
|
||||
$note =~ s/\\/\\\\/g;
|
||||
$statement->execute($this->uen($note), $this->uen($date), $num)
|
||||
or die $this->{DB}->errstr();
|
||||
$this->unlock;
|
||||
$this->changed;
|
||||
}
|
||||
|
||||
|
||||
sub set_new
|
||||
{
|
||||
my($this, $num, $note, $date) = @_;
|
||||
$this->lock;
|
||||
my $statement = $this->{DB}->prepare($this->{sql_insertnew}) || die $this->{DB}->errstr();
|
||||
|
||||
my ($topic, $note) = $this->get_topic($note);
|
||||
|
||||
$note =~ s/'/\'/g;
|
||||
$note =~ s/\\/\\\\/g;
|
||||
$topic =~ s/\\/\\\\/g;
|
||||
$statement->execute($num, $this->uen($note), $this->uen($date), $topic) || die $this->{DB}->errstr();
|
||||
$this->unlock;
|
||||
$this->changed;
|
||||
}
|
||||
|
||||
|
||||
sub set_del
|
||||
{
|
||||
my($this, $num) = @_;
|
||||
my($note, $date, $T);
|
||||
|
||||
$this->lock;
|
||||
($note, $date) = $this->get_single($num);
|
||||
|
||||
return "ERROR" if ($date !~ /^\d/);
|
||||
|
||||
# delete record!
|
||||
my $statement = $this->{DB}->prepare($this->{sql_del}) || die $this->{DB}->errstr();
|
||||
$statement->execute($num) || die $this->{DB}->errstr();
|
||||
$this->unlock;
|
||||
$this->changed;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
sub set_del_all
|
||||
{
|
||||
my($this) = @_;
|
||||
$this->lock;
|
||||
my $statement = $this->{DB}->prepare($this->{sql_del_all}) || die $this->{DB}->errstr();
|
||||
$statement->execute() || die $this->{DB}->errstr();
|
||||
$this->unlock;
|
||||
$this->changed;
|
||||
return;
|
||||
}
|
||||
|
||||
sub set_recountnums {
|
||||
my $this = shift;
|
||||
|
||||
$this->lock;
|
||||
|
||||
my(@count, $i, $num, $setnum, $pos);
|
||||
$setnum = 1;
|
||||
$pos=0; $i=0; @count = ();
|
||||
|
||||
my $statement = $this->{DB}->prepare($this->{sql_incrnum}) || die $this->{DB}->errstr();
|
||||
$statement->execute || die $this->{DB}->errstr();
|
||||
$statement->bind_columns(undef, \($num)) || die $this->{DB}->errstr();
|
||||
# store real id's in an array!
|
||||
while($statement->fetch) {
|
||||
$count[$i] = $num;
|
||||
$i++;
|
||||
}
|
||||
# now recount them!
|
||||
my $sub_statement = $this->{DB}->prepare($this->{sql_setnum}) || die $this->{DB}->errstr();
|
||||
for($pos=0;$pos<$i;$pos++) {
|
||||
$setnum = $pos +1;
|
||||
$sub_statement->execute($setnum,$count[$pos]) || die $this->{DB}->errstr();
|
||||
}
|
||||
$this->unlock;
|
||||
$this->changed;
|
||||
}
|
||||
|
||||
sub import_data {
|
||||
my ($this, $data) = @_;
|
||||
foreach my $num (keys %{$data}) {
|
||||
my $pos = $this->get_nextnum();
|
||||
$this->set_new($pos, $data->{$num}->{note}, $data->{$num}->{date});
|
||||
}
|
||||
}
|
||||
|
||||
sub uen
|
||||
{
|
||||
my $this = shift;
|
||||
my($T);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$T = pack("u", $this->{cipher}->encrypt($_[0]));
|
||||
};
|
||||
}
|
||||
else {
|
||||
$T = $_[0];
|
||||
}
|
||||
chomp $T;
|
||||
return $T;
|
||||
}
|
||||
|
||||
sub ude
|
||||
{
|
||||
my $this = shift;
|
||||
my($T);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$T = $this->{cipher}->decrypt(unpack("u",$_[0]))
|
||||
};
|
||||
return $T;
|
||||
}
|
||||
else {
|
||||
return $_[0];
|
||||
}
|
||||
}
|
||||
|
||||
sub get_topic {
|
||||
my ($this, $data) = @_;
|
||||
if ($data =~ /^\//) {
|
||||
my($topic, $note) = split /\n/, $data, 2;
|
||||
return ($topic, $note);
|
||||
}
|
||||
else {
|
||||
return ("", $data);
|
||||
}
|
||||
}
|
||||
|
||||
1; # keep this!
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
NOTEDB::mysql - module lib for accessing a notedb from perl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# include the module
|
||||
use NOTEDB;
|
||||
|
||||
# create a new NOTEDB object (the last 4 params are db table/field names)
|
||||
$db = new NOTEDB("mysql","note","localhost","username","password","note","number","note","date");
|
||||
|
||||
# get a single note
|
||||
($note, $date) = $db->get_single(1);
|
||||
|
||||
# search for a certain note
|
||||
%matching_notes = $db->get_search("somewhat");
|
||||
# format of returned hash:
|
||||
#$matching_notes{$numberofnote}->{'note' => 'something', 'date' => '23.12.2000 10:33:02'}
|
||||
|
||||
# get all existing notes
|
||||
%all_notes = $db->get_all();
|
||||
# format of returns hash like the one from get_search above
|
||||
|
||||
# get the next noteid available
|
||||
$next_num = $db->get_nextnum();
|
||||
|
||||
# recount all noteids starting by 1 (useful after deleting one!)
|
||||
$db->set_recountnums();
|
||||
|
||||
# modify a certain note
|
||||
$db->set_edit(1, "any text", "23.12.2000 10:33:02");
|
||||
|
||||
# create a new note
|
||||
$db->set_new(5, "any new text", "23.12.2000 10:33:02");
|
||||
|
||||
# delete a certain note
|
||||
$db->set_del(5);
|
||||
|
||||
# turn on encryption. CryptMethod must be IDEA, DES or BLOWFISH
|
||||
$db->use_crypt("passphrase", "CryptMethod");
|
||||
|
||||
# turn off encryption. This is the default.
|
||||
$db->no_crypt();
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
You can use this module for accessing a note database. There are currently
|
||||
two versions of this module, one version for a SQL database and one for a
|
||||
binary file (note's own database-format).
|
||||
However, both versions provides identical interfaces, which means, you do
|
||||
not need to change your code, if you want to switch to another database format.
|
||||
|
||||
Currently, NOTEDB module is only used by note itself. But feel free to use it
|
||||
within your own project! Perhaps someone want to implement a web interface to
|
||||
note...
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
please see the section SYNOPSIS, it says it all.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Thomas Linden <tom@daemon.de>.
|
||||
|
||||
|
||||
|
||||
=cut
|
||||
@@ -1,612 +0,0 @@
|
||||
# Perl module for note
|
||||
# pwsafe3 backend. see docu: perldoc NOTEDB::pwsafe3
|
||||
|
||||
package NOTEDB::pwsafe3;
|
||||
|
||||
$NOTEDB::pwsafe3::VERSION = "1.09";
|
||||
use strict;
|
||||
use Data::Dumper;
|
||||
use Time::Local;
|
||||
use Crypt::PWSafe3;
|
||||
|
||||
use NOTEDB;
|
||||
|
||||
use Fcntl qw(LOCK_EX LOCK_UN);
|
||||
|
||||
use Exporter ();
|
||||
use vars qw(@ISA @EXPORT);
|
||||
@ISA = qw(NOTEDB Exporter);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sub new {
|
||||
my($this, %param) = @_;
|
||||
|
||||
my $class = ref($this) || $this;
|
||||
my $self = {};
|
||||
bless($self,$class);
|
||||
|
||||
$self->{dbname} = $param{dbname} || File::Spec->catfile($ENV{HOME}, ".notedb.psafe3");
|
||||
|
||||
$self->{mtime} = $self->get_stat();
|
||||
$self->{unread} = 1;
|
||||
$self->{data} = {};
|
||||
$self->{LOCKFILE} = $param{dbname} . "~LOCK";
|
||||
$self->{keepkey} = 0;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub DESTROY {
|
||||
# clean the desk!
|
||||
}
|
||||
|
||||
sub version {
|
||||
my $this = shift;
|
||||
return $NOTEDB::pwsafe3::VERSION;
|
||||
}
|
||||
|
||||
sub get_stat {
|
||||
my ($this) = @_;
|
||||
if(-e $this->{dbname}) {
|
||||
return (stat($this->{dbname}))[9];
|
||||
}
|
||||
else {
|
||||
return time;
|
||||
}
|
||||
}
|
||||
|
||||
sub filechanged {
|
||||
my ($this) = @_;
|
||||
my $current = $this->get_stat();
|
||||
|
||||
if ($current > $this->{mtime}) {
|
||||
$this->{mtime} = $current;
|
||||
return $current;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub set_del_all {
|
||||
my $this = shift;
|
||||
unlink $this->{dbname};
|
||||
open(TT,">$this->{dbname}") or die "Could not create $this->{dbname}: $!\n";
|
||||
close (TT);
|
||||
}
|
||||
|
||||
|
||||
sub get_single {
|
||||
my($this, $num) = @_;
|
||||
my($address, $note, $date, $n, $t, $buffer, );
|
||||
|
||||
my %data = $this->get_all();
|
||||
|
||||
return ($data{$num}->{note}, $data{$num}->{date});
|
||||
}
|
||||
|
||||
|
||||
sub get_all {
|
||||
my $this = shift;
|
||||
my($num, $note, $date, %res);
|
||||
if ($this->unchanged) {
|
||||
return %{$this->{cache}};
|
||||
}
|
||||
|
||||
my %data = $this->_retrieve();
|
||||
|
||||
foreach my $num (keys %data) {
|
||||
($res{$num}->{date}, $res{$num}->{note}) = $this->_pwsafe3tonote($data{$num}->{note});
|
||||
}
|
||||
|
||||
$this->cache(%res);
|
||||
return %res;
|
||||
}
|
||||
|
||||
sub import_data {
|
||||
my ($this, $data) = @_;
|
||||
|
||||
my $fh;
|
||||
|
||||
if (-s $this->{dbname}) {
|
||||
$fh = new FileHandle "<$this->{dbname}" or die "could not open $this->{dbname}\n";
|
||||
flock $fh, LOCK_EX;
|
||||
}
|
||||
|
||||
my $key = $this->_getpass();
|
||||
|
||||
eval {
|
||||
my $vault = new Crypt::PWSafe3(password => $key, file => $this->{dbname});
|
||||
|
||||
foreach my $num (keys %{$data}) {
|
||||
my $checksum = $this->get_nextnum();
|
||||
my %record = $this->_notetopwsafe3($checksum, $data->{$num}->{note}, $data->{$num}->{date});
|
||||
|
||||
my $rec = new Crypt::PWSafe3::Record();
|
||||
$rec->uuid($record{uuid});
|
||||
$vault->addrecord($rec);
|
||||
$vault->modifyrecord($record{uuid}, %record);
|
||||
}
|
||||
|
||||
$vault->save();
|
||||
};
|
||||
if ($@) {
|
||||
print "Exception caught:\n$@\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
eval {
|
||||
flock $fh, LOCK_UN;
|
||||
$fh->close();
|
||||
};
|
||||
|
||||
$this->{keepkey} = 0;
|
||||
$this->{key} = 0;
|
||||
}
|
||||
|
||||
sub get_nextnum {
|
||||
my $this = shift;
|
||||
my($num, $te, $me, $buffer);
|
||||
|
||||
my $ug = new Data::UUID;
|
||||
|
||||
$this->{nextuuid} = unpack('H*', $ug->create());
|
||||
$num = $this->_uuid( $this->{nextuuid} );
|
||||
|
||||
return $num;
|
||||
}
|
||||
|
||||
sub get_search {
|
||||
my($this, $searchstring) = @_;
|
||||
my($buffer, $num, $note, $date, %res, $t, $n, $match);
|
||||
|
||||
my $regex = $this->generate_search($searchstring);
|
||||
eval $regex;
|
||||
if ($@) {
|
||||
print "invalid expression: \"$searchstring\"!\n";
|
||||
return;
|
||||
}
|
||||
$match = 0;
|
||||
|
||||
if ($this->unchanged) {
|
||||
foreach my $num (keys %{$this->{cache}}) {
|
||||
$_ = $this->{cache}{$num}->{note};
|
||||
eval $regex;
|
||||
if ($match) {
|
||||
$res{$num}->{note} = $this->{cache}{$num}->{note};
|
||||
$res{$num}->{date} = $this->{cache}{$num}->{date}
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
return %res;
|
||||
}
|
||||
|
||||
my %data = $this->get_all();
|
||||
|
||||
foreach my $num(sort keys %data) {
|
||||
$_ = $data{$num}->{note};
|
||||
eval $regex;
|
||||
if($match)
|
||||
{
|
||||
$res{$num}->{note} = $data{$num}->{note};
|
||||
$res{$num}->{date} = $data{$num}->{data};
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
|
||||
return %res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sub set_edit {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
|
||||
my %data = $this->_retrieve();
|
||||
|
||||
my %record = $this->_notetopwsafe3($num, $note, $date);
|
||||
|
||||
if (exists $data{$num}) {
|
||||
$data{$num}->{note} = \%record;
|
||||
$this->_store(\%record);
|
||||
}
|
||||
else {
|
||||
%record = $this->_store(\%record, 1);
|
||||
}
|
||||
|
||||
$this->changed;
|
||||
}
|
||||
|
||||
|
||||
sub set_new {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
$this->set_edit($num, $note, $date);
|
||||
}
|
||||
|
||||
|
||||
sub set_del {
|
||||
my($this, $num) = @_;
|
||||
|
||||
my $uuid = $this->_getuuid($num);
|
||||
if(! $uuid) {
|
||||
print "Note $num does not exist!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
my $fh = new FileHandle "<$this->{dbname}" or die "could not open $this->{dbname}\n";
|
||||
flock $fh, LOCK_EX;
|
||||
|
||||
my $key = $this->_getpass();
|
||||
eval {
|
||||
my $vault = new Crypt::PWSafe3(password => $key, file => $this->{dbname});
|
||||
delete $vault->{record}->{$uuid};
|
||||
$vault->markmodified();
|
||||
$vault->save();
|
||||
};
|
||||
if ($@) {
|
||||
print "Exception caught:\n$@\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
eval {
|
||||
flock $fh, LOCK_UN;
|
||||
$fh->close();
|
||||
};
|
||||
|
||||
# finally re-read the db, so that we always have the latest data
|
||||
$this->_retrieve($key);
|
||||
$this->changed;
|
||||
return;
|
||||
}
|
||||
|
||||
sub set_recountnums {
|
||||
my($this) = @_;
|
||||
# unsupported
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
sub _store {
|
||||
my ($this, $record, $create) = @_;
|
||||
|
||||
my $fh;
|
||||
|
||||
if (-s $this->{dbname}) {
|
||||
$fh = new FileHandle "<$this->{dbname}" or die "could not open $this->{dbname}\n";
|
||||
flock $fh, LOCK_EX;
|
||||
}
|
||||
|
||||
my $key;
|
||||
my $prompt = "pwsafe password: ";
|
||||
|
||||
foreach my $try (1..5) {
|
||||
if($try > 1) {
|
||||
$prompt = "pwsafe password ($try retry): ";
|
||||
}
|
||||
$key = $this->_getpass($prompt);
|
||||
eval {
|
||||
my $vault = new Crypt::PWSafe3(password => $key, file => $this->{dbname});
|
||||
if ($create) {
|
||||
my $rec = new Crypt::PWSafe3::Record();
|
||||
$rec->uuid($record->{uuid});
|
||||
$vault->addrecord($rec);
|
||||
$vault->modifyrecord($record->{uuid}, %{$record});
|
||||
}
|
||||
else {
|
||||
$vault->modifyrecord($record->{uuid}, %{$record});
|
||||
}
|
||||
$vault->save();
|
||||
};
|
||||
if ($@) {
|
||||
if($@ =~ /wrong pass/i) {
|
||||
$key = '';
|
||||
next;
|
||||
}
|
||||
else {
|
||||
print "Exception caught:\n$@\n";
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
eval {
|
||||
flock $fh, LOCK_UN;
|
||||
$fh->close();
|
||||
};
|
||||
|
||||
if(!$key) {
|
||||
print STDERR "Giving up after 5 failed password attempts.\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# finally re-read the db, so that we always have the latest data
|
||||
$this->_retrieve($key);
|
||||
}
|
||||
|
||||
sub _retrieve {
|
||||
my ($this, $key) = @_;
|
||||
my $file = $this->{dbname};
|
||||
if (-s $file) {
|
||||
if ($this->filechanged() || $this->{unread}) {
|
||||
my %data;
|
||||
if (! $key) {
|
||||
$key = $this->_getpass();
|
||||
}
|
||||
eval {
|
||||
my $vault = new Crypt::PWSafe3(password => $key, file => $this->{dbname});
|
||||
|
||||
my @records = $vault->getrecords();
|
||||
|
||||
foreach my $record (sort { $a->ctime <=> $b->ctime } @records) {
|
||||
my $num = $this->_uuid( $record->uuid );
|
||||
my %entry = (
|
||||
uuid => $record->uuid,
|
||||
title => $record->title,
|
||||
user => $record->user,
|
||||
passwd => $record->passwd,
|
||||
notes => $record->notes,
|
||||
group => $record->group,
|
||||
lastmod=> $record->lastmod,
|
||||
ctime => $record->ctime,
|
||||
);
|
||||
$data{$num}->{note} = \%entry;
|
||||
}
|
||||
};
|
||||
if ($@) {
|
||||
print "Exception caught:\n$@\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
$this->{unread} = 0;
|
||||
$this->{data} = \%data;
|
||||
return %data;
|
||||
}
|
||||
else {
|
||||
return %{$this->{data}};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
sub _pwsafe3tonote {
|
||||
#
|
||||
# convert pwsafe3 record to note record
|
||||
my ($this, $record) = @_;
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($record->{ctime});
|
||||
my $date = sprintf("%02d.%02d.%04d %02d:%02d:%02d", $mday, $mon+1, $year+1900, $hour, $min, $sec);
|
||||
chomp $date;
|
||||
my $note;
|
||||
if ($record->{group}) {
|
||||
my $group = $record->{group};
|
||||
# convert group separator
|
||||
$group =~ s#\.#/#g;
|
||||
$note = "/$group/\n";
|
||||
}
|
||||
|
||||
# pwsafe3 uses windows newlines, so convert ours
|
||||
$record->{notes} =~ s/\r\n/\n/gs;
|
||||
|
||||
#
|
||||
# we do NOT add user and password fields here extra
|
||||
# because if it is contained in the note, from were
|
||||
# it was extracted initially, where it remains anyway
|
||||
$note .= "$record->{title}\n$record->{notes}";
|
||||
|
||||
return ($date, $note);
|
||||
}
|
||||
|
||||
sub _notetopwsafe3 {
|
||||
#
|
||||
# convert note record to pwsafe3 record
|
||||
# only used on create or save
|
||||
#
|
||||
# this one is the critical part, because the two
|
||||
# record types are fundamentally incompatible.
|
||||
# we parse our record and try to guess the values
|
||||
# required for pwsafe3
|
||||
#
|
||||
# expected input for note:
|
||||
# /path/ -> group, optional
|
||||
# any text -> title
|
||||
# User: xxx -> user
|
||||
# Password: xxx -> passwd
|
||||
# anything else -> notes
|
||||
#
|
||||
# expected input for date:
|
||||
# 23.02.2010 07:56:27
|
||||
my ($this, $num, $text, $date) = @_;
|
||||
my ($group, $title, $user, $passwd, $notes, $ts, $content);
|
||||
if ($text =~ /^\//) {
|
||||
($group, $title, $content) = split /\n/, $text, 3;
|
||||
}
|
||||
else {
|
||||
($title, $content) = split /\n/, $text, 2;
|
||||
}
|
||||
|
||||
if(!defined $content) { $content = ""; }
|
||||
if(!defined $group) { $group = ""; }
|
||||
|
||||
$user = $passwd = '';
|
||||
if ($content =~ /(user|username|login|account|benutzer):\s*(.+)/i) {
|
||||
$user = $2;
|
||||
}
|
||||
if ($content =~ /(password|pass|passwd|kennwort|pw):\s*(.+)/i) {
|
||||
$passwd = $2;
|
||||
}
|
||||
|
||||
# 1 2 3 4 5 6
|
||||
if ($date =~ /^(\d\d)\.(\d\d)\.(\d{4}) (\d\d):(\d\d):(\d\d)$/) {
|
||||
# timelocal($sec,$min,$hour,$mday,$mon,$year);
|
||||
$ts = timelocal($6, $5, $4, $1, $2-1, $3-1900);
|
||||
}
|
||||
|
||||
# make our topics pwsafe3 compatible groups
|
||||
$group =~ s#^/##;
|
||||
$group =~ s#/$##;
|
||||
$group =~ s#/#.#g;
|
||||
|
||||
# pwsafe3 uses windows newlines, so convert ours
|
||||
$content =~ s/\n/\r\n/gs;
|
||||
my %record = (
|
||||
uuid => $this->_getuuid($num),
|
||||
user => $user,
|
||||
passwd => $passwd,
|
||||
group => $group,
|
||||
title => $title,
|
||||
ctime => $ts,
|
||||
lastmod=> $ts,
|
||||
notes => $content,
|
||||
);
|
||||
return %record;
|
||||
}
|
||||
|
||||
sub _uuid {
|
||||
my ($this, $uuid) = @_;
|
||||
if (exists $this->{uuidnum}->{$uuid}) {
|
||||
return $this->{uuidnum}->{$uuid};
|
||||
}
|
||||
|
||||
my $max = 0;
|
||||
|
||||
if (exists $this->{numuuid}) {
|
||||
$max = (sort { $b <=> $a } keys %{$this->{numuuid}})[0];
|
||||
}
|
||||
|
||||
my $num = $max + 1;
|
||||
|
||||
$this->{uuidnum}->{$uuid} = $num;
|
||||
$this->{numuuid}->{$num} = $uuid;
|
||||
|
||||
return $num;
|
||||
}
|
||||
|
||||
sub _getuuid {
|
||||
my ($this, $num) = @_;
|
||||
return $this->{numuuid}->{$num};
|
||||
}
|
||||
|
||||
sub _getpass {
|
||||
#
|
||||
# We're doing this here ourselfes
|
||||
# because the note way of handling encryption
|
||||
# doesn't work with pwsafe3, we can't hold a cipher
|
||||
# structure in memory, because pwsafe3 handles this
|
||||
# itself.
|
||||
# Instead we ask for the password everytime we want
|
||||
# to fetch data from the actual file OR want to write
|
||||
# to it. To minimize reads, we use caching by default.
|
||||
my($this, $prompt) = @_;
|
||||
|
||||
if ($this->{key}) {
|
||||
return $this->{key};
|
||||
}
|
||||
else {
|
||||
my $key;
|
||||
print STDERR $prompt ? $prompt : "pwsafe password: ";
|
||||
eval {
|
||||
local($|) = 1;
|
||||
local(*TTY);
|
||||
open(TTY,"/dev/tty") or die "No /dev/tty!";
|
||||
system ("stty -echo </dev/tty") and die "stty failed!";
|
||||
chomp($key = <TTY>);
|
||||
print STDERR "\r\n";
|
||||
system ("stty echo </dev/tty") and die "stty failed!";
|
||||
close(TTY);
|
||||
};
|
||||
if ($@) {
|
||||
$key = <>;
|
||||
}
|
||||
if ($this->{keepkey}) {
|
||||
$this->{key} = $key;
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
1; # keep this!
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
NOTEDB::pwsafe3 - module lib for accessing a notedb from perl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# include the module
|
||||
use NOTEDB;
|
||||
|
||||
# create a new NOTEDB object
|
||||
$db = new NOTEDB("text", "/home/tom/.notedb", 4096, 24);
|
||||
|
||||
# decide to use encryption
|
||||
# $key is the cipher to use for encryption
|
||||
# $method must be either Crypt::IDEA or Crypt::DES
|
||||
# you need Crypt::CBC, Crypt::IDEA and Crypt::DES to have installed.
|
||||
$db->use_crypt($key,$method);
|
||||
|
||||
# do not use encryption
|
||||
# this is the default
|
||||
$db->no_crypt;
|
||||
|
||||
# get a single note
|
||||
($note, $date) = $db->get_single(1);
|
||||
|
||||
# search for a certain note
|
||||
%matching_notes = $db->get_search("somewhat");
|
||||
# format of returned hash:
|
||||
#$matching_notes{$numberofnote}->{'note' => 'something', 'date' => '23.12.2000 10:33:02'}
|
||||
|
||||
# get all existing notes
|
||||
%all_notes = $db->get_all();
|
||||
# format of returns hash like the one from get_search above
|
||||
|
||||
# get the next noteid available
|
||||
$next_num = $db->get_nextnum();
|
||||
|
||||
# modify a certain note
|
||||
$db->set_edit(1, "any text", "23.12.2000 10:33:02");
|
||||
|
||||
# create a new note
|
||||
$db->set_new(5, "any new text", "23.12.2000 10:33:02");
|
||||
|
||||
# delete a certain note
|
||||
$db->set_del(5);
|
||||
|
||||
# turn on encryption. CryptMethod must be IDEA, DES or BLOWFISH
|
||||
$db->use_crypt("passphrase", "CryptMethod");
|
||||
|
||||
# turn off encryption. This is the default.
|
||||
$db->no_crypt();
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
You can use this module for accessing a note database. This backend uses
|
||||
a text file for storage and Config::General for accessing the file.
|
||||
|
||||
Currently, NOTEDB module is only used by note itself. But feel free to use it
|
||||
within your own project! Perhaps someone want to implement a web interface to
|
||||
note...
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
please see the section SYNOPSIS, it says it all.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Thomas Linden <tom AT linden DOT at>
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
@@ -1,352 +0,0 @@
|
||||
# Perl module for note
|
||||
# text database backend. see docu: perldoc NOTEDB::text
|
||||
# using Storable as backend.
|
||||
|
||||
package NOTEDB::text;
|
||||
|
||||
$NOTEDB::text::VERSION = "1.05";
|
||||
|
||||
use strict;
|
||||
#use Data::Dumper;
|
||||
use File::Spec;
|
||||
use Storable qw(lock_nstore lock_retrieve);
|
||||
use MIME::Base64;
|
||||
|
||||
use NOTEDB;
|
||||
|
||||
use Fcntl qw(LOCK_EX LOCK_UN);
|
||||
|
||||
use Exporter ();
|
||||
use vars qw(@ISA @EXPORT);
|
||||
@ISA = qw(NOTEDB Exporter);
|
||||
|
||||
|
||||
|
||||
|
||||
sub new {
|
||||
my($this, %param) = @_;
|
||||
|
||||
my $class = ref($this) || $this;
|
||||
my $self = {};
|
||||
bless($self,$class);
|
||||
|
||||
$self->{NOTEDB} = $self->{dbname} = $param{dbname} || File::Spec->catfile($ENV{HOME}, ".notedb.storable");
|
||||
|
||||
if(! -e $param{dbname}) {
|
||||
open(TT,">$param{dbname}") or die "Could not create $param{dbname}: $!\n";
|
||||
close (TT);
|
||||
}
|
||||
elsif(! -w $param{dbname}) {
|
||||
print "$param{dbname} is not writable!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$self->{LOCKFILE} = $param{dbname} . "~LOCK";
|
||||
$self->{mtime} = $self->get_stat();
|
||||
$self->{unread} = 1;
|
||||
$self->{data} = {};
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub DESTROY
|
||||
{
|
||||
# clean the desk!
|
||||
}
|
||||
|
||||
sub version {
|
||||
my $this = shift;
|
||||
return $NOTEDB::text::VERSION;
|
||||
}
|
||||
|
||||
sub get_stat {
|
||||
my ($this) = @_;
|
||||
my $mtime = (stat($this->{dbname}))[9];
|
||||
return $mtime;
|
||||
}
|
||||
|
||||
|
||||
sub set_del_all {
|
||||
my $this = shift;
|
||||
unlink $this->{NOTEDB};
|
||||
open(TT,">$this->{NOTEDB}") or die "Could not create $this->{NOTEDB}: $!\n";
|
||||
close (TT);
|
||||
}
|
||||
|
||||
|
||||
sub get_single {
|
||||
my($this, $num) = @_;
|
||||
my($address, $note, $date, $n, $t, $buffer, );
|
||||
|
||||
my %data = $this->get_all();
|
||||
|
||||
return ($data{$num}->{note}, $data{$num}->{date});
|
||||
}
|
||||
|
||||
|
||||
sub get_all {
|
||||
my $this = shift;
|
||||
my($num, $note, $date, %res);
|
||||
|
||||
if ($this->unchanged) {
|
||||
return %{$this->{cache}};
|
||||
}
|
||||
|
||||
my %data = $this->_retrieve();
|
||||
|
||||
foreach my $num (keys %data) {
|
||||
$res{$num}->{note} = $this->ude($data{$num}->{note});
|
||||
$res{$num}->{date} = $this->ude($data{$num}->{date});
|
||||
}
|
||||
|
||||
$this->cache(%res);
|
||||
return %res;
|
||||
}
|
||||
|
||||
sub import_data {
|
||||
my ($this, $data) = @_;
|
||||
my %res = $this->_retrieve();
|
||||
my $pos = (scalar keys %res) + 1;
|
||||
foreach my $num (keys %{$data}) {
|
||||
$res{$pos}->{note} = $this->uen($data->{$num}->{note});
|
||||
$res{$pos}->{date} = $this->uen($data->{$num}->{date});
|
||||
$pos++;
|
||||
}
|
||||
$this->_store(\%res);
|
||||
}
|
||||
|
||||
sub get_nextnum {
|
||||
my $this = shift;
|
||||
my($num, $te, $me, $buffer);
|
||||
|
||||
if ($this->unchanged) {
|
||||
my @numbers = sort { $a <=> $b } keys %{$this->{cache}};
|
||||
$num = pop @numbers;
|
||||
$num++;
|
||||
return $num;
|
||||
}
|
||||
|
||||
my %data = $this->get_all();
|
||||
my @numbers = sort { $a <=> $b } keys %data;
|
||||
$num = pop @numbers;
|
||||
$num++;
|
||||
return $num;
|
||||
}
|
||||
|
||||
sub get_search {
|
||||
my($this, $searchstring) = @_;
|
||||
my($buffer, $num, $note, $date, %res, $t, $n, $match);
|
||||
|
||||
my $regex = $this->generate_search($searchstring);
|
||||
eval $regex;
|
||||
if ($@) {
|
||||
print "invalid expression: \"$searchstring\"!\n";
|
||||
return;
|
||||
}
|
||||
$match = 0;
|
||||
|
||||
if ($this->unchanged) {
|
||||
foreach my $num (keys %{$this->{cache}}) {
|
||||
$_ = $this->{cache}{$num}->{note};
|
||||
eval $regex;
|
||||
if ($match) {
|
||||
$res{$num}->{note} = $this->{cache}{$num}->{note};
|
||||
$res{$num}->{date} = $this->{cache}{$num}->{date}
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
return %res;
|
||||
}
|
||||
|
||||
my %data = $this->get_all();
|
||||
|
||||
foreach my $num(sort keys %data) {
|
||||
$_ = $data{$num}->{note};
|
||||
eval $regex;
|
||||
if($match)
|
||||
{
|
||||
$res{$num}->{note} = $data{$num}->{note};
|
||||
$res{$num}->{date} = $data{$num}->{data};
|
||||
}
|
||||
$match = 0;
|
||||
}
|
||||
|
||||
return %res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
sub set_edit {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
|
||||
my %data = $this->_retrieve();
|
||||
|
||||
$data{$num} = {
|
||||
note => $this->uen($note),
|
||||
date => $this->uen($date)
|
||||
};
|
||||
|
||||
$this->_store(\%data);
|
||||
|
||||
$this->changed;
|
||||
}
|
||||
|
||||
|
||||
sub set_new {
|
||||
my($this, $num, $note, $date) = @_;
|
||||
$this->set_edit($num, $note, $date);
|
||||
}
|
||||
|
||||
|
||||
sub set_del {
|
||||
my($this, $num) = @_;
|
||||
my(%data, $note, $date, $T, $setnum, $buffer, $n, $N, $t);
|
||||
|
||||
$setnum = 1;
|
||||
|
||||
%data = $this->_retrieve();
|
||||
return "ERROR" if (! exists $data{$num});
|
||||
|
||||
delete $data{$num};
|
||||
|
||||
$this->_store(\%data);
|
||||
|
||||
$this->changed;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub set_recountnums {
|
||||
# not required here
|
||||
return;
|
||||
}
|
||||
|
||||
sub uen {
|
||||
my ($this, $raw) = @_;
|
||||
my($crypted);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$crypted = $this->{cipher}->encrypt($raw);
|
||||
};
|
||||
}
|
||||
else {
|
||||
$crypted = $raw;
|
||||
}
|
||||
my $coded = encode_base64($crypted);
|
||||
return $coded;
|
||||
}
|
||||
|
||||
sub ude {
|
||||
my ($this, $crypted) = @_;
|
||||
my($raw);
|
||||
if($NOTEDB::crypt_supported == 1) {
|
||||
eval {
|
||||
$raw = $this->{cipher}->decrypt(decode_base64($crypted));
|
||||
};
|
||||
}
|
||||
else {
|
||||
$raw = decode_base64($crypted)
|
||||
}
|
||||
return $raw;
|
||||
}
|
||||
|
||||
|
||||
sub _store {
|
||||
my ($this, $data) = @_;
|
||||
lock_nstore($data, $this->{NOTEDB});
|
||||
}
|
||||
|
||||
sub _retrieve {
|
||||
my $this = shift;
|
||||
if (-s $this->{NOTEDB}) {
|
||||
if ($this->changed() || $this->{unread}) {
|
||||
my $data = lock_retrieve($this->{NOTEDB});
|
||||
$this->{unread} = 0;
|
||||
$this->{data} = $data;
|
||||
return %{$data};
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1; # keep this!
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
NOTEDB::text - module lib for accessing a notedb from perl
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# include the module
|
||||
use NOTEDB;
|
||||
|
||||
# create a new NOTEDB object
|
||||
$db = new NOTEDB("text", "/home/tom/.notedb", 4096, 24);
|
||||
|
||||
# decide to use encryption
|
||||
# $key is the cipher to use for encryption
|
||||
# $method must be either Crypt::IDEA or Crypt::DES
|
||||
# you need Crypt::CBC, Crypt::IDEA and Crypt::DES to have installed.
|
||||
$db->use_crypt($key,$method);
|
||||
|
||||
# do not use encryption
|
||||
# this is the default
|
||||
$db->no_crypt;
|
||||
|
||||
# get a single note
|
||||
($note, $date) = $db->get_single(1);
|
||||
|
||||
# search for a certain note
|
||||
%matching_notes = $db->get_search("somewhat");
|
||||
# format of returned hash:
|
||||
#$matching_notes{$numberofnote}->{'note' => 'something', 'date' => '23.12.2000 10:33:02'}
|
||||
|
||||
# get all existing notes
|
||||
%all_notes = $db->get_all();
|
||||
# format of returns hash like the one from get_search above
|
||||
|
||||
# get the next noteid available
|
||||
$next_num = $db->get_nextnum();
|
||||
|
||||
# modify a certain note
|
||||
$db->set_edit(1, "any text", "23.12.2000 10:33:02");
|
||||
|
||||
# create a new note
|
||||
$db->set_new(5, "any new text", "23.12.2000 10:33:02");
|
||||
|
||||
# delete a certain note
|
||||
$db->set_del(5);
|
||||
|
||||
# turn on encryption. CryptMethod must be IDEA, DES or BLOWFISH
|
||||
$db->use_crypt("passphrase", "CryptMethod");
|
||||
|
||||
# turn off encryption. This is the default.
|
||||
$db->no_crypt();
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
You can use this module for accessing a note database. This backend uses
|
||||
a text file for storage and Storable for accessing the file.
|
||||
|
||||
Currently, NOTEDB module is only used by note itself. But feel free to use it
|
||||
within your own project! Perhaps someone want to implement a web interface to
|
||||
note...
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
please see the section SYNOPSIS, it says it all.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Thomas Linden <tom@daemon.de>.
|
||||
|
||||
|
||||
=cut
|
||||
74
mysql/README
74
mysql/README
@@ -1,74 +0,0 @@
|
||||
README for the mysql database installation for note
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
You need the following things:
|
||||
o perl installed (5.004x)
|
||||
o mysql database installed and running
|
||||
o Mysql perlmodule (you can find it on
|
||||
http://www.mysql.org) PLEASE NOTE:
|
||||
It needs the Module "Mysql". The install.sh
|
||||
script will install it for you directly from
|
||||
CPAN if you like. Newer versions
|
||||
are DBI, which you can also use to access
|
||||
mysql databases. If you want to use it, you
|
||||
have to rewrite the program. Please let me
|
||||
know, if you did it :-)
|
||||
o permissions to create a new database and
|
||||
to write data to this database.
|
||||
|
||||
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
First, make sure all these things above are ok.
|
||||
You can use the script "install.sh" to create a new
|
||||
database and the table structure. You might edit
|
||||
the script before running it.
|
||||
|
||||
If you are getting trouble, i.e. if you have not the
|
||||
required permissions to do that, please make sure,
|
||||
you can.
|
||||
As user root, you have to give your user the
|
||||
neccessary permissions. Please refer to the mysql
|
||||
documentation, how to do that.
|
||||
After that repeat the step above.
|
||||
|
||||
You can find a sample config file within the subdirectory
|
||||
"config" named noterc. There are some special values
|
||||
which you can use to connect to a different database
|
||||
then the default.
|
||||
install.sh will create the following database:
|
||||
name: user_note
|
||||
Maintable: note
|
||||
Number: number(int 10)
|
||||
Note: note(text)
|
||||
Date: date(text)
|
||||
|
||||
You can use the file "permissions" as a template for
|
||||
modifying a users permissions to her database. Please
|
||||
note, that there are different version of mysql out
|
||||
there with different access privilege systems, which
|
||||
are not compatible, refer to the documentation shipped
|
||||
with your mysql installation to learn, how many fields
|
||||
are available and what they are for.
|
||||
|
||||
You may also take a look to:
|
||||
http://www.mysql.org/Manual_chapter/manual_Privilege_system.html
|
||||
|
||||
|
||||
This should be all.
|
||||
|
||||
Manual Installation
|
||||
===================
|
||||
|
||||
1) create a mysql database
|
||||
mysqladmin create $db
|
||||
|
||||
2) add the required GRANT to a user and database
|
||||
echo "GRANT ALL PRIVILEGES ON $db TO $user@localhost IDENTIFIED BY '$password'" | mysql mysql
|
||||
|
||||
3) create the schema:
|
||||
mysql $db < sql
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/sh
|
||||
# installs note
|
||||
# This is the installer for the mysql version only!
|
||||
|
||||
echo "Welcome to note `cat ../VERSION` installation."
|
||||
echo "the install script will ask you a view questions,"
|
||||
echo "make sure to answer them correctly!"
|
||||
echo
|
||||
|
||||
/bin/echo -n "creating the note database..."
|
||||
NAME="_note"
|
||||
DBNAME="$USER$NAME"
|
||||
echo "DBNAME=$DBNAME"
|
||||
mysqladmin create $DBNAME
|
||||
echo "done."
|
||||
/bin/echo -n "creating the table structure using defaults..."
|
||||
mysql $DBNAME < sql
|
||||
|
||||
echo "Shall I try to install the required MySQL driver from CPAN?"
|
||||
read YESNO
|
||||
|
||||
case $YESNO in
|
||||
"y" | "Y")
|
||||
if [ $(id -ru) != 0 ] ; then
|
||||
echo "You should be root for that!"
|
||||
exit
|
||||
fi
|
||||
perl -MCPAN -e shell cpan> install mysql
|
||||
;;
|
||||
esac
|
||||
echo "done."
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
insert into user values
|
||||
('localhost','','','Y','Y','Y','Y','Y','Y','N','N','N','N','N','N','N','Y');
|
||||
@@ -1,9 +0,0 @@
|
||||
CREATE TABLE note (
|
||||
number int(10) DEFAULT '0' NOT NULL auto_increment,
|
||||
topic text,
|
||||
note text,
|
||||
date text,
|
||||
PRIMARY KEY (number)
|
||||
);
|
||||
# sample grant statement:
|
||||
#GRANT ALL PRIVILEGES ON tom_note TO tom@localhost IDENTIFIED BY 'password';
|
||||
547
note.pod
547
note.pod
@@ -1,547 +0,0 @@
|
||||
# -*-perl-*-
|
||||
|
||||
=head1 NAME
|
||||
|
||||
note - a perl script for maintaining notes.
|
||||
|
||||
|
||||
=head1 SYNPOPSIS
|
||||
|
||||
note [options] [ number [,number...]]
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<note> is a small console program written in perl, which allows you
|
||||
to manage notes similar to programs like "knotes" but from the command
|
||||
line. Note can use different database-backends for notes-storage. It
|
||||
ships with a DBI-based mysql-module(which can also be used for other
|
||||
by DBI supported DBMS), another module, which uses a binary file for
|
||||
storage and a DBM module. There are also two modules available which
|
||||
uses a text file. Note supports since version 1.0.0 encryption(IDEA
|
||||
or DES)! And last but not least the PWSafe3 format is also supported
|
||||
by the pwsafe3 backend, which is encrypted by default.
|
||||
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
|
||||
=over
|
||||
|
||||
=item I<-c, --config file>
|
||||
|
||||
Use another config file than the default ~/.noterc.
|
||||
|
||||
=item I<-n, --new>
|
||||
|
||||
Create a new note entry.
|
||||
|
||||
=item I<-l, --list [topic]>
|
||||
|
||||
Lists all existing notes. If no topic were specified,
|
||||
it will display a list of all existing topics.
|
||||
See the section I<TOPICS> for details about topics.
|
||||
|
||||
=item I<-L, --longlist [topic]>
|
||||
|
||||
The same as I<-l> but prints also the timestamp of the notes.
|
||||
|
||||
|
||||
=item I<-t, --topic>
|
||||
|
||||
Prints a list of all topics as a tree.
|
||||
|
||||
|
||||
=item I<-T, --longtopic>
|
||||
|
||||
Prints the topic-tree with the notes under each topic.
|
||||
|
||||
|
||||
=item I<-s, --search string>
|
||||
|
||||
Searches for <string> trough the notes database. See the section
|
||||
I<SEARCHING> for details about the search engine.
|
||||
|
||||
|
||||
=item I<-e, --edit number>
|
||||
|
||||
Edit the note with the number <number> using your default editor
|
||||
or the one you specified in the config file.
|
||||
|
||||
|
||||
=item I<-d, --delete number>
|
||||
|
||||
Delete the note with the number <number>. You can delete multiple notes
|
||||
with one command. "1-4" deletes the notes 1,2,3,4. And "1,5,7" deletes
|
||||
the specified ones.
|
||||
|
||||
|
||||
=item I<-D, --Dump [file | -]>
|
||||
|
||||
Dumps all notes to the textfile <file>. If <file> is a "-" it will
|
||||
be printed out to standard output (STDOUT).
|
||||
|
||||
=item I<-j --json>
|
||||
|
||||
Use JSON format for exports created using -D. The importer determines
|
||||
the format to be used automatically.
|
||||
|
||||
=item I<-I, --Import file | ->
|
||||
|
||||
Imports a previously dumped textfile into the
|
||||
note database. Data will be appended by default.
|
||||
You can also specify a dash I<note -I -> instead of a <file>,
|
||||
which causes note, silently to read in a dump from STDIN.
|
||||
|
||||
|
||||
=item I<-o, --overwrite>
|
||||
|
||||
Only suitable for use with --Import. Overwrites an
|
||||
existing notedb. Use with care.
|
||||
|
||||
|
||||
=item I<-r, --raw>
|
||||
|
||||
Raw mode, output will not be formatted. Works not in interactive
|
||||
mode, only on cmd-line for list and display. That means, no colors
|
||||
will be used and no lines or titles.
|
||||
|
||||
|
||||
=item I<-i, --interactive>
|
||||
|
||||
Start note in interactive mode. See the section I<INTERACTIVE MODE>
|
||||
for details on this mode.
|
||||
|
||||
|
||||
=item I<--encrypt cleartext>
|
||||
|
||||
Encrypt the given clear text string. You would need that if you want to
|
||||
store the mysql password not in cleartext in the config (if you are using
|
||||
the mysql backend!).
|
||||
|
||||
|
||||
=item I<-h, --help>
|
||||
|
||||
Display this help screen.
|
||||
|
||||
|
||||
=item I<-v, --version>
|
||||
|
||||
Display the version number.
|
||||
|
||||
|
||||
=item B<->
|
||||
|
||||
If you run note just with one dash: B<note ->, then it will read in a new
|
||||
note from STDIN until EOF. This makes it possible to pipe text into a new note, i.e.:
|
||||
|
||||
cat sometextfile | note -
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
=head2 GENERAL USAGE
|
||||
|
||||
If you don't know, how to run note, try "note -h" first.
|
||||
It will tell you all available command line options.
|
||||
|
||||
To create a new note, simply run "note". You can enter
|
||||
the note (the length is by default limited to 4096 bytes,
|
||||
which you can change from your config file if you are using
|
||||
the binary backend, otherwise there is no limitation).
|
||||
End by typing a . on a line itself. note will tell you the
|
||||
number of the note.
|
||||
|
||||
If you want to view the note, type "note 1", if the notenumber
|
||||
was 1.
|
||||
|
||||
If you want to get an overview of all notes, type "note -l".
|
||||
You will get a list of all notes, containing the number,
|
||||
the first line and the creation date. If topic-support is
|
||||
turned on (which is by default), then all subtopics under the
|
||||
current topic will be displayed first.
|
||||
If you want to see the timestamps, use "-L" instead of "-l".
|
||||
Read more about topics below in the section "Topics".
|
||||
You can also specify the topic which notes you want to see:
|
||||
"-l mytopic" does the trick.
|
||||
Additional, you might want to get an overview of your topic-
|
||||
structure. You can use the command "-t" in this case, which
|
||||
will display a tree-view of your topic-structure. You can
|
||||
use the command "-T" if you want to see the notes under each
|
||||
topic too. "-T" will also show the number of each note.
|
||||
|
||||
To edit a certain note, type "note -e 1". It will invoke your
|
||||
editor (vi or pico). You can edit it, after saving, note
|
||||
will store the changed note to the database.
|
||||
|
||||
Of course you can drop a certain note: "note -d 1" deletes
|
||||
note number 1. If a note in the middle or the beginning of
|
||||
the database will be deleted, note will recount the other
|
||||
existent notes. For example there are 3 notes, number 1, 2
|
||||
and 3. If you delete number 2, then number 3 will become
|
||||
number 2.
|
||||
You can also make use of the extended delete-syntax:
|
||||
To delete note 1 and 2, use "-d 1,2"
|
||||
To delete note 1,2 and 3, use "-d 1-3".
|
||||
|
||||
|
||||
|
||||
=head2 SEARCHING
|
||||
|
||||
If you cannot remember, which note you are looking for, you
|
||||
can use the search capability of note: "note -s <searchstring>".
|
||||
note will search the whole note database case insensitive for
|
||||
an occurrence of this string and tell you the number and first-
|
||||
line it has.
|
||||
|
||||
You can extend the searchstring using B<AND>, B<OR> ( and ) and
|
||||
shell-like wildcards:
|
||||
|
||||
$ note -s "moses AND lenin"
|
||||
|
||||
or:
|
||||
|
||||
$ note -s "(mike OR arnold) AND (jackson OR schwarzenegger)"
|
||||
|
||||
If note finds a note, which first line is a topic, then it will
|
||||
display it's second line.
|
||||
|
||||
These rules apply for the interactive search too.
|
||||
|
||||
You need to know, that note searches for the expression in every
|
||||
note. In other words, "moses AND lenin" searches for an occurrence
|
||||
of "moses" and "lenin" in ONE note. Or, if you are looking for
|
||||
"mike OR daniel", then it searches for an occurrence of "mike" or
|
||||
daniel" in ONE note. Thus a note with the text "mike oldfield" will
|
||||
match that search.
|
||||
|
||||
|
||||
=head2 TOPICS
|
||||
|
||||
If topic-support is turned on (which is by default), the various
|
||||
notes are sorted under various topics. There is no special database
|
||||
field for the topic. Instead the topic will be stored right in the
|
||||
note.
|
||||
If the first line of your note contains some text bordered by slashes
|
||||
(or whatever you prefer, set "TopicSeparator" in your config! default
|
||||
is slash), then note will consider it as the topic of this certain
|
||||
note. For examle:
|
||||
|
||||
B</TodoList/>
|
||||
|
||||
If you are using topics, no data after the topic is allowed, if there
|
||||
is any text, note will consider it as a subtopic! Therefore, don't for-
|
||||
get to put a newline after the topic-line.
|
||||
|
||||
The list-command will only show you notes under this topic. If you
|
||||
create a new note, it will automagically inserted under the current
|
||||
topic (note will prepend the string "/topicname/" to the text of your
|
||||
note).
|
||||
|
||||
You can create at any time from any point a new topic. Just create a new
|
||||
note and type the name of the new topic bordered by slashes (or
|
||||
TopicSeparator) at the first line of this note. After saving, there
|
||||
will be available a new topic with one note in it.
|
||||
|
||||
You can create as many subtopics as you like, the format is similar to
|
||||
a filesystem-path. An example, say, you want to create such a
|
||||
structure:
|
||||
|
||||
(root - top level)
|
||||
|
|
||||
|----test
|
||||
| |----subtopic
|
||||
| | |--note 1
|
||||
| | |--note 2
|
||||
| |
|
||||
| |--note 4
|
||||
|
|
||||
|--note 3
|
||||
|
||||
Then you may create those 4 new notes:
|
||||
|
||||
--- snip ---
|
||||
/test/subtopic/
|
||||
note 1
|
||||
--- snip ---
|
||||
/test/subtopic/
|
||||
note 2
|
||||
--- snip ---
|
||||
note 3
|
||||
--- snip ---
|
||||
/test/
|
||||
note 4
|
||||
--- snip ---
|
||||
|
||||
I hope, you got the point ;-)
|
||||
|
||||
If a note does not contain the "magic" /topic/ construction on the first
|
||||
line, it will be listed under the "root" of note, that is the point
|
||||
you are at the startup of note.
|
||||
|
||||
You can subsequently move a note without a topic to a certain topic.
|
||||
Simply edit it and insert at the first line the above mentioned
|
||||
construction.
|
||||
|
||||
Note: Please don't forget the prepending and appending a slash of a
|
||||
topic. You will get strange results without it!
|
||||
|
||||
|
||||
|
||||
|
||||
=head2 INTERACTIVE MODE
|
||||
|
||||
If you start note with the command line flag B<-i>, then it starts
|
||||
with an interactive interface.
|
||||
It will start with a listing under the default top-topic ("/").
|
||||
You can enter the name of a topic to change to that topic. This works
|
||||
similar to a filesystem structure. The current topic will be
|
||||
displayed on the top of the screen.
|
||||
|
||||
The following commands are available:
|
||||
|
||||
=over
|
||||
|
||||
=item B<L [topic]>
|
||||
|
||||
This command lists all notes with a timestamp. If you specify a topic, it
|
||||
will only list the notes under this topic. If you are under a certain subtopic,
|
||||
then it will only display the notes under this topic.
|
||||
|
||||
=item B<l [topic]>
|
||||
|
||||
This commands behaves similar to B<L> but it does not display the timestamp.
|
||||
You can achieve the same result by simply pressing enter at any time.
|
||||
|
||||
|
||||
=item B<N>
|
||||
|
||||
You can create a new note by simply pressing B<N> or B<n>. You favorite
|
||||
editor will be started and you can enter your note text. If you are already
|
||||
under a topic then this new note will automatically go to this topic.
|
||||
note adds an additional line to the top of the note with the topic. But
|
||||
you can, of course, specify your own topic.
|
||||
|
||||
Note will tell you which number it has assigned to the newly created note.
|
||||
|
||||
=item B<E number>
|
||||
|
||||
By entering B<E> or B<e> and a note-number you can edit an existing note
|
||||
using your favorite editor. This way you can also move an existing note
|
||||
from one topic to another one by editing the first line of the note.
|
||||
|
||||
|
||||
=item B<D number>
|
||||
|
||||
B<E> or B<e> deletes one or more existing note(s). It requires a note number
|
||||
or a set of note numbers. 1-5 and 1,7,9 are possible values.
|
||||
After one or more notes has been deleted note will recount all remaining notes.
|
||||
Say if you delete 1 and 2, then 3 will become 1, 4 will become 5 and so forth.
|
||||
|
||||
|
||||
=item B<S [expression]>
|
||||
|
||||
You can search for the occurrence of a text in your notes-database with the
|
||||
command B<S> or B<s>. If you omit an expression note will ask you for one.
|
||||
|
||||
If your search criteria matches on exactly one entry, note will display
|
||||
that note entry instead of displaying its number.
|
||||
|
||||
=item B<T>
|
||||
|
||||
This prints a tree-view of your topic-structure. B<T> displays the tree with
|
||||
notes, B<t> displays just the topics without notes.
|
||||
|
||||
=item B<C>
|
||||
|
||||
It is possible to change note's behavior at runtime. Specify the parameter
|
||||
you'd like to modify followed by equalsign and the new value. Use with
|
||||
care! However, database related parameters cannot be changed at runtime.
|
||||
Entering just "c" without parameters displays the customizable variables.
|
||||
|
||||
=item B<cd topic>
|
||||
|
||||
Change the actual topic under which you are. This works identical like just
|
||||
entering the topic but it has some advantages. You can enter B<cd ..> if
|
||||
you want to go one level up in the topic-structure. And you can enter B<cd />
|
||||
to go to the top of the structure. You can always leave out the 'cd' keyword too.
|
||||
|
||||
Additional it is possible to enter a note-number instead of a topic name.
|
||||
For this feature to be active you need to set the config option B<ShortCd>
|
||||
to B<1> or B<yes>. If you use a number and the note with this number is
|
||||
under a certain topic then you will "cd" to this topic. This allows you
|
||||
to do kind of jumps over multiple levels of topics.
|
||||
|
||||
If is possible to abbreviate a topic. This works only if the abbreviation
|
||||
matches on one single topic. If it matches more than one topic then the
|
||||
available ones will be suggested.
|
||||
|
||||
|
||||
=item B<? or h>
|
||||
|
||||
Display a short help screen.
|
||||
|
||||
|
||||
=item B<Q>
|
||||
|
||||
Quit note.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
=head2 BACKUP
|
||||
|
||||
You can also dump the contents of your note-database into a
|
||||
ASCII-textfile(I<-D>). You can use this file later to import it into
|
||||
your note-database(-I). This is useful, if you want quickly trans-
|
||||
fer your notes from one host to another (i.e. you could mail
|
||||
your note-dump form your office to home and import it there
|
||||
for further use).
|
||||
|
||||
The dumps from the two versions of note are in the same format.
|
||||
Using dumps it is also possible to reinitialize your database. You
|
||||
can use the "-o" switch which causes note to overwrite your existing
|
||||
database. This is very handy if you changed heavily your config. And
|
||||
it is required, if you changed: encryption, db-driver, (binary-format)
|
||||
and the password. You can use the following command for reinitializing:
|
||||
|
||||
$ note -D - | note -o -I -
|
||||
|
||||
What the hell, does this do?! Step by step:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
|
||||
B<note -D -> creates a note-database dump and prints it out
|
||||
to standard output.
|
||||
|
||||
=item *
|
||||
|
||||
B<|> this is the shell's pipe command. It takes the output
|
||||
of the left program and gives it to the right program as
|
||||
standard input.
|
||||
|
||||
=item *
|
||||
|
||||
B<note -o -I -> imports a note-database dump from standard
|
||||
input and overwrites an existing database.
|
||||
|
||||
=back
|
||||
|
||||
Before you use the B<-o> switch, I consider you to make a backup!
|
||||
|
||||
=head3 BACKUP FILE FORMAT
|
||||
|
||||
B<Caution>: since version 1.3.8 note uses a new file format
|
||||
for backups: YAML. The old format is only supported by the
|
||||
B<-I> option to import old backups. New backups are always
|
||||
created as YAML files. See L<YAML>.
|
||||
|
||||
|
||||
|
||||
=head2 FORMATING
|
||||
|
||||
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 colorizing. Those strings looks much like HTML:
|
||||
"<green>here is a green line of text</green> no more green."
|
||||
As you see, the beginning of another color starts with a tag(kinda) of
|
||||
the color <colorname> and ends with an end tag </colorname>.
|
||||
|
||||
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 "FormatText" 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}}
|
||||
hidden: //word//
|
||||
|
||||
The text will be formatted using the actually note-color.
|
||||
|
||||
The hidden formatting will use blue foreground and blue background
|
||||
to hide a string from the terminal, which is useful for passwords.
|
||||
|
||||
If you set "FormatText" to I<simple> then the formatting can be
|
||||
done this way instead:
|
||||
|
||||
bold: *word*
|
||||
underlined: _word_
|
||||
inverse: {word}
|
||||
hidden: /word/
|
||||
|
||||
=head1 ENCRYPTION
|
||||
|
||||
You can turn on encryption from the config file.
|
||||
Simply set UseEncryption to 1. Please note, that you need
|
||||
to decide, if you want to use encryption before the first use
|
||||
of note! If have already a note database and want to "migrate"
|
||||
to encryption, I suggest you to follow the directions in the
|
||||
file UPGRADE!
|
||||
|
||||
You can choose from different encryption algorythms. The default
|
||||
is IDEA, but DES or BLOWFISH are also possible. You need to have
|
||||
installed the following additional perl-modules on your system:
|
||||
MD5
|
||||
Crypt::IDEA
|
||||
Crypt::DES
|
||||
Crypt::CBC
|
||||
|
||||
After turning on encryption, note will ask you for a passphrase
|
||||
every time it runs! It will *not* store this passphrase!
|
||||
So, don't forget it! Be careful!
|
||||
|
||||
|
||||
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
You can use a configuration file with note but it is not required.
|
||||
Note will use default values if there is no config.
|
||||
|
||||
The default config file is B<~/.noterc>. You may specify another
|
||||
one with the command line flag I<--config>.
|
||||
|
||||
Comments start with #, empty lines will be ignored.
|
||||
|
||||
To turn on an option, set it to: B<1>, B<on> or B<yes>.
|
||||
|
||||
To turn off an option, set it to: B<0>, B<off> or B<no>.
|
||||
|
||||
An option consists of an atribute-value pair separated
|
||||
by minimum one space (more spaces and/or tabs are allowed)
|
||||
and an optional equal sign in between.
|
||||
|
||||
Variable names are case in-sensitive.
|
||||
|
||||
For a detailed explanation of each possible parameter take a look
|
||||
at the supplied sample configuration file in B<config/noterc>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
T.v.Dein <tlinden@cpan.org>
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
1.4.0
|
||||
|
||||
=cut
|
||||
135
t/run.t
135
t/run.t
@@ -1,135 +0,0 @@
|
||||
# -*-perl-*-
|
||||
#use Test::More tests => 8;
|
||||
use Test::More qw(no_plan);
|
||||
use Data::Dumper;
|
||||
|
||||
my $expect = {
|
||||
1 => {
|
||||
'date' => '23.12.2000 10:33:02',
|
||||
'note' => 'any new text'
|
||||
},
|
||||
2 => {
|
||||
'date' => '03.02.2004 18:13:52',
|
||||
'note' => 'yet whatever you mean'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
BEGIN { use_ok "NOTEDB" };
|
||||
require_ok("NOTEDB");
|
||||
my $key = '01010101';
|
||||
my $alg = 'Rijndael';
|
||||
|
||||
foreach my $CR (1 .. 0) {
|
||||
$NOTEDB::crypt_supported = $CR;
|
||||
|
||||
SKIP: {
|
||||
skip "no crypt", 1 if $CR; # FIXME: for some weird reason, crypto doesn't work with ::binary?
|
||||
eval { require NOTEDB::binary; };
|
||||
skip "Fatal, skipping test for NOTEDB::binary", 1 if $@;
|
||||
unlink "t/binary.out";
|
||||
my $db = new NOTEDB::binary(dbname => "t/binary.out");
|
||||
$db->use_crypt($key, $alg) if $CR;
|
||||
ok(ref($db), "Database object loaded");
|
||||
&wrdb($db, "NOTEDB::binary");
|
||||
}
|
||||
|
||||
SKIP: {
|
||||
eval { require NOTEDB::general; };
|
||||
skip "Config::General not installed, skipping test for NOTEDB::general", 1 if $@;
|
||||
unlink "t/general.out";
|
||||
my $db2 = NOTEDB::general->new(dbname => "t/general.out");
|
||||
$db2->use_crypt($key, $alg) if $CR;
|
||||
ok(ref($db2), "Database object loaded");
|
||||
&wrdb($db2, "NOTEDB::general");
|
||||
}
|
||||
|
||||
SKIP: {
|
||||
eval { require NOTEDB::text; };
|
||||
skip "Storable not installed, skipping test for NOTEDB::text", 1 if $@;
|
||||
unlink "t/test.out";
|
||||
my $db3 = NOTEDB::text->new(dbname => "t/text.out");
|
||||
$db3->use_crypt($key, $alg) if $CR;
|
||||
ok(ref($db3), "Database object loaded");
|
||||
&wrdb($db3, "NOTEDB::text");
|
||||
}
|
||||
|
||||
SKIP: {
|
||||
eval { require NOTEDB::dumper; };
|
||||
skip "Data::Dumper not installed, skipping test for NOTEDB::dumper", 1 if $@;
|
||||
unlink "t/dumper.out";
|
||||
my $db4 = NOTEDB::dumper->new(dbname => "t/dumper.out");
|
||||
$db4->use_crypt($key, $alg) if $CR;
|
||||
ok(ref($db4), "Database object loaded");
|
||||
&wrdb($db4, "NOTEDB::dumper");
|
||||
}
|
||||
|
||||
SKIP: {
|
||||
eval { require NOTEDB::dbm; };
|
||||
skip "DB_File not installed, skipping test for NOTEDB::dbm", 1 if $@;
|
||||
unlink "t/note.dbm";
|
||||
unlink "t/date.dbm";
|
||||
my $db5 = NOTEDB::dbm->new(dbname => "t");
|
||||
$db5->use_crypt($key, $alg) if $CR;
|
||||
ok(ref($db5), "Database object loaded");
|
||||
&wrdb($db5, "NOTEDB::dbm");
|
||||
}
|
||||
}
|
||||
|
||||
SKIP: {
|
||||
eval { require NOTEDB::pwsafe3; };
|
||||
skip "Crypt::PWSafe3 not installed, skipping test for NOTEDB::pwsafe3", 1 if $@;
|
||||
unlink "t/pwsafe3.out";
|
||||
my $db6 = NOTEDB::pwsafe3->new(dbname => "t/pwsafe3.out");
|
||||
$db6->{key} = "01010101";
|
||||
ok(ref($db6), "Database object loaded");
|
||||
&wrdb3($db6, "NOTEDB::pwsafe3");
|
||||
}
|
||||
|
||||
sub wrdb {
|
||||
my ($db, $name) = @_;
|
||||
is_deeply($db->{use_cache}, undef, "$name: Chache disabled");
|
||||
|
||||
$db->set_new(1, $expect->{1}->{note}, $expect->{1}->{date});
|
||||
my ($note, $date) = $db->get_single(1);
|
||||
like($note, qr/any new text/, "$name: Retrieve newly written entry content");
|
||||
like($date, qr/^\d\d/, "$name: Retrieve newly written entry date");
|
||||
|
||||
$db->set_new(2, $expect->{2}->{note}, $expect->{2}->{date});
|
||||
|
||||
my $next = $db->get_nextnum();
|
||||
is_deeply($next, 3, "$name: Get next note id");
|
||||
|
||||
my %all = $db->get_all();
|
||||
is_deeply($expect, \%all, "$name: Get all notes hash") or diag(Dumper(\%all));
|
||||
}
|
||||
|
||||
sub wrdb3 {
|
||||
my ($db, $name) = @_;
|
||||
is_deeply($db->{use_cache}, undef, "$name: Chache disabled");
|
||||
|
||||
my $ex3 = $expect;
|
||||
my $n = $db->get_nextnum;
|
||||
$db->set_new($n, $ex3->{1}->{note}, $ex3->{1}->{date});
|
||||
$ex3->{$n} = delete $ex3->{1};
|
||||
|
||||
my ($note, $date) = $db->get_single($n);
|
||||
like($note, qr/any new text/, "$name: Retrieve newly written entry content");
|
||||
like($date, qr/^\d\d/, "$name: Retrieve newly written entry date");
|
||||
|
||||
$n = $db->get_nextnum;
|
||||
$db->set_new($n, $ex3->{2}->{note}, $ex3->{2}->{date});
|
||||
$ex3->{$n} = delete $ex3->{2};
|
||||
|
||||
# hack db file mtime, since we're too fast here
|
||||
$db->{mtime} = 0;
|
||||
|
||||
my %all = $db->get_all();
|
||||
# hack %all to that it passes the next test
|
||||
foreach my $n (keys %all) {
|
||||
chomp $all{$n}->{note};
|
||||
}
|
||||
|
||||
is_deeply($ex3, \%all, "$name: Get all notes hash") or diag(Dumper(\%all));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user