As mentioned before, I set up RDP with real certs on my RDP hosts. I also frequently access those from my linux-laptop, and the way I had been doing that up until today was "ctrl-r"-ing through my bash history for xfreerdp
. I decided to put an end to that today, with something that could be called from within dmenu
.
#!/bin/sh
USER=josh
PASSWORD=""
# first, figure out which host we're accessing.
case $1 in
host1)
HOST=host1.joshgordon.net
;;
host2)
HOST=host2.joshgordon.net
;;
*)
zenity --warning --text="Invalid host"
exit 2
;;
esac
# get the password
xfrdp_res=1
# 0 = exited from linux
# 11 = disconnected
# 12 = signed off
while [ $xfrdp_res -ne 0 ] && [ $xfrdp_res -ne 11 ] && [ $xfrdp_res -ne 12 ]; do
# prompt for the psasword from the user
PASSWORD=$(zenity --password)
res=$?
# catch the password prompt being cancelled
if [ $res -ne 0 ]; then
echo "Cancelled"
exit 1
fi
# try xfreerdp with the user/password pair
xfreerdp /v:"$HOST" /u:"$USER" /p:"$PASSWORD" /f /d:WORKGROUP
xfrdp_res=$?
done
Alright, great. I can now type rdp host1
and get asked for a password. If I hit cancel, it doesn't re-prompt me, if I quit xfreerdp, it doesn't re-prompt me, but if I type my password wrong, it'll re-prompt me and retry. But there's just one small problem now.
I'm lazy.
I have to type out the whole host1
(which has been shortened for this example to omit real hostnames). I'd rather just have dmenu autocomplete these for me.
Digging into dmenu
So what really happens when I launch dmenu from i3?
[josh@laptop ~]$ cat ~/.config/i3/config | grep mod+d
bindsym $mod+d exec dmenu_run
Alright, what's behind dmenu_run
?
[josh@laptop ~]$ which dmenu_run
/usr/bin/dmenu_run
And that's.... A shell script!
[josh@laptop ~]$ cat /usr/bin/dmenu_run
#!/usr/bin/sh
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
I dug into what dmenu_path
does, and it just returns a list of commands that dmenu
can run (with some fancy caching on top). So all we need to do is whack a couple of extra lines into that command's output.
Let's make this simple. Let's make our own dmenu_run
:
#!/usr/bin/bash
cat <(dmenu_path) /dev/stdin <<EOF | dmenu "$@" | ${SHELL:-"/bin/sh"} &
rdp host1
rdp host2
EOF
That lives in my ~/bin/ directory, which exists in my PATH before any of the defaults.
That's it, we're done. dmenu now autocompletes my rdp
command.
If you don't know what the <() syntax is, it's bash syntax for process substitution. It spawns the command in the parens, and returns the file handle for stdout of the subprocess as a file handle.