Fix SIM2 QMI UIM provisioning, auto-enable ModemManager, PIN auto-prompt, call audio, and Dunst clearing
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# Maximum time to wait for SIM card to appear after starting the modem.
|
||||
# Some SIM cards or modem firmwares might take longer to initialize.
|
||||
# Set to 0 to disable waiting entirely.
|
||||
sim_wait_time=4
|
||||
sim_wait_time=10
|
||||
|
||||
# Preferred physical SIM slot (1 or 2) for Primary GW provisioning on Dual-SIM
|
||||
# Qualcomm MSM8905/MSM8909 devices. Falls back automatically if the preferred
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
#!/sbin/openrc-run
|
||||
|
||||
# This script tries to automatically configure UIM application for Qualcomm QMI
|
||||
# modems with more than one sim slot.
|
||||
|
||||
name="UIM Slot selection"
|
||||
description="Select UIM slot and application on the embedded QMI modem."
|
||||
|
||||
depend() {
|
||||
need rmtfs
|
||||
after msm8909-modem-wwan-port
|
||||
before ofono
|
||||
before modemmanager
|
||||
}
|
||||
|
||||
# Use the service start method instead of command= because we want to block
|
||||
# other services while the modem isn't ready yet.
|
||||
start() {
|
||||
SIM_WAIT_TIME="${sim_wait_time:-10}" /usr/libexec/msm-modem-uim-selection boot
|
||||
eend $?
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
horizontal_padding = 6
|
||||
frame_width = 2
|
||||
frame_color = "#005577"
|
||||
idle_threshold = 120
|
||||
idle_threshold = 0
|
||||
font = Fira Code 9.5
|
||||
markup = full
|
||||
max_icon_size = 24
|
||||
@@ -22,16 +22,16 @@
|
||||
[urgency_low]
|
||||
background = "#222222"
|
||||
foreground = "#cccccc"
|
||||
timeout = 8
|
||||
timeout = 5
|
||||
|
||||
[urgency_normal]
|
||||
background = "#1c1c1c"
|
||||
foreground = "#ffffff"
|
||||
frame_color = "#005577"
|
||||
timeout = 12
|
||||
timeout = 8
|
||||
|
||||
[urgency_critical]
|
||||
background = "#900000"
|
||||
foreground = "#ffffff"
|
||||
frame_color = "#ff0000"
|
||||
timeout = 0
|
||||
timeout = 10
|
||||
|
||||
@@ -3,61 +3,42 @@
|
||||
# shellcheck source=scripts/core/sxmo_common.sh
|
||||
. sxmo_common.sh
|
||||
|
||||
ca_dbus_get_prop() {
|
||||
dbus-send --session --print-reply --dest=org.mobian_project.CallAudio \
|
||||
--reply-timeout=2500 /org/mobian_project/CallAudio org.freedesktop.DBus.Properties.Get \
|
||||
string:org.mobian_project.CallAudio string:"$1"
|
||||
}
|
||||
|
||||
ca_dbus_set_prop() {
|
||||
dbus-send --session --print-reply --type=method_call \
|
||||
--reply-timeout=2500 --dest=org.mobian_project.CallAudio \
|
||||
/org/mobian_project/CallAudio org.mobian_project.CallAudio."$1" "$2" |\
|
||||
grep -q "boolean true" && return 0 || return 1
|
||||
}
|
||||
|
||||
enable_call_audio_mode() {
|
||||
if pactl -f json info 2>/dev/null | jq -r .server_name | grep -q PipeWire; then
|
||||
sxmo_audio.sh device set Earpiece
|
||||
sxmo_log "Successfully enabled call audio mode (Earpiece)."
|
||||
sxmo_hook_statusbar.sh volume
|
||||
return 0
|
||||
fi
|
||||
if ca_dbus_set_prop SelectMode uint32:1; then
|
||||
sxmo_log "Successfully enabled call audio mode."
|
||||
sxmo_hook_statusbar.sh volume
|
||||
else
|
||||
sxmo_notify_user.sh "Failed to enable call audio mode."
|
||||
return 1
|
||||
fi
|
||||
if command -v amixer >/dev/null 2>&1; then
|
||||
amixer -c 0 sset 'PRI_MI2S_RX Voice Mixer VoiceMMode1' on >/dev/null 2>&1 || true
|
||||
amixer -c 0 sset 'VoiceMMode1 Capture Mixer TERT_MI2S_TX' on >/dev/null 2>&1 || true
|
||||
amixer -c 0 sset 'RX1 MIX1 INP1' 'RX1' >/dev/null 2>&1 || true
|
||||
amixer -c 0 sset 'RDAC2 MUX' 'RX1' >/dev/null 2>&1 || true
|
||||
amixer -c 0 sset 'EAR_S' 'Switch' >/dev/null 2>&1 || true
|
||||
amixer -c 0 sset 'DEC1 MUX' 'ADC1' >/dev/null 2>&1 || true
|
||||
amixer -c 0 sset 'ADC1 Volume' 100% >/dev/null 2>&1 || true
|
||||
amixer -c 0 sset 'RX1 Digital Volume' 84 >/dev/null 2>&1 || true
|
||||
fi
|
||||
sxmo_audio.sh device set Earpiece >/dev/null 2>&1 || true
|
||||
sxmo_log "Enabled ALSA voice call audio mode (Earpiece)."
|
||||
sxmo_hook_statusbar.sh volume >/dev/null 2>&1 || true
|
||||
return 0
|
||||
}
|
||||
|
||||
disable_call_audio_mode() {
|
||||
if pactl -f json info 2>/dev/null | jq -r .server_name | grep -q PipeWire; then
|
||||
sxmo_audio.sh device set Speaker
|
||||
sxmo_log "Successfully disabled call audio mode (Speaker)."
|
||||
sxmo_hook_statusbar.sh volume
|
||||
return 0
|
||||
fi
|
||||
if ca_dbus_set_prop SelectMode uint32:0; then
|
||||
sxmo_log "Successfully disabled call audio mode."
|
||||
sxmo_hook_statusbar.sh volume
|
||||
else
|
||||
sxmo_notify_user.sh "Failed to disable call audio mode."
|
||||
return 1
|
||||
fi
|
||||
if command -v amixer >/dev/null 2>&1; then
|
||||
amixer -c 0 sset 'PRI_MI2S_RX Voice Mixer VoiceMMode1' off >/dev/null 2>&1 || true
|
||||
amixer -c 0 sset 'VoiceMMode1 Capture Mixer TERT_MI2S_TX' off >/dev/null 2>&1 || true
|
||||
fi
|
||||
sxmo_audio.sh device set Speaker >/dev/null 2>&1 || true
|
||||
sxmo_log "Disabled ALSA voice call audio mode (Speaker)."
|
||||
sxmo_hook_statusbar.sh volume >/dev/null 2>&1 || true
|
||||
return 0
|
||||
}
|
||||
|
||||
setup_audio() {
|
||||
if ! enable_call_audio_mode; then
|
||||
return 1
|
||||
fi
|
||||
enable_call_audio_mode
|
||||
return 0
|
||||
}
|
||||
|
||||
reset_audio() {
|
||||
if ! disable_call_audio_mode; then
|
||||
return 1
|
||||
fi
|
||||
disable_call_audio_mode
|
||||
return 0
|
||||
}
|
||||
|
||||
"$@"
|
||||
|
||||
@@ -36,7 +36,7 @@ pickup() {
|
||||
NUM="$(vid_to_number "$CALLID" 2>/dev/null || true)"
|
||||
|
||||
DIRECTION="$(
|
||||
mmcli --voice-status -o "$CALLID" -K |
|
||||
(mmcli -m any -o "$CALLID" -K 2>/dev/null || mmcli -o "$CALLID" -K 2>/dev/null || mmcli --voice-status -o "$CALLID" -K 2>/dev/null) |
|
||||
grep call.properties.direction |
|
||||
cut -d: -f2 |
|
||||
tr -d " "
|
||||
@@ -53,11 +53,12 @@ pickup() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
sxmo_notify_user.sh "Started call"
|
||||
touch "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.initiatedcall"
|
||||
log_event "call_start" "$CALLID"
|
||||
if command -v xcallscreen >/dev/null 2>&1; then
|
||||
xcallscreen outgoing "$CALLID" "$NUM" >/dev/null 2>&1 || true
|
||||
else
|
||||
sxmo_notify_user.sh "Started call"
|
||||
fi
|
||||
;;
|
||||
incoming)
|
||||
@@ -74,11 +75,12 @@ pickup() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
sxmo_notify_user.sh "Picked up call"
|
||||
touch "$XDG_RUNTIME_DIR/sxmo_calls/${CALLID}.pickedupcall"
|
||||
log_event "call_pickup" "$CALLID"
|
||||
if command -v xcallscreen >/dev/null 2>&1; then
|
||||
xcallscreen active "$CALLID" "$NUM" >/dev/null 2>&1 || true
|
||||
else
|
||||
sxmo_notify_user.sh "Picked up call"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
|
||||
@@ -16,15 +16,16 @@ dial_number() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
NUMBER="$1"
|
||||
NUMBER="$(printf "%s" "$1" | tr -cd '+0-9*#')"
|
||||
if [ -z "$NUMBER" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
CLEANEDNUMBER="$(pnc find ${DEFAULT_COUNTRY:+-c "$DEFAULT_COUNTRY"} "$1" 2>/dev/null || true)"
|
||||
if [ -n "$CLEANEDNUMBER" ] && [ "$NUMBER" != "$CLEANEDNUMBER" ]; then
|
||||
NUMBER="$(cat <<EOF | sxmo_dmenu.sh -p "Rewrite ?"
|
||||
$NUMBER
|
||||
$CLEANEDNUMBER
|
||||
EOF
|
||||
)"
|
||||
mm_state="$(mmcli -m any -K 2>/dev/null | awk -F': ' '$1 == "modem.generic.state" {print $2; exit}')"
|
||||
if [ "$mm_state" = "disabled" ] || [ -z "$mm_state" ]; then
|
||||
mmcli -m any -e >/dev/null 2>&1 || true
|
||||
mmcli -m any --3gpp-register-home >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
sxmo_log "Attempting to dial: $NUMBER"
|
||||
@@ -33,7 +34,7 @@ EOF
|
||||
fi
|
||||
|
||||
if ! CALLID="$(
|
||||
mmcli -m any --voice-create-call "number=$NUMBER" |
|
||||
mmcli -m any --voice-create-call="number=$NUMBER" 2>/dev/null |
|
||||
grep -Eo "Call/[0-9]+" |
|
||||
grep -oE "[0-9]+"
|
||||
)"; then
|
||||
@@ -79,16 +80,22 @@ EOF
|
||||
}
|
||||
|
||||
dial_ussd() {
|
||||
|
||||
USSD="$1"
|
||||
DBUS_MODEM=$(mmcli -J -L | jq -r '."modem-list"[]')
|
||||
MM_BUS="org.freedesktop.ModemManager1"
|
||||
USSD_IFACE="org.freedesktop.ModemManager1.Modem.Modem3gpp.Ussd"
|
||||
|
||||
sxmo_log "Dialling USSD: $USSD"
|
||||
OUTPUT=$(busctl --json=short call "$MM_BUS" "$DBUS_MODEM" "$USSD_IFACE" Initiate "s" "$USSD" | jq -r '.data[]')
|
||||
|
||||
sxmo_terminal.sh sxmo_ussd.sh "$DBUS_MODEM" "Unknown" "$OUTPUT" &
|
||||
OUTPUT="$(doas -n /usr/libexec/msm-modem-uim-selection ussd initiate "$USSD" 2>/dev/null || /usr/libexec/msm-modem-uim-selection ussd initiate "$USSD" 2>/dev/null || true)"
|
||||
if [ -z "$OUTPUT" ]; then
|
||||
DBUS_MODEM="$(mmcli -J -L 2>/dev/null | jq -r '."modem-list"[]' 2>/dev/null | head -n1)"
|
||||
MM_BUS="org.freedesktop.ModemManager1"
|
||||
USSD_IFACE="org.freedesktop.ModemManager1.Modem.Modem3gpp.Ussd"
|
||||
if [ -n "$DBUS_MODEM" ]; then
|
||||
OUTPUT="$(busctl --json=short call "$MM_BUS" "$DBUS_MODEM" "$USSD_IFACE" Initiate "s" "$USSD" 2>/dev/null | jq -r '.data[]' 2>/dev/null || true)"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$OUTPUT" ]; then
|
||||
sxmo_notify_user.sh "USSD ($USSD): $OUTPUT"
|
||||
else
|
||||
sxmo_notify_user.sh --urgency=critical "USSD request failed ($USSD)"
|
||||
fi
|
||||
}
|
||||
|
||||
dial_menu() {
|
||||
|
||||
Executable
+174
@@ -0,0 +1,174 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
# Copyright 2022 Sxmo Contributors
|
||||
|
||||
# include common definitions
|
||||
# shellcheck source=scripts/core/sxmo_common.sh
|
||||
. sxmo_common.sh
|
||||
|
||||
# see networkmanager documentation for these state names
|
||||
statenumtoname() {
|
||||
case "$1" in
|
||||
"int32 -1") printf "failed" ;;
|
||||
"int32 0") printf "unknown" ;;
|
||||
"int32 1") printf "initializing" ;;
|
||||
"int32 2") printf "locked" ;;
|
||||
"int32 3") printf "disabled" ;;
|
||||
"int32 4") printf "disabling" ;;
|
||||
"int32 5") printf "enabling" ;;
|
||||
"int32 6") printf "enabled" ;;
|
||||
"int32 7") printf "searching" ;;
|
||||
"int32 8") printf "registered" ;;
|
||||
"int32 9") printf "disconnecting" ;;
|
||||
"int32 10") printf "connecting" ;;
|
||||
"int32 11") printf "connected" ;;
|
||||
*) printf "ERROR" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
mainloop() {
|
||||
# get initial modem state and handle SIM2/QMI PIN lock or unprovisioned slot
|
||||
(
|
||||
tries=0
|
||||
newstate=""
|
||||
while [ "$tries" -lt 15 ]; do
|
||||
newstate="$(mmcli -m any -K 2>/dev/null | grep "^modem.generic.state " | cut -d':' -f2 | sed 's/^ //')"
|
||||
if [ -n "$newstate" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
tries=$((tries + 1))
|
||||
done
|
||||
|
||||
uim_st="$(doas -n /usr/libexec/msm-modem-uim-selection status 2>/dev/null || /usr/libexec/msm-modem-uim-selection status 2>/dev/null || true)"
|
||||
if printf "%s\n" "$uim_st" | grep -qE "SLOT[12]_PIN1_STATE=(enabled-not-verified|blocked)|SLOT[12]_APP_STATE=(pin1|puk1)"; then
|
||||
newstate="locked"
|
||||
elif printf "%s\n" "$uim_st" | grep -qE "SLOT[12]_STATE=present" && printf "%s\n" "$uim_st" | grep -q "^PRIMARY_GW_SLOT=0$"; then
|
||||
doas -n /usr/libexec/msm-modem-uim-selection boot >/dev/null 2>&1 || true
|
||||
newstate="$(mmcli -m any -K 2>/dev/null | grep "^modem.generic.state " | cut -d':' -f2 | sed 's/^ //')"
|
||||
fi
|
||||
|
||||
if [ -n "$newstate" ]; then
|
||||
# fake oldstate (boot) and reason (0)
|
||||
sxmo_hook_modem.sh "boot" "$newstate" "0"
|
||||
sxmo_hook_statusbar.sh modem
|
||||
fi
|
||||
) &
|
||||
|
||||
# Monitor for incoming calls
|
||||
dbus-monitor --system "interface='org.freedesktop.ModemManager1.Modem.Voice',type='signal',member='CallAdded'" |
|
||||
while read -r line; do
|
||||
echo "$line" | grep -qE "^signal" && sxmo_modem.sh checkforincomingcalls
|
||||
done &
|
||||
|
||||
# Monitor for incoming texts
|
||||
dbus-monitor --system "interface='org.freedesktop.ModemManager1.Modem.Messaging',type='signal',member='Added'" |
|
||||
while read -r line; do
|
||||
echo "$line" | grep -qE "^signal" && sxmo_modem.sh checkfornewtexts
|
||||
done &
|
||||
|
||||
# Check for new texts periodically
|
||||
sxmo_run_aligned.sh 300 sxmo_modem.sh checkfornewtexts &
|
||||
|
||||
# Monitor for finished calls
|
||||
dbus-monitor --system "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',arg0='org.freedesktop.ModemManager1.Call'" |
|
||||
while read -r line; do
|
||||
echo "$line" | grep -qE "^signal" && sxmo_modem.sh checkforfinishedcalls
|
||||
done &
|
||||
|
||||
# Periodically remove finished calls
|
||||
sxmo_run_aligned.sh 300 sxmo_modem.sh checkforfinishedcalls &
|
||||
|
||||
# Monitor for modem state change
|
||||
dbus-monitor --system "interface='org.freedesktop.ModemManager1.Modem',type='signal',member='StateChanged'" |
|
||||
while read -r line; do
|
||||
if echo "$line" | grep -qE "^signal.*StateChanged"; then
|
||||
read -r oldstate
|
||||
read -r newstate
|
||||
read -r reason
|
||||
sxmo_hook_modem.sh "$(statenumtoname "$oldstate")" \
|
||||
"$(statenumtoname "$newstate")" \
|
||||
"$(echo "$reason" | sed 's/uint32 //')"
|
||||
sxmo_hook_statusbar.sh modem
|
||||
fi
|
||||
done &
|
||||
|
||||
# Monitor for 3GPP USSD
|
||||
dbus-monitor --system "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',arg0='org.freedesktop.ModemManager1.Modem.Modem3gpp.Ussd'" |
|
||||
while read -r line; do
|
||||
case "$line" in
|
||||
*"/org/freedesktop/ModemManager1/Modem"*)
|
||||
MODEM=$(echo "$line" | awk -F'[;=]' '{print $6}')
|
||||
CHANGED=0
|
||||
;;
|
||||
*"string \"NetworkNotification"*)
|
||||
TYPE="NetworkNotification"
|
||||
CHANGED=1
|
||||
;;
|
||||
*"string \"NetworkRequest"*)
|
||||
TYPE="NetworkRequest"
|
||||
CHANGED=1
|
||||
;;
|
||||
*)
|
||||
CHANGED=0
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$CHANGED" = "1" ]; then
|
||||
# Fetch message (third argument) in sxmo_ussd.sh to save time in this loop
|
||||
sxmo_terminal.sh sxmo_ussd.sh "$MODEM" "$TYPE" "" &
|
||||
fi
|
||||
|
||||
done &
|
||||
|
||||
if [ -f "${SXMO_MMS_BASE_DIR:-"$HOME"/.mms/modemmanager}/mms" ]; then
|
||||
# monitor for received mms
|
||||
dbus-monitor "interface='org.ofono.mms.Service',type='signal',member='MessageAdded'" |
|
||||
while read -r line; do
|
||||
if echo "$line" | grep -q '^object path'; then
|
||||
MESSAGE_PATH="$(echo "$line" | cut -d\" -f2)"
|
||||
fi
|
||||
if echo "$line" | grep -q 'string "received"'; then
|
||||
sxmo_mms.sh processmms "$MESSAGE_PATH"
|
||||
fi
|
||||
done &
|
||||
fi
|
||||
|
||||
if [ -f "${SXMO_VVM_BASE_DIR:-"$HOME"/.vvm/modemmanager}/vvm" ]; then
|
||||
# monitor for vvm (Visual Voice Mail)
|
||||
VVM_START=0
|
||||
dbus-monitor "interface='org.kop316.vvm.Service',type='signal',member='MessageAdded'" |
|
||||
while read -r line; do
|
||||
if echo "$line" | grep -q '^object path'; then
|
||||
VVM_ID="$(echo "$line" | cut -d\" -f2 | rev | cut -d'/' -f1 | rev)"
|
||||
VVM_START=1
|
||||
fi
|
||||
|
||||
if echo "$line" | grep -q '^]'; then
|
||||
VVM_START=0
|
||||
sxmo_vvm.sh processvvm "$VVM_DATE" "$VVM_SENDER" "$VVM_ID" "$VVM_ATTACHMENT"
|
||||
fi
|
||||
|
||||
if [ "$VVM_START" -eq 1 ]; then
|
||||
if echo "$line" | grep -q '^string "Date"'; then
|
||||
read -r line
|
||||
VVM_DATE="$(echo "$line" | cut -d\" -f2)"
|
||||
elif echo "$line" | grep -q '^string "Sender"'; then
|
||||
read -r line
|
||||
VVM_SENDER="$(echo "$line" | cut -d\" -f2)"
|
||||
elif echo "$line" | grep -q '^string "Attachments"'; then
|
||||
read -r line
|
||||
VVM_ATTACHMENT="$(echo "$line" | cut -d\" -f2)"
|
||||
fi
|
||||
fi
|
||||
done &
|
||||
fi
|
||||
|
||||
wait
|
||||
}
|
||||
|
||||
# new session, clean up all phone related files
|
||||
rm "$XDG_RUNTIME_DIR/sxmo_calls/"* 2>/dev/null || true
|
||||
rm -f "$XDG_RUNTIME_DIR"/sxmo.ring.pid 2>/dev/null
|
||||
rm -f "$SXMO_NOTIFDIR"/incomingcall* 2>/dev/null
|
||||
mainloop
|
||||
@@ -12,189 +12,209 @@ SXMO_NOTIFDIR="${SXMO_NOTIFDIR:-${XDG_DATA_HOME:-$HOME/.local/share}/sxmo/notifi
|
||||
[ -z "$SXMO_NOTIFDIR" ] || [ "$SXMO_NOTIFDIR" = "/" ] && SXMO_NOTIFDIR="$HOME/.local/share/sxmo/notifications"
|
||||
|
||||
_clear_notif_group() {
|
||||
find "$SXMO_NOTIFDIR" -type f | while read -r file; do
|
||||
if awk NR==1 "$file" | grep -lxq "$1"; then
|
||||
rm "$file"
|
||||
fi
|
||||
done
|
||||
find "$SXMO_NOTIFDIR" -type f 2>/dev/null | while read -r file; do
|
||||
if [ -f "$file" ] && awk NR==1 "$file" 2>/dev/null | grep -lxq "$1"; then
|
||||
rm -f "$file"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
_handle_new_notif_file(){
|
||||
file="$1"
|
||||
clear_all() {
|
||||
rm -f "$SXMO_NOTIFDIR"/* 2>/dev/null || true
|
||||
dunstctl close-all >/dev/null 2>&1 || true
|
||||
dunstctl history-clear >/dev/null 2>&1 || true
|
||||
pkill -x dunstify >/dev/null 2>&1 || true
|
||||
sxmo_hook_statusbar.sh notifications >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
if [ "$(wc -l "$file" | cut -d' ' -f1)" -lt 3 ]; then
|
||||
sxmo_log "Invalid notification file $file found, deleting!"
|
||||
rm -f "$file"
|
||||
return
|
||||
fi
|
||||
_handle_new_notif_file() {
|
||||
file="$1"
|
||||
[ -f "$file" ] || return 0
|
||||
|
||||
sxmo_hook_notification.sh "$file" &
|
||||
if [ "$(wc -l < "$file" 2>/dev/null || echo 0)" -lt 3 ]; then
|
||||
sxmo_log "Invalid notification file $file found, deleting!"
|
||||
rm -f "$file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
group="$(awk NR==1 "$file")"
|
||||
action="$(awk NR==2 "$file")"
|
||||
msg="$(tail -n+3 "$file" | cut -c1-70)"
|
||||
sxmo_hook_notification.sh "$file" &
|
||||
|
||||
case "$(dunstify --action="default,Open" "$msg")" in
|
||||
"2")
|
||||
#
|
||||
# _clear_notif_group "$group"
|
||||
#
|
||||
;;
|
||||
"default")
|
||||
_clear_notif_group "$group"
|
||||
setsid -f sh -c "$action" > /dev/null 2>&1
|
||||
;;
|
||||
esac
|
||||
group="$(awk NR==1 "$file" 2>/dev/null)"
|
||||
action="$(awk NR==2 "$file" 2>/dev/null)"
|
||||
msg="$(tail -n+3 "$file" 2>/dev/null | cut -c1-70)"
|
||||
|
||||
(
|
||||
case "$(dunstify --action="default,Open" "$msg" 2>/dev/null)" in
|
||||
"2")
|
||||
;;
|
||||
"default")
|
||||
_clear_notif_group "$group"
|
||||
sxmo_hook_statusbar.sh notifications >/dev/null 2>&1 || true
|
||||
if [ -n "$action" ] && [ "$action" != "none" ]; then
|
||||
setsid -f sh -c "$action" > /dev/null 2>&1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
) &
|
||||
}
|
||||
|
||||
_notifications_hook() {
|
||||
_cnt=0
|
||||
for _nf in "$SXMO_NOTIFDIR"/*; do
|
||||
[ -f "$_nf" ] && _cnt=$((_cnt + 1))
|
||||
done
|
||||
sxmo_hook_notifications.sh "$_cnt"
|
||||
_cnt=0
|
||||
for _nf in "$SXMO_NOTIFDIR"/*; do
|
||||
[ -f "$_nf" ] && _cnt=$((_cnt + 1))
|
||||
done
|
||||
sxmo_hook_notifications.sh "$_cnt"
|
||||
}
|
||||
|
||||
monitor() {
|
||||
mkdir -p "$SXMO_NOTIFDIR"
|
||||
mkdir -p "$SXMO_NOTIFDIR"
|
||||
|
||||
find "$SXMO_NOTIFDIR" -type f | while read -r file; do
|
||||
_handle_new_notif_file "$file"
|
||||
done
|
||||
find "$SXMO_NOTIFDIR" -type f 2>/dev/null | while read -r file; do
|
||||
_handle_new_notif_file "$file"
|
||||
done
|
||||
|
||||
_notifications_hook
|
||||
_notifications_hook
|
||||
|
||||
fifo="$(mktemp -u)"
|
||||
mkfifo "$fifo"
|
||||
inotifywait -mq -e attrib,move,delete "$SXMO_NOTIFDIR" >> "$fifo" &
|
||||
inotif_pid=$!
|
||||
fifo="$(mktemp -u)"
|
||||
mkfifo "$fifo"
|
||||
inotifywait -mq -e close_write,moved_to,delete "$SXMO_NOTIFDIR" >> "$fifo" &
|
||||
inotif_pid=$!
|
||||
|
||||
finish() {
|
||||
kill "$inotif_pid"
|
||||
rm "$fifo"
|
||||
exit
|
||||
}
|
||||
trap 'finish' TERM INT EXIT
|
||||
finish() {
|
||||
kill "$inotif_pid" 2>/dev/null || true
|
||||
rm -f "$fifo"
|
||||
exit
|
||||
}
|
||||
trap 'finish' TERM INT EXIT
|
||||
|
||||
while read -r notif_folder notif_type notif_file; do
|
||||
if echo "$notif_type" | grep -qE "CREATE|MOVED_TO|ATTRIB"; then
|
||||
_handle_new_notif_file "$notif_folder$notif_file"
|
||||
fi
|
||||
_notifications_hook
|
||||
done < "$fifo"
|
||||
while read -r notif_folder notif_type notif_file; do
|
||||
if echo "$notif_type" | grep -qE "CLOSE_WRITE|MOVED_TO"; then
|
||||
_handle_new_notif_file "$notif_folder$notif_file"
|
||||
fi
|
||||
_notifications_hook
|
||||
done < "$fifo"
|
||||
|
||||
wait "$inotif_pid"
|
||||
wait "$inotif_pid"
|
||||
}
|
||||
|
||||
_menu_lines() {
|
||||
find "$SXMO_NOTIFDIR" -type f | while read -r file; do
|
||||
msg="$(tail -n+3 "$file" | tr "\n^" " ")"
|
||||
hrandmin="$(stat --printf %y "$file" | grep -oE '[0-9]{2}:[0-9]{2}')"
|
||||
cat <<EOF
|
||||
find "$SXMO_NOTIFDIR" -type f 2>/dev/null | while read -r file; do
|
||||
[ -f "$file" ] || continue
|
||||
msg="$(tail -n+3 "$file" 2>/dev/null | tr "\n^" " ")"
|
||||
hrandmin="$(stat -c %y "$file" 2>/dev/null | grep -oE '[0-9]{2}:[0-9]{2}' | head -n1)"
|
||||
cat <<EOF
|
||||
$hrandmin $msg^$file
|
||||
EOF
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
menu() {
|
||||
choices="$(cat <<EOF
|
||||
$icon_cls Close Menu
|
||||
choices="$(cat <<EOF
|
||||
$icon_del Clear Notifications
|
||||
$(_menu_lines)
|
||||
$icon_cls Close Menu
|
||||
EOF
|
||||
)"
|
||||
)"
|
||||
|
||||
picked="$(
|
||||
printf "%b" "$choices" |
|
||||
cut -d^ -f1 |
|
||||
sxmo_dmenu.sh -i -p "Notifs"
|
||||
)"
|
||||
picked="$(
|
||||
printf "%b" "$choices" |
|
||||
cut -d^ -f1 |
|
||||
sxmo_dmenu.sh -i -p "Notifs"
|
||||
)"
|
||||
|
||||
case "$picked" in
|
||||
"$icon_cls Close Menu"|"")
|
||||
exit
|
||||
;;
|
||||
"$icon_del Clear Notifications")
|
||||
rm "$SXMO_NOTIFDIR"/*
|
||||
# we must update statusbar here because this function depends
|
||||
# on number of files in $SXMO_NOTIFDIR
|
||||
sxmo_hook_statusbar.sh notifications
|
||||
exit
|
||||
;;
|
||||
*)
|
||||
file="$(
|
||||
printf "%b" "$choices" |
|
||||
grep -F "$picked" |
|
||||
cut -d^ -f2
|
||||
)"
|
||||
group="$(awk NR==1 "$file")"
|
||||
action="$(awk NR==2 "$file")"
|
||||
_clear_notif_group "$group"
|
||||
setsid -f sh -c "$action" > /dev/null 2>&1
|
||||
;;
|
||||
esac
|
||||
case "$picked" in
|
||||
"$icon_cls Close Menu"|"")
|
||||
exit
|
||||
;;
|
||||
"$icon_del Clear Notifications")
|
||||
clear_all
|
||||
exit
|
||||
;;
|
||||
*)
|
||||
file="$(
|
||||
printf "%b" "$choices" |
|
||||
grep -F "$picked" |
|
||||
cut -d^ -f2 |
|
||||
head -n1
|
||||
)"
|
||||
if [ -n "$file" ] && [ -f "$file" ]; then
|
||||
group="$(awk NR==1 "$file" 2>/dev/null)"
|
||||
action="$(awk NR==2 "$file" 2>/dev/null)"
|
||||
_clear_notif_group "$group"
|
||||
rm -f "$file" 2>/dev/null || true
|
||||
dunstctl close-all >/dev/null 2>&1 || true
|
||||
sxmo_hook_statusbar.sh notifications >/dev/null 2>&1 || true
|
||||
if [ -n "$action" ] && [ "$action" != "none" ]; then
|
||||
setsid -f sh -c "$action" > /dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
new() {
|
||||
while : ; do
|
||||
case "$1" in
|
||||
-i)
|
||||
id="$2"
|
||||
shift 2
|
||||
;;
|
||||
-g)
|
||||
group="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
while : ; do
|
||||
case "$1" in
|
||||
-i)
|
||||
id="$2"
|
||||
shift 2
|
||||
;;
|
||||
-g)
|
||||
group="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [ "$#" -lt 2 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$id" ]; then
|
||||
id="$(tr -dc 'a-zA-Z0-9' < /dev/urandom 2>/dev/null | head -c 10)"
|
||||
fi
|
||||
if [ -z "$group" ]; then
|
||||
group="$(tr -dc 'a-zA-Z0-9' < /dev/urandom 2>/dev/null | head -c 10)"
|
||||
fi
|
||||
if [ -z "$id" ]; then
|
||||
id="$(tr -dc 'a-zA-Z0-9' < /dev/urandom 2>/dev/null | head -c 10)"
|
||||
fi
|
||||
if [ -z "$group" ]; then
|
||||
group="$(tr -dc 'a-zA-Z0-9' < /dev/urandom 2>/dev/null | head -c 10)"
|
||||
fi
|
||||
|
||||
action="$1"
|
||||
msg="$2"
|
||||
action="$1"
|
||||
msg="$2"
|
||||
|
||||
touch "$SXMO_NOTIFDIR/$id"
|
||||
printf "%s\n%s\n%b\n" "$group" "$action" "$msg" > "$SXMO_NOTIFDIR/$id"
|
||||
mkdir -p "$SXMO_NOTIFDIR"
|
||||
printf "%s\n%s\n%b\n" "$group" "$action" "$msg" > "$SXMO_NOTIFDIR/$id"
|
||||
|
||||
sxmo_hook_statusbar.sh notifications
|
||||
sxmo_hook_statusbar.sh notifications
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
cat <<EOF
|
||||
$(basename "$0"): manage sxmo notifications
|
||||
|
||||
Subcommands:
|
||||
monitor
|
||||
Watch for new notification, dispatch libnotify events, handle actions
|
||||
menu
|
||||
Open a menu to dismiss notifications
|
||||
new [-i id] [-g group] <action> <message...>
|
||||
Register a new notification
|
||||
monitor
|
||||
Watch for new notification, dispatch libnotify events, handle actions
|
||||
menu
|
||||
Open a menu to dismiss notifications
|
||||
clear
|
||||
Clear all notifications and close active Dunst popups
|
||||
new [-i id] [-g group] <action> <message...>
|
||||
Register a new notification
|
||||
EOF
|
||||
}
|
||||
|
||||
cmd="$1"
|
||||
shift
|
||||
shift 2>/dev/null || true
|
||||
case "$cmd" in
|
||||
monitor) monitor "$@";;
|
||||
menu) menu "$@";;
|
||||
new) new "$@";;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
monitor) monitor "$@" ;;
|
||||
menu) menu "$@" ;;
|
||||
clear) clear_all ;;
|
||||
new) new "$@" ;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
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.
Binary file not shown.
@@ -8,7 +8,7 @@ if [ -r "$CONF_FILE" ]; then
|
||||
. "$CONF_FILE"
|
||||
fi
|
||||
|
||||
SIM_WAIT_TIME="${SIM_WAIT_TIME:-${sim_wait_time:-4}}"
|
||||
SIM_WAIT_TIME="${SIM_WAIT_TIME:-${sim_wait_time:-10}}"
|
||||
PREFERRED_SIM_SLOT="${PREFERRED_SIM_SLOT:-${preferred_sim_slot:-1}}"
|
||||
QMICLI_MODEM=""
|
||||
|
||||
@@ -16,15 +16,25 @@ 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
|
||||
if qmicli --silent -pd qrtr://0 --uim-noop >/dev/null 2>&1; then
|
||||
QMICLI_MODEM="qmicli --silent -pd qrtr://0"
|
||||
return 0
|
||||
elif [ -e "/dev/wwan0qmi0" ]; then
|
||||
if qmicli --silent -pd /dev/wwan0qmi0 --device-open-qmi --uim-noop >/dev/null 2>&1; then
|
||||
QMICLI_MODEM="qmicli --silent -pd /dev/wwan0qmi0 --device-open-qmi"
|
||||
return 0
|
||||
elif qmicli --silent -d /dev/wwan0qmi0 --device-open-qmi --uim-noop >/dev/null 2>&1; then
|
||||
QMICLI_MODEM="qmicli --silent -d /dev/wwan0qmi0 --device-open-qmi"
|
||||
return 0
|
||||
fi
|
||||
elif [ -e "/dev/modem" ]; then
|
||||
if qmicli --silent -pd /dev/modem --uim-noop >/dev/null 2>&1; then
|
||||
QMICLI_MODEM="qmicli --silent -pd /dev/modem"
|
||||
return 0
|
||||
elif qmicli --silent -d /dev/modem --uim-noop >/dev/null 2>&1; then
|
||||
QMICLI_MODEM="qmicli --silent -d /dev/modem"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
@@ -64,6 +74,8 @@ parse_uim_card_status() {
|
||||
pin1_state[s] = "not-initialized"
|
||||
pin1_ret[s] = 0
|
||||
puk1_ret[s] = 0
|
||||
want_aid[s] = 0
|
||||
need_aid_line[s] = 0
|
||||
}
|
||||
}
|
||||
/Primary GW:/ {
|
||||
@@ -95,7 +107,7 @@ parse_uim_card_status() {
|
||||
}
|
||||
if (!in_app && $0 ~ /Card state:/) {
|
||||
line = $0
|
||||
sub(/.*Card state: \x27/, "", line)
|
||||
sub(/.*Card state:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
rawstate[cur_slot] = line
|
||||
if (line == "present") cstate[cur_slot] = "present"
|
||||
@@ -104,25 +116,25 @@ parse_uim_card_status() {
|
||||
}
|
||||
if (!in_app && $0 ~ /UPIN state:/) {
|
||||
line = $0
|
||||
sub(/.*UPIN state: \x27/, "", line)
|
||||
sub(/.*UPIN state:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
upin_state[cur_slot] = line
|
||||
}
|
||||
if (!in_app && $0 ~ /UPIN retries:/) {
|
||||
line = $0
|
||||
sub(/.*UPIN retries: \x27/, "", line)
|
||||
sub(/.*UPIN retries:[[:space:]]*\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(/.*UPUK retries:[[:space:]]*\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(/.*Application type:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
if (line ~ /^usim/) {
|
||||
app_type[cur_slot] = "usim"
|
||||
@@ -130,13 +142,16 @@ parse_uim_card_status() {
|
||||
} else if (line ~ /^sim/ && app_type[cur_slot] != "usim") {
|
||||
app_type[cur_slot] = "sim"
|
||||
want_aid[cur_slot] = 1
|
||||
} else if (app_type[cur_slot] == "none") {
|
||||
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(/.*Application state:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
app_state[cur_slot] = line
|
||||
}
|
||||
@@ -147,26 +162,26 @@ parse_uim_card_status() {
|
||||
if (in_app && need_aid_line[cur_slot] == 1) {
|
||||
line = $0
|
||||
gsub(/^[[:space:]]+|[[:space:]]+$/, "", line)
|
||||
if (line != "") {
|
||||
if (line != "" && line !~ /:.*\x27/) {
|
||||
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(/.*PIN1 state:[[:space:]]*\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(/.*PIN1 retries:[[:space:]]*\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(/.*PUK1 retries:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
puk1_ret[cur_slot] = line + 0
|
||||
}
|
||||
@@ -192,8 +207,116 @@ parse_uim_card_status() {
|
||||
'
|
||||
}
|
||||
|
||||
parse_nas_serving_system() {
|
||||
raw_nas="$1"
|
||||
printf "%s\n" "$raw_nas" | awk '
|
||||
BEGIN {
|
||||
reg_state = "unknown"
|
||||
cs_state = "unknown"
|
||||
ps_state = "unknown"
|
||||
rat = ""
|
||||
mcc = ""
|
||||
mnc = ""
|
||||
op_desc = ""
|
||||
roam = "off"
|
||||
in_rat = 0
|
||||
in_plmn = 0
|
||||
in_roam = 0
|
||||
}
|
||||
/^[[:space:]]*Registration state:/ {
|
||||
line = $0
|
||||
sub(/.*Registration state:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
reg_state = line
|
||||
in_rat = 0; in_plmn = 0; in_roam = 0
|
||||
next
|
||||
}
|
||||
/^[[:space:]]*CS:/ {
|
||||
line = $0
|
||||
sub(/.*CS:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
cs_state = line
|
||||
next
|
||||
}
|
||||
/^[[:space:]]*PS:/ {
|
||||
line = $0
|
||||
sub(/.*PS:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
ps_state = line
|
||||
next
|
||||
}
|
||||
/^[[:space:]]*Radio interfaces:/ {
|
||||
in_rat = 1; in_plmn = 0; in_roam = 0
|
||||
next
|
||||
}
|
||||
/^[[:space:]]*Data service capabilities:/ {
|
||||
in_rat = 0
|
||||
next
|
||||
}
|
||||
/^[[:space:]]*Current PLMN:/ {
|
||||
in_plmn = 1; in_rat = 0; in_roam = 0
|
||||
next
|
||||
}
|
||||
/^[[:space:]]*Roaming indicators:/ {
|
||||
in_roam = 1; in_plmn = 0; in_rat = 0
|
||||
next
|
||||
}
|
||||
/^[[:space:]]*Default roaming status:/ {
|
||||
line = $0
|
||||
sub(/.*Default roaming status:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
roam = line
|
||||
in_roam = 0
|
||||
next
|
||||
}
|
||||
in_rat && /^[[:space:]]*\[[0-9]+\]:/ {
|
||||
line = $0
|
||||
sub(/.*\[[0-9]+\]:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
if (line != "" && line != "none" && rat == "") rat = line
|
||||
}
|
||||
in_plmn && /MCC:/ {
|
||||
line = $0
|
||||
sub(/.*MCC:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
mcc = line
|
||||
}
|
||||
in_plmn && /MNC:/ {
|
||||
line = $0
|
||||
sub(/.*MNC:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
mnc = line
|
||||
}
|
||||
in_plmn && /Description:/ {
|
||||
line = $0
|
||||
sub(/.*Description:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
gsub(/[\r\n\t]/, " ", line)
|
||||
op_desc = line
|
||||
in_plmn = 0
|
||||
}
|
||||
in_roam && /^[[:space:]]*\[[0-9]+\]:/ {
|
||||
line = $0
|
||||
sub(/.*\[[0-9]+\]:[[:space:]]*\x27/, "", line)
|
||||
sub(/\x27.*/, "", line)
|
||||
if (line == "on") roam = "on"
|
||||
}
|
||||
END {
|
||||
printf "NAS_REG_STATE=%s\n", reg_state
|
||||
printf "NAS_CS_STATE=%s\n", cs_state
|
||||
printf "NAS_PS_STATE=%s\n", ps_state
|
||||
printf "NAS_RAT=%s\n", rat
|
||||
printf "NAS_MCC=%s\n", mcc
|
||||
printf "NAS_MNC=%s\n", mnc
|
||||
printf "NAS_OPERATOR=%s\n", op_desc
|
||||
printf "NAS_ROAMING=%s\n", roam
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
save_preferred_slot() {
|
||||
target_slot="$1"
|
||||
PREFERRED_SIM_SLOT="$target_slot"
|
||||
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"
|
||||
@@ -201,7 +324,7 @@ save_preferred_slot() {
|
||||
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"
|
||||
printf "sim_wait_time=10\npreferred_sim_slot=%s\n" "$target_slot" > "$CONF_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -214,52 +337,154 @@ provision_slot() {
|
||||
return 2
|
||||
fi
|
||||
|
||||
$QMICLI_MODEM --dms-set-operating-mode=online >/dev/null 2>&1 || true
|
||||
|
||||
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
|
||||
while : ; do
|
||||
if [ -n "$QMI_CARDS" ]; then
|
||||
eval "$(parse_uim_card_status "$QMI_CARDS" "$req_slot")"
|
||||
if [ "$req_slot" = "2" ] && [ "$SLOT2_STATE" = "present" ] && [ "$SLOT2_APP_TYPE" != "none" ]; then
|
||||
break
|
||||
elif [ "$req_slot" != "2" ] && [ "$SLOT1_STATE" = "present" ] && [ "$SLOT1_APP_TYPE" != "none" ]; then
|
||||
break
|
||||
elif [ "$count" -ge 3 ] && { { [ "$SLOT1_STATE" = "present" ] && [ "$SLOT1_APP_TYPE" != "none" ]; } || { [ "$SLOT2_STATE" = "present" ] && [ "$SLOT2_APP_TYPE" != "none" ]; }; }; then
|
||||
break
|
||||
fi
|
||||
fi
|
||||
if [ "$count" -ge "$SIM_WAIT_TIME" ]; then
|
||||
echo "No SIM detected after $SIM_WAIT_TIME seconds."
|
||||
return 0
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
QMI_CARDS="$($QMICLI_MODEM --uim-get-card-status 2>/dev/null || true)"
|
||||
done
|
||||
|
||||
if [ -z "$QMI_CARDS" ]; then
|
||||
echo "No SIM card status returned."
|
||||
return 0
|
||||
fi
|
||||
|
||||
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
|
||||
if [ "$SLOT2_STATE" = "present" ]; then
|
||||
chosen_slot="2"
|
||||
chosen_aid="$SLOT2_AID"
|
||||
elif [ "$SLOT1_STATE" = "present" ] && [ -n "$SLOT1_AID" ]; then
|
||||
elif [ "$SLOT1_STATE" = "present" ]; then
|
||||
chosen_slot="1"
|
||||
chosen_aid="$SLOT1_AID"
|
||||
fi
|
||||
else
|
||||
if [ "$SLOT1_STATE" = "present" ] && [ -n "$SLOT1_AID" ]; then
|
||||
if [ "$SLOT1_STATE" = "present" ]; then
|
||||
chosen_slot="1"
|
||||
chosen_aid="$SLOT1_AID"
|
||||
elif [ "$SLOT2_STATE" = "present" ] && [ -n "$SLOT2_AID" ]; then
|
||||
elif [ "$SLOT2_STATE" = "present" ]; 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."
|
||||
if [ -z "$chosen_slot" ]; then
|
||||
echo "No SIM detected after $SIM_WAIT_TIME seconds."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$PRIMARY_GW_SLOT" != "0" ]; then
|
||||
if [ "$chosen_slot" != "$PREFERRED_SIM_SLOT" ]; then
|
||||
save_preferred_slot "$chosen_slot"
|
||||
fi
|
||||
|
||||
# If already provisioned on the chosen slot and application is ready, keep session intact
|
||||
eval "chosen_app_state=\$SLOT${chosen_slot}_APP_STATE"
|
||||
if [ "$PRIMARY_GW_SLOT" = "$chosen_slot" ] && [ "$chosen_app_state" = "ready" ]; then
|
||||
echo "Slot $chosen_slot already active and ready."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$PRIMARY_GW_SLOT" != "0" ] && [ "$PRIMARY_GW_SLOT" != "$chosen_slot" ]; 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 $?
|
||||
if [ -n "$chosen_aid" ]; then
|
||||
echo "Selecting AID $chosen_aid on slot $chosen_slot"
|
||||
if ! $QMICLI_MODEM --uim-change-provisioning-session="slot=$chosen_slot,activate=yes,session-type=primary-gw-provisioning,aid=$chosen_aid" >/dev/null 2>&1; then
|
||||
$QMICLI_MODEM --uim-change-provisioning-session="slot=$chosen_slot,activate=yes,session-type=primary-gw-provisioning" >/dev/null 2>&1 || true
|
||||
fi
|
||||
else
|
||||
echo "Selecting slot $chosen_slot"
|
||||
$QMICLI_MODEM --uim-change-provisioning-session="slot=$chosen_slot,activate=yes,session-type=primary-gw-provisioning" >/dev/null 2>&1 || true
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
enable_and_register_modem() {
|
||||
target_slot="${1:-$PREFERRED_SIM_SLOT}"
|
||||
if detect_qmicli_modem; then
|
||||
$QMICLI_MODEM --dms-set-operating-mode=online >/dev/null 2>&1 || true
|
||||
$QMICLI_MODEM --nas-initiate-network-register >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
i=0
|
||||
mm_state=""
|
||||
while [ "$i" -lt 12 ]; do
|
||||
mm_state="$(mmcli -m any -K 2>/dev/null | awk -F': ' '/^modem\.generic\.state / {print $2; exit}' || true)"
|
||||
if [ -n "$mm_state" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
if [ "$mm_state" = "failed" ]; then
|
||||
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
|
||||
i=0
|
||||
mm_state=""
|
||||
while [ "$i" -lt 12 ]; do
|
||||
mm_state="$(mmcli -m any -K 2>/dev/null | awk -F': ' '/^modem\.generic\.state / {print $2; exit}' || true)"
|
||||
if [ -n "$mm_state" ] && [ "$mm_state" != "failed" ]; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$mm_state" ] || [ "$mm_state" = "locked" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=0
|
||||
while [ "$i" -lt 10 ]; do
|
||||
mm_state="$(mmcli -m any -K 2>/dev/null | awk -F': ' '/^modem\.generic\.state / {print $2; exit}' || true)"
|
||||
case "$mm_state" in
|
||||
disabled)
|
||||
mmcli -m any -e >/dev/null 2>&1 || true
|
||||
;;
|
||||
enabled)
|
||||
mmcli -m any --3gpp-register-home >/dev/null 2>&1 || true
|
||||
break
|
||||
;;
|
||||
searching|registered|connected|connecting)
|
||||
break
|
||||
;;
|
||||
locked)
|
||||
break
|
||||
;;
|
||||
esac
|
||||
sleep 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
mmcli -m any --3gpp-register-home >/dev/null 2>&1 || true
|
||||
if command -v sxmo_hook_statusbar.sh >/dev/null 2>&1; then
|
||||
DISPLAY="${DISPLAY:-:0}" sxmo_hook_statusbar.sh modem >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
cmd="${1:-boot}"
|
||||
@@ -276,7 +501,8 @@ case "$cmd" in
|
||||
;;
|
||||
esac
|
||||
provision_slot "$PREFERRED_SIM_SLOT" 45
|
||||
exit $?
|
||||
( enable_and_register_modem "$PREFERRED_SIM_SLOT" ) >/dev/null 2>&1 </dev/null &
|
||||
exit 0
|
||||
;;
|
||||
|
||||
status)
|
||||
@@ -293,6 +519,10 @@ case "$cmd" in
|
||||
fi
|
||||
echo "MODEM_AVAILABLE=1"
|
||||
parse_uim_card_status "$QMI_CARDS" "$PREFERRED_SIM_SLOT"
|
||||
QMI_NAS="$($QMICLI_MODEM --nas-get-serving-system 2>/dev/null || true)"
|
||||
if [ -n "$QMI_NAS" ]; then
|
||||
parse_nas_serving_system "$QMI_NAS"
|
||||
fi
|
||||
exit 0
|
||||
;;
|
||||
|
||||
@@ -303,13 +533,14 @@ case "$cmd" in
|
||||
exit 1
|
||||
fi
|
||||
save_preferred_slot "$target"
|
||||
SIM_WAIT_TIME=2
|
||||
SIM_WAIT_TIME=3
|
||||
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
|
||||
( enable_and_register_modem "$target" ) >/dev/null 2>&1 </dev/null &
|
||||
exit 0
|
||||
;;
|
||||
|
||||
@@ -320,18 +551,27 @@ case "$cmd" in
|
||||
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
|
||||
verified=0
|
||||
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
|
||||
verified=1
|
||||
elif $QMICLI_MODEM --uim-verify-pin="PIN1,$pin,session-type=primary-gw-provisioning" >/dev/null 2>&1; then
|
||||
verified=1
|
||||
fi
|
||||
fi
|
||||
if [ "$verified" = "0" ]; then
|
||||
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
|
||||
verified=1
|
||||
fi
|
||||
fi
|
||||
if [ "$verified" = "1" ]; then
|
||||
save_preferred_slot "$slot"
|
||||
SIM_WAIT_TIME=2
|
||||
provision_slot "$slot" 3 >/dev/null 2>&1 || true
|
||||
( enable_and_register_modem "$slot" ) >/dev/null 2>&1 </dev/null &
|
||||
exit 0
|
||||
fi
|
||||
exit 1
|
||||
;;
|
||||
|
||||
@@ -343,18 +583,27 @@ case "$cmd" in
|
||||
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
|
||||
unblocked=0
|
||||
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
|
||||
unblocked=1
|
||||
elif $QMICLI_MODEM --uim-unblock-pin="PIN1,$puk,$newpin,session-type=primary-gw-provisioning" >/dev/null 2>&1; then
|
||||
unblocked=1
|
||||
fi
|
||||
fi
|
||||
if [ "$unblocked" = "0" ]; then
|
||||
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
|
||||
unblocked=1
|
||||
fi
|
||||
fi
|
||||
if [ "$unblocked" = "1" ]; then
|
||||
save_preferred_slot "$slot"
|
||||
SIM_WAIT_TIME=2
|
||||
provision_slot "$slot" 3 >/dev/null 2>&1 || true
|
||||
( enable_and_register_modem "$slot" ) >/dev/null 2>&1 </dev/null &
|
||||
exit 0
|
||||
fi
|
||||
exit 1
|
||||
;;
|
||||
|
||||
@@ -366,6 +615,14 @@ case "$cmd" in
|
||||
echo "Usage: $0 set-pin-lock <1|2> <enable|disable> <pin>" >&2
|
||||
exit 1
|
||||
fi
|
||||
if detect_qmicli_modem; then
|
||||
if $QMICLI_MODEM --uim-set-pin-protection="PIN1,$mode,$pin,session-type=card-slot-$slot" >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
if $QMICLI_MODEM --uim-set-pin-protection="PIN1,$mode,$pin,session-type=primary-gw-provisioning" >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
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
|
||||
@@ -374,14 +631,6 @@ case "$cmd" in
|
||||
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
|
||||
;;
|
||||
|
||||
@@ -393,17 +642,17 @@ case "$cmd" in
|
||||
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
|
||||
if $QMICLI_MODEM --uim-change-pin="PIN1,$oldpin,$newpin,session-type=primary-gw-provisioning" >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
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
|
||||
exit 1
|
||||
;;
|
||||
@@ -505,7 +754,12 @@ case "$cmd" in
|
||||
exit 1
|
||||
fi
|
||||
resp=""
|
||||
for candidate in "$port" /dev/wwan0at1 /dev/wwan0at0; do
|
||||
if [ "$PREFERRED_SIM_SLOT" = "2" ]; then
|
||||
at_candidates="$port /dev/wwan0at1 /dev/wwan0at0"
|
||||
else
|
||||
at_candidates="$port /dev/wwan0at0 /dev/wwan0at1"
|
||||
fi
|
||||
for candidate in $at_candidates; do
|
||||
case "$candidate" in
|
||||
wwan0at0|wwan0at1)
|
||||
dev="/dev/$candidate"
|
||||
@@ -518,7 +772,7 @@ case "$cmd" in
|
||||
;;
|
||||
esac
|
||||
if [ -n "$dev" ] && [ -c "$dev" ]; then
|
||||
resp="$(timeout 2 sh -c '
|
||||
resp="$(timeout 3 sh -c '
|
||||
dev="$1"
|
||||
cmd="$2"
|
||||
tmpf="/tmp/at_resp_$$.txt"
|
||||
@@ -528,7 +782,7 @@ case "$cmd" in
|
||||
sleep 0.04
|
||||
printf "%s\r\n" "$cmd" > "$dev" 2>/dev/null || true
|
||||
i=0
|
||||
while [ "$i" -lt 12 ]; do
|
||||
while [ "$i" -lt 16 ]; do
|
||||
if grep -qE "(^|[[:space:]])(OK|ERROR|\+CME ERROR|\+CMS ERROR)([[:space:]]|$)" "$tmpf" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
@@ -558,6 +812,84 @@ case "$cmd" in
|
||||
exit 1
|
||||
;;
|
||||
|
||||
ussd)
|
||||
ussd_mode="${2:-initiate}"
|
||||
shift 2 2>/dev/null || true
|
||||
ussd_code="$*"
|
||||
if [ "$ussd_mode" = "cancel" ]; then
|
||||
mmcli -m any --3gpp-ussd-cancel >/dev/null 2>&1 || true
|
||||
"$0" at auto 'AT+CUSD=2' >/dev/null 2>&1 || true
|
||||
echo "USSD session cancelled."
|
||||
exit 0
|
||||
fi
|
||||
if [ -z "$ussd_code" ]; then
|
||||
echo "ERROR: Empty USSD code"
|
||||
exit 1
|
||||
fi
|
||||
mm_state="$(mmcli -m any -K 2>/dev/null | awk -F': ' '$1 == "modem.generic.state" {print $2; exit}')"
|
||||
if [ "$mm_state" = "disabled" ] || [ -z "$mm_state" ]; then
|
||||
mmcli -m any -e >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
fi
|
||||
if [ "$ussd_mode" = "respond" ]; then
|
||||
mm_out="$(mmcli -m any --3gpp-ussd-respond="$ussd_code" 2>&1)"
|
||||
mm_rc=$?
|
||||
else
|
||||
mmcli -m any --3gpp-ussd-cancel >/dev/null 2>&1 || true
|
||||
mm_out="$(mmcli -m any --3gpp-ussd-initiate="$ussd_code" 2>&1)"
|
||||
mm_rc=$?
|
||||
fi
|
||||
if [ "$mm_rc" -eq 0 ] && [ -n "$mm_out" ]; then
|
||||
printf "%s\n" "$mm_out" | sed -e "s/^USSD session initiated; new reply from network: '\(.*\)'$/\1/" -e "s/^USSD response sent; new reply from network: '\(.*\)'$/\1/"
|
||||
exit 0
|
||||
fi
|
||||
# Fallback to direct AT+CUSD on the active SIM AT port
|
||||
if [ "$PREFERRED_SIM_SLOT" = "2" ]; then
|
||||
at_candidates="/dev/wwan0at1 /dev/wwan0at0"
|
||||
else
|
||||
at_candidates="/dev/wwan0at0 /dev/wwan0at1"
|
||||
fi
|
||||
for dev in $at_candidates; do
|
||||
[ -c "$dev" ] || continue
|
||||
cusd_out="$(timeout 12 sh -c '
|
||||
dev="$1"
|
||||
code="$2"
|
||||
tmpf="/tmp/ussd_resp_$$.txt"
|
||||
rm -f "$tmpf"
|
||||
cat "$dev" > "$tmpf" 2>/dev/null &
|
||||
rpid=$!
|
||||
sleep 0.05
|
||||
printf "AT+CSCS=\"GSM\";+CUSD=1,\"%s\",15\r\n" "$code" > "$dev" 2>/dev/null || true
|
||||
i=0
|
||||
while [ "$i" -lt 80 ]; do
|
||||
if grep -qE "\+CUSD:[[:space:]]*[0-9]+" "$tmpf" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
if grep -qE "(^|[[:space:]])(\+CME ERROR|\+CMS ERROR|ERROR)([[:space:]]|$)" "$tmpf" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
i=$((i + 1))
|
||||
done
|
||||
kill "$rpid" 2>/dev/null || true
|
||||
wait "$rpid" 2>/dev/null || true
|
||||
tr -d "\r" < "$tmpf" 2>/dev/null || true
|
||||
rm -f "$tmpf"
|
||||
' _ "$dev" "$ussd_code" 2>/dev/null || true)"
|
||||
cusd_msg="$(printf "%s\n" "$cusd_out" | sed -n 's/.*+CUSD:[[:space:]]*[0-9]*,[[:space:]]*"\([^"]*\)".*/\1/p' | tail -n1)"
|
||||
if [ -n "$cusd_msg" ]; then
|
||||
printf "%s\n" "$cusd_msg"
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
if [ -n "$mm_out" ]; then
|
||||
printf "%s\n" "$mm_out"
|
||||
else
|
||||
echo "ERROR: USSD request failed"
|
||||
fi
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sim-contacts-import)
|
||||
req_slot="${2:-auto}"
|
||||
if ! wait_for_qmicli_modem 3; then
|
||||
@@ -688,8 +1020,8 @@ case "$cmd" in
|
||||
# Method 2: Direct QMI UIM EF_ADN (3F00:7F10:6F3A) record fallback
|
||||
if [ ! -s "$tmp_contacts" ]; then
|
||||
adn_attr="$($QMICLI_MODEM --uim-get-file-attributes=0x3F00,0x7F10,0x6F3A 2>/dev/null || true)"
|
||||
reclen="$(printf "%s\n" "$adn_attr" | awk -F"'" '/Record length:/ {print $2 + 0; exit}')"
|
||||
reccount="$(printf "%s\n" "$adn_attr" | awk -F"'" '/Record count:/ {print $2 + 0; exit}')"
|
||||
reclen="$(printf "%s\n" "$adn_attr" | awk '/Record (size|length):/ {gsub(/[^0-9]/, "", $NF); print $NF + 0; exit}')"
|
||||
reccount="$(printf "%s\n" "$adn_attr" | awk '/Record count:/ {gsub(/[^0-9]/, "", $NF); print $NF + 0; exit}')"
|
||||
if [ -n "$reclen" ] && [ -n "$reccount" ] && [ "$reclen" -ge 14 ] 2>/dev/null && [ "$reccount" -ge 1 ] 2>/dev/null; then
|
||||
if [ "$reccount" -gt 250 ]; then
|
||||
reccount=250
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
horizontal_padding = 6
|
||||
frame_width = 2
|
||||
frame_color = "#005577"
|
||||
idle_threshold = 120
|
||||
idle_threshold = 0
|
||||
font = Fira Code 9.5
|
||||
markup = full
|
||||
max_icon_size = 24
|
||||
@@ -22,16 +22,16 @@
|
||||
[urgency_low]
|
||||
background = "#222222"
|
||||
foreground = "#cccccc"
|
||||
timeout = 8
|
||||
timeout = 5
|
||||
|
||||
[urgency_normal]
|
||||
background = "#1c1c1c"
|
||||
foreground = "#ffffff"
|
||||
frame_color = "#005577"
|
||||
timeout = 12
|
||||
timeout = 8
|
||||
|
||||
[urgency_critical]
|
||||
background = "#900000"
|
||||
foreground = "#ffffff"
|
||||
frame_color = "#ff0000"
|
||||
timeout = 0
|
||||
timeout = 10
|
||||
|
||||
@@ -15,22 +15,68 @@ newstate="$2"
|
||||
|
||||
sxmo_debug "$2 (old: $1 [reason: $3])"
|
||||
|
||||
case "$newstate" in
|
||||
"locked")
|
||||
sxmo_log "State is locked. Opening SIM PIN/PUK unlock dialog."
|
||||
open_sim_unlock_ui() {
|
||||
(
|
||||
i=0
|
||||
while [ "$i" -lt 40 ] && [ ! -p /tmp/dwm_plugin_modem.fifo ]; do
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
if command -v xmodem >/dev/null 2>&1; then
|
||||
xmodem unlock >/dev/null 2>&1 &
|
||||
DISPLAY="${DISPLAY:-:0}" xmodem unlock >/dev/null 2>&1 &
|
||||
elif ! pgrep -f "sxmo_unlocksim.sh" >/dev/null; then
|
||||
sxmo_unlocksim.sh &
|
||||
fi
|
||||
) &
|
||||
}
|
||||
|
||||
case "$newstate" in
|
||||
"locked")
|
||||
sxmo_log "State is locked. Opening SIM PIN/PUK unlock dialog."
|
||||
open_sim_unlock_ui
|
||||
;;
|
||||
"failed")
|
||||
sxmo_log "State is failed. Checking QMI UIM status for SIM2/PIN lock."
|
||||
(
|
||||
uim_st="$(doas -n /usr/libexec/msm-modem-uim-selection status 2>/dev/null || /usr/libexec/msm-modem-uim-selection status 2>/dev/null || true)"
|
||||
if printf "%s\n" "$uim_st" | grep -qE "SLOT[12]_PIN1_STATE=(enabled-not-verified|blocked)|SLOT[12]_APP_STATE=(pin1|puk1)"; then
|
||||
sxmo_log "QMI UIM reports locked SIM while ModemManager state is failed; opening unlock UI."
|
||||
open_sim_unlock_ui
|
||||
elif printf "%s\n" "$uim_st" | grep -qE "SLOT[12]_STATE=present" && printf "%s\n" "$uim_st" | grep -q "^PRIMARY_GW_SLOT=0$"; then
|
||||
now_ts="$(date +%s 2>/dev/null || echo 0)"
|
||||
last_ts="$(cat /tmp/sxmo_modem_reprov.stamp 2>/dev/null || echo 0)"
|
||||
if [ $((now_ts - last_ts)) -ge 25 ]; then
|
||||
echo "$now_ts" > /tmp/sxmo_modem_reprov.stamp
|
||||
sxmo_log "Unprovisioned SIM detected in failed state; running msm-modem-uim-selection boot."
|
||||
doas -n /usr/libexec/msm-modem-uim-selection boot >/dev/null 2>&1 || true
|
||||
sxmo_hook_statusbar.sh modem >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
) &
|
||||
;;
|
||||
"disabled")
|
||||
sxmo_log "State is disabled. Enabling modem and registering on network."
|
||||
(
|
||||
mmcli -m any -e >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
mmcli -m any --3gpp-register-home >/dev/null 2>&1 || true
|
||||
sxmo_hook_statusbar.sh modem >/dev/null 2>&1 || true
|
||||
) &
|
||||
;;
|
||||
"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."
|
||||
"enabled")
|
||||
sxmo_log "State is enabled. Requesting 3GPP network registration."
|
||||
(
|
||||
mmcli -m any --3gpp-register-home >/dev/null 2>&1 || true
|
||||
sxmo_hook_statusbar.sh modem >/dev/null 2>&1 || true
|
||||
) &
|
||||
;;
|
||||
"registered"|"connected")
|
||||
sxmo_log "State is $newstate. Checking for calls and messages."
|
||||
|
||||
# kill the pin-entry dmenu if still open
|
||||
pkill -f sxmo_unlocksim.sh 2>/dev/null || true
|
||||
|
||||
@@ -59,6 +59,13 @@ set_modem() {
|
||||
MODEMSTATE="$(printf %s "$MMCLI" | jq -r .modem.generic.state)"
|
||||
fi
|
||||
|
||||
if [ "$MODEMSTATE" = "failed" ] || [ "$MODEMSTATE" = "nomodem" ]; then
|
||||
uim_st="$(doas -n /usr/libexec/msm-modem-uim-selection status 2>/dev/null || /usr/libexec/msm-modem-uim-selection status 2>/dev/null || true)"
|
||||
if printf "%s\n" "$uim_st" | grep -qE "SLOT[12]_PIN1_STATE=(enabled-not-verified|blocked)|SLOT[12]_APP_STATE=(pin1|puk1)"; then
|
||||
MODEMSTATE="locked"
|
||||
fi
|
||||
fi
|
||||
|
||||
case "$MODEMSTATE" in
|
||||
nomodem)
|
||||
fgcolor=red
|
||||
@@ -119,7 +126,7 @@ set_modem() {
|
||||
sxmobar -a -f "$fgcolor" -b "$bgcolor" -t "$style" \
|
||||
modem-state 10 "$MODEMSTATECMP"
|
||||
|
||||
if [ "$MODEMSTATE" = nomodem ]; then
|
||||
if [ "$MODEMSTATE" = nomodem ] || [ "$MODEMSTATE" = locked ] || [ "$MODEMSTATE" = failed ] || [ "$MODEMSTATE" = unknown ]; then
|
||||
sxmobar -d modem-tech
|
||||
sxmobar -d modem-signal
|
||||
return
|
||||
@@ -131,7 +138,7 @@ set_modem() {
|
||||
style=normal
|
||||
|
||||
# see https://www.freedesktop.org/software/ModemManager/api/latest/ModemManager-Flags-and-Enumerations.html#MMModemAccessTechnology
|
||||
USEDTECHS="$(printf %s "$MMCLI" | jq -r '.modem.generic."access-technologies"[]')"
|
||||
USEDTECHS="$(printf %s "$MMCLI" | jq -r '.modem.generic."access-technologies"[]? // empty' 2>/dev/null)"
|
||||
case "$USEDTECHS" in
|
||||
*5gnr*)
|
||||
MODEMTECHCMP="$icon_modem_fiveg"
|
||||
@@ -178,7 +185,10 @@ set_modem() {
|
||||
|
||||
case "$MODEMSTATE" in
|
||||
registered|connected|connecting|disconnecting)
|
||||
MODEMSIGNAL="$(printf %s "$MMCLI" | jq -r '.modem.generic."signal-quality".value')"
|
||||
MODEMSIGNAL="$(printf %s "$MMCLI" | jq -r '.modem.generic."signal-quality".value // 0' 2>/dev/null)"
|
||||
case "$MODEMSIGNAL" in
|
||||
''|*[!0-9]*) MODEMSIGNAL=0 ;;
|
||||
esac
|
||||
if [ "$MODEMSIGNAL" -lt 33 ]; then
|
||||
MODEMSIGNALCMP="$icon_modem_signal_1"
|
||||
elif [ "$MODEMSIGNAL" -lt 66 ]; then
|
||||
|
||||
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.
Binary file not shown.
@@ -62,12 +62,15 @@ struct SimSlotInfo {
|
||||
|
||||
bool needsPin() const {
|
||||
return state == "present" &&
|
||||
(pin1State == "enabled-not-verified" || appState == "pin1");
|
||||
(pin1State == "enabled-not-verified" ||
|
||||
appState.rfind("pin1", 0) == 0);
|
||||
}
|
||||
|
||||
bool needsPuk() const {
|
||||
return state == "present" &&
|
||||
(pin1State == "blocked" || appState == "puk1");
|
||||
(pin1State == "blocked" ||
|
||||
appState.rfind("puk1", 0) == 0 ||
|
||||
appState == "pin1-blocked");
|
||||
}
|
||||
|
||||
bool isPinEnabled() const {
|
||||
@@ -88,6 +91,13 @@ struct ModemStatusData {
|
||||
std::string mmFailedReason;
|
||||
std::string mmPowerState = "off";
|
||||
std::string mmUnlockRequired;
|
||||
std::string mmRegState;
|
||||
std::string nasRegState;
|
||||
std::string nasOperator;
|
||||
std::string nasMcc;
|
||||
std::string nasMnc;
|
||||
std::string nasRoaming;
|
||||
std::string nasRadio;
|
||||
int mmPinRetries = -1;
|
||||
int mmPukRetries = -1;
|
||||
std::string operatorName;
|
||||
@@ -103,6 +113,56 @@ struct ModemStatusData {
|
||||
std::string simOperatorName;
|
||||
std::string currentModes;
|
||||
int modePresetIdx = 0;
|
||||
|
||||
bool isNetworkRegistered() const {
|
||||
return mmRegState == "home" || mmRegState == "roaming" ||
|
||||
nasRegState == "registered" ||
|
||||
mmState == "registered" || mmState == "connected";
|
||||
}
|
||||
|
||||
bool isNetworkSearching() const {
|
||||
return mmRegState == "searching" || nasRegState == "searching" ||
|
||||
mmState == "searching" || mmState == "enabling" ||
|
||||
mmState == "connecting";
|
||||
}
|
||||
|
||||
std::string regStatusLabel() const {
|
||||
if (slots[0].needsPuk() || slots[1].needsPuk() ||
|
||||
mmUnlockRequired == "sim-puk") {
|
||||
return "SIM PUK Required";
|
||||
}
|
||||
if (slots[0].needsPin() || slots[1].needsPin() ||
|
||||
mmUnlockRequired == "sim-pin" || mmState == "locked") {
|
||||
return "SIM PIN Required";
|
||||
}
|
||||
if (mmRegState == "home" ||
|
||||
(nasRegState == "registered" && nasRoaming != "on")) {
|
||||
return "Registered (Home)";
|
||||
}
|
||||
if (mmRegState == "roaming" ||
|
||||
(nasRegState == "registered" && nasRoaming == "on")) {
|
||||
return "Registered (Roaming)";
|
||||
}
|
||||
if (mmState == "connected" || mmState == "registered") {
|
||||
return "Registered";
|
||||
}
|
||||
if (isNetworkSearching()) {
|
||||
return "Searching...";
|
||||
}
|
||||
if (mmRegState == "denied" || nasRegState == "registration-denied") {
|
||||
return "Registration Denied";
|
||||
}
|
||||
if (slots[0].state != "present" && slots[1].state != "present") {
|
||||
return "No SIM Inserted";
|
||||
}
|
||||
if (primaryGwSlot == 0) {
|
||||
return "SIM Not Activated";
|
||||
}
|
||||
if (mmState == "disabled") {
|
||||
return "Modem Disabled";
|
||||
}
|
||||
return "Not Registered";
|
||||
}
|
||||
};
|
||||
|
||||
struct RadioModePreset {
|
||||
@@ -201,6 +261,12 @@ ModemStatusData queryModemAndSimStatus() {
|
||||
if (!uimKv["PRIMARY_GW_SLOT"].empty()) {
|
||||
d.primaryGwSlot = std::atoi(uimKv["PRIMARY_GW_SLOT"].c_str());
|
||||
}
|
||||
d.nasRegState = uimKv["NAS_REG_STATE"];
|
||||
d.nasOperator = uimKv["NAS_OPERATOR"];
|
||||
d.nasMcc = uimKv["NAS_MCC"];
|
||||
d.nasMnc = uimKv["NAS_MNC"];
|
||||
d.nasRoaming = uimKv["NAS_ROAMING"];
|
||||
d.nasRadio = uimKv["NAS_RADIO"];
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
std::string pfx = "SLOT" + std::to_string(i + 1) + "_";
|
||||
@@ -244,6 +310,7 @@ ModemStatusData queryModemAndSimStatus() {
|
||||
d.mmFailedReason = cleanMmVal(mmKv["modem.generic.state-failed-reason"]);
|
||||
d.mmPowerState = cleanMmVal(mmKv["modem.generic.power-state"]);
|
||||
d.mmUnlockRequired = cleanMmVal(mmKv["modem.generic.unlock-required"]);
|
||||
d.mmRegState = cleanMmVal(mmKv["modem.3gpp.registration-state"]);
|
||||
d.operatorName = cleanMmVal(mmKv["modem.3gpp.operator-name"]);
|
||||
d.operatorCode = cleanMmVal(mmKv["modem.3gpp.operator-code"]);
|
||||
d.accessTech = cleanMmVal(mmKv["modem.generic.access-technologies.value[1]"]);
|
||||
@@ -309,6 +376,16 @@ ModemStatusData queryModemAndSimStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
if (d.operatorName.empty() && !d.nasOperator.empty()) {
|
||||
d.operatorName = d.nasOperator;
|
||||
}
|
||||
if (d.operatorCode.empty() && !d.nasMcc.empty() && !d.nasMnc.empty()) {
|
||||
d.operatorCode = d.nasMcc + d.nasMnc;
|
||||
}
|
||||
if (d.accessTech.empty() && !d.nasRadio.empty() && d.nasRadio != "none") {
|
||||
d.accessTech = d.nasRadio;
|
||||
}
|
||||
|
||||
// Sync ModemManager lock info into active slot if QMI didn't report retries
|
||||
int actIdx = (d.primaryGwSlot >= 1 && d.primaryGwSlot <= 2)
|
||||
? (d.primaryGwSlot - 1)
|
||||
@@ -395,8 +472,8 @@ int runModemApp(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
writeIntFile(daemonPidPath, static_cast<int>(::getpid()));
|
||||
int fifoFd = setupPluginDaemonFifo("modem");
|
||||
writeIntFile(daemonPidPath, static_cast<int>(::getpid()));
|
||||
|
||||
struct sigaction sa {};
|
||||
sa.sa_handler = handleSignal;
|
||||
@@ -702,10 +779,24 @@ int runModemApp(int argc, char** argv) {
|
||||
line2 = "LOCKED (Enter PIN)";
|
||||
line2Col = &colOrange;
|
||||
} else if (s.isActiveProvisioned) {
|
||||
std::string op = status.operatorName.empty() ? "Ready" : status.operatorName;
|
||||
if (!status.ownNumber.empty()) op += " " + status.ownNumber;
|
||||
line2 = op;
|
||||
line2Col = &colGreen;
|
||||
std::string reg = status.regStatusLabel();
|
||||
if (!status.operatorName.empty()) {
|
||||
reg += " - " + status.operatorName;
|
||||
}
|
||||
if (!status.accessTech.empty()) {
|
||||
reg += " [" + status.accessTech + "]";
|
||||
}
|
||||
line2 = reg;
|
||||
if (status.isNetworkRegistered()) {
|
||||
line2Col = &colGreen;
|
||||
} else if (status.isNetworkSearching()) {
|
||||
line2Col = &colOrange;
|
||||
} else {
|
||||
line2Col = &colRed;
|
||||
}
|
||||
} else if (status.primaryGwSlot == 0) {
|
||||
line2 = "Present (Unactivated - Press Select)";
|
||||
line2Col = &colOrange;
|
||||
} else {
|
||||
line2 = "Present (Standby " + s.appType + ")";
|
||||
line2Col = &colBlue;
|
||||
@@ -726,6 +817,9 @@ int runModemApp(int argc, char** argv) {
|
||||
else if (pState == "blocked") pState = "PUK Req";
|
||||
line3 = pState + " (PIN:" + std::to_string(s.pin1Retries) +
|
||||
" PUK:" + std::to_string(s.puk1Retries) + ")";
|
||||
if (s.isActiveProvisioned && !status.ownNumber.empty()) {
|
||||
line3 += " " + status.ownNumber;
|
||||
}
|
||||
} else {
|
||||
line3 = "Insert nano-SIM & restart/switch";
|
||||
}
|
||||
@@ -736,8 +830,18 @@ int runModemApp(int argc, char** argv) {
|
||||
// Quick Action Rows below the 2 SIM cards (4 rows, 24px each)
|
||||
int actSlot = (simRowSel == 1) ? 2 : 1;
|
||||
int otherSlot = (status.preferredSlot == 1) ? 2 : 1;
|
||||
if (status.primaryGwSlot == 0) {
|
||||
if (status.slots[1].state == "present" && status.slots[0].state != "present") {
|
||||
otherSlot = 2;
|
||||
} else if (status.slots[0].state == "present" && status.slots[1].state != "present") {
|
||||
otherSlot = 1;
|
||||
}
|
||||
}
|
||||
std::string quickRows[4] = {
|
||||
std::string(kIconRefresh) + " Switch Active to SIM " + std::to_string(otherSlot),
|
||||
std::string(kIconRefresh) +
|
||||
(status.primaryGwSlot == 0
|
||||
? (" Activate SIM " + std::to_string(otherSlot))
|
||||
: (" Switch Active to SIM " + std::to_string(otherSlot))),
|
||||
std::string(kIconUnlock) + " Unlock SIM (PIN / PUK)",
|
||||
std::string(kIconLock) + " Enable / Disable SIM PIN",
|
||||
std::string(kIconKey) + " Change SIM PIN Code",
|
||||
@@ -762,29 +866,31 @@ int runModemApp(int argc, char** argv) {
|
||||
XSetForeground(dpy, gc, pt.spec.border);
|
||||
XDrawRectangle(dpy, pix, gc, 4, contentY, kWinWidth - 9, 101);
|
||||
|
||||
std::string stStr = status.mmPresent ? status.mmState : "nomodem";
|
||||
if (!status.mmFailedReason.empty()) {
|
||||
stStr += " (" + status.mmFailedReason + ")";
|
||||
}
|
||||
std::string regStr = status.regStatusLabel();
|
||||
XftColor* stCol = &colRed;
|
||||
if (status.mmState == "connected" || status.mmState == "registered") {
|
||||
if (status.isNetworkRegistered()) {
|
||||
stCol = &colGreen;
|
||||
} else if (status.mmState == "searching" || status.mmState == "connecting") {
|
||||
} else if (status.isNetworkSearching()) {
|
||||
stCol = &colOrange;
|
||||
}
|
||||
drawPango(layoutMain, stCol, 10, contentY + 2, 22,
|
||||
"State: " + stStr, 185);
|
||||
"Net: " + regStr, 185);
|
||||
drawSignalBars(kWinWidth - 32, contentY + 6, status.signalQuality);
|
||||
|
||||
std::string opLine = "Operator: " +
|
||||
(status.operatorName.empty() ? "--" : status.operatorName);
|
||||
if (!status.operatorCode.empty() &&
|
||||
status.operatorName != status.operatorCode) {
|
||||
opLine += " (" + status.operatorCode + ")";
|
||||
}
|
||||
if (!status.accessTech.empty()) {
|
||||
opLine += " [" + status.accessTech + "]";
|
||||
}
|
||||
drawPango(layoutSmall, &colLight, 10, contentY + 24, 18, opLine, 220);
|
||||
|
||||
std::string sigLine = "Signal: " + std::to_string(status.signalQuality) +
|
||||
"% | Slot: SIM " +
|
||||
std::string stStr = status.mmPresent ? status.mmState : "nomodem";
|
||||
std::string sigLine = "Modem: " + stStr + " | Sig: " +
|
||||
std::to_string(status.signalQuality) + "% | SIM " +
|
||||
(status.primaryGwSlot > 0 ? std::to_string(status.primaryGwSlot) : "--");
|
||||
drawPango(layoutSmall, &colLight, 10, contentY + 42, 18, sigLine, 220);
|
||||
|
||||
@@ -1090,6 +1196,15 @@ int runModemApp(int argc, char** argv) {
|
||||
};
|
||||
|
||||
auto showWindow = [&](const std::string& arg = "") {
|
||||
std::string a = toLowerStr(trimStr(arg));
|
||||
if (visible &&
|
||||
(modal == ModalMode::VerifyPin || modal == ModalMode::UnblockPuk) &&
|
||||
(a == "unlock" || a == "pin" || a == "puk")) {
|
||||
XRaiseWindow(dpy, win);
|
||||
grabKeys();
|
||||
render();
|
||||
return;
|
||||
}
|
||||
closeOtherPlugins("modem");
|
||||
refreshData(true);
|
||||
applyOpenArg(arg);
|
||||
@@ -1308,16 +1423,36 @@ int runModemApp(int argc, char** argv) {
|
||||
|
||||
auto triggerSimRowAction = [&](int row) {
|
||||
if (row == 0 || row == 1) {
|
||||
targetSlot = row + 1;
|
||||
actionSel = 0;
|
||||
modal = ModalMode::SimActions;
|
||||
int sNum = row + 1;
|
||||
const auto& s = status.slots[row];
|
||||
if (s.needsPin() || s.needsPuk()) {
|
||||
openPinOrPukModalForSlot(sNum);
|
||||
} else if (s.state == "present" && !s.isActiveProvisioned) {
|
||||
switchSimSlotNow(sNum);
|
||||
} else {
|
||||
targetSlot = sNum;
|
||||
actionSel = 0;
|
||||
modal = ModalMode::SimActions;
|
||||
}
|
||||
} else if (row == 2) {
|
||||
int otherSlot = (status.preferredSlot == 1) ? 2 : 1;
|
||||
if (status.primaryGwSlot == 0) {
|
||||
if (status.slots[1].state == "present" && status.slots[0].state != "present") {
|
||||
otherSlot = 2;
|
||||
} else if (status.slots[0].state == "present" && status.slots[1].state != "present") {
|
||||
otherSlot = 1;
|
||||
}
|
||||
}
|
||||
switchSimSlotNow(otherSlot);
|
||||
} else if (row == 3) {
|
||||
int slot = (status.primaryGwSlot >= 1 && status.primaryGwSlot <= 2)
|
||||
? status.primaryGwSlot
|
||||
: status.preferredSlot;
|
||||
if (status.slots[0].needsPin() || status.slots[0].needsPuk()) {
|
||||
slot = 1;
|
||||
} else if (status.slots[1].needsPin() || status.slots[1].needsPuk()) {
|
||||
slot = 2;
|
||||
}
|
||||
openPinOrPukModalForSlot(slot);
|
||||
} else if (row == 4) {
|
||||
targetSlot = (status.primaryGwSlot >= 1 && status.primaryGwSlot <= 2)
|
||||
@@ -1446,14 +1581,18 @@ int runModemApp(int argc, char** argv) {
|
||||
ussdResponse.clear();
|
||||
ussdWaitingReply = false;
|
||||
} else if (radioRowSel == 2) {
|
||||
bool powerOn = (status.mmPowerState == "on" ||
|
||||
status.mmState == "registered" ||
|
||||
status.mmState == "connected" ||
|
||||
status.mmState == "searching");
|
||||
bool powerOn = (status.mmPowerState == "on" &&
|
||||
status.mmState != "disabled" &&
|
||||
status.mmState != "failed");
|
||||
setBanner(powerOn ? "Disabling modem..." : "Enabling modem...");
|
||||
render();
|
||||
runCaptureCmd(powerOn ? "mmcli -m any -d >/dev/null 2>&1"
|
||||
: "mmcli -m any -e >/dev/null 2>&1");
|
||||
if (powerOn) {
|
||||
runCaptureCmd("mmcli -m any -d >/dev/null 2>&1");
|
||||
} else {
|
||||
runCaptureCmd(
|
||||
"doas -n /usr/libexec/msm-modem-uim-selection boot >/dev/null 2>&1 "
|
||||
"|| mmcli -m any -e >/dev/null 2>&1");
|
||||
}
|
||||
refreshData(false);
|
||||
runAsyncCmd("sxmo_hook_statusbar.sh modem >/dev/null 2>&1");
|
||||
} else if (radioRowSel == 3) {
|
||||
@@ -1494,6 +1633,9 @@ int runModemApp(int argc, char** argv) {
|
||||
}
|
||||
};
|
||||
|
||||
int autoCheckStage = isPreload ? 0 : 2;
|
||||
int64_t nextAutoCheckMs = nowMs() + 2500;
|
||||
|
||||
if (!isPreload) {
|
||||
showWindow(openArg);
|
||||
}
|
||||
@@ -1841,6 +1983,28 @@ int runModemApp(int argc, char** argv) {
|
||||
timeoutMs = static_cast<int>(rRem);
|
||||
}
|
||||
}
|
||||
} else if (autoCheckStage < 2) {
|
||||
int64_t aRem = nextAutoCheckMs - now;
|
||||
if (aRem <= 0) {
|
||||
++autoCheckStage;
|
||||
nextAutoCheckMs = now + 4500;
|
||||
refreshData(false);
|
||||
if (status.slots[0].needsPin() || status.slots[0].needsPuk() ||
|
||||
status.slots[1].needsPin() || status.slots[1].needsPuk() ||
|
||||
status.mmState == "locked") {
|
||||
autoCheckStage = 2;
|
||||
showWindow("unlock");
|
||||
} else if ((status.slots[0].state == "present" ||
|
||||
status.slots[1].state == "present") &&
|
||||
(status.primaryGwSlot == 0 ||
|
||||
status.mmState == "disabled")) {
|
||||
runAsyncCmd(
|
||||
"doas -n /usr/libexec/msm-modem-uim-selection boot >/dev/null "
|
||||
"2>&1");
|
||||
}
|
||||
} else if (timeoutMs < 0 || aRem < timeoutMs) {
|
||||
timeoutMs = static_cast<int>(aRem);
|
||||
}
|
||||
}
|
||||
|
||||
struct pollfd pfds[2];
|
||||
|
||||
@@ -183,7 +183,14 @@ inline bool sendPluginCommand(const char* name, const std::string& cmdLine) {
|
||||
return false;
|
||||
}
|
||||
std::string fifoPath = getPluginFifoPath(name);
|
||||
int fd = ::open(fifoPath.c_str(), O_WRONLY | O_NONBLOCK | O_CLOEXEC);
|
||||
int fd = -1;
|
||||
for (int attempt = 0; attempt < 6; ++attempt) {
|
||||
fd = ::open(fifoPath.c_str(), O_WRONLY | O_NONBLOCK | O_CLOEXEC);
|
||||
if (fd >= 0) {
|
||||
break;
|
||||
}
|
||||
::usleep(25000);
|
||||
}
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -1651,20 +1658,12 @@ inline std::string sendModemUssd(const std::string& input,
|
||||
if (clean.empty()) return "Empty USSD request.";
|
||||
|
||||
int rc = 0;
|
||||
std::string cmd;
|
||||
if (isReply && !isUssdCode(clean)) {
|
||||
cmd = "mmcli -m any --3gpp-ussd-respond=" + shellQuote(clean) + " 2>&1";
|
||||
} else {
|
||||
cmd = "mmcli -m any --3gpp-ussd-cancel >/dev/null 2>&1; "
|
||||
"mmcli -m any --3gpp-ussd-initiate=" + shellQuote(clean) + " 2>&1";
|
||||
}
|
||||
std::string mode = (isReply && !isUssdCode(clean)) ? "respond" : "initiate";
|
||||
std::string cmd =
|
||||
"doas -n /usr/libexec/msm-modem-uim-selection ussd " + mode + " " +
|
||||
shellQuote(clean) + " 2>&1";
|
||||
|
||||
std::string out = trimStr(runCaptureCmd(cmd, &rc));
|
||||
size_t q1 = out.find('\'');
|
||||
size_t q2 = out.rfind('\'');
|
||||
if (q1 != std::string::npos && q2 != std::string::npos && q2 > q1) {
|
||||
out = out.substr(q1 + 1, q2 - q1 - 1);
|
||||
}
|
||||
if (out.empty()) {
|
||||
out = (rc == 0) ? "USSD request completed." : "USSD request failed.";
|
||||
}
|
||||
@@ -1698,7 +1697,9 @@ inline std::string sendModemUssd(const std::string& input,
|
||||
}
|
||||
|
||||
inline void cancelModemUssd() {
|
||||
runAsyncCmd("mmcli -m any --3gpp-ussd-cancel >/dev/null 2>&1");
|
||||
runAsyncCmd(
|
||||
"doas -n /usr/libexec/msm-modem-uim-selection ussd cancel >/dev/null 2>&1 "
|
||||
"|| mmcli -m any --3gpp-ussd-cancel >/dev/null 2>&1");
|
||||
}
|
||||
|
||||
} // namespace bananarchy
|
||||
|
||||
+107
-24
@@ -816,6 +816,97 @@ write_str_file(const char *path, const char *val)
|
||||
return n > 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dunst_window_visible(void)
|
||||
{
|
||||
if (!dpy)
|
||||
return 0;
|
||||
Window r_ret, p_ret, *children = NULL;
|
||||
unsigned int nchildren = 0;
|
||||
int found = 0;
|
||||
if (!XQueryTree(dpy, root, &r_ret, &p_ret, &children, &nchildren) || !children)
|
||||
return 0;
|
||||
for (unsigned int i = 0; i < nchildren; i++) {
|
||||
XWindowAttributes wa;
|
||||
if (!XGetWindowAttributes(dpy, children[i], &wa) || wa.map_state != IsViewable)
|
||||
continue;
|
||||
XClassHint ch = { NULL, NULL };
|
||||
if (XGetClassHint(dpy, children[i], &ch)) {
|
||||
if ((ch.res_class && strcasecmp(ch.res_class, "Dunst") == 0) ||
|
||||
(ch.res_name && strcasecmp(ch.res_name, "dunst") == 0))
|
||||
found = 1;
|
||||
if (ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
if (ch.res_class)
|
||||
XFree(ch.res_class);
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(children);
|
||||
return found;
|
||||
}
|
||||
|
||||
static void
|
||||
unmap_dunst_windows(void)
|
||||
{
|
||||
if (!dpy)
|
||||
return;
|
||||
Window r_ret, p_ret, *children = NULL;
|
||||
unsigned int nchildren = 0;
|
||||
int unmapped = 0;
|
||||
if (!XQueryTree(dpy, root, &r_ret, &p_ret, &children, &nchildren) || !children)
|
||||
return;
|
||||
for (unsigned int i = 0; i < nchildren; i++) {
|
||||
XClassHint ch = { NULL, NULL };
|
||||
if (XGetClassHint(dpy, children[i], &ch)) {
|
||||
if ((ch.res_class && strcasecmp(ch.res_class, "Dunst") == 0) ||
|
||||
(ch.res_name && strcasecmp(ch.res_name, "dunst") == 0)) {
|
||||
XUnmapWindow(dpy, children[i]);
|
||||
unmapped = 1;
|
||||
}
|
||||
if (ch.res_name)
|
||||
XFree(ch.res_name);
|
||||
if (ch.res_class)
|
||||
XFree(ch.res_class);
|
||||
}
|
||||
}
|
||||
XFree(children);
|
||||
if (unmapped)
|
||||
XFlush(dpy);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_all_notifications_now(void)
|
||||
{
|
||||
const char *ndir = getenv("SXMO_NOTIFDIR");
|
||||
char default_dir[256];
|
||||
if (!ndir || !ndir[0]) {
|
||||
const char *home = getenv("HOME");
|
||||
snprintf(default_dir, sizeof(default_dir), "%s/.local/share/sxmo/notifications",
|
||||
(home && home[0]) ? home : "/home/user");
|
||||
ndir = default_dir;
|
||||
}
|
||||
DIR *d = opendir(ndir);
|
||||
if (d) {
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(d)) != NULL) {
|
||||
if (ent->d_name[0] == '.')
|
||||
continue;
|
||||
char fpath[512];
|
||||
snprintf(fpath, sizeof(fpath), "%s/%s", ndir, ent->d_name);
|
||||
unlink(fpath);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
unmap_dunst_windows();
|
||||
spawn_detached_sh(
|
||||
"dunstctl close-all >/dev/null 2>&1; "
|
||||
"dunstctl history-clear >/dev/null 2>&1; "
|
||||
"pkill -x dunstify >/dev/null 2>&1; "
|
||||
"sxmo_hook_statusbar.sh notifications >/dev/null 2>&1");
|
||||
}
|
||||
|
||||
static void
|
||||
handle_builtin_toggle(const char *toggle_name)
|
||||
{
|
||||
@@ -914,27 +1005,7 @@ handle_builtin_toggle(const char *toggle_name)
|
||||
}
|
||||
spawn_detached_sh("sxmo_hook_statusbar.sh audio");
|
||||
} else if (strcmp(toggle_name, "notif_clear_all") == 0) {
|
||||
const char *ndir = getenv("SXMO_NOTIFDIR");
|
||||
char default_dir[256];
|
||||
if (!ndir || !ndir[0]) {
|
||||
const char *home = getenv("HOME");
|
||||
snprintf(default_dir, sizeof(default_dir), "%s/.local/share/sxmo/notifications",
|
||||
(home && home[0]) ? home : "/home/user");
|
||||
ndir = default_dir;
|
||||
}
|
||||
DIR *d = opendir(ndir);
|
||||
if (d) {
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(d)) != NULL) {
|
||||
if (ent->d_name[0] == '.')
|
||||
continue;
|
||||
char fpath[512];
|
||||
snprintf(fpath, sizeof(fpath), "%s/%s", ndir, ent->d_name);
|
||||
unlink(fpath);
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
spawn_detached_sh("sxmo_hook_statusbar.sh notifs");
|
||||
clear_all_notifications_now();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,7 +1102,10 @@ activate_selection(unsigned int ev_state)
|
||||
fclose(fp);
|
||||
}
|
||||
unlink(fpath);
|
||||
spawn_detached_sh("sxmo_hook_statusbar.sh notifs");
|
||||
unmap_dunst_windows();
|
||||
spawn_detached_sh(
|
||||
"dunstctl close-all >/dev/null 2>&1; "
|
||||
"sxmo_hook_statusbar.sh notifications >/dev/null 2>&1");
|
||||
hide_menu();
|
||||
menu_mode = MODE_NONE;
|
||||
if (action_cmd[0] && strcmp(action_cmd, "none") != 0)
|
||||
@@ -1040,6 +1114,11 @@ activate_selection(unsigned int ev_state)
|
||||
}
|
||||
if (strncmp(act, "@toggle:", 8) == 0) {
|
||||
handle_builtin_toggle(act + 8);
|
||||
if (strcmp(act + 8, "notif_clear_all") == 0) {
|
||||
hide_menu();
|
||||
menu_mode = MODE_NONE;
|
||||
return;
|
||||
}
|
||||
char cur_menu[64];
|
||||
snprintf(cur_menu, sizeof(cur_menu), "%s", current_builtin_menu);
|
||||
open_builtin_menu(cur_menu, cur_idx);
|
||||
@@ -1906,9 +1985,13 @@ open_builtin_menu(const char *menu_name, int keep_idx)
|
||||
reset_session_defaults(1, "Sys");
|
||||
append_active_call_entries();
|
||||
int nnotifs = count_notifications();
|
||||
int dunst_vis = dunst_window_visible();
|
||||
if (nnotifs > 0) {
|
||||
snprintf(label, sizeof(label), "%s Notifications (%d)", ICON_BEL, nnotifs);
|
||||
add_menu_item(label, "@menu:notifications", 1);
|
||||
} else if (dunst_vis) {
|
||||
snprintf(label, sizeof(label), "%s Clear Notification", ICON_BEL);
|
||||
add_menu_item(label, "@toggle:notif_clear_all", 0);
|
||||
}
|
||||
const char *sh = getenv("SHELL");
|
||||
if (!sh || !sh[0])
|
||||
@@ -2105,9 +2188,9 @@ open_builtin_menu(const char *menu_name, int keep_idx)
|
||||
add_menu_item(label, "@close", 0);
|
||||
} else if (strcmp(menu_name, "notifications") == 0) {
|
||||
reset_session_defaults(1, "Notifs");
|
||||
populate_notifications_menu();
|
||||
snprintf(label, sizeof(label), "%s Clear All Notifications", ICON_CLS);
|
||||
add_menu_item(label, "@toggle:notif_clear_all", 1);
|
||||
add_menu_item(label, "@toggle:notif_clear_all", 0);
|
||||
populate_notifications_menu();
|
||||
snprintf(label, sizeof(label), "%s System Menu", ICON_MNU);
|
||||
add_menu_item(label, "@menu:sys", 1);
|
||||
snprintf(label, sizeof(label), "%s Close Menu", ICON_CLS);
|
||||
|
||||
Reference in New Issue
Block a user