1;;; erc-notify.el --- Online status change notification
2
3;; Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
4
5;; Author: Mario Lang <mlang@lexx.delysid.org>
6;; Keywords: comm
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs; see the file COPYING.  If not, write to the
22;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23;; Boston, MA 02110-1301, USA.
24
25;;; Commentary:
26
27;; This module defines a new command, /NOTIFY
28;; See the docstring of `erc-cmd-NOTIFY' for details.
29
30;;; Code:
31
32(require 'erc)
33(require 'erc-networks)
34(eval-when-compile
35 (require 'cl)
36 (require 'pcomplete))
37
38;;;; Customizable variables
39
40(defgroup erc-notify nil
41  "Track online status of certain nicknames."
42  :group 'erc)
43
44(defcustom erc-notify-list nil
45  "*List of nicknames you want to be notified about online/offline
46status change."
47  :group 'erc-notify
48  :type '(repeat string))
49
50(defcustom erc-notify-interval 60
51  "*Time interval (in seconds) for checking online status of notificated
52people."
53  :group 'erc-notify
54  :type 'integer)
55
56(defcustom erc-notify-signon-hook nil
57  "*Hook run after someone on `erc-notify-list' has signed on.
58Two arguments are passed to the function, SERVER and NICK, both
59strings."
60  :group 'erc-notify
61  :type 'hook
62  :options '(erc-notify-signon))
63
64(defcustom erc-notify-signoff-hook nil
65  "*Hook run after someone on `erc-notify-list' has signed off.
66Two arguments are passed to the function, SERVER and NICK, both
67strings."
68  :group 'erc-notify
69  :type 'hook
70  :options '(erc-notify-signoff))
71
72(defun erc-notify-signon (server nick)
73  (message "%s signed on at %s" nick server))
74
75(defun erc-notify-signoff (server nick)
76  (message "%s signed off from %s" nick server))
77
78;;;; Internal variables
79
80(defvar erc-last-ison nil
81  "Last ISON information received through `erc-notify-timer'.")
82(make-variable-buffer-local 'erc-last-ison)
83
84(defvar erc-last-ison-time 0
85  "Last time ISON was sent to the server in `erc-notify-timer'.")
86(make-variable-buffer-local 'erc-last-ison-time)
87
88;;;; Setup
89
90(defun erc-notify-install-message-catalogs ()
91  (erc-define-catalog
92   'english
93   '((notify_current . "Notificated people online: %l")
94     (notify_list    . "Current notify list: %l")
95     (notify_on      . "Detected %n on IRC network %m")
96     (notify_off     . "%n has left IRC network %m"))))
97
98;;;###autoload (autoload 'erc-notify-mode "erc-notify" nil t)
99(define-erc-module notify nil
100  "Periodically check for the online status of certain users and report
101changes."
102  ((add-hook 'erc-timer-hook 'erc-notify-timer)
103   (add-hook 'erc-server-JOIN-functions 'erc-notify-JOIN)
104   (add-hook 'erc-server-NICK-functions 'erc-notify-NICK)
105   (add-hook 'erc-server-QUIT-functions 'erc-notify-QUIT))
106  ((remove-hook 'erc-timer-hook 'erc-notify-timer)
107   (remove-hook 'erc-server-JOIN-functions 'erc-notify-JOIN)
108   (remove-hook 'erc-server-NICK-functions 'erc-notify-NICK)
109   (remove-hook 'erc-server-QUIT-functions 'erc-notify-QUIT)))
110
111;;;; Timer handler
112
113(defun erc-notify-timer (now)
114  (when (and erc-notify-list
115	     (> (erc-time-diff
116		 erc-last-ison-time now)
117		erc-notify-interval))
118    (erc-once-with-server-event
119     303
120     '(let* ((server (erc-response.sender parsed))
121	     (ison-list (delete "" (split-string
122				    (erc-response.contents parsed))))
123	     (new-list ison-list)
124	     (old-list (erc-with-server-buffer erc-last-ison)))
125	(while new-list
126	  (when (not (erc-member-ignore-case (car new-list) old-list))
127	    (run-hook-with-args 'erc-notify-signon-hook server (car new-list))
128	    (erc-display-message
129	     parsed 'notice proc
130	     'notify_on ?n (car new-list) ?m (erc-network-name)))
131	  (setq new-list (cdr new-list)))
132	(while old-list
133	  (when (not (erc-member-ignore-case (car old-list) ison-list))
134	    (run-hook-with-args 'erc-notify-signoff-hook server (car old-list))
135	    (erc-display-message
136	     parsed 'notice proc
137	     'notify_off ?n (car old-list) ?m (erc-network-name)))
138	  (setq old-list (cdr old-list)))
139	(setq erc-last-ison ison-list)
140	t))
141    (erc-server-send
142     (concat "ISON " (mapconcat 'identity erc-notify-list " ")))
143    (setq erc-last-ison-time now)))
144
145(defun erc-notify-JOIN (proc parsed)
146  "Check if channel joiner is on `erc-notify-list' and not on `erc-last-ison'.
147If this condition is satisfied, produce a notify_on message and add the nick
148to `erc-last-ison' to prevent any further notifications."
149  (let ((nick (erc-extract-nick (erc-response.sender parsed))))
150    (when (and (erc-member-ignore-case nick erc-notify-list)
151	       (not (erc-member-ignore-case nick erc-last-ison)))
152      (add-to-list 'erc-last-ison nick)
153      (run-hook-with-args 'erc-notify-signon-hook
154			  (or erc-server-announced-name erc-session-server)
155			  nick)
156      (erc-display-message
157       parsed 'notice proc
158       'notify_on ?n nick ?m (erc-network-name)))
159    nil))
160
161(defun erc-notify-NICK (proc parsed)
162  "Check if new nick is on `erc-notify-list' and not on `erc-last-ison'.
163If this condition is satisfied, produce a notify_on message and add the nick
164to `erc-last-ison' to prevent any further notifications."
165  (let ((nick (erc-response.contents parsed)))
166    (when (and (erc-member-ignore-case nick erc-notify-list)
167	       (not (erc-member-ignore-case nick erc-last-ison)))
168      (add-to-list 'erc-last-ison nick)
169      (run-hook-with-args 'erc-notify-signon-hook
170			  (or erc-server-announced-name erc-session-server)
171			  nick)
172      (erc-display-message
173       parsed 'notice proc
174       'notify_on ?n nick ?m (erc-network-name)))
175    nil))
176
177(defun erc-notify-QUIT (proc parsed)
178  "Check if quitter is on `erc-notify-list' and on `erc-last-ison'.
179If this condition is satisfied, produce a notify_off message and remove the
180nick from `erc-last-ison' to prevent any further notifications."
181  (let ((nick (erc-extract-nick (erc-response.sender parsed))))
182    (when (and (erc-member-ignore-case nick erc-notify-list)
183	       (erc-member-ignore-case nick erc-last-ison))
184      (setq erc-last-ison (erc-delete-if `(lambda (el)
185					    (string= ,(erc-downcase nick)
186						     (erc-downcase el)))
187					 erc-last-ison))
188      (run-hook-with-args 'erc-notify-signoff-hook
189			  (or erc-server-announced-name erc-session-server)
190			  nick)
191      (erc-display-message
192       parsed 'notice proc
193       'notify_off ?n nick ?m (erc-network-name)))
194    nil))
195
196;;;; User level command
197
198;;;###autoload
199(defun erc-cmd-NOTIFY (&rest args)
200  "Change `erc-notify-list' or list current notify-list members online.
201Without args, list the current list of notificated people online,
202with args, toggle notify status of people."
203  (cond
204   ((null args)
205    ;; Print current notificated people (online)
206    (let ((ison (erc-with-server-buffer erc-last-ison)))
207      (if (not ison)
208	  (erc-display-message
209	   nil 'notice 'active "No ison-list yet!")
210	(erc-display-message
211	 nil 'notice 'active
212	 'notify_current ?l ison))))
213   ((string= (car args) "-l")
214    (erc-display-message nil 'notice 'active
215			 'notify_list ?l (mapconcat 'identity erc-notify-list
216						    " ")))
217   (t
218    (while args
219      (if (erc-member-ignore-case (car args) erc-notify-list)
220	  (progn
221	    (setq erc-notify-list (delete (car args) erc-notify-list))
222	    ;; Remove the nick from the value of erc-last-ison in
223	    ;; every server buffer.  This prevents seeing a signoff
224	    ;; notification for a nick that you have just _removed_
225	    ;; from your notify list.
226	    (dolist (buf (erc-buffer-list))
227	      (with-current-buffer buf
228		(if (erc-server-buffer-p)
229		    (setq erc-last-ison (delete (car args) erc-last-ison))))))
230	(setq erc-notify-list (cons (erc-string-no-properties (car args))
231				    erc-notify-list)))
232      (setq args (cdr args)))
233    (erc-display-message
234     nil 'notice 'active
235     'notify_list ?l (mapconcat 'identity erc-notify-list " "))))
236  t)
237
238;;;###autoload
239(defun pcomplete/erc-mode/NOTIFY ()
240  (pcomplete-here (pcomplete-erc-all-nicks)))
241
242(erc-notify-install-message-catalogs)
243
244(provide 'erc-notify)
245
246;;; erc-notify.el ends here
247;;
248;; Local Variables:
249;; indent-tabs-mode: t
250;; tab-width: 8
251;; End:
252
253;; arch-tag: 0fb19dd0-1359-458a-89b7-81dc195a588e
254