commit 2d5ae7524ae9183b96e7286bb3a271412dc02679
Author: Matthew Carlson <matt@mcarlson.xyz>
Date: Tue, 7 Sep 2021 04:29:56 -0400
Initial commit
Diffstat:
A | Makefile | | | 17 | +++++++++++++++++ |
A | README.md | | | 23 | +++++++++++++++++++++++ |
A | iwd-dmenu | | | 142 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 182 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,17 @@
+PREFIX ?= /usr
+
+all:
+ @echo Run \'make install\' as root to install iwd-dmenu.
+
+install:
+ @mkdir -p $(DESTDIR)$(PREFIX)/bin/
+ @echo Copying iwd-dmenu to $(DESTDIR)$(PREFIX)/bin/...
+ @cp -p iwd-dmenu $(DESTDIR)$(PREFIX)/bin/iwd-dmenu
+ @echo Running chmod 755 on $(DESTDIR)$(PREFIX)/bin/iwd-dmenu...
+ @chmod 755 $(DESTDIR)$(PREFIX)/bin/iwd-dmenu
+ @echo Installation successful.
+
+uninstall:
+ @ echo Removing /usr/bin/iwd-dmenu...
+ @rm -f $(PREFIX)/bin/iwd-dmenu
+ @echo iwd-dmenu uninstalled.
diff --git a/README.md b/README.md
@@ -0,0 +1,23 @@
+# iwd-dmenu
+An interactive iwd menu using dmenu.
+
+![iwd-dmenu](https://mcarlson.xyz/img/iwd-dmenu.png)
+
+Used with my [dotfiles](https://www.git.mcarlson.xyz/dots/). This script has some hacky solutions, will maybe improve them ¯\\\_(ツ)_/¯
+
+Aside from grep word boundaries, this script should be pretty portable.
+
+Some dependencies:
+- iwd (duh)
+- dmenu (with center and password patches)
+- [herbe](https://github.com/dudik/herbe)
+
+# Installation
+```shell
+$ git clone https://github.com/mslcarlson/iwd-dmenu/
+$ cd iwd-dmenu
+$ sudo make install
+```
+
+# Usage
+Just run `iwd-dmenu` from the command line.
diff --git a/iwd-dmenu b/iwd-dmenu
@@ -0,0 +1,142 @@
+#!/bin/sh
+#
+# iwd-dmenu
+
+NEWLINE='
+'
+
+iwd_dmenu() {
+ main_menu() {
+ while :; do
+ # get first 802.11 capable device from /sys/class/net
+ interface="$(for dev in /sys/class/net/*; do
+ [ -d "${dev}/wireless/" ] && printf '%s\n' "${dev##*/}"
+ done | head -n 1)"
+
+ # user can connect, disconnect, or forget network
+ # don't care bout access points or other stuff
+ if ! show_menu 'iwd dmenu' 'Connect' 'Disconnect' 'Forget'; then break; fi
+ done
+ }
+
+ connect() {
+ get_network_info "iwctl station ${interface} get-networks"
+
+ # user can choose network to connect to
+ network="$(show_menu 'Connect' "${network_names}")"
+
+ # if network starts with '> ' it means user is already on that network
+ case "${network}" in '> '*) herbe 'Already connected to this network' & return ;; esac
+
+ get_network_info 'iwctl known-networks list'
+
+ # if network is known connect with no passphrase
+ if printf '%s\n' "${network_info}" | awk -F '|' '{print $1}' | grep -iq "\<${network}\>"; then
+ iwctl station "${interface}" connect "${network}"
+ return
+ fi
+
+ get_network_info "iwctl station ${interface} get-networks"
+
+ # if network is wep, psk, or 8021x get passphrase
+ case "$(printf '%s\n' "${network_info}" | grep -i "\<${network}\>" | awk -F '|' '{print $2}')" in
+ 'wep'|'psk'|'8021x') get_passphrase ;;
+ # if open just connect without passphrase
+ 'open') iwctl station "${interface}" connect "${network}" ;;
+ esac
+
+ # connect with passphrase
+ [ -n "${passphrase}" ] && iwctl --passphrase "${passphrase}" station "${interface}" connect "${network}"
+ }
+
+ disconnect() {
+ connected_network="$(iwctl station "${interface}" show | grep -i '\<Connected network\>' | awk '{ $1=""; $2=""; sub(" ", " "); { $1=$1; print } }')"
+ if [ -n "${connected_network}" ]; then
+ answer="$(show_menu "Disconnect from ${connected_network}?" 'Yes' 'No')"
+ case "$(printf '%s\n' "${answer}" | tr '[:upper:]' '[:lower:]')" in
+ 'yes') iwctl station "${interface}" disconnect ;;
+ 'no') return ;;
+ esac
+ fi
+ }
+
+ forget() {
+ get_network_info 'iwctl known-networks list'
+
+ # if there are known networks
+ if [ -n "${network_names}" ]; then
+ # get network
+ network="$(show_menu 'Forget' "${network_names}")"
+
+ # get confirmation
+ answer="$(show_menu "Forget ${network}?" 'Yes' 'No')"
+
+ # forget if answer is yes
+ [ "${answer}" = 'Yes' ] && iwctl known-networks "${network}" forget
+ fi
+ }
+
+ # get network column separately
+ get_network_column() {
+ printf '%s\n' "${info}" | awk -v var="${1}" 'BEGIN { FS = "open|wep|psk|8021x" } { print $var }' | sed 's/^[ \t]*//;s/[ \t]*$//'
+ }
+
+ get_network_info() {
+ # scan interface
+ iwctl station "${interface}" scan
+
+ info="$(eval "${1}" | grep '\s' | tail +3 | awk '{ $1 = $1 }; 1' | sed -e 's/\x1b\[[0-9;]*m//g')"
+
+ network_names="$(get_network_column '1')"
+ network_types="$(printf '%s\n' "${info}" | awk '{ for (i=1;i<=NF;i++){ if ($i ~ /open|wep|psk|8021x/) { print $i } } }')"
+ network_metas="$(get_network_column '2')"
+
+ i=1
+ network_info="$(printf '%s\n' "${network_names}" | ( while read -r name; do
+ type_field="$(printf '%s\n' "${network_types}" | sed -n ${i}p)"
+ meta_field="$(printf '%s\n' "${network_metas}" | sed -n ${i}p)"
+
+ if [ ${i} -eq 1 ]; then network_info="${name}|${type_field}|${meta_field}"
+ else network_info="${network_info}${NEWLINE}${name}|${type_field}|${meta_field}"
+ fi
+
+ i=$((i+1))
+ done
+ printf '%s\n' "${network_info}" ))"
+ }
+
+ # hide input with dmenu -P flag
+ get_passphrase() { passphrase="$(dmenu -c -p 'Passphrase:' -P)" ; }
+
+ show_menu() {
+ # first arg is prompt
+ prompt="${1}"
+ shift
+
+ # remaining opts are options
+ options="$(for option in "${@}"; do
+ printf '%s\n' "${option}"
+ done)"
+
+ # print using dmenu
+ if ! answer="$(printf '%s\n' "${options}" | dmenu -c -l 10 -p "${prompt}")"; then return 1; fi
+
+ # get user's answer
+ printf '%s\n' "${options}" | while read -r line; do
+ if [ "${line}" = "${answer}" ]; then
+ # if answer is a function run it else just print it
+ cmd="$(printf '%s\n' "${answer}" | tr '[:upper:]' '[:lower:]')"
+ if command -v "${cmd}" >/dev/null 2>&1 && [ "${cmd}" != 'yes' ]; then "${cmd}"
+ else printf '%s\n' "${answer}"
+ fi
+ break
+ fi
+ done
+ }
+
+ main_menu
+}
+
+main() { iwd_dmenu ; }
+
+main "${@}"