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