* riece-commands.el (riece-command-invite): Don't accept channel
[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 (eval-when-compile (require 'riece-inlines))
28
29 (if (featurep 'xemacs)
30     (require 'riece-xemacs)
31   (require 'riece-emacs))
32
33 (require 'riece-filter)
34 (require 'riece-highlight)
35 (require 'riece-display)
36 (require 'riece-server)
37 (require 'riece-compat)
38 (require 'riece-commands)
39
40 (defvar riece-channel-list-mode-map (make-sparse-keymap))
41 (defvar riece-user-list-mode-map (make-sparse-keymap))
42
43 (defvar riece-dialogue-mode-map
44   (let ((keymap (make-keymap)))
45     (suppress-keymap keymap 'nodigit)
46     keymap))
47
48 (defvar riece-command-mode-map (make-keymap))
49 (defvar riece-command-map (make-sparse-keymap))
50
51 (defvar riece-command-mode-syntax-table nil)
52
53 (put 'riece-command-mode 'mode-class 'special)
54 (put 'riece-dialogue-mode 'mode-class 'special)
55 (put 'riece-channel-list-mode 'mode-class 'special)
56 (put 'riece-user-list-mode 'mode-class 'special)
57 (put 'riece-channel-mode 'derived-mode-parent 'riece-dialogue-mode)
58 (put 'riece-others-mode 'derived-mode-parent 'riece-dialogue-mode)
59
60 (defvar riece-buffer-mode-alist
61   '((riece-dialogue-buffer . riece-dialogue-mode)
62     (riece-others-buffer . riece-others-mode)
63     (riece-channel-list-buffer . riece-channel-list-mode)
64     (riece-private-buffer . riece-dialogue-mode)
65     (riece-wallops-buffer)))
66     
67 (defvar riece-select-keys
68   '("1" riece-command-switch-to-channel-by-number-1
69     "2" riece-command-switch-to-channel-by-number-2
70     "3" riece-command-switch-to-channel-by-number-3
71     "4" riece-command-switch-to-channel-by-number-4
72     "5" riece-command-switch-to-channel-by-number-5
73     "6" riece-command-switch-to-channel-by-number-6
74     "7" riece-command-switch-to-channel-by-number-7
75     "8" riece-command-switch-to-channel-by-number-8
76     "9" riece-command-switch-to-channel-by-number-9
77     "0" riece-command-switch-to-channel-by-number-10
78     "\C-c1" riece-command-switch-to-channel-by-number-11
79     "\C-c2" riece-command-switch-to-channel-by-number-12
80     "\C-c3" riece-command-switch-to-channel-by-number-13
81     "\C-c4" riece-command-switch-to-channel-by-number-14
82     "\C-c5" riece-command-switch-to-channel-by-number-15
83     "\C-c6" riece-command-switch-to-channel-by-number-16
84     "\C-c7" riece-command-switch-to-channel-by-number-17
85     "\C-c8" riece-command-switch-to-channel-by-number-18
86     "\C-c9" riece-command-switch-to-channel-by-number-19
87     "\C-c0" riece-command-switch-to-channel-by-number-20))
88
89 ;;; Keymap macros. -- borrowed from `gnus-util.el'.
90 (defmacro riece-local-set-keys (&rest plist)
91   "Set the keys in PLIST in the current keymap."
92   `(riece-define-keys-1 (current-local-map) ',plist))
93
94 (defmacro riece-define-keys (keymap &rest plist)
95   "Assign KEYMAP keys from PLIST."
96   `(riece-define-keys-1 ',keymap ',plist))
97
98 (defmacro riece-define-keys-safe (keymap &rest plist)
99   "Assign KEYMAP keys from PLIST without overwriting previous definitions."
100   `(riece-define-keys-1 ',keymap ',plist t))
101
102 (put 'riece-define-keys 'lisp-indent-function 1)
103 (put 'riece-define-keys-safe 'lisp-indent-function 1)
104 (put 'riece-local-set-keys 'lisp-indent-function 1)
105
106 (defun riece-define-keys-1 (keymap plist &optional safe)
107   "Assign KEYMAP keys from PLIST.
108 If optional argument SAFE is nil, overwrite previous definitions."
109   (unless keymap
110     (error "Can't set keys in a null keymap"))
111   (cond
112    ((symbolp keymap)
113     (setq keymap (symbol-value keymap)))
114    ((keymapp keymap))
115    ((listp keymap)
116     (set (car keymap) nil)
117     (define-prefix-command (car keymap))
118     (define-key (symbol-value (nth 2 keymap)) (nth 1 keymap) (car keymap))
119     (setq keymap (symbol-value (car keymap)))))
120   (let (key)
121     (while plist
122       (when (symbolp (setq key (pop plist)))
123         (setq key (symbol-value key)))
124       (if (or (not safe)
125               (eq (lookup-key keymap key) 'undefined))
126           (define-key keymap key (pop plist))
127         (pop plist)))))
128
129 (when t
130   (riece-define-keys riece-dialogue-mode-map
131     "\177" scroll-down
132     [delete] scroll-down
133     [backspace] scroll-down
134     [return] scroll-up
135     " " scroll-up
136     "$" end-of-buffer
137     "/" riece-command-raw
138     ">" end-of-buffer
139     "<" beginning-of-buffer
140     "\C-ta" riece-command-toggle-away
141     "c" riece-command-select-command-buffer
142     "f" riece-command-finger
143     "\C-tf" riece-command-toggle-freeze
144     "\C-to" riece-command-toggle-own-freeze
145     "\C-tu" riece-command-toggle-user-list-buffer-mode
146     "\C-tc" riece-command-toggle-channel-buffer-mode
147     "i" riece-command-invite
148     "j" riece-command-join
149     "\C-k" riece-command-kick
150     "l" riece-command-list
151     "m" riece-dialogue-enter-message
152     "M" riece-command-change-mode
153     "n" riece-command-change-nickname
154     "o" other-window
155     "O" riece-command-open-server
156     "C" riece-command-close-server
157     "M" riece-command-universal-server-name-argument
158     "q" riece-command-quit
159     "r" riece-command-configure-windows
160     "x" riece-command-copy-region
161     "t" riece-command-topic)
162
163   (riece-define-keys riece-command-mode-map
164     "\r" riece-command-enter-message
165     [tab] riece-command-complete
166     [(meta control c) >] riece-command-push
167     [(meta control c) <] riece-command-pop)
168
169   (riece-define-keys (riece-command-map "\C-c" riece-command-mode-map)
170     "\177" riece-command-scroll-down
171     [delete] riece-command-scroll-down
172     [backspace] riece-command-scroll-down
173     " " riece-command-scroll-up
174     "$" riece-command-end-of-buffer
175     ">" riece-command-next-channel
176     "<" riece-command-previous-channel
177     "\C-j" riece-command-next-channel
178     "\C-n" riece-command-names
179     "l" riece-command-list
180     "\C-m" riece-command-change-mode
181     "o" riece-command-set-operators
182     "\C-p" riece-command-part
183     "r" riece-command-configure-windows
184     "v" riece-command-set-voices)
185   (set-keymap-parent riece-command-map riece-dialogue-mode-map)
186
187   (riece-define-keys riece-user-list-mode-map
188     "o" riece-command-set-operators
189     "v" riece-command-set-voices
190     "f" riece-command-finger
191     " " riece-command-nick-scroll-up
192     "\177" riece-command-nick-scroll-down
193     [delete] riece-command-nick-scroll-down
194     [backspace] riece-command-nick-scroll-down
195     "c" riece-command-select-command-buffer)
196
197   (riece-define-keys riece-channel-list-mode-map
198     ">" riece-command-next-channel
199     "<" riece-command-previous-channel
200     "u" riece-command-unread-channel
201     "o" other-window
202     "c" riece-command-select-command-buffer)
203
204   (riece-define-keys-1 riece-dialogue-mode-map riece-select-keys)
205   (riece-define-keys-1 riece-channel-list-mode-map riece-select-keys))
206
207 (defun riece-read-variables-files (&optional file)
208   "Read variables FILEs."
209   (or (file-directory-p riece-directory)
210       (make-directory riece-directory))
211   (let ((files (if file
212                    (setq riece-variables-file file
213                          riece-variables-files (list file))
214                  riece-variables-files)))
215     (while files
216       (condition-case nil
217           (load (expand-file-name (car files)))
218         (file-error nil))
219       (setq files (cdr files)))))
220
221 (defvar print-quoted)
222 (defvar print-escape-multibyte)
223 (defun riece-save-variables-files ()
224   "Save current settings to `riece-variables-file'."
225   (with-temp-file riece-saved-variables-file
226     (let ((print-quoted t)
227           (print-readably t)
228           print-escape-multibyte
229           print-level
230           print-length
231           (variables riece-saved-forms))
232       (while variables
233         (prin1 `(setq ,(car variables)
234                       ',(symbol-value (car variables)))
235                (current-buffer))
236         (insert "\n")
237         (setq variables (cdr variables)))))
238   (setq riece-save-variables-are-dirty nil))
239
240 ;;;###autoload
241 (defun riece (&optional confirm)
242   "Connect to the IRC server and start chatting.
243 If optional argument CONFIRM is non-nil, ask which IRC server to connect.
244 If already connected, just pop up the windows."
245   (interactive "P")
246   (riece-read-variables-files
247    (car command-line-args-left))
248   (pop command-line-args-left)
249   (run-hooks 'riece-after-load-startup-hook)
250   (if (riece-server-opened)
251       (riece-configure-windows)
252     (switch-to-buffer (riece-get-buffer-create riece-command-buffer))
253     (unless (eq major-mode 'riece-command-mode)
254       (riece-command-mode))
255     (if (or confirm (null riece-server))
256         (setq riece-server (completing-read "Server: " riece-server-alist)))
257     (if (stringp riece-server)
258         (setq riece-server (riece-server-name-to-server riece-server)))
259     (setq riece-server-process (riece-start-server riece-server))
260     (riece-create-buffers)
261     (riece-configure-windows)
262     (let ((channel-list riece-startup-channel-list))
263       (while channel-list
264         (if (listp (car channel-list))
265             (riece-command-join (car (car channel-list))
266                                 (cadr (car channel-list)))
267           (riece-command-join (car channel-list)))
268         (setq channel-list (cdr channel-list))))
269     (run-hooks 'riece-startup-hook)
270     (message "%s" (substitute-command-keys
271                    "Type \\[describe-mode] for help"))))
272
273 (defun riece-exit ()
274   (setq riece-server nil)
275   (if riece-save-variables-are-dirty
276       (riece-save-variables-files))
277   (riece-clear-system)
278   (run-hooks 'riece-exit-hook))
279
280 (defun riece-command-mode ()
281   "Major mode for Riece.  Normal edit function are available.
282 Typing Return or Linefeed enters the current line in the dialogue.
283 The following special commands are available:
284 For a list of the generic commands type \\[riece-command-generic] ? RET.
285 \\{riece-command-mode-map}"
286   (interactive)
287   (kill-all-local-variables)
288
289   (setq major-mode 'riece-command-mode
290         mode-name "Commands"
291         riece-away-indicator "-"
292         riece-freeze-indicator "-"
293         riece-own-freeze-indicator "-"
294         mode-line-buffer-identification
295         (riece-mode-line-buffer-identification
296          '("Riece: "
297            mode-line-modified
298            riece-away-indicator
299            "-- " riece-current-channel " " riece-real-nickname)))
300   (riece-simplify-mode-line-format)
301   (use-local-map riece-command-mode-map)
302
303   (unless riece-command-mode-syntax-table
304     (setq riece-command-mode-syntax-table
305           (copy-syntax-table (syntax-table)))
306     (set-syntax-table riece-command-mode-syntax-table)
307     (mapcar
308      (lambda (c) (modify-syntax-entry c "w"))
309      "^[]{}'`"))
310
311   (run-hooks 'riece-command-mode-hook))
312   
313 (defun riece-dialogue-mode ()
314   "Major mode for displaying the IRC dialogue.
315 All normal editing commands are turned off.
316 Instead, these commands are available:
317 \\{riece-dialogue-mode-map}"
318   (kill-all-local-variables)
319
320   (make-local-variable 'riece-freeze)
321   (make-local-variable 'riece-freeze-indicator)
322   (make-local-variable 'riece-own-freeze)
323   (make-local-variable 'riece-own-freeze-indicator)
324   (make-local-variable 'tab-stop-list)
325
326   (setq riece-freeze riece-default-freeze
327         riece-freeze-indicator (if riece-freeze "F" "-")
328         riece-own-freeze riece-default-own-freeze
329         riece-own-freeze-indicator (if riece-own-freeze "M" "-")
330
331         major-mode 'riece-dialogue-mode
332         mode-name "Dialogue"
333         mode-line-buffer-identification
334         (riece-mode-line-buffer-identification
335          '("Riece: "
336            mode-line-modified
337            riece-away-indicator
338            riece-freeze-indicator
339            riece-own-freeze-indicator
340            " " riece-channel-list-indicator " "))
341         buffer-read-only t
342         tab-stop-list riece-tab-stop-list)
343   (riece-simplify-mode-line-format)
344   (use-local-map riece-dialogue-mode-map)
345   (buffer-disable-undo)
346   (run-hooks 'riece-dialogue-mode-hook))
347
348 (define-derived-mode riece-others-mode riece-dialogue-mode
349   "Others"
350   "Major mode for displaying the IRC others message except current channel.
351 All normal editing commands are turned off.
352 Instead, these commands are available:
353 \\{riece-others-mode-map}")
354
355 (define-derived-mode riece-channel-mode riece-dialogue-mode
356   "Channel"
357   "Major mode for displaying the IRC current channel buffer.
358 All normal editing commands are turned off.
359 Instead, these commands are available:
360 \\{riece-channel-mode-map}"
361   (setq mode-line-buffer-identification
362         (riece-mode-line-buffer-identification
363          '("Riece: "
364            mode-line-modified
365            riece-away-indicator
366            riece-freeze-indicator
367            riece-own-freeze-indicator
368            " "
369            riece-channel-indicator))))
370
371 (defun riece-channel-list-mode ()
372   "Major mode for displaying channel list.
373 All normal editing commands are turned off."
374   (kill-all-local-variables)
375   (setq major-mode 'riece-channel-list-mode
376         mode-name "Channels"
377         mode-line-buffer-identification
378         (riece-mode-line-buffer-identification '("Riece: "))
379         truncate-lines t
380         buffer-read-only t)
381   (use-local-map riece-channel-list-mode-map)
382   (run-hooks 'riece-channel-list-mode-hook))
383
384 (defun riece-user-list-mode ()
385   "Major mode for displaying members in the IRC current channel buffer.
386 All normal editing commands are turned off.
387 Instead, these commands are available:
388 \\{riece-user-list-mode-map}"
389   (kill-all-local-variables)
390   (setq mode-line-modified "--- "
391         major-mode 'riece-user-list-mode
392         mode-name "Riece Channel member"
393         mode-line-buffer-identification
394         (riece-mode-line-buffer-identification
395          '("Riece: " riece-channel-indicator " "))
396         truncate-lines t
397         buffer-read-only t)
398   (if (boundp 'transient-mark-mode)
399       (set (make-local-variable 'transient-mark-mode) t))
400   (use-local-map riece-user-list-mode-map)
401   (run-hooks 'riece-user-list-mode-hook))
402
403 (defun riece-create-buffers ()
404   (let ((alist riece-buffer-mode-alist))
405     (while alist
406       (save-excursion
407         (set-buffer (riece-get-buffer-create
408                      (symbol-value (car (car alist)))))
409         (unless (or (null (cdr (car alist)))
410                     (eq major-mode (cdr (car alist))))
411           (funcall (cdr (car alist))))
412         (setq alist (cdr alist))))))
413
414 (provide 'riece)
415
416 ;;; riece.el ends here