~mil/sxmo-utils

049a93e5d86d242b58b0b8cad0a274c73ee9deb5 — Miles Alan 1 year, 5 months ago bd5ead1
Shellcheck and tabindent all scripts
M README.md => README.md +2 -2
@@ 1,5 1,5 @@
# sxmo-utils

This repository contains scripts and C programs to support sxmo.

This repository contains scripts and C programs to support Sxmo.

Note all scripts pass shellcheck and are tab-idented.

M scripts/appscripts/sxmo_record.sh => scripts/appscripts/sxmo_record.sh +1 -1
@@ 47,7 47,7 @@ record() {
}

while true; do
	NRECORDINGS="$(ls -1 "$RECDIR" | wc -l)"
	NRECORDINGS="$(find "$RECDIR" -type f | wc -l)"
	OPTION="$(
		printf %b "Line Jack\nMicrophone\n($NRECORDINGS) Recordings\nClose Menu" |
		dmenu -fn Terminus-30 -c -p "Record" -l 20

M scripts/appscripts/sxmo_rss.sh => scripts/appscripts/sxmo_rss.sh +30 -19
@@ 1,31 1,42 @@
#!/usr/bin/env sh
SFEEDCONF=/usr/share/sxmo/sxmo_sfeedrc
if [ -f "$XDG_CONFIG_HOME/sxmo/sfeedrc" ]; then
	SFEEDCONF="$XDG_CONFIG_HOME/sxmo/sfeedrc"
elif [ -f "$HOME/.sfeed/sfeedrc" ]; then
	SFEEDCONF="$HOME/.sfeed/sfeedrc"
else
	SFEEDCONF=/usr/share/sxmo/sxmo_sfeedrc
fi

die() {
	echo "Error: $1"
	exit 1
}

tflt() {
  # Date with feature like "1 day ago" etc main reason
  # coreutils is a dep...
  TIME=$(eval date -d \""$TIMESPAN"\" +%s)
  cat | gawk "\$1 > $TIME"
	# Date with feature like "1 day ago" etc main reason
	# coreutils is a dep...
	TIME=$(eval date -d \""$TIMESPAN"\" +%s)
	cat | gawk "\$1 > $TIME"
}

prep_temp_folder_with_items() {
    mkdir -p $FOLDER
    rm -rf $FOLDER/*
    cd ~/.sfeed/feeds/
    for f in $(ls)
    do
      cat $f | tflt $@ > $FOLDER/$f
      [ -s $FOLDER/$f ] || rm $FOLDER/$f
    done
	mkdir -p "$FOLDER"
	rm -rf "${FOLDER:?}/*"
	cd ~/.sfeed/feeds/ || die "Could cd to ~/.sfeed/feeds/"
	for f in ./*; do
		fclean="$(basename "$f")"
		tflt < "$fclean" > "$FOLDER/$fclean"
		[ -s "$FOLDER/$fclean" ] || rm "${FOLDER:?}/$fclean"
	done
}

list_items() {
    cd $FOLDER
    gawk -F'\t' '{print $1 " " FILENAME " | " $2 ": " $3}' * |\
    grep -E '^[0-9]{5}' |\
    sort -nk1 |\
    sort -r |\
    gawk -F' ' '{printf strftime("%y/%m/%d %H:%M",$1); $1=""; print $0}'
	cd "$FOLDER" || die "Couldn't cd to $FOLDER"
	gawk -F'\t' '{print $1 " " substr(FILENAME, 3) " | " $2 ": " $3}' ./* |\
	grep -E '^[0-9]{5}' |\
	sort -nk1 |\
	sort -r |\
	gawk -F' ' '{printf strftime("%y/%m/%d %H:%M",$1); $1=""; print $0}'
}

# Update Sfeed

M scripts/appscripts/sxmo_weather.sh => scripts/appscripts/sxmo_weather.sh +10 -10
@@ 2,16 2,16 @@

pidof svkbd-sxmo || svkbd-sxmo &
ZIP=$(
  printf %b "
    10025 - NYC
    60007 - Chicago
    94016 - San Francisco
    97035 - Portland, OR
  " |
  awk 'NF' |
  awk '{$1=$1};1' |
  dmenu -fn Terminus-20 -i -c -l 10 -p "US Zipcode" |
  awk -F " " '{print $1}'
	printf %b "
		10025 - NYC
		60007 - Chicago
		94016 - San Francisco
		97035 - Portland, OR
	" |
	awk 'NF' |
	awk '{$1=$1};1' |
	dmenu -fn Terminus-20 -i -c -l 10 -p "US Zipcode" |
	awk -F " " '{print $1}'
)
pkill svkbd-sxmo


M scripts/appscripts/sxmo_websearch.sh => scripts/appscripts/sxmo_websearch.sh +1 -1
@@ 1,7 1,7 @@
#!/usr/bin/env sh
pidof svkbd-sxmo || svkbd-sxmo &
SEARCHQUERY="$(
  echo "Close Menu" | dmenu -t -p "Search Query:" -c -fn "Terminus-20" -l 20
	echo "Close Menu" | dmenu -t -p "Search Query:" -c -fn "Terminus-20" -l 20
)"
pkill svkbd-sxmo
echo "$SEARCHQUERY" | grep . || exit 0

M scripts/core/sxmo_appmenu.sh => scripts/core/sxmo_appmenu.sh +229 -209
@@ 2,228 2,248 @@
WIN=$(xdotool getwindowfocus)

programchoicesinit() {
  XPROPOUT="$(xprop -id $(xdotool getactivewindow))"
  WMCLASS="${1:-$(echo "$XPROPOUT" | grep WM_CLASS | cut -d ' ' -f3-)}"

  # Default system menu (no matches)
  CHOICES="$(echo "
    $(
      [ -n "$(ls -A $XDG_CONFIG_HOME/sxmo/userscripts)" ] && 
      echo 'Userscripts  ^ 0 ^ sxmo_appmenu.sh userscripts'
    )
    Scripts              ^ 0 ^ sxmo_appmenu.sh scripts
    Apps                 ^ 0 ^ sxmo_appmenu.sh applications
    Volume ↑             ^ 1 ^ sxmo_vol.sh up
    Volume ↓             ^ 1 ^ sxmo_vol.sh down
    Dialer               ^ 0 ^ sxmo_modemcall.sh dial
    Texts                ^ 0 ^ sxmo_modemtext.sh
    Camera               ^ 0 ^ sxmo_camera.sh
    Wifi                 ^ 0 ^ st -e "nmtui"
    Audio                ^ 0 ^ sxmo_appmenu.sh audioout
    Config               ^ 0 ^ sxmo_appmenu.sh config
    Logout               ^ 0 ^ pkill -9 dwm
  ")" && WINNAME=Sys

  # Userscripts menu
  echo $WMCLASS | grep -i "userscripts" && CHOICES="$(
    ls -1 $XDG_CONFIG_HOME/sxmo/userscripts |
    sed 's/ /\\ /' |
    awk '{printf "%s\t^ 0 ^ $XDG_CONFIG_HOME/sxmo/userscripts/%s \n", $0, $0}'
  )" && WINNAME=Userscripts && return

  # Scripts menu
  echo $WMCLASS | grep -i "scripts" && CHOICES="$(echo "
    Web Search      ^ 0 ^ sxmo_websearch.sh
    Files           ^ 0 ^ sxmo_files.sh
    Record          ^ 0 ^ sxmo_record.sh
    Timer           ^ 0 ^ sxmo_timer.sh
    Youtube         ^ 0 ^ sxmo_youtube.sh video
    Youtube (Audio) ^ 0 ^ sxmo_youtube.sh audio
    Weather         ^ 0 ^ sxmo_weather.sh
    RSS             ^ 0 ^ sxmo_rss.sh
  ")" && WINNAME=Scripts && return

  # Apps menu
  echo $WMCLASS | grep -i "applications" && CHOICES="$(echo "
    Surf            ^ 0 ^ surf
    Netsurf         ^ 0 ^ netsurf
    Firefox         ^ 0 ^ firefox
    Sacc            ^ 0 ^ st -e sacc i-logout.cz/1/bongusta
    W3m             ^ 0 ^ st -e w3m duck.com
    Xcalc           ^ 0 ^ xcalc
    St              ^ 0 ^ st
    Foxtrotgps      ^ 0 ^ foxtrotgps
  ")" && WINNAME=Apps && return

  # System Control menu
  echo $WMCLASS | grep -i "config" && CHOICES="$(echo "
    Brightesss ↑               ^ 1 ^ sxmo_brightness.sh up
    Brightness ↓               ^ 1 ^ sxmo_brightness.sh down
    Modem Toggle               ^ 1 ^ sxmo_modemmonitortoggle.sh
    Modem Info                 ^ 0 ^ sxmo_modeminfo.sh
    Modem Log                  ^ 0 ^ sxmo_modemlog.sh
    Flash $(
      cat /sys/class/leds/white:flash/brightness | 
      grep -E '^0$' > /dev/null && 
      echo -n "Off → On" || echo -n "On → Off";
      echo -n "^ 1 ^ sxmo_flashtoggle.sh"
    )
    Bar Toggle                 ^ 1 ^ key Alt+b
    Change Timezone            ^ 1 ^ sxmo_timezonechange.sh
    Rotate                     ^ 1 ^ sxmo_rotate.sh
    Upgrade Pkgs               ^ 0 ^ st -e sxmo_upgrade.sh
  ")" && WINNAME=Config && return

  # Audio Out menu
  echo $WMCLASS | grep -i "audioout" && CURRENTDEV="$(sxmo_audiocurrentdevice.sh)" && CHOICES="$(echo "
    Headphones $([[ "$CURRENTDEV" == "Headphone" ]] && echo "✓") ^ 1 ^ sxmo_audioout.sh Headphones
    Speaker $([[ "$CURRENTDEV" == "Line Out" ]] && echo "✓")     ^ 1 ^ sxmo_audioout.sh Speaker
    Earpiece $([[ "$CURRENTDEV" == "Earpiece" ]] && echo "✓")    ^ 1 ^ sxmo_audioout.sh Earpiece
    None $([[ "$CURRENTDEV" == "None" ]] && echo "✓")            ^ 1 ^ sxmo_audioout.sh None
  ")" && WINNAME="Audio" && return

  # MPV
  echo $WMCLASS | grep -i "mpv" && CHOICES="$(echo "
   Pause        ^ 0 ^ key space
   Seek ←       ^ 1 ^ key Left
   Seek →       ^ 1 ^ key Right
   App Volume ↑ ^ 1 ^ key 0
   App Volume ↓ ^ 1 ^ key 9
   Speed ↑      ^ 1 ^ key bracketright
   Speed ↓      ^ 1 ^ key bracketleft
   Screenshot   ^ 1 ^ key s
   Loopmark     ^ 1 ^ key l
   Info         ^ 1 ^ key i
   Seek Info    ^ 1 ^ key o
  ")" && WINNAME=Mpv && return

  #  St
  echo $WMCLASS | grep -i "st-256color" && STSELMODEON="$(echo "$XPROPOUT" | grep -E '^_ST_SELMODE.+=' | cut -d= -f2 | tr -d ' ')" && CHOICES="$(echo "
      Type complete   ^ 0 ^ key Ctrl+Shift+u
      Copy complete   ^ 0 ^ key Ctrl+Shift+i
      Selmode $(
        [ $STSELMODEON == 1 ] && printf %b 'On → Off' || printf %b 'Off → On';
        printf %b '^ 0 ^ key Ctrl+Shift+s'
      )               
      $([ $STSELMODEON == 1 ] && echo 'Copy selection ^ 0 ^ key Ctrl+Shift+c')
      Paste           ^ 0 ^ key Ctrl+Shift+v
      Zoom +          ^ 1 ^ key Ctrl+Shift+Prior
      Zoom -          ^ 1 ^ key Ctrl+Shift+Next
      Scroll ↑        ^ 1 ^ key Ctrl+Shift+b
      Scroll ↓        ^ 1 ^ key Ctrl+Shift+f
      Invert          ^ 1 ^ key Ctrl+Shift+x
      Hotkeys         ^ 0 ^ sxmo_appmenu.sh sthotkeys
  ")" && WINNAME=St && return

  #  St hotkeys
  echo $WMCLASS | grep -i "sthotkeys" && CHOICES="$(echo "
      Send Ctrl-C      ^ 0 ^ key Ctrl+c
      Send Ctrl-L      ^ 0 ^ key Ctrl+l
      Send Ctrl-D      ^ 0 ^ key Ctrl+d
  ")" && WINNAME=St && return

  # Netsurf
  echo $WMCLASS | grep -i netsurf && CHOICES="$(echo "
      Pipe URL          ^ 0 ^ sxmo_urlhandler.sh
      Zoom +            ^ 1 ^ key Ctrl+plus
      Zoom -            ^ 1 ^ key Ctrl+minus
      History  ←      ^ 1 ^ key Alt+Left
      History  →   ^ 1 ^ key Alt+Right
  ")" && WINNAME=Netsurf && return

  # Surf
  echo $WMCLASS | grep surf && CHOICES="$(echo "
      Navigate    ^ 0 ^ key Ctrl+g
      Link Menu   ^ 0 ^ key Ctrl+d
      Pipe URL    ^ 0 ^ sxmo_urlhandler.sh
      Zoom +      ^ 1 ^ key Ctrl+Shift+k
      Zoom -      ^ 1 ^ key Ctrl+Shift+j
      Scroll ↑    ^ 1 ^ key Shift+space
      Scroll ↓    ^ 1 ^ key space
      JS Toggle   ^ 1 ^ key Ctrl+Shift+s
      History ←    ^ 1 ^ key Ctrl+h
      History →   ^ 1 ^ key Ctrl+l
  ")" && WINNAME=Surf && return

  # Firefox
  echo $WMCLASS | grep -i firefox && CHOICES="$(echo "
      Pipe URL          ^ 0 ^ sxmo_urlhandler.sh
      Zoom +            ^ 1 ^ key Ctrl+plus
      Zoom -            ^ 1 ^ key Ctrl+minus
      History  ←        ^ 1 ^ key Alt+Left
      History  →        ^ 1 ^ key Alt+Right
  ")" && WINNAME=Firefox && return

  # Foxtrot GPS
  echo $WMCLASS | grep -i foxtrot && CHOICES="$(echo "
      Zoom +            ^ 1 ^ key i
      Zoom -            ^ 1 ^ key o
      Panel toggle      ^ 1 ^ key m
      Autocenter toggle ^ 0 ^ key a
      Route             ^ 0 ^ key r
  ")" && WINNAME=Gps && return
	XPROPOUT="$(xprop -id "$(xdotool getactivewindow)")"
	WMCLASS="${1:-$(echo "$XPROPOUT" | grep WM_CLASS | cut -d ' ' -f3-)}"

	if echo "$WMCLASS" | grep -i "userscripts"; then
		# Userscripts menu
		CHOICES="$(
			find "$XDG_CONFIG_HOME/sxmo/userscripts" -type f -print0 | 
			xargs -IF basename F | 
			awk '{printf "%s\t^ 0 ^ $XDG_CONFIG_HOME/sxmo/userscripts/%s \n", $0, $0}'
		)"
		WINNAME=Userscripts
	elif echo "$WMCLASS" | grep -i "scripts"; then
		# Scripts menu
		CHOICES="
			Web Search      ^ 0 ^ sxmo_websearch.sh
			Files           ^ 0 ^ sxmo_files.sh
			Record          ^ 0 ^ sxmo_record.sh
			Timer           ^ 0 ^ sxmo_timer.sh
			Youtube         ^ 0 ^ sxmo_youtube.sh video
			Youtube (Audio) ^ 0 ^ sxmo_youtube.sh audio
			Weather         ^ 0 ^ sxmo_weather.sh
			RSS             ^ 0 ^ sxmo_rss.sh
		"
		WINNAME=Scripts
	elif echo "$WMCLASS" | grep -i "applications"; then
	# Apps menu
		CHOICES="
			Surf            ^ 0 ^ surf
			Netsurf         ^ 0 ^ netsurf
			Firefox         ^ 0 ^ firefox
			Sacc            ^ 0 ^ st -e sacc i-logout.cz/1/bongusta
			W3m             ^ 0 ^ st -e w3m duck.com
			Xcalc           ^ 0 ^ xcalc
			St              ^ 0 ^ st
			Foxtrotgps      ^ 0 ^ foxtrotgps
		"
		WINNAME=Apps
	elif echo "$WMCLASS" | grep -i "config"; then
		# System Control menu
		CHOICES="
			Brightesss ↑               ^ 1 ^ sxmo_brightness.sh up
			Brightness ↓               ^ 1 ^ sxmo_brightness.sh down
			Modem Toggle               ^ 1 ^ sxmo_modemmonitortoggle.sh
			Modem Info                 ^ 0 ^ sxmo_modeminfo.sh
			Modem Log                  ^ 0 ^ sxmo_modemlog.sh
			Flash $(
				grep -qE '^0$' /sys/class/leds/white:flash/brightness && 
				printf %b "Off → On" ||  printf %b "On → Off";
				printf %b "^ 1 ^ sxmo_flashtoggle.sh"
			)
			Bar Toggle                 ^ 1 ^ key Alt+b
			Change Timezone            ^ 1 ^ sxmo_timezonechange.sh
			Rotate                     ^ 1 ^ sxmo_rotate.sh
			Upgrade Pkgs               ^ 0 ^ st -e sxmo_upgrade.sh
		"
		WINNAME=Config
	elif echo "$WMCLASS" | grep -i "audioout"; then
		# Audio Out menu
		CURRENTDEV="$(sxmo_audiocurrentdevice.sh)"
		CHOICES="
			Headphones $([ "$CURRENTDEV" = "Headphone" ] && echo "✓") ^ 1 ^ sxmo_audioout.sh Headphones
			Speaker $([ "$CURRENTDEV" = "Line Out" ] && echo "✓")     ^ 1 ^ sxmo_audioout.sh Speaker
			Earpiece $([ "$CURRENTDEV" = "Earpiece" ] && echo "✓")    ^ 1 ^ sxmo_audioout.sh Earpiece
			None $([ "$CURRENTDEV" = "None" ] && echo "✓")            ^ 1 ^ sxmo_audioout.sh None
		"
		WINNAME="Audio"
	elif echo "$WMCLASS" | grep -i "mpv"; then
		# MPV
		CHOICES="
		 Pause        ^ 0 ^ key space
		 Seek ←       ^ 1 ^ key Left
		 Seek →       ^ 1 ^ key Right
		 App Volume ↑ ^ 1 ^ key 0
		 App Volume ↓ ^ 1 ^ key 9
		 Speed ↑      ^ 1 ^ key bracketright
		 Speed ↓      ^ 1 ^ key bracketleft
		 Screenshot   ^ 1 ^ key s
		 Loopmark     ^ 1 ^ key l
		 Info         ^ 1 ^ key i
		 Seek Info    ^ 1 ^ key o
		"
		WINNAME=Mpv && return
	elif echo "$WMCLASS" | grep -i "st-256color"; then
		#  St
		STSELMODEON="$(
			echo "$XPROPOUT" | grep -E '^_ST_SELMODE.+=' | cut -d= -f2 | tr -d ' '
		)"
		CHOICES="
			Type complete   ^ 0 ^ key Ctrl+Shift+u
			Copy complete   ^ 0 ^ key Ctrl+Shift+i
			Selmode $(
			  [ "$STSELMODEON" = 1 ] && 
			  printf %b 'On → Off' || 
			  printf %b 'Off → On'
			  printf %b '^ 0 ^ key Ctrl+Shift+s'
			)               
			$([ "$STSELMODEON" = 1 ] && echo 'Copy selection ^ 0 ^ key Ctrl+Shift+c')
			Paste           ^ 0 ^ key Ctrl+Shift+v
			Zoom +          ^ 1 ^ key Ctrl+Shift+Prior
			Zoom -          ^ 1 ^ key Ctrl+Shift+Next
			Scroll ↑        ^ 1 ^ key Ctrl+Shift+b
			Scroll ↓        ^ 1 ^ key Ctrl+Shift+f
			Invert          ^ 1 ^ key Ctrl+Shift+x
			Hotkeys         ^ 0 ^ sxmo_appmenu.sh sthotkeys
		"
		WINNAME=St
	elif echo "$WMCLASS" | grep -i "sthotkeys"; then
		#  St hotkeys
		CHOICES="
			Send Ctrl-C      ^ 0 ^ key Ctrl+c
			Send Ctrl-L      ^ 0 ^ key Ctrl+l
			Send Ctrl-D      ^ 0 ^ key Ctrl+d
		"
		WINNAME=St
	elif echo "$WMCLASS" | grep -i netsurf; then
		# Netsurf
		CHOICES="
			Pipe URL          ^ 0 ^ sxmo_urlhandler.sh
			Zoom +            ^ 1 ^ key Ctrl+plus
			Zoom -            ^ 1 ^ key Ctrl+minus
			History  ←        ^ 1 ^ key Alt+Left
			History  →        ^ 1 ^ key Alt+Right
		"
		WINNAME=Netsurf
	elif echo "$WMCLASS" | grep surf; then
		# Surf
		CHOICES="
			Navigate    ^ 0 ^ key Ctrl+g
			Link Menu   ^ 0 ^ key Ctrl+d
			Pipe URL    ^ 0 ^ sxmo_urlhandler.sh
			Zoom +      ^ 1 ^ key Ctrl+Shift+k
			Zoom -      ^ 1 ^ key Ctrl+Shift+j
			Scroll ↑    ^ 1 ^ key Shift+space
			Scroll ↓    ^ 1 ^ key space
			JS Toggle   ^ 1 ^ key Ctrl+Shift+s
			History ←   ^ 1 ^ key Ctrl+h
			History →   ^ 1 ^ key Ctrl+l
		"
		WINNAME=Surf
	elif echo "$WMCLASS" | grep -i firefox; then
		# Firefox
		CHOICES="
			Pipe URL          ^ 0 ^ sxmo_urlhandler.sh
			Zoom +            ^ 1 ^ key Ctrl+plus
			Zoom -            ^ 1 ^ key Ctrl+minus
			History  ←        ^ 1 ^ key Alt+Left
			History  →        ^ 1 ^ key Alt+Right
		"
		WINNAME=Firefox
	elif echo "$WMCLASS" | grep -i foxtrot; then
		# Foxtrot GPS
		CHOICES="
			Zoom +            ^ 1 ^ key i
			Zoom -            ^ 1 ^ key o
			Panel toggle      ^ 1 ^ key m
			Autocenter toggle ^ 0 ^ key a
			Route             ^ 0 ^ key r
		"
		WINNAME=Gps
	else
		# Default system menu (no matches)
		CHOICES="
			$(
				[ -n "$(ls -A "$XDG_CONFIG_HOME"/sxmo/userscripts)" ] && 
				echo 'Userscripts  ^ 0 ^ sxmo_appmenu.sh userscripts'
			)
			Scripts              ^ 0 ^ sxmo_appmenu.sh scripts
			Apps                 ^ 0 ^ sxmo_appmenu.sh applications
			Volume ↑             ^ 1 ^ sxmo_vol.sh up
			Volume ↓             ^ 1 ^ sxmo_vol.sh down
			Dialer               ^ 0 ^ sxmo_modemcall.sh dial
			Texts                ^ 0 ^ sxmo_modemtext.sh
			Camera               ^ 0 ^ sxmo_camera.sh
			Wifi                 ^ 0 ^ st -e nmtui
			Audio                ^ 0 ^ sxmo_appmenu.sh audioout
			Config               ^ 0 ^ sxmo_appmenu.sh config
			Logout               ^ 0 ^ pkill -9 dwm
		"
		WINNAME=Sys
	fi
}

getprogchoices() {
  # E.g. sets CHOICES var
  programchoicesinit $@

  # Decorate menu at top w/ incoming call entry if present
  INCOMINGCALL=$(cat /tmp/sxmo_incomingcall || echo NOCALL)
  echo "$INCOMINGCALL" | grep -v NOCALL && CHOICES="$(echo "
    Pickup $(echo $INCOMINGCALL | cut -d: -f2) ^ 0 ^ sxmo_modemcall.sh pickup $(echo $INCOMINGCALL | cut -d: -f1)
    $CHOICES
  ")"

  # Decorate menu at bottom w/ system menu entry if not system menu
  echo $WINNAME | grep -v Sys && CHOICES="
    $CHOICES
    System Menu   ^ 0 ^ sxmo_appmenu.sh sys
  "

  # Decorate menu at bottom w/ close menu entry
  CHOICES="
    $CHOICES
    Close Menu    ^ 0 ^ quit
  "

  PROGCHOICES="$(echo "$CHOICES" | xargs -0 echo | sed '/^[[:space:]]*$/d' | awk '{$1=$1};1')"
	# E.g. sets CHOICES var
	programchoicesinit "$@"

	# Decorate menu at top w/ incoming call entry if present
	INCOMINGCALL="$(cat /tmp/sxmo_incomingcall || echo NOCALL)"
	echo "$INCOMINGCALL" | grep -v NOCALL && CHOICES="
		Pickup $(echo "$INCOMINGCALL" | cut -d: -f2) ^ 0 ^ sxmo_modemcall.sh pickup $(echo "$INCOMINGCALL" | cut -d: -f1)
		$CHOICES
	"

	# Decorate menu at bottom w/ system menu entry if not system menu
	echo $WINNAME | grep -v Sys && CHOICES="
		$CHOICES
		System Menu   ^ 0 ^ sxmo_appmenu.sh sys
	"

	# Decorate menu at bottom w/ close menu entry
	CHOICES="
		$CHOICES
		Close Menu    ^ 0 ^ quit
	"

	PROGCHOICES="$(echo "$CHOICES" | xargs -0 echo | sed '/^[[:space:]]*$/d' | awk '{$1=$1};1')"
}

key() {
  xdotool windowactivate "$WIN"
  xdotool key --clearmodifiers "$1"
  #--window $WIN
	xdotool windowactivate "$WIN"
	xdotool key --clearmodifiers "$1"
	#--window $WIN
}

quit() {
  exit 0
	exit 0
}

mainloop() {
  DMENUIDX=0
  PICKED=""
  ARGS="$@"

  while :
  do
    # E.g. sets PROGCHOICES
    getprogchoices $ARGS

    PICKED="$(
      echo "$PROGCHOICES" |
      cut -d'^' -f1 | 
      dmenu -idx $DMENUIDX -l 14 -c -fn "Terminus-30" -p "$WINNAME"
    )"
    LOOP="$(echo "$PROGCHOICES" | grep -F "$PICKED" | cut -d '^' -f2)"
    CMD="$(echo "$PROGCHOICES" | grep -F "$PICKED" | cut -d '^' -f3)"
    DMENUIDX="$(echo "$PROGCHOICES" | grep -F -n "$PICKED" | cut -d ':' -f1)"
    echo "Eval: <$CMD> from picked <$PICKED> with loop <$LOOP>"
    eval $CMD
    echo $LOOP | grep 1 || quit
  done
	DMENUIDX=0
	PICKED=""
	ARGS="$*"

	while :
	do
		# E.g. sets PROGCHOICES
		getprogchoices "$ARGS"

		PICKED="$(
			echo "$PROGCHOICES" |
			cut -d'^' -f1 | 
			dmenu -idx $DMENUIDX -l 14 -c -fn "Terminus-30" -p "$WINNAME"
		)"
		LOOP="$(echo "$PROGCHOICES" | grep -F "$PICKED" | cut -d '^' -f2)"
		CMD="$(echo "$PROGCHOICES" | grep -F "$PICKED" | cut -d '^' -f3)"
		DMENUIDX="$(echo "$PROGCHOICES" | grep -F -n "$PICKED" | cut -d ':' -f1)"
		echo "Eval: <$CMD> from picked <$PICKED> with loop <$LOOP>"
		eval "$CMD"
		echo "$LOOP" | grep 1 || quit
	done
}

pgrep -f sxmo_appmenu.sh | grep -Ev "^${$}$" | xargs kill -9
pkill -9 dmenu
mainloop $@
mainloop "$@"
\ No newline at end of file

M scripts/core/sxmo_audiocurrentdevice.sh => scripts/core/sxmo_audiocurrentdevice.sh +4 -4
@@ 1,9 1,9 @@
#!/usr/bin/env sh
audiodevice() {
  amixer sget "Earpiece" | grep -E '\[on\]' > /dev/null && echo Earpiece && return
  amixer sget "Headphone" | grep -E '\[on\]' > /dev/null && echo Headphone && return
  amixer sget "Line Out" | grep -E '\[on\]' > /dev/null && echo Line Out && return
  echo "None"
	amixer sget "Earpiece" | grep -qE '\[on\]' && echo Earpiece && return
	amixer sget "Headphone" | grep -qE '\[on\]' && echo Headphone && return
	amixer sget "Line Out" | grep -qE '\[on\]' && echo Line Out && return
	echo "None"
}

audiodevice

M scripts/core/sxmo_audioout.sh => scripts/core/sxmo_audioout.sh +6 -6
@@ 9,12 9,12 @@ amixer set "$SPEAKER" mute
amixer set "$HEADPHONE" mute
amixer set "$EARPIECE" mute

if [[ "$ARG" = "Speaker" ]]; then
  amixer set "$SPEAKER" unmute
elif [[ "$ARG" = "Headphones" ]]; then
  amixer set "$HEADPHONE" unmute
elif [[ "$ARG" = "Earpiece" ]]; then
  amixer set "$EARPIECE" unmute
if [ "$ARG" = "Speaker" ]; then
	amixer set "$SPEAKER" unmute
elif [ "$ARG" = "Headphones" ]; then
	amixer set "$HEADPHONE" unmute
elif [ "$ARG" = "Earpiece" ]; then
	amixer set "$EARPIECE" unmute
fi

echo 1 > /tmp/sxmo_bar

M scripts/core/sxmo_blinkled.sh => scripts/core/sxmo_blinkled.sh +2 -2
@@ 1,4 1,4 @@
#!/usr/bin/env sh
sxmo_setpineled $1 150
sxmo_setpineled "$1" 150
sleep 0.01
sxmo_setpineled $1 0
sxmo_setpineled "$1" 0

M scripts/core/sxmo_brightness.sh => scripts/core/sxmo_brightness.sh +10 -12
@@ 8,24 8,22 @@ MINSTEP=1
STEP=$(echo "($MAX - $MIN) / 10" | bc | xargs -ISTP echo -e "$MINSTEP\nSTP" | sort -r | head -n1)

setdelta() {
  sxmo_setpinebacklight $(
    cat $DEV/brightness |
    xargs -IB echo B $1 |
    bc |
    xargs -INUM echo -e "$MIN\nNUM" | sort -n | tail -n1 |
    xargs -INUM echo -e "$MAX\nNUM" | sort -n | head -n1
  )
	sxmo_setpinebacklight "$(
		xargs -IB echo B "$1" < $DEV/brightness |
		bc |
		xargs -INUM echo -e "$MIN\nNUM" | sort -n | tail -n1 |
		xargs -INUM echo -e "$MAX\nNUM" | sort -n | head -n1
	)"

  dunstify -i 0 -u normal -r 999 "☀ $(cat $DEV/brightness)/${MAX}"
	dunstify -i 0 -u normal -r 999 "☀ $(cat $DEV/brightness)/${MAX}"
}

up() {
  setdelta "+${STEP}"
  
	setdelta "+${STEP}"
}

down() {
  setdelta "-${STEP}"
	setdelta "-${STEP}"
}

$1 $2
\ No newline at end of file
"$1" "$2"
\ No newline at end of file

M scripts/core/sxmo_dmenu_with_kb.sh => scripts/core/sxmo_dmenu_with_kb.sh +1 -0
@@ 1,6 1,7 @@
#!/usr/bin/env sh

pidof svkbd-sxmo >&2 || svkbd-sxmo &
# shellcheck disable=SC2068
OUTPUT="$(cat | dmenu $@)"
pkill svkbd-sxmo >&2
echo "$OUTPUT"

M scripts/core/sxmo_edit_screen.sh => scripts/core/sxmo_edit_screen.sh +1 -1
@@ 1,4 1,4 @@
#!/bin/sh
#!/usr/bin/env sh
tmpfile=$(mktemp /tmp/st-edit.XXXXXX)
trap  'rm "$tmpfile"' 0 1 15
cat > "$tmpfile"

M scripts/core/sxmo_flashtoggle.sh => scripts/core/sxmo_flashtoggle.sh +2 -2
@@ 1,6 1,6 @@
#!/usr/bin/env sh
sxmo_setpineled white "$(
  cat /sys/class/leds/white:flash/brightness | 
  grep -E '^0$' > /dev/null && echo 255 || echo 0
	grep -qE '^0$' /sys/class/leds/white:flash/brightness && 
	echo 255 || echo 0
)"


M scripts/core/sxmo_pipecomplete.sh => scripts/core/sxmo_pipecomplete.sh +26 -23
@@ 3,34 3,37 @@ INPUT="$(cat)"
STWIN="$(xprop -root | sed -n '/^_NET_ACTIVE_WINDOW/ s/.* //p')"

menu() {
  pidof svkbd-sxmo || svkbd-sxmo &
  RESULT="$(
    echo "$(
      echo "Close Menu" &&
      echo "$INPUT" | grep -Eo '\S+' | tr -d '[:blank:]' | sort | uniq
    )" | dmenu -p "$PROMPT" -l 10 -i -c -fn Terminus-20
  )"
  pkill svkbd-sxmo
	pidof svkbd-sxmo || svkbd-sxmo &
	RESULT="$(
		echo "Close Menu" &&
		echo "$INPUT" | 
		grep -Eo '\S+' | 
		tr -d '[:blank:]' | 
		sort | 
		uniq | 
		dmenu -p "$PROMPT" -l 10 -i -c -fn Terminus-20
	)" 
	pkill svkbd-sxmo
}

copy() {
  PROMPT=Copy
  menu
  if [[ "$RESULT" = "Close Menu" ]]; then
    exit 0
  else
    echo "$RESULT" | xclip -i
  fi
	PROMPT=Copy
	menu
	if [ "$RESULT" = "Close Menu" ]; then
		exit 0
	else
		echo "$RESULT" | xclip -i
	fi
}

type() {
  PROMPT=Type
  menu
  if [[ "$RESULT" = "Close Menu" ]]; then
    exit 0
  else
    xdotool type --window $STWIN "$RESULT"
  fi
	PROMPT=Type
	menu
	if [ "$RESULT" = "Close Menu" ]; then
		exit 0
	else
		xdotool type --window "$STWIN" "$RESULT"
	fi
}

$@
"$1"

M scripts/core/sxmo_statusbar.sh => scripts/core/sxmo_statusbar.sh +39 -30
@@ 2,43 2,52 @@
pgrep -f sxmo_statusbar.sh | grep -v $$ | xargs kill -9

UPDATEFILE=/tmp/sxmo_bar
touch $UPDATEFILE
touch "$UPDATEFILE"

update() {
  # M symbol if modem monitoring is on & modem present
  MODEMMON=""
  pgrep -f sxmo_modemmonitor.sh && MODEMMON="M "

  # Battery pct
  PCT=$(cat /sys/class/power_supply/*-battery/capacity)
  BATSTATUS=$(
    cat /sys/class/power_supply/*-battery/status |
    cut -c1
  )

  # Volume
  AUDIODEV="$(sxmo_audiocurrentdevice.sh)"
  [[ $AUDIODEV == "None" ]] && VOL="" || VOL=$(echo "$AUDIODEV" | cut -c1 | tr L S)"$(
      amixer sget "$AUDIODEV" |
      grep -oE '([0-9]+)%' |
      tr -d ' %' |
      awk '{ s += $1; c++ } END { print s/c }'  |
      xargs printf %.0f
  )"

  # Time
  TIME=$(date +%R)

  BAR=" ${MODEMMON}${VOL} ${BATSTATUS}${PCT}% ${TIME}"
  xsetroot -name "$BAR"
	# M symbol if modem monitoring is on & modem present
	MODEMMON=""
	pgrep -f sxmo_modemmonitor.sh && MODEMMON="M "

	# Battery pct
	PCT="$(cat /sys/class/power_supply/*-battery/capacity)"
	BATSTATUS="$(
		cat /sys/class/power_supply/*-battery/status |
		cut -c1
	)"

	# Volume
	AUDIODEV="$(sxmo_audiocurrentdevice.sh)"
	[ "$AUDIODEV" = "None" ] && VOL="" || VOL=$(echo "$AUDIODEV" | cut -c1 | tr L S)"$(
		amixer sget "$AUDIODEV" |
		grep -oE '([0-9]+)%' |
		tr -d ' %' |
		awk '{ s += $1; c++ } END { print s/c }'  |
		xargs printf %.0f
	)"

	# Time
	TIME="$(date +%R)"

	BAR=" ${MODEMMON}${VOL} ${BATSTATUS}${PCT}% ${TIME}"
	xsetroot -name "$BAR"
}

# E.g. on first boot justs to make sure the bar comes in quickly
update && sleep 1 && update && sleep 1 && update

periodicupdate() {
	while :
	do
		echo 1 > "$UPDATEFILE"
		sleep 30
	done
}

periodicupdate &

while :
do
  update
  inotifywait -e MODIFY $UPDATEFILE & sleep 30 & wait -n
  pgrep -P $$ | xargs kill -9
	update
	inotifywait -e MODIFY "$UPDATEFILE"
done

M scripts/core/sxmo_surf_linkselect.sh => scripts/core/sxmo_surf_linkselect.sh +53 -53
@@ 10,67 10,67 @@
SURF_WINDOW="${1:-$(xprop -root | sed -n '/^_NET_ACTIVE_WINDOW/ s/.* //p')}"
DMENU_PROMPT="${2:-Link}"

function dump_links_with_titles() {
  awk '{
    input = $0;
dump_links_with_titles() {
	awk '{
		input = $0;

    $0 = input;
    gsub("<[^>]*>", "");
    gsub(/[ ]+/, " ");
    gsub("&amp;", "\\&");
    gsub("&lt;", "<");
    gsub("&gt;", ">");
    $1 = $1;
    title = ($0 == "" ? "None" : $0);
		$0 = input;
		gsub("<[^>]*>", "");
		gsub(/[ ]+/, " ");
		gsub("&amp;", "\\&");
		gsub("&lt;", "<");
		gsub("&gt;", ">");
		$1 = $1;
		title = ($0 == "" ? "None" : $0);

    $0 = input;
    match($0, /\<[ ]*[aA][^>]* [hH][rR][eE][fF]=["]([^"]+)["]/, linkextract);
    $0 = linkextract[1];
    gsub(/^[ \t]+/,"");
    gsub(/[ \t]+$/,"");
    gsub("[ ]", "%20");
    link = $0;
		$0 = input;
		match($0, /\<[ ]*[aA][^>]* [hH][rR][eE][fF]=["]([^"]+)["]/, linkextract);
		$0 = linkextract[1];
		gsub(/^[ \t]+/,"");
		gsub(/[ \t]+$/,"");
		gsub("[ ]", "%20");
		link = $0;

    if (link != "") {
      print title ": " link;
    }
  }'
		if (link != "") {
			print title ": " link;
		}
	}'
}

function link_normalize() {
  URI=$1
  awk -v uri=$URI '{
    gsub("&amp;", "\\&");
link_normalize() {
	URI=$1
	awk -v uri="$URI" '{
		gsub("&amp;", "\\&");

    if ($0 ~ /^https?:\/\//  || $0 ~ /^\/\/.+$/) {
      print $0;
    } else if ($0 ~/^#/) {
      gsub(/[#?][^#?]+/, "", uri);
      print uri $0;
    } else if ($0 ~/^\//) {
      split(uri, uri_parts, "/");
      print uri_parts[3] $0;
    } else {
      gsub(/[#][^#]+/, "", uri);
      uri_parts_size = split(uri, uri_parts, "/");
      delete uri_parts[uri_parts_size];
      for (v in uri_parts) {
        uri_pagestripped = uri_pagestripped uri_parts[v] "/"
      }
      print uri_pagestripped $0;
    }
  }'
		if ($0 ~ /^https?:\/\//  || $0 ~ /^\/\/.+$/) {
			print $0;
		} else if ($0 ~/^#/) {
			gsub(/[#?][^#?]+/, "", uri);
			print uri $0;
		} else if ($0 ~/^\//) {
			split(uri, uri_parts, "/");
			print uri_parts[3] $0;
		} else {
			gsub(/[#][^#]+/, "", uri);
			uri_parts_size = split(uri, uri_parts, "/");
			delete uri_parts[uri_parts_size];
			for (v in uri_parts) {
				uri_pagestripped = uri_pagestripped uri_parts[v] "/"
			}
			print uri_pagestripped $0;
		}
	}'
}

function link_select() {
  tr '\n\r' ' ' |
    xmllint --html --xpath "//a" - |
    dump_links_with_titles |
    awk '!x[$0]++' |
    # sort | uniq
    dmenu -p "$DMENU_PROMPT" -l 10 -i -c |
    awk -F' ' '{print $NF}' |
    link_normalize $(xprop -id $SURF_WINDOW _SURF_URI | cut -d '"' -f 2)
link_select() {
	tr '\n\r' ' ' |
		xmllint --html --xpath "//a" - |
		dump_links_with_titles |
		awk '!x[$0]++' |
		# sort | uniq
		dmenu -p "$DMENU_PROMPT" -l 10 -i -c |
		awk -F' ' '{print $NF}' |
		link_normalize "$(xprop -id "$SURF_WINDOW" _SURF_URI | cut -d '"' -f 2)"
}

pidof svkbd-sxmo || svkbd-sxmo &

M scripts/core/sxmo_timezonechange.sh => scripts/core/sxmo_timezonechange.sh +17 -13
@@ 1,21 1,25 @@
#!/usr/bin/env sh

change() {
  echo "Changing timezone to $1"
  sudo setup-timezone -z "$1"
  echo 1 > /tmp/sxmo_bar
  echo Timezone changed ok
  read
	echo "Changing timezone to $1"
	sudo setup-timezone -z "$1"
	echo 1 > /tmp/sxmo_bar
	echo Timezone changed ok
	read -r
}

menu() {
  T="$(
    find /usr/share/zoneinfo -type f | 
    sed  's#^/usr/share/zoneinfo/##g' |
    sort |
    sxmo_dmenu_with_kb.sh -p Timezone -c -l 10 -fn Terminus-20 -i
  )"
  st -e "$0" change "$T"
	T="$(
		find /usr/share/zoneinfo -type f | 
		sed  's#^/usr/share/zoneinfo/##g' |
		sort |
		sxmo_dmenu_with_kb.sh -p Timezone -c -l 10 -fn Terminus-20 -i
	)"
	st -e "$0" change "$T"
}

[ $# -gt 0 ] && $@ || menu
\ No newline at end of file
if [ $# -gt 0 ]; then
	"$1" "$2"
else
	menu
fi

M scripts/core/sxmo_upgrade.sh => scripts/core/sxmo_upgrade.sh +1 -1
@@ 6,4 6,4 @@ echo "Upgrading all packages"
sudo apk upgrade

echo "Upgrade complete - reboot for all change to take effect"
read
read -r

M scripts/core/sxmo_urlhandler.sh => scripts/core/sxmo_urlhandler.sh +32 -34
@@ 1,45 1,43 @@
#!/usr/bin/env sh

if [[ ! -z "$1" ]]
if [ -n "$1" ]
then
  # E.g. passed liked: sxmo_urlhandler.sh http://foo.com
  URL=$1
	# E.g. passed liked: sxmo_urlhandler.sh http://foo.com
	URL="$1"
else
  # Surf
  WINDOW="$(xprop -root | sed -n '/^_NET_ACTIVE_WINDOW/ s/.* //p')"
  SURFURL=`xprop -id $WINDOW | grep URI | awk '{print $3}' | sed 's/\"//g'`
  if [[ ! -z "$SURFURL" ]]
  then
    URL="$SURFURL"
  fi
	# Surf
	WINDOW="$(xprop -root | sed -n '/^_NET_ACTIVE_WINDOW/ s/.* //p')"
	SURFURL="$(xprop -id "$WINDOW" | grep URI | awk '{print $3}' | sed 's/\"//g')"
	if [ -n "$SURFURL" ]; then
		URL="$SURFURL"
	fi

  # Is normal browser? (FF or Netsurf) - use Ctrl-L Ctrl-C to copy URL
  ISNORMBROWS=`xprop -id $(xdotool getactivewindow) | grep -E 'WM_CLASS.*(Netsurf|Firefox)'`
  if [[ ! -z "$ISNORMBROWS" ]]
  then
    xdotool key --clearmodifiers --delay 20 "ctrl+l" "ctrl+c"
    sleep 0.2
    URL="$(xclip -o)"
  fi
	# Is normal browser? (FF or Netsurf) - use Ctrl-L Ctrl-C to copy URL
	ISNORMBROWS="$(xprop -id "$(xdotool getactivewindow)" | grep -E 'WM_CLASS.*(Netsurf|Firefox)')"
	if [ -n "$ISNORMBROWS" ]; then
		xdotool key --clearmodifiers --delay 20 "ctrl+l" "ctrl+c"
		sleep 0.2
		URL="$(xclip -o)"
	fi
fi

COMMAND=$(
  echo "
    w3m URL
    mpv -v URL
    mpv -v --ytdl-format='[height<420]' URL
    firefox -new-window URL
    netsurf URL
    surf URL
    echo URL | xsel -i
    youtube-dl -o- URL | mpv -v -
    youtube-dl URL
    curl URL | vis -
    wget URL
    aria2c URL
    " | sed "s/URL/'URL'/g" | sed -e '/^\s*$/d' | sed -e 's/^\s*//' | dmenu -fn Terminus-15 -p "Pipe URL" -c -l 20
	echo "
		w3m URL
		mpv -v URL
		mpv -v --ytdl-format='[height<420]' URL
		firefox -new-window URL
		netsurf URL
		surf URL
		echo URL | xsel -i
		youtube-dl -o- URL | mpv -v -
		youtube-dl URL
		curl URL | vis -
		wget URL
		aria2c URL
	" | sed "s/URL/'URL'/g" | sed -e '/^\s*$/d' | sed -e 's/^\s*//' | dmenu -fn Terminus-15 -p "Pipe URL" -c -l 20
)
[[ -z "$COMMAND" ]] && exit 1
[ -z "$COMMAND" ] && exit 1

RUN=$(echo $URL | xargs -IURL echo "$COMMAND")
RUN=$(echo "$URL" | xargs -IURL echo "$COMMAND")
st -e sh -c "$RUN"

M scripts/core/sxmo_xinit.sh => scripts/core/sxmo_xinit.sh +1 -0
@@ 1,5 1,6 @@
#!/usr/bin/env sh
# Env vars
# shellcheck disable=SC1091
. /etc/profile
which "$TERM" || export TERM=st
which "$BROWSER" || export BROWSER=surf

M scripts/modem/sxmo_modemcall.sh => scripts/modem/sxmo_modemcall.sh +66 -65
@@ 21,14 21,16 @@ contacts() {
}

modem_cmd_errcheck() {
	ARGS="$@"
	RES="$(mmcli $ARGS 2>&1)"
	[ $? -eq 0 ] || err "Problem executing mmcli command!\n$RES"
	# shellcheck disable=SC2068
	RES="$(mmcli $@ 2>&1)"
	OK="$?"
	echo "Command: mmcli $*"
	if [ "$OK" != 0 ]; then err "Problem executing mmcli command!\n$RES"; fi
	echo "$RES"
}

vid_to_number() {
  mmcli -m "$(modem_n)" -o "$1" -K | grep call.properties.number | cut -d ':' -f2 | tr -d  ' ' | sed 's/^[+]//' | sed 's/^1//'
	mmcli -m "$(modem_n)" -o "$1" -K | grep call.properties.number | cut -d ':' -f2 | tr -d  ' ' | sed 's/^[+]//' | sed 's/^1//'
}

log_event() {


@@ 43,7 45,7 @@ log_event() {
toggleflag() {
	TOGGLEFLAG=$1
	shift
	FLAGS="$@"
	FLAGS="$*"

	echo -- "$FLAGS" | grep -- "$TOGGLEFLAG" >&2 && 
		NEWFLAGS="$(echo -- "$FLAGS" | sed "s/$TOGGLEFLAG//g")" ||


@@ 51,6 53,7 @@ toggleflag() {

	NEWFLAGS="$(echo -- "$NEWFLAGS" | sed "s/--//g; s/  / /g")"

	# shellcheck disable=SC2086
	sxmo_megiaudioroute $NEWFLAGS
	echo -- "$NEWFLAGS"
}


@@ 79,7 82,7 @@ dialmenu() {
		grep -oE "[0-9]+"
	)"
	echo "Starting call with VID: $VID" >&2
	startcall "$VID" >&@
	startcall "$VID" >&2
	echo "$VID"
}



@@ 107,69 110,67 @@ hangup() {
}

incallmenu() {
  DMENUIDX=0
  VID="$1"
  NUMBER="$(vid_to_number "$VID")"

  # E.g. There's some bug with the modem that' requires us to toggle the
  # DAI a few times before starting the call for it to kick in
  FLAGS=" "
  toggleflagset "-e"
  toggleflagset "-m"
  toggleflagset "-2"
  toggleflagset "-2"
  toggleflagset "-2"

  while true
  do
    CHOICES="
      Volume ↑    ^ sxmo_vol.sh up
      Volume ↓    ^ sxmo_vol.sh down
      Mic $(echo -- $FLAGS | grep -q -- -m && echo ✓)          ^ toggleflagset -m
      Linemic $(echo -- $FLAGS | grep -q -- -l && echo ✓)      ^ toggleflagset -l
      Echomic $(echo -- $FLAGS | grep -q -- -z && echo ✓)      ^ toggleflagset -z
      Earpiece $(echo -- $FLAGS | grep -q -- -e && echo ✓)     ^ toggleflagset -e
      Linejack $(echo -- $FLAGS | grep -q -- -h && echo ✓)     ^ toggleflagset -h
      Speakerphone $(echo -- $FLAGS | grep -q -- -s && echo ✓) ^ toggleflagset -s
      DTMF Tones  ^ dtmfmenu $VID
      Hangup      ^ hangup $VID
      Lock Screen ^ sh -c 'pkill -9 lisgd; sxmo_screenlock; lisgd &'
    "

    PICKED=""
    PICKED=$(
      echo "$CHOICES" | 
      xargs -0 echo | 
      cut -d'^' -f1 | 
      sed '/^[[:space:]]*$/d' |
      awk '{$1=$1};1' |
      dmenu -idx $DMENUIDX -l 14 -c -fn "Terminus-30" -p "$NUMBER"
	DMENUIDX=0
	VID="$1"
	NUMBER="$(vid_to_number "$VID")"

	# E.g. There's some bug with the modem that' requires us to toggle the
	# DAI a few times before starting the call for it to kick in
	FLAGS=" "
	toggleflagset "-e"
	toggleflagset "-m"
	toggleflagset "-2"
	toggleflagset "-2"
	toggleflagset "-2"

	while true; do
		CHOICES="
			Volume ↑    ^ sxmo_vol.sh up
			Volume ↓    ^ sxmo_vol.sh down
			Mic $(echo -- "$FLAGS" | grep -q -- -m && echo ✓)          ^ toggleflagset -m
			Linemic $(echo -- "$FLAGS" | grep -q -- -l && echo ✓)      ^ toggleflagset -l
			Echomic $(echo -- "$FLAGS" | grep -q -- -z && echo ✓)      ^ toggleflagset -z
			Earpiece $(echo -- "$FLAGS" | grep -q -- -e && echo ✓)     ^ toggleflagset -e
			Linejack $(echo -- "$FLAGS" | grep -q -- -h && echo ✓)     ^ toggleflagset -h
			Speakerphone $(echo -- "$FLAGS" | grep -q -- -s && echo ✓) ^ toggleflagset -s
			DTMF Tones  ^ dtmfmenu $VID
			Hangup      ^ hangup $VID
			Lock Screen ^ sh -c 'pkill -9 lisgd; sxmo_screenlock; lisgd &'
		"

		PICKED=""
		PICKED=$(
			echo "$CHOICES" | 
			xargs -0 echo | 
			cut -d'^' -f1 | 
			sed '/^[[:space:]]*$/d' |
			awk '{$1=$1};1' |
			dmenu -idx $DMENUIDX -l 14 -c -fn "Terminus-30" -p "$NUMBER"
    )

    # E.g. in modem watcher script we just kill dmenu if the other side hangsup
    echo "$PICKED" | grep -Ev "." && err "$NUMBER hung up the call"
		# E.g. in modem watcher script we just kill dmenu if the other side hangsup
		echo "$PICKED" | grep -Ev "." && err "$NUMBER hung up the call"

    CMD=$(echo "$CHOICES" | grep "$PICKED" | cut -d '^' -f2)
    DMENUIDX=$(echo $(echo "$CHOICES" | grep -n "$PICKED" | cut -d ':' -f1) - 1 | bc)
    eval $CMD
  done
		CMD=$(echo "$CHOICES" | grep "$PICKED" | cut -d '^' -f2)
		DMENUIDX=$(echo "$(echo "$CHOICES" | grep -n "$PICKED" | cut -d ':' -f1)" - 1 | bc)
		eval "$CMD"
	done
}

dtmfmenu() {
  VID="$1"
  DTMFINDEX=0
  NUMS="0123456789*#ABCD"
	VID="$1"
	DTMFINDEX=0
	NUMS="0123456789*#ABCD"

  while true
  do
    PICKED="$(
      echo "$NUMS" | grep -o . | sed '1 iReturn to Call Menu' |
      dmenu -l 20 -fn Terminus-20 -c -idx $DTMFINDEX -p "DTMF Tone"
    )"
    echo "$PICKED" | grep "Return to Call Menu" && return
    DTMFINDEX=$(echo "$NUMS" | grep -bo "$PICKED" | cut -d: -f1 | xargs -IN echo 2+N | bc)
    modem_cmd_errcheck -m "$(modem_n)" -o "$VID" --send-dtmf="$PICKED"
  done
	while true; do
		PICKED="$(
			echo "$NUMS" | grep -o . | sed '1 iReturn to Call Menu' |
			dmenu -l 20 -fn Terminus-20 -c -idx $DTMFINDEX -p "DTMF Tone"
		)"
		echo "$PICKED" | grep "Return to Call Menu" && return
		DTMFINDEX=$(echo "$NUMS" | grep -bo "$PICKED" | cut -d: -f1 | xargs -IN echo 2+N | bc)
		modem_cmd_errcheck -m "$(modem_n)" -o "$VID" --send-dtmf="$PICKED"
	done
}

dial() {


@@ 178,9 179,9 @@ dial() {
}

pickup() {
	acceptcall $1
	incallmenu $1
	acceptcall "$1"
	incallmenu "$1"
}

modem_n || err "Couldn't determine modem number - is modem online?"
$@
"$1" "$2"
\ No newline at end of file

M scripts/modem/sxmo_modeminfo.sh => scripts/modem/sxmo_modeminfo.sh +3 -3
@@ 6,9 6,9 @@ err() {
}

modem_n() {
  MODEMS="$(mmcli -L)"
  echo "$MODEMS" | grep -oE 'Modem\/([0-9]+)' > /dev/null || err "Couldn't find modem - is your modem enabled?"
  echo "$MODEMS" | grep -oE 'Modem\/([0-9]+)' | cut -d'/' -f2
	MODEMS="$(mmcli -L)"
	echo "$MODEMS" | grep -oE 'Modem\/([0-9]+)' > /dev/null || err "Couldn't find modem - is your modem enabled?"
	echo "$MODEMS" | grep -oE 'Modem\/([0-9]+)' | cut -d'/' -f2
}

st -e sh -c "mmcli -m $(modem_n) && read"

M scripts/modem/sxmo_modemmonitor.sh => scripts/modem/sxmo_modemmonitor.sh +26 -21
@@ 2,10 2,10 @@
TIMEOUT=3
LOGDIR="$XDG_CONFIG_HOME"/sxmo/modem
ACTIVECALL="NONE"
trap "kill 0" SIGINT
trap "kill 0" INT

err() {
	echo -e "$1" | dmenu -fn Terminus-20 -c -l 10
	printf %b "$1" | dmenu -fn Terminus-20 -c -l 10
	kill -9 0
}



@@ 21,13 21,13 @@ newcall() {
	sxmo_setpineled green 1

	# Delete all terminated calls
	for i in $(mmcli -m $(modem_n) --voice-list-calls | grep terminated | grep -oE Call\/[0-9]+ | cut -d'/' -f2); do
		mmcli -m $(modem_n) --voice-delete-call $i
	for i in $(mmcli -m "$(modem_n)" --voice-list-calls | grep terminated | grep -oE "Call\/[0-9]+" | cut -d'/' -f2); do
		mmcli -m "$(modem_n)" --voice-delete-call "$i"
	done

	echo "Incoming Call:"
	INCOMINGNUMBER=$(
		mmcli -m $(modem_n) --voice-list-calls -o "$VID" -K |
		mmcli -m "$(modem_n)" --voice-list-calls -o "$VID" -K |
		grep call.properties.number |
		cut -d ':' -f 2 |
		sed 's/^[+]//' | 


@@ 35,8 35,8 @@ newcall() {
	)

	TIME="$(date --iso-8601=seconds)"
	mkdir -p $LOGDIR
	echo -ne "$TIME\tcall_ring\t$INCOMINGNUMBER\n" >> $LOGDIR/modemlog.tsv
	mkdir -p "$LOGDIR"
	printf %b "$TIME\tcall_ring\t$INCOMINGNUMBER\n" >> "$LOGDIR/modemlog.tsv"
	echo "$VID:$INCOMINGNUMBER" > /tmp/sxmo_incomingcall
	echo "Number: $INCOMINGNUMBER (VID: $VID)"



@@ 46,8 46,8 @@ newtexts() {
	sxmo_setpineled green 1

	echo "New Texts:"
	for i in $(echo -e "$1") ; do
		DAT="$(mmcli -m $(modem_n) -s $i -K)"
	for i in $(printf %b "$1") ; do
		DAT="$(mmcli -m "$(modem_n)" -s "$i" -K)"

		TEXT="$(echo "$DAT" | grep sms.content.text | sed -E 's/^sms\.content\.text\s+:\s+//')"
		NUM="$(


@@ 58,12 58,12 @@ newtexts() {
			sed 's/^1//'
		)"
		TIME="$(echo "$DAT" | grep sms.properties.timestamp | sed -E 's/^sms\.properties\.timestamp\s+:\s+//')"
		TEXTSIZE="$(echo $TEXT | wc -c)"
		TEXTSIZE="${#TEXT}"

		mkdir -p "$LOGDIR/$NUM"
		echo -ne "Received from $NUM at $TIME:\n$TEXT\n\n" >> $LOGDIR/$NUM/sms.txt
		echo -ne "$TIME\trecv_txt\t$NUM\t$TEXTSIZE chars\n" >> $LOGDIR/modemlog.tsv
		mmcli -m $(modem_n) --messaging-delete-sms=$i
		printf %b "Received from $NUM at $TIME:\n$TEXT\n\n" >> "$LOGDIR/$NUM/sms.txt"
		printf %b "$TIME\trecv_txt\t$NUM\t$TEXTSIZE chars\n" >> "$LOGDIR/modemlog.tsv"
		mmcli -m "$(modem_n)" --messaging-delete-sms="$i"

		sxmo_vibratepine 300 && sleep 0.1
		sxmo_vibratepine 300 && sleep 0.1


@@ 78,16 78,15 @@ killinprogresscall() {

inprogresscallchecker() {
	# E.g. register current call in progress as ACTIVECALL
	CURRENTCALLS="$(mmcli -m $(modem_n) --voice-list-calls)"
	CURRENTCALLS="$(mmcli -m "$(modem_n)" --voice-list-calls)"

	# E.g. if we've previously registered an ACTIVECALL, check if it
	# was terminated by the otherside, if so kill the incall script
	# and notify user
	echo "$ACTIVECALL" | grep -E '[0-9]+' && $(
		echo "$CURRENTCALLS" | 
		grep -E "Call/${ACTIVECALL}.+terminated" && 
	if echo "$ACTIVECALL" | grep -E '[0-9]+'; then
		echo "$CURRENTCALLS" | grep -E "Call/${ACTIVECALL}.+terminated" && 
		killinprogresscall
	)
	fi

	# Register the active call so we can check in future loops if
	# other side hung up


@@ 104,13 103,13 @@ while true
do
	sxmo_setpineled green 0
	VOICECALLID="$(
		mmcli -m $(modem_n) --voice-list-calls -a |
		mmcli -m "$(modem_n)" --voice-list-calls -a |
		grep -Eo '[0-9]+ incoming \(ringing-in\)' |
		grep -Eo '[0-9]+'
	)"

	TEXTIDS="$(
		mmcli -m $(modem_n) --messaging-list-sms |
		mmcli -m "$(modem_n)" --messaging-list-sms |
		grep -Eo '/SMS/[0-9]+ \(received\)' |
		grep -Eo '[0-9]+'
	)"


@@ 119,7 118,13 @@ do

	inprogresscallchecker

	echo "$VOICECALLID" | grep . && newcall "$VOICECALLID" || rm -f /tmp/sxmo_incomingcall
	if echo "$VOICECALLID" | grep .; then
		newcall "$VOICECALLID"
	else
		rm -f /tmp/sxmo_incomingcall
	fi

	echo "$TEXTIDS" | grep . && newtexts "$TEXTIDS"

	sleep $TIMEOUT
done

M scripts/modem/sxmo_modemmonitortoggle.sh => scripts/modem/sxmo_modemmonitortoggle.sh +6 -1
@@ 1,5 1,10 @@
#!/usr/bin/env sh
pgrep -f sxmo_modemmonitor.sh && pkill -9 -f sxmo_modemmonitor.sh || sxmo_modemmonitor.sh &
if pgrep -f sxmo_modemmonitor.sh; then
	pkill -9 -f sxmo_modemmonitor.sh
else
	sxmo_modemmonitor.sh &
fi

rm /tmp/sxmo_incomingcall

# E.g. wait until process killed or started -- maybe there's a better way..

M scripts/modem/sxmo_modemtext.sh => scripts/modem/sxmo_modemtext.sh +34 -35
@@ 3,47 3,47 @@ EDITOR=vis
LOGDIR="$XDG_CONFIG_HOME"/sxmo/modem

err() {
	echo $1 | dmenu -fn Terminus-20 -c -l 10
	echo "$1" | dmenu -fn Terminus-20 -c -l 10
	kill $$
}

modem_n() {
  MODEMS="$(mmcli -L)"
  echo "$MODEMS" | grep -oE 'Modem\/([0-9]+)' > /dev/null || err "Couldn't find modem - is your modem enabled?"
  echo "$MODEMS" | grep -oE 'Modem\/([0-9]+)' | cut -d'/' -f2
	MODEMS="$(mmcli -L)"
	echo "$MODEMS" | grep -qoE 'Modem\/([0-9]+)' || err "Couldn't find modem - is your modem enabled?"
	echo "$MODEMS" | grep -oE 'Modem\/([0-9]+)' | cut -d'/' -f2
}

textcontacts() {
	# TODO: is find automatically sorted by timestamp?
	find $LOGDIR/* -type d -maxdepth 1 | awk -F'/' '{print $NF}' | tac
	find "$LOGDIR"/* -type d -maxdepth 1 | awk -F'/' '{print $NF}' | tac
}

editmsg() {
	TMP="$(mktemp --suffix $1_msg)"
	TMP="$(mktemp --suffix "$1_msg")"
	echo "$2" > "$TMP"
	TEXT="$(st -e $EDITOR $TMP)"
	cat $TMP
	TEXT="$(st -e $EDITOR "$TMP")"
	cat "$TMP"
}

sendmsg() {
	MODEM=$(modem_n)
	MODEM="$(modem_n)"
	NUMBER="$(echo "$1" | sed 's/^[+]//' | sed 's/^1//')"
	TEXT="$2"
	TEXTSIZE="$(echo "$TEXT" | wc -c)"
	TEXTSIZE="${#TEXT}"

	SMSNO=$(
		mmcli -m $MODEM --messaging-create-sms="text='$TEXT',number=$NUMBER" |
		grep -o [0-9]*$
	)
	mmcli -s ${SMSNO} --send || err "Couldn't send text message"
	for i in $(mmcli -m $MODEM --messaging-list-sms | grep " (sent)" | cut -f5 -d' ') ; do
	  mmcli -m $MODEM --messaging-delete-sms=$i
	SMSNO="$(
		mmcli -m "$MODEM" --messaging-create-sms="text='$TEXT',number=$NUMBER" |
		grep -o "[0-9]*$"
	)"
	mmcli -s "${SMSNO}" --send || err "Couldn't send text message"
	for i in $(mmcli -m "$MODEM" --messaging-list-sms | grep " (sent)" | cut -f5 -d' ') ; do
	  mmcli -m "$MODEM" --messaging-delete-sms="$i"
	done

	TIME="$(date --iso-8601=seconds)"
	mkdir -p $LOGDIR/$NUMBER
	echo -ne "Sent to $NUMBER at $TIME:\n$TEXT\n\n" >> $LOGDIR/$NUMBER/sms.txt
	echo -ne "$TIME\tsent_txt\t$NUMBER\t$TEXTSIZE chars\n" >> $LOGDIR/modemlog.tsv
	mkdir -p "$LOGDIR/$NUMBER"
	printf %b "Sent to $NUMBER at $TIME:\n$TEXT\n\n" >> "$LOGDIR/$NUMBER/sms.txt"
	printf %b "$TIME\tsent_txt\t$NUMBER\t$TEXTSIZE chars\n" >> "$LOGDIR/modemlog.tsv"

	err "Sent text message ok"
}


@@ 52,24 52,23 @@ sendtextmenu() {
	modem_n || err "Couldn't determine modem number - is modem online?"

	# Prompt for number
	NUMBER=$(
		echo -e "\nCancel\n$(textcontacts)" | 
	NUMBER="$(
		printf %b "\nCancel\n$(textcontacts)" | 
		awk NF |
		sxmo_dmenu_with_kb.sh -p "Number" -fn "Terminus-20" -l 10 -c
	)
	)"
	echo "$NUMBER" | grep -E "^Cancel$" && exit 1
	echo "$NUMBER" | grep -E '[0-9]+' || err "That doesn't seem like a valid number"

	# Compose first version of msg
	TEXT="$(editmsg $NUMBER 'Enter text message here')"
	TEXT="$(editmsg "$NUMBER" 'Enter text message here')"

	while true
	do
		CHARS=$(echo "$TEXT" | wc -c)
		CONFIRM=$(
			echo -e "Edit Message ($TEXT)\nSend to → $NUMBER\nCancel" |
		CONFIRM="$(
			printf %b "Edit Message ($TEXT)\nSend to → $NUMBER\nCancel" |
			dmenu -c -idx 1 -p "Confirm" -fn "Terminus-20" -l 10
		)
		)"
		echo "$CONFIRM" | grep -E "^Send" && sendmsg "$NUMBER" "$TEXT" && exit 0
		echo "$CONFIRM" | grep -E "^Cancel$" && exit 1
		echo "$CONFIRM" | grep -E "^Edit Message" && TEXT="$(editmsg "$NUMBER" "$TEXT")"


@@ 77,17 76,17 @@ sendtextmenu() {
}

tailtextlog() {
  st -e tail -f $LOGDIR/$1/sms.txt
  st -e tail -f "$LOGDIR/$1/sms.txt"
}

main() {
	# Display
	ENTRIES="$(echo -e "$(textcontacts)" | xargs -INUM echo NUM logfile)"
	ENTRIES="$(echo -e "Close Menu\nSend a Text\n$ENTRIES")"
	NUMBER="$(echo -e "$ENTRIES" | dmenu -p Texts -c -fn Terminus-20 -l 10)"
	echo $NUMBER | grep "Close Menu" && exit 1
	echo $NUMBER | grep "Send a Text" && sendtextmenu && exit 1
	tailtextlog "$(echo $NUMBER | sed 's/ logfile//g')"
	ENTRIES="$(printf %b "$(textcontacts)" | xargs -INUM echo NUM logfile)"
	ENTRIES="$(printf %b "Close Menu\nSend a Text\n$ENTRIES")"
	NUMBER="$(printf %b "$ENTRIES" | dmenu -p Texts -c -fn Terminus-20 -l 10)"
	echo "$NUMBER" | grep "Close Menu" && exit 1
	echo "$NUMBER" | grep "Send a Text" && sendtextmenu && exit 1
	tailtextlog "$(echo "$NUMBER" | sed 's/ logfile//g')"
}

main