Add modem/networks DWM plugins, Dual-SIM & PIN/PUK support, built-in dmenu views, and game UX fixes

This commit is contained in:
Luxferre
2026-10-24 18:59:48 +03:00
parent 668a4da11d
commit e549aaf413
63 changed files with 4781 additions and 426 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Bananarchy Bluetooth menu wrapper — routes to native xnetworks Bluetooth tab
if command -v xnetworks >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
exec xnetworks bluetooth
fi
exec /usr/bin/dwm-plugin networks bluetooth
+2 -2
View File
@@ -98,7 +98,7 @@ checkforfinishedcalls() {
sxmo_notifs.sh new \
-g "incoming-call-$FINISHEDNUMBER" \
"TERMNAME='$NOTIFMSG' sxmo_terminal.sh sh -c \"echo '$NOTIFMSG at $(date)' && read\"" \
"xcalllog" \
"Missed $icon_phn $CONTACT ($FINISHEDNUMBER)"
fi
@@ -280,7 +280,7 @@ checkfornewtexts() {
if [ -z "$SXMO_DISABLE_SMS_NOTIFS" ]; then
sxmo_notifs.sh new \
-g "incoming-message-$NUM" \
"sxmo_hook_tailtextlog.sh '$NUM'" \
"xsms tailtextlog '$NUM'" \
"$CONTACTNAME: $TEXT"
fi
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
if command -v xmodem >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
exec xmodem info
fi
. sxmo_common.sh
sxmo_terminal.sh sh -c "mmcli -m any && read"
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
if command -v xmodem >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
exec xmodem log
fi
. sxmo_common.sh
sxmo_terminal.sh sh -c "tail -n9999 -f $SXMO_LOGDIR/modemlog.tsv"
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Bananarchy Networks wrapper — routes to native xnetworks DWM plugin
if command -v xnetworks >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
exec xnetworks "$@"
fi
exec /usr/bin/dwm-plugin networks "$@"
+27
View File
@@ -0,0 +1,27 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Bananarchy SIM PIN/PUK unlock wrapper — routes to native xmodem plugin UI
if command -v xmodem >/dev/null 2>&1 && [ -n "${DISPLAY:-}" ]; then
exec xmodem unlock
fi
# Fallback if X11 plugin is not running
. sxmo_common.sh
SIM="$(mmcli -m any 2>/dev/null | grep -oE 'SIM/([0-9]+)' | head -n1 | cut -d'/' -f2 || true)"
[ -z "$SIM" ] && exit 0
LOCKSTATE="$(mmcli -m any -K 2>/dev/null | grep 'modem.generic.unlock-required' | cut -d':' -f2 | tr -d ' ' || true)"
case "$LOCKSTATE" in
sim-pin)
PIN="$(printf "0000\n1234\nCancel" | sxmo_dmenu.sh -p "PIN")"
[ -z "$PIN" ] || [ "$PIN" = "Cancel" ] && exit 0
mmcli -i "$SIM" --pin="$PIN"
;;
sim-puk)
PUK="$(printf "Cancel\n" | sxmo_dmenu.sh -p "PUK (8 digits)")"
[ -z "$PUK" ] || [ "$PUK" = "Cancel" ] && exit 0
NEWPIN="$(printf "0000\n1234\nCancel" | sxmo_dmenu.sh -p "New PIN")"
[ -z "$NEWPIN" ] || [ "$NEWPIN" = "Cancel" ] && exit 0
mmcli -i "$SIM" --puk="$PUK" --pin="$NEWPIN"
;;
esac
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
dwm-plugin
+1
View File
@@ -0,0 +1 @@
dwm-plugin
+1
View File
@@ -0,0 +1 @@
dwm-plugin
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+415
View File
@@ -0,0 +1,415 @@
#!/bin/sh
# Bananarchy Dual-SIM & QMI UIM Provisioning Helper for Qualcomm MSM8905/MSM8909
set -eu
CONF_FILE="/etc/conf.d/msm-modem-uim-selection"
if [ -r "$CONF_FILE" ]; then
# shellcheck disable=SC1090
. "$CONF_FILE"
fi
SIM_WAIT_TIME="${SIM_WAIT_TIME:-${sim_wait_time:-4}}"
PREFERRED_SIM_SLOT="${PREFERRED_SIM_SLOT:-${preferred_sim_slot:-1}}"
QMICLI_MODEM=""
detect_qmicli_modem() {
if ! command -v qmicli >/dev/null 2>&1; then
return 1
fi
if [ -e "/dev/modem" ]; then
QMICLI_MODEM="qmicli --silent -d /dev/modem"
return 0
elif [ -e "/dev/wwan0qmi0" ]; then
QMICLI_MODEM="qmicli --silent -d /dev/wwan0qmi0 --device-open-qmi"
return 0
elif qmicli --silent -pd qrtr://0 --uim-noop >/dev/null 2>&1; then
QMICLI_MODEM="qmicli --silent -pd qrtr://0"
return 0
fi
return 1
}
wait_for_qmicli_modem() {
max_wait="${1:-45}"
count=0
while [ "$count" -lt "$max_wait" ]; do
if detect_qmicli_modem; then
return 0
fi
sleep 1
count=$((count + 1))
done
return 1
}
# Parse `qmicli --uim-get-card-status` into shell-safe KEY=VALUE lines
parse_uim_card_status() {
raw_status="$1"
pref_slot="$2"
printf "%s\n" "$raw_status" | awk -v pref="$pref_slot" '
BEGIN {
prim_slot = 0
prim_app = 0
cur_slot = 0
in_app = 0
for (s = 1; s <= 2; s++) {
cstate[s] = "absent"
rawstate[s] = "absent"
upin_state[s] = "not-initialized"
upin_ret[s] = 0
upuk_ret[s] = 0
app_type[s] = "none"
app_state[s] = "none"
aid[s] = ""
pin1_state[s] = "not-initialized"
pin1_ret[s] = 0
puk1_ret[s] = 0
}
}
/Primary GW:/ {
if ($0 ~ /slot \x27[0-9]+\x27/) {
line = $0
sub(/.*slot \x27/, "", line)
sub(/\x27.*/, "", line)
prim_slot = line + 0
}
if ($0 ~ /application \x27[0-9]+\x27/) {
line = $0
sub(/.*application \x27/, "", line)
sub(/\x27.*/, "", line)
prim_app = line + 0
}
}
/^[[:space:]]*Slot \[[0-9]+\]:/ {
line = $0
sub(/.*Slot \[/, "", line)
sub(/\].*/, "", line)
cur_slot = line + 0
in_app = 0
next
}
cur_slot >= 1 && cur_slot <= 2 {
if ($0 ~ /^[[:space:]]*Application \[[0-9]+\]:/) {
in_app = 1
next
}
if (!in_app && $0 ~ /Card state:/) {
line = $0
sub(/.*Card state: \x27/, "", line)
sub(/\x27.*/, "", line)
rawstate[cur_slot] = line
if (line == "present") cstate[cur_slot] = "present"
else if (line == "absent" || line ~ /no-atr-received/) cstate[cur_slot] = "absent"
else cstate[cur_slot] = "error"
}
if (!in_app && $0 ~ /UPIN state:/) {
line = $0
sub(/.*UPIN state: \x27/, "", line)
sub(/\x27.*/, "", line)
upin_state[cur_slot] = line
}
if (!in_app && $0 ~ /UPIN retries:/) {
line = $0
sub(/.*UPIN retries: \x27/, "", line)
sub(/\x27.*/, "", line)
upin_ret[cur_slot] = line + 0
}
if (!in_app && $0 ~ /UPUK retries:/) {
line = $0
sub(/.*UPUK retries: \x27/, "", line)
sub(/\x27.*/, "", line)
upuk_ret[cur_slot] = line + 0
}
if (in_app && $0 ~ /Application type:/) {
line = $0
sub(/.*Application type: \x27/, "", line)
sub(/\x27.*/, "", line)
if (line ~ /^usim/) {
app_type[cur_slot] = "usim"
want_aid[cur_slot] = 2
} else if (line ~ /^sim/ && app_type[cur_slot] != "usim") {
app_type[cur_slot] = "sim"
want_aid[cur_slot] = 1
} else {
want_aid[cur_slot] = 0
}
}
if (in_app && $0 ~ /Application state:/ && want_aid[cur_slot] > 0) {
line = $0
sub(/.*Application state: \x27/, "", line)
sub(/\x27.*/, "", line)
app_state[cur_slot] = line
}
if (in_app && $0 ~ /Application ID:/ && want_aid[cur_slot] > 0) {
need_aid_line[cur_slot] = 1
next
}
if (in_app && need_aid_line[cur_slot] == 1) {
line = $0
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
if (line != "") {
aid[cur_slot] = line
}
need_aid_line[cur_slot] = 0
}
if (in_app && $0 ~ /PIN1 state:/ && want_aid[cur_slot] > 0) {
line = $0
sub(/.*PIN1 state: \x27/, "", line)
sub(/\x27.*/, "", line)
pin1_state[cur_slot] = line
}
if (in_app && $0 ~ /PIN1 retries:/ && want_aid[cur_slot] > 0) {
line = $0
sub(/.*PIN1 retries: \x27/, "", line)
sub(/\x27.*/, "", line)
pin1_ret[cur_slot] = line + 0
}
if (in_app && $0 ~ /PUK1 retries:/ && want_aid[cur_slot] > 0) {
line = $0
sub(/.*PUK1 retries: \x27/, "", line)
sub(/\x27.*/, "", line)
puk1_ret[cur_slot] = line + 0
}
}
END {
printf "PREFERRED_SLOT=%d\n", (pref == 2 ? 2 : 1)
printf "PRIMARY_GW_SLOT=%d\n", prim_slot
printf "PRIMARY_GW_APP=%d\n", prim_app
for (s = 1; s <= 2; s++) {
printf "SLOT%d_STATE=%s\n", s, cstate[s]
printf "SLOT%d_RAW_STATE=%s\n", s, rawstate[s]
printf "SLOT%d_APP_TYPE=%s\n", s, app_type[s]
printf "SLOT%d_APP_STATE=%s\n", s, app_state[s]
printf "SLOT%d_AID=%s\n", s, aid[s]
printf "SLOT%d_PIN1_STATE=%s\n", s, pin1_state[s]
printf "SLOT%d_PIN1_RETRIES=%d\n", s, pin1_ret[s]
printf "SLOT%d_PUK1_RETRIES=%d\n", s, puk1_ret[s]
printf "SLOT%d_UPIN_STATE=%s\n", s, upin_state[s]
printf "SLOT%d_UPIN_RETRIES=%d\n", s, upin_ret[s]
printf "SLOT%d_UPUK_RETRIES=%d\n", s, upuk_ret[s]
}
}
'
}
save_preferred_slot() {
target_slot="$1"
if [ -f "$CONF_FILE" ]; then
if grep -q "^preferred_sim_slot=" "$CONF_FILE"; then
sed -i "s/^preferred_sim_slot=.*/preferred_sim_slot=$target_slot/" "$CONF_FILE"
else
printf "\npreferred_sim_slot=%s\n" "$target_slot" >> "$CONF_FILE"
fi
else
printf "sim_wait_time=4\npreferred_sim_slot=%s\n" "$target_slot" > "$CONF_FILE"
fi
}
provision_slot() {
req_slot="$1"
wait_secs="$2"
if ! wait_for_qmicli_modem "$wait_secs"; then
echo "No modem available." >&2
return 2
fi
QMI_CARDS="$($QMICLI_MODEM --uim-get-card-status 2>/dev/null || true)"
count=0
while ! printf "%s" "$QMI_CARDS" | grep -Fq "Card state: 'present'"; do
if [ "$count" -ge "$SIM_WAIT_TIME" ]; then
echo "No SIM detected after $SIM_WAIT_TIME seconds."
return 0
fi
sleep 1
count=$((count + 1))
QMI_CARDS="$($QMICLI_MODEM --uim-get-card-status 2>/dev/null || true)"
done
eval "$(parse_uim_card_status "$QMI_CARDS" "$req_slot")"
chosen_slot=""
chosen_aid=""
if [ "$req_slot" = "2" ]; then
if [ "$SLOT2_STATE" = "present" ] && [ -n "$SLOT2_AID" ]; then
chosen_slot="2"
chosen_aid="$SLOT2_AID"
elif [ "$SLOT1_STATE" = "present" ] && [ -n "$SLOT1_AID" ]; then
chosen_slot="1"
chosen_aid="$SLOT1_AID"
fi
else
if [ "$SLOT1_STATE" = "present" ] && [ -n "$SLOT1_AID" ]; then
chosen_slot="1"
chosen_aid="$SLOT1_AID"
elif [ "$SLOT2_STATE" = "present" ] && [ -n "$SLOT2_AID" ]; then
chosen_slot="2"
chosen_aid="$SLOT2_AID"
fi
fi
if [ -z "$chosen_slot" ] || [ -z "$chosen_aid" ]; then
echo "No valid USIM/SIM application found on any slot."
return 0
fi
if [ "$PRIMARY_GW_SLOT" != "0" ]; then
$QMICLI_MODEM --uim-change-provisioning-session='activate=no,session-type=primary-gw-provisioning' >/dev/null 2>&1 || true
fi
echo "Selecting AID $chosen_aid on slot $chosen_slot"
$QMICLI_MODEM --uim-change-provisioning-session="slot=$chosen_slot,activate=yes,session-type=primary-gw-provisioning,aid=$chosen_aid" >/dev/null
return $?
}
cmd="${1:-boot}"
case "$cmd" in
boot)
if command -v systemd-notify >/dev/null 2>&1; then
trap '[ $? -eq 0 ] && systemd-notify --ready' EXIT
fi
case "$(cat /sys/devices/soc0/machine 2>/dev/null || true)" in
APQ*)
echo "Skipping SIM configuration on APQ SoC."
exit 0
;;
esac
provision_slot "$PREFERRED_SIM_SLOT" 45
exit $?
;;
status)
if ! detect_qmicli_modem; then
echo "MODEM_AVAILABLE=0"
echo "PREFERRED_SLOT=$PREFERRED_SIM_SLOT"
exit 0
fi
QMI_CARDS="$($QMICLI_MODEM --uim-get-card-status 2>/dev/null || true)"
if [ -z "$QMI_CARDS" ]; then
echo "MODEM_AVAILABLE=0"
echo "PREFERRED_SLOT=$PREFERRED_SIM_SLOT"
exit 0
fi
echo "MODEM_AVAILABLE=1"
parse_uim_card_status "$QMI_CARDS" "$PREFERRED_SIM_SLOT"
exit 0
;;
switch)
target="${2:-1}"
if [ "$target" != "1" ] && [ "$target" != "2" ]; then
echo "Invalid slot: $target (must be 1 or 2)" >&2
exit 1
fi
save_preferred_slot "$target"
SIM_WAIT_TIME=2
provision_slot "$target" 5
if command -v rc-service >/dev/null 2>&1; then
rc-service modemmanager restart >/dev/null 2>&1 || true
elif command -v systemctl >/dev/null 2>&1; then
systemctl restart ModemManager >/dev/null 2>&1 || true
fi
exit 0
;;
verify-pin)
slot="${2:-1}"
pin="${3:-}"
if [ -z "$pin" ]; then
echo "Missing PIN" >&2
exit 1
fi
sim_id="$(mmcli -m any 2>/dev/null | grep -oE 'SIM/[0-9]+' | head -n1 | cut -d'/' -f2 || true)"
if [ -n "$sim_id" ] && mmcli -i "$sim_id" --pin="$pin" >/dev/null 2>&1; then
exit 0
fi
if detect_qmicli_modem; then
if $QMICLI_MODEM --uim-verify-pin="PIN1,$pin,session-type=primary-gw-provisioning" >/dev/null 2>&1; then
exit 0
fi
if $QMICLI_MODEM --uim-verify-pin="PIN1,$pin,session-type=card-slot-$slot" >/dev/null 2>&1; then
exit 0
fi
fi
exit 1
;;
unblock-puk)
slot="${2:-1}"
puk="${3:-}"
newpin="${4:-}"
if [ -z "$puk" ] || [ -z "$newpin" ]; then
echo "Missing PUK or new PIN" >&2
exit 1
fi
sim_id="$(mmcli -m any 2>/dev/null | grep -oE 'SIM/[0-9]+' | head -n1 | cut -d'/' -f2 || true)"
if [ -n "$sim_id" ] && mmcli -i "$sim_id" --puk="$puk" --pin="$newpin" >/dev/null 2>&1; then
exit 0
fi
if detect_qmicli_modem; then
if $QMICLI_MODEM --uim-unblock-pin="PIN1,$puk,$newpin,session-type=primary-gw-provisioning" >/dev/null 2>&1; then
exit 0
fi
if $QMICLI_MODEM --uim-unblock-pin="PIN1,$puk,$newpin,session-type=card-slot-$slot" >/dev/null 2>&1; then
exit 0
fi
fi
exit 1
;;
set-pin-lock)
slot="${2:-1}"
mode="${3:-enable}"
pin="${4:-}"
if [ -z "$pin" ] || { [ "$mode" != "enable" ] && [ "$mode" != "disable" ]; }; then
echo "Usage: $0 set-pin-lock <1|2> <enable|disable> <pin>" >&2
exit 1
fi
sim_id="$(mmcli -m any 2>/dev/null | grep -oE 'SIM/[0-9]+' | head -n1 | cut -d'/' -f2 || true)"
if [ -n "$sim_id" ]; then
if [ "$mode" = "enable" ] && mmcli -i "$sim_id" --enable-pin --pin="$pin" >/dev/null 2>&1; then
exit 0
elif [ "$mode" = "disable" ] && mmcli -i "$sim_id" --disable-pin --pin="$pin" >/dev/null 2>&1; then
exit 0
fi
fi
if detect_qmicli_modem; then
if $QMICLI_MODEM --uim-set-pin-protection="PIN1,$mode,$pin,session-type=primary-gw-provisioning" >/dev/null 2>&1; then
exit 0
fi
if $QMICLI_MODEM --uim-set-pin-protection="PIN1,$mode,$pin,session-type=card-slot-$slot" >/dev/null 2>&1; then
exit 0
fi
fi
exit 1
;;
change-pin)
slot="${2:-1}"
oldpin="${3:-}"
newpin="${4:-}"
if [ -z "$oldpin" ] || [ -z "$newpin" ]; then
echo "Usage: $0 change-pin <1|2> <oldpin> <newpin>" >&2
exit 1
fi
sim_id="$(mmcli -m any 2>/dev/null | grep -oE 'SIM/[0-9]+' | head -n1 | cut -d'/' -f2 || true)"
if [ -n "$sim_id" ] && mmcli -i "$sim_id" --change-pin="$newpin" --pin="$oldpin" >/dev/null 2>&1; then
exit 0
fi
if detect_qmicli_modem; then
if $QMICLI_MODEM --uim-change-pin="PIN1,$oldpin,$newpin,session-type=primary-gw-provisioning" >/dev/null 2>&1; then
exit 0
fi
if $QMICLI_MODEM --uim-change-pin="PIN1,$oldpin,$newpin,session-type=card-slot-$slot" >/dev/null 2>&1; then
exit 0
fi
fi
exit 1
;;
*)
echo "Usage: $0 [boot|status|switch <1|2>|verify-pin <slot> <pin>|unblock-puk <slot> <puk> <newpin>|set-pin-lock <slot> <enable|disable> <pin>|change-pin <slot> <oldpin> <newpin>]" >&2
exit 1
;;
esac
+9
View File
@@ -9,6 +9,15 @@
export PATH="${HOME:-/home/user}/.local/bin:${HOME:-/home/user}/.config/sxmo/hooks:/usr/share/sxmo/default_hooks:$PATH"
. sxmo_hook_icons.sh
GAMES_CACHE="${XDG_RUNTIME_DIR:-/tmp}/sxmo_games.cache"
if [ -f "$GAMES_CACHE" ] && [ ! "$0" -nt "$GAMES_CACHE" ] && [ ! /usr/bin -nt "$GAMES_CACHE" ] && [ ! /usr/local/bin -nt "$GAMES_CACHE" ] && [ ! "${HOME:-/home/user}/.local/bin" -nt "$GAMES_CACHE" ]; then
cat "$GAMES_CACHE"
exit 0
fi
exec 3>&1 > "$GAMES_CACHE.tmp"
trap 'mv -f "$GAMES_CACHE.tmp" "$GAMES_CACHE" 2>/dev/null; cat "$GAMES_CACHE" >&3 2>/dev/null' EXIT
write_line() {
printf "%s ^ 0 ^ %s\n" "$1" "$2"
}
@@ -16,38 +16,31 @@ newstate="$2"
sxmo_debug "$2 (old: $1 [reason: $3])"
case "$newstate" in
"locked")
sxmo_log "State is locked. Attempting to unlock."
if ! pgrep -f "sxmo_unlocksim.sh" >/dev/null; then
sxmo_unlocksim.sh
fi
;;
"enabling")
sxmo_log "State is enabling. Clearing stale call files."
rm "$XDG_RUNTIME_DIR"/sxmo_calls/* 2>/dev/null
rm -f "$SXMO_NOTIFDIR"/incomingcall* 2>/dev/null
;;
"registered")
sxmo_log "State is registered. Checking for calls and messages."
"locked")
sxmo_log "State is locked. Opening SIM PIN/PUK unlock dialog."
if command -v xmodem >/dev/null 2>&1; then
xmodem unlock >/dev/null 2>&1 &
elif ! pgrep -f "sxmo_unlocksim.sh" >/dev/null; then
sxmo_unlocksim.sh &
fi
;;
"enabling")
sxmo_log "State is enabling. Clearing stale call files."
rm "$XDG_RUNTIME_DIR"/sxmo_calls/* 2>/dev/null || true
rm -f "$SXMO_NOTIFDIR"/incomingcall* 2>/dev/null || true
;;
"registered")
sxmo_log "State is registered. Checking for calls and messages."
# kill the pin-entry dmenu if still open
pkill -f sxmo_unlocksim.sh
# kill the pin-entry dmenu if still open
pkill -f sxmo_unlocksim.sh 2>/dev/null || true
sxmo_modem.sh checkforfinishedcalls
sxmo_modem.sh checkforincomingcalls
sxmo_modem.sh checkfornewtexts
sxmo_modem.sh checkforstucksms
if [ -f "${SXMO_MMS_BASE_DIR:-"$HOME"/.mms/modemmanager}/mms" ]; then
sxmo_mms.sh checkforlostmms
fi
# An example of something else to do here!
#if ! ping -Iwwan0 -q -c 1 -W 10 www.google.com >/dev/null; then
# sxmo_log "ping failed."
# nmcli c down "MINTY"
# nmcli c up "MINTY"
#else
# sxmo_log "ping ok."
#fi
;;
sxmo_modem.sh checkforfinishedcalls
sxmo_modem.sh checkforincomingcalls
sxmo_modem.sh checkfornewtexts
sxmo_modem.sh checkforstucksms
if [ -f "${SXMO_MMS_BASE_DIR:-"$HOME"/.mms/modemmanager}/mms" ]; then
sxmo_mms.sh checkforlostmms
fi
;;
esac