summaryrefslogtreecommitdiff
path: root/lisp/net/rcirc.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/net/rcirc.el')
-rw-r--r--lisp/net/rcirc.el126
1 files changed, 84 insertions, 42 deletions
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index 8feef6beebe..0d30b349229 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -262,6 +262,7 @@ The ARGUMENTS for each METHOD symbol are:
`bitlbee': NICK PASSWORD
`quakenet': ACCOUNT PASSWORD
`sasl': NICK PASSWORD
+ `certfp': KEY CERT
Examples:
((\"Libera.Chat\" nickserv \"bob\" \"p455w0rd\")
@@ -291,7 +292,11 @@ Examples:
(list :tag "SASL"
(const sasl)
(string :tag "Nick")
- (string :tag "Password")))))
+ (string :tag "Password"))
+ (list :tag "CertFP"
+ (const certfp)
+ (string :tag "Key")
+ (string :tag "Certificate")))))
(defcustom rcirc-auto-authenticate-flag t
"Non-nil means automatically send authentication string to server.
@@ -428,6 +433,20 @@ will be killed."
:version "28.1"
:type 'boolean)
+(defcustom rcirc-cycle-completion-flag nil
+ "Non-nil means to use cycling for completion in rcirc buffers.
+See the Info node `(emacs) Completion Options' for background on
+what cycling completion means."
+ :version "29.1"
+ :set (lambda (sym val)
+ (dolist (buf (match-buffers '(major-mode . rcirc-mode)))
+ (with-current-buffer buf
+ (if val
+ (setq-local completion-cycle-threshold t)
+ (kill-local-variable 'completion-cycle-threshold))))
+ (set-default sym val))
+ :type 'boolean)
+
(defvar-local rcirc-nick nil
"The nickname used for the current connection.")
@@ -547,13 +566,16 @@ If ARG is non-nil, instead prompt for connection parameters."
(password (plist-get (cdr c) :password))
(encryption (plist-get (cdr c) :encryption))
(server-alias (plist-get (cdr c) :server-alias))
+ (client-cert (when (eq (rcirc-get-server-method (car c))
+ 'certfp)
+ (rcirc-get-server-cert (car c))))
contact)
(when-let (((not password))
(auth (auth-source-search :host server
:user user-name
:port port))
- (fn (plist-get (car auth) :secret)))
- (setq password (funcall fn)))
+ (pwd (auth-info-password (car auth))))
+ (setq password pwd))
(when server
(let (connected)
(dolist (p (rcirc-process-list))
@@ -563,7 +585,7 @@ If ARG is non-nil, instead prompt for connection parameters."
(condition-case nil
(let ((process (rcirc-connect server port nick user-name
full-name channels password encryption
- server-alias)))
+ client-cert server-alias)))
(when rcirc-display-server-buffer
(pop-to-buffer-same-window (process-buffer process))))
(quit (message "Quit connecting to %s"
@@ -646,29 +668,23 @@ See `rcirc-connect' for more details on these variables.")
(defun rcirc-get-server-method (server)
"Return authentication method for SERVER."
- (catch 'method
- (dolist (i rcirc-authinfo)
- (let ((server-i (car i))
- (method (cadr i)))
- (when (string-match server-i server)
- (throw 'method method))))))
+ (cadr (assoc server rcirc-authinfo #'string-match)))
(defun rcirc-get-server-password (server)
"Return password for SERVER."
- (catch 'pass
- (dolist (i rcirc-authinfo)
- (let ((server-i (car i))
- (args (cdddr i)))
- (when (string-match server-i server)
- (throw 'pass (car args)))))))
+ (cadddr (assoc server rcirc-authinfo #'string-match)))
+
+(defun rcirc-get-server-cert (server)
+ "Return a list of key and certificate for SERVER."
+ (cddr (assoc server rcirc-authinfo #'string-match)))
;;;###autoload
(defun rcirc-connect (server &optional port nick user-name
full-name startup-channels password encryption
- server-alias)
+ certfp server-alias)
"Connect to SERVER.
The arguments PORT, NICK, USER-NAME, FULL-NAME, PASSWORD,
-ENCRYPTION, SERVER-ALIAS are interpreted as in
+ENCRYPTION, CERTFP, SERVER-ALIAS are interpreted as in
`rcirc-server-alist'. STARTUP-CHANNELS is a list of channels
that are joined after authentication."
(save-excursion
@@ -695,6 +711,7 @@ that are joined after authentication."
(setq process (open-network-stream
(or server-alias server) nil server port-number
:type (or encryption 'plain)
+ :client-certificate certfp
:nowait t))
(set-process-coding-system process 'raw-text 'raw-text)
(with-current-buffer (get-buffer-create (rcirc-generate-new-buffer-name process nil))
@@ -713,8 +730,8 @@ that are joined after authentication."
(setq rcirc-nick-table (make-hash-table :test 'equal))
(setq rcirc-nick nick)
(setq rcirc-startup-channels startup-channels)
- (setq rcirc-last-server-message-time (current-time))
(setq rcirc-last-connect-time (current-time))
+ (setq rcirc-last-server-message-time rcirc-last-connect-time)
;; Check if the immediate process state
(sit-for .1)
@@ -754,18 +771,26 @@ SERVER-PLIST is the property list for the server."
(yes-or-no-p "Encrypt connection?"))
'tls 'plain))
+(defvar rcirc-reconnect-delay)
(defun rcirc-keepalive ()
"Send keep alive pings to active rcirc processes.
Kill processes that have not received a server message since the
last ping."
(if (rcirc-process-list)
(mapc (lambda (process)
- (with-rcirc-process-buffer process
- (when (not rcirc-connecting)
- (rcirc-send-ctcp process
- rcirc-nick
- (format "KEEPALIVE %f"
- (float-time))))))
+ (with-rcirc-process-buffer process
+ (when (not rcirc-connecting)
+ (condition-case nil
+ (rcirc-send-ctcp process
+ rcirc-nick
+ (format "KEEPALIVE %f"
+ (float-time)))
+ (rcirc-closed-connection
+ (if (zerop rcirc-reconnect-delay)
+ (message "rcirc: Connection to %s closed"
+ (process-name process))
+ (rcirc-reconnect process))
+ (message ""))))))
(rcirc-process-list))
;; no processes, clean up timer
(when (timerp rcirc-keepalive-timer)
@@ -1057,17 +1082,18 @@ Note that the messages are stored in reverse order.")
;; expression and `rcirc-process-regexp'.
(error "Malformed tag %S" tag))
(cons (match-string 1 tag)
- (replace-regexp-in-string
- (rx (* ?\\ ?\\) ?\\ (any ?: ?s ?\\ ?r ?n))
- (lambda (rep)
- (concat (substring rep 0 -2)
- (cl-case (aref rep (1- (length rep)))
- (?: ";")
- (?s " ")
- (?\\ "\\\\")
- (?r "\r")
- (?n "\n"))))
- (match-string 2 tag))))
+ (when (match-string 2 tag)
+ (replace-regexp-in-string
+ (rx (* ?\\ ?\\) ?\\ (any ?: ?s ?\\ ?r ?n))
+ (lambda (rep)
+ (concat (substring rep 0 -2)
+ (cl-case (aref rep (1- (length rep)))
+ (?: ";")
+ (?s " ")
+ (?\\ "\\\\")
+ (?r "\r")
+ (?n "\n"))))
+ (match-string 2 tag)))))
(split-string tag-data ";"))))
rcirc-message-tags))
(user (match-string 3 text))
@@ -1119,6 +1145,8 @@ used as the message body."
"Check if PROCESS is open or running."
(memq (process-status process) '(run open)))
+(define-error 'rcirc-closed-connection "Network connection not open")
+
(defun rcirc-send-string (process &rest parts)
"Send PROCESS a PARTS plus a newline.
PARTS may contain a `:' symbol, to designate that the next string
@@ -1136,8 +1164,7 @@ element in PARTS is a list, append it to PARTS."
rcirc-encode-coding-system)
"\n")))
(unless (rcirc--connection-open-p process)
- (error "Network connection to %s is not open"
- (process-name process)))
+ (signal 'rcirc-closed-connection process))
(rcirc-debug process string)
(process-send-string process string)))
@@ -1431,7 +1458,8 @@ PROCESS is the process object used for communication.
(add-hook 'completion-at-point-functions
'rcirc-completion-at-point nil 'local)
- (setq-local completion-cycle-threshold t)
+ (when rcirc-cycle-completion-flag
+ (setq-local completion-cycle-threshold t))
(run-mode-hooks 'rcirc-mode-hook))
@@ -2044,6 +2072,13 @@ connection."
(run-hook-with-args 'rcirc-print-functions
process sender response target text)))))
+(defun rcirc-when ()
+ "Show the time of reception of the message at point."
+ (interactive)
+ (if-let (time (get-text-property (point) 'rcirc-time))
+ (message (format-time-string "%c" time))
+ (message "No time information at point.")))
+
(defun rcirc-generate-log-filename (process target)
"Return filename for log file based on PROCESS and TARGET."
(if target
@@ -2582,15 +2617,22 @@ that, an interactive form can specified."
(defun ,fn-name (,argument &optional process target)
,(concat documentation
"\n\nNote: If PROCESS or TARGET are nil, the values given"
- "\nby `rcirc-buffer-process' and `rcirc-target' will be used.")
- (interactive (list ,interactive-spec))
+ "\nby `rcirc-buffer-process' and `rcirc-target' will be used.")
+ (interactive ,(if (stringp interactive-spec)
+ ;; HACK: Necessary to wrap the result of
+ ;; the interactive spec in a list.
+ `(list (call-interactively
+ (lambda (&rest args)
+ (interactive ,interactive-spec)
+ args)))
+ `(list ,interactive-spec)))
(unless (if (listp ,argument)
(<= ,required (length ,argument) ,total)
(string-match ,regexp ,argument))
(user-error "Malformed input (%s): %S" ',command ,argument))
(push ,(upcase (symbol-name command)) rcirc-pending-requests)
(let ((process (or process (rcirc-buffer-process)))
- (target (or target rcirc-target)))
+ (target (or target rcirc-target)))
(ignore target process)
(let (,@(cl-loop
for i from 0 for arg in (delq '&optional arguments)