diff --git a/.gitmodules b/.gitmodules index aa589e91..68f8e67a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,9 +13,9 @@ [submodule "External/RHStatusItemView"] path = External/RHStatusItemView url = git://github.com/lhunath/RHStatusItemView.git -[submodule "External/DCIntrospect"] - path = External/DCIntrospect - url = https://github.com/lhunath/DCIntrospect.git [submodule "External/LoveLyndir"] path = External/LoveLyndir url = git://github.com/Lyndir/love-lyndir.client.git +[submodule "External/DCIntrospect"] + path = External/DCIntrospect + url = https://github.com/lhunath/DCIntrospect.git diff --git a/MasterPassword/Java/.mvn-tools b/MasterPassword/Java/.mvn-tools new file mode 100644 index 00000000..e69de29b diff --git a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/lhunath/masterpassword/MPTemplates.java b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/lhunath/masterpassword/MPTemplates.java index 4986ca4d..4a3d9b62 100644 --- a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/lhunath/masterpassword/MPTemplates.java +++ b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/lhunath/masterpassword/MPTemplates.java @@ -32,10 +32,16 @@ public class MPTemplates extends MetaObject { this.templates = templates; } + public static MPTemplates load() { + + return loadFromPList( "ciphers.plist" ); + } + public static MPTemplates loadFromPList(final String templateResource) { @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") InputStream templateStream = Thread.currentThread().getContextClassLoader().getResourceAsStream( templateResource ); + Preconditions.checkNotNull( templateStream, "Not found: %s", templateResource ); try { NSObject plistObject = PropertyListParser.parse( templateStream ); Preconditions.checkState( NSDictionary.class.isAssignableFrom( plistObject.getClass() ) ); @@ -98,6 +104,6 @@ public class MPTemplates extends MetaObject { public static void main(final String... arguments) { - loadFromPList( "templates.plist" ); + load(); } } diff --git a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/lhunath/masterpassword/MasterPassword.java b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/lhunath/masterpassword/MasterPassword.java index d18bf362..2e100b1e 100644 --- a/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/lhunath/masterpassword/MasterPassword.java +++ b/MasterPassword/Java/masterpassword-algorithm/src/main/java/com/lyndir/lhunath/masterpassword/MasterPassword.java @@ -31,7 +31,7 @@ public abstract class MasterPassword { private static final ByteOrder MP_byteOrder = ByteOrder.BIG_ENDIAN; private static final MessageDigests MP_hash = MessageDigests.SHA256; private static final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256; - private static final MPTemplates templates = MPTemplates.loadFromPList( "templates.plist" ); + private static final MPTemplates templates = MPTemplates.load(); public static byte[] keyForPassword(final String password, final String username) { diff --git a/MasterPassword/Java/masterpassword-cli/pom.xml b/MasterPassword/Java/masterpassword-cli/pom.xml index 86d7bba8..12cc8f38 100644 --- a/MasterPassword/Java/masterpassword-cli/pom.xml +++ b/MasterPassword/Java/masterpassword-cli/pom.xml @@ -29,30 +29,49 @@ org.apache.maven.plugins - maven-jar-plugin - - - - com.lyndir.lhunath.masterpassword.CLI - true - lib/ - - - + maven-antrun-plugin + 1.7 + + + prepare-package + prepare-package + + + + + + + run + + + org.apache.maven.plugins - maven-dependency-plugin - 2.4 + maven-shade-plugin + 2.2 - copy-dependencies package - copy-dependencies + shade - ${project.build.directory}/lib + + + com.lyndir.lhunath.masterpassword.CLI + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + diff --git a/MasterPassword/Java/masterpassword-cli/src/main/scripts/bashlib b/MasterPassword/Java/masterpassword-cli/src/main/scripts/bashlib new file mode 100755 index 00000000..ff367e7d --- /dev/null +++ b/MasterPassword/Java/masterpassword-cli/src/main/scripts/bashlib @@ -0,0 +1,1958 @@ +#! /usr/bin/env bash +# ___________________________________________________________________________ # +# # +# BashLIB -- A library for Bash scripting convenience. # +# # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ___________________________________________________________________________ # +# # +# # +# Copyright 2007-2013, lhunath # +# * http://www.lhunath.com # +# * Maarten Billemont # +# # + + + +# ______________________________________________________________________ +# | | +# | .:: TABLE OF CONTENTS ::. | +# |______________________________________________________________________| +# +# chr decimal +# Outputs the character that has the given decimal ASCII value. +# +# ord character +# Outputs the decimal ASCII value of the given character. +# +# hex character +# Outputs the hexadecimal ASCII value of the given character. +# +# unhex character +# Outputs the character that has the given decimal ASCII value. +# +# max numbers... +# Outputs the highest of the given numbers. +# +# min numbers... +# Outputs the lowest of the given numbers. +# +# totime "YYYY-MM-DD HH:MM:SS.mmm"... +# Outputs the number of milliseconds in the given date string(s). +# +# exists application +# Succeeds if the application is in PATH and is executable. +# +# eol message +# Return termination punctuation for a message, if necessary. +# +# hr pattern [length] +# Outputs a horizontal ruler of the given length in characters or the terminal column length otherwise. +# +# cloc +# Outputs the current cursor location as two space-separated numbers: row column. +# +# readwhile command [args] +# Outputs the characters typed by the user into the terminal's input buffer while running the given command. +# +# pushqueue element ... +# Pushes the given arguments as elements onto the queue. +# +# popqueue +# Pops one element off the queue. +# +# log [format] [arguments...] +# Log an event at a certain importance level. The event is expressed as a printf(1) format argument. +# +# emit [options] message... [-- [command args...]] +# Display a message with contextual coloring. +# +# spinner [-code|message... [-- style color textstyle textcolor]] +# Displays a spinner on the screen that waits until a certain time. +# +# report [-code] [-e] failure-message [success-message] +# This is a convenience function for replacement of spinner -code. +# +# ask [-c optionchars|-d default] [-s|-S maskchar] message... +# Ask a question and read the user's reply to it. Then output the result on stdout. +# +# trim lines ... +# Trim the whitespace off of the beginning and end of the given lines. +# +# reverse [-0|-d delimitor] [elements ...] [<<< elements] +# Reverse the order of the given elements. +# +# order [-0|-d char] [-[cC] isAscending|-n] [-t number] [elements ...] [<<< elements] +# Orders the elements in ascending order. +# +# mutex file +# Open a mutual exclusion lock on the file, unless another process already owns one. +# +# pushjob [poolsize] command +# Start an asynchronous command within a pool, waiting for space in the pool if it is full. +# +# fsleep time +# Wait for the given (fractional) amount of seconds. +# +# getArgs [options] optstring [args...] +# Retrieve all options present in the given arguments. +# +# showHelp name description author [option description]... +# Generate a prettily formatted usage description of the application. +# +# shquote [-e] [argument...] +# Shell-quote the arguments to make them safe for injection into bash code. +# +# requote [string] +# Escape the argument string to make it safe for injection into a regex. +# +# shorten [-p pwd] path [suffix]... +# Shorten an absolute path for pretty printing. +# +# up .../path|num +# Walk the current working directory up towards root num times or until path is found. +# +# buildarray name terms... -- elements... +# Create an array by adding all the terms to it for each element, replacing {} terms by the element. +# +# inArray element array +# Checks whether a certain element is in the given array. +# +# xpathNodes query [files...] +# Outputs every xpath node that matches the query on a separate line. +# +# hideDebug [on|off] +# Toggle Bash's debugging mode off temporarily. +# +# stackTrace +# Output the current script's function execution stack. +# +_tocHash=71e13f42e1ea82c1c7019b27a3bc71f3 + + +# ______________________________________________________________________ +# | | +# | .:: GLOBAL CONFIGURATION ::. | +# |______________________________________________________________________| + +# Unset all exported functions. Exported functions are evil. +while read _ _ func; do + command unset -f "$func" +done < <(command declare -Fx) + +{ +shopt -s extglob +shopt -s globstar +} 2>/dev/null ||: + +# Generate Table Of Contents +genToc() { + local line= comments=() usage= whatis= lineno=0 out= outhash= outline= + while read -r line; do + (( ++lineno )) + + [[ $line = '#'* ]] && comments+=("$line") && continue + [[ $line = +([[:alnum:]])'() {' ]] && IFS='()' read func _ <<< "$line" && [[ $func != $FUNCNAME ]] && { + usage=${comments[3]##'#'+( )} + whatis=${comments[5]##'#'+( )} + [[ $usage = $func* && $whatis = *. ]] || err "Malformed docs for %s (line %d)." "$func" "$lineno" + + printf -v outline '# %s\n# %s\n#\n' "$usage" "$whatis" + out+=$outline + } + comments=() + done < ~/.bin/bashlib + + outhash=$(openssl md5 <<< "$out") + if [[ $_tocHash = $outhash ]]; then + inf 'Table of contents up-to-date.' + else + printf '%s' "$out" + printf '_tocHash=%q' "$outhash" + wrn 'Table of contents outdated.' + fi +} + + + +# ______________________________________________________________________ +# | | +# | .:: GLOBAL DECLARATIONS ::. | +# |______________________________________________________________________| + +# Variables for global internal operation. +bobber=( '.' 'o' 'O' 'o' ) +spinner=( '-' \\ '|' '/' ) +crosser=( '+' 'x' '+' 'x' ) +runner=( '> >' \ + '>> ' \ + ' >>' ) + +# Variables for terminal requests. +[[ -t 2 ]] && { + alt=$( tput smcup || tput ti ) # Start alt display + ealt=$( tput rmcup || tput te ) # End alt display + hide=$( tput civis || tput vi ) # Hide cursor + show=$( tput cnorm || tput ve ) # Show cursor + save=$( tput sc ) # Save cursor + load=$( tput rc ) # Load cursor + dim=$( tput dim || tput mh ) # Start dim + bold=$( tput bold || tput md ) # Start bold + stout=$( tput smso || tput so ) # Start stand-out + estout=$( tput rmso || tput se ) # End stand-out + under=$( tput smul || tput us ) # Start underline + eunder=$( tput rmul || tput ue ) # End underline + reset=$( tput sgr0 || tput me ) # Reset cursor + blink=$( tput blink || tput mb ) # Start blinking + italic=$( tput sitm || tput ZH ) # Start italic + eitalic=$( tput ritm || tput ZR ) # End italic +[[ $TERM != *-m ]] && { + red=$( tput setaf 1|| tput AF 1 ) + green=$( tput setaf 2|| tput AF 2 ) + yellow=$( tput setaf 3|| tput AF 3 ) + blue=$( tput setaf 4|| tput AF 4 ) + magenta=$( tput setaf 5|| tput AF 5 ) + cyan=$( tput setaf 6|| tput AF 6 ) +} + black=$( tput setaf 0|| tput AF 0 ) + white=$( tput setaf 7|| tput AF 7 ) + default=$( tput op ) + eed=$( tput ed || tput cd ) # Erase to end of display + eel=$( tput el || tput ce ) # Erase to end of line + ebl=$( tput el1 || tput cb ) # Erase to beginning of line + ewl=$eel$ebl # Erase whole line + draw=$( tput -S <<< ' enacs + smacs + acsc + rmacs' || { \ + tput eA; tput as; + tput ac; tput ae; } ) # Drawing characters + back=$'\b' +} 2>/dev/null ||: + + + + + +# ______________________________________________________________________ +# | | +# | .:: FUNCTION DECLARATIONS ::. | +# |______________________________________________________________________| + + + +# ______________________________________________________________________ +# |__ Chr _______________________________________________________________| +# +# chr decimal +# +# Outputs the character that has the given decimal ASCII value. +# +chr() { + printf \\"$(printf '%03o' "$1")" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Ord _______________________________________________________________| +# +# ord character +# +# Outputs the decimal ASCII value of the given character. +# +ord() { + printf %d "'$1" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Hex _______________________________________________________________| +# +# hex character +# +# Outputs the hexadecimal ASCII value of the given character. +# +hex() { + printf '%x' "'$1" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Unhex _______________________________________________________________| +# +# unhex character +# +# Outputs the character that has the given decimal ASCII value. +# +unhex() { + printf \\x"$1" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ max _______________________________________________________________| +# +# max numbers... +# +# Outputs the highest of the given numbers. +# +max() { + local max=$1 n + for n + do (( n > max )) && max=$n; done + printf %d "$max" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ min _______________________________________________________________| +# +# min numbers... +# +# Outputs the lowest of the given numbers. +# +min() { + local min=$1 n + for n + do (( n < min )) && min=$n; done + printf %d "$min" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ totime ____________________________________________________________| +# +# totime "YYYY-MM-DD HH:MM:SS.mmm"... +# +# Outputs the number of milliseconds in the given date string(s). +# +# When multiple date string arguments are given, multiple time strings are output, one per line. +# +# The fields should be in the above defined order. The delimitor between the fields may be any one of [ -:.]. +# If a date string does not follow the defined format, the result is undefined. +# +# Note that this function uses a very simplistic conversion formula which does not take any special calendar +# convenions into account. It assumes there are 12 months in evert year, 31 days in every month, 24 hours +# in every day, 60 minutes in every hour, 60 seconds in every minute and 1000 milliseconds in every second. +# +totime() { + local arg time year month day hour minute second milli + for arg; do + IFS=' -:.' read year month day hour minute second milli <<< "$arg" && + (( time = (((((((((((10#$year * 12) + 10#$month) * 31) + 10#$day) * 24) + 10#$hour) * 60) + 10#$minute) * 60) + 10#$second) * 1000) + 10#$milli )) && + printf '%d\n' "$time" + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Exists ____________________________________________________________| +# +# exists application +# +# Succeeds if the application is in PATH and is executable. +# +exists() { + [[ -x $(type -P "$1" 2>/dev/null) ]] +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Eol _______________________________________________________________| +# +# eol message +# +# Return termination punctuation for a message, if necessary. +# +eol() { + : #[[ $1 && $1 != *[\!\?.,:\;\|] ]] && printf .. ||: +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Hr _______________________________________________________________| +# +# hr pattern [length] +# +# Outputs a horizontal ruler of the given length in characters or the terminal column length otherwise. +# The ruler is a repetition of the given pattern string. +# +hr() { + local pattern=${1:--} length=${2:-$COLUMNS} ruler= + (( length )) || length=$(tput cols) + + while (( ${#ruler} < length )); do + ruler+=${pattern:0:length-${#ruler}} + done + + printf %s "$ruler" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ CLoc ______________________________________________________________| +# +# cloc +# +# Outputs the current cursor location as two space-separated numbers: row column. +# +cloc() { + local old=$(stty -g) + trap 'stty "$old"' RETURN + stty raw + + # If the tty has input waiting then we can't read back its response. We'd only break and pollute the tty input buffer. + read -t 0 < /dev/tty 2>/dev/null && return 1 + + printf '\e[6n' > /dev/tty + IFS='[;' read -dR _ row col < /dev/tty + printf '%d %d' "$row" "$col" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ readwhile ______________________________________________________________| +# +# readwhile command [args] +# +# Outputs the characters typed by the user into the terminal's input buffer while running the given command. +# +readwhile() { + local old=$(stty -g) in result REPLY + trap 'stty "$old"' RETURN + stty raw + + "$@" + result=$? + + while read -t 0; do + IFS= read -rd '' -n1 && in+=$REPLY + done + printf %s "$in" + + return $result +} # _____________________________________________________________________ + + + +# ___________________________________________________________________________ +# |__ pushqueue ______________________________________________________________| +# +# pushqueue element ... +# +# Pushes the given arguments as elements onto the queue. +# +pushqueue() { + [[ $_queue ]] || { + coproc _queue { + while IFS= read -r -d ''; do + printf '%s\0' "$REPLY" + done + } + } + + printf '%s\0' "$@" >&"${_queue[1]}" +} # _____________________________________________________________________ + + + +# __________________________________________________________________________ +# |__ popqueue ______________________________________________________________| +# +# popqueue +# +# Pops one element off the queue. +# If no elements are available on the queue, this command fails with exit code 1. +# +popqueue() { + local REPLY + [[ $_queue ]] && read -t0 <&"${_queue[0]}" || return + IFS= read -r -d '' <&"${_queue[0]}" + printf %s "$REPLY" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Latest ____________________________________________________________| +# +# latest [file...] +# +# Output the argument that represents the file with the latest modification time. +# +latest() ( + shopt -s nullglob + local file latest=$1 + for file; do + [[ $file -nt $latest ]] && latest=$file + done + printf '%s\n' "$latest" +) # _____________________________________________________________________ + + + +# _______________________________________________________________________ +# |__ Iterate ____________________________________________________________| +# +# iterate [command] +# +# All arguments to iterate make up a single command that will be executed. +# +# Any of the arguments may be of the format {x..y[..z]} which causes the command +# to be executed in a loop, each iteration substituting the argument for the +# current step the loop has reached from x to y. We step from x to y by +# walking from x's position in the ASCII character table to y's with a step of z +# or 1 if z is not specified. +# +iterate() ( + set -x + local command=( "$@" ) iterationCommand=() loop= a= arg= current=() step=() target=() + for a in "${!command[@]}"; do + arg=${command[a]} + if [[ $arg = '{'*'}' ]]; then + loop=${arg#'{'} loop=${loop%'}'} + step[a]=${loop#*..*..} current[a]=${loop%%..*} target[a]=${loop#*..} target[a]=${target[a]%.."${step[a]}"} + [[ ! ${step[a]} || ${step[a]} = $loop ]] && step[a]=1 + fi + done + if (( ${#current[@]} )); then + for loop in "${!current[@]}"; do + while true; do + iterationCommand=() + + for a in "${!command[@]}"; do + (( a == loop )) \ + && iterationCommand+=( "${current[a]}" ) \ + || iterationCommand+=( "${command[a]}" ) + done + + iterate "${iterationCommand[@]}" + + [[ ${current[loop]} = ${target[loop]} ]] && break + current[loop]="$(chr "$(( $(ord "${current[loop]}") + ${step[loop]} ))")" + done + done + else + "${command[@]}" + fi +) # _____________________________________________________________________ + +# ______________________________________________________________________ +# |__ Logging ___________________________________________________________| +# +# log [format] [arguments...] +# +# Log an event at a certain importance level. The event is expressed as a printf(1) format argument. +# The current exit code remains unaffected by the execution of this function. +# +# Instead of 'log', you can use a level as command name, to log at that level. Using log, messages are +# logged at level inf. The supported levels are: trc, dbg, inf, wrn, err, ftl. +# +# If you prefix the command name with a p, the log message is shown as a spinner and waits for the next +# closing statement. Eg. +# +# pinf 'Converting image' +# convert image.png image.jpg +# fnip +# +# The closing statement (here fnip) is the reverse of the opening statement and exits with the exit code +# of the last command. If the last command failed, it shows the exit code in the spinner before it is stopped. +# The closing statement also takes a format and arguments, which are displayed in the spinner. +# +log() { + local exitcode=$? level=${level:-inf} supported=0 end=$'\n' type=msg conMsg= logMsg= format= colorFormat= date= info= arg= args=() colorArgs=() ruler= + + # Handle options. + local OPTIND=1 + while getopts :puPr arg; do + case $arg in + p) + end='.. ' + type=startProgress ;; + u) + end='.. ' + type=updateProgress ;; + P) + type=stopProgress ;; + r) + ruler='____' ;; + esac + done + shift "$((OPTIND-1))" + format=$1 args=( "${@:2}" ) + (( ! ${#args[@]} )) && [[ $format ]] && { args=("$format") format=%s; local bold=; } + + # Level-specific settings. + case $level in + TRC) (( supported = _logVerbosity >= 4 )) + logLevelColor=$_logTrcColor ;; + DBG) (( supported = _logVerbosity >= 3 )) + logLevelColor=$_logDbgColor ;; + INF) (( supported = _logVerbosity >= 2 )) + logLevelColor=$_logInfColor ;; + WRN) (( supported = _logVerbosity >= 1 )) + logLevelColor=$_logWrnColor ;; + ERR) (( supported = _logVerbosity >= 0 )) + logLevelColor=$_logErrColor ;; + FTL) (( supported = 1 )) + logLevelColor=$_logFtlColor ;; + *) + log FTL "Log level %s does not exist" "$level" + exit 1 ;; + esac + (( ! supported )) && return "$exitcode" + local logColor=${logColor:-$logLevelColor} + + # Generate the log message. + date=$(date +"${_logDate:-%H:%M}") + case $type in + msg|startProgress) + printf -v logMsg "[%s %-3s] $format$end" "$date" "$level" "${args[@]}" + if (( _logColor )); then + colorFormat=$(sed -e "s/$(requote "$reset")/$reset$logColor/g" -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format") + colorArgs=("${args[@]//$reset/$reset$bold$logColor}") + printf -v conMsg "$reset[%s $logLevelColor%-3s$reset] $logColor$colorFormat$reset$black\$$reset$end$save" "$date" "$level" "${colorArgs[@]}" + else + conMsg=$logMsg + fi + ;; + + updateProgress) + printf -v logMsg printf " [$format]" "${args[@]}" + if (( _logColor )); then + colorFormat=$(sed -e "s/$(requote "$reset")/$reset$logColor/g" -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format") + colorArgs=("${args[@]//$reset/$reset$bold$logColor}") + printf -v conMsg "$load$eel$blue$bold[$reset$logColor$colorFormat$reset$blue$bold]$reset$end" "${colorArgs[@]}" + else + conMsg=$logMsg + fi + ;; + + stopProgress) + case $exitcode in + 0) printf -v logMsg "done${format:+ ($format)}.\n" "${args[@]}" + if (( _logColor )); then + colorFormat=$(sed -e "s/$(requote "$reset")/$reset$logColor/g" -e "s/%[^a-z]*[a-z]/$reset$bold$logColor&$reset$logColor/g" <<< "$format") + colorArgs=("${args[@]//$reset/$reset$bold$logColor}") + printf -v conMsg "$load$eel$green${bold}done${colorFormat:+ ($reset$logColor$colorFormat$reset$green$bold)}$reset.\n" "${colorArgs[@]}" + else + conMsg=$logMsg + fi + ;; + + *) info=${format:+$(printf ": $format" "${args[@]}")} + printf -v logMsg "error(%d%s).\n" "$exitcode" "$info" + if (( _logColor )); then + printf -v conMsg "${eel}${red}error${reset}(${bold}${red}%d${reset}%s).\n" "$exitcode" "$info" + else + conMsg=$logMsg + fi + ;; + esac + ;; + esac + + # Create the log file. + if [[ $_logFile && ! -e $_logFile ]]; then + [[ $_logFile = */* ]] || $_logFile=./$logFile + mkdir -p "${_logFile%/*}" && touch "$_logFile" + fi + + # Stop the spinner. + if [[ $type = stopProgress && $_logSpinner ]]; then + kill "$_logSpinner" + wait "$_logSpinner" 2>/dev/null + unset _logSpinner + fi + + # Output the ruler. + if [[ $ruler ]]; then + printf >&2 '%s\n' "$(hr "$ruler")" + [[ -w $_logFile ]] \ + && printf >> "$_logFile" '%s' "$ruler" + fi + + # Output the log message. + printf >&2 '%s' "$conMsg" + [[ -w $_logFile ]] \ + && printf >> "$_logFile" '%s' "$logMsg" + + # Start the spinner. + if [[ $type = startProgress && ! $_logSpinner ]]; then + { + set +m + trap 'touch exit; printf %s "$show"' EXIT + echo "$BASHPID" > start + printf %s "$hide" + while printf "$eel$blue$bold[$reset%s$reset$blue$bold]$reset\b\b\b" "${spinner[s++ % ${#spinner[@]}]}" && sleep .1 + do :; done + } & _logSpinner=$! + fi 2>/dev/null + + return $exitcode +} +trc() { level=TRC log "$@"; } +dbg() { level=DBG log "$@"; } +inf() { level=INF log "$@"; } +wrn() { level=WRN log "$@"; } +err() { level=ERR log "$@"; } +ftl() { level=FTL log "$@"; } +plog() { log -p "$@"; } +ulog() { log -u "$@"; } +golp() { log -P "$@"; } +ptrc() { level=TRC plog "$@"; } +pdbg() { level=DBG plog "$@"; } +pinf() { level=INF plog "$@"; } +pwrn() { level=WRN plog "$@"; } +perr() { level=ERR plog "$@"; } +pftl() { level=FTL plog "$@"; } +utrc() { level=TRC ulog "$@"; } +udbg() { level=DBG ulog "$@"; } +uinf() { level=INF ulog "$@"; } +uwrn() { level=WRN ulog "$@"; } +uerr() { level=ERR ulog "$@"; } +uftl() { level=FTL ulog "$@"; } +gtrc() { level=trc golp "$@"; } +gbdp() { level=DBG golp "$@"; } +fnip() { level=INF golp "$@"; } +nrwp() { level=WRN golp "$@"; } +rrep() { level=ERR golp "$@"; } +ltfp() { level=FTL golp "$@"; } +_logColor=${_logColor:-$([[ -t 2 ]] && echo 1)} _logVerbosity=2 +_logTrcColor=$grey _logDbgColor=$blue _logInfColor=$white _logWrnColor=$yellow _logErrColor=$red _logFtlColor=$bold$red +# _______________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Emit ______________________________________________________________| +# +# emit [options] message... [-- [command args...]] +# +# Display a message with contextual coloring. +# +# DEPRECATED: Use inf and variants instead. +# +# When a command is provided, a spinner will be activated in front of the +# message for as long as the command runs. When the command ends, its +# exit status will result in a message 'done' or 'failed' to be displayed. +# +# It is possible to only specify -- as final argument. This will prepare +# a spinner for you with the given message but leave it up to you to +# notify the spinner that it needs to stop. See the documentation for +# 'spinner' to learn how to do this. +# +# -n Do not end the line with a newline. +# -b Activate bright (bold) mode. +# -d Activate half-bright (dim) mode. +# -g Display in green. +# -y Display in yellow. +# -r Display in red. +# -w Display in the default color. +# +# -[code] A proxy-call to 'spinner -[code]'. +# +# Non-captialized versions of these options affect the * or the spinner +# in front of the message. Capitalized options affect the message text +# displayed. +# +emit() { + + # Proxy call to spinner. + [[ $# -eq 1 && $1 = -+([0-9]) ]] \ + && { spinner $1; return; } + + # Initialize the vars. + local arg + local style= + local color= + local textstyle= + local textcolor= + local noeol=0 + local cmd=0 + + # Parse the options. + spinArgs=() + for arg in $(getArgs odbwgyrDBWGYRn "$@"); do + case ${arg%% } in + d) style=$dim ;; + b) style=$bold ;; + w) color=$white ;; + g) color=$green ;; + y) color=$yellow ;; + r) color=$red ;; + D) textstyle=$dim ;; + B) textstyle=$bold ;; + W) textcolor=$white ;; + G) textcolor=$green ;; + Y) textcolor=$yellow ;; + R) textcolor=$red ;; + n) noeol=1 + spinArgs+=(-n) ;; + o) spinArgs+=("-$arg") ;; + esac + done + shift $(getArgs -c odbwgyrDBWGYRn "$@") + while [[ $1 = +* ]]; do + spinArgs+=("-${1#+}") + shift + done + + # Defaults. + color=${color:-$textcolor} + color=${color:-$green} + [[ $color = $textcolor && -z $style ]] && style=$bold + + # Get the text message. + local text= origtext= + for arg; do [[ $arg = -- ]] && break; origtext+="$arg "; done + origtext=${origtext%% } + (( noeol )) && text=$origtext || text=$origtext$reset$(eol "$origtext")$'\n' + + + # Trim off everything up to -- + while [[ $# -gt 1 && $1 != -- ]]; do shift; done + [[ $1 = -- ]] && { shift; cmd=1; } + + # Figure out what FD to use for our messages. + [[ -t 1 ]]; local fd=$(( $? + 1 )) + + # Display the message or spinner. + if (( cmd )); then + # Don't let this Bash handle SIGINT. + #trap : INT + + # Create the spinner in the background. + spinPipe=${TMPDIR:-/tmp}/bashlib.$$ + { touch "$spinPipe" && rm -f "$spinPipe" && mkfifo "$spinPipe"; } 2>/dev/null \ + || unset spinPipe + { spinner "${spinArgs[@]}" "$origtext" -- "$style" "$color" "$textstyle" "$textcolor" < "${spinPipe:-/dev/null}" & } 2>/dev/null + [[ $spinPipe ]] && echo > "$spinPipe" + spinPid=$! + + # Execute the command for the spinner if one is given. + #fsleep 1 # Let the spinner initialize itself properly first. # Can probably remove this now that we echo > spinPipe? + if (( $# == 1 )); then command=$1 + elif (( $# > 1 )); then command=$(printf '%q ' "$@") + else return 0; fi + + eval "$command" >/dev/null \ + && spinner -0 \ + || spinner -1 + else + # Make reset codes restore the initial font. + local font=$reset$textstyle$textcolor + text=$font${text//$reset/$font} + + printf "\r$reset $style$color* %s$reset" "$text" >&$fd + fi +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Spinner ___________________________________________________________| +# +# spinner [-code|message... [-- style color textstyle textcolor]] +# +# DEPRECATED: Use pinf and variants instead. +# +# Displays a spinner on the screen that waits until a certain time. +# Best used through its interface provided by 'emit'. +# +# style A terminal control string that defines the style of the spinner. +# color A terminal control string that defines the color of the spinner. +# textstyle A terminal control string that defines the style of the message. +# textcolor A terminal control string that defines the color of the message. +# +# -[code] Shut down a previously activated spinner with the given exit +# code. If the exit code is 0, a green message 'done' will be +# displayed. Otherwise a red message 'failed' will appear. +# The function will return with this exit code as result. +# +# You can manually specify a previously started spinner by putting its PID in +# the 'spinPid' variable. If this variable is not defined, the PID of the most +# recently backgrounded process is used. The 'spinPid' variable is unset upon +# each call to 'spinner' and reset to the PID of the spinner if one is created. +# +spinner() { + + # Check usage. + (( ! $# )) || getArgs -q :h "$@" && { + emit -y 'Please specify a message as argument or a status option.' + return 1 + } + + # Initialize spinner vars. + # Make sure monitor mode is off or we won't be able to trap INT properly. + local monitor=0; [[ $- = *m* ]] && monitor=1 + local done= + + # Place the trap for interrupt signals. + trap 'done="${red}failed"' USR2 + trap 'done="${green}done"' USR1 + + # Initialize the vars. + local pid=${spinPid:-$!} + local graphics=( "${bobber[@]}" ) + local style=$bold + local color=$green + local textstyle= + local textcolor= + local output= + local noeol= + unset spinPid + + # Any remaining options are the exit status of an existing spinner or spinner type. + while [[ $1 = -* ]]; do + arg=${1#-} + shift + + # Stop parsing when arg is -- + [[ $arg = - ]] && break + + # Process arg: Either a spinner type or result code. + if [[ $arg = *[^0-9]* ]]; then + case $arg in + b) graphics=( "${bobber[@]}" ) ;; + c) graphics=( "${crosser[@]}" ) ;; + r) graphics=( "${runner[@]}" ) ;; + s) graphics=( "${spinner[@]}" ) ;; + o) output=1 ;; + n) noeol=1 ;; + esac + elif [[ $pid ]]; then + [[ $arg = 0 ]] \ + && kill -USR1 $pid 2>/dev/null \ + || kill -USR2 $pid 2>/dev/null + + trap - INT + wait $pid 2>/dev/null + + return $arg + fi + done + + # Read arguments. + local text= origtext= + for arg; do [[ $arg = -- ]] && break; origtext+="$arg "; done + origtext=${origtext% } + local styles=$*; [[ $styles = *' -- '* ]] || styles= + read -a styles <<< "${styles##* -- }" + [[ ${styles[0]} ]] && style=${styles[0]} + [[ ${styles[1]} ]] && color=${styles[1]} + [[ ${styles[2]} ]] && textstyle=${styles[2]} + [[ ${styles[3]} ]] && textcolor=${styles[3]} + + # Figure out what FD to use for our messages. + [[ -t 1 ]]; local fd=$(( $? + 1 )) + + # Make reset codes restore the initial font. + local font=$reset$textstyle$textcolor + origtext=$font${origtext//$reset/$font} + (( noeol )) && text=$origtext || text=$origtext$reset$(eol "$origtext") + + # Spinner initial status. + printf "\r$save$eel$reset $style$color* %s$reset" "$text" >&$fd + (( output )) && printf "\n" >&$fd + + # Render the spinner. + set +m + local i=0 + while [[ ! $done ]]; do + IFS= read -r -d '' newtext || true + newtext=${newtext%%$'\n'}; newtext=${newtext##*$'\n'} + if [[ $newtext = +* ]]; then + newtext="$origtext [${newtext#+}]" + fi + if [[ $newtext ]]; then + newtext="$font${newtext//$reset/$font}" + (( noeol )) && text=$newtext || text=$newtext$reset$(eol "$newtext") + fi + + if (( output )) + then printf "\r" >&$fd + else printf "$load$eel" >&$fd + fi + + if (( output )) + then printf "$reset $style$color$blue%s %s$reset" \ + "${graphics[i++ % 4]}" "$text" >&$fd + else printf "$reset $style$color%s %s$reset" \ + "${graphics[i++ % 4]}" "$text" >&$fd + fi + + fsleep .25 # Four iterations make one second. + + # Cancel when calling script disappears. + kill -0 $$ >/dev/null || done="${red}aborted" + done + + # Get rid of the spinner traps. + trap - USR1 USR2; (( monitor )) && set -m + + # Spinner final status. + if (( output )) + then text=; printf "\r" >&$fd + else printf "$load" >&$fd + fi + + printf "$eel$reset $style$color* %s${text:+ }$bold%s$font.$reset\n" \ + "$text" "$done" >&$fd +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ report ___________________________________________________________| +# +# report [-code] [-e] failure-message [success-message] +# +# This is a convenience function for replacement of spinner -code. +# +# DEPRECATED: Use fnip and variants instead. +# +# It checks either the exit code of the previously completed command or +# the code provided as option to determine whether to display the success +# or failure message. It calls spinner -code to complete an actively +# emitted message if there is one. The success message is optional. +# +# -[code] The exit code to use. +# -e Exit the script on failure. +# +report() { + + # Exit Status of previous command. + local code=$? + + # Parse the options. + while [[ $1 = -* && $2 ]]; do + arg=${1#-} + shift + + # Stop parsing when arg is -- + [[ $arg = - ]] && break + + # Process arg: Either a spinner type or result code. + if [[ $arg = *[^0-9]* ]]; then + case $arg in + esac + else code=$arg + fi + done + + # Initialize the vars. + local failure=$1 + local success=$2 + + # Check usage. + (( ! $# )) || getArgs -q :h "$@" && { + emit -y 'Please specify at least a failure message as argument.' + return 1 + } + + # Proxy call to spinner. + (( spinPid )) \ + && { spinner -$code; } + + # Success or failure message. + if (( ! code )) + then [[ $success ]] && emit " $success" + else [[ $failure ]] && emit -R " $failure" + fi + + # Pass on exit code. + return $code +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Ask _______________________________________________________________| +# +# ask [-c optionchars|-d default] [-s|-S maskchar] message... +# +# Ask a question and read the user's reply to it. Then output the result on stdout. +# +# When in normal mode, a single line is read. If the line is empty and +# -d was specified, the default argument is output instead of an empty line. +# The exit code is always 0. +# +# When in option mode (-c), the user is shown the option characters with +# which he can reply and a single character is read. +# If the reply is empty (user hits enter) and any of the optionchars are +# upper-case, the upper-case option (= the default option) character will +# be output instead of an empty line. +# If the reply character is not amoungst the provided options the default +# option is again output instead if present. If no default was given, an +# exit code of 2 is returned. +# You may mark an optionchar as 'valid' by appending a '!' to it. As a +# result, an exit code of 0 will only be returned if this valid option +# is replied. If not, an exit code of 1 will be returned. +# +ask() { + + # Check usage. + (( ! $# )) || getArgs -q :h "$@" && { + emit -y 'Please specify a question as argument.' + return 1 + } + + # Initialize the vars. + local opt arg + local option= + local options= + local default= + local silent= + local valid= + local muteChar= + local message= + + # Parse the options. + local OPTIND=1 + while getopts :sS:c:d: opt; do + case $opt in + s) silent=1 ;; + S) silent=1 muteChar=$OPTARG ;; + c) while read -n1 arg; do + case $arg in + [[:upper:]]) default=$arg ;; + !) valid=${options: -1}; continue ;; + esac + + options+=$arg + done <<< "$OPTARG" ;; + d) default=$OPTARG option=$default ;; + esac + done + + # Trim off the options. + shift $((OPTIND-1)) + + # Figure out what FD to use for our messages. + [[ -t 1 ]] && local fd=1 || local fd=2 + + # Ask the question. + message=$1; shift; printf -v message "$message" "$@" + emit -yn "$message${option:+ [$option]}${options:+ [$options]} " + + # Read the reply. + exec 8<&0; [[ -t 8 ]] || exec 8&$fd + done + REPLY=$reply + else + read -u8 -e ${options:+-n1} ${silent:+-s} + fi + [[ $options && $REPLY ]] || (( silent )) && printf '\n' >&$fd + + # Evaluate the reply. + while true; do + if [[ $REPLY && ( ! $options || $options = *$REPLY* ) ]]; then + if [[ $valid ]] + then [[ $REPLY = $valid ]] + else printf "%s" "$REPLY" + fi + + return + fi + + [[ -z $default || $REPLY = $default ]] \ + && return 2 + + REPLY=$default + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Trim ______________________________________________________________| +# +# trim lines ... +# +# Trim the whitespace off of the beginning and end of the given lines. +# Each argument is considdered one line; is treated and printed out. +# +# When no arguments are given, lines will be read from standard input. +# +trim() { + + # Initialize the vars. + local lines + local line + local oIFS + + # Get the lines. + lines=( "$@" ) + if (( ! ${#lines[@]} )); then + oIFS=$IFS; IFS=$'\n' + lines=( $(cat) ) + IFS=$oIFS + fi + + # Trim the lines + for line in "${lines[@]}"; do + line=${line##*([[:space:]])}; line=${line%%*([[:space:]])} + printf "%s" "$line" + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Reverse ___________________________________________________________| +# +# reverse [-0|-d delimitor] [elements ...] [<<< elements] +# +# Reverse the order of the given elements. +# Elements are read from command arguments or standard input if no element +# arguments are given. +# They are reversed and output on standard output. +# +# If the -0 option is given, input and output are delimited by NUL bytes. +# If the -d option is given, input and output are delimited by the +# character argument. +# Otherwise, they are delimited by newlines. +# +reverse() { + + # Initialize the vars. + local elements=() delimitor=$'\n' i + + # Parse the options. + local OPTIND=1 + while getopts :0d: opt; do + case $opt in + 0) delimitor=$'\0' ;; + d) delimitor=$OPTARG ;; + esac + done + shift "$((OPTIND-1))" + + # Get the elements. + if (( $# )); then + elements=( "$@" ) + else + while IFS= read -r -d "$delimitor"; do + elements+=("$REPLY") + done + fi + + # Iterate in reverse order. + for (( i=${#elements[@]} - 1; i >=0; --i )); do + printf "%s${delimitor:-'\0'}" "${elements[i]}" + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Order _____________________________________________________________| +# +# order [-0|-d char] [-[cC] isAscending|-n] [-t number] [-a array|elements ...] [<<< elements] +# +# Orders the elements in ascending order. +# Elements are read from command arguments or standard input if no element +# arguments are given. +# The result is output on standard output. +# +# By default, the elements will be ordered using lexicographic comparison. +# If the -n option is given, the elements will be considered integer numbers. +# If the -c option is given, the command name following it will be used +# as a comparator. +# If the -C option is given, the bash code following it will be used +# as a comparator. +# If the -t option is given, only the first number results are returned. +# If the -a option is given, the elements in array are ordered instead and +# array is mutated to contain the result. +# If number is 0, all results are returned. +# +# If given, isAscending comparator command will be executed for each element +# comparison and will be passed two element arguments. The command should +# succeed if the first argument is less than the second argument for the +# purpose of this sort. +# +# If the -0 option is given, input and output are delimited by NUL bytes. +# If the -d option is given, input and output are delimited by the +# character argument. +# Otherwise, they are delimited by newlines. +# +# The ordering is implemented by an insertion sort algorithm. +# +order() { + + # Initialize the vars. + local elements=() element delimitor=$'\n' i isAscending=_order_string_ascends top=0 array= arrayElements= + + # Parse the options. + local OPTIND=1 + while getopts :0nd:c:C:t:a: opt; do + case $opt in + 0) delimitor=$'\0' ;; + d) delimitor=$OPTARG ;; + n) comparator=_order_number_ascends ;; + c) isAscending=$OPTARG ;; + C) isAscending=_order_cmd_ascends _order_cmd=$OPTARG ;; + t) top=$OPTARG ;; + a) array=$OPTARG arrayElements=$array[@] ;; + esac + done + shift "$((OPTIND-1))" + + # Get the elements. + if [[ $array ]]; then + elements=( "${!arrayElements}" ) + elif (( $# )); then + elements=( "$@" ) + else + while IFS= read -r -d "$delimitor"; do + elements+=("$REPLY") + done + fi + + # Iterate in reverse order. + for (( i = 2; i < ${#elements[@]}; ++i )); do + for (( j = i; j > 1; --j )); do + element=${elements[j]} + if "$isAscending" "$element" "${elements[j-1]}"; then + elements[j]=${elements[j-1]} + elements[j-1]=$element + fi + done + done + + (( top )) || top=${#elements[@]} + if [[ $array ]]; then + declare -ga "$array=($(printf '%q ' "${elements[@]:0:top}"))" + else + printf "%s${delimitor:-\0}" "${elements[@]:0:top}" + fi +} # _____________________________________________________________________ +_order_string_ascends() { [[ $1 < $2 ]]; } +_order_number_ascends() { (( $1 < $2 )); } +_order_mtime_ascends() { [[ $1 -ot $2 ]]; } +_order_cmd_ascends() { bash -c "$_order_cmd" -- "$@"; } + + +# ______________________________________________________________________ +# |__ Mutex _____________________________________________________________| +# +# mutex file +# +# Open a mutual exclusion lock on the file, unless another process already owns one. +# +# If the file is already locked by another process, the operation fails. +# This function defines a lock on a file as having a file descriptor open to the file. +# This function uses FD 9 to open a lock on the file. To release the lock, close FD 9: +# exec 9>&- +# +mutex() { + local lockfile=${1:-${BASH_SOURCE[-1]}} pid pids + [[ -e $lockfile ]] || err "No such file: $lockfile" || return + + exec 9>> "$lockfile" && [[ $({ fuser -f "$lockfile"; } 2>&- 9>&-) == $$ ]] +} + + +# ______________________________________________________________________ +# |__ PushJob ___________________________________________________________| +# +# pushjob [poolsize] command +# +# Start an asynchronous command within a pool, waiting for space in the pool if it is full. +# +# The pool is pruned automatically as running jobs complete. This function +# allows you to easily run asynchronous commands within a pool of N, +# automatically starting the next command as soon as there's space. +# +pushjob() { + local size=$1; shift 1 + + # Wait for space in the pool. + until (( ${#jobpool[@]} < size )); do + sleep 1 & pushjobsleep=$! + wait "$pushjobsleep" + done 2>/dev/null + + # Register prunejobs and start the pushed job. + trap _prunejobs SIGCHLD + set -m + "$@" & jobpool[$!]= +} +_prunejobs() { + # Prune all pool jobs that are no longer running. + for pid in "${!jobpool[@]}"; do + kill -0 "$pid" 2>/dev/null || unset "jobpool[$pid]" + done + + # Unregister SIGCHLD if our pool is empty. + (( ${#jobpool[@]} )) || trap - SIGCHLD + + # Wake up pushjob. + kill "$pushjobsleep" 2>/dev/null +} + + + + +# ______________________________________________________________________ +# |__ FSleep _____________________________________________________________| +# +# fsleep time +# +# Wait for the given (fractional) amount of seconds. +# +# This implementation solves the problem portably, assuming that either +# bash 4.x or a fractional sleep(1) is available. +# +fsleep() { + + local fifo=${TMPDIR:-/tmp}/.fsleep.$$ + trap 'rm -f "$fifo"' RETURN + mkfifo "$fifo" && { read -t "$1" <> "$fifo" 2>/dev/null || sleep "$1"; } +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ GetArgs ___________________________________________________________| +# +# getArgs [options] optstring [args...] +# +# Retrieve all options present in the given arguments. +# +# This is a wrapper for getopts(P) which will safely work inside functions. +# It manages OPTIND for you and returns a list of options found in the +# provided arguments. +# +# optstring This is a string of characters in which each character +# represents an option to look for in the arguments. +# See getopts(P) for a description of the optstring syntax. +# +# args This is a list of arguments in which to look for options. +# Most commonly, you will use "$@" to supply these arguments. +# +# -c Instead of output the arguments, output OPTARGS. +# -q Be quiet. No arguments are displayed. Only the exit code is set. +# -n Use newlines as a separator between the options that were found. +# -0 Use NULL-bytes as a separator between the options that were found. +# +# If any given arguments are found, an exit code of 0 is returned. If none +# are found, an exit code of 1 is returned. +# +# After the operation, OPTARGS is set the the index of the last argument +# that has been parsed by getArgs. Ready for you to use shift $OPTARGS. +# +getArgs() { + + # Check usage. + (( ! $# )) && { + emit -y 'Please provide the arguments to search for in' \ + 'getopts(P) format followed by the positional parameters.' + return 1 + } + + # Initialize the defaults. + local arg + local found=0 + local quiet=0 + local count=0 + local delimitor=' ' + + # Parse the options. + while [[ $1 = -* ]]; do + case $1 in + -q) quiet=1 ;; + -c) count=1 ;; + -n) delimitor=$'\n' ;; + -0) delimitor=$'\0' ;; + esac + shift + done + + # Get the optstring. + local optstring=$1; shift + + # Enumerate the arguments. + local OPTIND=1 + while getopts "$optstring" arg; do + [[ $arg != '?' ]] && found=1 + + (( quiet + count )) || \ + printf "%s${OPTARG:+ }%s%s" "$arg" "$OPTARG" "$delimitor" + done + OPTARGS=$(( OPTIND - 1 )) + + # Any arguments found? + (( count )) && printf "%s" "$OPTARGS" + return $(( ! found )) +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ ShowHelp __________________________________________________________| +# +# showHelp name description author [option description]... +# +# Generate a prettily formatted usage description of the application. +# +# name Provide the name of the application. +# +# description Provide a detailed description of the application's +# purpose and usage. +# +# option An option the application can take as argument. +# +# description A description of the effect of the preceding option. +# +showHelp() { + + # Check usage. + (( $# < 3 )) || getArgs -q :h "$@" && { + emit -y 'Please provide the name, description, author and options' \ + 'of the application.' + return 1 + } + + # Parse the options. + local appName=$1; shift + local appDesc=${1//+([[:space:]])/ }; shift + local appAuthor=$1; shift + local cols=$(tput cols) + (( cols = ${cols:-80} - 10 )) + + # Figure out what FD to use for our messages. + [[ -t 1 ]]; local fd=$(( $? + 1 )) + + # Print out the help header. + printf "$reset$bold\n" >&$fd + printf "\t\t%s\n" "$appName" >&$fd + printf "$reset\n" >&$fd + printf "%s\n" "$appDesc" | fmt -w "$cols" | sed $'s/^/\t/' >&$fd + printf "\t $reset$bold~ $reset$bold%s\n" "$appAuthor" >&$fd + printf "$reset\n" >&$fd + + # Print out the application options and columnize them. + while (( $# )); do + local optName=$1; shift + local optDesc=$1; shift + printf " %s\t" "$optName" + printf "%s\n" "${optDesc//+( )/ }" | fmt -w "$cols" | sed $'1!s/^/ \t/' + printf "\n" + done | column -t -s $'\t' \ + | sed "s/^\( [^ ]*\)/$bold$green\1$reset/" >&$fd + printf "\n" >&$fd +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Quote _____________________________________________________________| +# +# shquote [-e] [argument...] +# +# Shell-quote the arguments to make them safe for injection into bash code. +# +# The result is bash code that represents a series of words, where each +# word is a literal string argument. By default, quoting happens using +# single-quotes. +# +# -e Use backslashes rather than single quotes. +# -d Use double-quotes rather than single quotes (does NOT disable expansions!). +# +shquote() { + + # Initialize the defaults. + local arg escape=0 sq="'\\''" dq='\"' quotedArgs=() type=single + + # Parse the options. + while [[ $1 = -* ]]; do + case $1 in + -e) type=escape ;; + -d) type=double ;; + --) shift; break ;; + esac + shift + done + + # Print out each argument, quoting it properly. + for arg; do + case "$type" in + escape) + quotedArgs+=("$(printf "%q" "$arg")") ;; + single) + arg=${arg//"'"/$sq} + quotedArgs+=("$(printf "'%s'" "$arg")") ;; + double) + arg=${arg//'"'/$dq} + quotedArgs+=("$(printf '"%s"' "$arg")") ;; + esac + done + + printf '%s\n' "$(IFS=' '; echo "${quotedArgs[*]}")" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ ReQuote __________________________________________________________| +# +# requote [string] +# +# Escape the argument string to make it safe for injection into a regex. +# +# The result is a regular expression that matches the literal argument +# string. +# +requote() { + + # Initialize the defaults. + local char + + printf '%s' "$1" | while IFS= read -r -d '' -n1 char; do + printf '[%s]' "$char" + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Shorten ___________________________________________________________| +# +# shorten [-p pwd] path [suffix]... +# +# Shorten an absolute path for pretty printing. +# Paths are shortened by replacing the homedir by ~, making it relative and +# cutting off given suffixes from the end. +# +# -p Use the given pathname as the base for relative filenames instead of PWD. +# path The path string to shorten. +# suffix Suffix strings that must be cut off from the end. +# Only the first suffix string matched will be cut off. +# +shorten() { + + # Check usage. + (( $# < 1 )) || getArgs -q :h "$@" && { + emit -y 'Please provide the path to shorten.' + return 1 + } + + # Parse the options. + local suffix path pwd=$PWD + [[ $1 = -p ]] && { pwd=$2; shift 2; } + path=$1; shift + + # Make path absolute. + [[ $path = /* ]] || path=$PWD/$path + + # If the path denotes something that exists; it's easy. + if [[ -d $path ]] + then path=$(cd "$path"; printf "%s" "$PWD") + elif [[ -d ${path%/*} ]] + then path=$(cd "${path%/*}"; printf "%s" "$PWD/${path##*/}") + + # If not, we'll try readlink -m. + elif readlink -m / >/dev/null 2>&1; then + path=$(readlink -m "$path") + + # If we don't have that - unleash the sed(1) madness. + else + local oldpath=/ + while [[ $oldpath != $path ]]; do + oldpath=$path + path=$(sed -e 's,///*,/,g' -e 's,\(^\|/\)\./,\1,g' -e 's,\(^\|/\)[^/]*/\.\.\($\|/\),\1,g' <<< "$path") + done + fi + + # Replace special paths. + path=${path/#$HOME/'~'} + path=${path#$pwd/} + + # Cut off suffix. + for suffix; do + [[ $path = *$suffix ]] && { + path=${path%$suffix} + break + } + done + + printf "%s" "$path" +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ Up ________________________________________________________________| +# +# up .../path|num +# +# Walk the current working directory up towards root num times or until path is found. +# +# Returns 0 if the destination was reached or 1 if we hit root. +# +# Prints PWD on stdout on success. +# +up() { + local up=0 + until [[ $PWD = / ]]; do + cd ../ + + if [[ $1 = .../* ]]; then + [[ -e ${1#.../} ]] && pwd && return + elif (( ++up == $1 )); then + pwd && return + fi + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ BuildArray ________________________________________________________| +# +# buildarray name terms... -- elements... +# +# Create an array by adding all the terms to it for each element, replacing {} terms by the element. +# +# name The name of the array to put the result into. +# terms The values to add to the array for each of the elements. A {} term is replaced by the current element. +# elements The elements to iterate the terms for. +# +buildarray() { + local target=$1 term terms=() element value + shift + + while [[ $1 != -- ]]; do + terms+=("$1") + shift + done + shift + + for element; do + for term in "${terms[@]}"; do + [[ $term = {} ]] && value="$element" || value="$term" + declare -ag "$target+=($(printf '%q' "$value"))" + done + done +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ InArray ___________________________________________________________| +# +# inArray element array +# +# Checks whether a certain element is in the given array. +# +# element The element to search the array for. +# array This is a list of elements to search through. +# +inArray() { + + # Check usage. + (( $# < 1 )) || getArgs -q :h "$@" && { + emit -y 'Please provide the element to search for and the array' \ + 'to search through.' + return 1 + } + + # Parse the options. + local element + local search=$1; shift + + # Perform the search. + for element + do [[ $element = $search ]] && return 0; done + return 1 +} # _____________________________________________________________________ + + + +# ______________________________________________________________________ +# |__ HideDebug _________________________________________________________| +# +# hideDebug [on|off] +# +# Toggle Bash's debugging mode off temporarily. +# To hide Bash's debugging output for a function, you should have +# hideDebug on +# as its first line, and +# hideDebug off +# as its last. +# +hideDebug() { + + if [[ $1 = on ]]; then + : -- HIDING DEBUG OUTPUT .. + [[ $- != *x* ]]; bashlib_debugWasOn=$? + set +x + elif [[ $1 = off ]]; then + : -- SHOWING DEBUG OUTPUT .. + (( bashlib_debugWasOn )) && \ + set -x + fi +} + + + +# ______________________________________________________________________ +# |__ anfunc ____________________________________________________________| +# +# anfunc [on|off] +# +# Turn on or off support for annonymous functions. +# +# WARNING: This is a hack. It turns on extdebug and causes any argument +# that matches (){code} to be replaced by a function name that if invoked +# runs code. +# +# eg. +# confirm '(){ rm "$1" }' *.txt +# # In this example, confirm() could be a function that asks confirmation +# # for each argument past the first and runs the anfunc in the first +# # argument on each confirmed argument. +# +# Don't use this. It is an academic experiment and has bugs. +# +# Bugs: +# - commands lose their exit code. +# To inhibit the real command from running, we use extdebug and +# a DEBUG trap that returns non-0. As a result, the actual return +# code is lost. +# +anfunc() { + case "$1" in + on) + shopt -s extdebug + trap _anfunc_trap DEBUG + ;; + off) + trap - DEBUG + shopt -u extdebug + ;; + esac +} +_anfunc_trap() { + local f w + + # Perform the command parsing and handling up to its word splitting. + # This includes command substitution, quote handling, pathname expansion, etc. + declare -a words="($BASH_COMMAND)" + + # Iterate the words to run in the final stage, and handle anfunc matches. + for ((w=0; w<${#words[@]}; ++w)); do + [[ ${words[w]} = '(){'*'}' ]] && + # Declare a new function for this anfunc. + eval "_f$((++f))${words[w]}" && + # Replace the word by the new function's name. + words[w]="_f$f" + done + + # Run the command. + eval "$(printf '%q ' "${words[@]}")" + + # Clean up the anfuncs. + for ((; f>0; --f)); do + unset -f "_f$f" + done + + # Inhibit the real command's execution. + return 1 +} + + + +# ______________________________________________________________________ +# |__ StackTrace ________________________________________________________| +# +# stackTrace +# +# Output the current script's function execution stack. +# +stackTrace() { + + # Some general debug information. + printf "\t$bold%s$reset v$bold%s$reset" "$BASH" "$BASH_VERSION\n" + printf " Was running: $bold%s %s$reset" "$BASH_COMMAND" "$*\n" + printf "\n" + printf " [Shell : $bold%15s$reset] [Subshells : $bold%5s$reset]\n" "$SHLVL" "$BASH_SUBSHELL" + printf " [Locale : $bold%15s$reset] [Runtime : $bold%5s$reset]\n" "$LC_ALL" "${SECONDS}s" + printf "\n" + + # Search through the map. + local arg=0 + for i in ${!FUNCNAME[@]}; do + #if (( i )); then + + # Print this execution stack's location. + printf "$reset $bold-$reset $green" + [[ ${BASH_SOURCE[i+1]} ]] \ + && printf "%s$reset:$green$bold%s" "${BASH_SOURCE[i+1]}" "${BASH_LINENO[i]}" \ + || printf "${bold}Prompt" + + # Print this execution stack's function and positional parameters. + printf "$reset :\t$bold%s(" "${FUNCNAME[i]}" + [[ ${BASH_ARGC[i]} ]] && \ + for (( j = 0; j < ${BASH_ARGC[i]}; j++ )); do + (( j )) && printf ', ' + printf "%s" "${BASH_ARGV[arg]}" + let arg++ + done + + # Print the end of this execution stack's line. + printf ")$reset\n" + #fi + done + printf "\n" + +} # _____________________________________________________________________ + + + + + +# ______________________________________________________________________ +# | | +# | .:: ENTRY POINT ::. | +# |______________________________________________________________________| + +# Make sure this file is sourced and not executed. +( return 2>/dev/null ) || { + emit -R "You should source this file, not execute it." + exit 1 +} + +: +: .:: END SOURCING ::. +: ______________________________________________________________________ +: diff --git a/MasterPassword/Java/masterpassword-cli/src/main/scripts/install b/MasterPassword/Java/masterpassword-cli/src/main/scripts/install new file mode 100755 index 00000000..8b4f8f61 --- /dev/null +++ b/MasterPassword/Java/masterpassword-cli/src/main/scripts/install @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# +# Install the Master Password CLI tool. +set -e +cd "${BASH_SOURCE%/*}" +source bashlib + +inf "This will install the mpw tool." + +# Try to guess then ask for the bin dir to install to. +IFS=: read -a paths <<< "$PATH" +if inArray ~/bin "${paths[@]}"; then + bindir=~/bin +elif inArray ~/.bin "${paths[@]}"; then + bindir=~/.bin +elif inArray /usr/local/bin "${paths[@]}"; then + bindir=/usr/local/bin +else + bindir=~/bin +fi +bindir=$(ask -d "$bindir" "What bin directory should I install to?") +[[ -d "$bindir" ]] || mkdir "$bindir" || ftl 'Cannot create missing bin directory: %s' "$bindir" || exit +[[ -w "$bindir" ]] || ftl 'Cannot write to bin directory: %s' "$bindir" || exit + +# Try to guess then ask for the share dir to install to. +sharedir=$(cd -P "$bindir/.."; [[ $bindir = */.bin ]] && printf '%s/.share' "$PWD" || printf '%s/share' "$PWD") +sharedir=$(ask -d "$sharedir" "What share directory should I install to?") +[[ -d "$sharedir" ]] || mkdir "$sharedir" || ftl 'Cannot create missing share directory: %s' "$sharedir" || exit +[[ -w "$sharedir" ]] || ftl 'Cannot write to share directory: %s' "$sharedir" || exit + +# Install Master Password. +sharepath=$sharedir/masterpassword +mkdir -p "$sharepath" +cp -a "masterpassword-cli-"*".jar" bashlib mpw "$sharepath" +ex -c "%s~%SHAREPATH%~$sharepath~g|x" "$sharepath/mpw" +ln -sf "$sharepath/mpw" "$bindir/mpw" +chmod +x "$sharepath/mpw" +[[ ! -e "$bindir/bashlib" ]] && ln -s "$sharepath/bashlib" "$bindir/bashlib" ||: + +# Convenience bash function. +inf "Installation successful!" +echo +inf "To improve usability, you can install an mpw function in your bash shell." +inf "This function adds the following features:" +inf " - Ask the Master Password once, remember in the shell." +inf " - Automatically put the password in the clipboard (some platforms)." +echo +inf "To do this you need the following function in ~/.bashrc:\n%s" "$(> ~/.bashrc + inf "Done! Don't forget to run '%s' to apply the changes!" "source ~/.bashrc" +fi +echo +inf "To begin using Master Password, type: mpw [site name]" diff --git a/MasterPassword/Java/masterpassword-cli/src/main/scripts/mpw b/MasterPassword/Java/masterpassword-cli/src/main/scripts/mpw index 9dbbe6a3..beb231b8 100755 --- a/MasterPassword/Java/masterpassword-cli/src/main/scripts/mpw +++ b/MasterPassword/Java/masterpassword-cli/src/main/scripts/mpw @@ -5,5 +5,5 @@ # Uncomment this to hardcode your master password. Make sure this file's permissions are tight. Master Password will not ask you for your master password anymore. This is probably not a good idea. # export MP_PASSWORD="banana colored duckling" -cd "${BASH_SOURCE[0]%/*}" -java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@" +cd "%SHAREPATH%" +exec java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@" diff --git a/MasterPassword/Java/masterpassword-cli/src/main/scripts/mpw.bashrc b/MasterPassword/Java/masterpassword-cli/src/main/scripts/mpw.bashrc new file mode 100644 index 00000000..6f790542 --- /dev/null +++ b/MasterPassword/Java/masterpassword-cli/src/main/scripts/mpw.bashrc @@ -0,0 +1,15 @@ +source bashlib +mpw() { + _nocopy() { echo >&2 "$(cat)"; } + _copy() { "$(type -P pbcopy || type -P xclip || echo _nocopy)"; } + + # Empty the clipboard + :| _copy 2>/dev/null + + # Ask for the user's name and password if not yet known. + MP_USERNAME=${MP_USERNAME:-$(ask -s 'Your Full Name:')} + MP_PASSWORD=${MP_PASSWORD:-$(ask -s 'Master Password:')} + + # Start Master Password and copy the output. + printf %s "$(MP_USERNAME=$MP_USERNAME MP_PASSWORD=$MP_PASSWORD command mpw "$@")" | _copy +} diff --git a/MasterPassword/Java/pom.xml b/MasterPassword/Java/pom.xml index 7db9107a..ea36869d 100644 --- a/MasterPassword/Java/pom.xml +++ b/MasterPassword/Java/pom.xml @@ -21,7 +21,7 @@ masterpassword-algorithm masterpassword-cli - masterpassword-android + diff --git a/MasterPassword/ObjC/MPAppDelegate_Store.m b/MasterPassword/ObjC/MPAppDelegate_Store.m index 79793f8c..752f6987 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Store.m +++ b/MasterPassword/ObjC/MPAppDelegate_Store.m @@ -274,7 +274,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext, #pragma mark - UbiquityStoreManagerDelegate -- (NSManagedObjectContext *)managedObjectContextForUbiquityChangesInManager:(UbiquityStoreManager *)manager { +- (NSManagedObjectContext *)ubiquityStoreManager:(UbiquityStoreManager *)manager managedObjectContextForUbiquityChanges:(NSNotification *)note { return [self mainManagedObjectContextIfReady]; } diff --git a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard index a647b2b6..0fd78c25 100644 --- a/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard +++ b/MasterPassword/ObjC/iOS/MainStoryboard_iPhone.storyboard @@ -1,8 +1,8 @@ - + - + diff --git a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj index a8ecf47b..0bffa382 100644 --- a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj +++ b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj @@ -15,9 +15,11 @@ 93D395F08A087F8A24689347 /* NSArray+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39067C0AFDC581794E2B8 /* NSArray+Indexing.m */; }; 93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3956915634581E737B38C /* PearlNavigationController.m */; }; 93D396BA1C74C4A06FD86437 /* PearlOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D3942A356B639724157982 /* PearlOverlay.h */; }; + 93D397952F5635C793C24DF1 /* NSError+MPFullDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39F9106F2CCFB94283188 /* NSError+MPFullDescription.m */; }; 93D3992FA1546E01F498F665 /* PearlNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */; }; 93D399433EA75E50656040CB /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93D394077F8FAB8167647187 /* Twitter.framework */; }; 93D399BBC0A7EC746CB1B19B /* MPLogsViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D391943675426839501BB8 /* MPLogsViewController.h */; }; + 93D39B842AB9A5D072810D76 /* NSError+MPFullDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D398C95847261903D781D3 /* NSError+MPFullDescription.h */; }; 93D39C34FE35830EF5BE1D2A /* NSArray+Indexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D396D04E57792A54D437AC /* NSArray+Indexing.h */; }; 93D39C8AD8EAB747856B3A8C /* LLModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D3923B42DA2DA18F287092 /* LLModel.m */; }; 93D39E281E3658B30550CB55 /* NSDictionary+Indexing.m in Sources */ = {isa = PBXBuildFile; fileRef = 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */; }; @@ -423,6 +425,7 @@ 93D3979190DACEBD1F6AE9F4 /* MPLogsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPLogsViewController.m; sourceTree = ""; }; 93D3983278751A530262F64E /* LLConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLConfig.h; sourceTree = ""; }; 93D398567FD02DB2647B8CF3 /* PearlNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlNavigationController.h; sourceTree = ""; }; + 93D398C95847261903D781D3 /* NSError+MPFullDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+MPFullDescription.h"; sourceTree = ""; }; 93D39A28369954D147E239BA /* MPSetupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSetupViewController.m; sourceTree = ""; }; 93D39A3CC4D8330831FC8CB4 /* LLToggleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LLToggleViewController.h; sourceTree = ""; }; 93D39AA1EE2E1E7B81372240 /* NSDictionary+Indexing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+Indexing.m"; sourceTree = ""; }; @@ -430,6 +433,7 @@ 93D39BF6BCBDFFE844E7D34C /* LLButtonView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLButtonView.m; sourceTree = ""; }; 93D39C8E26B06F01566785B7 /* LLToggleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LLToggleViewController.m; sourceTree = ""; }; 93D39F7C9F47BF6387FBC5C3 /* PearlEMail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlEMail.h; sourceTree = ""; }; + 93D39F9106F2CCFB94283188 /* NSError+MPFullDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+MPFullDescription.m"; sourceTree = ""; }; DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+PearlMutableInfo.h"; sourceTree = ""; }; DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+PearlMutableInfo.m"; sourceTree = ""; }; @@ -2693,6 +2697,8 @@ DAFE45F515039823003ABA7C /* PearlStringUtils.m */, DAFE45F815039823003ABA7C /* README */, DAFE45F915039823003ABA7C /* Resources */, + 93D39F9106F2CCFB94283188 /* NSError+MPFullDescription.m */, + 93D398C95847261903D781D3 /* NSError+MPFullDescription.h */, ); path = Pearl; sourceTree = ""; @@ -2886,6 +2892,7 @@ DA5E5C7417248959003798D8 /* sha256.h in Headers */, DA5E5C7517248959003798D8 /* sysendian.h in Headers */, DA5E5C7617248959003798D8 /* warn.h in Headers */, + 93D39B842AB9A5D072810D76 /* NSError+MPFullDescription.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3088,6 +3095,9 @@ DA5BFA43147E415C00F98B1E = { DevelopmentTeam = HL3Q45LX9N; SystemCapabilities = { + com.apple.BackgroundModes = { + enabled = 0; + }; com.apple.DataProtection = { enabled = 1; }; @@ -3403,7 +3413,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = "/bin/bash -e"; - shellScript = "../../../External/Crashlytics.framework/run \\\n \"$(/usr/libexec/PlistBuddy -c \"Print :'API Key'\" ../../Resources/Crashlytics/Crashlytics.plist)\""; + shellScript = "../../../External/Crashlytics.framework/run \\\n \"$(/usr/libexec/PlistBuddy -c \"Print :'API Key'\" ../../Resources/Crashlytics/Crashlytics.plist)\" || [[ $DEPLOYMENT_LOCATION != YES ]]"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -3531,6 +3541,7 @@ DA3509FF15F101A500C14A8E /* PearlQueue.m in Sources */, 93D3922A53E41A54832E90D9 /* PearlOverlay.m in Sources */, 93D396AA30690B256F30378A /* PearlNavigationController.m in Sources */, + 93D397952F5635C793C24DF1 /* NSError+MPFullDescription.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3822,7 +3833,8 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Maarten Billemont (DWGU95U4ZD)"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; EXCLUDED_SOURCE_FILE_NAMES = libTestFlight.a; GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword-Info.plist"; @@ -3831,6 +3843,7 @@ "-framework", Reveal, ); + PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "EBD2A2E4-AEC3-4EEA-8FF0-5F1A0D9FFA1C"; SKIP_INSTALL = NO; TARGETED_DEVICE_FAMILY = 1; @@ -3844,11 +3857,13 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Maarten Billemont (HL3Q45LX9N)"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; EXCLUDED_SOURCE_FILE_NAMES = ""; GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword-Info.plist"; + PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "4CBD21E7-DB60-4F7F-80F8-98DFA83D2CE0"; SKIP_INSTALL = NO; STRIP_INSTALLED_PRODUCT = YES; @@ -3975,7 +3990,8 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = MasterPassword.entitlements; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Maarten Billemont (HL3Q45LX9N)"; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; EXCLUDED_SOURCE_FILE_NAMES = ( libTestFlight.a, @@ -3983,6 +3999,7 @@ ); GCC_PREFIX_HEADER = "MasterPassword-Prefix.pch"; INFOPLIST_FILE = "MasterPassword-Info.plist"; + PROVISIONING_PROFILE = ""; "PROVISIONING_PROFILE[sdk=iphoneos*]" = "6C6B84DD-9D8F-4321-BD77-5F737DBE1778"; SKIP_INSTALL = NO; STRIP_INSTALLED_PRODUCT = YES; diff --git a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/xcshareddata/xcschemes/MasterPassword iOS (Development).xcscheme b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/xcshareddata/xcschemes/MasterPassword iOS (Development).xcscheme index 0b04c178..9cc7e2ed 100644 --- a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/xcshareddata/xcschemes/MasterPassword iOS (Development).xcscheme +++ b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/xcshareddata/xcschemes/MasterPassword iOS (Development).xcscheme @@ -28,16 +28,6 @@ shouldUseLaunchSchemeArgsEnv = "YES" buildConfiguration = "Debug-iOS"> - - - - +
+ Get it for: + iPhone | + PC (CLI) +
+
diff --git a/Site/2013-05/masterpassword-cli.zip b/Site/2013-05/masterpassword-cli.zip new file mode 100644 index 00000000..bc81e6c2 Binary files /dev/null and b/Site/2013-05/masterpassword-cli.zip differ