#!/bin/bash #========================================================== # Simple Note System, v2.0a8 # Copyright 2016, Xenese Labs/Sicron-Perion XNF #========================================================== if [ -z "$HOME" ]; then HOME=/home/"$(whoami)"; fi PROD_STR="Simple Note System" readonly VER_STR="v2.0a8" readonly ROOT_DIR="$HOME"/.config/sns readonly NOTES_DIR="$ROOT_DIR"/notes readonly TMP_DIR="$ROOT_DIR"/tmp readonly CONFIG_FILE="$ROOT_DIR/sns.conf" # Section: Functions function init_store { if [ ! -d "$ROOT_DIR" ]; then mkdir -p "$ROOT_DIR"; WILL_INIT="TRUE"; fi if [ ! -d "$TMP_DIR" ]; then mkdir -p "$TMP_DIR" ; WILL_INIT="TRUE"; fi cat > "$CONFIG_FILE" << EOF # This file contains directives for the Simple Note System. EXT=note # File extension to use (for listing notes) #EDITOR= # Preferred Editor: # If you would like to specify a different editor for # sns to use, you may do so here. ENCRYPTION="FALSE" # Main Encryption Toggle: # WARNING: ANY PREVIOUSLY UNENCRYPTED NOTES WILL BE LOST # Change this to TRUE to enable encryption. PUBKEY="" # Public Key # Encryption is done using GPG. You must enter your # public key's identifier here. EOF chmod 600 "$CONFIG_FILE" printf " - %s\n" "Rewrote Default Configuration" if [ "$WILL_INIT" == "TRUE" ]; then printf " - %s %s\n" "Environment initialized in" "$ROOT_DIR" else printf " - %s\n" "Store already initialized." fi } function verify_store { ETC_DIR="$(dirname \"$CONFIG_FILE\")" STORE_DIRS=("$ROOT_DIR" "$NOTES_DIR" "$TMP_DIR" "$ETC_DIR") for DIR in ${STORE_DIRS[@]}; do mkdir -p "$DIR" done } function pause { read -rp " Press [Enter] to continue." echo "" } function help { echo "" echo "usage: sns [-ce] NAME NOTEBOOK SECTION" echo " sns [-d ] NAME NOTEBOOK SECTION" echo " sns [-lp] NOTEBOOK" echo " sns [-w ]" echo " sns [-h ]" echo "" echo " -c | --create : Create note" echo " -d | --delete : Delete note" echo " -e | --edit : Open note for editing" echo " -h | --help : Display this message" echo " -p | --print : Print note to console" echo " -l | --list : List all notes in NOTEBOOK" echo " -i | --init : Write default config and initalize SNS store" echo "" } function p_header(){ printf "TITLE: %s\nDATE: %s\n" "$NAME" "$(date)" } function encrypt(){ # This function, given a recipient, $PUBKEY; a file to encrypt, $TMP_NOTE; and an # output file, "$NOTE", will encrypt $TMP_NOTE to $NOTE against $PUBKEY's private # GPG key. gpg -r "$PUBKEY" -o "$NOTE" -e "$TMP_NOTE" } function decrypt(){ # This function, given a recipient, $PUBKEY; a file to decrypt, $TMP_NOTE; and an # output file, "$NOTE", will decrpyt $TMP_NOTE to $NOTE against $PUBKEY's private # GPG key. gpg -d "$NOTE" } function create(){ # Depends : p_header # Requires: $NOTE, $NOTE_DIR, $NOTEBOOK, $SECTION, $NAME # Optional: $ENCRYPTION, $SESSION_ID, $TMP_DIR encrypt # Given a valid setup, create writes the standard note header as specified # by p_header, to $NOTE. # Refuse to overwrite a note if [ -e "$NOTE" ]; then printf "\nERROR: Note already exists\nHint: use -e to edit the note.\n" exit 200 # If the notebook doesn't exist, create it. elif [ ! -d "$NOTE_DIR" ]; then mkdir -p "$NOTE_DIR" fi # Write the standard note header if [ "$ENCRYPTION" == "TRUE" ]; then TMP_NOTE="$TMP_DIR"/"$SESSION_ID" p_header > "$TMP_NOTE" encrypt else p_header > "$NOTE" fi # Make sure the note exists, and inform the user. if [ -e "$NOTE" ]; then echo "Created note: $NOTEBOOK/$SECTION/$NAME." else printf "%s\n" "Something went wrong." fi } function delete(){ #Requires: $NOTE, $NOTEBOOK, $SECTION, $NAME # Given a valid $NOTE, delete removes $NOTE from sns. if [ -e "$NOTE" ]; then rm "$NOTE" printf "\n%s\n" "Deleted note: $NOTEBOOK/$SECTION/$NAME." else printf "\n%s\n" "ERROR: Note $NOTEBOOK/$SECTION/$NAME does not exist." fi } function edit(){ # Requires: $EDITOR, $NOTE # Optional: $ENCRYPTION, $TMP_DIR, $SESSION_ID, decrypt, encrypt # Verify an editor was specified if [ -z "$EDITOR" ]; then >&2 echo "Error no editor specified in environment." exit # Verify the note exists elif [ ! -r "$NOTE" ]; then echo "ERROR: Note cannot be opened for editing." exit 40; fi # When encryption is enabled, decrypt $NOTE to a temp file if [ "$ENCRYPTION" == "TRUE" ]; then cp "$NOTE" "$NOTE".bk #Insurance if [ ! -d "$TMP_DIR" ]; then mkdir "$TMP_DIR"; fi TMP_NOTE="$TMP_DIR/$SESSION_ID" decrypt > "$TMP_NOTE" else TMP_NOTE="$NOTE"; fi if [ -z "$CREATE" ]; then printf "\nEDIT %s" "$(date)" >> "$TMP_NOTE"; fi "$EDITOR" "$TMP_NOTE" if [ "$ENCRYPTION" == "TRUE" ]; then rm "$NOTE" encrypt; if [ -r "$NOTE" ]; then rm "$NOTE".bk; fi fi } function print(){ if [ -r "$NOTE" ]; then if [ -z "$CREATE" ]; then if [ "$ENCRYPTION" == "TRUE" ]; then decrypt else cat "$NOTE" fi else printf "\nERROR: Note cannot be found.\n" fi fi } function list(){ if [ -d "$NOTES_DIR"/"$NOTEBOOK" ]; then printf "+%s\n" "$NOTEBOOK" find "$NOTES_DIR"/"$NOTEBOOK" -type f | while read -r NOTE; do printf " -%s\n" "$(basename \"$NOTE\" | cut -d . -f 1 )" done fi } # End Section: Functions #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Entry Point #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #============================================================================== # Stage 1: Read Configuration / Verify Integrity #============================================================================== if [ -r "$CONFIG_FILE" ]; then source "$CONFIG_FILE" else init_store source "$CONFIG_FILE" fi verify_store if [ "$ENCRYPTION" == "TRUE" ]; then if [ -z "$PUBKEY" ]; then ERR_NO_KEY="TRUE" ENCRYPTION="FALSE" fi command -v gpg >/dev/null 2>&1 ||\ { ERR_NO_GPG="TRUE"; ENCRYPTION="FALSE"; } fi if [ "$ENCRYPTION" == "TRUE" ]; then PROD_STR="Simple Note System (Encryption Enabled)" if [ ! -d "$ROOT_DIR"/tmp ]; then mkdir -p "$ROOT_DIR"/tmp fi fi echo "$PROD_STR, $VER_STR" if [ -n "$ERR_NO_GPG" ]; then >&2 echo " Error: Encryption was specified, but GPG is not installed." exit 100 elif [ -n "$ERR_NO_KEY" ]; then >&2 echo " Error: No GPG recipient was provided in $CONFIG_FILE. " exit 110 fi #============================================================================== # Stage 2: Argument Parsing #============================================================================== NAME="" NOTEBOOK="" SECTION="" if [ -z "$1" ]; then help; exit 20 else ARGS=( "$@" ) for ARG in "${ARGS[@]}"; do if [ "$ARG" = "-c" ] || [ "$ARG" = "--create" ]; then CREATE="TRUE"; OP="TRUE" elif [ "$ARG" = "-d" ] || [ "$ARG" = "--delete" ]; then DELETE="TRUE"; OP="TRUE" elif [ "$ARG" = "-e" ] || [ "$ARG" = "--edit" ]; then EDIT="TRUE"; OP="TRUE" elif [ "$ARG" = "-ce" ] || [ "$ARG" = "-ec" ]; then EDIT="TRUE"; CREATE="TRUE"; OP="TRUE" elif [ "$ARG" = "-p" ] || [ "$ARG" = "--print" ]; then PRINT="TRUE"; OP="TRUE" elif [ "$ARG" = "-l" ] || [ "$ARG" = "--list" ]; then LIST="TRUE"; OP="TRUE" elif [ "$ARG" = "-h" ] || [ "$ARG" == "--help" ]; then help; exit 0 elif [ "$ARG" = "-i" ] || [ "$ARG" == "--init" ]; then init_store; exit 0 else if [ -z "$NAME" ] && [ -n "$ARG" ]; then NAME="$ARG" elif [ -z "$NOTEBOOK" ] && [ -n "$ARG" ]; then NOTEBOOK="$ARG" elif [ -z "$SECTION" ] && [ -n "$ARG" ]; then SECTION="$ARG" fi fi done if [ -n "$NAME" ] && [ -z "$NOTEBOOK" ] && [ -n "$LIST" ]; then # If a note title was specified, but no notebook, and the list option # was specified, assume that the detected note title is actually the # name of a notebook NOTEBOOK="$NAME" NAME="" fi fi # w_conf and help are called here to avoid excess stage 3 code. #============================================================================== # Section: Actions / Stage 3 #============================================================================== # Default behavior # If no operation was specified, print help and exit on ERR_NO_OP if [ "$OP" != "TRUE" ]; then help; exit 20 fi # All options not requiring at least a notebook to be specified have been dealt # with; if one isn't specified, exit on ERR_NO_NOTEBOOK. if [ -z "$NOTEBOOK" ]; then printf "\n%s\n %s\n" "ERROR: Insufficient arguments:" "Notebook not specified" exit 30 fi # List is the only option requiring only a notebook. # If list isn't the selected option and no note name was specified, throw code 30. if [ "$LIST" == TRUE ]; then list exit 0 elif [ -z "$NAME" ]; printf "\n%s\n %s\n" "ERROR: Insufficient arguments:" "Notebook not specified" exit 30 fi NOTE_DIR="$NOTES_DIR"/"$NOTEBOOK"/"$SECTION" if [ "$ENCRYPTION" == "TRUE" ]; then SESSION_ID="$RANDOM" #SESSION_ID later becomes the temporary filename readonly NOTE="$NOTE_DIR/$NAME.$EXT.gpg" else readonly NOTE="$NOTE_DIR/$NAME.$EXT" fi if [ "$PRINT" == "TRUE" ]; then print; exit 0; fi if [ "$DELETE" == "TRUE" ]; then delete; exit 0; fi if [ "$CREATE" == "TRUE" ]; then create; fi if [ "$EDIT" == "TRUE" ]; then edit; fi #============================================================================== # End Section: Actions / Stage 3 #==============================================================================