diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..af3698a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,23 @@ +--- +name: Bug report +about: Create a report to help us improve termux-api-package +title: '' +labels: '' +assignees: '' + +--- + + + +**Problem description** +A clear and concise description of what the problem with termux-api-package is. You may post screenshots or paste error messages in addition to description. + +**Steps to reproduce** +Please post all steps that are needed to reproduce the issue. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Additional information** +Post output of command `termux-info`. +If you are rooted or have access to adb then capture a logcat with `logcat -d "*:W"`, from a adb or root shell. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..d44d4db --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,15 @@ +--- +name: Feature request +about: Suggest a new feature in termux-api-package +title: '' +labels: '' +assignees: '' + +--- + +**Feature description** +Describe the feature and why you want it. + +**Background information** +Have you checked if the feature is accessible through the android API? +Do you know of other open-source apps that has a similar feature as the one you want? (Provide links) diff --git a/.gitignore b/.gitignore index 4473321..e89fbcd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ termux-api +*~ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c8b1f9e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,131 @@ +cmake_minimum_required(VERSION 3.0.0) +project(termux-api) +include(GNUInstallDirs) + +set(TERMUX_PREFIX ${CMAKE_INSTALL_PREFIX}) + +add_library(termux-api SHARED termux-api.c) +add_library(termux-api-static STATIC termux-api.c) +set_target_properties(termux-api-static PROPERTIES OUTPUT_NAME termux-api) + +add_executable(termux-api-broadcast termux-api-broadcast.c) +target_link_libraries(termux-api-broadcast termux-api-static) + +# TODO: get list through regex or similar +set(script_files + scripts/termux-api-start + scripts/termux-api-stop + scripts/termux-audio-info + scripts/termux-battery-status + scripts/termux-brightness + scripts/termux-call-log + scripts/termux-camera-info + scripts/termux-camera-photo + scripts/termux-clipboard-get + scripts/termux-clipboard-set + scripts/termux-contact-list + scripts/termux-dialog + scripts/termux-download + scripts/termux-fingerprint + scripts/termux-infrared-frequencies + scripts/termux-infrared-transmit + scripts/termux-job-scheduler + scripts/termux-keystore + scripts/termux-location + scripts/termux-media-player + scripts/termux-media-scan + scripts/termux-microphone-record + scripts/termux-nfc + scripts/termux-notification + scripts/termux-notification-channel + scripts/termux-notification-list + scripts/termux-notification-remove + scripts/termux-saf-create + scripts/termux-saf-dirs + scripts/termux-saf-ls + scripts/termux-saf-managedir + scripts/termux-saf-mkdir + scripts/termux-saf-read + scripts/termux-saf-rm + scripts/termux-saf-stat + scripts/termux-saf-write + scripts/termux-sensor + scripts/termux-share + scripts/termux-sms-inbox + scripts/termux-sms-list + scripts/termux-sms-send + scripts/termux-speech-to-text + scripts/termux-storage-get + scripts/termux-telephony-call + scripts/termux-telephony-cellinfo + scripts/termux-telephony-deviceinfo + scripts/termux-toast + scripts/termux-torch + scripts/termux-tts-engines + scripts/termux-tts-speak + scripts/termux-usb + scripts/termux-vibrate + scripts/termux-volume + scripts/termux-wallpaper + scripts/termux-wifi-connectioninfo + scripts/termux-wifi-enable + scripts/termux-wifi-scaninfo +) + +make_directory(scripts) +foreach(file ${script_files}) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/${file}.in + ${file} @ONLY + ) +endforeach() + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/termux-callback.in + termux-callback @ONLY +) + +install( + FILES ${CMAKE_BINARY_DIR}/termux-api-broadcast + DESTINATION ${CMAKE_INSTALL_PREFIX}/libexec + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE +) + +# Create a symlink for termux-api-broadcast->termux-api for backwards +# compatibility +INSTALL(CODE "execute_process( \ + COMMAND ${CMAKE_COMMAND} -E create_symlink \ + termux-api-broadcast \ + ${CMAKE_INSTALL_PREFIX}/libexec/termux-api \ + )" +) + +install( + FILES + ${CMAKE_BINARY_DIR}/libtermux-api.so + ${CMAKE_BINARY_DIR}/libtermux-api.a + TYPE LIB +) + +install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/termux-api.h + TYPE INCLUDE +) + +foreach(file ${script_files}) + install( + FILES ${CMAKE_BINARY_DIR}/${file} + TYPE BIN + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + ) +endforeach() + +install( + FILES ${CMAKE_BINARY_DIR}/termux-callback + DESTINATION ${CMAKE_INSTALL_PREFIX}/libexec + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE +) diff --git a/LICENSE b/LICENSE index 6e4a645..d5be6d1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 Termux +Copyright (c) 2017-2021 Termux Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile deleted file mode 100644 index ce7868e..0000000 --- a/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -CFLAGS += -std=c11 -Wall -Wextra -pedantic -Werror -PREFIX ?= /data/data/com.termux/files/usr - -termux-api: termux-api.c - -install: termux-api - mkdir -p $(PREFIX)/bin/ $(PREFIX)/libexec/ - install termux-api $(PREFIX)/libexec/ - install scripts/* $(PREFIX)/bin/ - -.PHONY: install diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..479f15c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1 @@ +Check https://termux.dev/security for info on Termux security policies and how to report vulnerabilities. diff --git a/scripts/termux-api-start.in b/scripts/termux-api-start.in new file mode 100644 index 0000000..f06d91d --- /dev/null +++ b/scripts/termux-api-start.in @@ -0,0 +1,2 @@ +#!@TERMUX_PREFIX@/bin/sh +am startservice -n com.termux.api/.KeepAliveService diff --git a/scripts/termux-api-stop.in b/scripts/termux-api-stop.in new file mode 100644 index 0000000..cf23769 --- /dev/null +++ b/scripts/termux-api-stop.in @@ -0,0 +1,2 @@ +#!@TERMUX_PREFIX@/bin/sh +am stopservice -n com.termux.api/.KeepAliveService diff --git a/scripts/termux-audio-info b/scripts/termux-audio-info.in old mode 100755 new mode 100644 similarity index 75% rename from scripts/termux-audio-info rename to scripts/termux-audio-info.in index 63444af..5add06f --- a/scripts/termux-audio-info +++ b/scripts/termux-audio-info.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-audio-info @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api AudioInfo +@TERMUX_PREFIX@/libexec/termux-api AudioInfo diff --git a/scripts/termux-battery-status b/scripts/termux-battery-status.in old mode 100755 new mode 100644 similarity index 74% rename from scripts/termux-battery-status rename to scripts/termux-battery-status.in index 9e0614c..919535a --- a/scripts/termux-battery-status +++ b/scripts/termux-battery-status.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-battery-status @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api BatteryStatus +@TERMUX_PREFIX@/libexec/termux-api BatteryStatus diff --git a/scripts/termux-brightness b/scripts/termux-brightness.in old mode 100755 new mode 100644 similarity index 75% rename from scripts/termux-brightness rename to scripts/termux-brightness.in index 7ec8647..799cef5 --- a/scripts/termux-brightness +++ b/scripts/termux-brightness.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/bash +#!@TERMUX_PREFIX@/bin/bash set -e -u SCRIPTNAME=termux-brightness @@ -17,10 +17,10 @@ if ! [[ $1 =~ ^([0-9]+)|auto$ ]]; then show_usage fi -if [ $1 == auto ]; then +if [ "$1" == auto ]; then ARGS="--ez auto true" else ARGS="--ei brightness $1 --ez auto false" fi -/data/data/com.termux/files/usr/libexec/termux-api Brightness $ARGS +@TERMUX_PREFIX@/libexec/termux-api Brightness $ARGS diff --git a/scripts/termux-call-log b/scripts/termux-call-log deleted file mode 100755 index 40e3162..0000000 --- a/scripts/termux-call-log +++ /dev/null @@ -1,32 +0,0 @@ -#!/data/data/com.termux/files/usr/bin/bash -set -u - -PARAM_LIMIT=10 -PARAM_OFFSET=0 -PARAMS="" - -SCRIPTNAME=termux-call-log - -show_usage () { - echo "Usage: $SCRIPTNAME [-l limit] [-o offset]" - echo "List call log history" - echo " -l limit offset in call log list (default: $PARAM_LIMIT)" - echo " -o offset offset in call log list (default: $PARAM_OFFSET)" - exit 0 -} - -while getopts :hl:o: option -do - case "$option" in - h) show_usage;; - l) PARAM_LIMIT=$OPTARG;; - o) PARAM_OFFSET=$OPTARG;; - ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; - esac -done -shift $(($OPTIND-1)) - -if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi - -PARAMS="$PARAMS --ei offset $PARAM_OFFSET --ei limit $PARAM_LIMIT" -/data/data/com.termux/files/usr/libexec/termux-api CallLog $PARAMS diff --git a/scripts/termux-call-log.in b/scripts/termux-call-log.in new file mode 100644 index 0000000..0d09d3a --- /dev/null +++ b/scripts/termux-call-log.in @@ -0,0 +1,46 @@ +#!@TERMUX_PREFIX@/bin/bash +set -u + +PARAM_LIMIT_DEFAULT=10 +PARAM_LIMIT="$PARAM_LIMIT_DEFAULT" + +PARAM_OFFSET_DEFAULT=0 +PARAM_OFFSET="$PARAM_OFFSET_DEFAULT" + +PARAMS="" + +SCRIPTNAME=termux-call-log + +validate_is_postive_number() { + if [[ ! "${2:-}" =~ ^[0-9]+$ ]]; then + echo "ERROR: The -$1 value '${2:-}' is not a positive number." 1>&2 + show_usage || return $? + exit 1 + fi +} + +show_usage () { + echo "Usage: $SCRIPTNAME [-l ] [-o ]" + echo "List call log history" + echo " -l limit in call log list (default: $PARAM_LIMIT_DEFAULT)" + echo " -o offset in call log list (default: $PARAM_OFFSET_DEFAULT)" +} + +while getopts :hl:o: option +do + case "$option" in + h) show_usage; exit 0;; + l) PARAM_LIMIT="$OPTARG";; + o) PARAM_OFFSET="$OPTARG";; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +validate_is_postive_number l "$PARAM_LIMIT" +validate_is_postive_number o "$PARAM_OFFSET" + +if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi + +PARAMS="$PARAMS --ei offset $PARAM_OFFSET --ei limit $PARAM_LIMIT" +@TERMUX_PREFIX@/libexec/termux-api CallLog $PARAMS diff --git a/scripts/termux-camera-info b/scripts/termux-camera-info.in old mode 100755 new mode 100644 similarity index 75% rename from scripts/termux-camera-info rename to scripts/termux-camera-info.in index 437d556..32fcbd9 --- a/scripts/termux-camera-info +++ b/scripts/termux-camera-info.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-camera-info @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api CameraInfo +@TERMUX_PREFIX@/libexec/termux-api CameraInfo diff --git a/scripts/termux-camera-photo b/scripts/termux-camera-photo.in old mode 100755 new mode 100644 similarity index 82% rename from scripts/termux-camera-photo rename to scripts/termux-camera-photo.in index 645853d..62d5751 --- a/scripts/termux-camera-photo +++ b/scripts/termux-camera-photo.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-camera-photo @@ -19,12 +19,12 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# = 0 ]; then echo "$SCRIPTNAME: missing file argument"; exit 1; fi if [ $# != 1 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -touch $1 +touch "$1" PARAMS="$PARAMS --es file `realpath $1`" -/data/data/com.termux/files/usr/libexec/termux-api CameraPhoto $PARAMS +@TERMUX_PREFIX@/libexec/termux-api CameraPhoto $PARAMS diff --git a/scripts/termux-clipboard-get b/scripts/termux-clipboard-get.in old mode 100755 new mode 100644 similarity index 74% rename from scripts/termux-clipboard-get rename to scripts/termux-clipboard-get.in index 8a19581..24b9f35 --- a/scripts/termux-clipboard-get +++ b/scripts/termux-clipboard-get.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-clipboard-get @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api Clipboard +@TERMUX_PREFIX@/libexec/termux-api Clipboard diff --git a/scripts/termux-clipboard-set b/scripts/termux-clipboard-set.in old mode 100755 new mode 100644 similarity index 73% rename from scripts/termux-clipboard-set rename to scripts/termux-clipboard-set.in index 45aa84d..c401a7f --- a/scripts/termux-clipboard-set +++ b/scripts/termux-clipboard-set.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-clipboard-set @@ -15,9 +15,9 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) -CMD="/data/data/com.termux/files/usr/libexec/termux-api Clipboard -e api_version 2 --ez set true" +CMD="@TERMUX_PREFIX@/libexec/termux-api Clipboard -e api_version 2 --ez set true" if [ $# = 0 ]; then $CMD else diff --git a/scripts/termux-contact-list b/scripts/termux-contact-list.in old mode 100755 new mode 100644 similarity index 74% rename from scripts/termux-contact-list rename to scripts/termux-contact-list.in index 1dc8014..90b1024 --- a/scripts/termux-contact-list +++ b/scripts/termux-contact-list.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-contact-list @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api ContactList +@TERMUX_PREFIX@/libexec/termux-api ContactList diff --git a/scripts/termux-dialog b/scripts/termux-dialog.in old mode 100755 new mode 100644 similarity index 94% rename from scripts/termux-dialog rename to scripts/termux-dialog.in index 92a4d15..4df392b --- a/scripts/termux-dialog +++ b/scripts/termux-dialog.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/bash +#!@TERMUX_PREFIX@/bin/bash set -e -u DEFAULT_WIDGET="text" @@ -142,7 +142,7 @@ list_widgets() { echo for w in "${widgets[@]}"; do - widget_usage $w + widget_usage "$w" echo done } @@ -183,14 +183,14 @@ parse_options() { options_error () { echo -e "ERROR: Invalid option(s) detected for '$1'\n" echo "Usage '$1'" - widget_usage $1 + widget_usage "$1" exit 1 } if [ $# -eq 0 ]; then WIDGET=$DEFAULT_WIDGET # First argument wasn't a widget -elif ! has_widget $1; then +elif ! has_widget "$1"; then # we didn't receive a widget as an argument, check to see if we # at least options (even if they're illegal) if ! [[ $1 =~ -[a-z] ]]; then @@ -211,35 +211,35 @@ case "$WIDGET" in # Text (default) if no widget specified "text") if [ $((FLAGS & (RANGE_FLAG | VALUES_FLAG))) -ne 0 ]; then - options_error $WIDGET + options_error "$WIDGET" fi if [ $((FLAGS & MULTI_LINE_FLAG)) -ne 0 ] && [ $((FLAGS & NUM_FLAG)) -ne 0 ]; then - options_error $WIDGET + options_error "$WIDGET" fi ;; "confirm") if [ $((FLAGS & (MULTI_LINE_FLAG | PASS_FLAG | RANGE_FLAG | VALUES_FLAG | NUM_FLAG))) -ne 0 ]; then - options_error $WIDGET + options_error "$WIDGET" fi ;; "counter") if [ $((FLAGS & (MULTI_LINE_FLAG | PASS_FLAG | VALUES_FLAG | NUM_FLAG))) -ne 0 ]; then - options_error $WIDGET + options_error "$WIDGET" fi ;; "speech") if [ $((FLAGS & (MULTI_LINE_FLAG | PASS_FLAG | RANGE_FLAG | VALUES_FLAG | NUM_FLAG))) -ne 0 ]; then - options_error $WIDGET + options_error "$WIDGET" fi ;; "date" | "time") if [ $((FLAGS & (HINT_FLAG | MULTI_LINE_FLAG | PASS_FLAG | RANGE_FLAG | VALUES_FLAG | NUM_FLAG))) -ne 0 ]; then - options_error $WIDGET + options_error "$WIDGET" fi ;; @@ -250,7 +250,7 @@ case "$WIDGET" in fi if [ $((FLAGS & (HINT_FLAG | MULTI_LINE_FLAG | PASS_FLAG | RANGE_FLAG | NUM_FLAG))) -ne 0 ]; then - options_error $WIDGET + options_error "$WIDGET" fi ;; @@ -277,4 +277,4 @@ if [ -n "$ARG_P" ]; then set -- "$@" $ARG_P "$OPT_P"; fi if [ -n "$ARG_N" ]; then set -- "$@" $ARG_N "$OPT_N"; fi if [ -n "$ARG_D" ]; then set -- "$@" $ARG_D "$OPT_D"; fi -/data/data/com.termux/files/usr/libexec/termux-api Dialog "$@" +@TERMUX_PREFIX@/libexec/termux-api Dialog "$@" diff --git a/scripts/termux-download b/scripts/termux-download.in old mode 100755 new mode 100644 similarity index 71% rename from scripts/termux-download rename to scripts/termux-download.in index afff2ac..83da2f1 --- a/scripts/termux-download +++ b/scripts/termux-download.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-download @@ -7,6 +7,7 @@ show_usage () { echo "Download a resource using the system download manager." echo " -d description description for the download request notification" echo " -t title title for the download request notification" + echo " -p path full path to which the file should be downloaded" exit 0 } @@ -14,17 +15,20 @@ ARG_D="" OPT_D="" ARG_T="" OPT_T="" +ARG_P="" +OPT_P="" -while getopts :hd:t: option +while getopts :hd:t:p: option do case "$option" in h) show_usage;; d) ARG_D="--es description"; OPT_D="$OPTARG";; t) ARG_T="--es title"; OPT_T="$OPTARG";; + p) ARG_P="--es path"; OPT_P="$OPTARG";; ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# -lt 1 ]; then echo "$SCRIPTNAME: no url specified"; exit 1; fi if [ $# -gt 1 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi @@ -34,6 +38,7 @@ URL_TO_DOWNLOAD="$1" set -- if [ -n "$ARG_D" ]; then set -- "$@" $ARG_D "$OPT_D"; fi if [ -n "$ARG_T" ]; then set -- "$@" $ARG_T "$OPT_T"; fi -set -- "$@" $URL_TO_DOWNLOAD +if [ -n "$ARG_P" ]; then set -- "$@" $ARG_P "$OPT_P"; fi +set -- "$@" "$URL_TO_DOWNLOAD" -/data/data/com.termux/files/usr/libexec/termux-api Download "$@" +@TERMUX_PREFIX@/libexec/termux-api Download "$@" diff --git a/scripts/termux-fingerprint b/scripts/termux-fingerprint deleted file mode 100755 index 48d421b..0000000 --- a/scripts/termux-fingerprint +++ /dev/null @@ -1,26 +0,0 @@ -#!/data/data/com.termux/files/usr/bin/sh -set -e -u - -SCRIPTNAME=termux-fingerprint -show_usage () { - echo "Usage: $SCRIPTNAME" - echo "Use fingerprint sensor on device to check for authentication" - echo "NOTE: Only available on Marshmallow and later" - exit 0 -} - -while getopts :h option -do - case "$option" in - h) show_usage;; - ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; - esac -done -shift $(($OPTIND-1)) - -if [ $# -ne 0 ]; then - echo "$SCRIPTNAME takes no arguments" - exit 1 -fi - -/data/data/com.termux/files/usr/libexec/termux-api Fingerprint diff --git a/scripts/termux-fingerprint.in b/scripts/termux-fingerprint.in new file mode 100644 index 0000000..ecb40b8 --- /dev/null +++ b/scripts/termux-fingerprint.in @@ -0,0 +1,39 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-fingerprint +show_usage () { + echo "Usage: $SCRIPTNAME [-t title] [-d description] [-s subtitle] [-c cancel]" + echo "Use fingerprint sensor on device to check for authentication" + echo "NOTE: Only available on Marshmallow and later" + exit 0 +} + +ARG_T="" +OPT_T="" +ARG_D="" +OPT_D="" +ARG_S="" +OPT_S="" +ARG_C="" +OPT_C="" + +while getopts :ht:d:s:c: option +do + case "$option" in + h) show_usage;; + t) ARG_T="--es title";OPT_T="$OPTARG";; + d) ARG_D="--es description";OPT_D="$OPTARG";; + s) ARG_S="--es subtitle";OPT_S="$OPTARG";; + c) ARG_C="--es cancel";OPT_C="$OPTARG";; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done + +set -- +if [ -n "$ARG_T" ]; then set -- "$@" $ARG_T "$OPT_T"; fi +if [ -n "$ARG_D" ]; then set -- "$@" $ARG_D "$OPT_D"; fi +if [ -n "$ARG_S" ]; then set -- "$@" $ARG_S "$OPT_S"; fi +if [ -n "$ARG_C" ]; then set -- "$@" $ARG_C "$OPT_C"; fi + +@TERMUX_PREFIX@/libexec/termux-api Fingerprint "$@" diff --git a/scripts/termux-infrared-frequencies b/scripts/termux-infrared-frequencies.in old mode 100755 new mode 100644 similarity index 74% rename from scripts/termux-infrared-frequencies rename to scripts/termux-infrared-frequencies.in index ab6b6f4..f7a494c --- a/scripts/termux-infrared-frequencies +++ b/scripts/termux-infrared-frequencies.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-infrared-frequencies @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api InfraredFrequencies +@TERMUX_PREFIX@/libexec/termux-api InfraredFrequencies diff --git a/scripts/termux-infrared-transmit b/scripts/termux-infrared-transmit.in old mode 100755 new mode 100644 similarity index 83% rename from scripts/termux-infrared-transmit rename to scripts/termux-infrared-transmit.in index 8f6fcdb..81c912a --- a/scripts/termux-infrared-transmit +++ b/scripts/termux-infrared-transmit.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-infrared-transmit @@ -18,11 +18,11 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ -z "$FREQUENCY" ]; then echo "$SCRIPTNAME: No frequency specified"; exit 1; fi if [ $# -lt 1 ]; then echo "$SCRIPTNAME: too few arguments"; exit 1; fi if [ $# -gt 1 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api InfraredTransmit $FREQUENCY --eia pattern $1 +@TERMUX_PREFIX@/libexec/termux-api InfraredTransmit $FREQUENCY --eia pattern $1 diff --git a/scripts/termux-job-scheduler b/scripts/termux-job-scheduler.in old mode 100755 new mode 100644 similarity index 79% rename from scripts/termux-job-scheduler rename to scripts/termux-job-scheduler.in index 3e6e82f..26c9ec1 --- a/scripts/termux-job-scheduler +++ b/scripts/termux-job-scheduler.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/bash +#!@TERMUX_PREFIX@/bin/bash set -e -u -f SCRIPTNAME=termux-job-scheduler @@ -6,17 +6,19 @@ SCRIPTNAME=termux-job-scheduler show_usage () { echo "Usage: termux-job-scheduler [options]" echo "Schedule a script to run at specified intervals." - echo " --pending list pending jobs and exit (default false)" - echo " --cancel-all boolean cancel all pending jobs and exit (default false)" - echo " --cancel boolean cancel given job-id and exit (default false)" + echo " -p/--pending list pending jobs and exit" + echo " --cancel-all cancel all pending jobs and exit" + echo " --cancel cancel given job-id and exit" echo "Options for scheduling:" - echo " --script text path to the script to be called" + echo " -s/--script path path to the script to be called" echo " --job-id int job id (will overwrite any previous job with the same id)" - echo " --period-ms int schedule job approximately every period-ms milliseconds (default 0 means once)" + echo " --period-ms int schedule job approximately every period-ms milliseconds (default 0 means once)." + echo " Note that since Android N, the minimum period is 900,000ms (15 minutes)." echo " --network text run only when this type of network available (default any): any|unmetered|cellular|not_roaming|none" echo " --battery-not-low boolean run only when battery is not low, default true (at least Android O)" echo " --storage-not-low boolean run only when storage is not low, default false (at least Android O)" echo " --charging boolean run only when charging, default false" + echo " --persisted boolean should the job survive reboots, default false" echo " --trigger-content-uri text (at least Android N)" echo " --trigger-content-flag int default 1, (at least Android N)" exit 0 @@ -33,10 +35,11 @@ OPT_NETWORK="" OPT_BATTERY_NOT_LOW="" OPT_STORAGE_NOT_LOW="" OPT_CHARGING="" +OPT_PERSISTED="" OPT_TRIGGER_CONTENT_URI="" OPT_TRIGGER_CONTENT_FLAG="" -TEMP=`busybox getopt \ +TEMP=`getopt \ -n $SCRIPTNAME \ -o hs:p \ --long script:,\ @@ -44,8 +47,8 @@ job-id:,pending,\ cancel,cancel-all,\ period-ms:,network:,\ battery-not-low:,storage-not-low:,\ -charging:,help,\ -trigger_content_flag:,trigger-content-uri: \ +charging:,persisted:,help,\ +trigger-content-flag:,trigger-content-uri: \ -s bash \ -- "$@"` eval set -- "$TEMP" @@ -62,6 +65,7 @@ while true; do --battery-not-low) OPT_BATTERY_NOT_LOW="$2"; shift 2;; --storage-not-low) OPT_STORAGE_NOT_LOW="$2"; shift 2;; --charging) OPT_CHARGING="$2"; shift 2;; + --persisted) OPT_PERSISTED="$2"; shift 2;; --trigger-content-flag) OPT_TRIGGER_CONTENT_FLAG="$2"; shift 2;; --trigger-content-uri) OPT_TRIGGER_CONTENT_URI="$2"; shift 2;; -h | --help) show_usage;; @@ -82,7 +86,8 @@ if [ -n "$OPT_NETWORK" ]; then set -- "$@" --es network "$OPT_NETWORK"; fi if [ -n "$OPT_BATTERY_NOT_LOW" ]; then set -- "$@" --ez battery_not_low "$OPT_BATTERY_NOT_LOW"; fi if [ -n "$OPT_STORAGE_NOT_LOW" ]; then set -- "$@" --ez storage_not_low "$OPT_STORAGE_NOT_LOW"; fi if [ -n "$OPT_CHARGING" ]; then set -- "$@" --ez charging "$OPT_CHARGING"; fi +if [ -n "$OPT_PERSISTED" ]; then set -- "$@" --ez persisted "$OPT_PERSISTED"; fi if [ -n "$OPT_TRIGGER_CONTENT_URI" ]; then set -- "$@" --es trigger_content_uri "$OPT_TRIGGER_CONTENT_URI"; fi if [ -n "$OPT_TRIGGER_CONTENT_FLAG" ]; then set -- "$@" --ez trigger_content_flag "$OPT_TRIGGER_CONTENT_FLAG"; fi -/data/data/com.termux/files/usr/libexec/termux-api JobScheduler "$@" +@TERMUX_PREFIX@/libexec/termux-api JobScheduler "$@" diff --git a/scripts/termux-keystore b/scripts/termux-keystore.in old mode 100755 new mode 100644 similarity index 95% rename from scripts/termux-keystore rename to scripts/termux-keystore.in index 66a69e1..d6d7ccc --- a/scripts/termux-keystore +++ b/scripts/termux-keystore.in @@ -1,7 +1,7 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u -readonly CMD_BASE="/data/data/com.termux/files/usr/libexec/termux-api Keystore" +readonly CMD_BASE="@TERMUX_PREFIX@/libexec/termux-api Keystore" SCRIPTNAME=termux-keystore show_usage () { @@ -109,7 +109,7 @@ generate_key () { # purpose 12 is SIGN+VERIFY $CMD_BASE -e command generate -e alias "$ALIAS" -e algorithm "$ALGORITHM" \ - --ei purposes 12 --esa digests SHA-1,SHA-256,SHA-384,SHA-512 \ + --ei purposes 12 --esa digests NONE,SHA-1,SHA-256,SHA-384,SHA-512 \ --ei size "$SIZE" -e curve "$CURVE" --ei validity "$VALIDITY" } diff --git a/scripts/termux-location b/scripts/termux-location.in old mode 100755 new mode 100644 similarity index 77% rename from scripts/termux-location rename to scripts/termux-location.in index b02956e..7c9eb96 --- a/scripts/termux-location +++ b/scripts/termux-location.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-location @@ -36,13 +36,13 @@ while getopts :hr:p: option do case "$option" in h) show_usage;; - r) validate_request $OPTARG; PARAMS="$PARAMS --es request $OPTARG";; - p) validate_provider $OPTARG; PARAMS="$PARAMS --es provider $OPTARG";; + r) validate_request "$OPTARG"; PARAMS="$PARAMS --es request $OPTARG";; + p) validate_provider "$OPTARG"; PARAMS="$PARAMS --es provider $OPTARG";; ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api Location $PARAMS +@TERMUX_PREFIX@/libexec/termux-api Location $PARAMS diff --git a/scripts/termux-media-player b/scripts/termux-media-player.in old mode 100755 new mode 100644 similarity index 91% rename from scripts/termux-media-player rename to scripts/termux-media-player.in index 800c962..31bde86 --- a/scripts/termux-media-player +++ b/scripts/termux-media-player.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/bash +#!@TERMUX_PREFIX@/bin/bash set -e SCRIPTNAME=termux-media-player @@ -15,7 +15,7 @@ show_usage () { } main() { - /data/data/com.termux/files/usr/libexec/termux-api MediaPlayer "$@" + @TERMUX_PREFIX@/libexec/termux-api MediaPlayer "$@" } case "$1" in diff --git a/scripts/termux-media-scan b/scripts/termux-media-scan.in old mode 100755 new mode 100644 similarity index 82% rename from scripts/termux-media-scan rename to scripts/termux-media-scan.in index f2d8c2f..0211529 --- a/scripts/termux-media-scan +++ b/scripts/termux-media-scan.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/bash +#!@TERMUX_PREFIX@/bin/bash set -e -u SCRIPTNAME=termux-media-scan @@ -18,7 +18,7 @@ get_paths() { if [[ "$ARG" =~ ^/ ]]; then echo "$ARG" else - echo "`pwd`/$ARG" + echo "$(pwd)/$ARG" fi fi done @@ -34,9 +34,9 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# = 0 ]; then echo "$SCRIPTNAME: missing file argument"; exit 1; fi PATHS=`get_paths "$@" | sed ':a;N;$!ba;s/,/\\\\,/g;s/\n/,/g'` -/data/data/com.termux/files/usr/libexec/termux-api MediaScanner $PARAMS "$PATHS" +@TERMUX_PREFIX@/libexec/termux-api MediaScanner $PARAMS "$PATHS" diff --git a/scripts/termux-microphone-record b/scripts/termux-microphone-record.in old mode 100755 new mode 100644 similarity index 94% rename from scripts/termux-microphone-record rename to scripts/termux-microphone-record.in index 9efb0d7..2cb7b39 --- a/scripts/termux-microphone-record +++ b/scripts/termux-microphone-record.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/bash +#!@TERMUX_PREFIX@/bin/bash set -e SCRIPTNAME=termux-microphone-record @@ -11,7 +11,7 @@ show_usage () { echo "-d Start recording w/ defaults" echo "-f Start recording to specific file" echo "-l Start recording w/ specified limit (in seconds, unlimited for 0)" - echo "-e Start recording w/ specified encoder (aac, amr_wb, amr_nb)" + echo "-e Start recording w/ specified encoder (aac, amr_wb, amr_nb, opus)" echo "-b Start recording w/ specified bitrate (in kbps)" echo "-r Start recording w/ specified sampling rate (in Hz)" echo "-c Start recording w/ specified channel count (1, 2, ...)" @@ -39,7 +39,7 @@ add_params() { } call_api () { - /data/data/com.termux/files/usr/libexec/termux-api MicRecorder "$@" + @TERMUX_PREFIX@/libexec/termux-api MicRecorder "$@" } while getopts h,f:,l:,e:,b:,r:,c:,d,i,q option diff --git a/scripts/termux-nfc.in b/scripts/termux-nfc.in new file mode 100644 index 0000000..b1b26c1 --- /dev/null +++ b/scripts/termux-nfc.in @@ -0,0 +1,47 @@ +#!@TERMUX_PREFIX@/bin/bash + +set -e -u + +show_usage() { + echo "Usage: termux-nfc [-r [short|full]] [-w] [-t [text for TAG] " + echo " read/write data from/to NDEF tag " + echo " -r, read tag " + echo " short, read short information from tag " + echo " full, read full information from tag " + echo " -w, write information on tag " + echo " -t, text for tag" + exit 0 +} + +ARG_R="" +OPT_R="" +ARG_W="" +OPT_T="" +ARG_T="" + +PARAM="" + +if [ $# -eq 0 ];then show_usage;fi + +while getopts ":r:t:w" opt +do + case "$opt" in + r) ARG_R="--es mode read"; OPT_R="--es param $OPTARG"; ;; + w) ARG_W="--es mode write";; + t) ARG_T="--es param text --es value"; OPT_T="$OPTARG"; ;; + ?) echo "Error: unknown parameters: $opt $OPTARG;";show_usage; ;; + esac +done + + +shift $((OPTIND-1)) + +if [ "$#" != 0 ]; then echo "Error: too many parameters!"; show_usage;fi +if [ -n "$ARG_R" ]; then if [ -n "$ARG_W" ]; then echo "Error: Incompatible parameters! \"-r and \"-n";show_usage;fi;fi + + + +if [ -n "$ARG_R" ]; then set -- "$@" $ARG_R $OPT_R;fi +if [ -n "$ARG_W" ]; then set -- "$@" $ARG_W;fi +if [ -n "$ARG_T" ]; then set -- "$@" $ARG_T "$OPT_T";fi +@TERMUX_PREFIX@/libexec/termux-api Nfc "$@" diff --git a/scripts/termux-notification b/scripts/termux-notification deleted file mode 100644 index 6ad3358..0000000 --- a/scripts/termux-notification +++ /dev/null @@ -1,150 +0,0 @@ -#!/data/data/com.termux/files/usr/bin/bash -set -e -u -f - -SCRIPTNAME=termux-notification -show_usage () { - echo "Usage: termux-notification [options]" - echo "Display a system notification. Content text is read from stdin or specified using --content." - echo " --action action action to execute when pressing the notification" - echo " --alert-once do not alert when the notification is edited" - echo " --button1 text text to show on the first notification button" - echo " --button1-action action action to execute on the first notification button" - echo " --button2 text text to show on the second notification button" - echo " --button2-action action action to execute on the second notification button" - echo " --button3 text text to show on the third notification button" - echo " --button3-action action action to execute on the third notification button" - echo " --content content content to show in the notification. Will take precedence over stdin." - echo " --group group notification group (notifications with the same group are shown together)" - echo " --id id notification id (will overwrite any previous notification with the same id)" - echo " --image-path path absolute path to an image which will be shown in the notification" - echo " --led-color rrggbb color of the blinking led as RRGGBB (default: none)" - echo " --led-off milliseconds number of milliseconds for the LED to be off while it's flashing (default: 800)" - echo " --led-on milliseconds number of milliseconds for the LED to be on while it's flashing (default: 800)" - echo " --on-delete action action to execute when the the notification is cleared" - echo " --ongoing pin the notification" - echo " --priority prio notification priority (high/low/max/min/default)" - echo " --sound play a sound with the notification" - echo " --title title notification title to show" - echo " --vibrate pattern vibrate pattern, comma separated as in 500,1000,200" - echo " --type type notification style to use (default/media)" - echo "Media actions (available with --type \"media\"):" - echo " --media-next action to execute on the media-next button" - echo " --media-pause action to execute on the media-pause button" - echo " --media-play action to execute on the media-play button" - echo " --media-previous action to execute on the media-previous button" - exit 0 -} - -OPT_ACTION="" -OPT_ALERT_ONCE="" -OPT_BUTTON1_ACTION="" -OPT_BUTTON1_TEXT="" -OPT_BUTTON2_ACTION="" -OPT_BUTTON2_TEXT="" -OPT_BUTTON3_ACTION="" -OPT_BUTTON3_TEXT="" -OPT_CONTENT="" -OPT_GROUP="" -OPT_ID="" -OPT_IMAGE_PATH="" -OPT_LED_COLOR="" -OPT_LED_OFF="" -OPT_LED_ON="" -OPT_MEDIA_NEXT="" -OPT_MEDIA_PAUSE="" -OPT_MEDIA_PLAY="" -OPT_MEDIA_PREVIOUS="" -OPT_ONGOING="" -OPT_ON_DELETE_ACTION="" -OPT_PRIORITY="" -OPT_SOUND="" -OPT_TITLE="" -OPT_TYPE="" -OPT_VIBRATE="" - -TEMP=`busybox getopt \ - -n $SCRIPTNAME \ - -o hc:i:t: \ - --long action:,alert-once,\ -button1:,button1-action:,\ -button2:,button2-action:,\ -button3:,button3-action:,\ -content:,group:,help,id:,image-path:\ -led-color:,led-on:,led-off:,\ -media-previous:,media-next:,media-play:,media-pause:,\ -on-delete:,ongoing,\ -priority:,\ -sound,title:,type:,vibrate: \ - -s bash \ - -- "$@"` -eval set -- "$TEMP" - -while true; do - case "$1" in - --action) OPT_ACTION="$2"; shift 2;; - --alert-once) OPT_ALERT_ONCE="true"; shift 1;; - --button1) OPT_BUTTON1_TEXT="$2"; shift 2;; - --button1-action) OPT_BUTTON1_ACTION="$2"; shift 2;; - --button2) OPT_BUTTON2_TEXT="$2"; shift 2;; - --button2-action) OPT_BUTTON2_ACTION="$2"; shift 2;; - --button3) OPT_BUTTON3_TEXT="$2"; shift 2;; - --button3-action) OPT_BUTTON3_ACTION="$2"; shift 2;; - -c | --content) OPT_CONTENT="$2"; shift 2;; - --group) OPT_GROUP="$2"; shift 2;; - -h | --help) show_usage;; - -i | --id) OPT_ID="$2"; shift 2;; - --image-path) OPT_IMAGE_PATH="$2"; shift 2;; - --led-color) OPT_LED_COLOR="$2"; shift 2;; - --led-off) OPT_LED_OFF="$2"; shift 2;; - --led-on) OPT_LED_ON="$2"; shift 2;; - --media-next) OPT_MEDIA_NEXT="$2"; shift 2;; - --media-pause) OPT_MEDIA_PAUSE="$2"; shift 2;; - --media-play) OPT_MEDIA_PLAY="$2"; shift 2;; - --media-previous) OPT_MEDIA_PREVIOUS="$2"; shift 2;; - --on-delete) OPT_ON_DELETE_ACTION="$2"; shift 2;; - --ongoing) OPT_ONGOING="true"; shift 1;; - --priority) OPT_PRIORITY="$2"; shift 2;; - --sound) OPT_SOUND="true"; shift 1;; - -t | --title) OPT_TITLE="$2"; shift 2;; - --type) OPT_TYPE="$2"; shift 2;; - --vibrate) OPT_VIBRATE="$2"; shift 2;; - --) shift; break ;; - esac -done - -if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi - -set -- -if [ -n "$OPT_ACTION" ]; then set -- "$@" --es action "$OPT_ACTION"; fi -if [ -n "$OPT_ALERT_ONCE" ]; then set -- "$@" --ez alert-once "$OPT_ALERT_ONCE"; fi -if [ -n "$OPT_BUTTON1_ACTION" ]; then set -- "$@" --es button_action_1 "$OPT_BUTTON1_ACTION"; fi -if [ -n "$OPT_BUTTON1_TEXT" ]; then set -- "$@" --es button_text_1 "$OPT_BUTTON1_TEXT"; fi -if [ -n "$OPT_BUTTON2_ACTION" ]; then set -- "$@" --es button_action_2 "$OPT_BUTTON2_ACTION"; fi -if [ -n "$OPT_BUTTON2_TEXT" ]; then set -- "$@" --es button_text_2 "$OPT_BUTTON2_TEXT"; fi -if [ -n "$OPT_BUTTON3_ACTION" ]; then set -- "$@" --es button_action_3 "$OPT_BUTTON3_ACTION"; fi -if [ -n "$OPT_BUTTON3_TEXT" ]; then set -- "$@" --es button_text_3 "$OPT_BUTTON3_TEXT"; fi -if [ -n "$OPT_GROUP" ]; then set -- "$@" --es group "$OPT_GROUP"; fi -if [ -n "$OPT_ID" ]; then set -- "$@" --es id "$OPT_ID"; fi -if [ -n "$OPT_IMAGE_PATH" ]; then set -- "$@" --es image-path "$OPT_IMAGE_PATH"; fi -if [ -n "$OPT_LED_COLOR" ]; then set -- "$@" --es led-color "$OPT_LED_COLOR"; fi -if [ -n "$OPT_LED_OFF" ]; then set -- "$@" --ei led-off "$OPT_LED_OFF"; fi -if [ -n "$OPT_LED_ON" ]; then set -- "$@" --ei led-on "$OPT_LED_ON"; fi -if [ -n "$OPT_MEDIA_NEXT" ]; then set -- "$@" --es media-next "$OPT_MEDIA_NEXT"; fi -if [ -n "$OPT_MEDIA_PAUSE" ]; then set -- "$@" --es media-pause "$OPT_MEDIA_PAUSE"; fi -if [ -n "$OPT_MEDIA_PLAY" ]; then set -- "$@" --es media-play "$OPT_MEDIA_PLAY"; fi -if [ -n "$OPT_MEDIA_PREVIOUS" ]; then set -- "$@" --es media-previous "$OPT_MEDIA_PREVIOUS"; fi -if [ -n "$OPT_ONGOING" ]; then set -- "$@" --ez ongoing "$OPT_ONGOING"; fi -if [ -n "$OPT_ON_DELETE_ACTION" ]; then set -- "$@" --es on_delete_action "$OPT_ON_DELETE_ACTION"; fi -if [ -n "$OPT_PRIORITY" ]; then set -- "$@" --es priority "$OPT_PRIORITY"; fi -if [ -n "$OPT_SOUND" ]; then set -- "$@" --ez sound "$OPT_SOUND"; fi -if [ -n "$OPT_TITLE" ]; then set -- "$@" --es title "$OPT_TITLE"; fi -if [ -n "$OPT_TYPE" ]; then set -- "$@" --es type "$OPT_TYPE"; fi -if [ -n "$OPT_VIBRATE" ]; then set -- "$@" --ela vibrate "$OPT_VIBRATE"; fi - -if [ -n "$OPT_CONTENT" ] || [ -t 0 ]; then - # we either have some content, so it takes precedence over STDIN - # or have no STDIN, so we must use content even if empty - echo "$OPT_CONTENT" | /data/data/com.termux/files/usr/libexec/termux-api Notification "$@" -else # use STDIN - /data/data/com.termux/files/usr/libexec/termux-api Notification "$@" -fi diff --git a/scripts/termux-notification-channel.in b/scripts/termux-notification-channel.in new file mode 100644 index 0000000..1fa91d3 --- /dev/null +++ b/scripts/termux-notification-channel.in @@ -0,0 +1,37 @@ +#!@TERMUX_PREFIX@/bin/bash +set -e -u + +SCRIPTNAME=termux-notification-channel +show_usage () { + echo "Usage: $SCRIPTNAME -d channel-id" + echo " $SCRIPTNAME channel-id channel-name" + echo "Create or delete a notification channel." + echo "Only usable on Android 8.0 and higher." + echo "Use -d to delete a channel." + echo "Creating a channel requires a channel id and a channel name." + echo "The name will be visible in the options, the id is used to send notifications on that specific channel." + echo "Creating a channel with the same id again will change the name." + echo "Creating a channel with the same id as a deleted channel will restore the user settings of the deleted channel." + echo "Use termux-notification --channel channel-id to send a notification on a custom channel." + exit 0 +} + +ARGS="" + +if [ "$1" = "-d" ]; then + shift + if [ $# == 1 ]; then + ARGS="--ez delete true --es id $1" + else + show_usage + fi +else + if [ $# == 2 ]; then + ARGS="--es id $1 --es name $2" + else + show_usage + fi +fi + + +@TERMUX_PREFIX@/libexec/termux-api NotificationChannel $ARGS diff --git a/scripts/termux-notification-list b/scripts/termux-notification-list.in old mode 100755 new mode 100644 similarity index 75% rename from scripts/termux-notification-list rename to scripts/termux-notification-list.in index ef2de02..2015197 --- a/scripts/termux-notification-list +++ b/scripts/termux-notification-list.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-notification-list @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api NotificationList +@TERMUX_PREFIX@/libexec/termux-api NotificationList diff --git a/scripts/termux-notification-remove b/scripts/termux-notification-remove.in old mode 100755 new mode 100644 similarity index 75% rename from scripts/termux-notification-remove rename to scripts/termux-notification-remove.in index 8146ed2..62b1c9d --- a/scripts/termux-notification-remove +++ b/scripts/termux-notification-remove.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-notification-remove @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 1 ]; then echo "$SCRIPTNAME: no notification id specified"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api NotificationRemove --es id $1 +@TERMUX_PREFIX@/libexec/termux-api NotificationRemove --es id "$1" diff --git a/scripts/termux-notification.in b/scripts/termux-notification.in new file mode 100644 index 0000000..61ee10b --- /dev/null +++ b/scripts/termux-notification.in @@ -0,0 +1,215 @@ +#!@TERMUX_PREFIX@/bin/bash +set -e -u -f + +SCRIPTNAME=termux-notification +show_usage () { + echo "Usage: termux-notification [options]" + echo "Display a system notification. Content text is specified using -c/--content or read from stdin." + echo "Please read --help-actions for help with action arguments." + echo " --action action action to execute when pressing the notification" + echo " --alert-once do not alert when the notification is edited" + echo " --button1 text text to show on the first notification button" + echo " --button1-action action action to execute on the first notification button" + echo " --button2 text text to show on the second notification button" + echo " --button2-action action action to execute on the second notification button" + echo " --button3 text text to show on the third notification button" + echo " --button3-action action action to execute on the third notification button" + echo " -c/--content content content to show in the notification. Will take" + echo " precedence over stdin. If content is not passed as" + echo " an argument or with stdin, then there will be a 3s delay." + echo " --channel channel-id Specifies the notification channel id this notification should be send on." + echo " On Android versions lower than 8.0 this is a no-op." + echo " Create custom channels with termux-notification-channel." + echo " If the channel id is invalid, the notification will not be send." + echo " --group group notification group (notifications with the same" + echo " group are shown together)" + echo " -h/--help show this help" + echo " --help-actions show the help for actions" + echo " -i/--id id notification id (will overwrite any previous notification" + echo " with the same id)" + echo " --icon icon-name set the icon that shows up in the status bar. View" + echo " available icons at https://material.io/resources/icons/" + echo " (default icon: event_note)" + echo " --image-path path absolute path to an image which will be shown in the" + echo " notification" + echo " --led-color rrggbb color of the blinking led as RRGGBB (default: none)" + echo " --led-off milliseconds number of milliseconds for the LED to be off while" + echo " it's flashing (default: 800)" + echo " --led-on milliseconds number of milliseconds for the LED to be on while" + echo " it's flashing (default: 800)" + echo " --on-delete action action to execute when the the notification is cleared" + echo " --ongoing pin the notification" + echo " --priority prio notification priority (high/low/max/min/default)" + echo " --sound play a sound with the notification" + echo " -t/--title title notification title to show" + echo " --vibrate pattern vibrate pattern, comma separated as in 500,1000,200" + echo " --type type notification style to use (default/media)" + echo "Media actions (available with --type \"media\"):" + echo " --media-next action to execute on the media-next button" + echo " --media-pause action to execute on the media-pause button" + echo " --media-play action to execute on the media-play button" + echo " --media-previous action to execute on the media-previous button" + exit 0 +} + +show_help_actions () { + echo "This help refers to the arguments to options like --action, --on-delete, --button-1-action and --media-next." + echo + echo "All these commands take an action string as their argument, which is fed to \`dash -c\`." + echo "A few important things must be kept in mind when using actions:" + echo + echo "You should use actions that do things outside of the terminal, like --action \"termux-toast hello\"." + echo "Anything that outputs to the terminal is useless, so the output should either be redirected (--action \"ls > ~/ls.txt\") or shown to the user in a different way (--action \"ls|termux-toast\")." + echo + echo "Running more than one command in a single action is as easy as" + echo "--action \"command1; command2; command3\"" + echo "or" + echo "--action \"if [ -e file ]; then termux-toast yes; else termux-toast no; fi\"." + echo + echo "For anything more complex, you should put your script in a file, make it executable, and use that as the action:" + echo "--action ~/bin/script" + echo + echo "The action is run in a different environment (not a subshell). Thus your environment is lost (most notably \$PATH), and ~/.profile is not sourced either. So if you need your \$PATH you should either:" + echo " - if the action is a script, set it explicitly in the script (e.g. export PATH=\"\$HOME/bin:\$PATH\")" + echo " - or use something like --action \"bash -l -c 'command1; command2'\")." + echo + echo "On Android N or above, you can use the special variable \$REPLY in your actions to use Android's Direct Reply feature." + echo "This prompts the user to enter some text directly in the notification, which is then substituted into your action." + echo " - termux-notification --button1 \"Answer\" --button1-action \"termux-toast \\\$REPLY\"" + echo "will call the action:" + echo " - termux-toast \"Some text entered by the user\"" + echo "Be careful to escape shell commands correctly for single or double quotes, e.g." + echo " --button1-action 'something \$REPLY' or --button1-action \"something \\\$REPLY\"" +} + +OPT_ACTION="" +OPT_ALERT_ONCE="" +OPT_BUTTON1_ACTION="" +OPT_BUTTON1_TEXT="" +OPT_BUTTON2_ACTION="" +OPT_BUTTON2_TEXT="" +OPT_BUTTON3_ACTION="" +OPT_BUTTON3_TEXT="" +OPT_CONTENT="" +OPT_CONTENT_PASSED="" +OPT_CHANNEL="" +OPT_GROUP="" +OPT_ID="" +OPT_ICON="" +OPT_IMAGE_PATH="" +OPT_LED_COLOR="" +OPT_LED_OFF="" +OPT_LED_ON="" +OPT_MEDIA_NEXT="" +OPT_MEDIA_PAUSE="" +OPT_MEDIA_PLAY="" +OPT_MEDIA_PREVIOUS="" +OPT_ONGOING="" +OPT_ON_DELETE_ACTION="" +OPT_PRIORITY="" +OPT_SOUND="" +OPT_TITLE="" +OPT_TYPE="" +OPT_VIBRATE="" + +TEMP=`getopt \ + -n $SCRIPTNAME \ + -o hc:i:t: \ + --long action:,alert-once,\ +button1:,button1-action:,\ +button2:,button2-action:,\ +button3:,button3-action:,\ +content:,channel:,group:,help,help-actions,\ +id:,icon:,image-path:,\ +led-color:,led-on:,led-off:,\ +media-previous:,media-next:,media-play:,media-pause:,\ +on-delete:,ongoing,\ +priority:,\ +sound,title:,type:,vibrate: \ + -s bash \ + -- "$@"` +eval set -- "$TEMP" + +while true; do + case "$1" in + --action) OPT_ACTION="$2"; shift 2;; + --alert-once) OPT_ALERT_ONCE="true"; shift 1;; + --button1) OPT_BUTTON1_TEXT="$2"; shift 2;; + --button1-action) OPT_BUTTON1_ACTION="$2"; shift 2;; + --button2) OPT_BUTTON2_TEXT="$2"; shift 2;; + --button2-action) OPT_BUTTON2_ACTION="$2"; shift 2;; + --button3) OPT_BUTTON3_TEXT="$2"; shift 2;; + --button3-action) OPT_BUTTON3_ACTION="$2"; shift 2;; + -c | --content) OPT_CONTENT_PASSED=1; OPT_CONTENT="$2"; shift 2;; + --channel) OPT_CHANNEL="$2"; shift 2;; + --group) OPT_GROUP="$2"; shift 2;; + -h | --help) show_usage;; + --help-actions) show_help_actions; exit 0;; + -i | --id) OPT_ID="$2"; shift 2;; + --icon) OPT_ICON="$2"; shift 2;; + --image-path) OPT_IMAGE_PATH="$2"; shift 2;; + --led-color) OPT_LED_COLOR="$2"; shift 2;; + --led-off) OPT_LED_OFF="$2"; shift 2;; + --led-on) OPT_LED_ON="$2"; shift 2;; + --media-next) OPT_MEDIA_NEXT="$2"; shift 2;; + --media-pause) OPT_MEDIA_PAUSE="$2"; shift 2;; + --media-play) OPT_MEDIA_PLAY="$2"; shift 2;; + --media-previous) OPT_MEDIA_PREVIOUS="$2"; shift 2;; + --on-delete) OPT_ON_DELETE_ACTION="$2"; shift 2;; + --ongoing) OPT_ONGOING="true"; shift 1;; + --priority) OPT_PRIORITY="$2"; shift 2;; + --sound) OPT_SOUND="true"; shift 1;; + -t | --title) OPT_TITLE="$2"; shift 2;; + --type) OPT_TYPE="$2"; shift 2;; + --vibrate) OPT_VIBRATE="$2"; shift 2;; + --) shift; break ;; + esac +done + +if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi + +if [ "$OPT_ONGOING" == true ] && [ -z "$OPT_ID" ]; then + echo "Ongoing notifications without an ID are not removable." + echo "Please set an id with --id \"string\"." + exit 1 +fi + +set -- +if [ -n "$OPT_ACTION" ]; then set -- "$@" --es action "$OPT_ACTION"; fi +if [ -n "$OPT_ALERT_ONCE" ]; then set -- "$@" --ez alert-once "$OPT_ALERT_ONCE"; fi +if [ -n "$OPT_BUTTON1_ACTION" ]; then set -- "$@" --es button_action_1 "$OPT_BUTTON1_ACTION"; fi +if [ -n "$OPT_BUTTON1_TEXT" ]; then set -- "$@" --es button_text_1 "$OPT_BUTTON1_TEXT"; fi +if [ -n "$OPT_BUTTON2_ACTION" ]; then set -- "$@" --es button_action_2 "$OPT_BUTTON2_ACTION"; fi +if [ -n "$OPT_BUTTON2_TEXT" ]; then set -- "$@" --es button_text_2 "$OPT_BUTTON2_TEXT"; fi +if [ -n "$OPT_BUTTON3_ACTION" ]; then set -- "$@" --es button_action_3 "$OPT_BUTTON3_ACTION"; fi +if [ -n "$OPT_BUTTON3_TEXT" ]; then set -- "$@" --es button_text_3 "$OPT_BUTTON3_TEXT"; fi +if [ -n "$OPT_CHANNEL" ]; then set -- "$@" --es channel "$OPT_CHANNEL"; fi +if [ -n "$OPT_GROUP" ]; then set -- "$@" --es group "$OPT_GROUP"; fi +if [ -n "$OPT_ID" ]; then set -- "$@" --es id "$OPT_ID"; fi +if [ -n "$OPT_ICON" ]; then set -- "$@" --es icon "$OPT_ICON"; fi +if [ -n "$OPT_IMAGE_PATH" ]; then set -- "$@" --es image-path "$OPT_IMAGE_PATH"; fi +if [ -n "$OPT_LED_COLOR" ]; then set -- "$@" --es led-color "$OPT_LED_COLOR"; fi +if [ -n "$OPT_LED_OFF" ]; then set -- "$@" --ei led-off "$OPT_LED_OFF"; fi +if [ -n "$OPT_LED_ON" ]; then set -- "$@" --ei led-on "$OPT_LED_ON"; fi +if [ -n "$OPT_MEDIA_NEXT" ]; then set -- "$@" --es media-next "$OPT_MEDIA_NEXT"; fi +if [ -n "$OPT_MEDIA_PAUSE" ]; then set -- "$@" --es media-pause "$OPT_MEDIA_PAUSE"; fi +if [ -n "$OPT_MEDIA_PLAY" ]; then set -- "$@" --es media-play "$OPT_MEDIA_PLAY"; fi +if [ -n "$OPT_MEDIA_PREVIOUS" ]; then set -- "$@" --es media-previous "$OPT_MEDIA_PREVIOUS"; fi +if [ -n "$OPT_ONGOING" ]; then set -- "$@" --ez ongoing "$OPT_ONGOING"; fi +if [ -n "$OPT_ON_DELETE_ACTION" ]; then set -- "$@" --es on_delete_action "$OPT_ON_DELETE_ACTION"; fi +if [ -n "$OPT_PRIORITY" ]; then set -- "$@" --es priority "$OPT_PRIORITY"; fi +if [ -n "$OPT_SOUND" ]; then set -- "$@" --ez sound "$OPT_SOUND"; fi +if [ -n "$OPT_TITLE" ]; then set -- "$@" --es title "$OPT_TITLE"; fi +if [ -n "$OPT_TYPE" ]; then set -- "$@" --es type "$OPT_TYPE"; fi +if [ -n "$OPT_VIBRATE" ]; then set -- "$@" --ela vibrate "$OPT_VIBRATE"; fi + +# If content was not passed as an argument, then attempt to read from STDIN with a 3s timeout +# Content argumOPT_CONTENT="$(echo "$OPT_CONTENT")" # trim trailing newlinesent takes precedence over STDIN +if [[ "$OPT_CONTENT_PASSED" != "1" ]]; then + set +e; IFS= read -t 3 -r -d '' OPT_CONTENT; set -e; +fi + +# Trim trailing newlines +OPT_CONTENT="$(echo "$OPT_CONTENT")" + +echo "$OPT_CONTENT" | @TERMUX_PREFIX@/libexec/termux-api Notification "$@" diff --git a/scripts/termux-saf-create.in b/scripts/termux-saf-create.in new file mode 100644 index 0000000..8b50e16 --- /dev/null +++ b/scripts/termux-saf-create.in @@ -0,0 +1,33 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-saf-create +show_usage () { + echo "Usage: $SCRIPTNAME [-t mime-type] folder-uri name" + echo "Creates a file in a folder managed by Termux:API." + echo "Returns the URI you can use to read and write the file with termux-saf-read and termux-saf-write." + echo "You can specify the mime type explicitly or let it be guessed based on the file extension." + echo "As the folder URI you can use the URI of a directory listed by termux-saf-dirs or by termux-saf-ls." + echo "Android doesn't allow creating files with the same name, so the name may be changed if a file or folder with that name already exists." + echo "You can use termux-saf-stat with the returned URI to get the name it was really given." + echo " -h show this help" + echo " -t specify the mime type of the file. The mime type is required for other apps to recognize the content as e.g. a video. If not specified, 'application/octet-stream' is assumed, that means raw binary data." + exit 0 +} + +mime='' + +while getopts :ht: option +do + case "$option" in + h) show_usage;; + t) mime="$OPTARG";; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ $# != 2 ]; then echo "$SCRIPTNAME: Invalid argument count"; exit 1; fi + +@TERMUX_PREFIX@/libexec/termux-api SAF --es safmethod createDocument --es treeuri "$1" --es filename "$2" --es mimetype "$mime" + diff --git a/scripts/termux-saf-dirs.in b/scripts/termux-saf-dirs.in new file mode 100644 index 0000000..e62e4df --- /dev/null +++ b/scripts/termux-saf-dirs.in @@ -0,0 +1,27 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-saf-dirs +show_usage () { + echo "Usage: $SCRIPTNAME" + echo "Lists all directories you gave Termux:API in the same format as termux-saf-ls." + echo "That meas this lists the 'directory' that contains all directories you can access with the other termux-saf-* commands." + echo "The URIs can be used with the other termux-saf-* commands to create files and folders and list the directory contents." + echo "See termux-saf-managedir to give Termux:API access to a folder." + echo " -h show this help" + exit 0 +} + +while getopts :h option +do + case "$option" in + h) show_usage;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi + +@TERMUX_PREFIX@/libexec/termux-api SAF --es safmethod getManagedDocumentTrees + diff --git a/scripts/termux-saf-ls.in b/scripts/termux-saf-ls.in new file mode 100644 index 0000000..7aeb807 --- /dev/null +++ b/scripts/termux-saf-ls.in @@ -0,0 +1,36 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-saf-ls +show_usage () { + echo "Usage: $SCRIPTNAME folder-uri" + echo "Lists the files and folders in a folder identified by a URI." + echo "You can get a folder URI by:" + echo "- Listing folders with termux-saf-ls" + echo "- Giving Termux:API access to folders with termux-saf-managedir" + echo "- Listing the folders you gave Termux:API access to with termux-saf-dirs" + echo "- Creating a folder with termux-saf-mkdir" + echo "The list is returned as a JSON array with one JSON object per entry." + echo "The objects have the keys:" + echo "- 'name' for the human-readable name" + echo "- 'uri' for URI you can use with the other termux-saf-* commands" + echo "- 'type' for the mime type" + echo "- 'length' for size in bytes if it's a file" + echo "You can recognize folders by the special mime type 'vnd.android.document/directory'." + echo " -h show this help" + exit 0 +} + +while getopts :h option +do + case "$option" in + h) show_usage;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ $# != 1 ]; then echo "$SCRIPTNAME: Invalid argument count"; exit 1; fi + +@TERMUX_PREFIX@/libexec/termux-api SAF --es safmethod listDirectory --es treeuri "$1" + diff --git a/scripts/termux-saf-managedir.in b/scripts/termux-saf-managedir.in new file mode 100644 index 0000000..1567033 --- /dev/null +++ b/scripts/termux-saf-managedir.in @@ -0,0 +1,28 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-saf-managedir +show_usage () { + echo "Usage: $SCRIPTNAME" + echo "Opens the system file explorer and lets you specify a folder Termux:API get access to." + echo "You can then use the termux-saf-* utilities to manage the contents in that folder." + echo "Returns a URI identifying the directory, this URI can be used with the other termux-saf-* commands to create files and folders and list the directory contents." + echo "If you close the file manager instead, an empty string will be returned." + echo "You can use termux-saf-dirs to list out all directories you gave Termux:API access to like this." + echo " -h show this help" + exit 0 +} + +while getopts :h option +do + case "$option" in + h) show_usage;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi + +@TERMUX_PREFIX@/libexec/termux-api SAF --es safmethod manageDocumentTree + diff --git a/scripts/termux-saf-mkdir.in b/scripts/termux-saf-mkdir.in new file mode 100644 index 0000000..2dbc28d --- /dev/null +++ b/scripts/termux-saf-mkdir.in @@ -0,0 +1,25 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-saf-mkdir +show_usage () { + echo "Usage: $SCRIPTNAME parent-uri name" + echo "Creates a directory via SAF." + echo "This behaves like termux-saf-create, just for directories." + echo " -h show this help" + exit 0 +} + +while getopts :h option +do + case "$option" in + h) show_usage;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ $# != 2 ]; then echo "$SCRIPTNAME: Invalid argument count"; exit 1; fi + +@TERMUX_PREFIX@/libexec/termux-api SAF --es safmethod createDocument --es treeuri "$1" --es filename "$2" --es mimetype 'vnd.android.document/directory' + diff --git a/scripts/termux-saf-read.in b/scripts/termux-saf-read.in new file mode 100644 index 0000000..89c195e --- /dev/null +++ b/scripts/termux-saf-read.in @@ -0,0 +1,26 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-saf-read +show_usage () { + echo "Usage: $SCRIPTNAME uri" + echo "Reads from a file identified by a URI and writes the data to sstandard output." + echo "You can use pipes to process the data or redirect it into a file to make a local copy." + echo "See termux-saf-list to get the URIs to files." + echo " -h show this help" + exit 0 +} + +while getopts :h option +do + case "$option" in + h) show_usage;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ $# != 1 ]; then echo "$SCRIPTNAME: Invalid argument count"; exit 1; fi + +@TERMUX_PREFIX@/libexec/termux-api SAF --es safmethod readDocument --es uri "$1" + diff --git a/scripts/termux-saf-rm.in b/scripts/termux-saf-rm.in new file mode 100644 index 0000000..0d41316 --- /dev/null +++ b/scripts/termux-saf-rm.in @@ -0,0 +1,25 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-saf-rm +show_usage () { + echo "Usage: $SCRIPTNAME uri" + echo "Removes the file or folder at the given URI. See other termux-saf-* commands for more info." + echo "Returns 0 on success, 1 if the file or folder couldn't be deleted and 2 if another error occurred." + echo " -h show this help" + exit 0 +} + +while getopts :h option +do + case "$option" in + h) show_usage;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ $# != 1 ]; then echo "$SCRIPTNAME: Invalid argument count"; exit 1; fi + +exit "$(@TERMUX_PREFIX@/libexec/termux-api SAF --es safmethod removeDocument --es uri "$1")" + diff --git a/scripts/termux-saf-stat.in b/scripts/termux-saf-stat.in new file mode 100644 index 0000000..8a49f4e --- /dev/null +++ b/scripts/termux-saf-stat.in @@ -0,0 +1,25 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-saf-stat +show_usage () { + echo "Usage: $SCRIPTNAME uri" + echo "Returns the file or folder info as a JSON object." + echo "The format is the same as an entry from termux-saf-ls." + echo " -h show this help" + exit 0 +} + +while getopts :h option +do + case "$option" in + h) show_usage;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ $# != 1 ]; then echo "$SCRIPTNAME: Invalid argument count"; exit 1; fi + +@TERMUX_PREFIX@/libexec/termux-api SAF --es safmethod statURI --es uri "$1" + diff --git a/scripts/termux-saf-write.in b/scripts/termux-saf-write.in new file mode 100644 index 0000000..5109bde --- /dev/null +++ b/scripts/termux-saf-write.in @@ -0,0 +1,24 @@ +#!@TERMUX_PREFIX@/bin/sh +set -e -u + +SCRIPTNAME=termux-saf-write +show_usage () { + echo "Usage: $SCRIPTNAME uri" + echo "Writes the standard input into an existing file identified by a URI. The previous contents are erased. To create a new file, use termux-saf-create." + echo " -h show this help" + exit 0 +} + +while getopts :h option +do + case "$option" in + h) show_usage;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ $# != 1 ]; then echo "$SCRIPTNAME: Invalid argument count"; exit 1; fi + +@TERMUX_PREFIX@/libexec/termux-api SAF --es safmethod writeDocument --es uri "$1" + diff --git a/scripts/termux-sensor b/scripts/termux-sensor.in old mode 100755 new mode 100644 similarity index 91% rename from scripts/termux-sensor rename to scripts/termux-sensor.in index 2dc73b0..6f29c60 --- a/scripts/termux-sensor +++ b/scripts/termux-sensor.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/bash +#!@TERMUX_PREFIX@/bin/bash set -e -u SCRIPTNAME=termux-sensor @@ -69,7 +69,7 @@ get_limit () { } call_api () { - /data/data/com.termux/files/usr/libexec/termux-api Sensor "$@" + @TERMUX_PREFIX@/libexec/termux-api Sensor "$@" } set_flag () { @@ -77,7 +77,7 @@ set_flag () { } usage_error () { - echo "ERROR: $@" + echo "ERROR: $*" show_usage exit 1 } @@ -92,8 +92,8 @@ do c) set_flag $CLEANUP_FLAG; PARAMS=(-a cleanup) ;; l) set_flag $LIST_FLAG; PARAMS=(-a list) ;; s) set_flag $SENSOR_FLAG; get_sensors "$OPTARG"; PARAMS+=(-a sensors --es sensors "$OPTARG") ;; - d) set_flag $DELAY_FLAG; get_delay $OPTARG; PARAMS+=(--ei delay $OPTARG) ;; - n) set_flag $LIMIT_FLAG; get_limit $OPTARG; PARAMS+=(--ei limit $OPTARG) ;; + d) set_flag $DELAY_FLAG; get_delay "$OPTARG"; PARAMS+=(--ei delay "$OPTARG") ;; + n) set_flag $LIMIT_FLAG; get_limit "$OPTARG"; PARAMS+=(--ei limit "$OPTARG") ;; ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done diff --git a/scripts/termux-share b/scripts/termux-share.in old mode 100755 new mode 100644 similarity index 83% rename from scripts/termux-share rename to scripts/termux-share.in index 7c33ef2..90177d5 --- a/scripts/termux-share +++ b/scripts/termux-share.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-share @@ -30,14 +30,14 @@ while getopts :ha:c:dt: option do case "$option" in h) show_usage;; - a) validate_share $OPTARG; PARAMS="$PARAMS --es action $OPTARG";; + a) validate_share "$OPTARG"; PARAMS="$PARAMS --es action $OPTARG";; c) PARAMS="$PARAMS --es content-type $OPTARG";; d) PARAMS="$PARAMS --ez default-receiver true";; t) PARAMS="$PARAMS --es title $OPTARG";; ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# -gt 1 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi @@ -48,7 +48,7 @@ if [ $# != 0 ]; then fi # Note that the file path can contain whitespace. - /data/data/com.termux/files/usr/libexec/termux-api Share $PARAMS --es file "$(realpath "$1")" + @TERMUX_PREFIX@/libexec/termux-api Share $PARAMS --es file "$(realpath "$1")" else - /data/data/com.termux/files/usr/libexec/termux-api Share $PARAMS + @TERMUX_PREFIX@/libexec/termux-api Share $PARAMS fi diff --git a/scripts/termux-sms-inbox b/scripts/termux-sms-inbox.in old mode 100755 new mode 100644 similarity index 66% rename from scripts/termux-sms-inbox rename to scripts/termux-sms-inbox.in index 5a08b60..bf26917 --- a/scripts/termux-sms-inbox +++ b/scripts/termux-sms-inbox.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh echo "termux-sms-inbox: This script has been replaced by termux-sms-list." exit 1 diff --git a/scripts/termux-sms-list b/scripts/termux-sms-list deleted file mode 100755 index 1f4e1fc..0000000 --- a/scripts/termux-sms-list +++ /dev/null @@ -1,50 +0,0 @@ -#!/data/data/com.termux/files/usr/bin/sh -set -u - -PARAM_LIMIT=10 -PARAM_OFFSET=0 -PARAM_TYPE=inbox -PARAMS="" - -SCRIPTNAME=termux-sms-list - -SUPPORTED_TYPES="all|inbox|sent|draft|outbox" -show_usage () { - echo "Usage: $SCRIPTNAME [-d] [-l limit] [-n] [-o offset] [-t type]" - echo "List SMS messages." - echo " -d show dates when messages were created" - echo " -l limit offset in sms list (default: $PARAM_LIMIT)" - echo " -n show phone numbers" - echo " -o offset offset in sms list (default: $PARAM_OFFSET)" - echo " -t type the type of messages to list (default: $PARAM_TYPE):" - echo " $SUPPORTED_TYPES" - exit 0 -} - -while getopts :hdl:t:no: option -do - case "$option" in - h) show_usage;; - d) PARAMS="$PARAMS --ez show-dates true";; - l) PARAM_LIMIT=$OPTARG;; - n) PARAMS="$PARAMS --ez show-phone-numbers true";; - o) PARAM_OFFSET=$OPTARG;; - t) PARAM_TYPE=$OPTARG;; - ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; - esac -done -shift $(($OPTIND-1)) - -if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi - -case "$PARAM_TYPE" in - all) PARAM_TYPE=0 ;; - inbox) PARAM_TYPE=1 ;; - sent) PARAM_TYPE=2 ;; - draft) PARAM_TYPE=3 ;; - outbox) PARAM_TYPE=4 ;; - *) echo "$SCRIPTNAME: Unsupported type '$PARAM_TYPE'. Use one of: $SUPPORTED_TYPES"; exit 1 ;; -esac - -PARAMS="$PARAMS --ei offset $PARAM_OFFSET --ei limit $PARAM_LIMIT --ei type $PARAM_TYPE" -/data/data/com.termux/files/usr/libexec/termux-api SmsInbox $PARAMS diff --git a/scripts/termux-sms-list.in b/scripts/termux-sms-list.in new file mode 100644 index 0000000..5409e87 --- /dev/null +++ b/scripts/termux-sms-list.in @@ -0,0 +1,616 @@ +#!@TERMUX_PREFIX@/bin/bash +# shellcheck shell=bash + +set -u + +if [ -z "${BASH_VERSION:-}" ]; then + echo "The 'termux-sms-list' script must be run from a 'bash' shell."; return 64 2>/dev/null|| exit 64 # EX__USAGE +fi + +termux_api__sms_list__init() { + +# Any and all global variables used by this script must be set to +# default values here so that old/wrong values are not used as the +# `termux_api__*__main()` function of this script or some other API +# script may be called (repeatedly) after sourcing the respective +# scripts. + +TERMUX_API__SCRIPT_NAME="termux-sms-list" +TERMUX_API__API_CONTROLLER="SmsInbox" + +TERMUX_API__COMMAND_TYPE_NOOP="false" # Default: `false` + + +TERMUX_API__CONVERSATION_LIST="" # Default: `` +TERMUX_API__CONVERSATION_LIMIT="" # Default: `` +TERMUX_API__CONVERSATION_OFFSET="" # Default: `` +TERMUX_API__CONVERSATION_SELECTION="" # Default: `` +TERMUX_API__CONVERSATION_SORT_ORDER="" # Default: `` +TERMUX_API__CONVERSATION_RETURN_MULTIPLE_MESSAGES="" # Default: `` +TERMUX_API__CONVERSATION_RETURN_NESTED_VIEW="" # Default: `` +TERMUX_API__CONVERSATION_RETURN_NO_ORDER_REVERSE="" # Default: `` + + +TERMUX_API__MESSASGE_LIMIT___DEFAULT_VALUE=10 # Default: `10` +TERMUX_API__MESSASGE_LIMIT="$TERMUX_API__MESSASGE_LIMIT___DEFAULT_VALUE" # Default: `10` +TERMUX_API__MESSASGE_OFFSET___DEFAULT_VALUE=0 # Default: `0` +TERMUX_API__MESSASGE_OFFSET="$TERMUX_API__MESSASGE_OFFSET___DEFAULT_VALUE" # Default: `0` +TERMUX_API__MESSASGE_SELECTION="" # Default: `` +TERMUX_API__MESSASGE_ADDRESS="" # Default: `` +TERMUX_API__MESSAGE_SORT_ORDER="" # Default: `` +TERMUX_API__MESSASGE_TYPE_NAME___DEFAULT_VALUE="all" # Default: `all` +TERMUX_API__MESSASGE_TYPE_NAME___SUPPORTED_VALUES="all|inbox|sent|draft|outbox|failed|queued" # Default: `all|inbox|sent|draft|outbox|failed|queued` +TERMUX_API__MESSASGE_TYPE_NAME="$TERMUX_API__MESSASGE_TYPE_NAME___DEFAULT_VALUE" # Default: `all` +TERMUX_API__MESSAGE_RETURN_NO_ORDER_REVERSE="" # Default: `` + +# Backward compatibility. +TERMUX_API__MESSAGE_SHOW_DATES="" # Default: `` +TERMUX_API__MESSAGE_SHOW_PHONE_NUMBERS="" # Default: `` + + +unset TERMUX_API__API_ARGS; declare -a TERMUX_API__API_ARGS=() + + +# FIXME: +#TERMUX__PREFIX___N="@TERMUX_ENV__S_TERMUX@PREFIX" +#TERMUX__PREFIX="${!TERMUX__PREFIX___N:-}" +#[[ ! "$TERMUX__PREFIX" =~ ^(/[^/]+)+$ ]] && \ +#TERMUX__PREFIX="@TERMUX__PREFIX@" +TERMUX__PREFIX="@TERMUX_PREFIX@" + + +# FIXME: +#TERMUX_API__LOG_LEVEL___N="@TERMUX_ENV__S_TERMUX_API@LOG_LEVEL" +TERMUX_API__LOG_LEVEL___N="TERMUX_API__LOG_LEVEL" +TERMUX_API__LOG_LEVEL="${!TERMUX_API__LOG_LEVEL___N:-}" +export "${TERMUX_API__LOG_LEVEL___N?}" || return $? + +TERMUX_API__MAX_LOG_LEVEL=5 # Default: `5` (VVVERBOSE=5) +{ [[ ! "$TERMUX_API__LOG_LEVEL" =~ ^[0-9]+$ ]] || [[ "$TERMUX_API__LOG_LEVEL" -gt "$TERMUX_API__MAX_LOG_LEVEL" ]]; } && \ +TERMUX_API__LOG_LEVEL=1 # Default: `1` (OFF=0, NORMAL=1, DEBUG=2, VERBOSE=3, VVERBOSE=4 and VVVERBOSE=5) + +} + + + +termux_api__log() { local log_level="${1:-}"; shift; if [[ "${TERMUX_API__LOG_LEVEL:-1}" -ge "$log_level" ]]; then echo "${TERMUX_API__SCRIPT_NAME:-termux-api}:" "$@"; fi } +termux_api__log_literal() { local log_level="${1:-}"; shift; if [[ "${TERMUX_API__LOG_LEVEL:-1}" -ge "$log_level" ]]; then echo -e "${TERMUX_API__SCRIPT_NAME:-termux-api}:" "$@"; fi } +termux_api__log_error() { echo "${TERMUX_API__SCRIPT_NAME:-termux-api}:" "$@" 1>&2; } + + + +## +# `termux_api__sms_list__main` [``] +## +termux_api__sms_list__main() { + + local return_value + + termux_api__sms_list__init || return $? + + # Process the command arguments passed to the script. + termux_api__sms_list__process_script_arguments "$@" || return $? + if [ "$TERMUX_API__COMMAND_TYPE_NOOP" = "true" ]; then return 0; fi + + + termux_api__log 2 "Running command" + + + local messasge_type_column + case "$TERMUX_API__MESSASGE_TYPE_NAME" in + all) messasge_type_column=0 ;; + inbox) messasge_type_column=1 ;; + sent) messasge_type_column=2 ;; + draft) messasge_type_column=3 ;; + outbox) messasge_type_column=4 ;; + failed) messasge_type_column=5 ;; + queued) messasge_type_column=6 ;; + *) + termux_api__log_error "Unsupported message type '$TERMUX_API__MESSASGE_TYPE_NAME'. It must one of following: $TERMUX_API__MESSASGE_TYPE_NAME___SUPPORTED_VALUES" + return 1 + ;; + esac + + + if [[ -n "$TERMUX_API__CONVERSATION_LIST" ]]; then + TERMUX_API__API_ARGS+=(--ez "conversation-list" "$TERMUX_API__CONVERSATION_LIST") + + if [[ "$TERMUX_API__CONVERSATION_LIST" == "true" ]]; then + if [[ -n "$TERMUX_API__CONVERSATION_LIMIT" ]]; then + TERMUX_API__API_ARGS+=(--ei "conversation-limit" "$TERMUX_API__CONVERSATION_LIMIT") + fi + + if [[ -n "$TERMUX_API__CONVERSATION_OFFSET" ]]; then + TERMUX_API__API_ARGS+=(--ei "conversation-offset" "$TERMUX_API__CONVERSATION_OFFSET") + fi + + if [[ -n "$TERMUX_API__CONVERSATION_SELECTION" ]]; then + TERMUX_API__API_ARGS+=(--es "conversation-selection" "$TERMUX_API__CONVERSATION_SELECTION") + fi + + if [[ -n "$TERMUX_API__CONVERSATION_SORT_ORDER" ]]; then + TERMUX_API__API_ARGS+=(--es "conversation-sort-order" "$TERMUX_API__CONVERSATION_SORT_ORDER") + fi + + if [[ -n "$TERMUX_API__CONVERSATION_RETURN_MULTIPLE_MESSAGES" ]]; then + TERMUX_API__API_ARGS+=(--ez "conversation-return-multiple-messages" "$TERMUX_API__CONVERSATION_RETURN_MULTIPLE_MESSAGES") + fi + + if [[ -n "$TERMUX_API__CONVERSATION_RETURN_NESTED_VIEW" ]]; then + TERMUX_API__API_ARGS+=(--ez "conversation-return-nested-view" "$TERMUX_API__CONVERSATION_RETURN_NESTED_VIEW") + fi + + if [[ -n "$TERMUX_API__CONVERSATION_SORT_ORDER" ]]; then + TERMUX_API__API_ARGS+=(--ez "conversation-return-no-order-reverse" "$TERMUX_API__CONVERSATION_RETURN_NO_ORDER_REVERSE") + fi + fi + fi + + + TERMUX_API__API_ARGS+=( + --ei "limit" "$TERMUX_API__MESSASGE_LIMIT" + --ei "offset" "$TERMUX_API__MESSASGE_OFFSET" + --ei "type" "$messasge_type_column" + ) + + if [[ -n "$TERMUX_API__MESSASGE_SELECTION" ]]; then + TERMUX_API__API_ARGS+=(--es "message-selection" "$TERMUX_API__MESSASGE_SELECTION") + fi + + if [[ -n "$TERMUX_API__MESSASGE_ADDRESS" ]]; then + TERMUX_API__API_ARGS+=(--es "from" "$TERMUX_API__MESSASGE_ADDRESS") + fi + + if [[ -n "$TERMUX_API__MESSAGE_SORT_ORDER" ]]; then + TERMUX_API__API_ARGS+=(--es "message-sort-order" "$TERMUX_API__MESSAGE_SORT_ORDER") + fi + + if [[ -n "$TERMUX_API__MESSAGE_RETURN_NO_ORDER_REVERSE" ]]; then + TERMUX_API__API_ARGS+=(--ez "message-return-no-order-reverse" "$TERMUX_API__MESSAGE_RETURN_NO_ORDER_REVERSE") + fi + + # Backward compatibility. + if [[ -n "$TERMUX_API__MESSAGE_SHOW_DATES" ]]; then + TERMUX_API__API_ARGS+=(--ez "show-dates" "$TERMUX_API__MESSAGE_SHOW_DATES") + fi + + # Backward compatibility. + if [[ -n "$TERMUX_API__MESSAGE_SHOW_PHONE_NUMBERS" ]]; then + TERMUX_API__API_ARGS+=(--ez "show-phone-numbers" "$TERMUX_API__MESSAGE_SHOW_PHONE_NUMBERS") + fi + + + if [[ $TERMUX_API__LOG_LEVEL -ge 2 ]]; then + local api_args_string="termux-api $TERMUX_API__API_CONTROLLER" + local i=1 + for ((i = 0; i < ${#TERMUX_API__API_ARGS[@]}; i++)); do + api_args_string="$api_args_string \`${TERMUX_API__API_ARGS[$i]}\`" + done + termux_api__log 2 "$api_args_string" + fi + + + return_value=0 + "$TERMUX__PREFIX/libexec/termux-api" "$TERMUX_API__API_CONTROLLER" "${TERMUX_API__API_ARGS[@]}" || return_value=$? + if [ $return_value -ne 0 ]; then + termux_api__log_error "Command failed with exit code $return_value" + else + termux_api__log 2 "Command successful" + fi + return $return_value + +} + +## +# `termux_api__sms_list__process_script_arguments` [``] +## +termux_api__sms_list__process_script_arguments() { + + local opt; local opt_arg; local OPTARG; local OPTIND + + # Parse options to main command. + while getopts ":hqvcdf:l:no:t:-:" opt; do + opt_arg="${OPTARG:-}" + case "${opt}" in + -) + case "${OPTARG}" in *?=*) opt_arg="${OPTARG#*=}";; *) opt_arg="";; esac + case "${OPTARG}" in + help) + TERMUX_API__COMMAND_TYPE_NOOP="true" + termux_api__sms_list__show_help; return $? + ;; + # FIXME: + #version) + # TERMUX_API__COMMAND_TYPE_NOOP="true" + # echo "@TERMUX_API_PKG__VERSION@"; return $? + # ;; + # [ --version ] Display version. + quiet) + TERMUX_API__LOG_LEVEL=0 + ;; + conversation-list) + TERMUX_API__CONVERSATION_LIST="true" + ;; + conversation-limit=?*) + TERMUX_API__CONVERSATION_LIMIT="$opt_arg" + ;; + conversation-limit | conversation-limit=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + conversation-offset=?*) + TERMUX_API__CONVERSATION_OFFSET="$opt_arg" + ;; + conversation-offset | conversation-offset=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + conversation-return-multiple-messages) + TERMUX_API__CONVERSATION_RETURN_MULTIPLE_MESSAGES="true" + ;; + conversation-return-nested-view) + TERMUX_API__CONVERSATION_RETURN_NESTED_VIEW="true" + ;; + conversation-return-no-order-reverse) + TERMUX_API__CONVERSATION_RETURN_NO_ORDER_REVERSE="true" + ;; + conversation-selection=?*) + TERMUX_API__CONVERSATION_SELECTION="$opt_arg" + ;; + conversation-selection | conversation-selection=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + conversation-sort-order=?*) + TERMUX_API__CONVERSATION_SORT_ORDER="$opt_arg" + ;; + conversation-sort-order | conversation-sort-order=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + message-address=?*) + TERMUX_API__MESSASGE_ADDRESS="$opt_arg" + ;; + message-address | message-address=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + message-limit=?*) + TERMUX_API__MESSASGE_LIMIT="$opt_arg" + ;; + message-limit | message-limit=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + message-offset=?*) + TERMUX_API__MESSASGE_OFFSET="$opt_arg" + ;; + message-offset | message-offset=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + message-return-no-order-reverse) + TERMUX_API__MESSAGE_RETURN_NO_ORDER_REVERSE="true" + ;; + message-selection=?*) + TERMUX_API__MESSASGE_SELECTION="$opt_arg" + ;; + message-selection | message-selection=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + message-sort-order=?*) + TERMUX_API__MESSAGE_SORT_ORDER="$opt_arg" + ;; + message-sort-order | message-sort-order=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + message-type=?*) + TERMUX_API__MESSASGE_TYPE_NAME="$opt_arg" + ;; + message-type | message-type=) + termux_api__log_error "No argument set for arg option '--${OPTARG%=*}'." + return 64 # EX__USAGE + ;; + '') + # End of options `--`. + break + ;; + *) + termux_api__log_error "Unknown option: '--${OPTARG:-}'." + termux_api__sms_list__exit_on_args_error || return $? + + ;; + esac + ;; + h) + TERMUX_API__COMMAND_TYPE_NOOP="true" + termux_api__sms_list__show_help; return $? + ;; + q) + TERMUX_API__LOG_LEVEL=0 + ;; + v) + if [ "$TERMUX_API__LOG_LEVEL" -lt "$TERMUX_API__MAX_LOG_LEVEL" ]; then + TERMUX_API__LOG_LEVEL=$((TERMUX_API__LOG_LEVEL+1)); + else + termux_api__log_error "Invalid option, max log level is $TERMUX_API__MAX_LOG_LEVEL." + return 64 # EX__USAGE + fi + ;; + c) + TERMUX_API__CONVERSATION_LIST="true" + ;; + d) + TERMUX_API__MESSAGE_SHOW_DATES="true" + ;; + f) + TERMUX_API__MESSASGE_ADDRESS="$opt_arg" + ;; + l) + TERMUX_API__MESSASGE_LIMIT="$opt_arg" + ;; + n) + TERMUX_API__MESSAGE_SHOW_PHONE_NUMBERS="true" + ;; + o) + TERMUX_API__MESSASGE_OFFSET="$opt_arg" + ;; + t) + TERMUX_API__MESSASGE_TYPE_NAME="$opt_arg" + ;; + :) + termux_api__log_error "No argument passed for arg option '-$OPTARG'." + termux_api__sms_list__exit_on_args_error || return $? + ;; + \?) + termux_api__log_error "Unknown option${OPTARG:+": '-${OPTARG:-}'"}." + termux_api__sms_list__exit_on_args_error || return $? + ;; + esac + done + shift $((OPTIND - 1)) # Remove already processed arguments from argument list + + # If a non-option argument is given to main command. + if [ $# -ne 0 ]; then + logger__log_error "Unknown argument(s) to command: $*" + return 64 # EX__USAGE + fi + + return 0; + +} + +## +# `termux_api__sms_list__exit_on_args_error` +## +termux_api__sms_list__exit_on_args_error() { + + termux_api__sms_list__show_help || return $? + + return 64 # EX__USAGE + +} + +## +# `termux_api__sms_list__show_help` +## +termux_api__sms_list__show_help() { + +# FIXME: CMake `configure_file` `@ONLY` will replace `@VAR@` style +# placeholders, so use `!VAR!` until we shift to make. + + cat <<'HELP_EOF' | \ + sed \ + -e "s%[!]TERMUX_API__SCRIPT_NAME[!]%${TERMUX_API__SCRIPT_NAME}%g" \ + -e "s%[!]TERMUX_API__MESSASGE_LIMIT___DEFAULT_VALUE[!]%${TERMUX_API__MESSASGE_LIMIT___DEFAULT_VALUE}%g" \ + -e "s%[!]TERMUX_API__MESSASGE_OFFSET___DEFAULT_VALUE[!]%${TERMUX_API__MESSASGE_OFFSET___DEFAULT_VALUE}%g" \ + -e "s%[!]TERMUX_API__MESSASGE_TYPE_NAME___DEFAULT_VALUE[!]%${TERMUX_API__MESSASGE_TYPE_NAME___DEFAULT_VALUE}%g" \ + -e "s%[!]TERMUX_API__MESSASGE_TYPE_NAME___SUPPORTED_VALUES[!]%${TERMUX_API__MESSASGE_TYPE_NAME___SUPPORTED_VALUES}%g" +!TERMUX_API__SCRIPT_NAME! command lists SMS conversations and messages. + +Usage: + !TERMUX_API__SCRIPT_NAME! [command_options] + +Available command_options: + [ -h | --help ] Display this help screen. +# [ --version ] Display version. + [ -q | --quiet ] Set log level to 'OFF'. + [ -v | -vv | -vvv | -vvvvv ] + Set log level to 'DEBUG', 'VERBOSE', + 'VVERBOSE' and 'VVVERBOSE'. + [ -c | --conversation-list ] + Show SMS conversations list instead of + messages list. + By default only one SMS message per + conversation is returned unless the + '--conversation-return-multiple-messages' + option is passed. + By default all SMS messages are returned + as a single array without nesting + unless the + '--conversation-return-nested-view' + option is passed. + [ --conversation-limit= ] + The SQL limit for returned SMS + conversations. + [ --conversation-offset= ] + The SQL offset for returned SMS + conversations. + [ --conversation-return-multiple-messages ] + Return multiple SMS messages per + conversation. + [ --conversation-return-nested-view ] + Return a nested object view of + conversations where each conversation + contains an array of SMS messages with + the conversation id as the key. + [ --conversation-return-no-order-reverse ] + Return SMS conversations without + reversing order of conversation sort. + [ --conversation-selection= ] + The SQL selection for returned SMS + conversations. + [ --conversation-sort-order= ] + The SMS conversations sort order as per + SQL 'ORDER BY col1, col2, ... ASC|DESC' + clause. + Default value: 'date DESC'. + [ -f address | --message-address=
] + The address or phone number of the + sender to return SMS messages for. + The '--conversation-selection' option + will override this if passed. + [ -l limit | --message-limit= ] + The limit for returned SMS messages. + Default value: '!TERMUX_API__MESSASGE_LIMIT___DEFAULT_VALUE!'. + [ -o offset | --message-offset= ] + The offset for returned SMS messages. + Default value: '!TERMUX_API__MESSASGE_OFFSET___DEFAULT_VALUE!'. + [ --message-return-no-order-reverse ] + Return SMS messages without reversing + order of message sort. + [ --message-selection= ] + The SQL selection for returned SMS + messages. + [ --message-sort-order= ] + The SMS messages sort order as per + SQL 'ORDER BY col1, col2, ... ASC|DESC' + clause. + Default value: 'date DESC'. + [ -t type | --message-type= ] + The type of returned SMS messages. + Default value: '!TERMUX_API__MESSASGE_TYPE_NAME___DEFAULT_VALUE!'. + Supported values: '!TERMUX_API__MESSASGE_TYPE_NAME___SUPPORTED_VALUES!'. + + + +# Sort and Print Order + +When conversation or messages are queried from the Android database, +first the sort order is applied, and then any offset and limit values +are used to filter the entries. Since the default sort order is +'date DESC', Android returns the latest dated conversations or +messages first, but the API reverses the order by default so that +the latest entries are printed at the end. If the order should not be +reversed, then pass the respective `--*-return-no-order-reverse` +options. + + + +# Message Type + +The following numbers can be used to match a message 'type' with +the '--message-selection' option. +- all: 0 +- inbox: 1 +- sent: 2 +- draft: 3 +- outbox: 4 +- failed: 5 +- queued: 6 + + + +### Examples + +# Get lastest 10 messages with latest dated message printed at end. +!TERMUX_API__SCRIPT_NAME! + +# Get lastest 10 messages with latest dated message printed at start. +!TERMUX_API__SCRIPT_NAME! --message-return-no-order-reverse + +# Get latest message of any type. +!TERMUX_API__SCRIPT_NAME! --message-limit=1 + +# Get latest inbox message. +!TERMUX_API__SCRIPT_NAME! --message-selection="type == 1" \ + --message-limit=1 + +# Get latest sent message. +!TERMUX_API__SCRIPT_NAME! --message-selection="type == 2" \ + --message-limit=1 + +# Get oldest 10 messages with latest dated message printed at end. +!TERMUX_API__SCRIPT_NAME! --message-sort-order="date ASC" \ + --message-return-no-order-reverse + +# Get the latest inbox message received from the address '666' that +# starts with the text 'Foo '. +!TERMUX_API__SCRIPT_NAME! \ + --message-selection="type == 1 and address == '666' and body LIKE 'Foo %'" \ + --message-limit=1 + +# Get the latest sent message sent to the address '666' that +# starts with the text 'Bar '. +!TERMUX_API__SCRIPT_NAME! \ + --message-selection="type == 2 and address == '666' and body LIKE 'Bar %'" \ + --message-limit=1 + + +# Get list view for conversations with default conversation limit and +# 1 message per conversastion. +!TERMUX_API__SCRIPT_NAME! --conversation-list + +# Get list view for conversations with default conversation limit and +# 10 messages per conversation. +!TERMUX_API__SCRIPT_NAME! --conversation-list \ + --conversation-return-multiple-messages + + +# Get nested view for conversations with default conversation and +# message limits. +!TERMUX_API__SCRIPT_NAME! --conversation-list \ + --conversation-return-multiple-messages \ + --conversation-return-nested-view + +# Get nested view for latest conversation with latest 5 messages. +!TERMUX_API__SCRIPT_NAME! --conversation-list \ + --conversation-return-multiple-messages \ + --conversation-return-nested-view \ + --conversation-limit=1 \ + --message-limit=5 + +# Get nested view for conversations sorted on thread id with highest +# conversation id printed at end. +!TERMUX_API__SCRIPT_NAME! --conversation-list \ + --conversation-return-multiple-messages \ + --conversation-return-nested-view \ + --conversation-sort-order="thread_id ASC" \ + --conversation-return-no-order-reverse + +# Get nested view for conversations for conversation with address +# equal to '666'. +!TERMUX_API__SCRIPT_NAME! --conversation-list \ + --conversation-return-multiple-messages \ + --conversation-return-nested-view \ + --conversation-selection="address == '666'" + +# Get nested view for conversations for conversation with thread id +# equal to '6'. +!TERMUX_API__SCRIPT_NAME! --conversation-list \ + --conversation-return-multiple-messages \ + --conversation-return-nested-view \ + --conversation-selection="thread_id == 6" + + + + **See Also:** + - https://developer.android.com/reference/android/provider/Telephony + - https://developer.android.com/reference/android/provider/Telephony.Sms.Conversations + - https://developer.android.com/reference/android/provider/Telephony.TextBasedSmsColumns + - https://developer.android.com/reference/android/provider/BaseColumns +HELP_EOF + +} + +# If script is sourced, return with success, otherwise call main function. +# - https://stackoverflow.com/a/28776166/14686958 +# - https://stackoverflow.com/a/29835459/14686958 +if (return 0 2>/dev/null); then + return 0 # EX__SUCCESS +else + termux_api__sms_list__main "$@" + exit $? +fi diff --git a/scripts/termux-sms-send b/scripts/termux-sms-send.in old mode 100755 new mode 100644 similarity index 60% rename from scripts/termux-sms-send rename to scripts/termux-sms-send.in index 33d9da4..8a1bd4c --- a/scripts/termux-sms-send +++ b/scripts/termux-sms-send.in @@ -1,32 +1,35 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-sms-send show_usage () { - echo "Usage: $SCRIPTNAME -n number[,number2,number3,...] [text]" + echo "Usage: $SCRIPTNAME -n number[,number2,number3,...] [-s slot] [text]" echo "Send a SMS message to the specified recipient number(s). The text to send is either supplied as arguments or read from stdin if no arguments are given." echo " -n number(s) recipient number(s) - separate multiple numbers by commas" + echo " -s slot sim slot to use - silently fails if slot number is invalid or if missing READ_PHONE_STATE permission" exit 0 } RECIPIENTS="" -while getopts :hn: option +SLOT="" +while getopts :hn:s: option do case "$option" in h) show_usage;; n) RECIPIENTS="--esa recipients $OPTARG";; + s) SLOT="--ei slot $OPTARG ";; ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ -z "$RECIPIENTS" ]; then echo "$SCRIPTNAME: no recipient number given"; exit 1; fi -CMD="/data/data/com.termux/files/usr/libexec/termux-api SmsSend $RECIPIENTS" +CMD="@TERMUX_PREFIX@/libexec/termux-api SmsSend $RECIPIENTS $SLOT" if [ $# = 0 ]; then $CMD else - echo $@ | $CMD + echo "$@" | $CMD fi diff --git a/scripts/termux-speech-to-text b/scripts/termux-speech-to-text.in old mode 100755 new mode 100644 similarity index 82% rename from scripts/termux-speech-to-text rename to scripts/termux-speech-to-text.in index 5a200ba..4bc7fd0 --- a/scripts/termux-speech-to-text +++ b/scripts/termux-speech-to-text.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-speech-to-text @@ -17,11 +17,11 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -CMD=/data/data/com.termux/files/usr/libexec/termux-api +CMD=@TERMUX_PREFIX@/libexec/termux-api if [ $show_progress = true ]; then $CMD SpeechToText else diff --git a/scripts/termux-storage-get b/scripts/termux-storage-get.in old mode 100755 new mode 100644 similarity index 76% rename from scripts/termux-storage-get rename to scripts/termux-storage-get.in index 4ec9977..86b236e --- a/scripts/termux-storage-get +++ b/scripts/termux-storage-get.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-storage-get @@ -16,9 +16,9 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# -gt 1 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi if [ $# -lt 1 ]; then echo "$SCRIPTNAME: no output file specified"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api StorageGet --es file "`realpath "$1"`" +@TERMUX_PREFIX@/libexec/termux-api StorageGet --es file "$(realpath "$1")" diff --git a/scripts/termux-telephony-call b/scripts/termux-telephony-call.in old mode 100755 new mode 100644 similarity index 72% rename from scripts/termux-telephony-call rename to scripts/termux-telephony-call.in index 8b42277..5a61015 --- a/scripts/termux-telephony-call +++ b/scripts/termux-telephony-call.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-telephony-call @@ -15,10 +15,10 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# = 1 ]; then - /data/data/com.termux/files/usr/libexec/termux-api TelephonyCall --es number "$1" + @TERMUX_PREFIX@/libexec/termux-api TelephonyCall --es number "$1" else echo "$SCRIPTNAME: No single number to call specified." >&2 exit 1 diff --git a/scripts/termux-telephony-cellinfo b/scripts/termux-telephony-cellinfo.in old mode 100755 new mode 100644 similarity index 78% rename from scripts/termux-telephony-cellinfo rename to scripts/termux-telephony-cellinfo.in index 1d394b8..e5c3d30 --- a/scripts/termux-telephony-cellinfo +++ b/scripts/termux-telephony-cellinfo.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-telephony-cellinfo @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api TelephonyCellInfo +@TERMUX_PREFIX@/libexec/termux-api TelephonyCellInfo diff --git a/scripts/termux-telephony-deviceinfo b/scripts/termux-telephony-deviceinfo.in old mode 100755 new mode 100644 similarity index 74% rename from scripts/termux-telephony-deviceinfo rename to scripts/termux-telephony-deviceinfo.in index 4f303ad..14115dc --- a/scripts/termux-telephony-deviceinfo +++ b/scripts/termux-telephony-deviceinfo.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-telephony-deviceinfo @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api TelephonyDeviceInfo +@TERMUX_PREFIX@/libexec/termux-api TelephonyDeviceInfo diff --git a/scripts/termux-toast b/scripts/termux-toast deleted file mode 100755 index 95bd865..0000000 --- a/scripts/termux-toast +++ /dev/null @@ -1,37 +0,0 @@ -#!/data/data/com.termux/files/usr/bin/bash -set -e -u - -SCRIPTNAME=termux-toast -show_usage () { - echo "Usage: termux-toast [-b bgcolor] [-c color] [-g gravity] [-s] [text]" - echo "Show text in a Toast (a transient popup). The text to show is either supplied as arguments or read from stdin if no arguments are given." - echo " -h show this help" - echo " -b set background color (default: gray)" - echo " -c set text color (default: white)" - echo " -g set position of toast: [top, middle, or bottom] (default: middle)" - echo " -s only show the toast for a short while" - echo "NOTE: color can be a standard name (i.e. red) or 6 / 8 digit hex value (i.e. \"#FF0000\" or \"#FFFF0000\") where order is (AA)RRGGBB. Invalid color will revert to default value" - exit 0 -} - -PARAMS="" -while getopts :hsc:b:g: option -do - case "$option" in - h) show_usage;; - s) PARAMS+=" --ez short true";; - c) PARAMS+=" --es text_color $OPTARG";; - b) PARAMS+=" --es background $OPTARG";; - g) PARAMS+=" --es gravity $OPTARG";; - ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; - esac -done -shift $(($OPTIND-1)) - -CMD="/data/data/com.termux/files/usr/libexec/termux-api Toast $PARAMS" - -if [ $# = 0 ]; then - $CMD -else - echo $@ | $CMD -fi diff --git a/scripts/termux-toast.in b/scripts/termux-toast.in new file mode 100644 index 0000000..58e8843 --- /dev/null +++ b/scripts/termux-toast.in @@ -0,0 +1,48 @@ +#!@TERMUX_PREFIX@/bin/bash +set -e -u + +SCRIPTNAME=termux-toast +show_usage () { + echo "Usage: termux-toast [-b bgcolor] [-c color] [-g gravity] [-s] [text]" + echo "Show text in a Toast (a transient popup)." + echo "The toast text is either supplied as arguments or read from stdin" + echo "if no arguments are given. Arguments will take precedence over stdin." + echo "If toast text is not passed as arguments or with stdin, then there will" + echo "be a 3s delay." + echo " -h show this help" + echo " -b set background color (default: gray)" + echo " -c set text color (default: white)" + echo " -g set position of toast: [top, middle, or bottom] (default: middle)" + echo " -s only show the toast for a short while" + echo "NOTE: color can be a standard name (i.e. red) or 6 / 8 digit hex value (i.e. \"#FF0000\" or \"#FFFF0000\") where order is (AA)RRGGBB. Invalid color will revert to default value" + exit 0 +} + +PARAMS="" +while getopts :hsc:b:g: option +do + case "$option" in + h) show_usage;; + s) PARAMS+=" --ez short true";; + c) PARAMS+=" --es text_color $OPTARG";; + b) PARAMS+=" --es background $OPTARG";; + g) PARAMS+=" --es gravity $OPTARG";; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +CMD="@TERMUX_PREFIX@/libexec/termux-api Toast $PARAMS" + +# If toast text was not passed as an argument, then attempt to read from STDIN with a 3s timeout +# Toast text arguments takes precedence over STDIN +if [ $# = 0 ]; then + set +e; IFS= read -t 3 -r -d '' TOAST_TEXT; set -e; +else + TOAST_TEXT="$*" +fi + +# Trim trailing newlines +TOAST_TEXT="$(echo "$TOAST_TEXT")" + +echo "$TOAST_TEXT" | $CMD diff --git a/scripts/termux-torch b/scripts/termux-torch.in old mode 100755 new mode 100644 similarity index 67% rename from scripts/termux-torch rename to scripts/termux-torch.in index 73b93b7..cf30efb --- a/scripts/termux-torch +++ b/scripts/termux-torch.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-torch @@ -16,13 +16,13 @@ fi PARAMS="" -if [ $1 = 'on' ]; then +if [ "$1" = on ]; then PARAMS="--ez enabled true" -elif [ $1 = 'off' ]; then +elif [ "$1" = off ]; then PARAMS="--ez enabled false" else echo "Illegal parameter: $1" show_usage fi -/data/data/com.termux/files/usr/libexec/termux-api Torch $PARAMS +@TERMUX_PREFIX@/libexec/termux-api Torch $PARAMS diff --git a/scripts/termux-tts-engines b/scripts/termux-tts-engines.in old mode 100755 new mode 100644 similarity index 75% rename from scripts/termux-tts-engines rename to scripts/termux-tts-engines.in index e62fbc1..af0959b --- a/scripts/termux-tts-engines +++ b/scripts/termux-tts-engines.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-tts-engines @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api TextToSpeech --es engine LIST_AVAILABLE +@TERMUX_PREFIX@/libexec/termux-api TextToSpeech --es engine LIST_AVAILABLE diff --git a/scripts/termux-tts-speak b/scripts/termux-tts-speak.in old mode 100755 new mode 100644 similarity index 92% rename from scripts/termux-tts-speak rename to scripts/termux-tts-speak.in index 4bfafa6..bd95037 --- a/scripts/termux-tts-speak +++ b/scripts/termux-tts-speak.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-tts-speak @@ -38,12 +38,12 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) -CMD="/data/data/com.termux/files/usr/libexec/termux-api TextToSpeech $PARAMS" +CMD="@TERMUX_PREFIX@/libexec/termux-api TextToSpeech $PARAMS" if [ $# = 0 ]; then $CMD else - echo $@ | $CMD + echo "$@" | $CMD fi diff --git a/scripts/termux-usb.in b/scripts/termux-usb.in new file mode 100644 index 0000000..4c77ba2 --- /dev/null +++ b/scripts/termux-usb.in @@ -0,0 +1,78 @@ +#!@TERMUX_PREFIX@/bin/bash +set -e -u + +SCRIPTNAME=termux-usb +show_usage () { + echo "Usage: $SCRIPTNAME [-l | [-r] [-E] [-e command] [device | vendorId productId]]" + echo "List or access USB devices. Devices cannot be accessed directly," + echo " only using $SCRIPTNAME." + echo " -l list available devices" + echo " -r show permission request dialog if necessary" + echo " -e command execute the specified command with a file descriptor" + echo " referring to the device as an argument (unless -E" + echo " argument is given)" + echo " -E transfer file descriptor as TERMUX_USB_FD env var" + echo " instead of as command line argument" + exit 0 +} + +ACTION="permission" +PARAMS="" +while getopts :hlre:E option +do + case "$option" in + h) show_usage;; + l) ACTION="list";; + r) PARAMS="$PARAMS --ez request true";; + e) ACTION="open"; export TERMUX_CALLBACK="$OPTARG";; + E) export TERMUX_EXPORT_FD=true;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; + esac +done +shift $((OPTIND-1)) + +if [ "$ACTION" == "list" ] +then + if [ $# -gt 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi +else + if [ $# -lt 1 ]; then + echo "$SCRIPTNAME: missing -l or device path" + exit 1 + elif [ $# -eq 1 ]; then + # The device's usbfs path has been provided + PARAMS="$PARAMS --es device $1" + elif [ $# -eq 2 ]; then + # A vendorId and ProductId of the device has been provided + PARAMS="$PARAMS --es vendorId $1" + PARAMS="$PARAMS --es productId $2" + else + echo "$SCRIPTNAME: too many arguments" + exit 1 + fi +fi + +CMD="@TERMUX_PREFIX@/libexec/termux-api Usb -a $ACTION $PARAMS" + +if [[ "$ACTION" == "list" ]]; then + $CMD +elif [[ "$ACTION" == "permission" ]]; then + OUTPUT="$($CMD)" + case "$OUTPUT" in + "No such device"|"No such device.") echo "No such device."; exit 1;; + "yes") echo "Permission granted."; exit 0;; + "no"|"Permission denied.") echo "Permission denied."; exit 1;; + "Permission request timeout.") echo "Permission request timeout."; exit 1;; + *) printf "%s\n" "$OUTPUT"; exit 0;; + esac +elif [[ "$ACTION" == "open" ]]; then + OUTPUT="$($CMD)" + case "$OUTPUT" in + "No such device"|"No such device.") echo "No such device."; exit 1;; + "No permission"|"Permission denied.") echo "Permission denied."; exit 1;; + "Permission request timeout.") echo "Permission request timeout."; exit 1;; + "Failed to open device"|"Open device failed.") echo "Open device failed."; exit 1;; + *) printf "%s\n" "$OUTPUT"; exit 0;; + esac +fi + +exit 0 diff --git a/scripts/termux-vibrate b/scripts/termux-vibrate.in old mode 100755 new mode 100644 similarity index 82% rename from scripts/termux-vibrate rename to scripts/termux-vibrate.in index 74896c9..36b03fa --- a/scripts/termux-vibrate +++ b/scripts/termux-vibrate.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-vibrate @@ -21,8 +21,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api Vibrate $PARAMS +@TERMUX_PREFIX@/libexec/termux-api Vibrate $PARAMS diff --git a/scripts/termux-volume b/scripts/termux-volume.in old mode 100755 new mode 100644 similarity index 86% rename from scripts/termux-volume rename to scripts/termux-volume.in index 410c771..84425d9 --- a/scripts/termux-volume +++ b/scripts/termux-volume.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/bash +#!@TERMUX_PREFIX@/bin/bash set -e -u SCRIPTNAME=termux-volume @@ -27,4 +27,4 @@ if [ $# -gt 0 ]; then ARGS="-a set-volume --es stream $1 --ei volume $2" fi -/data/data/com.termux/files/usr/libexec/termux-api Volume $ARGS +@TERMUX_PREFIX@/libexec/termux-api Volume $ARGS diff --git a/scripts/termux-wallpaper b/scripts/termux-wallpaper deleted file mode 100755 index 58fbdb4..0000000 --- a/scripts/termux-wallpaper +++ /dev/null @@ -1,71 +0,0 @@ -#!/data/data/com.termux/files/usr/bin/bash - -set -e - -SCRIPTNAME=termux-wallpaper - -show_usage () { - echo "Change wallpaper on your device" - echo - echo "Usage: $SCRIPTNAME cmd [args]" - echo "-h show this help" - echo "-f set wallpaper from file" - echo "-u set wallpaper from url resource" - echo "-l set wallpaper for lockscreen (Nougat and later)" - exit 1 -} - -call_api() { - /data/data/com.termux/files/usr/libexec/termux-api Wallpaper "$@" -} - -usage_error () { - echo "ERROR: $@" - show_usage -} - -LOCKSCREEN_FLAG=1 -RESOURCE_FLAG=2 - -FLAGS=0 - -set_single () { - if [ $((FLAGS & $1)) -ne 0 ]; then - usage_error "Option already set" - fi - FLAGS=$((FLAGS | $1)) - PARAMS="$PARAMS $2" -} - -set_resource () { - if [ $((FLAGS & $RESOURCE_FLAG)) -ne 0 ]; then - usage_error "More than one image resource specified!" - fi - set_single $RESOURCE_FLAG "$1" -} - -set_file () { - if [ ! -f $1 ]; then - usage_error "'$1' is not a file!" - fi - set_resource "--es file "$(realpath $1)"" -} - -while getopts :h,:l,f:,u: option -do - case "$option" in - h) show_usage ;; - l) set_single $LOCKSCREEN_FLAG "--ez lockscreen true" ;; - f) set_file $OPTARG ;; - u) set_resource "--es url $OPTARG" ;; - ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1 ;; - esac -done - -shift $((OPTIND - 1)) - -if [ $((FLAGS & RESOURCE_FLAG)) -eq 0 ]; then - usage_error "No file or url provided!" -fi - -call_api $PARAMS diff --git a/scripts/termux-wallpaper.in b/scripts/termux-wallpaper.in new file mode 100644 index 0000000..247bc72 --- /dev/null +++ b/scripts/termux-wallpaper.in @@ -0,0 +1,52 @@ +#!@TERMUX_PREFIX@/bin/bash + +set -e + +SCRIPTNAME=termux-wallpaper +show_usage () { + echo "Change wallpaper on your device" + echo + echo "Usage: $SCRIPTNAME [options]" + echo "-h show this help" + echo "-f set wallpaper from file" + echo "-u set wallpaper from url resource" + echo "-l set wallpaper for lockscreen (Nougat and later)" + exit 1 +} + +OPT_LS="" +OPT_FILE="" +OPT_URL="" + +while getopts :h,:l,f:,u: option +do + case "$option" in + h) show_usage ;; + l) OPT_LS="true" ;; + f) path="$(realpath "$OPTARG")" + if [[ ! -f "$path" ]]; then + echo "$SCRIPTNAME: $path is not a file!" + exit 1 + fi + OPT_FILE="$path" ;; + u) OPT_URL="$OPTARG" ;; + ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1 ;; + esac +done + +if [[ -z "$OPT_FILE""$OPT_URL" ]]; then + echo "$SCRIPTNAME: you must specify either -f or -u" + exit 1 +elif [[ -n "$OPT_FILE" ]] && [[ -n "$OPT_URL" ]]; then + echo "$SCRIPTNAME: you must specify either -f or -u, but not both" + exit 1 +fi + +shift $((OPTIND - 1)) +if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi + +set -- +[ -n "$OPT_LS" ] && set -- "$@" --ez lockscreen "$OPT_LS" +[ -n "$OPT_FILE" ] && set -- "$@" --es file "$OPT_FILE" +[ -n "$OPT_URL" ] && set -- "$@" --es url "$OPT_URL" +@TERMUX_PREFIX@/libexec/termux-api Wallpaper "$@" diff --git a/scripts/termux-wifi-connectioninfo b/scripts/termux-wifi-connectioninfo.in old mode 100755 new mode 100644 similarity index 75% rename from scripts/termux-wifi-connectioninfo rename to scripts/termux-wifi-connectioninfo.in index b1a6c58..dde982f --- a/scripts/termux-wifi-connectioninfo +++ b/scripts/termux-wifi-connectioninfo.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-wifi-connectioninfo @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api WifiConnectionInfo +@TERMUX_PREFIX@/libexec/termux-api WifiConnectionInfo diff --git a/scripts/termux-wifi-enable b/scripts/termux-wifi-enable.in similarity index 69% rename from scripts/termux-wifi-enable rename to scripts/termux-wifi-enable.in index dd6cea3..9e9a1ef 100644 --- a/scripts/termux-wifi-enable +++ b/scripts/termux-wifi-enable.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-wifi-enable @@ -18,4 +18,4 @@ case $1 in *) show_usage;; esac -/data/data/com.termux/files/usr/libexec/termux-api WifiEnable --ez enabled $1 \ No newline at end of file +@TERMUX_PREFIX@/libexec/termux-api WifiEnable --ez enabled "$1" diff --git a/scripts/termux-wifi-scaninfo b/scripts/termux-wifi-scaninfo.in old mode 100755 new mode 100644 similarity index 75% rename from scripts/termux-wifi-scaninfo rename to scripts/termux-wifi-scaninfo.in index 646579d..85b5fdb --- a/scripts/termux-wifi-scaninfo +++ b/scripts/termux-wifi-scaninfo.in @@ -1,4 +1,4 @@ -#!/data/data/com.termux/files/usr/bin/sh +#!@TERMUX_PREFIX@/bin/sh set -e -u SCRIPTNAME=termux-wifi-scaninfo @@ -15,8 +15,8 @@ do ?) echo "$SCRIPTNAME: illegal option -$OPTARG"; exit 1; esac done -shift $(($OPTIND-1)) +shift $((OPTIND-1)) if [ $# != 0 ]; then echo "$SCRIPTNAME: too many arguments"; exit 1; fi -/data/data/com.termux/files/usr/libexec/termux-api WifiScanInfo +@TERMUX_PREFIX@/libexec/termux-api WifiScanInfo diff --git a/termux-api-broadcast.c b/termux-api-broadcast.c new file mode 100644 index 0000000..cfd319f --- /dev/null +++ b/termux-api-broadcast.c @@ -0,0 +1,23 @@ +/* termux-api.c - helper binary for calling termux api classes + * Usage: termux-api ${API_METHOD} ${ADDITIONAL_FLAGS} + * This executes + * am broadcast com.termux.api/.TermuxApiReceiver \ + * --es socket_input ${INPUT_SOCKET} \ + * --es socket_output ${OUTPUT_SOCKET} \ + * --es api_method ${API_METHOD} \ + * ${ADDITIONAL_FLAGS} + * where ${INPUT_SOCKET} and ${OUTPUT_SOCKET} are addresses to linux + * abstract namespace sockets, used to pass on stdin to the java + * implementation and pass back output from java to stdout. + */ + +#include "termux-api.h" + +int main(int argc, char** argv) { + /* Run the api command */ + int fd = run_api_command(argc, argv); + + if (fd != -1) { exec_callback(fd); } + + return 0; +} diff --git a/termux-api.c b/termux-api.c index 115c450..74b669b 100644 --- a/termux-api.c +++ b/termux-api.c @@ -1,12 +1,3 @@ -// termux-api.c - helper binary for calling termux api classes -// Usage: termux-api ${API_METHOD} ${ADDITIONAL_FLAGS} -// This executes -// am broadcast com.termux.api/.TermuxApiReceiver --es socket_input ${INPUT_SOCKET} -// --es socket_output ${OUTPUT_SOCKET} -// --es ${API_METHOD} -// ${ADDITIONAL_FLAGS} -// where ${INPUT_SOCKET} and ${OUTPUT_SOCKET} are addresses to linux abstract namespace sockets, -// used to pass on stdin to the java implementation and pass back output from java to stdout. #define _POSIX_SOURCE #define _GNU_SOURCE #include @@ -17,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -24,8 +16,229 @@ #include #include +#ifdef __ANDROID__ +#include +#endif + +#include "termux-api.h" + +#define TERMUX_API_PACKAGE_VERSION "0.59.1" + +#ifndef PREFIX +# define PREFIX "/data/data/com.termux/files/usr" +#endif + +#define LISTEN_SOCKET_ADDRESS "com.termux.api://listen" + +/* passes the arguments to the plugin via the unix socket, falling + * back to exec_am_broadcast() if that doesn't work + */ +_Noreturn void contact_plugin(int argc, char** argv, + char* input_address_string, + char* output_address_string) +{ + // Redirect stdout to /dev/null (but leave stderr open): + close(STDOUT_FILENO); + open("/dev/null", O_RDONLY); + // Close stdin: + close(STDIN_FILENO); + + // ignore SIGPIPE, so am will be called when the connection is closed unexpectedly + struct sigaction sigpipe_action = { + .sa_handler = SIG_IGN, + .sa_flags = 0 + }; + sigaction(SIGPIPE, &sigpipe_action, NULL); + + // Try to connect over the listen socket first if running on Android `< 14`. + // On Android `>= 14`, if termux-api app process was started previously + // and it started the socket server, but later Android froze the + // process, the socket will still be connectable, but no response + // will be received until the app process is unfrozen agin and + // `read()` call below will hang indefinitely until that happens, + // so use legacy `am broadcast` command, which will also unfreeze + // the app process to deliver the intent. + // - https://github.com/termux/termux-api/issues/638#issuecomment-1813233924 + int listenfd = -1; + #ifdef __ANDROID__ + if (android_get_device_api_level() < 34) { + listenfd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); + } + #endif + if (listenfd != -1) { + struct sockaddr_un listen_addr = { .sun_family = AF_UNIX }; + memcpy(listen_addr.sun_path+1, LISTEN_SOCKET_ADDRESS, strlen(LISTEN_SOCKET_ADDRESS)); + if (connect(listenfd, (struct sockaddr*) &listen_addr, sizeof(sa_family_t) + strlen(LISTEN_SOCKET_ADDRESS) + 1) == 0) { + socklen_t optlen = sizeof(struct ucred); + // check the uid to see if the socket is actually provided by the plugin + struct ucred cred; + if (getsockopt(listenfd, SOL_SOCKET, SO_PEERCRED, &cred, &optlen) == 0 && cred.uid == getuid()) { + + const char insock_str[] = "--es socket_input \""; + const char outsock_str[] = "--es socket_output \""; + const char method_str[] = "--es api_method \""; + + int len = 0; + len += sizeof(insock_str)-1 + strlen(output_address_string)+2; + len += sizeof(outsock_str)-1 + strlen(input_address_string)+2; + len += sizeof(method_str)-1 + strlen(argv[1])+2; + for (int i = 2; i 0) { + int ret = send(listenfd, transmit, totransmit, 0); + if (ret == -1) { + err = true; + break; + } + totransmit -= ret; + } + + // transmit the argument list + if (! err) { + totransmit = len; + transmit = buffer; + while (totransmit > 0) { + int ret = send(listenfd, transmit, totransmit, 0); + if (ret == -1) { + err = true; + break; + } + totransmit -= ret; + } + } + + if (! err) { + char readbuffer[100]; + int ret; + bool first = true; + err = true; + while ((ret = read(listenfd, readbuffer, 99)) > 0) { + // if a single null byte is received as the first message, the call was successful + if (ret == 1 && readbuffer[0] == 0 && first) { + err = false; + break; + } + // otherwise it's an error message + readbuffer[ret] = '\0'; + // printing out the error is good for debug purposes, but feel free to disable this + fprintf(stderr, "%s", readbuffer); + fflush(stderr); + first = false; + } + } + + // if everything went well, there is no need to call am + if (! err) { + exit(0); + } + } + } + } + + exec_am_broadcast(argc, argv, input_address_string, output_address_string); +} + // Function which execs "am broadcast ..". -_Noreturn void exec_am_broadcast(int argc, char** argv, char* input_address_string, char* output_address_string) +_Noreturn void exec_am_broadcast(int argc, char** argv, + char* input_address_string, + char* output_address_string) { // Redirect stdout to /dev/null (but leave stderr open): close(STDOUT_FILENO); @@ -33,8 +246,19 @@ _Noreturn void exec_am_broadcast(int argc, char** argv, char* input_address_stri // Close stdin: close(STDIN_FILENO); - int const extra_args = 15; // Including ending NULL. - char** child_argv = malloc((sizeof(char*)) * (argc + extra_args)); + const int child_pre_argc = 14; + const int child_post_argc = argc - 1; // Except `argv[0]`. + const int child_argc = child_pre_argc + child_post_argc; + + size_t child_argv_size = (sizeof(char*)) * (child_argc + 1); // Including trailing `NULL`. + // Do not directly cast, otherwise can trigger null pointer dereference if `NULL` is returned. + void* result = malloc(child_argv_size); + if (result == NULL) { + perror("malloc failed for am child args"); + exit(1); + } + + char **child_argv = (char **) result; child_argv[0] = "am"; child_argv[1] = "broadcast"; @@ -51,28 +275,58 @@ _Noreturn void exec_am_broadcast(int argc, char** argv, char* input_address_stri child_argv[11] = input_address_string; child_argv[12] = "--es"; child_argv[13] = "api_method"; - child_argv[14] = argv[1]; - // Copy the remaining arguments -2 for first binary and second api name: - memcpy(child_argv + extra_args, argv + 2, (argc-1) * sizeof(char*)); + // Copy the remaining arguments except `argv[0]`, `argv[1]` should be `api_method` extra value: + memcpy(child_argv + child_pre_argc, argv + 1, child_post_argc * sizeof(char*)); // End with NULL: - child_argv[argc + extra_args] = NULL; + child_argv[child_argc] = NULL; // Use an a executable taking care of PATH and LD_LIBRARY_PATH: - execv("/data/data/com.termux/files/usr/bin/am", child_argv); + execv(PREFIX "/bin/am", child_argv); - perror("execv(\"/data/data/com.termux/files/usr/bin/am\")"); + // We should not reach here, if we do, then free memory we malloc'ed + free(child_argv); + perror("execv(\"" PREFIX "/bin/am\")"); + exit(1); +} + +_Noreturn void exec_callback(int fd) +{ + char *fds; + if (asprintf(&fds, "%d", fd) == -1) + perror("asprintf"); + + /* TERMUX_EXPORT_FD and TERMUX_USB_FD are (currently) specific for + termux-usb, so there's some room for improvement here (this + function should be generic) */ + char errmsg[256]; + char *export_to_env = getenv("TERMUX_EXPORT_FD"); + if (export_to_env && strncmp(export_to_env, "true", 4) == 0) { + if (setenv("TERMUX_USB_FD", fds, true) == -1) + perror("setenv"); + execl(PREFIX "/libexec/termux-callback", "termux-callback", NULL); + sprintf(errmsg, "execl(\"" PREFIX "/libexec/termux-callback\")"); + } else { + execl(PREFIX "/libexec/termux-callback", "termux-callback", fds, NULL); + sprintf(errmsg, "execl(\"" PREFIX "/libexec/termux-callback\", %s)", fds); + } + perror(errmsg); exit(1); } void generate_uuid(char* str) { sprintf(str, "%x%x-%x-%x-%x-%x%x%x", - arc4random(), arc4random(), // Generates a 64-bit Hex number - (uint32_t) getpid(), // Generates a 32-bit Hex number - ((arc4random() & 0x0fff) | 0x4000), // Generates a 32-bit Hex number of the form 4xxx (4 indicates the UUID version) - arc4random() % 0x3fff + 0x8000, // Generates a 32-bit Hex number in the range [0x8000, 0xbfff] - arc4random(), arc4random(), arc4random()); // Generates a 96-bit Hex number + /* 64-bit Hex number */ + arc4random(), arc4random(), + /* 32-bit Hex number */ + (uint32_t) getpid(), + /* 32-bit Hex number of the form 4xxx (4 is the UUID version) */ + ((arc4random() & 0x0fff) | 0x4000), + /* 32-bit Hex number in the range [0x8000, 0xbfff] */ + arc4random() % 0x3fff + 0x8000, + /* 96-bit Hex number */ + arc4random(), arc4random(), arc4random()); } // Thread function which reads from stdin and writes to socket. @@ -80,7 +334,9 @@ void* transmit_stdin_to_socket(void* arg) { int output_server_socket = *((int*) arg); struct sockaddr_un remote_addr; socklen_t addrlen = sizeof(remote_addr); - int output_client_socket = accept(output_server_socket, (struct sockaddr*) &remote_addr, &addrlen); + int output_client_socket = accept(output_server_socket, + (struct sockaddr*) &remote_addr, + &addrlen); ssize_t len; char buffer[1024]; @@ -93,64 +349,117 @@ void* transmit_stdin_to_socket(void* arg) { } // Main thread function which reads from input socket and writes to stdout. -void transmit_socket_to_stdout(int input_socket_fd) { +int transmit_socket_to_stdout(int input_socket_fd) { ssize_t len; char buffer[1024]; - while ((len = read(input_socket_fd, &buffer, sizeof(buffer))) > 0) { + char cbuf[256]; + struct iovec io = { .iov_base = buffer, .iov_len = sizeof(buffer) }; + struct msghdr msg = { 0 }; + int fd = -1; // An optional file descriptor received through the socket + msg.msg_iov = &io; + msg.msg_iovlen = 1; + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); + while ((len = recvmsg(input_socket_fd, &msg, 0)) > 0) { + struct cmsghdr * cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { + if (cmsg->cmsg_type == SCM_RIGHTS) { + fd = *((int *) CMSG_DATA(cmsg)); + } + } + // A file descriptor must be accompanied by a non-empty message, + // so we use "@" when we don't want any output. + if (fd != -1 && len == 1 && buffer[0] == '@') { len = 0; } write(STDOUT_FILENO, buffer, len); + msg.msg_controllen = sizeof(cbuf); } - if (len < 0) perror("read()"); + if (len < 0) perror("recvmsg()"); + return fd; } -int main(int argc, char** argv) { +int run_api_command(int argc, char **argv) { + // If only `--version` argument is passed + if (argc == 2 && strcmp(argv[1], "--version") == 0) { + fprintf(stdout, "%s\n", TERMUX_API_PACKAGE_VERSION); + fflush(stdout); + exit(0); + } + // Do not transform children into zombies when they terminate: - struct sigaction sigchld_action = { .sa_handler = SIG_DFL, .sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_NOCLDWAIT }; + struct sigaction sigchld_action = { + .sa_handler = SIG_DFL, + .sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_NOCLDWAIT + }; sigaction(SIGCHLD, &sigchld_action, NULL); - char input_address_string[100]; // This program reads from it. - char output_address_string[100]; // This program writes to it. + char input_addr_str[100]; // This program reads from it. + char output_addr_str[100]; // This program writes to it. - generate_uuid(input_address_string); - generate_uuid(output_address_string); + generate_uuid(input_addr_str); + generate_uuid(output_addr_str); - struct sockaddr_un input_address = { .sun_family = AF_UNIX }; - struct sockaddr_un output_address = { .sun_family = AF_UNIX }; - // Leave struct sockaddr_un.sun_path[0] as 0 and use the UUID string as abstract linux namespace: - strncpy(&input_address.sun_path[1], input_address_string, strlen(input_address_string)); - strncpy(&output_address.sun_path[1], output_address_string, strlen(output_address_string)); + struct sockaddr_un input_addr = { .sun_family = AF_UNIX }; + struct sockaddr_un output_addr = { .sun_family = AF_UNIX }; + // Leave struct sockaddr_un.sun_path[0] as 0 and use the UUID + // string as abstract linux namespace: + strncpy(&input_addr.sun_path[1], input_addr_str, strlen(input_addr_str)); + strncpy(&output_addr.sun_path[1], output_addr_str, strlen(output_addr_str)); int input_server_socket = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); - if (input_server_socket == -1) { perror("socket()"); return 1; } + if (input_server_socket == -1) { + perror("socket()"); + return -1; + } int output_server_socket = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); - if (output_server_socket == -1) { perror("socket()"); return 1; } + if (output_server_socket == -1) { + perror("socket()"); + return -1; + } - if (bind(input_server_socket, (struct sockaddr*) &input_address, sizeof(sa_family_t) + strlen(input_address_string) + 1) == -1) { + int ret; + ret = bind(input_server_socket, (struct sockaddr*) &input_addr, + sizeof(sa_family_t) + strlen(input_addr_str) + 1); + if (ret == -1) { perror("bind(input)"); - return 1; + return ret; } - if (bind(output_server_socket, (struct sockaddr*) &output_address, sizeof(sa_family_t) + strlen(output_address_string) + 1) == -1) { + + ret = bind(output_server_socket, (struct sockaddr*) &output_addr, + sizeof(sa_family_t) + strlen(output_addr_str) + 1); + if (ret == -1) { perror("bind(output)"); - return 1; + return ret; } - if (listen(input_server_socket, 1) == -1) { perror("listen()"); return 1; } - if (listen(output_server_socket, 1) == -1) { perror("listen()"); return 1; } + if (listen(input_server_socket, 1) == -1) { + perror("listen()"); + return -1; + } - pid_t fork_result = fork(); - switch (fork_result) { - case -1: perror("fork()"); return 1; - case 0: exec_am_broadcast(argc, argv, input_address_string, output_address_string); + if (listen(output_server_socket, 1) == -1) { + perror("listen()"); + return -1; } + pid_t fork_result = fork(); + if (fork_result == -1) { + perror("fork()"); + return -1; + } else if (fork_result == 0) + contact_plugin(argc, argv, input_addr_str, output_addr_str); + struct sockaddr_un remote_addr; socklen_t addrlen = sizeof(remote_addr); - int input_client_socket = accept(input_server_socket, (struct sockaddr*) &remote_addr, &addrlen); + int input_client_socket = accept(input_server_socket, + (struct sockaddr*) &remote_addr, + &addrlen); pthread_t transmit_thread; - pthread_create(&transmit_thread, NULL, transmit_stdin_to_socket, &output_server_socket); - - transmit_socket_to_stdout(input_client_socket); + pthread_create(&transmit_thread, NULL, transmit_stdin_to_socket, + &output_server_socket); - return 0; + /* Device has been opened, time to actually get the fd */ + int fd = transmit_socket_to_stdout(input_client_socket); + close(input_client_socket); + return fd; } - diff --git a/termux-api.h b/termux-api.h new file mode 100644 index 0000000..c3a8edf --- /dev/null +++ b/termux-api.h @@ -0,0 +1,22 @@ +#ifndef TERMUX_API_H +#define TERMUX_API_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +_Noreturn void exec_am_broadcast(int, char**, char*, char*); +_Noreturn void contact_plugin(int, char**, char*, char*); +_Noreturn void exec_callback(int); +void generate_uuid(char*); +void* transmit_stdin_to_socket(void*); +int transmit_socket_to_stdout(int); +int run_api_command(int, char**); + +#if defined(__cplusplus) +} +#endif + +#endif /* TERMUX_API_H */ diff --git a/termux-callback.in b/termux-callback.in new file mode 100644 index 0000000..3f36e17 --- /dev/null +++ b/termux-callback.in @@ -0,0 +1,3 @@ +#!@TERMUX_PREFIX@/bin/bash +set -e -u +$TERMUX_CALLBACK "$@"