Mercurial > emacs
comparison lisp/erc/erc-log.el @ 68451:fc745b05e928
Revision: emacs@sv.gnu.org/emacs--devo--0--patch-22
Creator: Michael Olson <mwolson@gnu.org>
Install ERC.
author | Miles Bader <miles@gnu.org> |
---|---|
date | Sun, 29 Jan 2006 13:08:58 +0000 |
parents | |
children | 7010bb070445 |
comparison
equal
deleted
inserted
replaced
68450:a3ba4ef5d590 | 68451:fc745b05e928 |
---|---|
1 ;;; erc-log.el --- Logging facilities for ERC. | |
2 | |
3 ;; Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. | |
4 | |
5 ;; Author: Lawrence Mitchell <wence@gmx.li> | |
6 ;; Keywords: IRC, chat, client, Internet, logging | |
7 | |
8 ;; Created 2003-04-26 | |
9 ;; Logging code taken from erc.el and modified to use markers. | |
10 | |
11 ;; This file is part of GNU Emacs. | |
12 | |
13 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
14 ;; it under the terms of the GNU General Public License as published by | |
15 ;; the Free Software Foundation; either version 2, or (at your option) | |
16 ;; any later version. | |
17 | |
18 ;; GNU Emacs is distributed in the hope that it will be useful, | |
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 ;; GNU General Public License for more details. | |
22 | |
23 ;; You should have received a copy of the GNU General Public License | |
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
25 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
26 ;; Boston, MA 02110-1301, USA. | |
27 | |
28 ;;; Commentary: | |
29 | |
30 ;; This file implements log file writing support for ERC. | |
31 | |
32 ;; Quick start: | |
33 ;; | |
34 ;; (setq erc-enable-logging t) | |
35 ;; (setq erc-log-channels-directory "/path/to/logfiles") ; must be writable | |
36 ;; | |
37 ;; There are two ways to setup logging. The first will write to the log files | |
38 ;; on each incoming or outgoing line - this may not be optimal on a laptop | |
39 ;; HDD. To do this, M-x customize-variable erc-modules, and add "log". | |
40 ;; | |
41 ;; The second method will save buffers on /part, /quit, or killing the | |
42 ;; channel buffer. To do this, add the following to your .emacs: | |
43 ;; | |
44 ;; (require 'erc-log) | |
45 ;; | |
46 ;; You may optionally want the following code, to save all ERC buffers | |
47 ;; without confirmation when exiting emacs: | |
48 ;; | |
49 ;; (defadvice save-buffers-kill-emacs (before save-logs (&rest args) activate) | |
50 ;; (save-some-buffers t (lambda () | |
51 ;; (when (and (eq major-mode 'erc-mode) | |
52 ;; (not (null buffer-file-name))) t)))) | |
53 ;; | |
54 ;; If you only want to save logs for some buffers, customise the | |
55 ;; variable `erc-enable-logging'. | |
56 | |
57 ;; How it works: | |
58 ;; | |
59 ;; If logging is enabled, at some point, `erc-save-buffer-in-logs' | |
60 ;; will be called. The "end" of the buffer is taken from | |
61 ;; `erc-insert-marker', while `erc-last-saved-position' holds the | |
62 ;; position the buffer was last saved at (as a marker, or if the | |
63 ;; buffer hasn't been saved before, as the number 1 (point-min)). | |
64 | |
65 ;; The region between `erc-last-saved-position' and | |
66 ;; `erc-insert-marker' is saved to the current buffer's logfile, and | |
67 ;; `erc-last-saved-position' is updated to reflect this. | |
68 | |
69 ;;; History: | |
70 ;; 2003-04-26: logging code pulled out of erc.el. Switched to using | |
71 ;; markers. | |
72 | |
73 ;;; TODO: | |
74 ;; * Erc needs a generalised make-safe-file-name function, so that | |
75 ;; generated file names don't contain any invalid file characters. | |
76 ;; | |
77 ;; * Really, we need to lock the logfiles somehow, so that if a user | |
78 ;; is running multiple emacsen and/or on the same channel as more | |
79 ;; than one user, only one process writes to the logfile. This is | |
80 ;; especially needed for those logfiles with no nick in them, as | |
81 ;; these would become corrupted. | |
82 ;; For a single emacs process, the problem could be solved using a | |
83 ;; variable which contained the names of buffers already being | |
84 ;; logged. This would require that logging be buffer-local, | |
85 ;; possibly not a bad thing anyway, since many people don't want to | |
86 ;; log the server buffer. | |
87 ;; For multiple emacsen the problem is trickier. On some systems, | |
88 ;; on could use the function `lock-buffer' and `unlock-buffer'. | |
89 ;; However, file locking isn't implemented on all platforms, for | |
90 ;; example, there is none on w32 systems. | |
91 ;; A third possibility might be to fake lockfiles. However, this | |
92 ;; might lead to problems if an emacs crashes, as the lockfile | |
93 ;; would be left lying around. | |
94 | |
95 ;;; Code: | |
96 | |
97 (require 'erc) | |
98 (eval-when-compile (require 'cl)) | |
99 | |
100 (defgroup erc-log nil | |
101 "Logging facilities for ERC." | |
102 :group 'erc) | |
103 | |
104 (defcustom erc-generate-log-file-name-function 'erc-generate-log-file-name-long | |
105 "*A function to generate a log filename. | |
106 The function must take five arguments: BUFFER, TARGET, NICK, SERVER and PORT. | |
107 BUFFER is the buffer to be saved, | |
108 TARGET is the name of the channel, or the target of the query, | |
109 NICK is the current nick, | |
110 SERVER and PORT are the parameters used to connect BUFFERs | |
111 `erc-server-process'." | |
112 :group 'erc-log | |
113 :type '(choice (const erc-generate-log-file-name-long) | |
114 (const erc-generate-log-file-name-short) | |
115 (const erc-generate-log-file-name-with-date) | |
116 (symbol))) | |
117 | |
118 (defcustom erc-save-buffer-on-part nil | |
119 "*Save the channel buffer content using `erc-save-buffer-in-logs' on PART." | |
120 :group 'erc-log | |
121 :type 'boolean) | |
122 | |
123 (defcustom erc-truncate-buffer-on-save nil | |
124 "Truncate any ERC (channel, query, server) buffer when it is saved." | |
125 :group 'erc-log | |
126 :type 'boolean) | |
127 | |
128 (defcustom erc-enable-logging t | |
129 "If non-nil, ERC will log IRC conversations. | |
130 This can either be a boolean value of nil or t, or a function. | |
131 If the value is a function, it will be called with one argument, the | |
132 name of the current ERC buffer. One possible function, which saves | |
133 all but server buffers is `erc-log-all-but-server-buffers'. | |
134 | |
135 This variable is buffer local. Setting it via \\[customize] sets the | |
136 default value. | |
137 | |
138 Log files are stored in `erc-log-channels-directory'." | |
139 :group 'erc-log | |
140 :type '(choice boolean | |
141 function)) | |
142 (make-variable-buffer-local 'erc-enable-logging) | |
143 | |
144 (defcustom erc-log-channels-directory "~/log" | |
145 "The directory to place log files for channels. | |
146 Leave blank to disable logging. If not nil, all the channel | |
147 buffers are logged in separate files in that directory. The | |
148 directory should not end with a trailing slash." | |
149 :group 'erc-log | |
150 :type '(choice directory | |
151 (const nil))) | |
152 | |
153 (defcustom erc-log-insert-log-on-open t | |
154 "*Insert log file contents into the buffer if a log file exists." | |
155 :group 'erc-log | |
156 :type 'boolean) | |
157 | |
158 (defcustom erc-save-queries-on-quit nil | |
159 "Save all query (also channel) buffers of the server on QUIT. | |
160 See the variable `erc-save-buffer-on-part' for details." | |
161 :group 'erc-log | |
162 :type 'boolean) | |
163 | |
164 (defcustom erc-log-file-coding-system (if (featurep 'xemacs) | |
165 'binary | |
166 'emacs-mule) | |
167 "*The coding system ERC should use for writing log files. | |
168 | |
169 This should ideally, be a \"catch-all\" coding system, like | |
170 `emacs-mule', or `iso-2022-7bit'." | |
171 :group 'erc-log) | |
172 | |
173 ;;;###autoload (autoload 'erc-log-mode "erc-log" nil t) | |
174 (define-erc-module log nil | |
175 "Automatically logs things you receive on IRC into files. | |
176 Files are stored in `erc-log-channels-directory'; file name | |
177 format is defined through a formatting function on | |
178 `erc-generate-log-file-name-function'. | |
179 | |
180 Since automatic logging is not always a Good Thing (especially if | |
181 people say things in different coding systems), you can turn logging | |
182 behaviour on and off with the variable `erc-enable-logging', which can | |
183 also be a predicate function. To only log when you are not set away, use: | |
184 | |
185 \(setq erc-enable-logging | |
186 (lambda (buffer) | |
187 (with-current-buffer buffer | |
188 (not erc-away))))" | |
189 ;; enable | |
190 ((add-hook 'erc-insert-post-hook | |
191 'erc-save-buffer-in-logs) | |
192 (add-hook 'erc-send-post-hook | |
193 'erc-save-buffer-in-logs)) | |
194 ;; disable | |
195 ((remove-hook 'erc-insert-post-hook | |
196 'erc-save-buffer-in-logs) | |
197 (remove-hook 'erc-send-post-hook | |
198 'erc-save-buffer-in-logs))) | |
199 | |
200 (when erc-enable-logging | |
201 (add-hook 'erc-kill-buffer-hook | |
202 'erc-save-buffer-in-logs) | |
203 (add-hook 'erc-kill-channel-hook | |
204 'erc-save-buffer-in-logs) | |
205 (add-hook 'erc-quit-hook | |
206 'erc-conditional-save-queries) | |
207 (add-hook 'erc-part-hook | |
208 'erc-conditional-save-buffer)) | |
209 | |
210 (define-key erc-mode-map "\C-c\C-l" 'erc-save-buffer-in-logs) | |
211 | |
212 ;;;functionality referenced from erc.el | |
213 (defun erc-log-setup-logging () | |
214 "Setup the buffer-local logging variables in the current buffer. | |
215 This function is destined to be run from `erc-connect-pre-hook'." | |
216 (when (erc-logging-enabled) | |
217 (auto-save-mode -1) | |
218 (setq buffer-offer-save t | |
219 buffer-file-name "") | |
220 (set (make-local-variable 'write-file-functions) | |
221 '(erc-save-buffer-in-logs)) | |
222 (when erc-log-insert-log-on-open | |
223 (ignore-errors (insert-file-contents (erc-current-logfile)) | |
224 (move-marker erc-last-saved-position | |
225 (1- (point-max))))))) | |
226 | |
227 ;;; Append, so that 'erc-initialize-log-marker keeps running first. | |
228 (add-hook 'erc-connect-pre-hook 'erc-log-setup-logging 'append) | |
229 | |
230 (defun erc-log-all-but-server-buffers (buffer) | |
231 "Returns t if logging should be enabled in BUFFER. | |
232 Returns nil iff `erc-server-buffer-p' returns t." | |
233 (save-excursion | |
234 (save-window-excursion | |
235 (set-buffer buffer) | |
236 (not (erc-server-buffer-p))))) | |
237 | |
238 (defun erc-save-query-buffers (process) | |
239 "Save all buffers process." | |
240 (erc-with-all-buffers-of-server process | |
241 nil | |
242 (erc-save-buffer-in-logs))) | |
243 | |
244 (defun erc-conditional-save-buffer (buffer) | |
245 "Save Query BUFFER if `erc-save-queries-on-quit' is t." | |
246 (when erc-save-buffer-on-part | |
247 (erc-save-buffer-in-logs buffer))) | |
248 | |
249 (defun erc-conditional-save-queries (process) | |
250 "Save Query buffers of PROCESS if `erc-save-queries-on-quit' is t." | |
251 (when erc-save-queries-on-quit | |
252 (erc-save-query-buffers process))) | |
253 | |
254 ;;;###autoload | |
255 (defun erc-logging-enabled (&optional buffer) | |
256 "Return non-nil if logging is enabled for BUFFER. | |
257 If BUFFER is nil, the value of `current-buffer' is used. | |
258 Logging is enabled if `erc-log-channels-directory' is non-nil, the directory | |
259 is writeable (it will be created as necessary) and | |
260 `erc-enable-logging' returns a non-nil value." | |
261 (and erc-log-channels-directory | |
262 (erc-directory-writable-p erc-log-channels-directory) | |
263 (if (functionp erc-enable-logging) | |
264 (funcall erc-enable-logging (or buffer (current-buffer))) | |
265 erc-enable-logging))) | |
266 | |
267 (defun erc-current-logfile (&optional buffer) | |
268 "Return the logfile to use for BUFFER. | |
269 If BUFFER is nil, the value of `current-buffer' is used. | |
270 This is determined by `erc-generate-log-file-name-function'. | |
271 The result is converted to lowercase, as IRC is case-insensitive" | |
272 (expand-file-name | |
273 (downcase (funcall erc-generate-log-file-name-function | |
274 (or buffer (current-buffer)) | |
275 (or (erc-default-target) (buffer-name buffer)) | |
276 (erc-current-nick) | |
277 erc-session-server erc-session-port)) | |
278 erc-log-channels-directory)) | |
279 | |
280 (defun erc-generate-log-file-name-with-date (buffer &rest ignore) | |
281 "This function computes a short log file name. | |
282 The name of the log file is composed of BUFFER and the current date. | |
283 This function is a possible value for `erc-generate-log-file-name-function'." | |
284 (concat (buffer-name buffer) "-" (format-time-string "%Y-%m-%d") ".txt")) | |
285 | |
286 (defun erc-generate-log-file-name-short (buffer &rest ignore) | |
287 "This function computes a short log file name. | |
288 In fact, it only uses the buffer name of the BUFFER argument, so | |
289 you can affect that using `rename-buffer' and the-like. This | |
290 function is a possible value for | |
291 `erc-generate-log-file-name-function'." | |
292 (concat (buffer-name buffer) ".txt")) | |
293 | |
294 (defun erc-generate-log-file-name-long (buffer target nick server port) | |
295 "Generates a log-file name in the way ERC always did it. | |
296 This results in a file name of the form #channel!nick@server:port.txt. | |
297 This function is a possible value for `erc-generate-log-file-name-function'." | |
298 (let ((file (concat | |
299 (if target (concat target "!")) | |
300 nick "@" server ":" (cond ((stringp port) port) | |
301 ((numberp port) | |
302 (number-to-string port))) ".txt"))) | |
303 ;; we need a make-safe-file-name function. | |
304 (convert-standard-filename file))) | |
305 | |
306 ;;;###autoload | |
307 (defun erc-save-buffer-in-logs (&optional buffer) | |
308 "Append BUFFER contents to the log file, if logging is enabled. | |
309 If BUFFER is not provided, current buffer is used. | |
310 Logging is enabled if `erc-logging-enabled' returns non-nil. | |
311 | |
312 This is normally done on exit, to save the unsaved portion of the | |
313 buffer, since only the text that runs off the buffer limit is logged | |
314 automatically. | |
315 | |
316 You can save every individual message by putting this function on | |
317 `erc-insert-post-hook'." | |
318 (interactive) | |
319 (or buffer (setq buffer (current-buffer))) | |
320 (when (erc-logging-enabled buffer) | |
321 (let ((file (erc-current-logfile buffer)) | |
322 (coding-system-for-write erc-log-file-coding-system)) | |
323 (save-excursion | |
324 (with-current-buffer buffer | |
325 (save-restriction | |
326 (widen) | |
327 ;; early on in the initalisation, don't try and write the log out | |
328 (when (and (markerp erc-last-saved-position) | |
329 (> erc-insert-marker (1+ erc-last-saved-position))) | |
330 (write-region (1+ (marker-position erc-last-saved-position)) | |
331 (marker-position erc-insert-marker) | |
332 file t 'nomessage) | |
333 (if (and erc-truncate-buffer-on-save (interactive-p)) | |
334 (progn | |
335 (let ((inhibit-read-only t)) (erase-buffer)) | |
336 (move-marker erc-last-saved-position (point-max)) | |
337 (erc-display-prompt)) | |
338 (move-marker erc-last-saved-position | |
339 ;; If we place erc-last-saved-position at | |
340 ;; erc-insert-marker, because text gets | |
341 ;; inserted /before/ erc-insert-marker, | |
342 ;; the log file will not be saved | |
343 ;; (erc-last-saved-position will always | |
344 ;; be equal to erc-insert-marker). | |
345 (1- (marker-position erc-insert-marker))))) | |
346 (set-buffer-modified-p nil)))))) | |
347 t) | |
348 | |
349 (provide 'erc-log) | |
350 | |
351 ;;; erc-log.el ends here | |
352 ;; | |
353 ;; Local Variables: | |
354 ;; indent-tabs-mode: t | |
355 ;; tab-width: 8 | |
356 ;; End: | |
357 | |
358 ;; arch-tag: 54072f99-9f0a-4846-8908-2ccde92221de |