a1d53025445338c73fba6b338693a69ee448fa18
[riece] / lisp / riece.el
1 ;;; riece.el --- IRC client for Emacsen
2 ;; Copyright (C) 1998-2003 Daiki Ueno
3
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
5 ;; Created: 1998-09-28
6 ;; Keywords: IRC, riece
7
8 ;; This file is part of Riece.
9
10 ;; This program 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 ;; This program 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., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Code:
26
27 (require 'riece-display)
28 (require 'riece-server)
29 (require 'riece-compat)
30 (require 'riece-commands)
31 (require 'riece-addon)
32 (require 'riece-signal)
33
34 (autoload 'derived-mode-class "derived")
35
36 (defvar riece-channel-list-mode-map (make-sparse-keymap))
37 (defvar riece-user-list-mode-map (make-sparse-keymap))
38
39 (defvar riece-dialogue-mode-map
40   (let ((keymap (make-keymap)))
41     (suppress-keymap keymap 'nodigit)
42     keymap))
43
44 (defvar riece-command-mode-map (make-keymap))
45 (defvar riece-command-map (make-sparse-keymap))
46
47 (defvar riece-command-mode-syntax-table nil)
48
49 (put 'riece-command-mode 'mode-class 'special)
50 (put 'riece-dialogue-mode 'mode-class 'special)
51 (put 'riece-others-mode 'derived-mode-parent 'riece-dialogue-mode)
52 (put 'riece-channel-list-mode 'mode-class 'special)
53 (put 'riece-user-list-mode 'mode-class 'special)
54 (put 'riece-channel-mode 'derived-mode-parent 'riece-dialogue-mode)
55
56 (defvar riece-buffer-alist
57   '((riece-command-buffer "*Command*" riece-command-mode)
58     (riece-dialogue-buffer "*Dialogue*" riece-dialogue-mode)
59     (riece-others-buffer "*Others*" riece-others-mode)
60     (riece-channel-list-buffer "*Channels*" riece-channel-list-mode)
61     (riece-user-list-buffer " *Users*" riece-user-list-mode)
62     (riece-temp-buffer " *Temp*")
63     (riece-debug-buffer " *Debug*")))
64
65 (defvar riece-shrink-buffer-idle-timer nil
66   "Timer object to periodically shrink channel buffers.")
67
68 (defvar riece-addons-insinuated nil
69   "Non nil if add-ons are already insinuated.")
70
71 (defvar riece-select-keys
72   `("#" riece-command-switch-to-channel-by-number
73     "1" riece-command-switch-to-channel-by-number-1
74     "2" riece-command-switch-to-channel-by-number-2
75     "3" riece-command-switch-to-channel-by-number-3
76     "4" riece-command-switch-to-channel-by-number-4
77     "5" riece-command-switch-to-channel-by-number-5
78     "6" riece-command-switch-to-channel-by-number-6
79     "7" riece-command-switch-to-channel-by-number-7
80     "8" riece-command-switch-to-channel-by-number-8
81     "9" riece-command-switch-to-channel-by-number-9
82     "0" riece-command-switch-to-channel-by-number-10
83     ,(concat riece-command-prefix "1")
84     riece-command-switch-to-channel-by-number-11
85     ,(concat riece-command-prefix "2")
86     riece-command-switch-to-channel-by-number-12
87     ,(concat riece-command-prefix "3")
88     riece-command-switch-to-channel-by-number-13
89     ,(concat riece-command-prefix "4")
90     riece-command-switch-to-channel-by-number-14
91     ,(concat riece-command-prefix "5")
92     riece-command-switch-to-channel-by-number-15
93     ,(concat riece-command-prefix "6")
94     riece-command-switch-to-channel-by-number-16
95     ,(concat riece-command-prefix "7")
96     riece-command-switch-to-channel-by-number-17
97     ,(concat riece-command-prefix "8")
98     riece-command-switch-to-channel-by-number-18
99     ,(concat riece-command-prefix "9")
100     riece-command-switch-to-channel-by-number-19
101     ,(concat riece-command-prefix "0")
102     riece-command-switch-to-channel-by-number-20))
103
104 ;;; Keymap macros. -- borrowed from `gnus-util.el'.
105 (defmacro riece-local-set-keys (&rest plist)
106   "Set the keys in PLIST in the current keymap."
107   `(riece-define-keys-1 (current-local-map) ',plist))
108
109 (defmacro riece-define-keys (keymap &rest plist)
110   "Assign KEYMAP keys from PLIST."
111   `(riece-define-keys-1 ',keymap ',plist))
112
113 (defmacro riece-define-keys-safe (keymap &rest plist)
114   "Assign KEYMAP keys from PLIST without overwriting previous definitions."
115   `(riece-define-keys-1 ',keymap ',plist t))
116
117 (put 'riece-define-keys 'lisp-indent-function 1)
118 (put 'riece-define-keys-safe 'lisp-indent-function 1)
119 (put 'riece-local-set-keys 'lisp-indent-function 1)
120
121 (defun riece-define-keys-1 (keymap plist &optional safe)
122   "Assign KEYMAP keys from PLIST.
123 If optional argument SAFE is nil, overwrite previous definitions."
124   (unless keymap
125     (error "Can't set keys in a null keymap"))
126   (cond
127    ((symbolp keymap)
128     (setq keymap (symbol-value keymap)))
129    ((keymapp keymap))
130    ((listp keymap)
131     (set (car keymap) nil)
132     (define-prefix-command (car keymap))
133     (define-key (symbol-value (nth 2 keymap))
134       (if (symbolp (nth 1 keymap))
135           (symbol-value (nth 1 keymap))
136         (nth 1 keymap))
137       (car keymap))
138     (setq keymap (symbol-value (car keymap)))))
139   (let (key)
140     (while plist
141       (if (symbolp (setq key (car plist)))
142           (setq key (symbol-value key)))
143       (setq plist (cdr plist))
144       (if (or (not safe)
145               (eq (lookup-key keymap key) 'undefined))
146           (define-key keymap key (car plist))
147         (car plist))
148       (setq plist (cdr plist)))))
149
150 (when t
151   (riece-define-keys riece-dialogue-mode-map
152     "\177" scroll-down
153     [delete] scroll-down
154     [backspace] scroll-down
155     [return] scroll-up
156     " " scroll-up
157     [home] beginning-of-buffer
158     "$" end-of-buffer
159     [end] end-of-buffer
160     "/" riece-command-raw
161     ">" end-of-buffer
162     "<" beginning-of-buffer
163     "^" riece-command-list-addons
164     "\C-ta" riece-command-toggle-away
165     "c" riece-command-select-command-buffer
166     "f" riece-command-finger
167     "\C-tf" riece-command-toggle-freeze
168     "\C-to" riece-command-toggle-own-freeze
169     "\C-tu" riece-command-toggle-user-list-buffer-mode
170     "\C-tc" riece-command-toggle-channel-buffer-mode
171     "\C-tC" riece-command-toggle-channel-list-buffer-mode
172     "\C-tl" riece-command-change-layout
173     "i" riece-command-invite
174     "j" riece-command-join
175     "\C-k" riece-command-kick
176     "l" riece-command-list
177     "M" riece-command-change-mode
178     "n" riece-command-change-nickname
179     "N" riece-command-names
180     "o" other-window
181     "O" riece-command-open-server
182     "C" riece-command-close-server
183     "M" riece-command-universal-server-name-argument
184     "p" riece-command-enter-message-to-user
185     "q" riece-command-quit
186     "r" riece-command-configure-windows
187     "x" riece-command-copy-region
188     "t" riece-command-topic
189     "w" riece-command-who
190     "z" riece-command-suspend-resume)
191
192   (riece-define-keys riece-command-mode-map
193     "\r" riece-command-enter-message
194     [(control return)] riece-command-enter-message-as-notice
195     [tab] riece-command-complete-user)
196
197   (riece-define-keys (riece-command-map riece-command-prefix
198                                         riece-command-mode-map)
199     "\177" riece-command-scroll-down
200     [delete] riece-command-scroll-down
201     [backspace] riece-command-scroll-down
202     " " riece-command-scroll-up
203     [home] riece-command-beginning-of-buffer
204     "$" riece-command-end-of-buffer
205     [end] riece-command-end-of-buffer
206     ">" riece-command-next-channel
207     "<" riece-command-previous-channel
208     "\C-j" riece-command-next-channel
209     "\C-n" riece-command-names
210     "l" riece-command-list
211     "\C-m" riece-command-change-mode
212     "o" riece-command-set-operators
213     "\C-p" riece-command-part
214     "r" riece-command-configure-windows
215     "v" riece-command-set-speakers
216     "V" riece-version)
217   (set-keymap-parent riece-command-map riece-dialogue-mode-map)
218
219   (riece-define-keys riece-user-list-mode-map
220     "o" riece-command-set-operators
221     "v" riece-command-set-voices
222     "f" riece-command-finger
223     " " riece-command-user-list-scroll-up
224     "\177" riece-command-user-list-scroll-down
225     [delete] riece-command-user-list-scroll-down
226     [backspace] riece-command-user-list-scroll-down
227     "c" riece-command-select-command-buffer)
228
229   (riece-define-keys riece-channel-list-mode-map
230     ">" riece-command-next-channel
231     "<" riece-command-previous-channel
232     "o" other-window
233     "c" riece-command-select-command-buffer)
234
235   (riece-define-keys-1 riece-dialogue-mode-map riece-select-keys)
236   (riece-define-keys-1 riece-channel-list-mode-map riece-select-keys))
237
238 (defun riece-read-variables-files (&optional file)
239   "Read variables FILEs."
240   (or (file-directory-p riece-directory)
241       (make-directory riece-directory))
242   (let ((files (if file
243                    (setq riece-variables-file file
244                          riece-variables-files (list file))
245                  riece-variables-files)))
246     (while files
247       (condition-case nil
248           (load (expand-file-name (car files)))
249         (file-error nil))
250       (setq files (cdr files)))))
251
252 (defvar print-quoted)
253 (defvar print-escape-multibyte)
254 (defun riece-save-variables-files ()
255   "Save current settings to `riece-variables-file'."
256   (with-temp-file riece-saved-variables-file
257     (let ((print-quoted t)
258           (print-readably t)
259           print-escape-multibyte
260           print-level
261           print-length
262           (variables riece-saved-forms))
263       (while variables
264         (prin1 `(setq ,(car variables)
265                       ',(symbol-value (car variables)))
266                (current-buffer))
267         (insert "\n")
268         (setq variables (cdr variables)))))
269   (setq riece-save-variables-are-dirty nil))
270
271 ;;;###autoload
272 (defun riece (&optional confirm)
273   "Connect to the IRC server and start chatting.
274 If optional argument CONFIRM is non-nil, ask which IRC server to connect."
275   (interactive "P")
276   (riece-read-variables-files (if noninteractive
277                                   (car command-line-args-left)))
278   (run-hooks 'riece-after-load-startup-hook)
279   (if (riece-server-opened)
280       (riece-command-configure-windows)
281     (modify-frame-parameters (selected-frame)
282                              (list (cons 'riece-window-configuration
283                                          (current-window-configuration))))
284     (unless riece-addons-insinuated
285       (setq riece-addons (riece-resolve-addons riece-addons))
286       (let ((pointer riece-addons))
287         (while pointer
288           (riece-insinuate-addon (car pointer) riece-debug)
289           (setq pointer (cdr pointer))))
290       (setq riece-addons-insinuated t))
291     (if (or confirm (null riece-server))
292         (setq riece-server (completing-read "Server: " riece-server-alist)))
293     (if (stringp riece-server)
294         (setq riece-server (riece-server-name-to-server riece-server)))
295     (riece-create-buffers)
296     (if riece-max-buffer-size
297         (setq riece-shrink-buffer-idle-timer
298               (riece-run-with-idle-timer
299                riece-shrink-buffer-idle-time-delay t
300                (lambda ()
301                  (let ((buffers riece-buffer-list))
302                    (while buffers
303                      (if (buffer-live-p (car buffers))
304                          (if (eq (derived-mode-class
305                                   (with-current-buffer (car buffers)
306                                     major-mode))
307                                  'riece-dialogue-mode)
308                              (riece-shrink-buffer (car buffers)))
309                        (delq (car buffers) riece-buffer-list))
310                      (setq buffers (cdr buffers))))))))
311     (switch-to-buffer riece-command-buffer)
312     (riece-display-connect-signals)
313     (riece-redisplay-buffers)
314     (riece-open-server riece-server "")
315     ;; If no server process is available, exit.
316     (if (null riece-server-process-alist)
317         (riece-exit)
318       (let ((server-list riece-startup-server-list))
319         (while server-list
320           (riece-command-open-server (car server-list))
321           (setq server-list (cdr server-list))))
322       (let ((channel-list riece-startup-channel-list)
323             server)
324         (while channel-list
325           (setq server (riece-identity-server
326                         (riece-parse-identity (car channel-list))))
327           (unless (riece-server-opened server)
328             (riece-command-open-server server))
329           (setq channel-list (cdr channel-list))))
330       (let ((pointer riece-addons))
331         (while pointer
332           (unless (get (car pointer) 'riece-addon-default-disabled)
333             (riece-enable-addon (car pointer) riece-debug))
334           (setq pointer (cdr pointer))))
335       (run-hooks 'riece-startup-hook)
336       (message "%s" (substitute-command-keys
337                      "Type \\[describe-mode] for help")))))
338
339 (defun riece-shrink-buffer (buffer)
340   (save-excursion
341     (set-buffer buffer)
342     (goto-char (point-min))
343     (while (> (buffer-size) riece-max-buffer-size)
344       (let* ((inhibit-read-only t)
345              buffer-read-only
346              (end (progn
347                     (goto-char riece-shrink-buffer-remove-chars)
348                     (beginning-of-line 2)
349                     (point)))
350              (overlays (riece-overlays-in (point-min) end)))
351         (while overlays
352           (riece-delete-overlay (car overlays))
353           (setq overlays (cdr overlays)))
354         (delete-region (point-min) end)))))
355
356 (defun riece-exit ()
357   (if riece-save-variables-are-dirty
358       (riece-save-variables-files))
359   (while riece-buffer-list
360     (if (and (get-buffer (car riece-buffer-list))
361              (buffer-live-p (car riece-buffer-list)))
362         (funcall riece-buffer-dispose-function (car riece-buffer-list)))
363     (setq riece-buffer-list (cdr riece-buffer-list)))
364   (if riece-shrink-buffer-idle-timer
365       (riece-cancel-timer riece-shrink-buffer-idle-timer))
366   (riece-clear-signal-slots)
367   (setq riece-server nil
368         riece-current-channels nil
369         riece-current-channel nil
370         riece-channel-buffer nil
371         riece-channel-buffer-alist nil
372         riece-user-indicator nil
373         riece-long-channel-indicator "None"
374         riece-channel-list-indicator "No channel"
375         riece-away-indicator "-"
376         riece-operator-indicator "-"
377         riece-channel-status-indicator "-"
378         riece-freeze-indicator "-")
379   (modify-frame-parameters (selected-frame)
380                            (list (list 'riece-window-configuration)))
381   (delete-other-windows)
382   (run-hooks 'riece-exit-hook))
383
384 (defun riece-command-mode ()
385   "Major mode for Riece.  Normal edit function are available.
386 Typing Return or Linefeed enters the current line in the dialogue.
387 The following special commands are available:
388 For a list of the generic commands type \\[riece-command-generic] ? RET.
389 \\{riece-command-mode-map}"
390   (interactive)
391   (kill-all-local-variables)
392
393   ;; Make `truncate-partial-width-windows' buffer local and set it to
394   ;; nil.  This causes `truncate-lines' to directly control line
395   ;; truncation.
396   (make-local-variable 'truncate-partial-width-windows)
397   (setq truncate-partial-width-windows nil)
398
399   (setq riece-away-indicator "-"
400         riece-operator-indicator "-"
401         riece-channel-status-indicator "-"
402         major-mode 'riece-command-mode
403         mode-name "Command"
404         mode-line-buffer-identification
405         (riece-mode-line-buffer-identification
406          '("Riece: "
407            riece-away-indicator
408            riece-operator-indicator
409            riece-channel-status-indicator
410            " "
411            riece-user-indicator
412            " "
413            riece-channel-indicator))
414         truncate-lines nil)
415   (riece-simplify-mode-line-format)
416   (use-local-map riece-command-mode-map)
417
418   (unless riece-command-mode-syntax-table
419     (setq riece-command-mode-syntax-table
420           (copy-syntax-table (syntax-table)))
421     (set-syntax-table riece-command-mode-syntax-table)
422     (mapcar
423      (lambda (c) (modify-syntax-entry c "w"))
424      "^[]{}'`"))
425
426   (run-hooks 'riece-command-mode-hook))
427
428 (defun riece-dialogue-mode ()
429   "Major mode for displaying the IRC dialogue.
430 All normal editing commands are turned off.
431 Instead, these commands are available:
432 \\{riece-dialogue-mode-map}"
433   (kill-all-local-variables)
434   (make-local-variable 'riece-freeze)
435   (make-local-variable 'riece-freeze-indicator)
436
437   ;; Make `truncate-partial-width-windows' buffer local and set it to
438   ;; nil.  This causes `truncate-lines' to directly control line truncation.
439   (make-local-variable 'truncate-partial-width-windows)
440   (setq truncate-partial-width-windows nil)
441
442   (setq riece-freeze riece-default-freeze
443         riece-away-indicator "-"
444         riece-operator-indicator "-"
445         riece-channel-status-indicator "-"
446         major-mode 'riece-dialogue-mode
447         mode-name "Dialogue"
448         mode-line-buffer-identification
449         (riece-mode-line-buffer-identification
450          '("Riece: "
451            riece-away-indicator
452            riece-operator-indicator
453            riece-freeze-indicator
454            riece-channel-status-indicator
455            " "
456            riece-channel-list-indicator " "))
457         truncate-lines nil
458         buffer-read-only t)
459   (riece-simplify-mode-line-format)
460   (use-local-map riece-dialogue-mode-map)
461   (buffer-disable-undo)
462   (run-hooks 'riece-dialogue-mode-hook))
463
464 (define-derived-mode riece-others-mode riece-dialogue-mode
465   "Others"
466   "Major mode for displaying the IRC others message except current channel.
467 All normal editing commands are turned off.
468 Instead, these commands are available:
469 \\{riece-others-mode-map}")
470
471 (define-derived-mode riece-channel-mode riece-dialogue-mode
472   "Channel"
473   "Major mode for displaying the IRC current channel buffer.
474 All normal editing commands are turned off.
475 Instead, these commands are available:
476 \\{riece-channel-mode-map}"
477   (make-local-variable 'riece-channel-buffer-window-point)
478   (setq mode-line-buffer-identification
479         (riece-mode-line-buffer-identification
480          '("Riece: "
481            riece-away-indicator
482            riece-operator-indicator
483            riece-freeze-indicator
484            riece-channel-status-indicator
485            " "
486            riece-long-channel-indicator))))
487
488 (defun riece-channel-list-mode ()
489   "Major mode for displaying channel list.
490 All normal editing commands are turned off."
491   (kill-all-local-variables)
492   (buffer-disable-undo)
493
494   ;; Make `truncate-partial-width-windows' buffer local and set it to
495   ;; nil.  This causes `truncate-lines' to directly control line truncation.
496   (make-local-variable 'truncate-partial-width-windows)
497   (setq truncate-partial-width-windows nil)
498
499   (setq major-mode 'riece-channel-list-mode
500         mode-name "Channels"
501         mode-line-buffer-identification
502         (riece-mode-line-buffer-identification '("Riece: "))
503         truncate-lines t
504         buffer-read-only t)
505   (make-local-hook 'riece-update-buffer-functions)
506   (add-hook 'riece-update-buffer-functions
507             'riece-update-channel-list-buffer nil t)
508   (use-local-map riece-channel-list-mode-map)
509   (run-hooks 'riece-channel-list-mode-hook))
510
511 (defun riece-user-list-mode ()
512   "Major mode for displaying members in the IRC current channel buffer.
513 All normal editing commands are turned off.
514 Instead, these commands are available:
515 \\{riece-user-list-mode-map}"
516   (kill-all-local-variables)
517   (buffer-disable-undo)
518
519   ;; Make `truncate-partial-width-windows' buffer local and set it to
520   ;; nil.  This causes `truncate-lines' to directly control line truncation.
521   (make-local-variable 'truncate-partial-width-windows)
522   (setq truncate-partial-width-windows nil)
523
524   (setq major-mode 'riece-user-list-mode
525         mode-name "Users"
526         mode-line-buffer-identification
527         (riece-mode-line-buffer-identification
528          '("Riece: " riece-long-channel-indicator " "))
529         truncate-lines t
530         buffer-read-only t)
531   (if (boundp 'transient-mark-mode)
532       (set (make-local-variable 'transient-mark-mode) t))
533   (make-local-hook 'riece-update-buffer-functions)
534   (add-hook 'riece-update-buffer-functions
535             'riece-update-user-list-buffer nil t)
536   (use-local-map riece-user-list-mode-map)
537   (run-hooks 'riece-user-list-mode-hook))
538
539 (defun riece-create-buffers ()
540   (let ((alist riece-buffer-alist))
541     (while alist
542       (save-excursion
543         (set-buffer (apply #'riece-get-buffer-create
544                            (cdr (car alist))))
545         (set (car (car alist)) (current-buffer))
546         (unless (or (null (nth 2 (car alist)))
547                     (eq major-mode (nth 2 (car alist))))
548           (funcall (nth 2 (car alist))))
549         (setq alist (cdr alist))))))
550
551 (defvar reporter-prompt-for-summary-p)
552 (defun riece-submit-bug-report (&optional recent-messages recent-keys)
553   "Submit via mail a bug report on Riece."
554   ;; This strange form ensures that (recent-keys) is the value before
555   ;; the bug subject string is read.
556   (interactive (list (riece-recent-messages 20) (recent-keys)))
557   (message "Querying server version...")
558   (let ((pointer riece-server-process-alist)
559         nickname)
560     (while pointer
561       (when (riece-server-process-opened (cdr (car pointer)))
562         (process-send-string (cdr (car pointer)) "VERSION\r\n")
563         (if (setq nickname
564                   (with-current-buffer (process-buffer (cdr (car pointer)))
565                     riece-real-nickname))
566             (process-send-string
567              (cdr (car pointer))
568              (format "PRIVMSG %s :\1VERSION\1\r\n" nickname))))
569       (setq pointer (cdr pointer))))
570   (sit-for 3)
571   (message "Querying server version...done")
572   (require 'reporter)
573   (let ((reporter-prompt-for-summary-p t))
574     (unless riece-debug
575       (error "Please turn on riece-debug and restart Riece."))
576     (reporter-submit-bug-report
577      "liece@unixuser.org"
578      (riece-version)
579      '(riece-debug)
580      nil
581      nil
582      "This bug report will be sent to the Riece Development Team,
583 not to your local site managers!!
584
585 Please write in Japanese or English, because the Riece maintainers do
586 not have translators to read other languages for them.
587
588 Please describe as succinctly as possible:
589 \t- What happened.
590 \t- What you thought should have happened.
591 \t- Precisely what you were doing at the time.
592
593 Also include a reliable recipe for triggering the bug, as well as
594 any lisp back-traces that you may have.
595 \(setq stack-trace-on-error t\), or \(setq debug-on-error t\) if you
596 are familiar with the debugger, to get a lisp back-trace.")
597     (delete-other-windows)
598     (save-excursion
599       (goto-char (point-max))
600       (insert
601        "\nAdd-on state:\n"
602        "------------\n"
603        (save-window-excursion
604          (save-excursion
605            (riece-command-list-addons)
606            (search-forward "\n\n")
607            (buffer-substring (point-min) (point)))))
608       (insert "Recent messages from servers:\n"
609               "--------------------------")
610       (let ((pointer riece-server-process-alist))
611         (while pointer
612           (insert "\n- \"" (car (car pointer)) "\", \n"
613                   (format "%S" (if (equal (car (car pointer)) "")
614                                    riece-server
615                                  (cdr (assoc (car (car pointer))
616                                              riece-server-alist))))
617                   "\n"
618                   (if (riece-server-process-opened (cdr (car pointer)))
619                       (save-excursion
620                         (set-buffer (process-buffer (cdr (car pointer))))
621                         (goto-char (point-max))
622                         (beginning-of-line -60)
623                         (buffer-substring (point) (point-max)))
624                     "(closed server)"))
625           (setq pointer (cdr pointer))))
626       ;; Insert recent keystrokes.
627       (insert "\n\nRecent keystrokes:\n"
628               "-----------------\n\n")
629       (let ((before-keys (point)))
630         (insert (key-description recent-keys))
631         (save-restriction
632           (narrow-to-region before-keys (point))
633           (goto-char before-keys)
634           (while (progn (move-to-column 50) (not (eobp)))
635             (search-forward " " nil t)
636             (insert "\n"))))
637       ;; Insert recent minibuffer messages.
638       (insert "\n\nRecent messages (most recent first):\n"
639               "-----------------------------------\n"
640               recent-messages))))
641
642 (provide 'riece)
643
644 ;;; riece.el ends here