~mil/f_scripts

ref: c52a77c4185fd4dc9a5177a5437a3329ea4c847b f_scripts/scripts/f_phone -rwxr-xr-x 13.4 KiB
c52a77c4Miles Alan f_audio: Set AIF1 DA0 to 20% rather then 100% to prevent distortion 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
#!/usr/bin/env osh
shopt -s strict:all
DEP="polkit modemmanager linuxconsoletools pinephone-call-audio pn"
DEC="Manages phone calls / text messages using modemmanager"
DOC="
  A single interactive prompt-driven script to manage all aspects of
  using your phone's modem for sending & receiving text messages and
  placing and receiving calls.

  Transfers incoming text messages and logs calls and all actions to
  a single logfile which can be interactively filtered (per-contact
  etc..) via using the provided phonelog submenu. The log file used
  can be customized by setting \$F_PHONE_MODEMHISTORYFILE. Additionally
  a number of hooks can be set, see variables for usable.
  
  The script in the background (via a subshell), continually monitors
  modemmanager (via its DBus interface via mmcli), alerts you when a
  new call is incoming (vibrating the phone and interrupting your
  current prompt to provide a pickup prompt).
  
  So in short, basically, this script allows you to use pinephone (or
  otherwise) as , who would have thought.. a lightweight... phone(!)
"
VAR="
  F_PHONE_MODEMHISTORYFILE=~/.f_phone_modemhistory
  F_PHONE_MONITORSTATEFILE=/tmp/f_phone_monitorstate
  F_PHONE_HOOKRINGSTART='yes 5 | fftest /dev/input/by-path/platform-vibrator-event'
  F_PHONE_HOOKRINGSTOP='pkill fftest'
  F_PHONE_HOOKMISSEDSTART='echo 255 > /sys/class/leds/green:indicator/brightness; { echo 5; sleep 1; echo -1; }  | fftest /dev/input/by-path/platform-vibrator-event'
  F_PHONE_HOOKMISSEDSTOP='echo 0 > /sys/class/leds/green:indicator/brightness'
  F_PHONE_COUNTRYCODE='US'
"

cleannumber() { pn find -c "$F_PHONE_COUNTRYCODE" "$1"; }
mm() { mmcli -m any "$@"; }
monitorstateget() { cat "$F_PHONE_MONITORSTATEFILE" || echo ""; }
monitorstateset() { echo "$1" > "$F_PHONE_MONITORSTATEFILE"; }
ringhangup() { mm -o "$(callid "incoming.+ringing")" --hangup; }
ringpickup() { loopincall --accept "$(callid "incoming.+ringing")"; }

promptok() {
  [ -p /tmp/fbp.fifo ] && echo -e "\b\f\rok" > /tmp/fbp.fifo
  read -p Ok foo
}

errdie() {
  echo "$1"
  terminate
}

terminate() {
  [ -n "$GLOBAL_AUDIOSAVE_FILE" ] && alsactl --file "$GLOBAL_AUDIOSAVE_FILE" restore
  [ -n "$GLOBAL_CALLID_INPROGRESS" ] && mm -o "$GLOBAL_CALLID_INPROGRESS" --hangup
  eval "$F_PHONE_HOOKMISSEDSTOP" >&2 2>/dev/null &
  eval "$F_PHONE_HOOKRINGSTOP" >&2 2>/dev/null &
  kill 0
  exit 1
}

installpolkitudevrules() {
  TARGETPOLKITFILE="/etc/polkit-1/rules.d/00-f_scripts-fphone-mmplugdev.rules"
  TARGETUDEVFILE="/etc/udev/rules.d/00-f-scripts-f-phone.rules"

  test -f "$TARGETPOLKITFILE" || {
    echo "Installing polkit rule for modemmanager (for group plugdev)"
    sudo mkdir -p "$(dirname "$TARGETPOLKITFILE")"
    echo '
      polkit.addRule(function(action, subject) {
        if (
          action.id.indexOf("org.freedesktop.ModemManager1.") == 0 &&
          subject.isInGroup("plugdev")
        ) { return polkit.Result.YES; }
      });
    ' | sudo tee "$TARGETPOLKITFILE"
    sudo chmod a+rx "$TARGETPOLKITFILE"
    sudo addgroup "$USER" plugdev
    clear
    echo "polkit rule installed! you may need to reboot"
    promptok
  }

  test -f "$TARGETUDEVFILE" || {
    echo "Installing udev rule for setting system LED (for group video)"
    sudo mkdir -p "$(dirname "$TARGETUDEVFILE")"
    echo '
      ACTION=="add", SUBSYSTEM=="leds", RUN+="/bin/chgrp video /sys/class/leds/%k/brightness"
      ACTION=="add", SUBSYSTEM=="leds", RUN+="/bin/chmod g+w /sys/class/leds/%k/brightness"
    ' | sudo tee "$TARGETUDEVFILE"
    sudo addgroup "$USER" video
    sudo chmod a+rx "$TARGETUDEVFILE"
    clear
    echo "udev rule installed! you may need to reboot"
    promptok
  }
}

ensuremmrunning() {
  rc-service modemmanager status | grep started || {
    sudo /etc/init.d/modemmanager start
    sudo rc-update add modemmanager boot
  }
}

maketext() {
  local MSG NUMBER ACTION

  echo "maketext: Dialog for sending a text message"
  while true; do
    if [ -z "$NUMBER" ]; then
      { echo -e "\b\f\e"; seq 0 9; echo -e "\\\\n"; } > /tmp/fbp.fifo
      read -p "Number: " NUMBER
    fi
    if [ -z "$MSG" ]; then
      echo -e "\a" > /tmp/fbp.fifo
      read -p "Message: " MSG
    fi

    echo "Will send to <$NUMBER>, the message: <$MSG>"

    OPTS="send cancel editmsg editnum"
    [ -p /tmp/fbp.fifo ] && { echo -e "\b\f\r"; echo "$OPTS" | tr " " "\n"; } > /tmp/fbp.fifo
    read -p "Action ($OPTS): " ACTION


    [ "$ACTION" == send ] && break
    [ "$ACTION" == editmsg ] && MSG=''
    [ "$ACTION" == editnum ] && NUMBER=''
    [ "$ACTION" == cancel ] && return
    [ "$ACTION" == interrupt ] && return
  done

  NUMBER="$(cleannumber "$NUMBER")"
  logevt textsend_attempt "$(date +%s)" "$NUMBER" "$MSG"
  echo "Sending text message to <$NUMBER>: <$MSG>"

  TEXTID="$(
    mm --messaging-create-sms="text=\"$MSG\",number=$NUMBER" |
    grep -Eo "SMS/[0-9]+" | cut -d/ -f2
  )"
  mm -s "$TEXTID" --send
  logevt textsend_success "$(date +%s)" "$NUMBER" "$MSG"
  promptok
}

volset() {
  amixer sget "$GLOBAL_EARPIECE" | grep -qE '\[on\]' && amixer set "$GLOBAL_EARPIECE" $1 > /dev/null
  amixer sget "$GLOBAL_HEADPHONE" | grep -qE '\[on\]' && amixer set "$GLOBAL_HEADPHONE" $1 > /dev/null
  amixer sget "$GLOBAL_SPEAKER" | grep -qE '\[on\]' && amixer set "$GLOBAL_SPEAKER" $1 > /dev/null
}

logevt() {
  {
    FIRST=1
    for ARG in "$@"; do
        if [ "$FIRST" = 1 ]; then
          FIRST=0
        else
          printf %b '\t'
        fi
        printf %b "$ARG"
    done
    printf "%b" "\n"
  } >> "$F_PHONE_MODEMHISTORYFILE"
}

makecall() {
  local NUMBER ACTION

  echo "makecall: Dialog for placing a call"
  while true; do
    if [ -z "$NUMBER" ]; then
      { echo -e "\b\f\e"; seq 0 9; echo -e "\\\\n"; } > /tmp/fbp.fifo
      read -p "Number: " NUMBER
    fi

    echo "Will initiate a call with <$NUMBER>"
    
    OPTS="confirm cancel editnum"
    [ -p /tmp/fbp.fifo ] && { echo -e "\b\f\r"; echo "$OPTS" | tr " " "\n"; } > /tmp/fbp.fifo
    read -p "Action ($OPTS): " ACTION

    [ "$ACTION" == confirm ] && break
    [ "$ACTION" == editnum ] && NUMBER=''
    [ "$ACTION" == cancel ] && return
    [ "$ACTION" == interrupt ] && return
  done

  NUMBER="$(cleannumber "$NUMBER")"
  logevt callsend_attempt $(date +%s) "$NUMBER" "$MSG"
  CALLID="$(
    mm --voice-create-call "number=$NUMBER" |
    grep -Eo "Call/[0-9]+" | cut -d/ -f2
  )"
  loopincall --start "$CALLID"
}

modemrst() {
  mmcli -L | grep /org/freedesktop/ModemManager1 ||
    sudo /etc/init.d/modemmanager restart

  while ! mmcli -L | grep /org/freedesktop/ModemManager1; do
    echo "Waiting for modem to come online"
    sleep 1
  done
}


callid() {
  TYPE="$1"
  mm --voice-list-calls -a |
    grep -v terminated |
    grep -Eo "Call/[0-9]+.+$TYPE" |
    grep -Eo '[0-9]+'
}

lookupnumberfromcallid() {
  VOICECALLID="$1"

  cleannumber "$(
    mm --voice-list-calls -o "$VOICECALLID" -K |
      grep call.properties.number |
      cut -d ':' -f 2 |
      tr -d ' '
  )"
}

loopincall() {
  local CALLID
  PICKUPORACCEPT="$1"
  CALLID="$2"
  GLOBAL_CALLID_INPROGRESS="$CALLID"

  echo "Initiating call id $CALLID via $PICKUPORACCEPT with $(lookupnumberfromcallid $CALLID)"
  mm -o "$CALLID" "$PICKUPORACCEPT"

  # Audio routing setup
  # Correct for some bug with modem requiring toggling DAI a few times to kick in
  GLOBAL_AUDIOSAVE_FILE="$(mktemp)"
  alsactl --file "$GLOBAL_AUDIOSAVE_FILE" store
  for i in $(seq 3); do
    pinephone-call-audio -e -m
    pinephone-call-audio -e -m -2
  done

  # Loop to end
  # CHECK FOR mmcli incall id here!
  while true; do
    OPTS="nop hangup volup voldown modespeaker modehandheld modewired 1 2 3 4 5 6 7 8 9 0"
    [ -p /tmp/fbp.fifo ] && { echo -e "\b\f\r"; echo "$OPTS" | tr " " "\n"; } > /tmp/fbp.fifo
    read -p "Action ($OPTS): " ACTION

    [ "$ACTION" = "volup" ] && volset 1+
    [ "$ACTION" = "voldown" ] && volset 1-
    [ "$ACTION" = "modehandheld" ] && pinephone-call-audio -e -m -2
    [ "$ACTION" = "modespeaker" ] && pinephone-call-audio -s -m -2
    [ "$ACTION" = "modewired" ] && pinephone-call-audio -h -l -2
    [ "$ACTION" = "hangup" ] && mm -o "$CALLID" --hangup && break
    echo "$ACTION" | grep '[0-9]' && mm -o "$CALLID" --send-dtmf="$ACTION"
  done

  echo "Call terminated"
  promptok
  alsactl --file "$GLOBAL_AUDIOSAVE_FILE" restore && GLOBAL_AUDIOSAVE_FILE=""
}

phoneinfo() {
  echo "phoneinfo: Diagnostics about the phone"
  mm | grep -E 'Numbers|imei' | tr -s ' '
  promptok
}

phonelog() {
  eval "$F_PHONE_HOOKMISSEDSTOP" >&2 2>/dev/null &

  FILTERGREP="."
  while true; do
    clear
    touch "$F_PHONE_MODEMHISTORYFILE"
    if [ "$FILTERGREP" = "." ]; then
      cat "$F_PHONE_MODEMHISTORYFILE" | grep -E "$FILTERGREP"
    else
      cat "$F_PHONE_MODEMHISTORYFILE" | grep -F "$FILTERGREP"
    fi

    [ -p /tmp/fbp.fifo ] && {
      echo -e "\b\f\r"; 
      echo "cancel"
      echo "."
      cat "$F_PHONE_MODEMHISTORYFILE" | cut -f3 | sort | uniq
      cat "$F_PHONE_MODEMHISTORYFILE" | cut -f1 | sort | uniq
    } > /tmp/fbp.fifo
    read -p "Filter: " FILTERGREP
    [ "$FILTERGREP" == cancel ] && return
  done
}


determinemodemtransition() {
  local MONITORSTATE

  if callid active >/dev/null; then
    MONITORSTATE=incall
  elif callid "incoming.+ringing" >/dev/null; then
    MONITORSTATE=ringing
  else
    MONITORSTATE=idle
  fi
  [ "$(monitorstateget)" != "$MONITORSTATE" ] && {
    TRANSITION="$(monitorstateget)_to_$MONITORSTATE"
    monitorstateset "$MONITORSTATE"
    echo "$TRANSITION"
  }
}

devicepine64pinephone() {
  amixer set "AIF1 DA0" "100%" > /dev/null
  amixer set "AIF1 Slot 0 Digital DAC" unmute > /dev/null
  GLOBAL_SPEAKER="Line Out"
  GLOBAL_HEADPHONE="Headphone"
  GLOBAL_EARPIECE="Earpiece"
}

syncmmstatetolog() {
  for TEXTID in $(
    mm --messaging-list-sms |
    grep -Eo '/SMS/[0-9]+ \(received\)' |
    grep -Eo '[0-9]+'
  ); do
    TEXTDATA="$(mm -s "$TEXTID" -K)"
    MSG="$(echo "$TEXTDATA" | grep sms.content.text | sed -E 's/^sms\.content\.text\s+:\s+//')"
    NUM="$(cleannumber "$(echo "$TEXTDATA" | grep sms.content.number | sed -E 's/^sms\.content\.number\s+:\s+//')")"
    TIME="$(echo "$TEXTDATA" | grep sms.properties.timestamp | sed -E 's/^sms\.properties\.timestamp\s+:\s+//' | xargs -IDATE date -d 'DATE' +%s)"

    logevt textrecv "$(date +%s)" "$NUM" "$TIME" "$MSG"
    mm --messaging-delete-sms="$TEXTID"
    eval "$F_PHONE_HOOKMISSEDSTART" >&2 2>/dev/null &
  done

  for CALLID in $(
    mm --voice-list-calls |
      grep terminated |
      grep -oE "Call\/[0-9]+" |
      cut -d'/' -f2
  ); do
    NUM="$(lookupnumberfromcallid "$CALLID")"

    logevt callterminate "$(date +%s)" "$NUM"
    mm --voice-delete-call "$CALLID"
  done
}

monitorboot() {
  local KILLPID EVTCALLADD EVTMSGADD EVTCALLPROP TRANSITION
  KILLPID="$1"
  EVTCALLADD="interface='org.freedesktop.ModemManager1.Modem.Voice',type='signal',member='CallAdded'"
  EVTMSGADD="interface='org.freedesktop.ModemManager1.Modem.Messaging',type='signal',member='Added'"
  EVTCALLPROP="interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',arg0='org.freedesktop.ModemManager1.Call'"

  dbus-monitor --system "$EVTCALLADD" "$EVTMSGADD" "$EVTCALLPROP" | while read -r LINE; do
    TRANSITION="$(determinemodemtransition)"

    syncmmstatetolog >&2 2>/dev/null

    if [ "$TRANSITION" = incall_to_idle ]; then
      kill -HUP $KILLPID
    elif [ "$TRANSITION" = idle_to_ringing ]; then
      logevt callring "$(date +%s)" "$(lookupnumberfromcallid $(callid "incoming.+ringing"))"
      eval "$F_PHONE_HOOKRINGSTART" >&2 2>/dev/null &
      kill -HUP $KILLPID
    elif [ "$TRANSITION" = ringing_to_idle ]; then
      eval "$F_PHONE_HOOKRINGSTOP" >&2 2>/dev/null &
      eval "$F_PHONE_HOOKMISSEDSTART" >&2 2>/dev/null &
      kill -HUP $KILLPID
    elif [ "$TRANSITION" = ringing_to_incall ]; then
      eval "$F_PHONE_HOOKRINGSTOP" >&2 2>/dev/null &
    fi
  done
}


mainloop() {
  while true; do
      OPTS="maketext makecall phonelog phoneinfo modemrst"

      clear
      callid ringing >/dev/null && echo "Ringing in call from $(lookupnumberfromcallid $(callid "incoming.+ringing"))!" >&2
      echo "Calls events: $(grep -c ^call $F_PHONE_MODEMHISTORYFILE)" >&2
      echo "Text events: $(grep -c ^text $F_PHONE_MODEMHISTORYFILE)" >&2
      echo "===================================" >&2
      echo "phoneinfo: get sim card status, iccid, etc." >&2
      echo "phonelog: read log for modem, dismisses unread messages/missed calls" >&2
      echo "maketext: send a new text message" >&2
      echo "makecall: place a new call" >&2
      echo "modemrst: reset modemmanager and wait for connection"
      if callid "incoming.+ringing" >/dev/null; then
        echo "ringpickup: pickup the ringing in call" >&2
        echo "ringhangup: hangup the ringing in call" >&2
        OPTS="ringpickup ringhangup $OPTS"
      fi
      echo "===================================" >&2

      [ -p /tmp/fbp.fifo ] && { echo -e "\b\f\r"; echo "$OPTS" | tr " " "\n"; } > /tmp/fbp.fifo

      FUNC=none
      while ! declare -F "$FUNC" > /dev/null; do
        read -p "Run: " FUNC
      done
      clear
      "$FUNC"
  done
}

main() {
  trap terminate INT TERM
  trap mainloop HUP

  GLOBAL_AUDIOSAVE_FILE=""
  GLOBAL_CALLID_INPROGRESS=""
  GLOBAL_SPEAKER=""
  GLOBAL_HEADPHONE=""
  GLOBAL_EARPIECE=""

  installpolkitudevrules
  ensuremmrunning
  modemrst
  env | grep -q "^$(basename "$0" | tr '[a-z]' '[A-Z]')=" || eval "$VAR"
  eval "$(grep deviceinfo_codename /etc/deviceinfo | cut -d= -f2 | tr -d \"- | xargs -ID echo deviceD)" || 
    errdie "Device unsupported - only pinephone supported currently"

  monitorboot $$ >&2 2>/dev/null &
  mainloop
}

if [ -n "$1" ]; then "$@"; else main; fi