;;; noise.el --- Signal Messenger client for Emacs -*- lexical-binding: t; -*- ;; Author: Noise contributors ;; Version: 0.1.0 ;; Package-Requires: ((emacs "27.1")) ;; Keywords: comm ;;; Commentary: ;; Noise is a Signal Messenger client powered by signal-cli JSON-RPC. ;;; Code: (require 'noise-rpc) (require 'noise-chat-list) (require 'noise-conversation) (require 'noise-new-chat) (require 'noise-receive) (defgroup noise nil "Signal Messenger client for Emacs." :group 'comm :prefix "noise-") (defcustom noise-signal-cli-address "http://localhost:8080" "Base URL of the signal-cli JSON-RPC daemon. Format: http://HOST:PORT The default port is 8080, matching signal-cli's `--http` default." :type 'string :group 'noise) (defcustom noise-account nil "The Signal account to use, as a phone number in E.164 format. signal-cli can have multiple accounts registered. When the daemon serves more than one account, every request must say which account it is for, so this must be set (e.g. \"+15551234567\"). When nil, the daemon is assumed to serve a single account (started with `-a`). Use `noise-select-account' to pick one interactively from the accounts registered with signal-cli." :type '(choice (const :tag "Single-account daemon" nil) (string :tag "Phone number (E.164)")) :group 'noise) (defcustom noise-sse-max-reconnect-delay 60 "Maximum delay in seconds between SSE reconnection attempts." :type 'integer :group 'noise) ;;;###autoload (defun noise-select-account () "Select which signal-cli account Noise should use. Queries the daemon for registered accounts and sets `noise-account'." (interactive) (let* ((accounts (noise-rpc-call "listAccounts")) (numbers (mapcar (lambda (a) (gethash "number" a)) (append accounts nil)))) (cond ((null numbers) (user-error "No accounts registered with signal-cli")) ((null (cdr numbers)) (setq noise-account (car numbers))) (t (setq noise-account (completing-read "Signal account: " numbers nil t)))) (message "Using Signal account %s" noise-account))) ;;;###autoload (defun noise-check-connection () "Check connectivity to the signal-cli JSON-RPC daemon." (interactive) (condition-case err (progn (noise-rpc-check) (message "signal-cli connected at %s" noise-signal-cli-address)) (noise-rpc-error (message "Error: %s" (cdr err))))) (defun noise--unread-lighter () "Return the mode-line lighter string with unread count." (let ((count 0)) (when (and (boundp 'noise-db--connection) noise-db--connection (fboundp 'sqlitep) (sqlitep noise-db--connection)) (condition-case nil (setq count (or (caar (sqlite-select noise-db--connection "SELECT COALESCE(SUM(unread_count), 0) FROM conversations")) 0)) (error 0))) (if (> count 0) (format " Noise[%d]" count) " Noise"))) ;;;###autoload (define-minor-mode noise-mode "Toggle Noise Signal client mode." :global t :lighter (:eval (noise--unread-lighter)) :group 'noise (if noise-mode (progn (noise-chat-list) (noise-receive-start-sse)) (noise-receive-stop-sse) (message "Noise mode disabled"))) (provide 'noise) ;;; noise.el ends here