84bffe8ef17897944ee7e7e62da1b3c6bbe2c358
[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   (unless (riece-server-opened (riece-identity-server target))
447     (error "%s" (substitute-command-keys
448                  "Type \\[riece-command-open-server] to open server.")))
449   (riece-send-string (if key
450                          (format "JOIN %s :%s\r\n"
451                                  (riece-identity-prefix target)
452                                  key)
453                        (format "JOIN %s\r\n"
454                                (riece-identity-prefix target)))
455                      target))
456
457 (defun riece-command-join-partner (target)
458   (let ((pointer (riece-identity-member target riece-current-channels)))
459     (if pointer
460         (riece-command-switch-to-channel (car pointer))
461       (riece-join-channel target)
462       (riece-switch-to-channel target))))
463
464 (defun riece-command-join (target)
465   (interactive
466    (let ((completion-ignore-case t))
467      (list
468       (if riece-join-channel-candidate
469           (let ((default (riece-format-identity
470                           riece-join-channel-candidate)))
471             (riece-completing-read-identity
472              (format "Join channel/user (default %s): " default)
473              (riece-get-identities-on-server (riece-current-server-name))
474              nil nil nil nil default))
475         (riece-completing-read-identity
476          "Join channel/user: "
477          (riece-get-identities-on-server (riece-current-server-name)))))))
478   (let ((pointer (riece-identity-member target riece-current-channels)))
479     (if pointer
480         (riece-command-switch-to-channel (car pointer))
481       (if (riece-channel-p (riece-identity-prefix target))
482           (riece-command-join-channel target nil)
483         (riece-command-join-partner target)))))
484
485 (defun riece-command-part-channel (target message)
486   (unless (riece-server-opened (riece-identity-server target))
487     (error "%s" (substitute-command-keys
488                  "Type \\[riece-command-open-server] to open server.")))
489   (riece-send-string (if message
490                          (format "PART %s :%s\r\n"
491                                  (riece-identity-prefix target)
492                                  message)
493                        (format "PART %s\r\n"
494                                (riece-identity-prefix target)))
495                      target))
496
497 (defun riece-command-part (target &optional message)
498   (interactive
499    (progn
500      (riece-check-channel-commands-are-usable)
501      (let* ((completion-ignore-case t)
502             (target
503              (riece-completing-read-identity
504               (format "Part from channel/user (default %s): "
505                       (riece-format-identity riece-current-channel))
506               riece-current-channels nil nil nil nil
507               (riece-format-identity riece-current-channel)))
508             (message
509              (if current-prefix-arg
510                  (read-string "Message: ")
511                riece-part-message)))
512        (list target message))))
513   (if (riece-identity-member target riece-current-channels)
514       (if (riece-channel-p (riece-identity-prefix target))
515           (riece-command-part-channel target message)
516         (riece-part-channel target))
517     (error "You are not talking with %s" target)))
518
519 (defun riece-command-change-nickname (nickname)
520   "Change your nickname to NICK."
521   (interactive "sEnter your nickname: ")
522   (riece-send-string (format "NICK %s\r\n" nickname)))
523
524 (defun riece-command-scroll-down (lines)
525   "Scroll LINES down dialogue buffer from command buffer."
526   (interactive "P")
527   (let ((buffer (if (and riece-channel-buffer-mode
528                          riece-current-channel)
529                     riece-channel-buffer
530                   riece-dialogue-buffer)))
531     (if (get-buffer-window buffer)
532         (condition-case nil
533             (let ((other-window-scroll-buffer buffer))
534               (scroll-other-window-down lines))
535           (beginning-of-buffer
536            (message "Beginning of buffer"))))))
537
538 (defun riece-command-scroll-up (lines)
539   "Scroll LINES up dialogue buffer from command buffer."
540   (interactive "P")
541   (let ((buffer (if (and riece-channel-buffer-mode
542                          riece-current-channel)
543                     riece-channel-buffer
544                   riece-dialogue-buffer)))
545     (if (get-buffer-window buffer)
546         (condition-case nil
547             (let ((other-window-scroll-buffer buffer))
548               (scroll-other-window lines))
549           (end-of-buffer
550            (message "End of buffer"))))))
551
552 (defun riece-command-user-list-scroll-down (lines)
553   "Scroll LINES down user list buffer from command buffer."
554   (interactive "P")
555   (if (get-buffer-window riece-user-list-buffer)
556       (condition-case nil
557           (let ((other-window-scroll-buffer riece-user-list-buffer))
558             (scroll-other-window-down lines))
559         (beginning-of-buffer
560          (message "Beginning of buffer")))))
561
562 (defun riece-command-user-list-scroll-up (lines)
563   "Scroll LINES up user list buffer from command buffer."
564   (interactive "P")
565   (if (get-buffer-window riece-user-list-buffer)
566       (condition-case nil
567           (let ((other-window-scroll-buffer riece-user-list-buffer))
568             (scroll-other-window lines))
569         (end-of-buffer
570          (message "End of buffer")))))
571
572 (defun riece-command-toggle-away (&optional message)
573   "Mark yourself as being away."
574   (interactive
575    (if (and (not (riece-with-server-buffer (riece-identity-server
576                                             (riece-current-nickname))
577                    (riece-user-get-away (riece-identity-prefix
578                                          (riece-current-nickname)))))
579             current-prefix-arg)
580        (list (read-from-minibuffer
581               "Away message: " (cons (or riece-away-message "") 0)))))
582   (if (riece-with-server-buffer (riece-identity-server
583                                  (riece-current-nickname))
584         (riece-user-get-away (riece-identity-prefix
585                               (riece-current-nickname))))
586       (riece-send-string "AWAY\r\n")
587     (riece-send-string (format "AWAY :%s\r\n" (or message
588                                                   riece-away-message)))))
589
590 (defun riece-command-toggle-freeze (&optional arg)
591   "Prevent automatic scrolling of the dialogue window.
592 If prefix argument ARG is non-nil, toggle frozen status."
593   (interactive "P")
594   (with-current-buffer (if (eq (derived-mode-class major-mode)
595                                'riece-dialogue-mode)
596                            (current-buffer)
597                          (if (and riece-channel-buffer-mode
598                                   riece-channel-buffer)
599                              riece-channel-buffer
600                            riece-dialogue-buffer))
601     (setq riece-freeze (if arg
602                            (< 0 (prefix-numeric-value arg))
603                          (not riece-freeze)))
604     (riece-emit-signal 'buffer-freeze-changed
605                        (current-buffer) riece-freeze)))
606
607 (defun riece-command-toggle-own-freeze (&optional arg)
608   "Prevent automatic scrolling of the dialogue window.
609 The difference from `riece-command-freeze' is that your messages are hidden.
610 If prefix argument ARG is non-nil, toggle frozen status."
611   (interactive "P")
612   (with-current-buffer (if (eq (derived-mode-class major-mode)
613                                'riece-dialogue-mode)
614                            (current-buffer)
615                          (if (and riece-channel-buffer-mode
616                                   riece-channel-buffer)
617                              riece-channel-buffer
618                            riece-dialogue-buffer))
619     (if (if arg
620             (< 0 (prefix-numeric-value arg))
621           (not (eq riece-freeze 'own)))
622         (setq riece-freeze 'own)
623       (setq riece-freeze nil))
624     (riece-emit-signal 'buffer-freeze-changed
625                        (current-buffer) riece-freeze)))
626
627 (eval-when-compile
628   (autoload 'riece-exit "riece"))
629 (defun riece-command-quit (&optional arg)
630   "Quit IRC."
631   (interactive "P")
632   (if (null riece-server-process-alist)
633       (progn
634         (message "No server process")
635         (ding))
636     (if (y-or-n-p "Really quit IRC? ")
637         (let ((message
638                (if arg
639                    (read-string "Message: ")
640                  riece-quit-message))
641               (alist riece-server-process-alist))
642           (while alist
643             (riece-quit-server-process (cdr (car alist)) message)
644             (setq alist (cdr alist)))))))
645
646 (defun riece-command-raw (command)
647   "Enter raw IRC command, which is sent to the server."
648   (interactive "sIRC command: ")
649   (riece-send-string (concat command "\r\n")))
650
651 (defun riece-command-beginning-of-buffer ()
652   "Scroll channel buffer to the beginning."
653   (interactive)
654   (let (buffer window)
655     (setq buffer (if riece-channel-buffer-mode
656                      riece-channel-buffer
657                    riece-dialogue-buffer))
658     (or (setq window (get-buffer-window buffer))
659         (setq window (get-buffer-window riece-dialogue-buffer)
660               buffer riece-dialogue-buffer))
661     (when window
662       (save-selected-window
663         (select-window window)
664         (goto-char (point-min))))))
665
666 (defun riece-command-end-of-buffer ()
667   "Scroll channel buffer to the end."
668   (interactive)
669   (let (buffer window)
670     (setq buffer (if riece-channel-buffer-mode
671                      riece-channel-buffer
672                    riece-dialogue-buffer))
673     (or (setq window (get-buffer-window buffer))
674         (setq window (get-buffer-window riece-dialogue-buffer)
675               buffer riece-dialogue-buffer))
676     (when window
677       (save-selected-window
678         (select-window window)
679         (goto-char (point-max))))))
680
681 (defun riece-command-copy-region (start end)
682   "Move current region between START and END to `kill-ring'."
683   (interactive "r")
684   (kill-new (buffer-substring-no-properties start end)))
685
686 (defun riece-command-complete-user ()
687   "Complete a user name in the current buffer."
688   (interactive)
689   (let* ((completion-ignore-case t)
690          (table (mapcar (lambda (user)
691                           (list (riece-format-identity user t)))
692                         (riece-get-users-on-server
693                          (riece-current-server-name))))
694          (current (or (current-word) ""))
695          (completion (try-completion current table))
696          (all (all-completions current table)))
697     (if (eq completion t)
698         nil
699       (if (null completion)
700           (message "Can't find completion for \"%s\"" current)
701         (if (equal current completion)
702             (with-output-to-temp-buffer "*Help*"
703               (display-completion-list all))
704           (re-search-forward "\\>" nil t)
705           (delete-region (point) (- (point) (length current)))
706           (insert completion))))))
707
708 (defun riece-command-open-server (server-name)
709   (interactive
710    (list (completing-read "Open server: " riece-server-alist)))
711   (if (riece-server-process server-name)
712       (error "%s is already opened" server-name))
713   (riece-open-server
714    (riece-server-name-to-server server-name)
715    server-name))
716
717 (defun riece-command-close-server (server-name &optional message)
718   (interactive
719    (list (completing-read "Close server: " riece-server-process-alist)
720          (if current-prefix-arg
721              (read-string "Message: ")
722            riece-quit-message)))
723   (let ((process (riece-server-process server-name)))
724     (unless process
725       (error "%s is not opened" server-name))
726     (riece-quit-server-process process message)))
727
728 (defun riece-command-universal-server-name-argument ()
729   (interactive)
730   (let* ((riece-overriding-server-name
731           (completing-read "Server: " riece-server-process-alist))
732          (command
733           (key-binding (read-key-sequence
734                         (format "Command to execute on \"%s\":"
735                                 riece-overriding-server-name)))))
736     (message "")
737     (call-interactively command)))
738
739 (eval-when-compile
740   (autoload 'riece-save-variables-files "riece"))
741 (defun riece-command-save-variables ()
742   "Save `riece-variables-file'."
743   (interactive)
744   (if (or riece-save-variables-are-dirty
745           (y-or-n-p "No changes made.  Save anyway? "))
746       (riece-save-variables-files)))
747
748 (provide 'riece-commands)
749
750 ;;; riece-commands.el ends here