* riece-mcat.el: New file.
[elisp/riece.git] / lisp / riece-commands.el
1 ;;; riece-commands.el --- commands available in command buffer
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., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02110-1301, USA.
24
25 ;;; Code:
26
27 (require 'riece-channel)
28 (require 'riece-complete)
29 (require 'riece-layout)
30 (require 'riece-display)
31 (require 'riece-server)
32 (require 'riece-misc)
33 (require 'riece-identity)
34 (require 'riece-message)
35 (require 'riece-mcat)
36
37 (autoload 'derived-mode-class "derived")
38
39 ;;; Channel movement:
40 (defun riece-command-switch-to-channel (channel)
41   (interactive (list (riece-completing-read-identity
42                       "Switch to channel/user: "
43                       riece-current-channels nil t)))
44   (unless (equal channel riece-current-channel)
45     (riece-switch-to-channel channel)))
46
47 (defun riece-command-switch-to-channel-by-number (number)
48   (interactive
49    (let ((command-name (symbol-name this-command)))
50      (if (string-match "[0-9]+$" command-name)
51          (list (string-to-number (match-string 0 command-name)))
52        (list (string-to-number (read-string "Switch to number: "))))))
53   (let ((channel (nth (1- number) riece-current-channels)))
54     (if channel
55         (riece-command-switch-to-channel channel)
56       (error "No such number!"))))
57
58 (eval-and-compile
59   (let ((number 1))
60     (while (<= number 20)
61       (defalias (intern (concat "riece-command-switch-to-channel-by-number-"
62                                 (number-to-string number)))
63         'riece-command-switch-to-channel-by-number)
64       (setq number (1+ number)))))
65
66 (defun riece-command-next-channel ()
67   "Select the next channel."
68   (interactive)
69   (when (> (length riece-current-channels) 1)
70     (let ((pointer (cdr (riece-identity-member
71                          riece-current-channel
72                          riece-current-channels))))
73       (while (and pointer
74                   (null (car pointer)))
75         (setq pointer (cdr pointer)))
76       (when (null pointer)
77         (setq pointer riece-current-channels)
78         (while (and pointer
79                     (null (car pointer)))
80           (setq pointer (cdr pointer))))
81       (if (car pointer)
82           (riece-command-switch-to-channel (car pointer))
83         (error "No such channel!")))))
84
85 (defun riece-command-previous-channel ()
86   "Select the previous channel."
87   (interactive)
88   (when (> (length riece-current-channels) 1)
89     (let ((pointer (riece-identity-member
90                     riece-current-channel
91                     riece-current-channels))
92           (start riece-current-channels)
93           channel)
94       (while (and start (not (eq start pointer)))
95         (if (car start)
96             (setq channel (car start)))
97         (setq start (cdr start)))
98       (when (null channel)
99         (setq start (copy-sequence riece-current-channels))
100         (setq start (delq nil start))
101         (and (> (length start) 1)
102              (setq channel (nth (1- (length start)) start))))
103       (if channel
104           (riece-command-switch-to-channel channel)
105         (error "No such channel!")))))
106
107 (defun riece-command-select-command-buffer ()
108   "Select the command buffer."
109   (interactive)
110   (let ((window (get-buffer-window riece-command-buffer)))
111     (if window
112         (select-window window))))
113
114 (defun riece-command-configure-windows ()
115   (interactive)
116   "Reconfigure windows with the current layout."
117   (riece-redisplay-buffers t))
118
119 (defun riece-command-suspend-resume ()
120   (interactive)
121   "Save or restore the current window configuration."
122   (let ((entry (assq 'riece-window-configuration (frame-parameters))))
123     (modify-frame-parameters (selected-frame)
124                              (list (cons 'riece-window-configuration
125                                          (current-window-configuration))))
126     (if (cdr entry)
127         (set-window-configuration (cdr entry))
128       (delete-other-windows))
129     (message
130      (substitute-command-keys
131       "\\[riece-command-suspend-resume] to get back the last windows"))))
132
133 (defun riece-command-change-layout (name)
134   "Select a layout-name from all current available layouts and change
135 the layout to the selected layout-name."
136   (interactive (list (completing-read "Change layout: " riece-layout-alist)))
137   (setq riece-layout name
138         riece-save-variables-are-dirty t)
139   (riece-command-configure-windows))
140
141 (defun riece-command-toggle-channel-buffer-mode ()
142   (interactive)
143   (setq riece-channel-buffer-mode
144         (not riece-channel-buffer-mode)
145         riece-save-variables-are-dirty t)
146   (riece-command-configure-windows))
147
148 (defun riece-command-toggle-others-buffer-mode ()
149   (interactive)
150   (setq riece-others-buffer-mode
151         (not riece-others-buffer-mode)
152         riece-save-variables-are-dirty t)
153   (riece-command-configure-windows))
154
155 (defun riece-command-toggle-user-list-buffer-mode ()
156   (interactive)
157   (setq riece-user-list-buffer-mode
158         (not riece-user-list-buffer-mode)
159         riece-save-variables-are-dirty t)
160   (riece-command-configure-windows))
161
162 (defun riece-command-toggle-channel-list-buffer-mode ()
163   (interactive)
164   (setq riece-channel-list-buffer-mode
165         (not riece-channel-list-buffer-mode)
166         riece-save-variables-are-dirty t)
167   (riece-command-configure-windows))
168
169 (defun riece-command-finger (user &optional recurse)
170   (interactive
171    (let* ((completion-ignore-case t)
172           (user (riece-completing-read-identity
173                  "Finger user: "
174                  (riece-get-users-on-server (riece-current-server-name))
175                  nil nil nil nil nil t)))
176      (list user current-prefix-arg)))
177   (if recurse
178       (riece-send-string (format "WHOIS %s %s\r\n"
179                                  (riece-identity-prefix user)
180                                  (riece-identity-prefix user)))
181     (riece-send-string (format "WHOIS %s\r\n" (riece-identity-prefix user)))))
182
183 (defun riece-command-topic (topic)
184   (interactive
185    (progn
186      (riece-check-channel-commands-are-usable t)
187      (list (read-from-minibuffer
188             "Set topic: " (cons (or (riece-with-server-buffer
189                                      (riece-identity-server
190                                       riece-current-channel)
191                                      (riece-channel-get-topic
192                                       (riece-identity-prefix
193                                        riece-current-channel)))
194                                     "")
195                                 0)))))
196   (riece-send-string (format "TOPIC %s :%s\r\n"
197                              (riece-identity-prefix riece-current-channel)
198                              topic)
199                      riece-current-channel))
200
201 (defun riece-command-invite (user)
202   (interactive
203    (let ((completion-ignore-case t))
204      (riece-check-channel-commands-are-usable t)
205      (list (riece-completing-read-identity
206             "Invite user: "
207             (riece-get-users-on-server (riece-current-server-name))
208             nil nil nil nil nil t))))
209   (riece-send-string (format "INVITE %s :%s\r\n"
210                              (riece-identity-prefix user)
211                              (riece-identity-prefix riece-current-channel))))
212
213 (defun riece-command-kick (user &optional message)
214   (interactive
215    (let ((completion-ignore-case t))
216      (riece-check-channel-commands-are-usable t)
217      (list (completing-read
218             "Kick user: "
219             (riece-with-server-buffer
220                 (riece-identity-server riece-current-channel)
221               (riece-channel-get-users (riece-identity-prefix
222                                         riece-current-channel))))
223            (if current-prefix-arg
224                (read-string "Message: ")))))
225   (riece-send-string
226    (if message
227        (format "KICK %s %s :%s\r\n"
228                (riece-identity-prefix riece-current-channel)
229                user message)
230      (format "KICK %s %s\r\n"
231              (riece-identity-prefix riece-current-channel)
232              user))
233    riece-current-channel))
234
235 (defun riece-command-names (pattern)
236   (interactive
237    (let ((completion-ignore-case t))
238      (list (read-from-minibuffer
239             "NAMES pattern: "
240             (if (and riece-current-channel
241                      (riece-channel-p (riece-identity-prefix
242                                        riece-current-channel)))
243                 (cons (riece-identity-prefix riece-current-channel)
244                       0))))))
245   (if (or (not (equal pattern ""))
246           (yes-or-no-p "Really want to query NAMES without argument? "))
247       (riece-send-string (format "NAMES %s\r\n" pattern))))
248
249 (defun riece-command-who (pattern)
250   (interactive
251    (let ((completion-ignore-case t))
252      (list (read-from-minibuffer
253             "WHO pattern: "
254             (if (and riece-current-channel
255                      (riece-channel-p (riece-identity-prefix
256                                        riece-current-channel)))
257                 (cons (riece-identity-prefix riece-current-channel)
258                       0))))))
259   (if (or (not (equal pattern ""))
260           (yes-or-no-p "Really want to query WHO without argument? "))
261       (riece-send-string (format "WHO %s\r\n" pattern))))
262
263 (defun riece-command-list (pattern)
264   (interactive
265    (let ((completion-ignore-case t))
266      (list (read-from-minibuffer
267             "LIST pattern: "
268             (if (and riece-current-channel
269                      (riece-channel-p (riece-identity-prefix
270                                        riece-current-channel)))
271                 (cons (riece-identity-prefix riece-current-channel)
272                       0))))))
273   (if (or (not (equal pattern ""))
274           (yes-or-no-p "Really want to query LIST without argument? "))
275       (riece-send-string (format "LIST %s\r\n" pattern))))
276
277 (defun riece-command-change-mode (channel change)
278   (interactive
279    (let* ((completion-ignore-case t)
280           (channel
281            (if current-prefix-arg
282                (riece-completing-read-identity
283                 "Change mode for channel/user: "
284                 (riece-get-identities-on-server (riece-current-server-name))
285                 nil nil nil nil nil t)
286              (riece-check-channel-commands-are-usable t)
287              riece-current-channel))
288           (riece-overriding-server-name (riece-identity-server channel))
289           (riece-temp-minibuffer-message
290            (concat "[Available modes: "
291                    (riece-with-server-buffer (riece-identity-server channel)
292                      (if (riece-channel-p (riece-identity-prefix channel))
293                          (if riece-supported-channel-modes
294                              (apply #'string riece-supported-channel-modes))
295                        (if riece-supported-user-modes
296                            (apply #'string riece-supported-user-modes))))
297                    "]")))
298      (list channel
299            (read-from-minibuffer
300             (concat (riece-concat-channel-modes
301                      channel "Mode (? for help)") ": ")
302             nil riece-minibuffer-map))))
303   (if (equal change "")
304       (riece-send-string (format "MODE %s\r\n"
305                                  (riece-identity-prefix channel)))
306     (riece-send-string (format "MODE %s %s\r\n"
307                                (riece-identity-prefix channel)
308                                change))))
309
310 (defun riece-command-set-operators (users &optional arg)
311   (interactive
312    (progn
313      (riece-check-channel-commands-are-usable t)
314      (let ((completion-ignore-case t))
315        (list (riece-completing-read-multiple
316               (if current-prefix-arg
317                   "Unset +o for users"
318                 "Set +o for users")
319               (riece-with-server-buffer
320                   (riece-identity-server riece-current-channel)
321                 (riece-channel-get-users (riece-identity-prefix
322                                          riece-current-channel)))
323               (if current-prefix-arg
324                   (lambda (user)
325                     (memq ?o (cdr user)))
326                 (lambda (user)
327                   (not (memq ?o (cdr user))))))
328              current-prefix-arg))))
329   (let (group)
330     (while users
331       (setq group (cons (car users) group)
332             users (cdr users))
333       (when (or (= (length group) 3)
334                 (null users))
335         (riece-send-string
336          (format "MODE %s %c%s %s\r\n"
337                  (riece-identity-prefix riece-current-channel)
338                  (if current-prefix-arg
339                      ?-
340                    ?+)
341                  (make-string (length group) ?o)
342                  (mapconcat #'identity (nreverse group) " ")))
343         (setq group nil)))))
344
345 (defun riece-command-set-speakers (users &optional arg)
346   (interactive
347    (progn
348      (riece-check-channel-commands-are-usable t)
349      (let ((completion-ignore-case t))
350        (list (riece-completing-read-multiple
351               (if current-prefix-arg
352                   "Unset +v for users"
353                 "Set +v for users")
354               (riece-with-server-buffer
355                   (riece-identity-server riece-current-channel)
356                 (riece-channel-get-users (riece-identity-prefix
357                                           riece-current-channel)))
358               (if current-prefix-arg
359                   (lambda (user)
360                     (memq ?v (cdr user)))
361                 (lambda (user)
362                   (not (memq ?v (cdr user))))))
363              current-prefix-arg))))
364   (let (group)
365     (while users
366       (setq group (cons (car users) group)
367             users (cdr users))
368       (when (or (= (length group) 3)
369                 (null users))
370         (riece-send-string
371          (format "MODE %s %c%s %s\r\n"
372                  (riece-identity-prefix riece-current-channel)
373                  (if current-prefix-arg
374                      ?-
375                    ?+)
376                  (make-string (length group) ?v)
377                  (mapconcat #'identity (nreverse group) " ")))
378         (setq group nil)))))
379
380 (defun riece-command-send-message (message notice)
381   "Send MESSAGE to the current channel."
382   (run-hooks 'riece-command-send-message-hook)
383   (if (equal message "")
384       (error "No text to send"))
385   (riece-check-channel-commands-are-usable)
386   (if notice
387       (progn
388         (riece-send-string
389          (format "NOTICE %s :%s\r\n"
390                  (riece-identity-prefix riece-current-channel)
391                  message)
392          riece-current-channel)
393         (riece-display-message
394          (riece-make-message (riece-current-nickname) riece-current-channel
395                              message 'notice t)))
396     (riece-send-string
397      (format "PRIVMSG %s :%s\r\n"
398              (riece-identity-prefix riece-current-channel)
399              message)
400      riece-current-channel)
401     (riece-display-message
402      (riece-make-message (riece-current-nickname) riece-current-channel
403                          message nil t))))
404
405 (defun riece-command-enter-message ()
406   "Send the current line to the current channel."
407   (interactive)
408   (riece-command-send-message (buffer-substring
409                                (riece-line-beginning-position)
410                                (riece-line-end-position))
411                               nil)
412   (let ((next-line-add-newlines t))
413     (next-line 1)))
414
415 (defun riece-command-enter-message-as-notice ()
416   "Send the current line to the current channel as NOTICE."
417   (interactive)
418   (riece-command-send-message (buffer-substring
419                                (riece-line-beginning-position)
420                                (riece-line-end-position))
421                               t)
422   (let ((next-line-add-newlines t))
423     (next-line 1)))
424
425 (defun riece-command-enter-message-to-user (user)
426   "Send the current line to USER."
427   (interactive
428    (if (and (bolp) (eolp))
429        (error "No text to send")
430      (let ((completion-ignore-case t))
431        (list (riece-completing-read-identity
432               "Message to user: "
433               (riece-get-users-on-server (riece-current-server-name))
434               nil nil nil nil nil t)))))
435   (let ((text (buffer-substring
436                (riece-line-beginning-position)
437                (riece-line-end-position))))
438     (riece-send-string
439      (format "PRIVMSG %s :%s\r\n" (riece-identity-prefix user) text)
440      user)
441     (riece-display-message
442      (riece-make-message (riece-current-nickname) user text nil t)))
443   (let ((next-line-add-newlines t))
444     (next-line 1)))
445
446 (defun riece-command-join-channel (target key)
447   (unless (riece-server-opened (riece-identity-server target))
448     (error "%s" (substitute-command-keys
449                  "Type \\[riece-command-open-server] to open server.")))
450   (riece-send-string (if key
451                          (format "JOIN %s :%s\r\n"
452                                  (riece-identity-prefix target)
453                                  key)
454                        (format "JOIN %s\r\n"
455                                (riece-identity-prefix target)))
456                      target))
457
458 (defun riece-command-join-partner (target)
459   (let ((pointer (riece-identity-member target riece-current-channels)))
460     (if pointer
461         (riece-command-switch-to-channel (car pointer))
462       (riece-join-channel target)
463       (riece-switch-to-channel target))))
464
465 (defun riece-command-join (target)
466   (interactive
467    (let ((completion-ignore-case t))
468      (list
469       (if riece-join-channel-candidate
470           (let ((default (riece-format-identity
471                           riece-join-channel-candidate)))
472             (riece-completing-read-identity
473              (format "Join channel/user (default %s): " default)
474              (riece-get-identities-on-server (riece-current-server-name))
475              nil nil nil nil default))
476         (riece-completing-read-identity
477          "Join channel/user: "
478          (riece-get-identities-on-server (riece-current-server-name)))))))
479   (let ((pointer (riece-identity-member target riece-current-channels)))
480     (if pointer
481         (riece-command-switch-to-channel (car pointer))
482       (if (riece-channel-p (riece-identity-prefix target))
483           (riece-command-join-channel target nil)
484         (riece-command-join-partner target)))))
485
486 (defun riece-command-part-channel (target message)
487   (unless (riece-server-opened (riece-identity-server target))
488     (error "%s" (substitute-command-keys
489                  "Type \\[riece-command-open-server] to open server.")))
490   (riece-send-string (if message
491                          (format "PART %s :%s\r\n"
492                                  (riece-identity-prefix target)
493                                  message)
494                        (format "PART %s\r\n"
495                                (riece-identity-prefix target)))
496                      target))
497
498 (defun riece-command-part (target &optional message)
499   (interactive
500    (progn
501      (riece-check-channel-commands-are-usable)
502      (let* ((completion-ignore-case t)
503             (target
504              (riece-completing-read-identity
505               (format "Part from channel/user (default %s): "
506                       (riece-format-identity riece-current-channel))
507               riece-current-channels nil nil nil nil
508               (riece-format-identity riece-current-channel)))
509             (message
510              (if current-prefix-arg
511                  (read-string "Message: ")
512                riece-part-message)))
513        (list target message))))
514   (if (riece-identity-member target riece-current-channels)
515       (if (riece-channel-p (riece-identity-prefix target))
516           (riece-command-part-channel target message)
517         (riece-part-channel target))
518     (error "You are not talking with %s" target)))
519
520 (defun riece-command-change-nickname (nickname)
521   "Change your nickname to NICK."
522   (interactive "sEnter your nickname: ")
523   (riece-send-string (format "NICK %s\r\n" nickname)))
524
525 (defun riece-command-scroll-down (lines)
526   "Scroll LINES down dialogue buffer from command buffer."
527   (interactive "P")
528   (let ((buffer (if (and riece-channel-buffer-mode
529                          riece-current-channel)
530                     riece-channel-buffer
531                   riece-dialogue-buffer)))
532     (if (get-buffer-window buffer)
533         (condition-case nil
534             (let ((other-window-scroll-buffer buffer))
535               (scroll-other-window-down lines))
536           (beginning-of-buffer
537            (message "Beginning of buffer"))))))
538
539 (defun riece-command-scroll-up (lines)
540   "Scroll LINES up dialogue buffer from command buffer."
541   (interactive "P")
542   (let ((buffer (if (and riece-channel-buffer-mode
543                          riece-current-channel)
544                     riece-channel-buffer
545                   riece-dialogue-buffer)))
546     (if (get-buffer-window buffer)
547         (condition-case nil
548             (let ((other-window-scroll-buffer buffer))
549               (scroll-other-window lines))
550           (end-of-buffer
551            (message "End of buffer"))))))
552
553 (defun riece-command-user-list-scroll-down (lines)
554   "Scroll LINES down user list buffer from command buffer."
555   (interactive "P")
556   (if (get-buffer-window riece-user-list-buffer)
557       (condition-case nil
558           (let ((other-window-scroll-buffer riece-user-list-buffer))
559             (scroll-other-window-down lines))
560         (beginning-of-buffer
561          (message "Beginning of buffer")))))
562
563 (defun riece-command-user-list-scroll-up (lines)
564   "Scroll LINES up user list buffer from command buffer."
565   (interactive "P")
566   (if (get-buffer-window riece-user-list-buffer)
567       (condition-case nil
568           (let ((other-window-scroll-buffer riece-user-list-buffer))
569             (scroll-other-window lines))
570         (end-of-buffer
571          (message "End of buffer")))))
572
573 (defun riece-command-toggle-away (&optional message)
574   "Mark yourself as being away."
575   (interactive
576    (if (and (not (riece-with-server-buffer (riece-identity-server
577                                             (riece-current-nickname))
578                    (riece-user-get-away (riece-identity-prefix
579                                          (riece-current-nickname)))))
580             current-prefix-arg)
581        (list (read-from-minibuffer
582               "Away message: " (cons (or riece-away-message "") 0)))))
583   (if (riece-with-server-buffer (riece-identity-server
584                                  (riece-current-nickname))
585         (riece-user-get-away (riece-identity-prefix
586                               (riece-current-nickname))))
587       (riece-send-string "AWAY\r\n")
588     (riece-send-string (format "AWAY :%s\r\n" (or message
589                                                   riece-away-message)))))
590
591 (defun riece-command-toggle-freeze (&optional arg)
592   "Prevent automatic scrolling of the dialogue window.
593 If prefix argument ARG is non-nil, toggle frozen status."
594   (interactive "P")
595   (with-current-buffer (if (eq (derived-mode-class major-mode)
596                                'riece-dialogue-mode)
597                            (current-buffer)
598                          (if (and riece-channel-buffer-mode
599                                   riece-channel-buffer)
600                              riece-channel-buffer
601                            riece-dialogue-buffer))
602     (setq riece-freeze (if arg
603                            (< 0 (prefix-numeric-value arg))
604                          (not riece-freeze)))
605     (riece-emit-signal 'buffer-freeze-changed
606                        (current-buffer) riece-freeze)))
607
608 (defun riece-command-toggle-own-freeze (&optional arg)
609   "Prevent automatic scrolling of the dialogue window.
610 The difference from `riece-command-freeze' is that your messages are hidden.
611 If prefix argument ARG is non-nil, toggle frozen status."
612   (interactive "P")
613   (with-current-buffer (if (eq (derived-mode-class major-mode)
614                                'riece-dialogue-mode)
615                            (current-buffer)
616                          (if (and riece-channel-buffer-mode
617                                   riece-channel-buffer)
618                              riece-channel-buffer
619                            riece-dialogue-buffer))
620     (if (if arg
621             (< 0 (prefix-numeric-value arg))
622           (not (eq riece-freeze 'own)))
623         (setq riece-freeze 'own)
624       (setq riece-freeze nil))
625     (riece-emit-signal 'buffer-freeze-changed
626                        (current-buffer) riece-freeze)))
627
628 (eval-when-compile
629   (autoload 'riece-exit "riece"))
630 (defun riece-command-quit (&optional arg)
631   "Quit IRC."
632   (interactive "P")
633   (if (null riece-server-process-alist)
634       (progn
635         (message "No server process")
636         (ding))
637     (if (y-or-n-p (riece-mcat "Really quit IRC? "))
638         (let ((message
639                (if arg
640                    (read-string "Message: ")
641                  riece-quit-message))
642               (alist riece-server-process-alist))
643           (while alist
644             (riece-quit-server-process (cdr (car alist)) message)
645             (setq alist (cdr alist)))))))
646
647 (defun riece-command-raw (command)
648   "Enter raw IRC command, which is sent to the server."
649   (interactive "sIRC command: ")
650   (riece-send-string (concat command "\r\n")))
651
652 (defun riece-command-beginning-of-buffer ()
653   "Scroll channel buffer to the beginning."
654   (interactive)
655   (let (buffer window)
656     (setq buffer (if riece-channel-buffer-mode
657                      riece-channel-buffer
658                    riece-dialogue-buffer))
659     (or (setq window (get-buffer-window buffer))
660         (setq window (get-buffer-window riece-dialogue-buffer)
661               buffer riece-dialogue-buffer))
662     (when window
663       (save-selected-window
664         (select-window window)
665         (goto-char (point-min))))))
666
667 (defun riece-command-end-of-buffer ()
668   "Scroll channel buffer to the end."
669   (interactive)
670   (let (buffer window)
671     (setq buffer (if riece-channel-buffer-mode
672                      riece-channel-buffer
673                    riece-dialogue-buffer))
674     (or (setq window (get-buffer-window buffer))
675         (setq window (get-buffer-window riece-dialogue-buffer)
676               buffer riece-dialogue-buffer))
677     (when window
678       (save-selected-window
679         (select-window window)
680         (goto-char (point-max))))))
681
682 (defun riece-command-copy-region (start end)
683   "Move current region between START and END to `kill-ring'."
684   (interactive "r")
685   (kill-new (buffer-substring-no-properties start end)))
686
687 (defun riece-command-complete-user ()
688   "Complete a user name in the current buffer."
689   (interactive)
690   (let* ((completion-ignore-case t)
691          (table (mapcar (lambda (user)
692                           (list (riece-format-identity user t)))
693                         (riece-get-users-on-server
694                          (riece-current-server-name))))
695          (current (or (current-word) ""))
696          (completion (try-completion current table))
697          (all (all-completions current table)))
698     (if (eq completion t)
699         nil
700       (if (null completion)
701           (message "Can't find completion for \"%s\"" current)
702         (if (equal current completion)
703             (with-output-to-temp-buffer "*Help*"
704               (display-completion-list all))
705           (re-search-forward "\\>" nil t)
706           (delete-region (point) (- (point) (length current)))
707           (insert completion))))))
708
709 (defun riece-command-open-server (server-name)
710   (interactive
711    (list (completing-read "Open server: " riece-server-alist)))
712   (if (riece-server-process server-name)
713       (error "%s is already opened" server-name))
714   (riece-open-server
715    (riece-server-name-to-server server-name)
716    server-name))
717
718 (defun riece-command-close-server (server-name &optional message)
719   (interactive
720    (list (completing-read "Close server: " riece-server-process-alist)
721          (if current-prefix-arg
722              (read-string "Message: ")
723            riece-quit-message)))
724   (let ((process (riece-server-process server-name)))
725     (unless process
726       (error "%s is not opened" server-name))
727     (riece-quit-server-process process message)))
728
729 (defun riece-command-universal-server-name-argument ()
730   (interactive)
731   (let* ((riece-overriding-server-name
732           (completing-read "Server: " riece-server-process-alist))
733          (command
734           (key-binding (read-key-sequence
735                         (format "Command to execute on \"%s\":"
736                                 riece-overriding-server-name)))))
737     (message "")
738     (call-interactively command)))
739
740 (eval-when-compile
741   (autoload 'riece-save-variables-files "riece"))
742 (defun riece-command-save-variables ()
743   "Save `riece-variables-file'."
744   (interactive)
745   (if (or riece-save-variables-are-dirty
746           (y-or-n-p "No changes made.  Save anyway? "))
747       (riece-save-variables-files)))
748
749 (provide 'riece-commands)
750
751 ;;; riece-commands.el ends here