erc-netsplit.el 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. ;;; erc-netsplit.el --- Reduce JOIN/QUIT messages on netsplits
  2. ;; Copyright (C) 2002-2004, 2006-2017 Free Software Foundation, Inc.
  3. ;; Author: Mario Lang <mlang@delysid.org>
  4. ;; Maintainer: emacs-devel@gnu.org
  5. ;; Keywords: comm
  6. ;; This file is part of GNU Emacs.
  7. ;; GNU Emacs is free software: you can redistribute it and/or modify
  8. ;; it under the terms of the GNU General Public License as published by
  9. ;; the Free Software Foundation, either version 3 of the License, or
  10. ;; (at your option) any later version.
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;; GNU General Public License for more details.
  15. ;; You should have received a copy of the GNU General Public License
  16. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;; This module hides quit/join messages if a netsplit occurs.
  19. ;; To enable, add the following to your init file:
  20. ;; (require 'erc-netsplit)
  21. ;; (erc-netsplit-mode 1)
  22. ;;; Code:
  23. (require 'erc)
  24. (defgroup erc-netsplit nil
  25. "Netsplit detection tries to automatically figure when a
  26. netsplit happens, and filters the QUIT messages. It also keeps
  27. track of netsplits, so that it can filter the JOIN messages on a netjoin too."
  28. :group 'erc)
  29. ;;;###autoload (autoload 'erc-netsplit-mode "erc-netsplit")
  30. (define-erc-module netsplit nil
  31. "This mode hides quit/join messages if a netsplit occurs."
  32. ((erc-netsplit-install-message-catalogs)
  33. (add-hook 'erc-server-JOIN-functions 'erc-netsplit-JOIN)
  34. (add-hook 'erc-server-MODE-functions 'erc-netsplit-MODE)
  35. (add-hook 'erc-server-QUIT-functions 'erc-netsplit-QUIT)
  36. (add-hook 'erc-timer-hook 'erc-netsplit-timer))
  37. ((remove-hook 'erc-server-JOIN-functions 'erc-netsplit-JOIN)
  38. (remove-hook 'erc-server-MODE-functions 'erc-netsplit-MODE)
  39. (remove-hook 'erc-server-QUIT-functions 'erc-netsplit-QUIT)
  40. (remove-hook 'erc-timer-hook 'erc-netsplit-timer)))
  41. (defcustom erc-netsplit-show-server-mode-changes-flag nil
  42. "Set to t to enable display of server mode changes."
  43. :group 'erc-netsplit
  44. :type 'boolean)
  45. (defcustom erc-netsplit-debug nil
  46. "If non-nil, debug messages will be shown in the
  47. sever buffer."
  48. :group 'erc-netsplit
  49. :type 'boolean)
  50. (defcustom erc-netsplit-regexp
  51. "^[^ @!\"\n]+\\.[^ @!\n]+ [^ @!\n]+\\.[^ @!\"\n]+$"
  52. "This regular expression should match quit reasons produced
  53. by netsplits."
  54. :group 'erc-netsplit
  55. :type 'regexp)
  56. (defcustom erc-netsplit-hook nil
  57. "Run whenever a netsplit is detected the first time.
  58. Args: PROC is the process the netsplit originated from and
  59. SPLIT is the netsplit (e.g. \"server.name.1 server.name.2\")."
  60. :group 'erc-hooks
  61. :type 'hook)
  62. (defcustom erc-netjoin-hook nil
  63. "Run whenever a netjoin is detected the first time.
  64. Args: PROC is the process the netjoin originated from and
  65. SPLIT is the netsplit (e.g. \"server.name.1 server.name.2\")."
  66. :group 'erc-hooks
  67. :type 'hook)
  68. (defvar erc-netsplit-list nil
  69. "This is a list of the form
  70. \((\"a.b.c.d e.f.g\" TIMESTAMP FIRST-JOIN \"nick1\" ... \"nickn\") ...)
  71. where FIRST-JOIN is t or nil, depending on whether or not the first
  72. join from that split has been detected or not.")
  73. (make-variable-buffer-local 'erc-netsplit-list)
  74. (defun erc-netsplit-install-message-catalogs ()
  75. (erc-define-catalog
  76. 'english
  77. '((netsplit . "netsplit: %s")
  78. (netjoin . "netjoin: %s, %N were split")
  79. (netjoin-done . "netjoin: All lost souls are back!")
  80. (netsplit-none . "No netsplits in progress")
  81. (netsplit-wholeft . "split: %s missing: %n %t"))))
  82. (defun erc-netsplit-JOIN (proc parsed)
  83. "Show/don't show rejoins."
  84. (let ((nick (erc-response.sender parsed))
  85. (no-next-hook nil))
  86. (dolist (elt erc-netsplit-list)
  87. (if (member nick (nthcdr 3 elt))
  88. (progn
  89. (if (not (nth 2 elt))
  90. (progn
  91. (erc-display-message
  92. parsed 'notice (process-buffer proc)
  93. 'netjoin ?s (car elt) ?N (length (nthcdr 3 elt)))
  94. (setcar (nthcdr 2 elt) t)
  95. (run-hook-with-args 'erc-netjoin-hook proc (car elt))))
  96. ;; need to remove this nick, perhaps the whole entry here.
  97. ;; Note that by removing the nick now, we can't tell if further
  98. ;; join messages (for other channels) should also be
  99. ;; suppressed.
  100. (if (null (nthcdr 4 elt))
  101. (progn
  102. (erc-display-message
  103. parsed 'notice (process-buffer proc)
  104. 'netjoin-done ?s (car elt))
  105. (setq erc-netsplit-list (delq elt erc-netsplit-list)))
  106. (delete nick elt))
  107. (setq no-next-hook t))))
  108. no-next-hook))
  109. (defun erc-netsplit-MODE (proc parsed)
  110. "Hide mode changes from servers."
  111. ;; regexp matches things with a . in them, and no ! or @ in them.
  112. (when (string-match "^[^@!\n]+\\.[^@!\n]+$" (erc-response.sender parsed))
  113. (and erc-netsplit-debug
  114. (erc-display-message
  115. parsed 'notice (process-buffer proc)
  116. "[debug] server mode change."))
  117. (not erc-netsplit-show-server-mode-changes-flag)))
  118. (defun erc-netsplit-QUIT (proc parsed)
  119. "Detect netsplits."
  120. (let ((split (erc-response.contents parsed))
  121. (nick (erc-response.sender parsed))
  122. ass)
  123. (when (string-match erc-netsplit-regexp split)
  124. (setq ass (assoc split erc-netsplit-list))
  125. (if ass
  126. ;; element for this netsplit exists already
  127. (progn
  128. (setcdr (nthcdr 2 ass) (cons nick (nthcdr 3 ass)))
  129. (when (nth 2 ass)
  130. ;; There was already a netjoin for this netsplit, it
  131. ;; seems like the old one didn't get finished...
  132. (erc-display-message
  133. parsed 'notice (process-buffer proc)
  134. 'netsplit ?s split)
  135. (setcar (nthcdr 2 ass) t)
  136. (run-hook-with-args 'erc-netsplit-hook proc split)))
  137. ;; element for this netsplit does not yet exist
  138. (setq erc-netsplit-list
  139. (cons (list split
  140. (erc-current-time)
  141. nil
  142. nick)
  143. erc-netsplit-list))
  144. (erc-display-message
  145. parsed 'notice (process-buffer proc)
  146. 'netsplit ?s split)
  147. (run-hook-with-args 'erc-netsplit-hook proc split))
  148. t)))
  149. (defun erc-netsplit-timer (now)
  150. "Clean cruft from `erc-netsplit-list' older than 10 minutes."
  151. (when erc-server-connected
  152. (dolist (elt erc-netsplit-list)
  153. (when (> (erc-time-diff (cadr elt) now) 600)
  154. (when erc-netsplit-debug
  155. (erc-display-message
  156. nil 'notice (current-buffer)
  157. (concat "Netsplit: Removing " (car elt))))
  158. (setq erc-netsplit-list (delq elt erc-netsplit-list))))))
  159. ;;;###autoload
  160. (defun erc-cmd-WHOLEFT ()
  161. "Show who's gone."
  162. (erc-with-server-buffer
  163. (if (null erc-netsplit-list)
  164. (erc-display-message
  165. nil 'notice 'active
  166. 'netsplit-none)
  167. (dolist (elt erc-netsplit-list)
  168. (erc-display-message
  169. nil 'notice 'active
  170. 'netsplit-wholeft ?s (car elt)
  171. ?n (mapconcat 'erc-extract-nick (nthcdr 3 elt) " ")
  172. ?t (if (nth 2 elt)
  173. "(joining)"
  174. "")))))
  175. t)
  176. (defalias 'erc-cmd-WL 'erc-cmd-WHOLEFT)
  177. (provide 'erc-netsplit)
  178. ;;; erc-netsplit.el ends here
  179. ;;
  180. ;; Local Variables:
  181. ;; indent-tabs-mode: t
  182. ;; tab-width: 8
  183. ;; End: