diff --git a/errors.md b/errors.md new file mode 100644 index 0000000..936ec07 --- /dev/null +++ b/errors.md @@ -0,0 +1,28 @@ +# Simple Note System, version 2 +## Error Code Reference + +### General Codes +| Name | Code | Meaning | +|--------------|------|---------------------------------------| +| ERR_NO_STORE | 5 | the SNS store needs to be initialized | +| | | | +| ERR_NO_OPTS | 10 | No mode argument was specified | +| | | | +| ERR_NO_ARGS | 11 | A mode requiring an argument was | +| | | specified without an argument | +| | | | + +### Encryption-related codes +|Name | Code | Meaning | +|------------|------|-----------------------------------------| +| ERR_NO_GPG | 100 | Encryption is enabled, but GPG is not | +| | | installed | +| | | | +| ERR_NO_KEY | 110 | Encryption is enabled, but no recipient | +| | | was specified | + +### Creation-related codes +|Name | Code | Meaning | +|-----------------|------|------------------------------------| +| ERR_NOTE_EXiSTS | 200 | The specified note already exists | +| ERR_NOTE_NO_READ| 205 | The specified note cannot be read | diff --git a/sns.sh b/sns.sh index 2c195ec..911c62d 100755 --- a/sns.sh +++ b/sns.sh @@ -2,14 +2,44 @@ XL_PRODUCT="Simple Note System" XL_VER="v2a" -# Environment +# Environment Constants readonly SNS_STORE="$HOME/.local/sns" readonly SNS_KEYFILE="$SNS_STORE/.pubkey" -readonly SNS_DEPS=("gpg" "tree" "git") +readonly SNS_DEPS=("gpg2" "tree" "git") readonly IFS=$'\n\t' set -euo pipefail +readonly SNS_RED_COLOR='\033[1;31m' +readonly SNS_YELLOW_COLOR='\033[1;33m' +readonly SNS_RESET_COLOR='\033[0m' + +# Erroneous Exit Constants + + # Invocation Errors + readonly SNS_ERR_NO_STORE=5 # The sns store needs to be initialized + readonly SNS_ERR_NO_OPTS=10 # No mode argument was specified + readonly SNS_ERR_NS_ARGS=11 # The specified mode requires an argument + + # Dependency Errors + readonly SNS_ERR_DEPS=20 # Base error - add the following codes + readonly SNS_ERR_NO_gpg2=1 # GPG is not installed + readonly SNS_ERR_NO_tree=2 # Tree is not installed + readonly SNS_ERR_NO_git=3 # Git is not installed + +# Global Variables +typeset -i SNS_SID="$RANDOM" +typeset -a SNS_ACTION=("") +typeset -a MISSING_DEPS +typeset -i SNS_EXIT=0 +declare SNS_PUBKEY= + # Function Definitions +# sns_printError Prints an error message +# sns_NoteHeader Prints standard note header to stdout +# sns_checkDeps Checks the system for required dependencies +# sns_checkStore Checks if $SNS_STORE exists +# sns_sanityCheck Wrapper for sns_checkDeps and sns_checkStore +# ---- # sns_initStore Initializes the SNS Store ( -i) # sns_printHelp Prints help page ( -h) # sns_list Lists all notes in `tree` format ( *) @@ -18,40 +48,18 @@ set -euo pipefail # sns_print Prints note to stdout ( -p) # sns_rm Deletes note from store ( -d) # sns_gitPassthrough Passes through all instructions to git (git) -# sns_checkDeps Checks the system for required dependencies -# sns_checkStore Checks if $SNS_STORE exists -# sns_sanityCheck Wrapper for sns_checkDeps and sns_checkStore -function sns_initStore { - mkdir -p "$SNS_STORE" - echo $* | awk '{print $1}' > "$SNS_KEYFILE" +function sns_printError(){ + printf "$SNS_RED_COLOR!$SNS_RESET_COLOR - %s\n" "$@" } -function sns_printHelp(){ - printf "%s" "Import helpfile from sns v2" -} -function sns_list(){ - cd "$SNS_STORE" || exit - tree -C --noreport "$(echo $* | awk '{print $1}')" -} -function sns_create(){ - gpg -r "$SNS_PUBKEY" -o "echo $* | awk '{print $1}'" < /dev/null - sns_edit "echo $* | awk '{print $1}'" -} -function sns_print(){ - gpg -d "echo $* | awk '{print $1}'" -} -function sns_rm(){ - rm -f "echo $* | awk '{print $1}'" -} -function sns_gitPassthrough(){ - cd "$SNS_STORE" || exit; - git "$@"; +function sns_NoteHeader(){ + printf "%s\n%s\n" "Title:" "Date:" } function sns_checkDeps(){ local SNS_RETURN="true"; for DEP in "${SNS_DEPS[@]}"; do - if test ! -e "$(which gpg 2>/dev/null)"; then - echo "Dependency missing: $DEP"; + if test ! -e "$(which "$DEP" 2>/dev/null)"; then + MISSING_DEPS+=("$DEP") SNS_RETURN="false"; fi done @@ -62,18 +70,112 @@ function sns_checkStore(){ } function sns_sanityCheck { if ! sns_checkDeps; then - exit 10 + SNS_EXIT="$SNS_ERR_DEPS" + for DEP in "${MISSING_DEPS[@]}"; do + local SNS_DEP_EC="\$ERR_NO_$DEP" + printError "Dependency %s not in path." "$DEP"; + SNS_EXIT+=${!SNS_DEP_EC} + done fi - if ! sns_checkStore; then - if [ "$(echo "$SNS_ACTION" | awk '{print $1;}')" != "sns_initStore" ]; then - printf "%s\n" "Please run \`sns -i\` to initialize sns." - exit 20 + + if [ -r "$SNS_STORE/.pubkey" ]; then + SNS_PUBKEY="$(cat "$SNS_STORE/.pubkey")" + elif ! sns_checkStore; then + if [ "$(echo "${SNS_ACTION[@]}" | awk '{print $1;}')" != "sns_initStore" ]; then + printError "The sns store does not exist." + printf " - %s\n" "Please run \`sns -i [gpg-key]\` to initialize sns." + SNS_EXIT="$SNS_ERR_NO_STORE" fi fi } +#---- +function sns_initStore { + mkdir -p "$SNS_STORE" + echo "$@" | awk '{print $1}' > "$SNS_KEYFILE" +} +function sns_printHelp(){ + printf "%s" "usage: sns [-cedlp] " + printf "\n%s%s%s" "usage: sns " "git" " ..." + printf "\n%s" " sns [-hi]" + + printf "\n%s" " -c | --create : Create note" + printf "\n%s" " -C | --config : Edit Config" + printf "\n%s" " -d | --delete : Delete note" + printf "\n%s" " -e | --edit : Open note for editing" + printf "\n%s" " -h | --help : Display this message" + printf "\n%s" " -i | --init : Write default config and initalize SNS store" + printf "\n%s" " -l | --list : List all notes in NOTEBOOK" + printf "\n%s" " -p | --print : Print note to console" + printf "\n\n" +} +function sns_list(){ + # Change directories to fix tree header + cd "$SNS_STORE" || exit; cd .. || exit; + # Print the tree + tree -C --noreport --prune "$(echo "$@" | awk '{print $1}')" +} +function sns_create(){ + # Make sure the note doesn't already exist + if [ -r "$SNS_STORE/$(echo "$@" | awk '{print $1}')" ]; then + sns_printError "Note already exists." + return + fi + + # Print the standard header to a temporary note + sns_NoteHeader > /tmp/"$SNS_SID" + + # Edit the new note + sns_edit "$(echo "$@" | awk '{print $1}')" +} +function sns_edit(){ + # Make the function more readable + local readonly SNS_NOTE="$SNS_STORE/$(echo "$@" | awk '{print $1}')" + + # Test if edit was called from create + if [ ! -r /tmp/"$SNS_SID" ]; then gpg2 -d -o /tmp/"$SNS_SID" "$SNS_NOTE"; fi + + # Edit the note + vim /tmp/"$SNS_SID" + + # Make sure the notebook/section exists + if [ ! -d "$(dirname "$SNS_NOTE")" ]; then mkdir -p "$(dirname "$SNS_NOTE")"; fi + + # If the note previously existed, make a backup. + if [ -r "$SNS_NOTE" ]; then mv "$SNS_NOTE" "$SNS_NOTE.bk"; fi + + # Re-encrypt it to the store + gpg2 -r "$SNS_PUBKEY" -o "$SNS_NOTE" -e /tmp/"$SNS_SID" + + # If all went well, remove the backup + if [ -r "$SNS_NOTE" ]; then rm "$SNS_NOTE.bk"; fi +} +function sns_print(){ + gpg2 -d "$SNS_STORE/$(echo "$@" | awk '{print $1}')" +} +function sns_rm(){ + rm -f "$SNS_STORE/$(echo "$@" | awk '{print $1}')" +} +function sns_gitPassthrough(){ + cd "$SNS_STORE" || exit; + git "$@"; +} +# ---- function sns_argParse(){ - declare -ga SNS_ACTION=() + ARGS=($@) + #echo "${#ARGS}" + SNS_ACTION=() while getopts ":i:hc:e:p:d:" OPT; do + + # If an option requiring an argument was passed without an argument, + # inform the user and set exit code to "$SNS_ERR_NS_ARGS" + case "${ARGS[!OPTIND]}" in + -i|-c|-e|-p|-d) + if [ "${#ARGS}" -lt 2 ]; then + printError "A required argument was not given." + SNS_EXIT="$SNS_ERR_NS_ARGS" + return + fi + esac case "$OPT" in i) SNS_ACTION=("sns_initStore" "$OPTARG");; @@ -89,12 +191,15 @@ function sns_argParse(){ SNS_ACTION=("sns_rm $OPTARG");; esac done + if [ "${#SNS_ACTION[@]}" -eq 0 ]; then if [ "$(echo "$@" | awk '{print $1}')" == "git" ]; then SNS_ACTION=($@) else if [ -d "$SNS_STORE/$*" ]; then - SNS_ACTION=("sns_list" "./$*") + SNS_ACTION=("sns_list" "sns/$@") + else + SNS_ACTION=("sns_list" "sns") fi fi fi @@ -102,6 +207,14 @@ function sns_argParse(){ # Entry Point printf "%s\n%s\n" "$XL_PRODUCT" "$XL_VER" +printf "\n" + sns_argParse "$@" sns_sanityCheck -"${SNS_ACTION[@]}" +if [ "$SNS_EXIT" -eq 0 ]; then + eval "${SNS_ACTION[@]}" +fi + +printf "\n" + +exit "$SNS_EXIT"