erc-notify.el 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. ;;; erc-notify.el --- Online status change notification -*- lexical-binding:t -*-
  2. ;; Copyright (C) 2002-2004, 2006-2017 Free Software Foundation, Inc.
  3. ;; Author: Mario Lang <mlang@lexx.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 defines a new command, /NOTIFY
  19. ;; See the docstring of `erc-cmd-NOTIFY' for details.
  20. ;;; Code:
  21. (require 'erc)
  22. (require 'erc-networks)
  23. (eval-when-compile (require 'pcomplete))
  24. ;;;; Customizable variables
  25. (defgroup erc-notify nil
  26. "Track online status of certain nicknames."
  27. :group 'erc)
  28. (defcustom erc-notify-list nil
  29. "List of nicknames you want to be notified about online/offline
  30. status change."
  31. :group 'erc-notify
  32. :type '(repeat string))
  33. (defcustom erc-notify-interval 60
  34. "Time interval (in seconds) for checking online status of notified
  35. people."
  36. :group 'erc-notify
  37. :type 'integer)
  38. (defcustom erc-notify-signon-hook nil
  39. "Hook run after someone on `erc-notify-list' has signed on.
  40. Two arguments are passed to the function, SERVER and NICK, both
  41. strings."
  42. :group 'erc-notify
  43. :type 'hook
  44. :options '(erc-notify-signon))
  45. (defcustom erc-notify-signoff-hook nil
  46. "Hook run after someone on `erc-notify-list' has signed off.
  47. Two arguments are passed to the function, SERVER and NICK, both
  48. strings."
  49. :group 'erc-notify
  50. :type 'hook
  51. :options '(erc-notify-signoff))
  52. (defun erc-notify-signon (server nick)
  53. (message "%s signed on at %s" nick server))
  54. (defun erc-notify-signoff (server nick)
  55. (message "%s signed off from %s" nick server))
  56. ;;;; Internal variables
  57. (defvar erc-last-ison nil
  58. "Last ISON information received through `erc-notify-timer'.")
  59. (make-variable-buffer-local 'erc-last-ison)
  60. (defvar erc-last-ison-time 0
  61. "Last time ISON was sent to the server in `erc-notify-timer'.")
  62. (make-variable-buffer-local 'erc-last-ison-time)
  63. ;;;; Setup
  64. (defun erc-notify-install-message-catalogs ()
  65. (erc-define-catalog
  66. 'english
  67. '((notify_current . "Notified people online: %l")
  68. (notify_list . "Current notify list: %l")
  69. (notify_on . "Detected %n on IRC network %m")
  70. (notify_off . "%n has left IRC network %m"))))
  71. ;;;###autoload (autoload 'erc-notify-mode "erc-notify" nil t)
  72. (define-erc-module notify nil
  73. "Periodically check for the online status of certain users and report
  74. changes."
  75. ((add-hook 'erc-timer-hook 'erc-notify-timer)
  76. (add-hook 'erc-server-JOIN-functions 'erc-notify-JOIN)
  77. (add-hook 'erc-server-NICK-functions 'erc-notify-NICK)
  78. (add-hook 'erc-server-QUIT-functions 'erc-notify-QUIT))
  79. ((remove-hook 'erc-timer-hook 'erc-notify-timer)
  80. (remove-hook 'erc-server-JOIN-functions 'erc-notify-JOIN)
  81. (remove-hook 'erc-server-NICK-functions 'erc-notify-NICK)
  82. (remove-hook 'erc-server-QUIT-functions 'erc-notify-QUIT)))
  83. ;;;; Timer handler
  84. (defun erc-notify-timer (now)
  85. (when (and erc-server-connected
  86. erc-notify-list
  87. (> (erc-time-diff
  88. erc-last-ison-time now)
  89. erc-notify-interval))
  90. (erc-once-with-server-event
  91. 303
  92. (lambda (proc parsed)
  93. (let* ((server (erc-response.sender parsed))
  94. (ison-list (delete "" (split-string
  95. (erc-response.contents parsed))))
  96. (new-list ison-list)
  97. (old-list (erc-with-server-buffer erc-last-ison)))
  98. (while new-list
  99. (when (not (erc-member-ignore-case (car new-list) old-list))
  100. (run-hook-with-args 'erc-notify-signon-hook server (car new-list))
  101. (erc-display-message
  102. parsed 'notice proc
  103. 'notify_on ?n (car new-list) ?m (erc-network-name)))
  104. (setq new-list (cdr new-list)))
  105. (while old-list
  106. (when (not (erc-member-ignore-case (car old-list) ison-list))
  107. (run-hook-with-args 'erc-notify-signoff-hook server (car old-list))
  108. (erc-display-message
  109. parsed 'notice proc
  110. 'notify_off ?n (car old-list) ?m (erc-network-name)))
  111. (setq old-list (cdr old-list)))
  112. (setq erc-last-ison ison-list)
  113. t)))
  114. (erc-server-send
  115. (concat "ISON " (mapconcat 'identity erc-notify-list " ")))
  116. (setq erc-last-ison-time now)))
  117. (defun erc-notify-JOIN (proc parsed)
  118. "Check if channel joiner is on `erc-notify-list' and not on `erc-last-ison'.
  119. If this condition is satisfied, produce a notify_on message and add the nick
  120. to `erc-last-ison' to prevent any further notifications."
  121. (let ((nick (erc-extract-nick (erc-response.sender parsed))))
  122. (when (and (erc-member-ignore-case nick erc-notify-list)
  123. (not (erc-member-ignore-case nick erc-last-ison)))
  124. (add-to-list 'erc-last-ison nick)
  125. (run-hook-with-args 'erc-notify-signon-hook
  126. (or erc-server-announced-name erc-session-server)
  127. nick)
  128. (erc-display-message
  129. parsed 'notice proc
  130. 'notify_on ?n nick ?m (erc-network-name)))
  131. nil))
  132. (defun erc-notify-NICK (proc parsed)
  133. "Check if new nick is on `erc-notify-list' and not on `erc-last-ison'.
  134. If this condition is satisfied, produce a notify_on message and add the nick
  135. to `erc-last-ison' to prevent any further notifications."
  136. (let ((nick (erc-response.contents parsed)))
  137. (when (and (erc-member-ignore-case nick erc-notify-list)
  138. (not (erc-member-ignore-case nick erc-last-ison)))
  139. (add-to-list 'erc-last-ison nick)
  140. (run-hook-with-args 'erc-notify-signon-hook
  141. (or erc-server-announced-name erc-session-server)
  142. nick)
  143. (erc-display-message
  144. parsed 'notice proc
  145. 'notify_on ?n nick ?m (erc-network-name)))
  146. nil))
  147. (defun erc-notify-QUIT (proc parsed)
  148. "Check if quitter is on `erc-notify-list' and on `erc-last-ison'.
  149. If this condition is satisfied, produce a notify_off message and remove the
  150. nick from `erc-last-ison' to prevent any further notifications."
  151. (let ((nick (erc-extract-nick (erc-response.sender parsed))))
  152. (when (and (erc-member-ignore-case nick erc-notify-list)
  153. (erc-member-ignore-case nick erc-last-ison))
  154. (setq erc-last-ison (erc-delete-if
  155. (let ((nick-down (erc-downcase nick)))
  156. (lambda (el)
  157. (string= nick-down (erc-downcase el))))
  158. erc-last-ison))
  159. (run-hook-with-args 'erc-notify-signoff-hook
  160. (or erc-server-announced-name erc-session-server)
  161. nick)
  162. (erc-display-message
  163. parsed 'notice proc
  164. 'notify_off ?n nick ?m (erc-network-name)))
  165. nil))
  166. ;;;; User level command
  167. ;;;###autoload
  168. (defun erc-cmd-NOTIFY (&rest args)
  169. "Change `erc-notify-list' or list current notify-list members online.
  170. Without args, list the current list of notified people online,
  171. with args, toggle notify status of people."
  172. (cond
  173. ((null args)
  174. ;; Print current notified people (online)
  175. (let ((ison (erc-with-server-buffer erc-last-ison)))
  176. (if (not ison)
  177. (erc-display-message
  178. nil 'notice 'active "No ison-list yet!")
  179. (erc-display-message
  180. nil 'notice 'active
  181. 'notify_current ?l ison))))
  182. ((string= (car args) "-l")
  183. (erc-display-message nil 'notice 'active
  184. 'notify_list ?l (mapconcat 'identity erc-notify-list
  185. " ")))
  186. (t
  187. (while args
  188. (if (erc-member-ignore-case (car args) erc-notify-list)
  189. (progn
  190. (setq erc-notify-list (delete (car args) erc-notify-list))
  191. ;; Remove the nick from the value of erc-last-ison in
  192. ;; every server buffer. This prevents seeing a signoff
  193. ;; notification for a nick that you have just _removed_
  194. ;; from your notify list.
  195. (dolist (buf (erc-buffer-list))
  196. (with-current-buffer buf
  197. (if (erc-server-buffer-p)
  198. (setq erc-last-ison (delete (car args) erc-last-ison))))))
  199. (setq erc-notify-list (cons (erc-string-no-properties (car args))
  200. erc-notify-list)))
  201. (setq args (cdr args)))
  202. (erc-display-message
  203. nil 'notice 'active
  204. 'notify_list ?l (mapconcat 'identity erc-notify-list " "))))
  205. t)
  206. (autoload 'pcomplete-erc-all-nicks "erc-pcomplete")
  207. ;; "--" is not a typo.
  208. (declare-function pcomplete--here "pcomplete"
  209. (&optional form stub paring form-only))
  210. ;;;###autoload
  211. (defun pcomplete/erc-mode/NOTIFY ()
  212. (require 'pcomplete)
  213. (pcomplete-here (pcomplete-erc-all-nicks)))
  214. (erc-notify-install-message-catalogs)
  215. (provide 'erc-notify)
  216. ;;; erc-notify.el ends here
  217. ;;
  218. ;; Local Variables:
  219. ;; indent-tabs-mode: t
  220. ;; tab-width: 8
  221. ;; End: