In this patch, I've moved the filelock and all clipboard calls to after dmenu.
This allows you to escape dmenu without effecting the clipboard. Say
"xyz" is in your clipboard. You run passmenu and select a url, login and
password. Then you start passmenu again, but change your mind and hit escape.

The behavior previously would restore your clipboard to "xyz". The new
behavior keeps the selected passwords in queue. I find this behavior
preferable. 

Calling dmenu sooner should also have a small added benefit of making
the start of the program feel somewhat faster on slow machines.

I'm attaching two files. 
passmenu_multi-clip.patch # Contains 11 commits.
0001-Delayed-file-lock-improves-corner-case.patch # Contains 1 commit.


e6f32f4d33fe022c4b13def31c401890298e5b1e
 contrib/dmenu/passmenu | 51 +++++++++++++++++++++++++++-----------------------
 1 file changed, 28 insertions(+), 23 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index 68b4150..40dfe97 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -17,25 +17,37 @@ prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
 password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
-password=( ${password:-""} )
-before=( "${before:-}" )
-userID="$(id -u $(whoami))"
-stalelock=( "${stalelock:-""}" )
-stalelock=( "$(find '/tmp' -maxdepth 1 -name "passmenulock."$userID".*" -user 
$(whoami) -print0  -quit)" ) &&
-cleanup=True || { true; cleanup=False; }
+password=( '' )
+cleanup=( '' )
+before=( '' )
+userID=( "$(id -u $(whoami))" )
 
 _finish () {
-  [[ -n $before ]] &&
+  [[ True == $cleanup ]] &&
   printf "$before" | base64 -d | xclip -sel "$X_SELECTION" -i
   [[ True = "$cleanup" ]] &&
   if compgen -G "/tmp/passmenulock.1000*" >/dev/null 2>&1 ;then
-    rmdir /tmp/passmenulock."$userID".* >/dev/null 2>&1
+    rmdir /tmp/passmenulock.*.*."$$" >/dev/null 2>&1
   fi
   exit
 }
+
+## dmenu exits on KeyPress not KeyRelease.
+# It might be nice to send KeyRelease event to some dummy window.
+# psydocode: xdotool getwindowfocus; create dummy window;
+# exec dmenu; close dummy window; restore focus.
+for password in $(printf '%s\n' "${password_files[@]}" | dmenu -f "$@"); do
+  passel+=("$password")
+done
+
+[[ -n $password ]] || exit
+
 trap _finish EXIT
 
-## Clearing stale Xclip loops avoids a posible race condition.
+## Clearing old filelock(s). 
+umask 077
+stalelock=( "${stalelock:-''}" )
+stalelock=( "$(find '/tmp' -maxdepth 1 -name "passmenulock."$userID".*" -user 
$(whoami) -print0  -quit)" ) &&
 if test -n "$stalelock" ;then
   report=( "$(ps -u $(id -u $(whoami)) aux | grep "bash" | 
   grep "passmenu" | grep -v "$$")" )
@@ -44,26 +56,19 @@ if test -n "$stalelock" ;then
   if [[ "$report" == *"$stalePID"* ]] ;then
     kill "$stalePID" || exit 1
   else
-    rmdir /tmp/passmenulock.$userID.* >/dev/null 2>&1 || exit 1
+    rmdir /tmp/passmenulock."$userID".* >/dev/null 2>&1 ||
+    { echo ":: Unable to clear old filelock"; exit 1; }
   fi
 fi
 
-## dmenu exits on KeyPress not KeyRelease.
-# It would be nice to send KeyRelease event to some dummy window.
-# psydocode: xdotool getwindowfocus; create dummy window;
-# exec dmenu; close dummy window; restore focus.
-for password in $(printf '%s\n' "${password_files[@]}" | dmenu -f "$@"); do
-  passel+=("$password")
-done
-
-[[ -n $password ]] || exit
-# It would be nice to first somehow test if string exists.
-before="$(xclip -sel "$X_SELECTION" -o 2>/dev/null | base64)" || true
-
-umask 077
+## Adding a new filelock
 ( mktemp -d "/tmp/passmenulock."$userID".XXXXXXXXXX"."$$" >/dev/null 2>&1 && 
cleanup=True ||
   { echo >&2 ":: Unable to make a filelock."; exit 1; } )
 
+cleanup=True
+# It would be nice to first first test if string exists.
+before="$(xclip -sel "$X_SELECTION" -o 2>/dev/null | base64)" || true
+
 if [[ $typeit -eq 0 ]]; then
   if [ ${#passel[@]} -gt "1" ]; then
     round=0


-- 
At your service,
mitfree
http://ampling.com
From 1d2e5d9d0b3e46e1ce72e4151193eb648d668176 Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Fri, 8 Apr 2016 23:38:57 -0400
Subject: [PATCH 01/11] Adding xclip loop to select multiple pass entries.

---
 contrib/dmenu/passmenu | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index 7a9c517..b80399c 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -4,22 +4,27 @@ shopt -s nullglob globstar
 
 typeit=0
 if [[ $1 == "--type" ]]; then
-	typeit=1
-	shift
+    typeit=1
+    shift
 fi
 
+X_SELECTION="$PASSWORD_STORE_X_SELECTION"
 prefix=${PASSWORD_STORE_DIR-~/.password-store}
+
 password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
 
-password=$(printf '%s\n' "${password_files[@]}" | dmenu "$@")
+if [[ $typeit -eq 0 ]]; then
+    for password in $(printf '%s\n' "${password_files[@]}" | 
+	dmenu -f "$@"); do
+	pass show $password | 
+	    xclip -l 1 -quiet -sel $X_SELECTION
+    done
 
 [[ -n $password ]] || exit
 
-if [[ $typeit -eq 0 ]]; then
-	pass show -c "$password" 2>/dev/null
 else
-	pass show "$password" | { read -r pass; printf %s "$pass"; } |
-		xdotool type --clearmodifiers --file -
+    pass show "$password" | { read -r pass; printf %s "$pass"; } |
+	xdotool type --clearmodifiers --file -
 fi
-- 
2.8.0


From 4b003d9bbd9b79d71250aeee029468806bf16e09 Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Sat, 9 Apr 2016 00:46:26 -0400
Subject: [PATCH 02/11] Add condition to skip xclip loop on 1 selection.

---
 contrib/dmenu/passmenu | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index b80399c..ddfb07f 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -17,13 +17,20 @@ password_files=( "${password_files[@]%.gpg}" )
 
 if [[ $typeit -eq 0 ]]; then
     for password in $(printf '%s\n' "${password_files[@]}" | 
-	dmenu -f "$@"); do
-	pass show $password | 
-	    xclip -l 1 -quiet -sel $X_SELECTION
+	dmenu -f "$@");  do
+	lot+=($password)
     done
 
-[[ -n $password ]] || exit
+    [[ -n $password ]] || exit
 
+    if [ ${#lot[@]} -gt "0" ]; then
+	for entry in "${lot[@]}";  do
+	      pass show $entry | awk 'NR==1' | 
+	      xclip -l 1 -quiet -sel $X_SELECTION
+	done
+    else
+	pass show -c "$password" 2>/dev/null
+    fi
 else
     pass show "$password" | { read -r pass; printf %s "$pass"; } |
 	xdotool type --clearmodifiers --file -
-- 
2.8.0


From 1e52e9fc165961a94bc834d5fd58ee2669eaae1d Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Thu, 14 Apr 2016 02:03:17 -0400
Subject: [PATCH 03/11] Restores clipboard to previous state.

---
 contrib/dmenu/passmenu | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index ddfb07f..789d0de 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -15,22 +15,24 @@ password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
 
-if [[ $typeit -eq 0 ]]; then
-    for password in $(printf '%s\n' "${password_files[@]}" | 
-	dmenu -f "$@");  do
+for password in $(printf '%s\n' "${password_files[@]}" | 
+    dmenu -f "$@"); do
 	lot+=($password)
-    done
+done
 
-    [[ -n $password ]] || exit
+[[ -n $password ]] || exit
 
-    if [ ${#lot[@]} -gt "0" ]; then
-	for entry in "${lot[@]}";  do
-	      pass show $entry | awk 'NR==1' | 
-	      xclip -l 1 -quiet -sel $X_SELECTION
+if [[ $typeit -eq 0 ]]; then
+    xclip -sel clip -o | xclip -sel sec -i
+    if [ ${#lot[@]} -gt "1" ]; then
+	for entry in "${lot[@]}"; do
+	    pass show $entry | awk 'NR==1' | 
+	    xclip -l 1 -quiet -sel $X_SELECTION &>/dev/null
 	done
+    xclip -sel sec -o | xclip -sel clip -i
     else
-	pass show -c "$password" 2>/dev/null
-    fi
+	pass show -c "$password" &>/dev/null
+    fi 
 else
     pass show "$password" | { read -r pass; printf %s "$pass"; } |
 	xdotool type --clearmodifiers --file -
-- 
2.8.0


From 24d3194a119c4503d471d09159d11f3d4c12eda3 Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Fri, 22 Apr 2016 14:44:51 -0400
Subject: [PATCH 04/11] Clears secondary clipboard after use.

---
 contrib/dmenu/passmenu | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index 789d0de..84b4ae4 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -8,13 +8,14 @@ if [[ $1 == "--type" ]]; then
     shift
 fi
 
-X_SELECTION="$PASSWORD_STORE_X_SELECTION"
-prefix=${PASSWORD_STORE_DIR-~/.password-store}
+X_SELECTION="${PASSWORD_STORE_X_SELECTION:-clipboard}"
+prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
 
 password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
 
+## Press Ctrl-Return to continue selecting entries.
 for password in $(printf '%s\n' "${password_files[@]}" | 
     dmenu -f "$@"); do
 	lot+=($password)
@@ -23,15 +24,19 @@ done
 [[ -n $password ]] || exit
 
 if [[ $typeit -eq 0 ]]; then
-    xclip -sel clip -o | xclip -sel sec -i
+    xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
     if [ ${#lot[@]} -gt "1" ]; then
+        x=0
 	for entry in "${lot[@]}"; do
-	    pass show $entry | awk 'NR==1' | 
-	    xclip -l 1 -quiet -sel $X_SELECTION &>/dev/null
+	    printf '%s\n' "Sending "${lot[$x]}" via "$X_SELECTION""
+	    pass show $entry | head -n 1 | tr -d '\n' |
+	    xclip -l 1 -quiet -sel "$X_SELECTION" &>/dev/null
+	    x=`expr $x + 1`
 	done
-    xclip -sel sec -o | xclip -sel clip -i
+    xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
+    printf "" | xclip -sel sec -i 
     else
-	pass show -c "$password" &>/dev/null
+	pass -c "$password" 2>/dev/null
     fi 
 else
     pass show "$password" | { read -r pass; printf %s "$pass"; } |
-- 
2.8.0


From 8e25eeeab68810ec295fb5d8cb2b4412bcd529f2 Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Sat, 23 Apr 2016 02:36:55 -0400
Subject: [PATCH 05/11] Limits use of secondary clip to multi selections.

---
 contrib/dmenu/passmenu | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index 84b4ae4..a784481 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -24,17 +24,17 @@ done
 [[ -n $password ]] || exit
 
 if [[ $typeit -eq 0 ]]; then
-    xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
     if [ ${#lot[@]} -gt "1" ]; then
         x=0
+	xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
 	for entry in "${lot[@]}"; do
 	    printf '%s\n' "Sending "${lot[$x]}" via "$X_SELECTION""
 	    pass show $entry | head -n 1 | tr -d '\n' |
 	    xclip -l 1 -quiet -sel "$X_SELECTION" &>/dev/null
 	    x=`expr $x + 1`
 	done
-    xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
-    printf "" | xclip -sel sec -i 
+	xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
+	printf "" | xclip -sel sec -i
     else
 	pass -c "$password" 2>/dev/null
     fi 
-- 
2.8.0


From 20d3a8a8c55dfb31fa9cdc191b156f7d98ac3a53 Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Sat, 23 Apr 2016 17:12:29 -0400
Subject: [PATCH 06/11] Changes variables and comments for readability.

---
 contrib/dmenu/passmenu | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index a784481..45eb66f 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -8,30 +8,31 @@ if [[ $1 == "--type" ]]; then
     shift
 fi
 
-X_SELECTION="${PASSWORD_STORE_X_SELECTION:-clipboard}"
+X_SELECTION="${PASSWORD_STORE_X_SELECTION:-primary}"
 prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
 
 password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
 
-## Press Ctrl-Return to continue selecting entries.
+## dmenu exits on KeyPress.  
+## We should send KeyRelease event to some dummy window.
 for password in $(printf '%s\n' "${password_files[@]}" | 
     dmenu -f "$@"); do
-	lot+=($password)
+	passel+=($password)
 done
 
 [[ -n $password ]] || exit
 
 if [[ $typeit -eq 0 ]]; then
-    if [ ${#lot[@]} -gt "1" ]; then
-        x=0
+    if [ ${#passel[@]} -gt "1" ]; then
+        round=0
 	xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
-	for entry in "${lot[@]}"; do
-	    printf '%s\n' "Sending "${lot[$x]}" via "$X_SELECTION""
+	for entry in "${passel[@]}"; do
+	    printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
 	    pass show $entry | head -n 1 | tr -d '\n' |
 	    xclip -l 1 -quiet -sel "$X_SELECTION" &>/dev/null
-	    x=`expr $x + 1`
+	    round=`expr $round + 1`
 	done
 	xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
 	printf "" | xclip -sel sec -i
-- 
2.8.0


From 499a2b10739514860744c0179f00a551bd34cd12 Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Sat, 23 Apr 2016 20:22:08 -0400
Subject: [PATCH 07/11] Adding multi password selection to option --type.

---
 contrib/dmenu/passmenu | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index 45eb66f..1b0339f 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -40,6 +40,20 @@ if [[ $typeit -eq 0 ]]; then
 	pass -c "$password" 2>/dev/null
     fi 
 else
-    pass show "$password" | { read -r pass; printf %s "$pass"; } |
-	xdotool type --clearmodifiers --file -
+    if [ ${#passel[@]} -gt "1" ]; then
+        round=0
+	xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
+	for entry in "${passel[@]}"; do
+	    printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
+	    printf '' | xclip -l 1 -quiet -sel "$X_SELECTION" &>/dev/null
+	    pass show "$entry" | { read -r pass; printf %s "$pass"; } |
+		xdotool type --clearmodifiers --file -
+	    round=`expr $round + 1`
+	done
+	xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
+	printf "" | xclip -sel sec -i
+    else
+	pass show "$password" | { read -r pass; printf %s "$pass"; } |
+	    xdotool type --clearmodifiers --file -
+    fi
 fi
-- 
2.8.0


From 67dacee2237bf12dfa0f6e14806971ad2daab7ea Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Wed, 27 Apr 2016 20:29:07 -0400
Subject: [PATCH 08/11] Locks script and attemps to clear old loop.

---
 contrib/dmenu/passmenu | 91 ++++++++++++++++++++++++++++----------------------
 1 file changed, 52 insertions(+), 39 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index 1b0339f..e842f13 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -4,56 +4,69 @@ shopt -s nullglob globstar
 
 typeit=0
 if [[ $1 == "--type" ]]; then
-    typeit=1
-    shift
+  typeit=1
+  shift
 fi
 
-X_SELECTION="${PASSWORD_STORE_X_SELECTION:-primary}"
+X_SELECTION="${PASSWORD_STORE_X_SELECTION:-clipboard}"
 prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
 
 password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
 
-## dmenu exits on KeyPress.  
-## We should send KeyRelease event to some dummy window.
-for password in $(printf '%s\n' "${password_files[@]}" | 
-    dmenu -f "$@"); do
-	passel+=($password)
+## Preexisting xclip loops can cause unanticipated behavior.
+exec {lock_fd}>/tmp/passmenulock || exit 1
+flock -n "$lock_fd" || 
+  { xclip -sel "$X_SELECTION" -o >/dev/null 2>&1 
+    flock -n "$lock_fd" ||
+    printf '%s\n' 'Already running' >&2
+    exit 1
+  }
+
+## dmenu exits on KeyPress not KeyRelease.
+## It would be nice to send KeyRelease event to some dummy window.
+for password in $(printf '%s\n' "${password_files[@]}" |
+  dmenu -f "$@"); do
+  passel+=($password)
 done
 
 [[ -n $password ]] || exit
-
+ 
 if [[ $typeit -eq 0 ]]; then
-    if [ ${#passel[@]} -gt "1" ]; then
-        round=0
-	xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
-	for entry in "${passel[@]}"; do
-	    printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
-	    pass show $entry | head -n 1 | tr -d '\n' |
-	    xclip -l 1 -quiet -sel "$X_SELECTION" &>/dev/null
-	    round=`expr $round + 1`
-	done
-	xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
-	printf "" | xclip -sel sec -i
-    else
-	pass -c "$password" 2>/dev/null
-    fi 
+  if [ ${#passel[@]} -gt "1" ]; then
+    xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
+    round=0
+    for entry in "${passel[@]}"; do
+      printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
+      pass show $entry | sed '1!d' | tr -d '\n' |
+      xclip -l 1 -quiet -sel "$X_SELECTION" >/dev/null 2>&1
+      ~/bin/beeponce
+      round=`expr $round + 1`
+    done
+    xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
+  else
+    pass -c "$password" 2>/dev/null
+  fi
 else
-    if [ ${#passel[@]} -gt "1" ]; then
-        round=0
-	xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
-	for entry in "${passel[@]}"; do
-	    printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
-	    printf '' | xclip -l 1 -quiet -sel "$X_SELECTION" &>/dev/null
-	    pass show "$entry" | { read -r pass; printf %s "$pass"; } |
-		xdotool type --clearmodifiers --file -
-	    round=`expr $round + 1`
-	done
-	xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
-	printf "" | xclip -sel sec -i
-    else
-	pass show "$password" | { read -r pass; printf %s "$pass"; } |
-	    xdotool type --clearmodifiers --file -
-    fi
+  command -v xdotool >/dev/null 2>&1 ||
+  { echo >&2 "e: cannot find xdotool."; exit 1; }
+  if [ ${#passel[@]} -gt "1" ]; then
+    xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
+    round=0
+    for entry in "${passel[@]}"; do
+      printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
+      printf '' | xclip -l 1 -quiet -sel "$X_SELECTION" >/dev/null 2>&1
+      ~/bin/beeponce
+      pass show "$entry" | sed '1!d' | tr -d '\n' | 
+      xdotool type --clearmodifiers --file -
+      round=`expr $round + 1`
+    done
+    xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
+  else
+    pass show "$password" | sed '1!d' | tr -d '\n' |
+    xdotool type --clearmodifiers --file -
+  fi
 fi
+printf "" | xclip -sel sec -i
+flock -u "$lock_fd"
-- 
2.8.0


From 5cee86eb671b0db6229bcb490ca1762ae2eb8d76 Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Sun, 1 May 2016 17:49:36 -0400
Subject: [PATCH 09/11] A portable process lock avoids unanticipated behavior.

---
 contrib/dmenu/passmenu | 68 ++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 49 insertions(+), 19 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index e842f13..021c48f 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -1,6 +1,7 @@
 #!/usr/bin/env bash
 
 shopt -s nullglob globstar
+set -o errexit
 
 typeit=0
 if [[ $1 == "--type" ]]; then
@@ -9,64 +10,93 @@ if [[ $1 == "--type" ]]; then
 fi
 
 X_SELECTION="${PASSWORD_STORE_X_SELECTION:-clipboard}"
+CLIP_TIME="${PASSWORD_STORE_CLIP_TIME:-45}"
 prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
 
 password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
 
-## Preexisting xclip loops can cause unanticipated behavior.
-exec {lock_fd}>/tmp/passmenulock || exit 1
-flock -n "$lock_fd" || 
-  { xclip -sel "$X_SELECTION" -o >/dev/null 2>&1 
-    flock -n "$lock_fd" ||
-    printf '%s\n' 'Already running' >&2
-    exit 1
+_finish () {
+  [[ 1 = "$remove" ]]
+    rmdir /tmp/passmenu."$uid".* 2>/dev/null
+    ## kill more child processes here.
+    # echo $(ps -o pgid=$$ | grep -o [0-9]*)
+    printf "$buffer" | xclip -sel "$X_SELECTION" -i
+  exit
   }
+trap _finish EXIT
+
+_fire () {
+  stale="$(find /tmp/passmenu."$uid".* -print -quit | 
+  sed -e "s/\/tmp\/passmenu\.[0-9]\{1,6\}\?\..*\.//g")"
+  report="$(ps -u $(id -u $(whoami)) aux | grep "bash" | 
+  grep "passmenu" | grep -v "$$")"
+  if [[ "$report" == *"passmenu"* ]] ;then 
+    kill "$stale" && rmdir /tmp/passmenu.$uid.* >/dev/null 2>&1 || exit 1
+  else
+    rmdir /tmp/passmenu.$uid.* >/dev/null 2>&1 || exit 1
+  fi
+}
+
+## Clearing stale Xclip loops avoids a posible race condition.
+uid="$(id -u $(whoami))"
+remove=0
+if compgen -G "/tmp/passmenu.1000*" >/dev/null 2>&1 ;then
+  question=$(printf 'yes\nno'|
+  dmenu -nf red -f -p "The clipboard is locked by another process. Kill it with fire?")
+  if [ "$question" = 'yes' ] ;then
+    _fire
+  else
+    exit 0
+  fi
+fi
 
 ## dmenu exits on KeyPress not KeyRelease.
 ## It would be nice to send KeyRelease event to some dummy window.
+## psydocode: xdotool getwindowfocus; create dummy window;
+## exec dmenu; close dummy window; restore focus.
 for password in $(printf '%s\n' "${password_files[@]}" |
   dmenu -f "$@"); do
-  passel+=($password)
+  passel+=("$password")
 done
 
 [[ -n $password ]] || exit
- 
+
+umask 077
+mktemp -d "/tmp/passmenu."$uid".XXXXXXXXXX"."$$" >/dev/null 2>&1 || exit 1  
+remove=1
+
+buffer="$(xclip -sel "$X_SELECTION" -o)"
 if [[ $typeit -eq 0 ]]; then
   if [ ${#passel[@]} -gt "1" ]; then
-    xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
     round=0
     for entry in "${passel[@]}"; do
       printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
-      pass show $entry | sed '1!d' | tr -d '\n' |
+      pass show "$entry" | sed '1!d' | tr -d '\n' |
       xclip -l 1 -quiet -sel "$X_SELECTION" >/dev/null 2>&1
-      ~/bin/beeponce
       round=`expr $round + 1`
     done
-    xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
   else
-    pass -c "$password" 2>/dev/null
+    pass show "$password" | sed '1!d' | tr -d '\n' |
+    xclip -sel "$X_SELECTION" -i 
+    sleep "$CLIP_TIME"
   fi
 else
   command -v xdotool >/dev/null 2>&1 ||
   { echo >&2 "e: cannot find xdotool."; exit 1; }
   if [ ${#passel[@]} -gt "1" ]; then
-    xclip -sel "$X_SELECTION" -o | xclip -sel sec -i
     round=0
     for entry in "${passel[@]}"; do
       printf '%s\n' "Sending "${passel[$round]}" via "$X_SELECTION""
       printf '' | xclip -l 1 -quiet -sel "$X_SELECTION" >/dev/null 2>&1
-      ~/bin/beeponce
       pass show "$entry" | sed '1!d' | tr -d '\n' | 
       xdotool type --clearmodifiers --file -
       round=`expr $round + 1`
     done
-    xclip -sel sec -o | xclip -sel "$X_SELECTION" -i
   else
     pass show "$password" | sed '1!d' | tr -d '\n' |
     xdotool type --clearmodifiers --file -
   fi
 fi
-printf "" | xclip -sel sec -i
-flock -u "$lock_fd"
+exit
-- 
2.8.0


From f8b10ed59edbb293e3728f29fc087ddcf316cc3c Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Fri, 6 May 2016 11:58:34 -0400
Subject: [PATCH 10/11] Adding strict mode.

---
 contrib/dmenu/passmenu | 58 ++++++++++++++++++++++----------------------------
 1 file changed, 26 insertions(+), 32 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index 021c48f..e6e2cfc 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -1,10 +1,11 @@
 #!/usr/bin/env bash
 
-shopt -s nullglob globstar
-set -o errexit
+shopt -s nullglob globstar failglob
+set -euo pipefail
 
+tool=${1:-} 
 typeit=0
-if [[ $1 == "--type" ]]; then
+if [[ $tool == "--type" ]]; then
   typeit=1
   shift
 fi
@@ -18,56 +19,49 @@ password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
 
 _finish () {
-  [[ 1 = "$remove" ]]
-    rmdir /tmp/passmenu."$uid".* 2>/dev/null
-    ## kill more child processes here.
-    # echo $(ps -o pgid=$$ | grep -o [0-9]*)
-    printf "$buffer" | xclip -sel "$X_SELECTION" -i
+  [[ -n $before ]] &&
+  printf "$before" | xclip -sel "$X_SELECTION" -i
+  [[ True = "$remove" ]] &&
+  if compgen -G "/tmp/passmenu.1000*" >/dev/null 2>&1 ;then
+    rmdir /tmp/passmenu."$uid".* >/dev/null 2>&1
+  fi
   exit
-  }
+}
 trap _finish EXIT
 
-_fire () {
+## Clearing stale Xclip loops avoids a posible race condition.
+uid="$(id -u $(whoami))"
+remove=False
+if compgen -G "/tmp/passmenu.1000*" >/dev/null 2>&1 ;then
   stale="$(find /tmp/passmenu."$uid".* -print -quit | 
   sed -e "s/\/tmp\/passmenu\.[0-9]\{1,6\}\?\..*\.//g")"
   report="$(ps -u $(id -u $(whoami)) aux | grep "bash" | 
   grep "passmenu" | grep -v "$$")"
-  if [[ "$report" == *"passmenu"* ]] ;then 
+  if [[ "$report" == *"$stale"* ]] ;then 
     kill "$stale" && rmdir /tmp/passmenu.$uid.* >/dev/null 2>&1 || exit 1
   else
     rmdir /tmp/passmenu.$uid.* >/dev/null 2>&1 || exit 1
   fi
-}
-
-## Clearing stale Xclip loops avoids a posible race condition.
-uid="$(id -u $(whoami))"
-remove=0
-if compgen -G "/tmp/passmenu.1000*" >/dev/null 2>&1 ;then
-  question=$(printf 'yes\nno'|
-  dmenu -nf red -f -p "The clipboard is locked by another process. Kill it with fire?")
-  if [ "$question" = 'yes' ] ;then
-    _fire
-  else
-    exit 0
-  fi
 fi
 
 ## dmenu exits on KeyPress not KeyRelease.
 ## It would be nice to send KeyRelease event to some dummy window.
 ## psydocode: xdotool getwindowfocus; create dummy window;
 ## exec dmenu; close dummy window; restore focus.
-for password in $(printf '%s\n' "${password_files[@]}" |
-  dmenu -f "$@"); do
+password=${password:-}
+for password in $(printf '%s\n' "${password_files[@]}" | dmenu -f "$@"); do
   passel+=("$password")
 done
 
+before=${before:-}
 [[ -n $password ]] || exit
+before="$(xclip -sel "$X_SELECTION" -o >/dev/null 2>&1)" || true
 
 umask 077
-mktemp -d "/tmp/passmenu."$uid".XXXXXXXXXX"."$$" >/dev/null 2>&1 || exit 1  
-remove=1
+mktemp -d "/tmp/passmenu."$uid".XXXXXXXXXX"."$$" >/dev/null 2>&1 ||
+{ echo >&2 ":: Unable to make a filelock."; exit 1; }
+remove=True
 
-buffer="$(xclip -sel "$X_SELECTION" -o)"
 if [[ $typeit -eq 0 ]]; then
   if [ ${#passel[@]} -gt "1" ]; then
     round=0
@@ -78,12 +72,12 @@ if [[ $typeit -eq 0 ]]; then
       round=`expr $round + 1`
     done
   else
+    printf '%s\n' "Sending "$password" via "$X_SELECTION""
     pass show "$password" | sed '1!d' | tr -d '\n' |
-    xclip -sel "$X_SELECTION" -i 
-    sleep "$CLIP_TIME"
+    xclip -sel "$X_SELECTION" -i && sleep "$CLIP_TIME" 
   fi
 else
-  command -v xdotool >/dev/null 2>&1 ||
+  command -v xdotool >/dev/null 2>&1 || 
   { echo >&2 "e: cannot find xdotool."; exit 1; }
   if [ ${#passel[@]} -gt "1" ]; then
     round=0
-- 
2.8.0


From 90a3613d854085e1fe1416714729aa24e2013cf3 Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Sat, 7 May 2016 06:14:50 -0400
Subject: [PATCH 11/11] Improved filelock, and more appropriate variable names.

---
 contrib/dmenu/passmenu | 48 +++++++++++++++++++++++++-----------------------
 1 file changed, 25 insertions(+), 23 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index e6e2cfc..68b4150 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -17,50 +17,52 @@ prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
 password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
+password=( ${password:-""} )
+before=( "${before:-}" )
+userID="$(id -u $(whoami))"
+stalelock=( "${stalelock:-""}" )
+stalelock=( "$(find '/tmp' -maxdepth 1 -name "passmenulock."$userID".*" -user $(whoami) -print0  -quit)" ) &&
+cleanup=True || { true; cleanup=False; }
 
 _finish () {
   [[ -n $before ]] &&
-  printf "$before" | xclip -sel "$X_SELECTION" -i
-  [[ True = "$remove" ]] &&
-  if compgen -G "/tmp/passmenu.1000*" >/dev/null 2>&1 ;then
-    rmdir /tmp/passmenu."$uid".* >/dev/null 2>&1
+  printf "$before" | base64 -d | xclip -sel "$X_SELECTION" -i
+  [[ True = "$cleanup" ]] &&
+  if compgen -G "/tmp/passmenulock.1000*" >/dev/null 2>&1 ;then
+    rmdir /tmp/passmenulock."$userID".* >/dev/null 2>&1
   fi
   exit
 }
 trap _finish EXIT
 
 ## Clearing stale Xclip loops avoids a posible race condition.
-uid="$(id -u $(whoami))"
-remove=False
-if compgen -G "/tmp/passmenu.1000*" >/dev/null 2>&1 ;then
-  stale="$(find /tmp/passmenu."$uid".* -print -quit | 
-  sed -e "s/\/tmp\/passmenu\.[0-9]\{1,6\}\?\..*\.//g")"
-  report="$(ps -u $(id -u $(whoami)) aux | grep "bash" | 
-  grep "passmenu" | grep -v "$$")"
-  if [[ "$report" == *"$stale"* ]] ;then 
-    kill "$stale" && rmdir /tmp/passmenu.$uid.* >/dev/null 2>&1 || exit 1
+if test -n "$stalelock" ;then
+  report=( "$(ps -u $(id -u $(whoami)) aux | grep "bash" | 
+  grep "passmenu" | grep -v "$$")" )
+  stalePID=( "$(printf $stalelock | 
+  sed -e "s/\/tmp\/passmenulock\.[0-9]\{1,6\}\?\..*\.//g")" )
+  if [[ "$report" == *"$stalePID"* ]] ;then
+    kill "$stalePID" || exit 1
   else
-    rmdir /tmp/passmenu.$uid.* >/dev/null 2>&1 || exit 1
+    rmdir /tmp/passmenulock.$userID.* >/dev/null 2>&1 || exit 1
   fi
 fi
 
 ## dmenu exits on KeyPress not KeyRelease.
-## It would be nice to send KeyRelease event to some dummy window.
-## psydocode: xdotool getwindowfocus; create dummy window;
-## exec dmenu; close dummy window; restore focus.
-password=${password:-}
+# It would be nice to send KeyRelease event to some dummy window.
+# psydocode: xdotool getwindowfocus; create dummy window;
+# exec dmenu; close dummy window; restore focus.
 for password in $(printf '%s\n' "${password_files[@]}" | dmenu -f "$@"); do
   passel+=("$password")
 done
 
-before=${before:-}
 [[ -n $password ]] || exit
-before="$(xclip -sel "$X_SELECTION" -o >/dev/null 2>&1)" || true
+# It would be nice to first somehow test if string exists.
+before="$(xclip -sel "$X_SELECTION" -o 2>/dev/null | base64)" || true
 
 umask 077
-mktemp -d "/tmp/passmenu."$uid".XXXXXXXXXX"."$$" >/dev/null 2>&1 ||
-{ echo >&2 ":: Unable to make a filelock."; exit 1; }
-remove=True
+( mktemp -d "/tmp/passmenulock."$userID".XXXXXXXXXX"."$$" >/dev/null 2>&1 && cleanup=True ||
+  { echo >&2 ":: Unable to make a filelock."; exit 1; } )
 
 if [[ $typeit -eq 0 ]]; then
   if [ ${#passel[@]} -gt "1" ]; then
-- 
2.8.0

From e6f32f4d33fe022c4b13def31c401890298e5b1e Mon Sep 17 00:00:00 2001
From: ampling <[email protected]>
Date: Fri, 13 May 2016 16:40:32 -0400
Subject: [PATCH] Delayed file-lock improves corner-case.

---
 contrib/dmenu/passmenu | 51 +++++++++++++++++++++++++++-----------------------
 1 file changed, 28 insertions(+), 23 deletions(-)

diff --git a/contrib/dmenu/passmenu b/contrib/dmenu/passmenu
index 68b4150..40dfe97 100755
--- a/contrib/dmenu/passmenu
+++ b/contrib/dmenu/passmenu
@@ -17,25 +17,37 @@ prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store}"
 password_files=( "$prefix"/**/*.gpg )
 password_files=( "${password_files[@]#"$prefix"/}" )
 password_files=( "${password_files[@]%.gpg}" )
-password=( ${password:-""} )
-before=( "${before:-}" )
-userID="$(id -u $(whoami))"
-stalelock=( "${stalelock:-""}" )
-stalelock=( "$(find '/tmp' -maxdepth 1 -name "passmenulock."$userID".*" -user $(whoami) -print0  -quit)" ) &&
-cleanup=True || { true; cleanup=False; }
+password=( '' )
+cleanup=( '' )
+before=( '' )
+userID=( "$(id -u $(whoami))" )
 
 _finish () {
-  [[ -n $before ]] &&
+  [[ True == $cleanup ]] &&
   printf "$before" | base64 -d | xclip -sel "$X_SELECTION" -i
   [[ True = "$cleanup" ]] &&
   if compgen -G "/tmp/passmenulock.1000*" >/dev/null 2>&1 ;then
-    rmdir /tmp/passmenulock."$userID".* >/dev/null 2>&1
+    rmdir /tmp/passmenulock.*.*."$$" >/dev/null 2>&1
   fi
   exit
 }
+
+## dmenu exits on KeyPress not KeyRelease.
+# It might be nice to send KeyRelease event to some dummy window.
+# psydocode: xdotool getwindowfocus; create dummy window;
+# exec dmenu; close dummy window; restore focus.
+for password in $(printf '%s\n' "${password_files[@]}" | dmenu -f "$@"); do
+  passel+=("$password")
+done
+
+[[ -n $password ]] || exit
+
 trap _finish EXIT
 
-## Clearing stale Xclip loops avoids a posible race condition.
+## Clearing old filelock(s). 
+umask 077
+stalelock=( "${stalelock:-''}" )
+stalelock=( "$(find '/tmp' -maxdepth 1 -name "passmenulock."$userID".*" -user $(whoami) -print0  -quit)" ) &&
 if test -n "$stalelock" ;then
   report=( "$(ps -u $(id -u $(whoami)) aux | grep "bash" | 
   grep "passmenu" | grep -v "$$")" )
@@ -44,26 +56,19 @@ if test -n "$stalelock" ;then
   if [[ "$report" == *"$stalePID"* ]] ;then
     kill "$stalePID" || exit 1
   else
-    rmdir /tmp/passmenulock.$userID.* >/dev/null 2>&1 || exit 1
+    rmdir /tmp/passmenulock."$userID".* >/dev/null 2>&1 ||
+    { echo ":: Unable to clear old filelock"; exit 1; }
   fi
 fi
 
-## dmenu exits on KeyPress not KeyRelease.
-# It would be nice to send KeyRelease event to some dummy window.
-# psydocode: xdotool getwindowfocus; create dummy window;
-# exec dmenu; close dummy window; restore focus.
-for password in $(printf '%s\n' "${password_files[@]}" | dmenu -f "$@"); do
-  passel+=("$password")
-done
-
-[[ -n $password ]] || exit
-# It would be nice to first somehow test if string exists.
-before="$(xclip -sel "$X_SELECTION" -o 2>/dev/null | base64)" || true
-
-umask 077
+## Adding a new filelock
 ( mktemp -d "/tmp/passmenulock."$userID".XXXXXXXXXX"."$$" >/dev/null 2>&1 && cleanup=True ||
   { echo >&2 ":: Unable to make a filelock."; exit 1; } )
 
+cleanup=True
+# It would be nice to first first test if string exists.
+before="$(xclip -sel "$X_SELECTION" -o 2>/dev/null | base64)" || true
+
 if [[ $typeit -eq 0 ]]; then
   if [ ${#passel[@]} -gt "1" ]; then
     round=0
-- 
2.8.0

Attachment: signature.asc
Description: signature

_______________________________________________
Password-Store mailing list
[email protected]
http://lists.zx2c4.com/mailman/listinfo/password-store

Reply via email to