summaryrefslogtreecommitdiff
path: root/lisp/erc/erc.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/erc/erc.el')
-rw-r--r--lisp/erc/erc.el456
1 files changed, 278 insertions, 178 deletions
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 73202016ba7..df6c3c09d90 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -3,6 +3,7 @@
;; Copyright (C) 1997-2021 Free Software Foundation, Inc.
;; Author: Alexander L. Belikoff (alexander@belikoff.net)
+;; Maintainer: Amin Bandali <bandali@gnu.org>
;; Contributors: Sergey Berezin (sergey.berezin@cs.cmu.edu),
;; Mario Lang (mlang@delysid.org),
;; Alex Schroeder (alex@gnu.org)
@@ -11,10 +12,10 @@
;; David Edmondson (dme@dme.org)
;; Michael Olson (mwolson@gnu.org)
;; Kelvin White (kwhite@gnu.org)
-;; Maintainer: Amin Bandali <bandali@gnu.org>
+;; Version: 5.4.1
+;; Package-Requires: ((emacs "27.1"))
;; Keywords: IRC, chat, client, Internet
-
-;; Version: 5.3
+;; URL: https://www.gnu.org/software/emacs/erc.html
;; This file is part of GNU Emacs.
@@ -57,7 +58,7 @@
;;; Code:
-(load "erc-loaddefs" nil t)
+(load "erc-loaddefs" 'noerror 'nomessage)
(require 'cl-lib)
(require 'format-spec)
@@ -68,10 +69,23 @@
(require 'iso8601)
(eval-when-compile (require 'subr-x))
+(defconst erc-version "5.4.1"
+ "This version of ERC.")
+
(defvar erc-official-location
"https://www.gnu.org/software/emacs/erc.html (mailing list: emacs-erc@gnu.org)"
"Location of the ERC client on the Internet.")
+;; Map each :package-version to the associated Emacs version.
+;; (This eliminates the need for explicit :version keywords on the
+;; custom definitions.)
+(add-to-list
+ 'customize-package-emacs-version-alist
+ '(ERC ("5.2" . "22.1")
+ ("5.3" . "23.1")
+ ("5.4" . "28.1")
+ ("5.4.1" . "29.1")))
+
(defgroup erc nil
"Emacs Internet Relay Chat client."
:link '(url-link "https://www.gnu.org/software/emacs/erc.html")
@@ -80,32 +94,32 @@
:group 'applications)
(defgroup erc-buffers nil
- "Creating new ERC buffers"
+ "Creating new ERC buffers."
:group 'erc)
(defgroup erc-display nil
- "Settings for how various things are displayed"
+ "Settings for how various things are displayed."
:group 'erc)
(defgroup erc-mode-line-and-header nil
- "Displaying information in the mode-line and header"
+ "Displaying information in the mode-line and header."
:group 'erc-display)
(defgroup erc-ignore nil
- "Ignoring certain messages"
+ "Ignoring certain messages."
:group 'erc)
(defgroup erc-lurker nil
- "Hide specified message types sent by lurkers"
+ "Hide specified message types sent by lurkers."
:version "24.3"
:group 'erc-ignore)
(defgroup erc-query nil
- "Using separate buffers for private discussions"
+ "Using separate buffers for private discussions."
:group 'erc)
(defgroup erc-quit-and-part nil
- "Quitting and parting channels"
+ "Quitting and parting channels."
:group 'erc)
(defgroup erc-paranoia nil
@@ -113,7 +127,7 @@
:group 'erc)
(defgroup erc-scripts nil
- "Running scripts at startup and with /LOAD"
+ "Running scripts at startup and with /LOAD."
:group 'erc)
(require 'erc-backend)
@@ -157,9 +171,7 @@ parameters and authentication."
:type 'string)
(defcustom erc-try-new-nick-p t
- "If the nickname you chose isn't available, and this option is non-nil,
-ERC should automatically attempt to connect with another nickname.
-
+ "Non-nil means attempt to connect with another nickname if nickname unavailable.
You can manually set another nickname with the /NICK command."
:group 'erc
:type 'boolean)
@@ -189,10 +201,12 @@ parameters and authentication."
It is not strictly necessary to provide this, since ERC will
prompt you for it.")
-(defcustom erc-user-mode nil
+(defcustom erc-user-mode "+i"
+ ;; +i "Invisible". Hides user from global /who and /names.
"Initial user modes to be set after a connection is established."
:group 'erc
- :type '(choice (const nil) string function))
+ :type '(choice (const nil) string function)
+ :version "28.1")
(defcustom erc-prompt-for-password t
@@ -280,9 +294,9 @@ indicate it has handled the input."
:type 'hook)
(defcustom erc-join-hook nil
- "Hook run when we join a channel. Hook functions are called
-without arguments, with the current buffer set to the buffer of
-the new channel.
+ "Hook run when we join a channel.
+Hook functions are called without arguments, with the current
+buffer set to the buffer of the new channel.
See also `erc-server-JOIN-functions', `erc-part-hook'."
:group 'erc-hooks
@@ -328,15 +342,15 @@ Functions are passed a buffer as the first argument."
(defvar-local erc-channel-users nil
- "A hash table of members in the current channel, which
-associates nicknames with cons cells of the form:
+ "Hash table of members in the current channel.
+It associates nicknames with cons cells of the form:
\(USER . MEMBER-DATA) where USER is a pointer to an
erc-server-user struct, and MEMBER-DATA is a pointer to an
erc-channel-user struct.")
(defvar-local erc-server-users nil
- "A hash table of users on the current server, which associates
-nicknames with erc-server-user struct instances.")
+ "Hash table of users on the current server.
+It associates nicknames with `erc-server-user' struct instances.")
(defun erc-downcase (string)
"Convert STRING to IRC standard conforming downcase."
@@ -380,13 +394,11 @@ If no server buffer exists, return nil."
(last-message-time nil))
(define-inline erc-get-channel-user (nick)
- "Find the (USER . CHANNEL-DATA) element corresponding to NICK
-in the current buffer's `erc-channel-users' hash table."
+ "Find NICK in the current buffer's `erc-channel-users' hash table."
(inline-quote (gethash (erc-downcase ,nick) erc-channel-users)))
(define-inline erc-get-server-user (nick)
- "Find the USER corresponding to NICK in the current server's
-`erc-server-users' hash table."
+ "Find NICK in the current server's `erc-server-users' hash table."
(inline-letevals (nick)
(inline-quote (erc-with-server-buffer
(gethash (erc-downcase ,nick) erc-server-users)))))
@@ -533,10 +545,10 @@ Removes all users in the current channel. This is called by
(erc-channel-user-voice (cdr cdata))))))))
(defun erc-get-channel-user-list ()
- "Return a list of users in the current channel. Each element
-of the list is of the form (USER . CHANNEL-DATA), where USER is
-an erc-server-user struct, and CHANNEL-DATA is either nil or an
-erc-channel-user struct.
+ "Return a list of users in the current channel.
+Each element of the list is of the form (USER . CHANNEL-DATA),
+where USER is an erc-server-user struct, and CHANNEL-DATA is
+either nil or an erc-channel-user struct.
See also: `erc-sort-channel-users-by-activity'."
(let (users)
@@ -816,7 +828,7 @@ set if some hacker is trying to flood you away."
(defcustom erc-system-name nil
"Use this as the name of your system.
-If nil, ERC will call `system-name' to get this information."
+If nil, ERC will call function `system-name' to get this information."
:group 'erc
:type '(choice (const :tag "Default system name" nil)
string))
@@ -860,8 +872,8 @@ See `erc-server-flood-margin' for other flood-related parameters.")
;; Script parameters
(defcustom erc-startup-file-list
- (list (concat user-emacs-directory ".ercrc.el")
- (concat user-emacs-directory ".ercrc")
+ (list (locate-user-emacs-file ".ercrc.el")
+ (locate-user-emacs-file ".ercrc")
"~/.ercrc.el" "~/.ercrc" ".ercrc.el" ".ercrc")
"List of files to try for a startup script.
The first existent and readable one will get executed.
@@ -1280,7 +1292,7 @@ Example:
#\\='erc-replace-insert))
((remove-hook \\='erc-insert-modify-hook
#\\='erc-replace-insert)))"
- (declare (doc-string 3))
+ (declare (doc-string 3) (indent defun))
(let* ((sn (symbol-name name))
(mode (intern (format "erc-%s-mode" (downcase sn))))
(group (intern (format "erc-%s" (downcase sn))))
@@ -1383,8 +1395,7 @@ If BUFFER is nil, the current buffer is used."
(null (erc-default-target)))))
(defun erc-open-server-buffer-p (&optional buffer)
- "Return non-nil if argument BUFFER is an ERC server buffer that
-has an open IRC process.
+ "Return non-nil if BUFFER is an ERC server buffer with an open IRC process.
If BUFFER is nil, the current buffer is used."
(and (erc-server-buffer-p buffer)
@@ -1468,6 +1479,7 @@ Defaults to the server buffer."
(define-derived-mode erc-mode fundamental-mode "ERC"
"Major mode for Emacs IRC."
+ :interactive nil
(setq local-abbrev-table erc-mode-abbrev-table)
(setq-local next-line-add-newlines nil)
(setq line-move-ignore-invisible t)
@@ -1487,8 +1499,8 @@ Defaults to the server buffer."
"IRC port to use if it cannot be detected otherwise.")
(defconst erc-default-port-tls 6697
- "IRC port to use for encrypted connections if it cannot be
- detected otherwise.")
+ "IRC port to use for encrypted connections if it cannot be \
+detected otherwise.")
(defcustom erc-join-buffer 'buffer
"Determines how to display a newly created IRC buffer.
@@ -1732,20 +1744,11 @@ FORMS will be evaluated in all buffers having the process PROCESS and
where PRED matches or in all buffers of the server process if PRED is
nil."
(declare (indent 1) (debug (form form body)))
- ;; Make the evaluation have the correct order
- (let ((pre (make-symbol "pre"))
- (pro (make-symbol "pro")))
- `(let* ((,pro ,process)
- (,pre ,pred)
- (res (mapcar (lambda (buffer)
- (with-current-buffer buffer
- ,@forms))
- (erc-buffer-list ,pre
- ,pro))))
- ;; Silence the byte-compiler by binding the result of mapcar to
- ;; a variable.
- (ignore res)
- res)))
+ (macroexp-let2 nil pred pred
+ `(erc-buffer-filter (lambda ()
+ (when (or (not ,pred) (funcall ,pred))
+ ,@forms))
+ ,process)))
(define-obsolete-function-alias 'erc-iswitchb #'erc-switch-to-buffer "25.1")
(defun erc--switch-to-buffer (&optional arg)
@@ -2271,7 +2274,7 @@ first element is the certificate key file name, and the second
element is the certificate file name itself, or t, which means
that `auth-source' will be queried for the key and the
certificate. Authenticating using a TLS client certificate is
-also refered to as \"CertFP\" (Certificate Fingerprint)
+also referred to as \"CertFP\" (Certificate Fingerprint)
authentication by various IRC networks.
Example usage:
@@ -2312,6 +2315,22 @@ message instead, to make debugging easier."
;;; Debugging the protocol
+(defvar erc-debug-irc-protocol-time-format "%FT%T.%6N%z "
+ "Timestamp format string for protocol logger.")
+
+(defconst erc-debug-irc-protocol-version "1"
+ "Protocol log format version number.
+This exists to help tooling track changes to the format.
+
+In version 1, everything before and including the first double CRLF is
+front matter, which must also be CRLF terminated. Lines beginning with
+three asterisks must be ignored as comments. Other lines should be
+interpreted as email-style headers. Folding is not supported. A second
+double CRLF, if present, signals the end of a log. Session resumption
+is not supported. Logger lines must adhere to the following format:
+TIMESTAMP PEER-NAME FLOW-INDICATOR IRC-MESSAGE CRLF. Outgoing messages
+are indicated with a >> and incoming with a <<.")
+
(defvar erc-debug-irc-protocol nil
"If non-nil, log all IRC protocol traffic to the buffer \"*erc-protocol*\".
@@ -2333,32 +2352,32 @@ This only has any effect if `erc-debug-irc-protocol' is non-nil.
The buffer is created if it doesn't exist.
-If OUTBOUND is non-nil, STRING is being sent to the IRC server
-and appears in face `erc-input-face' in the buffer."
+If OUTBOUND is non-nil, STRING is being sent to the IRC server and
+appears in face `erc-input-face' in the buffer. Lines must already
+contain CRLF endings. Peer is identified by the most precise label
+available at run time, starting with the network name, followed by the
+announced host name, and falling back to the dialed <server>:<port>."
(when erc-debug-irc-protocol
- (let ((network-name (or (ignore-errors (erc-network-name))
- "???")))
+ (let ((esid (or (and (fboundp 'erc-network)
+ (erc-network)
+ (erc-network-name))
+ erc-server-announced-name
+ (format "%s:%s" erc-session-server erc-session-port)))
+ (ts (when erc-debug-irc-protocol-time-format
+ (format-time-string erc-debug-irc-protocol-time-format))))
(with-current-buffer (get-buffer-create "*erc-protocol*")
(save-excursion
(goto-char (point-max))
(let ((inhibit-read-only t))
- (insert (if (not outbound)
- ;; Cope with the fact that string might
- ;; contain multiple lines of text.
- (let ((lines (delete "" (split-string string
- "\n\\|\r\n")))
- (result ""))
- (dolist (line lines)
- (setq result (concat result network-name
- " << " line "\n")))
- result)
- (propertize
- (concat network-name " >> " string
- (if (/= ?\n
- (aref string
- (1- (length string))))
- "\n"))
- 'font-lock-face 'erc-input-face)))))
+ (insert (if outbound
+ (concat ts esid " >> " string)
+ ;; Cope with multi-line messages
+ (let ((lines (split-string string "[\r\n]+" t))
+ result)
+ (dolist (line lines)
+ (setq result (concat result ts esid
+ " << " line "\r\n")))
+ result)))))
(let ((orig-win (selected-window))
(debug-buffer-window (get-buffer-window (current-buffer) t)))
(when debug-buffer-window
@@ -2377,9 +2396,18 @@ If ARG is non-nil, show the *erc-protocol* buffer."
(with-current-buffer buf
(view-mode-enter)
(when (null (current-local-map))
- (let ((inhibit-read-only t))
- (insert (erc-make-notice "This buffer displays all IRC protocol traffic exchanged with each server.\n"))
- (insert (erc-make-notice "Kill this buffer to terminate protocol logging.\n\n")))
+ (let ((inhibit-read-only t)
+ (msg (list
+ (concat "Version: " erc-debug-irc-protocol-version)
+ (concat "ERC-Version: " erc-version)
+ (concat "Emacs-Version: " emacs-version)
+ (erc-make-notice
+ (concat "This buffer displays all IRC protocol "
+ "traffic exchanged with servers."))
+ (erc-make-notice "Kill it to disable logging.")
+ (erc-make-notice (substitute-command-keys
+ "Press \\`t' to toggle.")))))
+ (insert (string-join msg "\r\n")))
(use-local-map (make-sparse-keymap))
(local-set-key (kbd "t") 'erc-toggle-debug-irc-protocol))
(add-hook 'kill-buffer-hook
@@ -2387,10 +2415,12 @@ If ARG is non-nil, show the *erc-protocol* buffer."
nil 'local)
(goto-char (point-max))
(let ((inhibit-read-only t))
- (insert (erc-make-notice
- (format "IRC protocol logging %s at %s -- Press `t' to toggle logging.\n"
+ (insert (if erc-debug-irc-protocol "\r\n" "")
+ (erc-make-notice
+ (format "IRC protocol logging %s at %s"
(if erc-debug-irc-protocol "disabled" "enabled")
- (current-time-string))))))
+ (current-time-string)))
+ (if erc-debug-irc-protocol "\r\n" "\r\n\r\n"))))
(setq erc-debug-irc-protocol (not erc-debug-irc-protocol))
(if (and arg
(not (get-buffer-window "*erc-protocol*" t)))
@@ -2583,9 +2613,8 @@ See also `erc-lurker-trim-nicks'."
Returns NICK unmodified unless `erc-lurker-trim-nicks' is
non-nil."
(if erc-lurker-trim-nicks
- (replace-regexp-in-string
- (regexp-opt-charset (string-to-list erc-lurker-ignore-chars))
- "" nick)
+ (string-trim-right
+ nick (rx-to-string `(+ (in ,@(string-to-list erc-lurker-ignore-chars)))))
nick))
(defcustom erc-lurker-hide-list nil
@@ -2709,9 +2738,8 @@ displayed hostnames."
:type 'alist)
(defun erc-canonicalize-server-name (server)
- "Return the canonical network name for SERVER if any,
-otherwise `erc-server-announced-name'. SERVER is matched against
-`erc-common-server-suffixes'."
+ "Return canonical network name for SERVER or `erc-server-announced-name'.
+SERVER is matched against `erc-common-server-suffixes'."
(when server
(or (cdar (cl-remove-if-not
(lambda (net) (string-match (car net) server))
@@ -2791,20 +2819,17 @@ present."
(let ((prop-val (erc-get-parsed-vector position)))
(and prop-val (member (erc-response.command prop-val) list))))
-(defvar-local erc-send-input-line-function 'erc-send-input-line)
+(defvar-local erc-send-input-line-function 'erc-send-input-line
+ "Function for sending lines lacking a leading user command.
+When a line typed into a buffer contains an explicit command, like /msg,
+a corresponding handler (here, erc-cmd-MSG) is called. But lines typed
+into a channel or query buffer already have an implicit target and
+command (PRIVMSG). This function is called on such occasions and also
+for special purposes (see erc-dcc.el).")
(defun erc-send-input-line (target line &optional force)
- "Send LINE to TARGET.
-
-See also `erc-server-send'."
- (setq line (format "PRIVMSG %s :%s"
- target
- ;; If the line is empty, we still want to
- ;; send it - i.e. an empty pasted line.
- (if (string= line "\n")
- " \n"
- line)))
- (erc-server-send line force target))
+ "Send LINE to TARGET."
+ (erc-message "PRIVMSG" (concat target " " line) force))
(defun erc-get-arglist (fun)
"Return the argument list of a function without the parens."
@@ -2942,7 +2967,7 @@ Commands for which no erc-cmd-xxx exists, are tunneled through
this function. LINE is sent to the server verbatim, and
therefore has to contain the command itself as well."
(erc-log (format "cmd: DEFAULT: %s" line))
- (erc-server-send (substring line 1))
+ (erc-server-send (string-trim-right (substring line 1) "[\r\n]"))
t)
(defvar erc--read-time-period-history nil)
@@ -3288,19 +3313,39 @@ a script after exceeding the flood threshold."
t)
(t nil)))
-(defun erc-cmd-WHOIS (user &optional server)
- "Display whois information for USER.
+(defun erc-cmd-WHOIS (first &optional second)
+ "Display whois information for the given user.
+
+With one argument, FIRST is the nickname of the user to request
+whois information for.
-If SERVER is non-nil, use that, rather than the current server."
- ;; FIXME: is the above docstring correct? -- Lawrence 2004-01-08
- (let ((send (if server
- (format "WHOIS %s %s" user server)
- (format "WHOIS %s" user))))
+With two arguments, FIRST is the server, and SECOND is the user
+nickname.
+
+Specifying the server is useful for getting the time the user has
+been idle for, when the user is connected to a different server
+on the same IRC network. (Only the server a user is connected to
+knows how long the user has been idle for.)"
+ (let ((send (if second
+ (format "WHOIS %s %s" first second)
+ (format "WHOIS %s" first))))
(erc-log (format "cmd: %s" send))
(erc-server-send send)
t))
(defalias 'erc-cmd-WI #'erc-cmd-WHOIS)
+(defun erc-cmd-WII (nick)
+ "Display whois information for NICK, including idle time.
+
+This is a convenience function which calls `erc-cmd-WHOIS' with
+the given NICK for both arguments. Using NICK in place of the
+server argument -- effectively delegating to the IRC network the
+looking up of the server to which NICK is connected -- is not
+standardized, but is widely supported across IRC networks.
+
+See `erc-cmd-WHOIS' for more details."
+ (erc-cmd-WHOIS nick nick))
+
(defun erc-cmd-WHOAMI ()
"Display whois information about yourself."
(erc-cmd-WHOIS (erc-current-nick))
@@ -3545,8 +3590,7 @@ just as you provided it. Use this command with care!"
(put 'erc-cmd-QUOTE 'do-not-parse-args t)
(defcustom erc-query-display 'window
- "Indicates how to display query buffers when using the /QUERY
-command to talk to someone.
+ "How to display query buffers when using the /QUERY command to talk to someone.
The default behavior is to display the message in a new window
and bring it to the front. See the documentation for
@@ -3564,11 +3608,13 @@ other people should be displayed."
(defun erc-cmd-QUERY (&optional user)
"Open a query with USER.
-The type of query window/frame/etc will depend on the value of
-`erc-query-display'.
-
-If USER is omitted, close the current query buffer if one exists
-- except this is broken now ;-)"
+How the query is displayed (in a new window, frame, etc.) depends
+on the value of `erc-query-display'."
+ ;; FIXME: The doc string used to say at the end:
+ ;; "If USER is omitted, close the current query buffer if one exists
+ ;; - except this is broken now ;-)"
+ ;; Does it make sense to have that functionality? What's wrong with
+ ;; `kill-buffer'? If it makes sense, re-add it. -- SK @ 2021-11-11
(interactive
(list (read-string "Start a query with: ")))
(let ((session-buffer (erc-server-buffer))
@@ -3582,7 +3628,7 @@ If USER is omitted, close the current query buffer if one exists
(defun erc-quit/part-reason-default ()
"Default quit/part message."
- (format "\C-bERC\C-b (IRC client for Emacs %s)" emacs-version))
+ (erc-version nil 'bold-erc))
(defun erc-quit-reason-normal (&optional s)
@@ -3597,7 +3643,9 @@ If S is non-nil, it will be used as the quit reason."
If S is non-nil, it will be used as the quit reason."
(or s
(if (fboundp 'yow)
- (string-replace "\n" "" (yow))
+ (if (>= emacs-major-version 28)
+ (string-replace "\n" "" (yow))
+ (replace-regexp-in-string "\n" "" (yow)))
(erc-quit/part-reason-default))))
(make-obsolete 'erc-quit-reason-zippy "it will be removed." "24.4")
@@ -3624,7 +3672,9 @@ If S is non-nil, it will be used as the part reason."
If S is non-nil, it will be used as the quit reason."
(or s
(if (fboundp 'yow)
- (string-replace "\n" "" (yow))
+ (if (>= emacs-major-version 28)
+ (string-replace "\n" "" (yow))
+ (replace-regexp-in-string "\n" "" (yow)))
(erc-quit/part-reason-default))))
(make-obsolete 'erc-part-reason-zippy "it will be removed." "24.4")
@@ -3706,13 +3756,17 @@ the message given by REASON."
(setq buffer (current-buffer)))
(with-current-buffer buffer
(setq erc-server-quitting nil)
- (setq erc-server-reconnecting t)
+ (with-suppressed-warnings ((obsolete erc-server-reconnecting))
+ (setq erc-server-reconnecting t))
+ (setq erc--server-reconnecting t)
(setq erc-server-reconnect-count 0)
(setq process (get-buffer-process (erc-server-buffer)))
(if process
(delete-process process)
(erc-server-reconnect))
- (setq erc-server-reconnecting nil)))
+ (with-suppressed-warnings ((obsolete erc-server-reconnecting))
+ (setq erc-server-reconnecting nil))
+ (setq erc--server-reconnecting nil)))
t)
(put 'erc-cmd-RECONNECT 'process-not-needed t)
@@ -3722,7 +3776,7 @@ the message given by REASON."
(condition-case nil
(erc :server server :nick (erc-current-nick))
(error
- (erc-error "Cannot find host %s." server)))
+ (erc-error "Cannot find host: `%s'" server)))
t)
(put 'erc-cmd-SERVER 'process-not-needed t)
@@ -3731,7 +3785,8 @@ the message given by REASON."
(defun erc-cmd-SV ()
"Say the current ERC and Emacs version into channel."
- (erc-send-message (format "I'm using ERC with GNU Emacs %s (%s%s)%s."
+ (erc-send-message (format "I'm using ERC %s with GNU Emacs %s (%s%s)%s."
+ erc-version
emacs-version
system-configuration
(concat
@@ -3783,6 +3838,24 @@ the message given by REASON."
(mapconcat #'identity people " ")))
t))
+(defun erc-cmd-OPME ()
+ "Ask ChanServ to op the current nick in the current channel.
+
+This command assumes a ChanServ (channel service) available on
+the IRC network which accepts an \"op\" command that takes the
+channel name and the user's nick, and that the current nick is
+allowed to become an operator in the current channel (typically
+means that the user has a +o flag in the channel's access list)."
+ (erc-message "PRIVMSG"
+ (format "ChanServ op %s %s"
+ (erc-default-target)
+ (erc-current-nick))
+ nil))
+
+(defun erc-cmd-DEOPME ()
+ "Deop the current nick in the current channel."
+ (erc-cmd-DEOP (erc-current-nick)))
+
(defun erc-cmd-TIME (&optional line)
"Request the current time and date from the current server."
(cond
@@ -4280,8 +4353,8 @@ disconnected, you should set this option to t."
:type 'boolean)
(defcustom erc-format-query-as-channel-p t
- "If non-nil, format text from others in a query buffer like in a channel,
-otherwise format like a private message."
+ "If non-nil, format text from others in a query buffer like in a channel.
+Otherwise format like a private message."
:group 'erc-query
:type 'boolean)
@@ -4471,7 +4544,7 @@ also `erc-format-nick-function'."
(propertize prefix 'font-lock-face 'erc-default-face))))
(defun erc-echo-notice-in-default-buffer (s parsed buffer _sender)
- "Echos a private notice in the default buffer, namely the
+ "Echo a private notice in the default buffer, namely the
target buffer specified by BUFFER, or there is no target buffer,
the server buffer. This function is designed to be added to
either `erc-echo-notice-hook' or `erc-echo-notice-always-hook',
@@ -4480,30 +4553,32 @@ and always returns t."
t)
(defun erc-echo-notice-in-target-buffer (s parsed buffer _sender)
- "Echos a private notice in BUFFER, if BUFFER is non-nil. This
-function is designed to be added to either `erc-echo-notice-hook'
-or `erc-echo-notice-always-hook', and returns non-nil if BUFFER
-is non-nil."
+ "Echo a private notice in BUFFER, if BUFFER is non-nil.
+This function is designed to be added to either
+`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and
+returns non-nil if BUFFER is non-nil."
(if buffer
(progn (erc-display-message parsed nil buffer s) t)
nil))
(defun erc-echo-notice-in-minibuffer (s _parsed _buffer _sender)
- "Echos a private notice in the minibuffer. This function is
-designed to be added to either `erc-echo-notice-hook' or
-`erc-echo-notice-always-hook', and always returns t."
+ "Echo a private notice in the minibuffer.
+This function is designed to be added to either
+`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and
+always returns t."
(message "%s" (concat "NOTICE: " s))
t)
(defun erc-echo-notice-in-server-buffer (s parsed _buffer _sender)
- "Echos a private notice in the server buffer. This function is
-designed to be added to either `erc-echo-notice-hook' or
-`erc-echo-notice-always-hook', and always returns t."
+ "Echo a private notice in the server buffer.
+This function is designed to be added to either
+`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and
+always returns t."
(erc-display-message parsed nil nil s)
t)
(defun erc-echo-notice-in-active-non-server-buffer (s parsed _buffer _sender)
- "Echos a private notice in the active buffer if the active
+ "Echo a private notice in the active buffer if the active
buffer is not the server buffer. This function is designed to be
added to either `erc-echo-notice-hook' or
`erc-echo-notice-always-hook', and returns non-nil if the active
@@ -4513,15 +4588,16 @@ buffer is not the server buffer."
nil))
(defun erc-echo-notice-in-active-buffer (s parsed _buffer _sender)
- "Echos a private notice in the active buffer. This function is
-designed to be added to either `erc-echo-notice-hook' or
-`erc-echo-notice-always-hook', and always returns t."
+ "Echo a private notice in the active buffer.
+This function is designed to be added to either
+`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and
+always returns t."
(erc-display-message parsed nil 'active s)
t)
(defun erc-echo-notice-in-user-buffers (s parsed _buffer sender)
- "Echos a private notice in all of the buffers for which SENDER
-is a member. This function is designed to be added to either
+ "Echo a private notice in all of the buffers for which SENDER is a member.
+This function is designed to be added to either
`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and
returns non-nil if there is at least one buffer for which the
sender is a member.
@@ -4534,12 +4610,11 @@ See also: `erc-echo-notice-in-first-user-buffer',
nil)))
(defun erc-echo-notice-in-user-and-target-buffers (s parsed buffer sender)
- "Echos a private notice in BUFFER and in all of the buffers for
-which SENDER is a member. This function is designed to be added
-to either `erc-echo-notice-hook' or
-`erc-echo-notice-always-hook', and returns non-nil if there is
-at least one buffer for which the sender is a member or the
-default target.
+ "Echo a private notice in BUFFER and in all buffers for which SENDER is a member.
+This function is designed to be added to either
+`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and
+returns non-nil if there is at least one buffer for which the
+sender is a member or the default target.
See also: `erc-echo-notice-in-user-buffers',
`erc-buffer-list-with-nick'."
@@ -4550,8 +4625,8 @@ See also: `erc-echo-notice-in-user-buffers',
nil)))
(defun erc-echo-notice-in-first-user-buffer (s parsed _buffer sender)
- "Echos a private notice in one of the buffers for which SENDER
-is a member. This function is designed to be added to either
+ "Echo a private notice in one of the buffers for which SENDER is a member.
+This function is designed to be added to either
`erc-echo-notice-hook' or `erc-echo-notice-always-hook', and
returns non-nil if there is at least one buffer for which the
sender is a member.
@@ -4790,8 +4865,8 @@ See also `erc-display-message'."
(unless erc-disable-ctcp-replies
(erc-send-ctcp-notice
nick (format
- "VERSION \C-bERC\C-b - an IRC client for Emacs %s (\C-b%s\C-b)"
- emacs-version
+ "VERSION %s (\C-b%s\C-b)"
+ (erc-version nil 'bold-erc)
erc-official-location)))
nil)
@@ -5011,10 +5086,11 @@ See also: `erc-update-user'."
(defun erc-update-user (user &optional new-nick
host login full-name info)
- "Update user info for USER. USER must be an erc-server-user
-struct. Any of NEW-NICK, HOST, LOGIN, FULL-NAME, INFO which are
-non-nil and not equal to the existing values for USER are used to
-replace the stored values in USER.
+ "Update user info for USER.
+USER must be an erc-server-user struct. Any of NEW-NICK, HOST,
+LOGIN, FULL-NAME, INFO which are non-nil and not equal to the
+existing values for USER are used to replace the stored values in
+USER.
If, and only if, a change is made,
`erc-channel-members-changed-hook' is run for each channel for
@@ -5159,8 +5235,7 @@ See also: `erc-update-user' and `erc-update-channel-member'."
(defun erc-update-channel-member (channel nick new-nick
&optional add voice halfop op admin owner host login
full-name info update-message-time)
- "Update user and channel information for the user with
-nickname NICK in channel CHANNEL.
+ "Update user and channel for user with nickname NICK in channel CHANNEL.
See also: `erc-update-current-channel-member'."
(erc-with-buffer
@@ -5551,9 +5626,9 @@ submitted line to be intentional."
string insertp sendp)
(defun erc-send-input (input)
- "Treat INPUT as typed in by the user. It is assumed that the input
-and the prompt is already deleted.
-This returns non-nil only if we actually send anything."
+ "Treat INPUT as typed in by the user.
+It is assumed that the input and the prompt is already deleted.
+Return non-nil only if we actually send anything."
;; Handle different kinds of inputs
(cond
;; Ignore empty input
@@ -5587,7 +5662,9 @@ This returns non-nil only if we actually send anything."
(when (and (erc-input-sendp state)
erc-send-this)
(let ((string (erc-input-string state)))
- (if (or (string-search "\n" string)
+ (if (or (if (>= emacs-major-version 28)
+ (string-search "\n" string)
+ (string-match "\n" string))
(not (string-match erc-command-regexp string)))
(mapc
(lambda (line)
@@ -5626,8 +5703,7 @@ This returns non-nil only if we actually send anything."
;; (run-hooks 'erc-send-post-hook))))))
(defun erc-display-msg (line)
- "Display LINE as a message of the user to the current target at the
-current position."
+ "Display LINE as a message of the user to the current target at point."
(when erc-insert-this
(let ((insert-position (point)))
(insert (erc-format-my-nick))
@@ -6359,8 +6435,8 @@ See `erc-mode-line-format' for which characters are can be used."
:type 'boolean)
(defcustom erc-header-line-uses-help-echo-p t
- "Show the contents of the header line in the echo area or as a tooltip
-when you move point into the header line."
+ "Show header line in echo area or as a tooltip
+when point moves to the header line."
:group 'erc-mode-line-and-header
:type 'boolean)
@@ -6449,8 +6525,7 @@ shortened server name instead."
(t (buffer-name (current-buffer))))))
(defun erc-format-away-status ()
- "Return a formatted `erc-mode-line-away-status-format'
-if `erc-away' is non-nil."
+ "Return a formatted `erc-mode-line-away-status-format' if `erc-away' is non-nil."
(let ((a (erc-away-time)))
(if a
(format-time-string erc-mode-line-away-status-format a)
@@ -6528,13 +6603,21 @@ if `erc-away' is non-nil."
(fill-region (point-min) (point-max))
(buffer-string))))
(setq header-line-format
- (string-replace
- "%"
- "%%"
- (if face
- (propertize header 'help-echo help-echo
- 'face face)
- (propertize header 'help-echo help-echo))))))
+ (if (>= emacs-major-version 28)
+ (string-replace
+ "%"
+ "%%"
+ (if face
+ (propertize header 'help-echo help-echo
+ 'face face)
+ (propertize header 'help-echo help-echo)))
+ (replace-regexp-in-string
+ "%"
+ "%%"
+ (if face
+ (propertize header 'help-echo help-echo
+ 'face face)
+ (propertize header 'help-echo help-echo)))))))
(t (setq header-line-format
(if face
(propertize header 'face face)
@@ -6553,6 +6636,15 @@ If BUFFER is nil, update the mode line in all ERC buffers."
;; Miscellaneous
+(defun erc-bug (subject)
+ "Send a bug report to the Emacs bug tracker and ERC mailing list."
+ (interactive "sBug Subject: ")
+ (report-emacs-bug
+ (format "ERC %s: %s" erc-version subject))
+ (save-excursion
+ (goto-char (point-min))
+ (insert "X-Debbugs-CC: emacs-erc@gnu.org\n")))
+
(defun erc-port-to-string (p)
"Convert port P to a string.
P may be an integer or a service name."
@@ -6569,12 +6661,18 @@ P may be an integer or a service name."
s
n))))
-(defun erc-version (&optional here)
+(defun erc-version (&optional here bold-erc)
"Show the version number of ERC in the minibuffer.
-If optional argument HERE is non-nil, insert version number at point."
+If optional argument HERE is non-nil, insert version number at point.
+If optional argument BOLD-ERC is non-nil, display \"ERC\" as bold."
(interactive "P")
(let ((version-string
- (format "ERC (IRC client for Emacs %s)" emacs-version)))
+ (format "%s %s (IRC client for GNU Emacs %s)"
+ (if bold-erc
+ "\C-bERC\C-b"
+ "ERC")
+ erc-version
+ emacs-version)))
(if here
(insert version-string)
(if (called-interactively-p 'interactive)
@@ -6804,7 +6902,9 @@ functions."
nick user host channel
(if (not (string= reason ""))
(format ": %s"
- (string-replace "%" "%%" reason))
+ (if (>= emacs-major-version 28)
+ (string-replace "%" "%%" reason)
+ (replace-regexp-in-string "%" "%%" reason)))
"")))))