emacs/lisp/erc/erc-netsplit.el
Po Lu ecf08f0621 Merge from savannah/emacs-29
dc4e6b1329 ; Update copyright years in more files
64b3777631 ; Run set-copyright from admin.el
8e1c56ae46 ; Add 2024 to copyright years

# Conflicts:
#	doc/misc/modus-themes.org
#	doc/misc/texinfo.tex
#	etc/NEWS
#	etc/refcards/ru-refcard.tex
#	etc/themes/modus-operandi-theme.el
#	etc/themes/modus-themes.el
#	etc/themes/modus-vivendi-theme.el
#	lib/alloca.in.h
#	lib/binary-io.h
#	lib/c-ctype.h
#	lib/c-strcasecmp.c
#	lib/c-strncasecmp.c
#	lib/careadlinkat.c
#	lib/cloexec.c
#	lib/close-stream.c
#	lib/diffseq.h
#	lib/dup2.c
#	lib/filemode.h
#	lib/fpending.c
#	lib/fpending.h
#	lib/fsusage.c
#	lib/getgroups.c
#	lib/getloadavg.c
#	lib/gettext.h
#	lib/gettime.c
#	lib/gettimeofday.c
#	lib/group-member.c
#	lib/malloc.c
#	lib/md5-stream.c
#	lib/md5.c
#	lib/md5.h
#	lib/memmem.c
#	lib/memrchr.c
#	lib/nanosleep.c
#	lib/save-cwd.h
#	lib/sha1.c
#	lib/sig2str.c
#	lib/stdlib.in.h
#	lib/strtoimax.c
#	lib/strtol.c
#	lib/strtoll.c
#	lib/time_r.c
#	lib/xalloc-oversized.h
#	lisp/auth-source-pass.el
#	lisp/emacs-lisp/lisp-mnt.el
#	lisp/emacs-lisp/timer.el
#	lisp/info-look.el
#	lisp/jit-lock.el
#	lisp/loadhist.el
#	lisp/mail/rmail.el
#	lisp/net/ntlm.el
#	lisp/net/webjump.el
#	lisp/progmodes/asm-mode.el
#	lisp/progmodes/project.el
#	lisp/progmodes/sh-script.el
#	lisp/textmodes/flyspell.el
#	lisp/textmodes/reftex-toc.el
#	lisp/textmodes/reftex.el
#	lisp/textmodes/tex-mode.el
#	lisp/url/url-gw.el
#	m4/alloca.m4
#	m4/clock_time.m4
#	m4/d-type.m4
#	m4/dirent_h.m4
#	m4/dup2.m4
#	m4/euidaccess.m4
#	m4/fchmodat.m4
#	m4/filemode.m4
#	m4/fsusage.m4
#	m4/getgroups.m4
#	m4/getloadavg.m4
#	m4/getrandom.m4
#	m4/gettime.m4
#	m4/gettimeofday.m4
#	m4/gnulib-common.m4
#	m4/group-member.m4
#	m4/inttypes.m4
#	m4/malloc.m4
#	m4/manywarnings.m4
#	m4/mempcpy.m4
#	m4/memrchr.m4
#	m4/mkostemp.m4
#	m4/mktime.m4
#	m4/nproc.m4
#	m4/nstrftime.m4
#	m4/pathmax.m4
#	m4/pipe2.m4
#	m4/pselect.m4
#	m4/pthread_sigmask.m4
#	m4/readlink.m4
#	m4/realloc.m4
#	m4/sig2str.m4
#	m4/ssize_t.m4
#	m4/stat-time.m4
#	m4/stddef_h.m4
#	m4/stdint.m4
#	m4/stdio_h.m4
#	m4/stdlib_h.m4
#	m4/stpcpy.m4
#	m4/strnlen.m4
#	m4/strtoimax.m4
#	m4/strtoll.m4
#	m4/time_h.m4
#	m4/timegm.m4
#	m4/timer_time.m4
#	m4/timespec.m4
#	m4/unistd_h.m4
#	m4/warnings.m4
#	nt/configure.bat
#	nt/preprep.c
#	test/lisp/register-tests.el
2024-01-02 10:28:14 +08:00

214 lines
7.4 KiB
EmacsLisp

;;; erc-netsplit.el --- Reduce JOIN/QUIT messages on netsplits -*- lexical-binding: t; -*-
;; Copyright (C) 2002-2004, 2006-2024 Free Software Foundation, Inc.
;; Author: Mario Lang <mlang@delysid.org>
;; Maintainer: Amin Bandali <bandali@gnu.org>, F. Jason Park <jp@neverwas.me>
;; Keywords: comm
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; This module hides quit/join messages if a netsplit occurs.
;; To enable, add the following to your init file:
;; (require 'erc-netsplit)
;; (erc-netsplit-mode 1)
;;; Code:
(require 'erc)
(defgroup erc-netsplit nil
"Netsplit detection tries to automatically figure when a netsplit
happens, and filters the QUIT messages. It also keeps track of
netsplits, so that it can filter the JOIN messages on a netjoin too."
:group 'erc)
;;;###autoload(autoload 'erc-netsplit-mode "erc-netsplit")
(define-erc-module netsplit nil
"This mode hides quit/join messages if a netsplit occurs."
( ; FIXME delete newline on next edit
(add-hook 'erc-server-JOIN-functions #'erc-netsplit-JOIN)
(add-hook 'erc-server-MODE-functions #'erc-netsplit-MODE)
(add-hook 'erc-server-QUIT-functions #'erc-netsplit-QUIT)
(add-hook 'erc-timer-hook #'erc-netsplit-timer))
((remove-hook 'erc-server-JOIN-functions #'erc-netsplit-JOIN)
(remove-hook 'erc-server-MODE-functions #'erc-netsplit-MODE)
(remove-hook 'erc-server-QUIT-functions #'erc-netsplit-QUIT)
(remove-hook 'erc-timer-hook #'erc-netsplit-timer)))
(defcustom erc-netsplit-show-server-mode-changes-flag nil
"Non-nil means to enable display of server mode changes."
:type 'boolean)
(defcustom erc-netsplit-debug nil
"If non-nil, debug messages will be shown in the sever buffer."
:type 'boolean)
(defcustom erc-netsplit-regexp
"^[^ @!\"\n]+\\.[^ @!\n]+ [^ @!\n]+\\.[^ @!\"\n]+$"
"This regular expression should match quit reasons produced by netsplits."
:type 'regexp)
(defcustom erc-netsplit-hook nil
"Run whenever a netsplit is detected the first time.
Args: PROC is the process the netsplit originated from and
SPLIT is the netsplit (e.g. \"server.name.1 server.name.2\")."
:group 'erc-hooks
:type 'hook)
(defcustom erc-netjoin-hook nil
"Run whenever a netjoin is detected the first time.
Args: PROC is the process the netjoin originated from and
SPLIT is the netsplit (e.g. \"server.name.1 server.name.2\")."
:group 'erc-hooks
:type 'hook)
(defvar-local erc-netsplit-list nil
"This is a list of the form
\((\"a.b.c.d e.f.g\" TIMESTAMP FIRST-JOIN \"nick1\" ... \"nickn\") ...)
where FIRST-JOIN is t or nil, depending on whether or not the first
join from that split has been detected or not.")
(defun erc-netsplit-install-message-catalogs ()
(declare (obsolete "defined at top level in erc-netsplit.el" "30.1"))
(with-suppressed-warnings ((obsolete erc-define-catalog)) ; indentation
(erc-define-catalog
'english
'((netsplit . "netsplit: %s")
(netjoin . "netjoin: %s, %N were split")
(netjoin-done . "netjoin: All lost souls are back!")
(netsplit-none . "No netsplits in progress")
(netsplit-wholeft . "split: %s missing: %n %t"))))) ; indentation
(erc-define-message-format-catalog english
(netsplit . "netsplit: %s")
(netjoin . "netjoin: %s, %N were split")
(netjoin-done . "netjoin: All lost souls are back!")
(netsplit-none . "No netsplits in progress")
(netsplit-wholeft . "split: %s missing: %n %t"))
(defun erc-netsplit-JOIN (proc parsed)
"Show/don't show rejoins."
(let ((nick (erc-response.sender parsed))
(no-next-hook nil))
(dolist (elt erc-netsplit-list)
(if (member nick (nthcdr 3 elt))
(progn
(if (not (nth 2 elt))
(progn
(erc-display-message
parsed 'notice (process-buffer proc)
'netjoin ?s (car elt) ?N (length (nthcdr 3 elt)))
(setcar (nthcdr 2 elt) t)
(run-hook-with-args 'erc-netjoin-hook proc (car elt))))
;; need to remove this nick, perhaps the whole entry here.
;; Note that by removing the nick now, we can't tell if further
;; join messages (for other channels) should also be
;; suppressed.
(if (null (nthcdr 4 elt))
(progn
(erc-display-message
parsed 'notice (process-buffer proc)
'netjoin-done ?s (car elt))
(setq erc-netsplit-list (delq elt erc-netsplit-list)))
;; Avoid `ignored-return-value' warning for `delete'.
(let ((tail (nthcdr 2 elt))) ; (t n1 ... nN)
(setcdr tail (delete nick (cdr tail)))))
(setq no-next-hook t))))
no-next-hook))
(defun erc-netsplit-MODE (proc parsed)
"Hide mode changes from servers."
;; regexp matches things with a . in them, and no ! or @ in them.
(when (string-match "^[^@!\n]+\\.[^@!\n]+$" (erc-response.sender parsed))
(and erc-netsplit-debug
(erc-display-message
parsed 'notice (process-buffer proc)
"[debug] server mode change."))
(not erc-netsplit-show-server-mode-changes-flag)))
(defun erc-netsplit-QUIT (proc parsed)
"Detect netsplits."
(let ((split (erc-response.contents parsed))
(nick (erc-response.sender parsed))
ass)
(when (string-match erc-netsplit-regexp split)
(setq ass (assoc split erc-netsplit-list))
(if ass
;; element for this netsplit exists already
(progn
(setcdr (nthcdr 2 ass) (cons nick (nthcdr 3 ass)))
(when (nth 2 ass)
;; There was already a netjoin for this netsplit, it
;; seems like the old one didn't get finished...
(erc-display-message
parsed 'notice (process-buffer proc)
'netsplit ?s split)
(setcar (nthcdr 2 ass) t)
(run-hook-with-args 'erc-netsplit-hook proc split)))
;; element for this netsplit does not yet exist
(setq erc-netsplit-list
(cons (list split
(erc-current-time)
nil
nick)
erc-netsplit-list))
(erc-display-message
parsed 'notice (process-buffer proc)
'netsplit ?s split)
(run-hook-with-args 'erc-netsplit-hook proc split))
t)))
(defun erc-netsplit-timer (now)
"Clean cruft from `erc-netsplit-list' older than 10 minutes."
(when erc-server-connected
(dolist (elt erc-netsplit-list)
(when (> (erc-time-diff (cadr elt) now) 600)
(when erc-netsplit-debug
(erc-display-message
nil 'notice (current-buffer)
(concat "Netsplit: Removing " (car elt))))
(setq erc-netsplit-list (delq elt erc-netsplit-list))))))
;;;###autoload
(defun erc-cmd-WHOLEFT ()
"Show who's gone."
(erc-with-server-buffer
(if (null erc-netsplit-list)
(erc-display-message
nil 'notice 'active
'netsplit-none)
(dolist (elt erc-netsplit-list)
(erc-display-message
nil 'notice 'active
'netsplit-wholeft ?s (car elt)
?n (mapconcat #'erc-extract-nick (nthcdr 3 elt) " ")
?t (if (nth 2 elt)
"(joining)"
"")))))
t)
(defalias 'erc-cmd-WL #'erc-cmd-WHOLEFT)
(provide 'erc-netsplit)
;;; erc-netsplit.el ends here
;;
;; Local Variables:
;; generated-autoload-file: "erc-loaddefs.el"
;; End: