;;; termux.el --- Termux functions. -*- lexical-binding: t; -*- ;; Copyright (C) 2016-2021 by Jean Louis ;; Author: Jean Louis ;; Version: 0.1 ;; Package-Requires: (rcd-utilities rcd-cf rcd-db-init rcd-db time-date) ;; Keywords: ;; URL: https://gnu.support/gnu-emacs/packages/termux-el.html ;; This file is not part of GNU Emacs. ;; This program is free software: you can redistribute it and/or ;; modify it under the terms of the GNU General Public License as ;; published by the Free Software Foundation, either version 3 of the ;; License, or (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, but ;; WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; These are the Termux utilities for GNU Emacs Lisp ;; ;; RCD is acronym for Reach, Connect, Deliver, my personal ;; principle and formula for Wealth. ;;; Change Log: ;;; Code: (require 'rcd-db-init) (require 'rcd-db) (require 'rcd-utilities) (require 'subr-x) (require 'time-date) (defcustom termux-ip "192.168.43.1" "IP Address of Replicant system" :type 'string :group 'Termux) (setq termux-ip "192.168.42.129") ;;(setq termux-ip "192.168.43.1") (defvar termux-ssh-command "ssh") (defvar termux-ssh-port "8022") (defvar termux-bin-directory "/data/data/com.termux/files/usr/bin/") ;;;; END OF SETUP (defun termux/send-command (command) "Sends command to connected Replicant device and returns the output string" (let* ((command (concat termux-ssh-command " -p " termux-ssh-port " " termux-ip " \"" command "\"")) (output (shell-command-to-string command)) (output (string-trim output))) output)) (defun termux/error (error) "Messages error" (message error)) (defun termux/escape-double-quotes (s) "Escapes double quotes" (replace-regexp-in-string "\"" "\\\\\"" s)) (defun termux/escape-single-quotes (s) "Escapes single quotes" (replace-regexp-in-string "'" "\'" s)) (defun termux/escape-quotes (s) "Escapes double and single quotes" (let* ((s (termux/escape-double-quotes s))) ;;(s (termux/escape-single-quotes s))) s)) (defun termux/commands () "Returns the list of all available termux commands and run the command if available." (interactive) (let* ((command (concat "cd " termux-bin-directory " && ls termux*")) (commands (termux/send-command command)) (commands (split-string commands "\n")) (commands (append commands '("insert-location"))) (command (completing-read "Termux commands: " commands)) (command (intern (concat "termux/" command)))) (if (functionp command) (funcall command) (message (concat "Command " (symbol-name command) " does not exist"))))) (defun termux/termux-location () (let* ((command "termux-location") (result (termux/send-command command)) (parsed (json-parse-string result))) (if (gethash "longitude" parsed) (let* ((latitude (number-to-string (gethash "latitude" parsed))) (longitude (number-to-string (gethash "longitude" parsed))) (location (concat latitude "," longitude))) location) (termux/error "Could not get location")))) (defun termux/termux-location-insert () "Inserts current location in the buffer" (interactive) (let ((location (termux/termux-location))) (insert location))) (defun termux/termux-clipboard-get () "Returns the Replicant clipboard value" (let* ((command "termux-clipboard-get") (result (termux/send-command command))) result)) (defun termux/termux-clipboard-get-insert () "Inserts the Replicant clipboard value" (interactive) (let ((clipboard (termux/termux-clipboard-get))) (insert clipboard))) (defun termux/termux-clipboard-set (value) "Sets the Replicant clipboard value" (interactive "MSet clipboard to: ") (let* ((value (termux/escape-double-quotes value)) (command (concat "termux-clipboard-set \"" value "\""))) (termux/send-command command))) (defun termux/termux-wifi-enable (boolean) ;; TODO "Enable or disable Wi-Fi on Replicant" (interactive "MEnable Wi-Fi (T for true, F or else for false): ") (let* ((boolean (if (string-match "t" (downcase boolean)) "true" "false")) (command (concat "termux-wifi-enable \"" boolean "\""))) (termux/send-command command))) (defun termux/termux-tts-speak (text) "Speaks by using termux" (interactive "MText to speak: ") (let* ((text (termux/escape-quotes text)) (command (concat "termux-tts-speak \"" text "\""))) (termux/send-command command))) (defun termux/termux-vibrate () "Vibrate Replicant device" (interactive) (let* ((command "termux-vibrate")) (termux/send-command command))) ;; (defun termux-sms-send (number text) ;; "Sends SMS message by using termux" ;; (interactive "MNumber: \nMText: ") ;; (let* ((text (termux/escape-double-quotes text)) ;; (command (concat "termux-sms-send -n \"" number "\" \"" text "\""))) ;; (termux/send-command command))) (defun termux-sms-send (number text) "Send SMS message by using ShellMS application" (let* ((text (termux/escape-quotes text)) (command (format "am startservice --user 0 -n com.android.shellms/.sendSMS -e contact %s -e msg \\\"%s\\\"" number text))) (termux/send-command command))) ;; (termux-sms-send "+123" sms) ;; (termux-sms-send "+123" "Hello") ;; (termux-sms-send "+123" "Hello thank you, but I do not have this number registered, what is your name?") (defun termux-import-sms-list () (interactive) (let* ((command "termux-sms-list -t inbox -l 500") (list (termux/send-command command)) (list (json-parse-string list)) (remainder-file (concat (getenv "TMPDIR") "SMS-import-" (rcd-timestamp) ".el")) (_ (data-to-file list remainder-file)) (how-many (length list))) (dotimes (n how-many) (let ((sms (elt list n))) (cf-sms-insert sms))))) ;; (termux-import-sms-list) (defun cf-sms-handle (sms) "Returns list after reading the `sms' hash" (let* ((type (gethash "type" sms)) (status (cf-sms-status type)) (number (gethash "number" sms)) (date-received (gethash "received" sms)) (body (gethash "body" sms))) (list status number date-received body))) (defun cf-sms-status (status) (cond ((string= status "inbox") 2) (t (error (concat "Cannot find SMS type: " status))))) (defun cf-sms-insert (sms) "Inserts the SMS hash into the database" (let ((exists (cf-sms-imported-exists sms))) (if exists (message-any sms) (let* ((sms (cf-sms-handle sms)) (status (elt sms 0)) (number (elt sms 1)) (date-received (elt sms 2)) (date-received (cf-sms-repair-date date-received)) (body (elt sms 3)) (body (sql-escape-string body)) (id (cf-contact-by-phone-1 number)) (sql (format "INSERT INTO sms (sms_datecreated, sms_contacts, sms_smsstatus, sms_body, sms_phone) VALUES ('%s', %s, %s, %s, '%s') RETURNING sms_id" date-received id status body number))) (if id (rcd-sql-first sql *cf*) (message (format "SMS not entered: %s" (prin1-to-string sms)))))))) (defun cf-sms-imported-exists (sms) (let* ((sms (cf-sms-handle sms)) (status (elt sms 0)) (number (elt sms 1)) (date-received (elt sms 2)) (date-received (cf-sms-repair-date date-received)) (body (elt sms 3)) (body (sql-escape-string body)) (id (cf-contact-by-phone-1 number)) (sql (format "SELECT * FROM sms WHERE sms_datecreated = '%s' AND sms_contacts = %s AND sms_smsstatus = %s AND sms_body = %s AND sms_phone = '%s'" date-received id status body number))) (if id (let ((ids (rcd-sql-list sql *cf*))) (if ids ids nil)) (message (format "SMS did not find ID: %s" (prin1-to-string sms)))))) (defun cf-sms-repair-date (date) "Repairs the date give by `termux-sms-list' function" (let* ((time (decoded-time-add (parse-time-string date) '(nil nil nil nil nil nil nil nil nil))) (year (decoded-time-year time)) (month (decoded-time-month time)) (day (decoded-time-day time)) (hour (decoded-time-hour time)) (minute (decoded-time-minute time)) (second (decoded-time-second time)) (date-time (format "%04.f-%02.f-%02.f %02.f:%02.f:%02.f" year month day hour minute second))) date-time)) ;; (defun termux-sms-list () ;; (interactive) ;; (let* ((command "termux-sms-list -t inbox -l 500") ;; (list (termux/send-command command)) ;; (list (json-parse-string list)) ;; (how-many (length list))) ;; (dotimes (n how-many) ;; (let ((sms (elt list n))) ;; (cf-sms-insert sms))))) (defun rcd-kdeconnect-send-sms (number message) (let* ((status (shell-command (mapconcat 'identity (list "kdeconnect-cli" "-d" ;; "73fc592ea61a3a70" ;; Airtel "c47e5d958b455603" ;; MTN "--destination" number "--send-sms" (shell-quote-argument message)) " ")))) status)) (defvar rcd-prefixes-uganda-airtel-mobile '(700 701 702 703 704 705 706 710 711 712 713 714 715 716 717 718 719 750 751 752 753 754 755 756 757 758 759)) (defvar rcd-prefixes-uganda-mtn-mobile '(770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789)) (defun rcd-sql-phone-national-prefix-or (country-prefix prefixes) (let* ((country-prefix (if (numberp country-prefix) (number-to-string country-prefix) country-prefix)) (prefixes (mapcar (lambda (n) (single-quote (concat country-prefix (number-to-string n)))) prefixes)) (prefixes (string-join prefixes ", "))) prefixes)) (defun rcd-sql-phone-recent-people-by-mobile-prefix (prefixes &optional how-many) (let* ((how-many (or how-many 200)) (sql (format "SELECT people_id, get_full_contacts_name(people_id) FROM people WHERE (substring(people_officephone, 2, 6) IN (%s) OR substring(people_mobilephone, 2, 6) IN (%s) OR substring(people_homephone, 2, 6) IN (%s) OR substring(people_otherphone, 2, 6) IN (%s) OR substring(people_fax, 2, 6) IN (%s)) ORDER BY people_id DESC LIMIT %s" prefixes prefixes prefixes prefixes prefixes how-many))) sql)) (defun cf-tabulated-people-recent-by-airtel-mobile () (interactive) (let* ((prefixes (rcd-sql-phone-national-prefix-or 256 rcd-prefixes-uganda-airtel-mobile)) (sql (rcd-sql-phone-recent-people-by-mobile-prefix prefixes))) (rcd-db-sql-report-two "Recent people with UG Airtel numbers" sql [("ID" 8) ("Person" 80)] "people" nil))) (provide 'termux) ;;; termux.el ends here