#compdef john

local curcontext="$curcontext" state line
typeset -A opt_args

_arguments -C -s \
  '(--help)'{--help,-h}'[display help]' \
  '(--single)'--single'[use single crack mode]' \
  '(--single-seed)'--single-seed='[add static seed words for all salts in single mode]' \
  '(--single-wordlist)'--single-wordlist=-'[short wordlist with static seed words/morphemes]:wordlist to use:_files' \
  '(--single-user-seed)'--single-wordlist=-'[short wordlist with static seed words/morphemes]:user seed file:_files' \
  '(--single-retest-guess)'--single-retest-guess=-'[override config for SingleRetestGuess]:boolean yes/no' \
  '(--loopback,--wordlist,-w)'{--wordlist,--wordlist=-,-w,-w=-,-w\:-}'[use wordlist]:wordlist to use:_files' \
  '(--loopback,--wordlist,-w)'{--loopback,--loopback=-}'[like --wordlist, but fetch words from a .pot file]:loopback to use:_files' \
  '(--incremental,-w,--wordlist,--stdin,-i,--markov)'{--incremental,--incremental=-,-i,-i=-,-i\:-}'[incremental mode]:incremental section to use' \
  '(--incremental,-w,--wordlist,-r,--rule,--stdin,-i,--markov)'{--markov,--markov=-}'[markov mode]:options for markov mode' \
  '(--mem-file-size)'--mem-file-size=-'[size threshold for wordlist preload (default 5 MB)]:memory (default 5 MB)' \
  '(--dupe-suppression)'--dupe-suppression'[suppress all dupes in wordlist (and force preload]' \
  '(--prince)'--prince=-'[PRINCE mode, read words from FILE]:prince file to use:_files' \
  '(--prince-loopback)'--prince-loopback=-'[fetch words from a .pot file]:pot file to use:_files' \
  '(--prince-elem-cnt-min)'--prince-elem-cnt-min=-'[minimum number of elements per chain (1)]:number' \
  '(--prince-elem-cnt-max)'--prince-elem-cnt-max=-'[maximum number of elements per chain (1)]:number' \
  '(--prince-skip)'--prince-skip=-'[initial skip]:boolean yes/no' \
  '(--prince-limit)'--prince-limit=-'[limit number of candidates generated]:boolean yes/no' \
  '(--prince-wl-dist-len)'--prince-wl-dist-len'[calculate length distribution from wordlist]' \
  '(--prince-wl-max)'--prince-wl-max='[calculate length distribution from wordlist]:number' \
  '(--prince-case-permute)'--prince-case-permute'[permute case of first letter]' \
  '(--prince-mmap)'--prince-mmap'[memory-map infile (not available with case permute)]' \
  '(--prince-keyspace)'--prince-keyspace'[just show total keyspace that would be produced]' \
  '(--encoding)'{--encoding=-,--input-encoding=-}'[input data is non-ascii (eg. UTF-8, ISO-8859-1)]:encoding to use:->list-encodings' \
  '(--rules,-r,--stdin)'{--rules=-,-r=-}'[use rule]:rule to use:->list-rules' \
  '(--rules-stack)'--rules-stack='[stacked rules]' \
  '(--rules-skip-nop)'--rules-skip-nop='[skip any NOP ":" rules (you already ran w/o rules]' \
  '(--mask)'--mask='[mask mode using MASK (or default from john.conf)]' \
  '(--mkv-stats)'--mkv-stats=-'[markov stats file (see doc/MARKOV)]:markov stats file:_files' \
  '(--external)'--external=-'[external mode or word filter]:external mode to use:->list-externals' \
  '(--subsets)'--subsets=-'["subsets" mode (see doc/SUBSETS)]' \
  '(--subsets-required)'--subsets-required=-'[The N first characters of "subsets" charset are the "required set"]' \
  '(--subsets-min-diff)'--subsets-min-diff=-'[Minimum unique characters in subset]' \
  '(--subsets-max-diff)'--subsets-max-diff=-'[Maximum unique characters in subset]' \
  '(--stdout)'{--stdout,--stdout=-}'[just output candidate passwords]:cut at LENGTH' \
  '(--config,-c)'{--config=-,-c=-}'[use config]:config to use:_files' \
  '(--restore)'{--restore,--restore=-}'[restore an interrupted session]:name of session' \
  '(--session)'{--session,--session=-}'[give a new session the NAME]:name of session' \
  '(--status)'{--status,--status=-}'[print status of a session]:name of session' \
  '(--reject-printable)'--reject-printable'[reject printable binaries]' \
  '(--stress-test)'--stress-test'[loop self tests forever]' \
  '(--no-mask)'--no-mask'[used with --test for alternate benchmark w/o mask]' \
  '(--skip-self-tests)'--skip-self-tests'[skip self tests]' \
  '(--test-full)'--test-full'[run more thorough self-tests]' \
  '(--users)'--users=-'[do not load these users only]:user login or uid' \
  '(--groups)'--groups=-'[do not load these group only]:group gid' \
  '(--salts)'--salts=-'[load salts with(out) COUNT (to MAX) hashes]:salts' \
  '(--costs)'--costs=-'[load salts with(out) cost value Cn (to Mn)]:costs' \
  '(--make-charset)'--make-charset=-'[make a charset file. It will be overwritten]:charset file:_files' \
  '(--pot)'--pot=-'[pot file to use]:pot file:_files' \
  '(--node)'--node=-"[this node's number range out of TOTAL count]:number" \
  '(--subformat)'--subformat=-'[pick a benchmark format for --format=crypt]:format to use:->list-formats' \
  '(--mkpc)'--mkpc=-'[request a lower max. keys per crypt]:number' \
  '(--min-length)'--min-length=-'[request a minimum candidate length in bytes]:number' \
  '(--max-length)'--max-length=-'[request a maximum candidate length in bytes]:number' \
  '(--length)'--length=-'[shortcut for --min-len=N --max-len=N]:number' \
  '(--field-separator-char)'--field-separator-char=-'[use "C" instead of ":" in input and pot files]:char' \
  '(--verbosity)'--verbosity=-'[change verbosity (1-5 or 6 for debug, default 3)]:number' \
  '(--show)'{--show,--show=LEFT}'[show cracked passwords (if =LEFT, then uncracked)]' \
  '(--format)'--format=-'[use specific format]:format to use:->list-formats' \
  '(--save-memory)'--save-memory=-'[Enable memory saving, at LEVEL 1..3]:LEVEL 1..3' \
  '(--max-run-time)'--max-run-time=-'[gracefully exit after this many seconds]:number of seconds' \
  '(--regen-lost-salts=)'--regen-lost-salts=-'[regenerate lost salts (see doc/OPTIONS)]:number' \
  '(--platform=)'--platform=-'[set OpenCL platform]:OpenCL platform' \
  '(--device=)'--device=-'[set OpenCL device (list using --list=opencl-devices)]:OpenCL device number' \
  '(--list)'--list=-'[list capabilities]:capabilities to list:->list-help' \
  '(--pipe,--stdin,--wordlist,-w)'--pipe'[read from pipe/stdin but with rules]' \
  '(--dupe-suppression)'--dupe-suppression'[suppress all dupes in wordlist (and force preload)]' \
  '(--bare-always-valid)'--bare-always-valid='[treat bare hashes as valid (Y/N)]:boolean yes/no' \
  '(--no-log)'--no-log'[disables creation and writing to john.log file]' \
  '(--log-stderr)'--log-stderr'[log to screen instead of file]' \
  '(--progress-every)'--progress-every='[emit a status line every N seconds]:number' \
  '(--crack-status)'--crack-status'[emit a status line whenever a password is cracked]' \
  '(--keep-guessing)'--keep-guessing'[try finding plaintext collisions]' \
  '(--no-keep-guessing)'--no-keep-guessing'[do not try finding plaintext collisions]' \
  '(--max-candidates)'--max-candidates='[gracefully exit after this many candidates tried]:number' \
  '(--max-run-time)'--max-run-time='[gracefully exit after this many seconds, if negative reset number on each crack]:number' \
  '(--regen-lost-salts)'--regen-lost-salts='[brute force unknown salts]' \
  '(--internal-codepage)'--internal-codepage='[codepage used in rules/masks]' \
  '(--tuning)'--tuning='[tuning options (auto/report/N)]' \
  '(--fork)'--fork='[fork N processes]:number' \
  '*:files:_files' && return 0

local ret

case "$state" in
  list-rules)
    if (( $+opt_args[--config] )); then
      vals=( help ${(f)"$(_call_program list-rules john --config=$opt_args[--config] --list=rules 2>/dev/null)"/	/:} )
      _describe -t list-rules 'list rules' vals && ret=0
    else
      vals=( help ${(f)"$(_call_program list-rules john --list=rules 2>/dev/null)"/	/:} )
      _describe -t list-rules 'list rules' vals && ret=0
    fi
    ;;

  list-externals)
    if (( $+opt_args[--config] )); then
      vals=( help ${(f)"$(_call_program list-externals john --config=$opt_args[--config] --list=externals 2>/dev/null)"/	/:} )
      _describe -t list-rules 'list externals' vals && ret=0
    else
      vals=( help ${(f)"$(_call_program list-externals john --list=externals 2>/dev/null)"/	/:} )
      _describe -t list-rules 'list externals' vals && ret=0
    fi
    ;;
  list-encodings)
    vals=( help ${(f)"$(_call_program list-encodings john --list=encodings 2>&1 \
	|grep -v '^Supported encodings within john are:' | sed -e 's/, /\
/g' -e 's/,$//' | sed '/^$/d' | sort)"} )
    _describe -t list-encodings 'list encodings' vals && ret=0
    ;;
  list-formats)
    vals=( help ${(f)"$(_call_program list-formats john --list=formats 2>/dev/null \
	|sed -e 's/, /\
/g' | sed '/^$/d' | sort)"} )
    _describe -t list-formats 'list formats' vals && ret=0
    ;;
  list-help)
    vals=( help ${(f)"$(_call_program list-help john --list=help 2>/dev/null \
	|sed -e 's/, /\
/g' -e 's/,$//' | sed -e '/<conf section name>/d' -e '/\:SECTION/d' -e '/^$/d' -e '/\[.*\]/d' | sort)"} )
    _describe -t list-help 'list help' vals && ret=0
    ;;
esac

return ret
