#!/usr/bin/env bash

# rofi-pass
# (c) 2015 Rasmus Steinke <rasi@xssn.at>
basecommand="$0"

# set default settings
_rofi () {
        rofi -no-auto-select -i "$@"
}

_pwgen () {
        pwgen -y "$@"
}

_image_viewer () {
        feh -
}

config_dir=${XDG_CONFIG_HOME:-$HOME/.config}
cache_dir=${XDG_CACHE_HOME:-$HOME/.cache}

# We expect to find these fields in pass(1)'s output
URL_field='url'
USERNAME_field='user'
AUTOTYPE_field='autotype'
OTPmethod_field='otp_method'

default_autotype="user :tab pass"
delay=2
wait=0.2
type_delay=12
default_do='menu' # menu, copyPass, typeUser, typePass, copyUser, copyUrl, viewEntry, typeMenu, actionMenu, copyMenu, openUrl
auto_enter='false'
notify='false'
help_color=""
clip=primary
clip_clear=45
default_user="${ROFI_PASS_DEFAULT_USER-$(whoami)}"
default_user2=john_doe
password_length=12
fix_layout=false

# default shortcuts
autotype="Alt+1"
type_user="Alt+2"
type_pass="Alt+3"
open_url="Alt+4"
copy_name="Alt+u"
copy_url="Alt+l"
copy_pass="Alt+p"
show="Alt+o"
copy_menu="Alt+c"
action_menu="Alt+a"
type_menu="Alt+t"
help="Alt+h"
switch="Alt+x"
insert_pass="Alt+n"
qrcode="Alt+q"
previous_root="Shift+Left"
next_root="Shift+Right"
clipboard_backend=${ROFI_PASS_CLIPBOARD_BACKEND:-xclip}
backend=${ROFI_PASS_BACKEND:-xdotool}

case "$clipboard_backend" in
        "xclip");;
        "wl-clipboard");;
        *)
                >&2 echo "Invalid clipboard backend '$clipboard_backend', falling back to xclip"
                clipboard_backend=xclip
                ;;
esac

case "$backend" in
        "xdotool");;
        "wtype");;
        *)
                >&2 echo "Invalid backend '$backend', falling back to xdotool"
                backend=xdotool
                ;;
esac

# Safe permissions
umask 077

# Backends for clipboard manipulation
_clip_in_primary_wl-clipboard() {
        wl-copy -p
}

_clip_in_clipboard_wl-clipboard() {
        wl-copy
}

_clip_out_primary_wl-clipboard() {
        wl-paste -p
}

_clip_out_clipboard_wl-clipboard() {
        wl-paste
}

_clip_in_primary_xclip() {
        xclip
}

_clip_in_clipboard_xclip() {
        xclip -selection clipboard
}

_clip_out_primary_xclip() {
        xclip -o
}

_clip_out_clipboard_xclip() {
        xclip --selection clipboard -o
}

# Backends for typing what's in stdin
_do_type_xdotool() {
        xdotool type --delay ${type_delay} --clearmodifiers --file -
}

_do_type_wtype() {
        wtype -d ${type_delay} -
}

# Backends for pressing the key specified by the first argument ($1)
_do_press_key_xdotool() {
        xdotool key "$1"
}

_do_press_key_wtype() {
        wtype -P "$1" -p "$1"
}

has_qrencode() {
        command -v qrencode >/dev/null 2>&1
}

listgpg () {
        mapfile -d '' pw_list < <(find -L . -name '*.gpg' -print0)
        pw_list=("${pw_list[@]#./}")
        printf '%s\n' "${pw_list[@]}" | sort -n
}

# get all password files and output as newline-delimited text
list_passwords() {
        cd "${root}" || exit
        mapfile -t pw_list < <(listgpg)
        printf '%s\n' "${pw_list[@]%.gpg}" | sort -n
}

doClip () {
        case "$clip" in
                "primary") ${clip_in_primary} ;;
                "clipboard") ${clip_in_clipboard} ;;
                "both") ${clip_in_primary}; ${clip_out_primary} | ${clip_in_clipboard};;
        esac
}

checkIfPass () {
        printf '%s\n' "${root}: $selected_password" >| "$cache_dir/rofi-pass/last_used"
}


autopass () {
        if [[ $backend == "xdotool" ]]; then
                x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
                xset r off
        fi

        rm -f "$cache_dir/rofi-pass/last_used"
        printf '%s\n' "${root}: $selected_password" > "$cache_dir/rofi-pass/last_used"
        for word in ${stuff["$AUTOTYPE_field"]}; do
                case "$word" in
                        ":tab") ${do_press_key} Tab;;
                        ":space") ${do_press_key} space;;
                        ":delay") sleep "${delay}";;
                        ":enter") ${do_press_key} Return;;
                        ":otp") printf '%s' "$(generateOTP)" | ${do_type};;
                        "pass") printf '%s' "${password}" | ${do_type};;
                        "path") printf '%s' "${selected_password}" | rev | cut -d'/' -f1 | rev | ${do_type};;
                        *) printf '%s' "${stuff[${word}]}" | ${do_type};;
                esac
        done

        if [[ ${auto_enter} == "true" ]]; then
                ${do_press_key} Return
        fi

        if [[ $backend == "xdotool" ]]; then
                xset r "$x_repeat_enabled"
                unset x_repeat_enabled
        fi

        clearUp
}

generateQrCode() {
        has_qrencode

        if [[ $? -eq "1" ]]; then
                printf '%s\n' "qrencode not found" | _rofi -dmenu
                exit_code=$?
                if [[ $exit_code -eq "1" ]]; then
                        exit
                else
                        "${basecommand}"
                fi
        fi

        checkIfPass
        pass "$selected_password" | head -n 1 | qrencode -d 300 -v 8 -l H -o - | _image_viewer
        if [[ $? -eq "1" ]]; then
                printf '%s\n' "" | _rofi -dmenu -mesg "Image viewer not defined or cannot read from pipe"
                exit_value=$?
                if [[ $exit_value -eq "1" ]]; then
                        exit
                else
                        "${basecommand}"
                fi
        fi
        clearUp
}

openURL () {
        checkIfPass
        $BROWSER "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${URL_field}: " | gawk '{sub(/:/,"")}{print $2}1' | head -1)"; exit;
        clearUp
}

typeUser () {
        checkIfPass

        if [[ $backend == "xdotool" ]]; then
                x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
                xset r off
        fi

        printf '%s' "${stuff[${USERNAME_field}]}" | ${do_type}

        if [[ $backend == "xdotool" ]]; then
                xset r "$x_repeat_enabled"
                unset x_repeat_enabled
        fi

        clearUp
}

typePass () {
        checkIfPass

        if [[ $backend == "xdotool" ]]; then
                x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
                xset r off
        fi

        printf '%s' "${password}" | ${do_type}

        if [[ $notify == "true" ]]; then
                if [[ "${stuff[notify]}" == "false" ]]; then
                        :
                else
                        notify-send "rofi-pass" "finished typing password";
                fi
        elif [[ $notify == "false" ]]; then
                if [[ "${stuff[notify]}" == "true" ]]; then
                        notify-send "rofi-pass" "finished typing password";
                else
                        :
                fi
        fi

        if [[ $backend == "xdotool" ]]; then
                xset r "$x_repeat_enabled"
                unset x_repeat_enabled
        fi

        clearUp
}

typeField () {
        checkIfPass
        local to_type

        if [[ $backend == "xdotool" ]]; then
                x_repeat_enabled=$(xset q | awk '/auto repeat:/ {print $3}')
                xset r off
        fi

        case $typefield in
                "OTP") to_type="$(generateOTP)" ;;
                *) to_type="${stuff[${typefield}]}" ;;
        esac

        printf '%s' "$to_type" | ${do_type}

        if [[ $backend == "xdotool" ]]; then
                xset r "$x_repeat_enabled"
                unset x_repeat_enabled
        fi

        unset to_type

        clearUp
}

generateOTP () {
        checkIfPass

        # First, we check if there is a non-conventional OTP command in the pass file
        if PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep -q "${OTPmethod_field}: "; then
                # We execute the commands after otp_method: AS-IS
                bash -c "$(PASSWORD_STORE_DIR="${root}" pass "$selected_password" | grep "${OTPmethod_field}: " | cut -d' ' -f2-)"
        else
                # If there is no method defined, fallback to pass-otp
                PASSWORD_STORE_DIR="${root}" pass otp "$selected_password"
        fi

        clearUp
}

copyUser () {
        checkIfPass
        printf '%s' "${stuff[${USERNAME_field}]}" | doClip
        clearUp
}

copyField () {
        checkIfPass
        printf '%s' "${stuff[${copyfield}]}" | doClip
        clearUp
}

copyURL () {
        checkIfPass
        printf '%s' "${stuff[${URL_field}]}" | doClip
        clearUp
}

copyPass () {
        checkIfPass
        printf '%s' "$password" | doClip
        if [[ $notify == "true" ]]; then
                notify-send "rofi-pass" "Copied Password\\nClearing in $clip_clear seconds"
        fi

        if [[ $notify == "true" ]]; then
                (sleep $clip_clear; printf '%s' "" | ${clip_in_primary}; printf '%s' "" | ${clip_in_clipboard} | notify-send "rofi-pass" "Clipboard cleared") &
        elif [[ $notify == "false" ]]; then
                (sleep $clip_clear; printf '%s' "" | ${clip_in_primary}; printf '%s' "" | ${clip_in_clipboard}) &
        fi
}

viewEntry () {
        checkIfPass
        showEntry "${selected_password}"
}

generatePass () {
        askmenu_content=(
                "Yes"
                "No"
        )

        askGenMenu=$(printf '%s\n' "${askmenu_content[@]}" | _rofi -dmenu -p "Generate new Password for ${selected_password}? > ")
        askgen_exit=$?

        if [[ $askgen_exit -eq 1 ]]; then
                exit
        fi
        if [[ $askGenMenu == "Yes" ]]; then
                true
        elif [[ $askGenMenu == "No" ]]; then
                actionMenu
        fi

        checkIfPass

        symbols_content=(
                "0  Cancel"
                "1  Yes"
                "2  No"
        )

        symbols=$(printf '%s\n' "${symbols_content[@]}" | _rofi -dmenu -p "Use Symbols? > ")
        symbols_val=$?

        if [[ $symbols_val -eq 1 ]]; then
                exit
        fi
        if [[ $symbols == "0  Cancel" ]]; then
                mainMenu;
        elif [[ $symbols == "1  Yes" ]]; then
                symbols="";
        elif [[ $symbols == "2  No" ]]; then
                symbols="-n";
        fi

        HELP="<span$help_color_attribute>Enter Number or hit Enter to use default length</span>"
        length=$(printf '%s' "" | _rofi -dmenu -mesg "${HELP}" -p "Password length? (Default: ${password_length}) > ")
        length_exit=$?

        if [[ $length_exit -eq 1 ]]; then
                exit
        fi
        if [[ $length == "" ]]; then
                PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${password_length}" > /dev/null;
        else
                PASSWORD_STORE_DIR="${root}" pass generate ${symbols} -i "$selected_password" "${length}" > /dev/null;
        fi
}

# main Menu
mainMenu () {
        if [[ $1 == "--bmarks" ]]; then
                selected_password="$(list_passwords 2>/dev/null \
                        | _rofi -mesg "Bookmarks Mode. ${switch} to switch" \
                        -dmenu \
                        -kb-custom-10 "${switch}" \
                        -select "$entry" \
                        -p "rofi-pass > ")"

                rofi_exit=$?

                if [[ $rofi_exit -eq 1 ]]; then
                        exit
                elif [[ $rofi_exit -eq 19 ]]; then
                        ${basecommand}
                elif [[ $rofi_exit -eq 0 ]]; then
                        openURL
                fi
        else
                unset selected_password

                args=( -dmenu
                        -kb-custom-1 "${autotype}"
                        -kb-custom-2 "${type_user}"
                        -kb-custom-3 "${type_pass}"
                        -kb-custom-4 "${open_url}"
                        -kb-custom-5 "${copy_name}"
                        -kb-custom-6 "${copy_pass}"
                        -kb-custom-7 "${show}"
                        -kb-custom-8 "${copy_url}"
                        -kb-custom-9 "${type_menu}"
                        -kb-custom-10 "${previous_root}"
                        -kb-custom-11 "${next_root}"
                        -kb-custom-14 "${action_menu}"
                        -kb-custom-15 "${copy_menu}"
                        -kb-custom-16 "${help}"
                        -kb-custom-17 "${switch}"
                        -kb-custom-18 "${insert_pass}"
                        -kb-custom-19 "${qrcode}"
                )
                args+=( -kb-mode-previous ""    # These keyboard shortcut options are needed, because
                -kb-mode-next ""            # Shift+<Left|Right> are otherwise taken by rofi.
                -select "$entry"
                -p "> "	)

                if [[ ${#roots[@]} -gt "1" || $custom_root == "true" ]]; then
                        args+=(-mesg "PW Store: ${root}")
                fi

                selected_password="$(list_passwords 2>/dev/null | _rofi "${args[@]}")"

                rofi_exit=$?
                if [[ $rofi_exit -eq 1 ]]; then
                        exit
                fi

                # Actions based on exit code, which do not need the entry.
                # The exit code for -kb-custom-X is X+9.
                case "${rofi_exit}" in
                        19) roots_index=$(( (roots_index-1+roots_length) % roots_length)); root=${roots[$roots_index]}; mainMenu; return;;
                        20) roots_index=$(( (roots_index+1) % roots_length)); root=${roots[$roots_index]}; mainMenu; return;;
                        25) helpMenu; return;;
                        26) ${basecommand} --bmarks; return;;
                esac

                mapfile -t password_temp < <(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
                password=${password_temp[0]}

                if [[ ${password} == "#FILE="* ]]; then
                        pass_file="${password#*=}"
                        mapfile -t password_temp2 < <(PASSWORD_STORE_DIR="${root}" pass show "${pass_file}")
                        password=${password_temp2[0]}
                fi

                fields=$(printf '%s\n' "${password_temp[@]:1}" | awk '$1 ~ /:$/ || /otpauth:\/\// {$1=$1;print}')
                declare -A stuff
                stuff["pass"]=${password}

                if [[ -n $fields ]]; then
                        while read -r LINE; do
                                unset _id _val
                                case "$LINE" in
                                        "otpauth://"*|"${OTPmethod_field}"*)
                                                _id="OTP"
                                                _val=""
                                                ;;
                                        *)
                                                _id="${LINE%%: *}"
                                                _val="${LINE#* }"
                                                ;;
                                esac

                                if [[ -n "$_id" ]]; then
                                        stuff["${_id}"]=${_val}
                                fi
                        done < <(printf '%s\n' "${fields}")

                        if test "${stuff['autotype']+autotype}"; then
                                :
                        else
                                stuff["autotype"]="${USERNAME_field} :tab pass"
                        fi
                fi
        fi

        if [[ -z "${stuff["${AUTOTYPE_field}"]}" ]]; then
                if [[ -n $default_autotype ]]; then
                        stuff["${AUTOTYPE_field}"]="${default_autotype}"
                fi
        fi
        if [[ -z "${stuff["${USERNAME_field}"]}" ]]; then
                if [[ -n $default_user ]]; then
                        if [[ "$default_user" == ":filename" ]]; then
                                stuff["${USERNAME_field}"]="$(basename "$selected_password")"
                        else
                                stuff["${USERNAME_field}"]="${default_user}"
                        fi
                fi
        fi
        pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"

        # actions based on keypresses
        # The exit code for -kb-custom-X is X+9.
        case "${rofi_exit}" in
                0) typeMenu;;
                10) sleep $wait; autopass;;
                11) sleep $wait; typeUser;;
                12) sleep $wait; typePass;;
                13) openURL;;
                14) copyUser;;
                15) copyPass;;
                16) viewEntry;;
                17) copyURL;;
                18) default_do="menu" typeMenu;;
                23) actionMenu;;
                24) copyMenu;;
                27) insertPass;;
                28) generateQrCode;;
        esac
        clearUp
}


clearUp () {
        password=''
        selected_password=''
        unset stuff
        unset password
        unset selected_password
        unset password_temp
        unset stuff
}

helpMenu () {
        _rofi -dmenu -mesg "Hint: All hotkeys are configurable in config file" -p "Help > " <<- EOM
        ${autotype}: Autotype
        ${type_user}: Type Username
        ${type_pass}: Type Password
        ${qrcode}: Generate and display qrcode
        ---
        ${copy_name}: Copy Username
        ${copy_pass}: Copy Password
        ${copy_url}: Copy URL
        ${open_url}: Open URL
        ${copy_menu}: Copy Custom Field
        ---
        ${action_menu}: Edit, Move, Delete, Re-generate Submenu
        ${show}: Show Password File
        ${insert_pass}: Insert new Pass Entry
        ${switch}: Switch Pass/Bookmark Mode
        ---
        ${previous_root}: Switch to previous password store (--root)
        ${next_root}: Switch to next password store (--root)
EOM
help_val=$?

if [[ $help_val -eq 1 ]]; then
        exit;
else
        unset helptext; mainMenu;
fi
}


typeMenu () {
        if [[ -n $default_do ]]; then
                if [[ $default_do == "menu" ]]; then
                        checkIfPass
                        local -a keys=("${!stuff[@]}")
                        keys=("${keys[@]/$AUTOTYPE_field}")
                        typefield=$({ printf '%s' "${AUTOTYPE_field}" ; printf '%s\n' "${keys[@]}" | sort; } | _rofi -dmenu  -p "Choose Field to type > ")
                        typefield_exit=$?
                        if [[ $typefield_exit -eq 1 ]]; then
                                exit
                        fi
                        case "$typefield" in
                                '') exit;;
                                'pass') sleep $wait; typePass;;
                                "${AUTOTYPE_field}") sleep $wait; autopass;;
                                *) sleep $wait; typeField
                        esac
                        clearUp
                elif [[ $default_do == "${AUTOTYPE_field}" ]]; then
                        sleep $wait; autopass
                else
                        ${default_do}
                fi
        fi
}

copyMenu () {
        checkIfPass
        copyfield=$(printf '%s\n' "${!stuff[@]}" | sort | _rofi -dmenu  -p "Choose Field to copy > ")
        val=$?
        if [[ $val -eq 1 ]]; then
                exit;
        fi
        if [[ $copyfield == "pass" ]]; then
                copyPass;
        else
                copyField
        fi
        clearUp
}

actionMenu () {
        checkIfPass
        action_content=("< Return"
                "---"
                "1 Move Password File"
                "2 Copy Password File"
                "3 Delete Password File"
                "4 Edit Password File"
                "5 Generate New Password"
        )

        action=$(printf '%s\n' "${action_content[@]}" | _rofi -dmenu -p "Choose Action > ")
        if [[ ${action} == "1 Move Password File" ]]; then
                manageEntry move;
        elif [[ ${action} == "3 Delete Password File" ]]; then
                manageEntry delete;
        elif [[ ${action} == "2 Copy Password File" ]]; then
                manageEntry copy;
        elif [[ ${action} == "4 Edit Password File" ]]; then
                manageEntry edit;
        elif [[ ${action} == "5 Generate New Password" ]]; then
                generatePass;
        elif [[ ${action} == "< Return" ]]; then
                mainMenu;
        elif [[ ${action} == "" ]]; then
                exit
        fi
}

showEntry () {
        if [[ -z $pass_content ]]; then
                pass_temp=$(PASSWORD_STORE_DIR="${root}" pass show "$selected_password")
                password="${pass_temp%%$'\n'*}"
                pass_key_value=$(printf '%s\n' "${pass_temp}" | tail -n+2 | grep ': ')
                declare -A stuff

                while read -r LINE; do
                        _id="${LINE%%: *}"
                        _val="${LINE#* }"
                        stuff["${_id}"]=${_val}
                done < <(printf '%s\n' "${pass_key_value}")

                stuff["pass"]=${password}

                if test "${stuff['autotype']+autotype}"; then
                        :
                else
                        stuff["autotype"]="${USERNAME_field} :tab pass"
                fi

                pass_content="$(for key in "${!stuff[@]}"; do printf '%s\n' "${key}: ${stuff[$key]}"; done)"
        fi

        bla_content=("< Return"
                "${pass_content}"
        )

        bla=$(printf '%s\n' "${bla_content[@]}" | _rofi -dmenu -mesg "Enter: Copy entry to clipboard" -p "> ")
        rofi_exit=$?

        word=$(printf '%s' "$bla" | gawk -F': ' '{print $1}')

        if [[ ${rofi_exit} -eq 1 ]]; then
                exit
        elif [[ ${rofi_exit} -eq 0 ]]; then
                if [[ ${bla} == "< Return" ]]; then
                        mainMenu
                else
                        if [[ -z $(printf '%s' "${stuff[${word}]}") ]]; then
                                printf '%s' "$word" | doClip
                        else
                                printf '%s' "${stuff[${word}]}" | doClip
                        fi
                        if [[ $notify == "true" ]]; then
                                notify-send "rofi-pass" "Copied Password\\nClearing in $clip_clear seconds"
                        fi
                        if [[ $notify == "true" ]]; then
                                (sleep $clip_clear; printf '%s' "" | ${clip_in_primary}; printf '%s' "" | ${clip_in_clipboard} | notify-send "rofi-pass" "Clipboard cleared") &
                        elif [[ $notify == "false" ]];  then
                                (sleep $clip_clear; printf '%s' "" | ${clip_in_primary}; printf '%s' "" | ${clip_in_clipboard}) &
                        fi
                        exit
                fi
        fi
        exit
        unset stuff
        unset password
        unset selected_password
        unset password_temp
        unset stuff
        exit
}

manageEntry () {
        if [[ "$1" == "edit" ]]; then
                EDITOR=$EDITOR PASSWORD_STORE_DIR="${root}" pass edit "${selected_password}"
                mainMenu
        elif [[ $1 == "move" ]]; then
                cd "${root}" || exit
                group_array=(*/)
                group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
                if [[ $group == "" ]]; then
                        exit
                fi
                PASSWORD_STORE_DIR="${root}" pass mv "$selected_password" "${group}"
                mainMenu
        elif [[ $1 == "copy" ]]; then
                cd "${root}" || exit
                group_array=(*/)
                group=$(printf '%s\n' "${group_array[@]%/}" | _rofi -dmenu -p "Choose Group > ")
                if [[ $group == "" ]]; then
                        exit
                else
                        new_name="$(listgpg | _rofi -dmenu -format 'f' -mesg "Copying to same Group. Please enter a name for the new entry" -p "> ")"
                fi
                PASSWORD_STORE_DIR="${root}" pass cp "$selected_password" "${group}/${new_name}"
                mainMenu
        elif [[ "$1" == "delete" ]]; then
                HELP="<span$help_color_attribute>Selected entry: ${selected_password}</span>"
                ask_content=("Yes"
                        "No"
                )
                ask=$(printf '%s\n' "${ask_content[@]}" | _rofi -mesg "${HELP}" -dmenu -p "Are You Sure? > ")
                if [[ "$ask" == "Yes" ]]; then
                        PASSWORD_STORE_DIR="${root}" pass rm --force "${selected_password}"
                elif [[ "$ask" == "No" ]]; then
                        mainMenu
                elif [[ -z "$ask" ]]; then
                        exit
                fi
        else
                mainMenu
        fi
}

edit_pass() {
    if [[ $edit_new_pass == "true" ]]; then
        PASSWORD_STORE_DIR="${root}" pass edit "${1}"
    fi
}

insertPass () {
        url=$(${clip_out_clipboard})

        if [[ "${url:0:4}" == "http" ]]; then
                domain_name="$(printf '%s\n' "${url}" | awk -F / '{l=split($3,a,"."); print (a[l-1]=="com"?a[l-2] OFS:X) a[l-1] OFS a[l]}' OFS=".")"
                help_content="Domain: ${domain_name}
                Type name, make sure it is unique"
        else
                help_content="Hint: Copy URL to clipboard before calling this menu.
                Type name, make sure it is unique"
        fi

        cd "${root}" || exit
        group_array=(*/)
        grouplist=$(printf '%s\n' "${group_array[@]%/}")
        name="$(listgpg | _rofi -dmenu -format 'f' -filter "${domain_name}" -mesg "${help_content}" -p "> ")"
        val=$?

        if [[ $val -eq 1 ]]; then
                exit
        fi

        user_content=("${default_user2}"
                "${USER}"
                "${default_user}"
        )

        user=$(printf '%s\n' "${user_content[@]}" | _rofi -dmenu -mesg "Chose Username or type" -p "> ")
        val=$?

        if [[ $val -eq 1 ]]; then
                exit
        fi

        group_content=("No Group"
                "---"
                "${grouplist}"
        )

        group=$(printf '%s\n' "${group_content[@]}" | _rofi -dmenu -p "Choose Group > ")
        val=$?

        if [[ $val -eq 1 ]]; then
                exit
        fi

        pw=$(printf '%s' "Generate" | _rofi -dmenu -password -p "Password > " -mesg "Type Password or hit Enter to generate one")

        if [[ $pw == "Generate" ]]; then
                pw=$(_pwgen "${password_length}")
        fi

        clear

        if [[ "$group" == "No Group" ]]; then
                if [[ $url == http* ]]; then
                        pass_content=("${pw}"
                                "---"
                                "${USERNAME_field}: ${user}"
                                "${URL_field}: ${url}"
                        )
                        printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && edit_pass "${name}"
                else
                        pass_content=("${pw}"
                                "---"
                                "${USERNAME_field}: ${user}"
                        )
                        printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${name}" > /dev/null && edit_pass "${name}"
                fi
        else
                if [[ $url == http* ]]; then
                        pass_content=("${pw}"
                                "---"
                                "${USERNAME_field}: ${user}"
                                "${URL_field}: ${url}"
                        )
                        printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null && edit_pass "${group}/${name}"
                else
                        pass_content=("${pw}"
                                "---"
                                "${USERNAME_field}: ${user}"
                        )
                        printf '%s\n' "${pass_content[@]}" | PASSWORD_STORE_DIR="${root}" pass insert -m "${group}/${name}" > /dev/null && edit_pass "${group}/${name}"
                fi
        fi
}

help_msg () {
        cat <<'EOF'
        Usage:
        rofi-pass [command]

        Commands:
        --insert         insert new entry to password store
        --root           set custom root directories (colon separated)
        --last-used      highlight last used item
        --show-last      show details of last used Entry
        --bmarks         start in bookmarks mode

        rofi-pass version 1.5.3
EOF
}

get_config_file () {
        configs=("$ROFI_PASS_CONFIG"
                "$config_dir/rofi-pass/config"
                "/etc/rofi-pass.conf")

        # return the first config file with a valid path
        for config in "${configs[@]}"; do
                # '-n' is needed in case ROFI_PASS_CONFIG is not set
                if [[ -n "${config}" && -f "${config}" ]]; then
                        printf "%s" "$config"
                        return
                fi
        done
}

main () {
        # load config file
        config_file="$(get_config_file)"
        [[ -n "$config_file" ]] && source "$config_file"

        # create tmp dir
        if [[ ! -d "$cache_dir/rofi-pass" ]]; then
                mkdir -p "$cache_dir/rofi-pass"
        fi

        # set backends
        clip_in_primary=_clip_in_primary_${clipboard_backend}
        clip_in_clipboard=_clip_in_clipboard_${clipboard_backend}
        clip_out_primary=_clip_out_primary_${clipboard_backend}
        clip_out_clipboard=_clip_out_clipboard_${clipboard_backend}

        do_type=_do_type_${backend}
        do_press_key=_do_press_key_${backend}

        # backwards compat
        if [[ -n "$xdotool_delay" ]]; then
                >&2 echo "Setting 'xdotool_delay' is deprecated. Please update your configuration to use 'type_delay' instead"
                type_delay=${xdotool_delay}
        fi

        # Only valid for the xdotool backend
        if [[ $backend == "xdotool" ]]; then
                # fix keyboard layout if enabled in config
                if [[ $fix_layout == "true" ]]; then
                        layout_cmd
                fi
        fi

        # set help color
        if [[ $help_color == "" ]]; then
                help_color_attribute=""
        else
                help_color_attribute=" color='$help_color'"
        fi

        # check for BROWSER variable, use xdg-open as fallback
        if [[ -z $BROWSER ]]; then
                export BROWSER=xdg-open
        fi

        # check if alternative root directory was given on commandline
        if [[ -r "$cache_dir/rofi-pass/last_used" ]] && [[ $1 == "--last-used" || $1 == "--show-last" ]]; then
                roots=("$(awk -F ': ' '{ print $1 }' "$cache_dir/rofi-pass/last_used")")
        elif [[ -n "$2" && "$1" == "--root" ]]; then
                custom_root=true; IFS=: read -r -a roots <<< "$2"
        elif [[ -n $root ]]; then
                custom_root=true; IFS=: read -r -a roots <<< "${root}"
        elif [[ -n ${PASSWORD_STORE_DIR} ]]; then
                roots=("${PASSWORD_STORE_DIR}")
        else
                roots=("$HOME/.password-store")
        fi
        roots_index=0
        roots_length=${#roots[@]}
        export root=${roots[$roots_index]}
        export PASSWORD_STORE_DIR="${root}"
        case $1 in
                --insert)
                        insertPass
                        ;;
                --root)
                        mainMenu
                        ;;
                --help)
                        help_msg
                        ;;
                --last-used)
                        if [[ -r "$cache_dir/rofi-pass/last_used" ]]; then
                                entry="$(awk -F ': ' '{ print $2 }' "$cache_dir/rofi-pass/last_used")"
                        fi
                        mainMenu
                        ;;
                --show-last)
                        if [[ -r "$cache_dir/rofi-pass/last_used" ]]; then
                                selected_password="$(awk -F ': ' '{ print $2 }' "$cache_dir/rofi-pass/last_used")" viewEntry
                        else
                                mainMenu
                        fi
                        ;;
                --bmarks)
                        mainMenu --bmarks;
                        ;;
                *)
                        mainMenu
                        ;;
        esac
}

main "$@"