* etc/po/ja.po: Add new item.
[elisp/liece.git] / lisp / liece-commands.el
1 ;;; liece-commands.el --- Interactive commands in command buffer.
2 ;; Copyright (C) 1998-2000 Daiki Ueno
3
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
5 ;; Created: 1998-09-28
6 ;; Revised: 1999-12-24
7 ;; Keywords: IRC, liece
8
9 ;; This file is part of Liece.
10
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
15
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
25
26
27 ;;; Commentary:
28 ;; 
29
30 ;;; Code:
31
32 (eval-when-compile
33    (require 'liece-crypt)
34    (require 'liece-misc))
35
36 (require 'liece-channel)
37 (require 'liece-nick)
38 (require 'liece-coding)
39 (require 'liece-intl)
40 (require 'liece-minibuf)
41
42 (autoload 'liece-dcc-chat-send "liece-dcc")
43 (autoload 'liece-window-configuration-pop "liece-window")
44
45 (autoload 'liece-command-ctcp-version "liece-ctcp" nil t)
46 (autoload 'liece-command-ctcp-userinfo "liece-ctcp" nil t)
47 (autoload 'liece-command-ctcp-clientinfo "liece-ctcp" nil t)
48 (autoload 'liece-command-ctcp-ping "liece-ctcp" nil t)
49 (autoload 'liece-command-ctcp-time "liece-ctcp" nil t)
50 (autoload 'liece-command-ctcp-x-face "liece-ctcp" nil t)
51 (autoload 'liece-command-ctcp-comment "liece-ctcp" nil t)
52 (autoload 'liece-command-ctcp-help "liece-ctcp" nil t)
53
54 (defun liece-command-poll-names ()
55   "Handler for polling NAMES."
56   (when (liece-server-opened)
57     (setq liece-polling
58           (+ liece-polling
59              (length liece-channel-alist)))
60     (dolist (chnl liece-channel-alist)
61       (liece-send "NAMES %s" (car chnl)))))
62
63 (defun liece-command-poll-friends ()
64   "Handler for polling ISON."
65   (and liece-friends
66        (liece-server-opened)
67        (liece-send "ISON %s" (mapconcat 'identity liece-friends " "))))
68
69 (defun liece-command-find-timestamp ()
70   "Find recent timestamp in dialogue buffer."
71   (interactive)
72   (save-excursion
73     (let ((range "")
74           (regexp (concat "^\\(" liece-time-prefix-regexp "\\)?"
75                           (regexp-quote liece-timestamp-prefix))))
76       (unless (eq 'liece-dialogue-mode (derived-mode-class major-mode))
77         (set-buffer liece-dialogue-buffer)
78         (goto-char (point-max)))
79       (if (re-search-backward regexp (point-min) t)
80           (setq range (concat (buffer-substring (match-end 0)
81                                                 (line-end-position))
82                               "   ---   ")))
83       (if (re-search-forward regexp (point-max) t)
84           (setq range (concat range (buffer-substring (match-end 0)
85                                                       (line-end-position)))))
86       (liece-message range))))
87
88 (defun liece-command-keepalive ()
89   "Handler for polling server connection."
90   (if (not (liece-server-opened))
91       (liece)
92     (liece-ping-if-idle)))
93
94 (defvar liece-last-timestamp-time nil "Last time timestamp was inserted.")
95 (defvar liece-last-timestamp-no-cons-p nil "Last timestamp was no-cons.")
96
97 (defun liece-command-timestamp-if-interval-expired (&optional no-cons)
98   "If interval timer has expired, insert timestamp into dialogue buffer.
99 And save variables into `liece-variable-file' if there are variables to save.
100 Optional argument NO-CONS specifies timestamp format is cons cell."
101   (interactive)
102   (when (and (not (and no-cons
103                        liece-last-timestamp-no-cons-p))
104              (numberp liece-timestamp-interval)
105              (> liece-timestamp-interval 0)
106              (or (null liece-last-timestamp-time)
107                  (> (liece-time-difference liece-last-timestamp-time
108                                             (current-time))
109                     liece-timestamp-interval)))
110     (if liece-save-variables-are-dirty
111         (liece-command-save-vars))
112     (liece-command-timestamp)
113     (setq liece-last-timestamp-no-cons-p no-cons)))
114
115 (defun liece-command-timestamp ()
116   "Insert timestamp into dialogue buffer."
117   (interactive)
118   (let ((stamp (format liece-timestamp-format
119                        (funcall liece-format-time-function (current-time))))
120         (liece-timestamp-interval 0))
121     (liece-insert liece-D-buffer (concat stamp "\n"))
122     (setq liece-last-timestamp-time (current-time))))
123
124 (defun liece-command-point-back-to-command-buffer ()
125   "Set point back to command buffer."
126   (interactive)
127   (let ((win (liece-get-buffer-window liece-command-buffer)))
128     (if win (select-window win))))
129
130 (defun liece-command-send-message
131   (message &optional arg key)
132   "Send MESSAGE to current chat partner of current channel.
133 If argument ARG is non-nil message will be encrypted with KEY."
134   (when arg
135     (setq liece-crypt-mode-active (not liece-crypt-mode-active)))
136   (if (string-equal message "")
137       (progn (liece-message (_ "No text to send")) nil)
138     (let ((addr (if (eq liece-command-buffer-mode 'chat)
139                     liece-current-chat-partner
140                   liece-current-channel))
141           repr method name target
142           (msg message))
143       (with-liece-encryption (msg addr arg key)
144         (cond
145          ((eq liece-command-buffer-mode 'chat)
146           (if (null liece-current-chat-partner)
147               (message
148                (substitute-command-keys
149                 "Type \\[liece-command-join] to start private conversation"))
150             (setq repr (liece-channel-parse-representation
151                         liece-current-chat-partner)
152                   method (aref repr 0)
153                   name (aref repr 1)
154                   target (aref repr 2))
155             (cond ((eq method 'dcc)
156                    (liece-dcc-chat-send target msg))
157                   ((eq method 'irc)
158                    (liece-send "PRIVMSG %s :%s"
159                                 liece-current-chat-partner msg)))
160             (liece-own-private-message message)))
161          ((not liece-current-channel)
162           (beep t)
163           (message (substitute-command-keys
164                     "Type \\[liece-command-join] to join a channel")))
165          (t
166           (liece-send
167            "PRIVMSG %s :%s"
168            (liece-channel-real liece-current-channel) msg)
169           (liece-own-channel-message message))))
170       t)))
171
172 (defun liece-enter-message (&optional arg key)
173   "Enter the current line as an entry in the IRC dialogue.
174 If argument ARG is non-nil message will be encrypted with KEY."
175   (beginning-of-line)
176   (if (liece-command-send-message
177        (buffer-substring (point)(progn (end-of-line) (point)))
178        arg key)
179       (liece-next-line 1)))
180
181 (defun liece-command-enter-message (&optional arg key)
182   "Enter the current line as an entry in the IRC dialogue.
183 If the prefix argument ARG is non-nil, message will be encrypted with KEY."
184   (interactive
185    (let ((completion-ignore-case t))
186      (and (if current-prefix-arg
187               (not liece-crypt-mode-active)
188             liece-crypt-mode-active)
189           (list
190            'encrypt
191            (completing-read
192             (_ "Encrypt message with key [RET for none]: ")
193             (cons (cons "" nil)
194                   liece-crypt-encryption-keys))))))
195   (liece-enter-message arg (if (string-equal key "") nil key)))
196
197 (defun liece-dialogue-enter-message ()
198   "Ask for a line as an entry in the IRC dialogue on the current channel."
199   (interactive)
200   (let (message)
201     (while (not (string-equal (setq message (read-string "> ")) ""))
202       (liece-command-send-message message))))
203
204 (defun liece-command-inline ()
205   "Send current line as a message to the IRC server."
206   (interactive)
207   (beginning-of-line)
208   (liece-send (buffer-substring (point)(progn (end-of-line) (point))))
209   (liece-next-line 1))
210
211 (defun liece-command-join-channel (join-channel-var key)
212   "Join a JOIN-CHANNEL-VAR with KEY."
213   (let ((nicks liece-nick-alist) nick)
214     (while (and nicks
215                 (not (and
216                       (car nick)
217                       (liece-channel-equal join-channel-var (car nick)))))
218       (setq nick (pop nicks)))
219     (when nicks
220       (setq join-channel-var
221             (or (car (get (intern (car nick) liece-obarray) 'chnl))
222                 join-channel-var)))
223     (if (liece-channel-member join-channel-var liece-current-channels)
224         (progn
225           (setq liece-current-channel join-channel-var)
226           (liece-switch-to-channel liece-current-channel)
227           (liece-channel-change))
228       (liece-send "JOIN %s %s" (liece-channel-real join-channel-var) key))))
229
230 (defun liece-command-join-partner (join-channel-var)
231   "Join a JOIN-CHANNEL-VAR."
232   (if (liece-channel-member join-channel-var liece-current-chat-partners)
233       (progn
234         (setq liece-current-chat-partner join-channel-var)
235         (liece-switch-to-channel liece-current-chat-partner))
236     (setq liece-current-chat-partner join-channel-var)
237     (liece-channel-join liece-current-chat-partner))
238   (liece-channel-change))
239
240 (defun liece-command-join (join-channel-var &optional key)
241   "Join a JOIN-CHANNEL-VAR with KEY.
242 If user nickname is given join the same set of channels as the specified user.
243 If command-buffer is in chat-mode, start private conversation
244 with specified user."
245   (interactive
246    (let (join-channel-var key (completion-ignore-case t))
247      (setq join-channel-var
248            (if (numberp current-prefix-arg)
249                current-prefix-arg
250              (liece-channel-virtual
251               (if (eq liece-command-buffer-mode 'chat)
252                   (liece-minibuffer-completing-default-read
253                    (_ "Start private conversation with: ")
254                    liece-nick-alist
255                    nil nil liece-privmsg-partner)
256                 (liece-minibuffer-completing-default-read
257                  (_ "Join channel: ")
258                  (append liece-channel-alist liece-nick-alist)
259                  nil nil liece-default-channel-candidate)))))
260      (if (and current-prefix-arg
261               (not (numberp current-prefix-arg)))
262          (setq key
263                (if (eq current-prefix-arg '-)
264                    (read-string
265                     (format (_ "Key for channel %s: ") join-channel-var))
266                  (let ((passwd-echo ?*))
267                    (read-passwd
268                     (format (_ "Key for channel %s: ") join-channel-var))))))
269      (list join-channel-var key)))
270   (let ((real-chnl (liece-channel-real join-channel-var)))
271     (if (numberp join-channel-var)
272         (liece-switch-to-channel-no join-channel-var)
273       (setq liece-default-channel-candidate nil)
274       (if (liece-channel-p real-chnl)
275           (liece-toggle-command-buffer-mode 'channel)
276         (liece-toggle-command-buffer-mode 'chat))
277       (if (eq liece-command-buffer-mode 'chat)
278           (liece-command-join-partner join-channel-var)
279         (if (null key)
280             (setq key (get (intern join-channel-var liece-obarray) 'key)))
281         (put (intern join-channel-var liece-obarray) 'key key)
282         (if (null key)
283             (setq key ""))
284         (liece-command-join-channel join-channel-var key))
285       (force-mode-line-update))))
286
287 (defun liece-command-part (part-channel-var &optional part-msg)
288   "Part a PART-CHANNEL-VAR with PART-MSG."
289   (interactive
290    (let (part-channel-var
291          (completion-ignore-case t)
292          (part-msg "bye..."))
293      (setq part-channel-var
294            (liece-channel-virtual
295             (if (eq liece-command-buffer-mode 'chat)
296                 (liece-minibuffer-completing-default-read
297                  (_ "End private conversation with: ")
298                  (list-to-alist liece-current-chat-partners)
299                  nil nil liece-current-chat-partner)
300               (liece-minibuffer-completing-default-read
301                (_ "Part channel: ")
302                (list-to-alist liece-current-channels)
303                nil nil liece-current-channel))))
304      (when current-prefix-arg
305        (setq part-msg (read-string (_ "Part Message: "))))
306      (list part-channel-var part-msg)))
307   (let ((real-chnl (liece-channel-real part-channel-var)))
308     (if (liece-channel-p real-chnl)
309         (progn
310           (if (liece-channel-member part-channel-var liece-current-channels)
311               (setq liece-current-channel part-channel-var))
312           (liece-send "PART %s :%s" real-chnl part-msg)
313           (setq liece-default-channel-candidate part-channel-var))
314       (setq liece-current-chat-partners
315             (liece-channel-remove part-channel-var
316                                   liece-current-chat-partners)
317             liece-current-chat-partner
318             (car liece-current-chat-partners))
319       (liece-set-channel-indicator)
320       (liece-set-crypt-indicator)
321       (liece-channel-part part-channel-var))))
322
323 (defun liece-command-kill (kill-nickname-var &optional timeout silent)
324   "Ignore messages from KILL-NICKNAME-VAR.
325 Username can be given as case insensitive regular expression of form
326 \".*@.*\.sub.domain\".
327 If already ignoring him/her, toggle.
328 If `liece-variables-file' is defined and the file is writable,
329 settings are updated automatically for future sessions.
330 Optional argument TIMEOUT says expiration.
331 If SILENT is non-nil, don't notify current status."
332   (interactive
333    (let (kill-nickname-var timeout (completion-ignore-case t))
334      (setq kill-nickname-var (completing-read
335                               (_ "Ignore nickname or regexp: ")
336                               (append liece-nick-alist
337                                       liece-kill-nickname)))
338      (or (string-equal "" kill-nickname-var)
339          (string-assoc-ignore-case kill-nickname-var liece-kill-nickname)
340          (setq timeout (string-to-int (read-from-minibuffer
341                                        (_ "Timeout [RET for none]: ")))))
342      (list kill-nickname-var timeout)))
343   ;; empty, just list them
344   (if (string-equal "" kill-nickname-var)
345       (with-current-buffer liece-dialogue-buffer
346         (let ((ignores liece-kill-nickname) (time (current-time))
347               buffer-read-only expire expiretime)
348           (goto-char (point-max))
349           (liece-insert-info liece-D-buffer (_ "Currently ignoring:"))
350           (dolist (ignore ignores)
351             (setq expiretime (if (cdr ignore)
352                                  (/ (liece-time-difference time (cdr ignore))
353                                     60))
354                   expire (cond ((not expiretime) "")
355                                ((>= expiretime 0)
356                                 (format (_ " (%d min)") expiretime))
357                                ((< expiretime 0)
358                                 (_ " expired"))))
359             (liece-insert liece-D-buffer
360                            (concat " " (car ignore) expire "\n")))))
361     ;; else not empty, check if exists
362     (let ((ignore
363            (string-assoc-ignore-case
364             kill-nickname-var liece-kill-nickname)))
365       (if ignore
366           (when (setq ignore (string-assoc-ignore-case
367                               (car ignore) liece-kill-nickname))
368             (setq liece-kill-nickname
369                   (delq ignore liece-kill-nickname))
370             (liece-insert-info liece-D-buffer
371                                (format (_ "No longer ignoring: %s.\n")
372                                        (car ignore))))
373         ;; did not find, add to ignored ones
374         (let ((expire-time (if (> timeout 0)
375                                (liece-time-add (current-time)
376                                                 (* timeout 60)))))
377           (and silent (> timeout 0)
378                (setcar (cdr (cdr expire-time)) -1))
379           (setq liece-kill-nickname
380                 (cons (cons kill-nickname-var expire-time)
381                       liece-kill-nickname))
382           (unless silent
383             (liece-insert-info liece-D-buffer
384                                 (format (_ "Ignoring %s") kill-nickname-var))
385             (liece-insert-info liece-D-buffer
386                                 (if (> timeout 0)
387                                     (format " for %d minutes.\n" timeout)
388                                   (format ".\n")))))))
389     (setq liece-save-variables-are-dirty t)))
390
391 (defun liece-command-kick (nick &optional msg)
392   "Kick this NICK out with MSG."
393   (interactive
394    (let ((completion-ignore-case t)
395          (nicks (liece-channel-get-nicks)) nick msg)
396      (setq nick (completing-read
397                  (_ "Kick out nickname: ")
398                  (list-to-alist nicks)))
399      (if current-prefix-arg
400          (setq msg (concat " :" (read-string (_ "Kick Message: ")))))
401      (list nick msg)))
402   (liece-send "KICK %s %s%s"
403                (liece-channel-real liece-current-channel)
404                nick (or msg "")))
405
406 (defun liece-command-ban (ban)
407   "BAN this user out."
408   (interactive
409    (let* ((completion-ignore-case t)
410           (nicks (liece-channel-get-nicks))
411           (uahs (mapcar
412                  (function
413                   (lambda (nick)
414                     (list
415                      (concat nick "!" (liece-nick-get-user-at-host nick)))))
416                  nicks))
417           ban nick msg)
418      (setq ban (liece-minibuffer-completing-default-read
419                 (_ "Ban pattern: ") uahs nil nil
420                 (concat nick "!" (liece-nick-get-user-at-host nick))))
421      (list ban)))
422   (liece-send "MODE %s :+b %s"
423                (liece-channel-real liece-current-channel) ban))
424    
425 (defun liece-command-ban-kick (ban nick &optional msg)
426   "BAN kick this NICK out with MSG."
427   (interactive
428    (let* ((completion-ignore-case t)
429           (nicks (liece-channel-get-nicks))
430           (uahs (mapcar
431                  (function
432                   (lambda (nick)
433                     (list
434                      (concat nick "!" (liece-nick-get-user-at-host nick)))))
435                  nicks))
436           ban nick msg)
437      (setq nick (completing-read (_ "Kick out nickname: ")
438                                  (list-to-alist nicks))
439            ban (liece-minibuffer-completing-default-read
440                 (_ "Ban pattern: ") uahs nil nil
441                 (concat nick "!" (liece-nick-get-user-at-host nick))))
442      (if current-prefix-arg
443          (setq msg (concat " :" (read-string (_ "Kick Message: "))))
444        (setq msg ""))
445      (list ban nick msg)))
446   (liece-send "MODE %s :+b %s"
447                (liece-channel-real liece-current-channel) ban)
448   (liece-send "KICK %s %s%s"
449                (liece-channel-real liece-current-channel)
450                nick (or msg "")))
451
452 (defun liece-command-list (&optional channel)
453   "List the given CHANNEL and its topics.
454 If you enter only Control-U as argument, list the current channel.
455 With - as argument, list all channels."
456   (interactive
457    (if (or current-prefix-arg (null liece-current-channel))
458        (if (eq current-prefix-arg '-)
459            (list current-prefix-arg))
460      (let ((completion-ignore-case t) channel)
461        (setq channel (liece-minibuffer-completing-default-read
462                       (_ "LIST channel: ")
463                       liece-channel-alist nil nil liece-current-channel))
464        (unless (string-equal "" channel)
465          (list channel)))))
466   
467   (cond ((not channel)
468          (if liece-current-channel
469              (liece-send "LIST %s"
470                           (liece-channel-real liece-current-channel))))
471         ((and (eq channel '-)
472               (y-or-n-p (_ "Do you really query LIST without argument?")))
473          (liece-send "LIST"))
474         ((not (string-equal channel ""))
475          (liece-send "LIST %s" (liece-channel-real channel))
476          )))
477
478 (defun liece-command-lusers ()
479   "List the number of users and servers."
480   (interactive)
481   (liece-send "LUSERS"))
482
483 (defun liece-command-modec (chnl change)
484   "Send a MODE command to this CHNL.
485 Argument CHANGE ."
486   (interactive
487    (let ((completion-ignore-case t)
488          (chnl liece-current-channel)
489          liece-minibuffer-complete-function prompt)
490      (if current-prefix-arg
491          (setq chnl
492                (liece-minibuffer-completing-default-read
493                 (_ "Channel/User: ")
494                 (append liece-channel-alist liece-nick-alist)
495                 nil nil liece-current-channel)))
496      (cond
497       ((liece-channel-p (liece-channel-real chnl))
498        (setq prompt (format
499                      (_ "Mode for channel %s [%s]: ")
500                      chnl (or (liece-channel-get-modes chnl) ""))
501              liece-minibuffer-complete-function
502              (function liece-minibuffer-complete-channel-modes)))
503       (t
504        (setq prompt (format
505                      (_ "Mode for user %s [%s]: ")
506                      chnl (or (liece-nick-get-modes chnl) ""))
507              liece-minibuffer-complete-function
508              (function liece-minibuffer-complete-user-modes))))
509      (list chnl (read-from-minibuffer prompt nil liece-minibuffer-map))))
510   (liece-send "MODE %s %s" (liece-channel-real chnl) change))
511
512 (defun liece-command-mode+o (opers)
513   "Send a MODE +o OPERS command."
514   (interactive
515    (let ((opers (liece-channel-get-operators)) oper
516          (nicks (liece-channel-get-nicks))
517          (completion-ignore-case t))
518      (setq nicks (filter-elements
519                   nick nicks
520                   (not (liece-nick-member nick opers)))
521            opers (liece-minibuffer-completing-sequential-read
522                   (_ "Set Operator for") 0
523                   (list-to-alist nicks)))
524      (list opers)))
525   (let (ops)
526     (dolist (oper opers)
527       (push oper ops)
528       (when (= (length ops) liece-compress-mode-length)
529         (liece-send "MODE %s +%s %s"
530                      (liece-channel-real liece-current-channel)
531                      (string-times "o" liece-compress-mode-length)
532                      (string-join ops " "))
533         (setq ops nil)))
534     (if ops
535         (liece-send "MODE %s +%s %s"
536                      (liece-channel-real liece-current-channel)
537                      (string-times "o" (length ops))
538                      (string-join ops " ")))))
539
540 (defun liece-command-mode-o (opers)
541   "Send a MODE -o OPERS command."
542   (interactive
543    (let ((completion-ignore-case t)
544          (opers (liece-channel-get-operators)) oper nicks)
545      (setq nicks (liece-minibuffer-completing-sequential-read
546                   (_ "Unset Operator for") 0
547                   (list-to-alist opers)))
548      (list nicks)))
549   (let (ops)
550     (dolist (oper opers)
551       (push oper ops)
552       (when (= (length ops) liece-compress-mode-length)
553         (liece-send "MODE %s -%s %s"
554                      (liece-channel-real liece-current-channel)
555                      (string-times "o" liece-compress-mode-length)
556                      (string-join ops " "))
557         (setq ops nil)))
558     (if ops
559         (liece-send "MODE %s -%s %s"
560                      (liece-channel-real liece-current-channel)
561                      (string-times "o" (length ops))
562                      (string-join ops " ")))))
563
564 (defun liece-command-mode+v (voices)
565   "Send a MODE +v VOICES command."
566   (interactive
567    (let ((voices (append (liece-channel-get-voices)
568                          (liece-channel-get-operators)))
569          voice
570          (nicks (liece-channel-get-nicks))
571          (completion-ignore-case t)
572          (count 0))
573      (setq nicks (filter-elements nick nicks
574                    (not (string-assoc-ignore-case nick voices)))
575            voices (liece-minibuffer-completing-sequential-read
576                    (_ "Set Voice for") 0 (list-to-alist nicks)))
577      (list voices)))
578   (let (vcs)
579     (dolist (voice voices)
580       (push voice vcs)
581       (when (= (length vcs) liece-compress-mode-length)
582         (liece-send "MODE %s +%s %s"
583                      (liece-channel-real liece-current-channel)
584                      (string-times "v" liece-compress-mode-length)
585                      (string-join vcs " "))
586         (setq vcs nil)))
587     (if vcs
588         (liece-send "MODE %s +%s %s"
589                      (liece-channel-real liece-current-channel)
590                      (string-times "v" (length vcs))
591                      (string-join vcs " ")))))
592
593 (defun liece-command-mode-v (voices)
594   "Send a MODE -v VOICES command."
595   (interactive
596    (let ((completion-ignore-case t)
597          (voices (liece-channel-get-voices)) voice nicks)
598      (setq nicks (liece-minibuffer-completing-sequential-read
599                   (_ "Unset Voice for") 0 (list-to-alist voices)))
600      (list nicks)))
601   (let (vcs)
602     (dolist (voice voices)
603       (push voice vcs)
604       (when (= (length vcs) liece-compress-mode-length)
605         (liece-send "MODE %s -%s %s"
606                      (liece-channel-real liece-current-channel)
607                      (string-times "v" liece-compress-mode-length)
608                      (string-join vcs " "))
609         (setq vcs nil)))
610     (if vcs
611         (liece-send "MODE %s -%s %s"
612                      (liece-channel-real liece-current-channel)
613                      (string-times "v" (length vcs))
614                      (string-join vcs " ")))))
615
616 (defun liece-command-message (address message &optional arg key)
617   "Send ADDRESS a private MESSAGE.
618 If argument ARG is non-nil message will be encrypted with KEY."
619   (interactive
620    (let ((completion-ignore-case t) address)
621      (setq address
622            (liece-channel-virtual
623             (liece-minibuffer-completing-default-read
624              (_ "Private message to: ")
625              (append liece-nick-alist liece-channel-alist)
626              nil nil liece-privmsg-partner)))
627      (list address
628            (read-string
629             (format
630              (_ "Private message to %s: ")
631              address))
632            (if current-prefix-arg
633                (not liece-crypt-mode-active)
634              liece-crypt-mode-active)
635            nil)))
636   (if (funcall liece-message-empty-predicate message)
637       (progn (liece-message (_ "No text to send")) nil)
638     (let ((chnl (liece-channel-real address)) (msg message))
639       (with-liece-encryption (msg address arg key)
640         (liece-send "PRIVMSG %s :%s" chnl msg)
641         (if (liece-channel-p chnl)
642             (liece-own-channel-message message
643                                         (liece-channel-virtual address))
644           (liece-own-private-message message address)))
645       t)))
646
647 ;; Added at mta@tut.fi's request...
648 ;; Does not support encryption (yet!?)
649
650 (defun liece-command-mta-private (partner)
651   "Send a private message (current line) to PARTNER."
652   (interactive
653    (let ((completion-ignore-case t))
654      (setq liece-privmsg-partner
655            (liece-channel-virtual
656             (liece-minibuffer-completing-default-read
657              (_ "To whom: ")
658              (append liece-nick-alist liece-channel-alist)
659              nil nil liece-privmsg-partner)))
660      (list liece-privmsg-partner)))
661   (let ((message (buffer-substring (progn (beginning-of-line) (point))
662                                    (progn (end-of-line) (point)))))
663     (if (> (length message) 0)
664         (progn
665           (liece-command-message liece-privmsg-partner message)
666           (liece-next-line 1))
667       (liece-message (_ "No text to send")))))
668
669 (defun liece-command-names (&optional expr)
670   "List the nicknames of the current IRC users on given EXPR.
671 With an Control-U as argument, only the current channel is listed.
672 With - as argument, list all channels."
673   (interactive
674    (if (or current-prefix-arg (null liece-current-channel))
675        (if (eq current-prefix-arg '-)
676            (list current-prefix-arg))
677      (let ((completion-ignore-case t) expr)
678        (setq expr (liece-minibuffer-completing-default-read
679                       (_ "Names on channel: ")
680                       liece-channel-alist nil nil liece-current-channel))
681        (unless (string-equal "" expr)
682          (list expr)))))
683   (when (or (and (eq expr '-)
684                  (y-or-n-p
685                   (_ "Do you really query NAMES without argument?")))
686             (not (or expr
687                      (if liece-current-channel
688                          (setq expr (liece-channel-real
689                                      liece-current-channel))))))
690     (setq expr ""))
691   (when expr
692     (liece-send "NAMES %s" expr)))
693
694 (defun liece-command-nickname (nick)
695   "Set your nickname to NICK."
696   (interactive "sEnter your nickname: ")
697   (let ((nickname (truncate-string nick liece-nick-max-length)))
698     (if (zerop (length nickname))
699         (liece-message (_ "illegal nickname \"%s\"; not changed") nickname)
700       (liece-send "NICK %s" nick))))
701       
702 (defun liece-command-who (&optional expr)
703   "Lists tue users that match the given expression EXPR.
704 If you enter only Control-U as argument, list the current channel.
705 With - as argument, list all users."
706   (interactive
707    (if (or current-prefix-arg (null liece-current-channel))
708        (if (eq current-prefix-arg '-)
709            (list current-prefix-arg))
710      (let ((completion-ignore-case t) expr)
711        (setq expr (liece-minibuffer-completing-default-read
712                    (_ "WHO expression: ")
713                    (append liece-channel-alist liece-nick-alist)))
714        (unless (string-equal "" expr)
715          (list expr)))))
716   (when (or (and (eq expr '-)
717                  (y-or-n-p
718                   (_ "Do you really query WHO without argument?")))
719             (not (or expr
720                      (if liece-current-channel
721                          (setq expr (liece-channel-real
722                                      liece-current-channel))))))
723     (setq expr ""))
724   (when expr
725     (liece-send "WHO %s" expr)
726     (setq liece-who-expression expr)))
727
728 (defun liece-command-finger (finger-nick-var &optional server)
729   "Get information about a specific user FINGER-NICK-VAR.
730 If called with optional argument SERVER or any prefix argument,
731 query information to the foreign server."
732   (interactive
733    (let (finger-nick-var (completion-ignore-case t))
734      (setq finger-nick-var
735            (completing-read (_ "Finger whom: ") liece-nick-alist))
736      (list finger-nick-var (and current-prefix-arg finger-nick-var))))
737   (if server
738       (liece-send "WHOIS %s %s" server finger-nick-var)
739     (liece-send "WHOIS %s" finger-nick-var)))
740
741 (defun liece-command-topic (topic)
742   "Change TOPIC of the current channel."
743   (interactive
744    (list (read-from-minibuffer
745           "Topic: " (cons (or (liece-channel-get-topic) "") 0))))
746   (liece-send "TOPIC %s :%s"
747               (liece-channel-real liece-current-channel) topic))
748
749 (defun liece-command-invite (&optional invite-nick-var invite-channel-var)
750   "Invite INVITE-NICK-VAR to INVITE-CHANNEL-VAR."
751   (interactive
752    (let ((completion-ignore-case t) invite-channel-var invite-nick-var)
753      (if current-prefix-arg
754          (setq invite-channel-var
755                (liece-channel-virtual
756                 (completing-read
757                  (_ "Invite channel: ")
758                  (list-to-alist liece-current-channels)))))
759      (setq invite-nick-var
760            (completing-read
761             (_ "Invite whom: ")
762             liece-nick-alist))
763      (list invite-nick-var invite-channel-var)))
764   (or invite-channel-var
765       (setq invite-channel-var liece-current-channel))
766   (liece-send "INVITE %s %s"
767                invite-nick-var (liece-channel-real invite-channel-var)))
768
769 (defun liece-command-away (awaymsg)
770   "Mark/unmark yourself as being away.
771 Leave message AWAYMSG."
772   (interactive "sAway message: ")
773   (liece-send "AWAY :%s" awaymsg)
774   (setq liece-away-message awaymsg))
775
776 (defun liece-command-scroll-down (lines)
777   "Scroll LINES down dialogue buffer from command buffer."
778   (interactive "P")
779   (let ((other-window-scroll-buffer
780          (if liece-channel-buffer-mode
781              liece-channel-buffer
782            liece-dialogue-buffer)))
783     (when (liece-get-buffer-window other-window-scroll-buffer)
784       (condition-case nil
785           (scroll-other-window-down lines)
786         (beginning-of-buffer
787          (message "Beginning of buffer"))))))
788
789 (defun liece-command-scroll-up (lines)
790   "Scroll LINES up dialogue buffer from command buffer."
791   (interactive "P")
792   (let* ((other-window-scroll-buffer
793           (if liece-channel-buffer-mode
794               liece-channel-buffer
795             liece-dialogue-buffer)))
796     (when (liece-get-buffer-window other-window-scroll-buffer)
797       (condition-case nil
798           (scroll-other-window lines)
799         (end-of-buffer
800          (message "End of buffer"))))))
801
802 (defun liece-command-nick-scroll-down (lines)
803   "Scroll LINES down nick buffer from command buffer."
804   (interactive "P")
805   (let ((other-window-scroll-buffer liece-nick-buffer))
806     (when (liece-get-buffer-window other-window-scroll-buffer)
807       (condition-case nil
808           (scroll-other-window-down lines)
809         (beginning-of-buffer
810          (message "Beginning of buffer"))))))
811
812 (defun liece-command-nick-scroll-up (lines)
813   "Scroll LINES up nick buffer from command buffer."
814   (interactive "P")
815   (let* ((other-window-scroll-buffer liece-nick-buffer))
816     (when (liece-get-buffer-window other-window-scroll-buffer)
817       (condition-case nil
818           (scroll-other-window lines)
819         (end-of-buffer
820          (message "End of buffer"))))))
821
822 (defun liece-command-toggle-crypt (&optional arg)
823   "Toggle crypt status.
824 If prefix argument ARG is non-nil, force set crypt status."
825   (interactive "P")
826   (if arg
827       (setq liece-crypt-mode-active (prefix-numeric-value arg))
828     (if liece-crypt-mode-active
829         (setq liece-crypt-mode-active nil)
830       (setq liece-crypt-mode-active t)))
831   (liece-set-crypt-indicator)
832   (switch-to-buffer (current-buffer)))
833
834 (defun liece-command-freeze (&optional arg)
835   "Prevent automatic scrolling of the dialogue window.
836 If prefix argument ARG is non-nil, toggle frozen status."
837   (interactive "P")
838   (liece-freeze (if liece-channel-buffer-mode
839                     liece-channel-buffer
840                   liece-dialogue-buffer)
841                 (if arg (prefix-numeric-value arg))))
842
843 (defun liece-command-own-freeze (&optional arg)
844   "Prevent automatic scrolling of the dialogue window.
845 The difference from `liece-command-freeze' is that your messages are hidden.
846 If prefix argument ARG is non-nil, toggle frozen status."
847   (interactive "P")
848   (liece-own-freeze (if liece-channel-buffer-mode
849                         liece-channel-buffer
850                       liece-dialogue-buffer)
851                     (if arg (prefix-numeric-value arg))))
852
853 (defun liece-command-beep (&optional arg)
854   "Toggle the automatic beep notice when the channel message is received."
855   (interactive "P")
856   (liece-beep (if liece-channel-buffer-mode
857                   liece-channel-buffer
858                 liece-dialogue-buffer)
859               (if arg (prefix-numeric-value arg))))
860
861 (defun liece-command-quit (&optional arg)
862   "Quit IRC.
863 If prefix argument ARG is non-nil, leave signoff message."
864   (interactive "P")
865   (when (and (liece-server-opened)
866              (y-or-n-p (_ "Quit IRC? ")))
867     (message "")
868     (let ((quit-string
869            (if arg (read-string (_ "Signoff message: "))
870              (or liece-signoff-message
871                  (product-name (product-find 'liece-version))))))
872       (liece-send "QUIT :%s" quit-string))
873     (liece-clear-system)
874     (liece-close-server)
875     (if liece-save-variables-are-dirty
876         (liece-command-save-vars))
877     (if (interactive-p)
878         (liece-window-configuration-pop))
879     (run-hooks 'liece-exit-hook)))
880
881 (defun liece-command-generic (message)
882   "Enter a generic IRC MESSAGE, which is sent to the server.
883 A ? lists the useful generic messages."
884   (interactive "sIRC command (? to help): ")
885   (if (string-equal message "?")
886       (with-output-to-temp-buffer "*IRC Help*"
887         (princ "The following generic IRC messages may be of interest to you:
888 TOPIC <new topic>               set the topic of your channel
889 INVITE <nickname>               invite another user to join your channel
890 LINKS                           lists the currently reachable IRC servers
891 SUMMON <user@host>              invites an user not currently in IRC
892 USERS <host>                    lists the users on a host
893 AWAY <reason>                   marks you as not really actively using IRC
894                                 (an empty reason clears it)
895 WALL <message>                  send to everyone on IRC
896 NAMES <channel>                 lists users per channel
897 "))
898     (liece-send "%s" message)))
899
900 (defun liece-command-irc-compatible ()
901   "If entered at column 0, allow you to enter a generic IRC message."
902   (interactive)
903   (if (zerop (current-column))
904       (call-interactively (function liece-command-generic))
905     (self-insert-command 1)))
906
907 (defun liece-command-exec (command)
908   "Execute COMMAND, stdout to dialogue."
909   (interactive "sShell command: ")
910   (shell-command command t)
911   (let ((opoint (point)))
912     (while (< (point) (mark))
913       (liece-command-enter-message)
914       (set-buffer liece-command-buffer))
915     (push-mark opoint t)))
916
917 (defun liece-command-yank-send (&optional arg)
918   "Send message from yank buffer.
919 Prefix argument ARG is regarded as distance from yank pointer."
920   (interactive)
921   (when (y-or-n-p (_ "Really SEND from Yank Buffer?"))
922     (save-restriction
923       (narrow-to-region (point) (point))
924       (insert (car kill-ring-yank-pointer))
925       (goto-char (point-min))
926       (while (eobp)
927         (liece-command-enter-message)
928         (set-buffer liece-command-buffer)))))
929
930 (defun liece-command-complete ()
931   "Complete word before point from userlist."
932   (interactive)
933   (let ((completion-ignore-case t)
934         (alist (if liece-current-channel
935                    (list-to-alist (liece-channel-get-nicks))
936                  liece-nick-alist))
937         candidate completion all)
938     (setq candidate (current-word)
939           completion (try-completion candidate alist)
940           all (all-completions candidate alist))
941     (liece-minibuffer-finalize-completion completion candidate all)))
942
943 (defun liece-command-load-vars ()
944   "Load configuration from liece-variables-file."
945   (interactive)
946   (let ((nick liece-real-nickname))
947     (unwind-protect
948         (liece-read-variables-files)
949       (setq liece-real-nickname nick)
950       (liece-command-reconfigure-windows))))
951
952 (defun liece-command-save-vars ()
953   "Save current settings to `liece-variables-file'."
954   (interactive)
955   (let* ((output-buffer
956           (find-file-noselect
957            (expand-file-name liece-variables-file)))
958          output-marker p)
959     (save-excursion
960       (set-buffer output-buffer)
961       (goto-char (point-min))
962       (cond ((re-search-forward "^;; Saved Settings *\n" nil 'move)
963              (setq p (match-beginning 0))
964              (goto-char p)
965              (or (re-search-forward
966                   "^;; End of Saved Settings *\\(\n\\|\\'\\)" nil t)
967                  (error
968                   (concat "can't find END of saved state in "
969                           liece-variables-file)))
970              (delete-region p (match-end 0)))
971             (t
972              (goto-char (point-max))
973              (insert "\n")))
974       (setq output-marker (point-marker))
975       (let ((print-readably t)
976             (print-escape-newlines t)
977             (standard-output output-marker))
978         (princ ";; Saved Settings\n")
979         (dolist (var liece-saved-forms)
980           (if (symbolp var)
981               (prin1 (list 'setq var
982                            (let ((val (symbol-value var)))
983                              (if (memq val '(t nil))
984                                  val
985                                (list 'quote val)))))
986             (setq var (eval var))
987             (cond ((eq (car-safe var) 'progn)
988                    (while (setq var (cdr var))
989                      (prin1 (car var))
990                      (princ "\n")
991                      (if (cdr var) (princ "  "))))
992                   (var
993                    (prin1 "xx")(prin1 var))))
994           (if var (princ "\n")))
995         (princ "\n")
996         (princ ";; End of Saved Settings\n")))
997     (set-marker output-marker nil)
998     (save-excursion
999       (set-buffer output-buffer)
1000       (save-buffer)))
1001   (setq liece-save-variables-are-dirty nil))
1002
1003 (defun liece-command-reconfigure-windows ()
1004   "Rearrange window splitting."
1005   (interactive)
1006   (let ((command-window (liece-get-buffer-window liece-command-buffer))
1007         (dialogue-window (liece-get-buffer-window liece-dialogue-buffer))
1008         (obuffer (current-buffer)))
1009     (if (and command-window dialogue-window)
1010         (let ((ch (window-height command-window))
1011               (dh (window-height dialogue-window)))
1012           (delete-window command-window)
1013           (pop-to-buffer liece-dialogue-buffer)
1014           (enlarge-window (+ ch dh (- dh))))
1015       (pop-to-buffer liece-dialogue-buffer))
1016     (liece-configure-windows)
1017     (if liece-one-buffer-mode
1018         (pop-to-buffer liece-dialogue-buffer)
1019       (pop-to-buffer obuffer))))
1020
1021 (defun liece-command-end-of-buffer ()
1022   "Get end of the dialogue buffer."
1023   (interactive)
1024   (let (buffer window)
1025     (setq buffer (if liece-channel-buffer-mode
1026                      liece-channel-buffer
1027                    liece-dialogue-buffer))
1028     (or (setq window (liece-get-buffer-window buffer))
1029         (setq window (liece-get-buffer-window liece-dialogue-buffer)
1030               buffer liece-dialogue-buffer))
1031     (when window
1032       (save-selected-window
1033         (select-window window)
1034         (goto-char (point-max))))))
1035
1036 (defun liece-command-private-conversation (arg)
1037   "Toggle between private conversation mode and channel mode.
1038 User can then join and part to a private conversation as he would
1039 join or part to a channel.
1040
1041 If there are no private conversations or argument is given user is
1042 prompted the partner/channel (return as partner/channel means toggle
1043 mode, the current channel and current chat partner are not altered)
1044 Argument ARG is prefix argument of toggle status."
1045   (interactive
1046    (let ((completion-ignore-case t))
1047      (list
1048       (if current-prefix-arg
1049           ;; prefixed, ask where to continue
1050           (if (eq liece-command-buffer-mode 'chat)
1051               (liece-minibuffer-completing-default-read
1052                (_ "Return to channel: ")
1053                (append liece-channel-alist liece-nick-alist)
1054                nil nil liece-current-channel)
1055             (completing-read
1056              (_ "Start private conversation with: ")
1057              liece-nick-alist nil nil))
1058         ;; no prefix, see if going to chat
1059         (if (eq liece-command-buffer-mode 'channel)
1060             ;; and if we have chat partner, select that
1061             (if liece-current-chat-partner
1062                 liece-current-chat-partner
1063               (completing-read
1064                (_ "Start private conversation with: ")
1065                liece-nick-alist )))))))
1066   
1067   (liece-toggle-command-buffer-mode)
1068   (if (and arg (not (string-equal arg "")))
1069       (liece-command-join arg))
1070   (liece-set-channel-indicator)
1071   (liece-set-crypt-indicator)
1072   ;; refresh mode line
1073   (force-mode-line-update))
1074
1075 (defun liece-command-next-channel ()
1076   "Select next channel or chat partner, and *DONT* rotate list."
1077   (interactive)
1078   (let ((rest (copy-sequence
1079                (if (eq liece-command-buffer-mode 'chat)
1080                    liece-current-chat-partners
1081                  liece-current-channels)))
1082         (chnl (if (eq liece-command-buffer-mode 'chat)
1083                   liece-current-chat-partner
1084                 liece-current-channel)))
1085     (liece-switch-to-channel
1086      (or (cadr (liece-channel-member chnl (delq nil rest)))
1087          (car (delq nil rest))
1088          chnl))))
1089
1090 (defun liece-command-previous-channel ()
1091   "Select previous channel or chat partner, and *DONT* rotate list."
1092   (interactive)
1093   (let ((rest
1094          (reverse
1095           (if (eq liece-command-buffer-mode 'chat)
1096               liece-current-chat-partners
1097             liece-current-channels)))
1098         (chnl
1099          (if (eq liece-command-buffer-mode 'chat)
1100              liece-current-chat-partner
1101            liece-current-channel)))
1102     (liece-switch-to-channel
1103      (or (cadr (liece-channel-member chnl (delq nil rest)))
1104          (car (delq nil rest))
1105          chnl))))
1106       
1107 (defun liece-command-unread-channel ()
1108   "Select unread channel or chat partner."
1109   (interactive)
1110   (let ((chnl (car liece-channel-unread-list)))
1111     (if chnl
1112         (liece-switch-to-channel chnl)
1113       (liece-message (_ "No unread channel or chat partner.")))))
1114
1115 (defun liece-command-push ()
1116   "Select next channel or chat partner, and rotate list."
1117   (interactive)
1118   (let* ((rest
1119           (if (eq liece-command-buffer-mode 'chat)
1120               liece-current-chat-partners
1121             liece-current-channels))
1122          (temp (car (last rest)))
1123          (len (length rest)))
1124     (unwind-protect
1125         (while (< 1 len)
1126           (setcar (nthcdr (1- len) rest) (nth (- len 2) rest))
1127           (decf len))
1128       (when rest
1129         (setcar rest temp)))
1130     (liece-channel-change)))
1131
1132 (defun liece-command-pop ()
1133   "Select previous channel or chat partner, and rotate list."
1134   (interactive)
1135   (let* ((rest
1136           (if (eq liece-command-buffer-mode 'chat)
1137               liece-current-chat-partners
1138             liece-current-channels))
1139          (temp (car rest))
1140          (len (length rest)))
1141     (unwind-protect
1142         (dotimes (i len)
1143           (setcar (nthcdr i rest) (nth (1+ i) rest)))
1144       (when rest
1145         (setcar (last rest) temp)))
1146     (liece-channel-change)))
1147
1148 (defvar liece-redisplay-buffer-functions
1149   '(liece-channel-redisplay-buffer
1150     liece-nick-redisplay-buffer
1151     liece-channel-list-redisplay-buffer))
1152
1153 (defun liece-switch-to-channel (chnl)
1154   "Switch the current channel to CHNL."
1155   (if (liece-channel-p (liece-channel-real chnl))
1156       (progn
1157         (liece-toggle-command-buffer-mode 'channel)
1158         (setq liece-current-channel chnl)
1159         (liece-set-channel-indicator))
1160     (liece-toggle-command-buffer-mode 'chat)
1161     (setq liece-current-chat-partner chnl)
1162     (liece-set-channel-indicator))
1163   (save-excursion
1164     (run-hook-with-args 'liece-redisplay-buffer-functions chnl))
1165   (liece-set-crypt-indicator)
1166   t)
1167
1168 (defun liece-switch-to-channel-no (num)
1169   "Switch the current channel to NUM."
1170   (let* ((mode liece-command-buffer-mode)
1171          (chnls (if (eq mode 'chat)
1172                     liece-current-chat-partners
1173                   liece-current-channels)))
1174     (if (and (integerp num)
1175              (stringp (nth num chnls)))
1176         (let ((chnl (nth num chnls)))
1177           (if (eq mode 'chat)
1178               (progn
1179                 (liece-toggle-command-buffer-mode 'chat)
1180                 (setq liece-current-chat-partner chnl)
1181                 (liece-set-channel-indicator))
1182             (liece-toggle-command-buffer-mode 'channel)
1183             (setq liece-current-channel chnl)
1184             (liece-set-channel-indicator))
1185           (save-excursion
1186             (run-hook-with-args 'liece-redisplay-buffer-functions chnl))
1187           (liece-set-crypt-indicator)
1188           t)
1189       (message "Invalid channel!")
1190       nil)))
1191
1192 (defun liece-command-ping ()
1193   "Send PING to server."
1194   (interactive)
1195   (if (stringp liece-server-name)
1196       (liece-send "PING %s" liece-server-name)))
1197
1198 (defun liece-command-ison (nicks)
1199   "IsON users NICKS."
1200   (interactive
1201    (let (nicks (completion-ignore-case t))
1202      (setq nicks (liece-minibuffer-completing-sequential-read
1203                   "IsON" 0 liece-nick-alist))
1204      (list nicks)))
1205   (liece-send "ISON :%s" (mapconcat #'identity nicks " ")))
1206
1207 (defun liece-command-activate-friends (nicks)
1208   "Register NICKS to the frinends list."
1209   (interactive
1210    (let (nicks (completion-ignore-case t))
1211      (setq nicks
1212            (liece-minibuffer-completing-sequential-read
1213             (_ "Friend") 0
1214             (filter-elements nick liece-nick-alist
1215               (not (string-list-member-ignore-case
1216                     (car nick) liece-friends)))))
1217      (list nicks)))
1218   (setq liece-friends (append nicks liece-friends)))
1219
1220 (defun liece-command-deactivate-friends ()
1221   "Clear current friends list."
1222   (interactive)
1223   (setq liece-friends nil))
1224
1225 (defun liece-command-display-friends ()
1226   "Display status of the friends."
1227   (interactive)
1228   (with-output-to-temp-buffer " *IRC Friends*"
1229     (set-buffer standard-output)
1230     (insert "Friends status: \n\n")
1231     (dolist (friend liece-friends)
1232       (if (string-list-member-ignore-case friend liece-friends-last)
1233           (insert "+ " friend "\n")
1234         (insert "- " friend "\n")))))
1235
1236 (defun liece-command-userhost (nicks)
1237   "Ask for the hostnames of NICKS."
1238   (interactive
1239    (let (nicks (completion-ignore-case t))
1240      (setq nicks (liece-minibuffer-completing-sequential-read
1241                   (_ "Userhost nick") 0
1242                   (list-to-alist liece-nick-alist)))
1243      (list nicks)))
1244   (liece-send "USERHOST :%s" (mapconcat 'identity nicks ",")))
1245
1246 (defun liece-command-show-last-kill ()
1247   "Dig last kill from KILL and show it."
1248   (interactive)
1249   (liece-insert-info
1250    (append liece-D-buffer liece-O-buffer)
1251    (save-excursion
1252      (set-buffer liece-KILLS-buffer)
1253      (goto-char (point-max))
1254      (forward-line -1)
1255      (concat (buffer-substring (point) (point-max)) "\n"))))
1256
1257 (defun liece-command-toggle-private ()
1258   "Toggle private mode / channel mode."
1259   (interactive)
1260   (case (prog1 liece-command-buffer-mode
1261           (liece-toggle-command-buffer-mode))
1262     (chat
1263      (if liece-current-channel
1264          (liece-switch-to-channel liece-current-channel))
1265      (setq liece-command-buffer-mode-indicator "Channels"))
1266     (channel
1267      (if liece-current-chat-partner
1268          (liece-switch-to-channel liece-current-chat-partner))
1269      (setq liece-command-buffer-mode-indicator "Partners")))
1270   (liece-channel-change))
1271
1272 (defun liece-command-tag-region (start end)
1273   "Move current region between START and END to `kill-ring'."
1274   (interactive
1275    (if (region-active-p)
1276        (list (region-beginning)(region-end))
1277      (list (line-beginning-position)(line-end-position))))
1278   (static-if (fboundp 'extent-property)
1279       (kill-ring-save start end)
1280     (let ((start (set-marker (make-marker) start))
1281           (end (set-marker (make-marker) end))
1282           (inhibit-read-only t)
1283           buffer-read-only
1284           buffer-undo-list)
1285       (liece-remove-properties-region start end)
1286       (kill-ring-save start end)
1287       (push nil buffer-undo-list)
1288       (undo))))
1289
1290 (provide 'liece-commands)
1291
1292 ;;; liece-commands.el ends here