#!/bin/bash
#       Name: SearchSploit - Exploit-DB's CLI search tool
#    Version: 4.0.6 (2020-04-06)
# Written by: Offensive Security, Unix-Ninja, and g0tmi1k
#   Homepage: https://github.com/offensive-security/exploitdb
#     Manual: https://www.exploit-db.com/searchsploit
#
## NOTE:
#   Exit code '0' means finished normally
#   Exit code '1' means something went wrong
#   Exit code '2' means help screen
#   Exit code '6' means updated packages (APT, brew or Git)
#-----------------------------------------------------------------------------#


## Settings File
rc_file=""


## Default options
CLIPBOARD=0
COLOUR=1
EDBID=0
EXACT=0
EXAMINE=0
FILEPATH=1
GETPATH=0
JSON=0
MIRROR=0
OVERFLOW=0
SCASE=0
VERBOSE=0
WEBLINK=0
XML=0
COLOUR_TAG=""
TAGS=""
SEARCH=""
EXCLUDE=""
CASE_TAG_GREP="-i"
CASE_TAG_FGREP="tolower"
AWK_SEARCH=""
COLOUR_OFF_GREP=
COLOUR_ON_GREP=


## Check if our grep supports --color
if grep --help 2>&1 | grep "[-]-color" >/dev/null 2>&1 ; then
  COLOUR_OFF_GREP="--color=never"
  COLOUR_ON_GREP="--color=always"
fi


## Set LANG variable to avoid illegal byte sequence errors
LANG=C


## Usage info
function usage()
{
  echo "  Usage: ${progname} [options] term1 [term2] ... [termN]"
  echo ""
  echo "=========="
  echo " Examples "
  echo "=========="
  echo "  ${progname} afd windows local"
  echo "  ${progname} -t oracle windows"
  echo "  ${progname} -p 39446"
  echo "  ${progname} linux kernel 3.2 --exclude=\"(PoC)|/dos/\""
  echo "  ${progname} linux reverse password"
  echo ""
  echo "  For more examples, see the manual: https://www.exploit-db.com/searchsploit"
  echo ""
  echo "========="
  echo " Options "
  echo "========="
  echo "   -c, --case     [Term]      Perform a case-sensitive search (Default is inSEnsITiVe)"
  echo "   -e, --exact    [Term]      Perform an EXACT match on exploit title (Default is AND) [Implies \"-t\"]"
  echo "   -h, --help                 Show this help screen"
  echo "   -j, --json     [Term]      Show result in JSON format"
  echo "   -m, --mirror   [EDB-ID]    Mirror (aka copies) an exploit to the current working directory"
  echo "   -o, --overflow [Term]      Exploit titles are allowed to overflow their columns"
  echo "   -p, --path     [EDB-ID]    Show the full path to an exploit (and also copies the path to the clipboard if possible)"
  echo "   -t, --title    [Term]      Search JUST the exploit title (Default is title AND the file's path)"
  echo "   -u, --update               Check for and install any exploitdb package updates (deb or git)"
  echo "   -w, --www      [Term]      Show URLs to Exploit-DB.com rather than the local path"
  echo "   -x, --examine  [EDB-ID]    Examine (aka opens) the exploit using \$PAGER"
  echo "       --colour               Disable colour highlighting in search results"
  echo "       --id                   Display the EDB-ID value rather than local path"
  echo "       --nmap     [file.xml]  Checks all results in Nmap's XML output with service version (e.g.: nmap -sV -oX file.xml)"
  echo "                                Use \"-v\" (verbose) to try even more combinations"
  echo "       --exclude=\"term\"       Remove values from results. By using \"|\" to separate, you can chain multiple values"
  echo "                                e.g. --exclude=\"term1|term2|term3\""
  echo ""
  echo "======="
  echo " Notes "
  echo "======="
  echo " * You can use any number of search terms"
  echo " * Search terms are not case-sensitive (by default), and ordering is irrelevant"
  echo "   * Use '-c' if you wish to reduce results by case-sensitive searching"
  echo "   * And/Or '-e' if you wish to filter results by using an exact match"
  echo " * Use '-t' to exclude the file's path to filter the search results"
  echo "   * Remove false positives (especially when searching using numbers - i.e. versions)"
  echo " * When updating or displaying help, search terms will be ignored"
  echo ""
  exit 2
}


## Update database check
function update()
{
  arraylength="${#files_array[@]}"
  for (( i=0; i<${arraylength}; i++ )); do
    ## Check to see if we already have the value
    [[ "${tmp_package[*]}" =~ "${package_array[${i}]}" ]] \
      && continue

    ## Else save all the information
    tmp_git+=("${git_array[${i}]}")
    tmp_path+=("${path_array[${i}]}")
    tmp_package+=("${package_array[${i}]}")
  done


  ## Loop around all the new arrays
  arraylength="${#tmp_git[@]}"
  for (( i=0; i<${arraylength}; i++ )); do
    git="${tmp_git[${i}]}"
    path="${tmp_path[${i}]}"
    package="${tmp_package[${i}]}"

    ## Update from the repos (e.g. Kali)
    apt-cache search "${package}" 2>/dev/null >/dev/null       #dpkg -l "${package}" 2>/dev/null >/dev/null
    if [[ "$?" == "0" ]]; then
      updatedeb "${package}"
    else
      ## Update from homebrew (e.g. OSX)
      brew 2>/dev/null >/dev/null
      if [[ "$?" == "0" ]]; then
        ## This only really only updates "./searchsploit". The rest (can) come via git as its updated more frequently
        updatedbrew "${package}"
      fi

      ## Update via Git
      updategit "${package}" "${path}" "${git}"
    fi
  done

  ## Done
  exit 6
}


## Update database (via .deb/apt)
function updatedeb()
{
  package_in="${1}"

  echo -e "[i] Updating via apt package management (Expect weekly-ish updates): ${package_in}\n"

  sudo apt update \
    || echo -e "\n[-] Issue with apt update (Please check network connectivity & apt SourcesList values)" 1>&2
  sudo apt -y install "${package_in}" \
    || echo -e "\n[-] Issue with apt upgrade" 1>&2

  echo -e "\n[*] apt update finished"
}


## Update database (via homebrew)
function updatedbrew()
{
  package_in="${1}"

  echo -e "[i] Updating via brew package management\n"

  brew update \
    || echo -e "\n[-] Issue with brew update (Please check network connectivity)" 1>&2
  brew upgrade "${package_in}"

  echo -e "\n[*] Brew update finished"
}


## Update database (via Git)
function updategit()
{
  package_in="${1}"
  path_in="${2}"
  git_in="${3}"

  echo -e "[i] Updating via Git (Expect daily updates): ${package_in} ~ ${path_in}\n"

  ## Make sure we are in the correct folder
  mkdir -p "${path_in}/" 2>/dev/null \
    || sudo mkdir -p "${path_in}/"
  cd "${path_in}/"

  ## Are we in a Git repo?
  if [[ "$( git rev-parse --is-inside-work-tree 2>/dev/null )" != "true" ]]; then
    if [[ "$( ls )" = "" ]]; then
      # If directory is empty, just clone
      echo -e "\n[-] Nothing here (${path_in}). Starting fresh..."
      git clone -v "${git_in}" "${path_in}/" 2>/dev/null \
        || sudo git clone -v "${git_in}" "${path_in}/"
    fi
  fi

  # Is our Git remote added? (aka wouldn't be via homebrew method)
  if [[ "$( git remote -v )" != *"upstream"*"${git_in}"* ]]; then
    echo -e "\n[-] Missing Git remote upstream (${git_in})"
    git init 2>/dev/null \
      || sudo git init
    git remote add upstream "${git_in}" 2>/dev/null \
      || sudo git remote add upstream "${git_in}"
  fi

  # Make sure to prep checkout first
  git checkout -- . 2>/dev/null \
    || sudo git checkout -- .

  # Update from git
  echo -e "\n[i] Git pull'ing"
  git pull -v upstream master 2>/dev/null \
    || sudo git pull -v upstream master

  # If conflicts, clean and try again
  if [[ "$?" -ne 0 ]]; then
    echo -e "\n[-] Git conflict"
    git clean -d -fx "" \
      || sudo git clean -d -fx ""
    git pull -v upstream master \
      || sudo git pull -v upstream master
  fi

  echo -e "\n[*] Git update finished"
  echo "[i] Path: ${path_in}/"
}


## Printing dotted lines in the correct manner
function drawline()
{
  printf "%0.s-" $( eval echo {1..$(( COL1 + 1 ))} )
  echo -n " "
  printf "%0.s-" $( eval echo {1..$(( COL2 - 1 ))} )
  echo ""
}


## Used in searchsploitout/nmap's XML
function validterm()
{
  ## Check to see if its any phrases which would give a TON of incorrect results
  if [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "microsoft" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "microsoft windows" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "windows" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "apache" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "ftp" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "http" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "linux" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "net" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "network" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "oracle" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "ssh" ] \
    || [ "$( echo ${1} | tr '[:upper:]' '[:lower:]' )" == "unknown" ]; then
    echo -e "[-] Skipping term: ${1}   (Term is too general. Please re-search manually: $0 ${arg} ${1})\n" 1>&2
    ## Issues, return with something
    return 1
  fi

  ## No issues, return without anything
  return 0
}


## Used in searchsploitout/nmap's XML
function searchsploitout()
{
  ## Make sure there is a value
  [ "${software}" = "" ] \
    && return

  #echo "" 1>&2

  arg="-t"   ## Title search by default!
  [[ "${JSON}" == "1" ]] && arg="${arg} --json"
  [[ "${OVERFLOW}" == "1" ]] && arg="${arg} --overflow"
  [[ "${WEBLINK}" == "1" ]] && arg="${arg} --www"
  [[ "${COLOUR}" != "1" ]] && arg="${arg} --colour"
  [[ "${EDBID}" == "1" ]] && arg="${arg} --id"

  ## Try and remove terms that could confuse searches
  #software=$( echo "${software}" | sed 's_/_ _g' )
  software=$( echo "${software}" | sed -e 's/[^a-zA-Z0-9]/ /g' )

  if [[ "${VERBOSE}" -eq 1 ]]; then
    ## Loop each word?
    tmp=""
    for word in $( echo ${software} ); do
      ## Add current search term on
      tmp="${tmp}${word} "

      ## Check to see if its any phrases which would give a TON of incorrect results
      validterm "${tmp}" \
        || continue

      ## Feedback
      echo "[i] $0 ${arg} ${tmp}" 1>&2
      out=$( bash "$0" ${arg} ${tmp} )

      ## Are there too many results?
      lines=$( echo -e "${out}" | wc -l )
      if [[ "${lines}" -gt 100 ]]; then
        echo -e "[-] Skipping output: ${tmp}   (Too many results. Please re-search manually: $0 ${arg} ${tmp})\n" 1>&2
      ## Are there any results?
      elif [[ "${lines}" -gt 5 ]]; then
        echo -e "${out}\n\n"
      ## If there's no results
      else
        break
      fi
    done

    ## Padding between loops
    echo -e "\n\n" 1>&2
  else
    ## Check to see if its any phrases which would give a TON of incorrect results
    validterm "${software}" \
      || return

    ## Feedback
    echo "[i] $0 ${arg} ${software}" 1>&2
    out=$( bash "$0" ${arg} ${software} )

    ## Are there too many results?
    lines=$( echo -e "${out}" | wc -l )
    if [[ "${lines}" -gt 100 ]]; then
      echo -e "[-] Skipping output: ${software}   (Too many results. Please re-search manually: $0 ${arg} ${software})\n" 1>&2
    ## Are there any results?
    elif [[ "${lines}" -gt 5 ]]; then
      echo -e "${out}\n\n"
    fi
  fi
}


## Read XML file
function nmapxml()
{
  ## Feedback to the end user
  echo -e "[i] Reading: '${FILE}'\n" 1>&2

  ## Read in XMP (IP, name, service and version)
  xmllint --xpath '//address/@addr|//service/@name|//service/@product|//service/@version' "${FILE}" \
    | sed -e $'s/addr=/\\\n[IP] /g; s/name=/\\\n[NAME] /g; s/product=/\\\n[PRODUCT] /g;s/" version="/\\\n[VERSION] /g; s/"//g' \
    | grep -v '\[IP\].*\:' \
    | while read line; do
      type=$( echo "${line}" | cut -d" " -f 1 )
      input=$( echo "${line}" | cut -d" " -f 2- )

      case "${type}" in
        "[IP]")
          #[[ "${VERBOSE}" -eq 1 ]] && echo -e "\n\n\e[32m[*] IP: ${input}\e[39m" 1>&2
          ;;
        "[NAME]")
          ## If we have already looped around and got something, save it before moving onto the current value
          if [[ "${software}" ]]; then
            #searchsploitout
            echo "${software}"
          fi
          ## Something is better than nothing. Will just go on the default service that matches the port.   e.g. domain
          software="${input}"
          ## Might not get any more than this, if -sV failed
          ;;
        "[PRODUCT]")
          ## We have a name, but no version (yet?)   e.g. dnsmasq
          echo "${software}"
          software="${input}"
          echo "${software}"
          ;;
        "[VERSION]")
          software="${software} ${input}"
          ## Name & version. There isn't any more information to get, game over.   e.g. dnsmasq 2.72
          echo "${software}"
          software=
          ;;
      esac
  done | tr '[:upper:]' '[:lower:]' | awk '!x[$0]++' | while read software; do
    searchsploitout
  done
}


## Build search terms
function buildterms()
{
  tag_in="${1}"

  ## If we are to use colour ("--colour"), add the values to search for between "or"
  if [[ "${COLOUR}" -eq 1 ]]; then
    [[ "${COLOUR_TAG}" ]] \
      && COLOUR_TAG="${COLOUR_TAG}|"
    COLOUR_TAG="${COLOUR_TAG}${tag_in}"
  fi

  ## Search both title AND path
  if [[ "${FILEPATH}" -eq 1 ]]; then
    ## Search command for each term (with case sensitive flag, "-c")
    SEARCH="${SEARCH} | grep ${COLOUR_OFF_GREP} -F ${CASE_TAG_GREP} \"${tag_in}\""
  ## Search just the title, NOT the path ("-t"/"-e")
  else
    ## If there is already a value, prepend text to get ready
    [[ "${AWK_SEARCH}" ]] \
      && AWK_SEARCH="${AWK_SEARCH}/ && ${CASE_TAG_FGREP}(\$3) ~ /"

    ## Escape any slashes
    tag_in="$( echo ${tag_in} | sed 's_/_\\/_g' )"

    ## Case sensitive ("-c")?
    if [[ "${SCASE}" -eq 1 ]]; then
      AWK_SEARCH="${AWK_SEARCH}${tag_in}"
    else
      AWK_SEARCH="${AWK_SEARCH}$( echo ${tag_in} | tr '[:upper:]' '[:lower:]' )"
    fi
  fi
}


## Read in the values from files_*.csv
function findresults()
{
  file_in="${1}"
  path_in="${2}"
  name_in="${3}"

  if [[ "${name_in}" == "Paper"* ]]; then
    url="papers"
  elif [[ "${name_in}" == "Shellcode"* ]]; then
    url="shellcodes"
  else
    url="exploits"
  fi


  ## JSON require full options
  if [[ "${JSON}" -eq 1 ]]; then
    ## Read in (id, title, path, date, author, type, platform) separated between commas
    SEARCH="awk -F '[,]' '{print \$1\",\"\$2\",\"\$3\",\"\$4\",\"\$5\",\"\$6\",\"\$7}' \"${path_in}/${file_in}\""
  else
    ## Read in (id, title, path) separated between commas (as these are the only visible fields)
    SEARCH="awk -F '[,]' '{print \$1\",\"\$2\",\"\$3}' \"${path_in}/${file_in}\""
  fi


  ## EXACT search command ("-e")?
  if [[ "${EXACT}" -eq 1 ]]; then
    buildterms "${TAGS}"
  ## or AND search command?
  else
    ## For each term
    for TAG in ${TAGS}; do
      buildterms "${TAG}"
    done
  fi


  ## If we are NOT to use the path name ("-t"/"-e")
  [[ "${FILEPATH}" -eq 0 ]] \
    && SEARCH="${SEARCH} | awk -F '[,]' '${CASE_TAG_FGREP}(\$3) ~ /${AWK_SEARCH}/ {print}'"


  ## If we are to use colour ("--colour"), add the value here
  if [[ "${COLOUR_TAG}" ]] && [[ "${JSON}" -eq 0 ]]; then
    COLOUR_TAG="grep ${COLOUR_ON_GREP} -iE \"${COLOUR_TAG}|$\""
  fi


  ## Dynamically set column widths to the current screen size
  [[ "${WEBLINK}" -eq 1 ]] \
    && COL2=45 \
    || COL2=$(( ${#path_in} + 21 ))
  COL1=$(( $( tput cols ) - COL2 - 1 ))


  ## Search, format, and print results (--overflow)
  if [[ "${OVERFLOW}" -eq 1 ]]; then
    FORMAT_COL1=${COL1}
  else
    FORMAT_COL1=${COL1}'.'${COL1}
  fi

  ## Maximum length COL2 can be
  FORMAT_COL2=$(( ${COL2} - 2 ))

  ## Strip un-wanted values
  SEARCH="${SEARCH} | sed 's/\"//g'"


  ## Remove any terms not wanted from the search
  [[ "${EXCLUDE}" ]] \
    && SEARCH="${SEARCH} | grep -vEi '${EXCLUDE}'"


  ## Magic search Fu
  ## Print JSON format (full options) ("--json")?
  if [[ "${JSON}" -eq 1 ]]; then
    ## Web link format ("--json --www")?
    if [[ "${WEBLINK}" -eq 1 ]]; then
      OUTPUT="$( eval ${SEARCH} \
        | awk -F ',' '{ printf "\\n\\t\\t'{'\"Title\":\"%s\",\"URL\":\"https://www.exploit-db.com/'${url}'/%s\"},", $3, $1 }' )"
    ## Just the EDB-ID ("--json --id")?
    elif [[ "${EDBID}" -eq 1 ]]; then
      OUTPUT="$( eval ${SEARCH} \
        | awk -F ',' '{ printf "\\n\\t\\t'{'\"Title\":\"%s\",\"EDB-ID\":\"%s\",\"Path\":\"'${path_in}/'%s\"},", $3, $1, $2 }' )"
    ## Default JSON ("--json")?
    else
      OUTPUT="$( eval ${SEARCH} \
        | awk -F ',' '{ printf "\\n\\t\\t'{'\"Title\":\"%s\",\"EDB-ID\":\"%s\",\"Date\":\"%s\",\"Author\":\"%s\",\"Type\":\"%s\",\"Platform\":\"%s\",\"Path\":\"'${path_in}/'%s\"},", $3, $1, $4, $5, $6, $7, $2 }' )"
    fi
    OUTPUT="$( echo -e ${OUTPUT} \
      | sort \
      | sed '$ s/,$//' )"
  ## Web link format ("--www")?
  elif [[ "${WEBLINK}" -eq 1 ]]; then
    OUTPUT="$( eval ${SEARCH} \
      | awk -F ',' '{ printf "%-'${FORMAT_COL1}'s | %s\n", $3, "https://www.exploit-db.com/'${url}'/"$1 }' \
      | sort )"
  ## Just the EDB-ID ("--id")?
  elif [[ "${EDBID}" -eq 1 ]]; then
    OUTPUT="$( eval ${SEARCH} \
      | awk -F ',' '{ printf "%-'${FORMAT_COL1}'s | %s\n", $3, $1 }' \
      | sort )"
  ## Default view
  else
    OUTPUT="$( eval ${SEARCH} \
      | awk -F ',' '{ printf "%-'${FORMAT_COL1}'s | %.'${FORMAT_COL2}'s\n", $3, $2 }' \
      | sort )"
  fi


  ## Display colour highlights ("--colour")?
  if [[ "${COLOUR_TAG}" ]] && [[ "${JSON}" -eq 0 ]]; then
    [[ "${OUTPUT}" ]] \
      && OUTPUT=$( echo -e "${OUTPUT}" | eval ${COLOUR_TAG} )
  fi
}


function printresults()
{
  title_in="${1}"
  path_in="${2}"
  json_title="$(echo ${title_in} | tr /a-z/ /A-Z/)"


  ## Print header if in JSON ("--json")
  if [[ "${JSON}" -eq 1 ]]; then
    printf ",\n\t\"DB_PATH_${json_title}\": \"${path_in}\",\n"
    printf "\t\"RESULTS_${json_title}\": ["
  ## ASCII table
  else
    drawline
    printf "%-${COL1}s %s" " ${title_in} Title"
    if [[ "${WEBLINK}" -eq 1 ]]; then
      echo "|  URL"
    elif [[ "${EDBID}" -eq 1 ]]; then
      echo "|  EDB-ID"
    else
      echo "|  Path"
      #echo "    > Results (0)"
      printf "%-${COL1}s "
      echo "| (${path_in}/)"
    fi
    drawline
  fi


  ## Show content
  [[ "${OUTPUT}" ]] \
    && echo "${OUTPUT}"


  ## Print footer if in JSON ("--json")
  if [[ "${JSON}" -eq 1 ]]; then
    printf "\t]"
  else
    drawline
  fi
}


#-----------------------------------------------------------------------------#


## Locate setting file
## User home folder config
if [[ -f "${HOME}/.searchsploit_rc" ]]; then
  rc_file="${HOME}/.searchsploit_rc"
## Global config
elif [[ -f "/etc/searchsploit_rc" ]]; then
  rc_file="/etc/searchsploit_rc"
## Method #1 - File itself
elif [[ -f "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/.searchsploit_rc" ]]; then
  rc_file="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/.searchsploit_rc"
## Method #2 - Symbolic link
elif [[ -f "$( dirname "$( readlink "$0" )" )/.searchsploit_rc" ]]; then
  rc_file="$( dirname "$( readlink "$0" )" )/.searchsploit_rc"
## Manually specified?
elif [[ ! -f "${rc_file}" ]]; then
  echo "[!] Could not find: rc_file ~ ${rc_file}"
  exit 1
fi


## Use config file
source "${rc_file}"


#-----------------------------------------------------------------------------#


## Check for empty arguments
if [[ $# -eq 0 ]]; then
  usage >&2
fi


## Parse long arguments
ARGS="-"
for param in "$@"; do
  if [[ "${param}" == "--case" ]]; then
    SCASE=1
  elif [[ "${param}" == "--exact" ]]; then
    EXACT=1
  elif [[ "${param}" == "--examine" ]] || [[ "${param}" == "--open" ]] || [[ "${param}" == "--view" ]]; then
    GETPATH=1
    EXAMINE=1
  elif [[ "${param}" == "--help" ]]; then
    usage >&2
  elif [[ "${param}" == "--json" ]]; then
    JSON=1
  elif [[ "${param}" == "--mirror" ]] || [[ "${param}" == "--copy" ]] || [[ "${param}" == "--dup" ]] || [[ "${param}" == "--duplicate" ]]; then
    GETPATH=1
    MIRROR=1
  elif [[ "${param}" == "--overflow" ]]; then
    OVERFLOW=1
  elif [[ "${param}" == "--path" ]]; then
    GETPATH=1
    CLIPBOARD=1
  elif [[ "${param}" == "--title" ]]; then
    FILEPATH=0
  elif [[ "${param}" == "--update" ]]; then
    update
  elif [[ "${param}" == "--www" ]]; then
    WEBLINK=1
  elif [[ "${param}" == "--colour" ]] || [[ "${param}" == "--color" ]]; then
    COLOUR=""
  elif [[ "${param}" == "--id" ]]; then
    EDBID=1
  elif [[ "${param}" == "--nmap" ]]; then
    XML=1
  elif [[ "${param}" =~ "--exclude=" ]]; then
    EXCLUDE="$( echo "${param}" | cut -d '=' -f 2- )"
  elif [[ "${param}" == "--verbose" ]]; then
    VERBOSE=1
  else
    if [[ "${param:0:1}" == "-" ]]; then
      ARGS=${ARGS}${param:1}
      shift
      continue
    fi
    TAGS="${TAGS} ${param//\`/_}"
  fi
done


## Parse short arguments
while getopts "cehjmnoptuvwx" arg "${ARGS}"; do
  if [[ "${arg}" = "?" ]]; then
    usage >&2;
  fi
  case ${arg} in
    c) SCASE=1;;
    e) EXACT=1;;
    h) usage >&2;;
    j) JSON=1;;
    m) GETPATH=1; MIRROR=1;;
    n) XML=1;;
    o) OVERFLOW=1;;
    p) GETPATH=1; CLIPBOARD=1;;
    t) FILEPATH=0;;
    u) update;;
    v) VERBOSE=1;;
    w) WEBLINK=1;;
    x) GETPATH=1; EXAMINE=1;;
  esac
  shift $(( OPTIND - 1 ))
done


#-----------------------------------------------------------------------------#


## Check for files_*.csv
arraylength="${#files_array[@]}"
for (( i=0; i<${arraylength}; i++ )); do
  files="${path_array[${i}]}/${files_array[${i}]}"

  if [[ -f "${files}" ]]; then
    continue
  ## Method #1 - File itself
  elif [[ -f "$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)/${files_array[${i}]}" ]]; then
    echo "[i] Found (#1): $(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)/${files_array[${i}]}" 1>&2
    echo "[i] To remove this message, please edit \"${rc_file}\" for \"${files_array[${i}]}\" (package_array: ${package_array[${i}]})" 1>&2
    echo 1>&2
    path_array[${i}]="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)"
  ## Method #2 - Symbolic link
  elif [[ -f "$(dirname "$(readlink "$0")")/${files_array[${i}]}" ]]; then
    echo "[i] Found (#2): $(dirname "$(readlink "$0")")/${files_array[${i}]}" 1>&2
    echo "[i] To remove this message, please edit \"${rc_file}\" for \"${files_array[${i}]}\" (package_array: ${package_array[${i}]})" 1>&2
    echo 1>&2
    path_array[${i}]="$(dirname "$(readlink "$0")")"
  else
    #echo "[!] Could not find: ${files}" 1>&2
    #echo "[i] To remove this message, please remove \"${files_array[${i}]}\" (package_array: ${package_array[${i}]}) from \"${rc_file}\"" 1>&2
    #echo 1>&2
    unset "files_array[${i}]"
    unset "path_array[${i}]"
    unset "name_array[${i}]"
    unset "git_array[${i}]"
    unset "package_array[${i}]"
  fi
done


#-----------------------------------------------------------------------------#


## Read in XML
if [[ "${XML}" -eq 1 ]]; then
  ## Trim white spaces
  FILE=$( echo ${TAGS} | xargs )

  ## Is there a file?
  if [[ ! -f "${FILE}" ]]; then
    echo -e "\n[!] Could not find file: ${FILE}" 1>&2
    exit 1
  fi

  if ! hash xmllint 2>/dev/null; then
    echo -e "\n[!] Please install xmllint" 1>&2
    echo -e "[i]   Kali Linux -> apt -y install libxml2-utils" 1>&2
    exit 1
  fi

  if [[ "${VERBOSE}" -ne 1 ]]; then
    echo "[i] SearchSploit's XML mode (without verbose enabled).   To enable: ${progname} -v --xml..." 1>&2
  fi

  ## Do the magic
  nmapxml

  ## Done
  exit 0
fi


## Print the full path. If pbcopy/xclip is available then copy to the clipboard
if [[ "${GETPATH}" -eq 1 ]]; then
  for exploit in $( echo ${TAGS} ); do
    ## Get EDB-ID from input
    edbdb="$( echo ${exploit} | rev | cut -d '/' -f1 | rev | cut -d'-' -f1 | cut -d'.' -f1 | tr -dc '0-9' )"


    ## Loop until we find something
    arraylength="${#files_array[@]}"
    for (( i=0; i<${arraylength}; i++ )); do
      files="${path_array[${i}]}/${files_array[${i}]}"

      ## Check to see if the files_*.csv has a value
      line=$( grep -m 1 -E "^${edbdb}," "${files}" )

      if [[ "${line}" ]]; then
        path="$( echo $line | cut -d ',' -f 2 )"
        location="${path_array[${i}]}/${path}"
        name="${name_array[${i}]}"

        if [[ "${name}" == "Paper"* ]]; then
          url="papers/${edbdb}"
        elif [[ "${name}" == "Shellcode"* ]]; then
          url="shellcodes/${edbdb}"
        else
          url="exploits/${edbdb}"
        fi

        break
      fi
    done


    ## Did we find the exploit?
    if [[ -f "${location}" ]]; then
      ## Get title
      title=$( grep -m 1 "${path}" "${files}" | cut -d ',' -f 3 | sed 's/"//g' )

      ## File type
      fileinfo="$(file -b "${location}")"

      ## How long is the name?
      PADDING=$(( 9 - ${#name} ))

      ## Display out
      printf "%-${PADDING}s%s"
      echo "${name}: ${title}"
      echo "      URL: https://www.exploit-db.com/${url}"
      echo "     Path: ${location}"
      echo "File Type: ${fileinfo}"
      echo ""

      ## Copy to clipboard?
      if [[ "${CLIPBOARD}" -eq 1 ]]; then
        ## Are any copy programs available?
        if hash xclip 2>/dev/null || hash pbcopy 2>/dev/null; then
          ## Linux (Will require $DISPLAY)
          if hash xclip 2>/dev/null; then
            echo -ne "${location}" | xclip -selection clipboard 2>/dev/null
            echo "Copied EDB-ID   #${edbdb}'s path to the clipboard"
          ## OSX
          elif hash pbcopy 2>/dev/null; then
            echo -ne "${location}" | pbcopy
            echo "Copied EDB-ID #${edbdb}'s path to the clipboard"
          fi
        fi

        ## Done (early!)
        exit 0
      fi

      ## Open the exploit up?
      if [[ "${EXAMINE}" -eq 1 ]]; then
        if [[ "${PAGER}" ]]; then
          /bin/sh -c "${PAGER} ${location}"
        elif [[ -f "$( which pager 2>/dev/null )" ]]; then
          pager "${location}"
        else
          less "${location}"
        fi
        echo -e "\n"
      fi

      if [[ "${MIRROR}" -eq 1 ]]; then
        cp -i "${location}" "$( pwd )/"
        echo "Copied to: $( pwd )/$( basename ${location} )"
        echo -e "\n"
      fi
    else
      ## Feedback
      echo "[!] Could not find EDB-ID #${edbdb}"
      echo -e "\n"
    fi
  done

  ## Done
  exit 0
fi


#-----------------------------------------------------------------------------#


## Are we are doing an exact match ("-e")? If so, do NOT check folder path (Implies "-t").
if [[ "${EXACT}" -eq 1 ]]; then
  FILEPATH=0
fi


## Case sensitive?
if [[ "${SCASE}" -eq 1 ]]; then
  ## Remove the default flags
  CASE_TAG_GREP=""
  CASE_TAG_FGREP=""
fi


## Remove leading space
TAGS="$( echo ${TAGS} | sed -e 's/^[[:space:]]//' )"


#-----------------------------------------------------------------------------#


## Print header if in JSON ("--json")
[[ "${JSON}" -eq 1 ]] \
  && printf "{\n\t\"SEARCH\": \"${TAGS}\""


## Check for files_*.csv
arraylength="${#files_array[@]}"
for (( i=0; i<${arraylength}; i++ )); do
  ## Search
  findresults "${files_array[${i}]}" "${path_array[${i}]}" "${name_array[${i}]}"
  ## Print results if in JSON ("--json") or if there are any results
  if ([[ "${JSON}" -eq 1 ]] || [[ "${OUTPUT}" ]]); then
    printresults "${name_array[${i}]}" "${path_array[${i}]}"
  ## Summary if NOT JSON ("--json")
  elif [[ "${JSON}" -eq 0 ]]; then
    echo "${name_array[${i}]}s: No Result"
  fi
  ## Reset
  COLOUR_TAG=""
done


## Print footer if in JSON ("--json")
[[ "${JSON}" -eq 1 ]] \
  && printf "\n}\n"


## Done
exit 0