1 ;;; liece-commands.el --- Interactive commands in command buffer.
2 ;; Copyright (C) 1998-2000 Daiki Ueno
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
7 ;; Keywords: IRC, liece
9 ;; This file is part of Liece.
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)
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.
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.
33 (require 'liece-misc))
35 (require 'liece-channel)
37 (require 'liece-coding)
39 (require 'liece-minibuf)
41 (autoload 'liece-dcc-chat-send "liece-dcc")
42 (autoload 'liece-window-configuration-pop "liece-window")
44 (autoload 'liece-command-ctcp-version "liece-ctcp" nil t)
45 (autoload 'liece-command-ctcp-userinfo "liece-ctcp" nil t)
46 (autoload 'liece-command-ctcp-clientinfo "liece-ctcp" nil t)
47 (autoload 'liece-command-ctcp-ping "liece-ctcp" nil t)
48 (autoload 'liece-command-ctcp-time "liece-ctcp" nil t)
49 (autoload 'liece-command-ctcp-x-face "liece-ctcp" nil t)
50 (autoload 'liece-command-ctcp-comment "liece-ctcp" nil t)
51 (autoload 'liece-command-ctcp-help "liece-ctcp" nil t)
53 (defun liece-command-poll-names ()
54 "Handler for polling NAMES."
55 (when (liece-server-opened)
58 (length liece-channel-alist)))
59 (dolist (chnl liece-channel-alist)
60 (liece-send "NAMES %s" (car chnl)))))
62 (defun liece-command-poll-friends ()
63 "Handler for polling ISON."
66 (liece-send "ISON %s" (mapconcat 'identity liece-friends " "))))
68 (defun liece-command-find-timestamp ()
69 "Find recent timestamp in dialogue buffer."
73 (regexp (concat "^\\(" liece-time-prefix-regexp "\\)?"
74 (regexp-quote liece-timestamp-prefix))))
75 (unless (eq 'liece-dialogue-mode (derived-mode-class major-mode))
76 (set-buffer liece-dialogue-buffer)
77 (goto-char (point-max)))
78 (if (re-search-backward regexp (point-min) t)
79 (setq range (concat (buffer-substring (match-end 0)
82 (if (re-search-forward regexp (point-max) t)
83 (setq range (concat range (buffer-substring (match-end 0)
84 (line-end-position)))))
85 (liece-message range))))
87 (defun liece-command-keepalive ()
88 "Handler for polling server connection."
89 (if (not (liece-server-opened))
91 (liece-ping-if-idle)))
93 (defvar liece-last-timestamp-time nil "Last time timestamp was inserted.")
94 (defvar liece-last-timestamp-no-cons-p nil "Last timestamp was no-cons.")
96 (defun liece-command-timestamp-if-interval-expired (&optional no-cons)
97 "If interval timer has expired, insert timestamp into dialogue buffer.
98 And save variables into `liece-variable-file' if there are variables to save.
99 Optional argument NO-CONS specifies timestamp format is cons cell."
101 (when (and (not (and no-cons
102 liece-last-timestamp-no-cons-p))
103 (numberp liece-timestamp-interval)
104 (> liece-timestamp-interval 0)
105 (or (null liece-last-timestamp-time)
106 (> (liece-time-difference liece-last-timestamp-time
108 liece-timestamp-interval)))
109 (if liece-save-variables-are-dirty
110 (liece-command-save-vars))
111 (liece-command-timestamp)
112 (setq liece-last-timestamp-no-cons-p no-cons)))
114 (defun liece-command-timestamp ()
115 "Insert timestamp into dialogue buffer."
117 (let ((stamp (format liece-timestamp-format
118 (funcall liece-format-time-function (current-time))))
119 (liece-timestamp-interval 0))
120 (liece-insert liece-D-buffer (concat stamp "\n"))
121 (setq liece-last-timestamp-time (current-time))))
123 (defun liece-command-point-back-to-command-buffer ()
124 "Set point back to command buffer."
126 (let ((win (liece-get-buffer-window liece-command-buffer)))
127 (if win (select-window win))))
129 (defun liece-command-send-message (message)
130 "Send MESSAGE to current chat partner of current channel."
131 (if (string-equal message "")
132 (progn (liece-message (_ "No text to send")) nil)
133 (let ((addr (if (eq liece-command-buffer-mode 'chat)
134 liece-current-chat-partner
135 liece-current-channel))
136 repr method name target)
138 ((eq liece-command-buffer-mode 'chat)
139 (or liece-current-chat-partner
141 (substitute-command-keys
142 "Type \\[liece-command-join] to start private conversation")))
143 (setq repr (liece-channel-parse-representation
144 liece-current-chat-partner)
147 target (aref repr 2))
148 (cond ((eq method 'dcc)
149 (liece-dcc-chat-send target message))
151 (liece-send "PRIVMSG %s :%s"
152 liece-current-chat-partner message)))
153 (liece-own-private-message message))
155 (or liece-current-channel
157 (substitute-command-keys
158 "Type \\[liece-command-join] to join a channel")))
161 (liece-channel-real liece-current-channel) message)
162 (liece-own-channel-message message))))))
164 (defun liece-command-enter-message ()
165 "Enter the current line as an entry in the IRC dialogue."
168 (liece-command-send-message
169 (buffer-substring (point)(progn (end-of-line) (point))))
172 (defun liece-dialogue-enter-message ()
173 "Ask for a line as an entry in the IRC dialogue on the current channel."
176 (while (not (string-equal (setq message (read-string "> ")) ""))
177 (liece-command-send-message message))))
179 (defun liece-command-inline ()
180 "Send current line as a message to the IRC server."
183 (liece-send (buffer-substring (point)(progn (end-of-line) (point))))
186 (defun liece-command-join-channel (join-channel-var key)
187 "Join a JOIN-CHANNEL-VAR with KEY."
188 (let ((nicks liece-nick-alist) nick)
192 (liece-channel-equal join-channel-var (car nick)))))
193 (setq nick (pop nicks)))
195 (setq join-channel-var
196 (or (car (get (intern (car nick) liece-obarray) 'chnl))
198 (if (liece-channel-member join-channel-var liece-current-channels)
200 (setq liece-current-channel join-channel-var)
201 (liece-switch-to-channel liece-current-channel)
202 (liece-channel-change))
203 (liece-send "JOIN %s %s" (liece-channel-real join-channel-var) key))))
205 (defun liece-command-join-partner (join-channel-var)
206 "Join a JOIN-CHANNEL-VAR."
207 (if (liece-channel-member join-channel-var liece-current-chat-partners)
209 (setq liece-current-chat-partner join-channel-var)
210 (liece-switch-to-channel liece-current-chat-partner))
211 (setq liece-current-chat-partner join-channel-var)
212 (liece-channel-join liece-current-chat-partner))
213 (liece-channel-change))
215 (defun liece-command-join (join-channel-var &optional key)
216 "Join a JOIN-CHANNEL-VAR with KEY.
217 If user nickname is given join the same set of channels as the specified user.
218 If command-buffer is in chat-mode, start private conversation
219 with specified user."
221 (let (join-channel-var key (completion-ignore-case t))
222 (setq join-channel-var
223 (if (numberp current-prefix-arg)
225 (liece-channel-virtual
226 (if (eq liece-command-buffer-mode 'chat)
227 (liece-minibuffer-completing-default-read
228 (_ "Start private conversation with: ")
230 nil nil liece-privmsg-partner)
231 (liece-minibuffer-completing-default-read
233 (append liece-channel-alist liece-nick-alist)
234 nil nil liece-default-channel-candidate)))))
235 (if (and current-prefix-arg
236 (not (numberp current-prefix-arg)))
238 (if (eq current-prefix-arg '-)
240 (format (_ "Key for channel %s: ") join-channel-var))
241 (let ((passwd-echo ?*))
243 (format (_ "Key for channel %s: ") join-channel-var))))))
244 (list join-channel-var key)))
245 (let ((real-chnl (liece-channel-real join-channel-var)))
246 (if (numberp join-channel-var)
247 (liece-switch-to-channel-no join-channel-var)
248 (setq liece-default-channel-candidate nil)
249 (if (liece-channel-p real-chnl)
250 (liece-toggle-command-buffer-mode 'channel)
251 (liece-toggle-command-buffer-mode 'chat))
252 (if (eq liece-command-buffer-mode 'chat)
253 (liece-command-join-partner join-channel-var)
255 (setq key (get (intern join-channel-var liece-obarray) 'key)))
256 (put (intern join-channel-var liece-obarray) 'key key)
259 (liece-command-join-channel join-channel-var key))
260 (force-mode-line-update))))
262 (defun liece-command-part (part-channel-var &optional part-msg)
263 "Part a PART-CHANNEL-VAR with PART-MSG."
265 (let (part-channel-var
266 (completion-ignore-case t)
268 (setq part-channel-var
269 (liece-channel-virtual
270 (if (eq liece-command-buffer-mode 'chat)
271 (liece-minibuffer-completing-default-read
272 (_ "End private conversation with: ")
273 (list-to-alist liece-current-chat-partners)
274 nil nil liece-current-chat-partner)
275 (liece-minibuffer-completing-default-read
277 (list-to-alist liece-current-channels)
278 nil nil liece-current-channel))))
279 (when current-prefix-arg
280 (setq part-msg (read-string (_ "Part Message: "))))
281 (list part-channel-var part-msg)))
282 (let ((real-chnl (liece-channel-real part-channel-var)))
283 (if (liece-channel-p real-chnl)
285 (if (liece-channel-member part-channel-var liece-current-channels)
286 (setq liece-current-channel part-channel-var))
287 (liece-send "PART %s :%s" real-chnl part-msg)
288 (setq liece-default-channel-candidate part-channel-var))
289 (setq liece-current-chat-partners
290 (liece-channel-remove part-channel-var
291 liece-current-chat-partners)
292 liece-current-chat-partner
293 (car liece-current-chat-partners))
294 (liece-set-channel-indicator)
295 (liece-channel-part part-channel-var))))
297 (defun liece-command-kill (kill-nickname-var &optional timeout silent)
298 "Ignore messages from KILL-NICKNAME-VAR.
299 Username can be given as case insensitive regular expression of form
300 \".*@.*\.sub.domain\".
301 If already ignoring him/her, toggle.
302 If `liece-variables-file' is defined and the file is writable,
303 settings are updated automatically for future sessions.
304 Optional argument TIMEOUT says expiration.
305 If SILENT is non-nil, don't notify current status."
307 (let (kill-nickname-var timeout (completion-ignore-case t))
308 (setq kill-nickname-var (completing-read
309 (_ "Ignore nickname or regexp: ")
310 (append liece-nick-alist
311 liece-kill-nickname)))
312 (or (string-equal "" kill-nickname-var)
313 (string-assoc-ignore-case kill-nickname-var liece-kill-nickname)
314 (setq timeout (string-to-int (read-from-minibuffer
315 (_ "Timeout [RET for none]: ")))))
316 (list kill-nickname-var timeout)))
317 ;; empty, just list them
318 (if (string-equal "" kill-nickname-var)
319 (with-current-buffer liece-dialogue-buffer
320 (let ((ignores liece-kill-nickname) (time (current-time))
321 buffer-read-only expire expiretime)
322 (goto-char (point-max))
323 (liece-insert-info liece-D-buffer (_ "Currently ignoring:"))
324 (dolist (ignore ignores)
325 (setq expiretime (if (cdr ignore)
326 (/ (liece-time-difference time (cdr ignore))
328 expire (cond ((not expiretime) "")
330 (format (_ " (%d min)") expiretime))
333 (liece-insert liece-D-buffer
334 (concat " " (car ignore) expire "\n")))))
335 ;; else not empty, check if exists
337 (string-assoc-ignore-case
338 kill-nickname-var liece-kill-nickname)))
340 (when (setq ignore (string-assoc-ignore-case
341 (car ignore) liece-kill-nickname))
342 (setq liece-kill-nickname
343 (delq ignore liece-kill-nickname))
344 (liece-insert-info liece-D-buffer
345 (format (_ "No longer ignoring: %s.\n")
347 ;; did not find, add to ignored ones
348 (let ((expire-time (if (> timeout 0)
349 (liece-time-add (current-time)
351 (and silent (> timeout 0)
352 (setcar (cdr (cdr expire-time)) -1))
353 (setq liece-kill-nickname
354 (cons (cons kill-nickname-var expire-time)
355 liece-kill-nickname))
357 (liece-insert-info liece-D-buffer
358 (format (_ "Ignoring %s") kill-nickname-var))
359 (liece-insert-info liece-D-buffer
361 (format " for %d minutes.\n" timeout)
363 (setq liece-save-variables-are-dirty t)))
365 (defun liece-command-kick (nick &optional msg)
366 "Kick this NICK out with MSG."
368 (let ((completion-ignore-case t)
369 (nicks (liece-channel-get-nicks)) nick msg)
370 (setq nick (completing-read
371 (_ "Kick out nickname: ")
372 (list-to-alist nicks)))
373 (if current-prefix-arg
374 (setq msg (concat " :" (read-string (_ "Kick Message: ")))))
376 (liece-send "KICK %s %s%s"
377 (liece-channel-real liece-current-channel)
380 (defun liece-command-ban (ban)
383 (let* ((completion-ignore-case t)
384 (nicks (liece-channel-get-nicks))
389 (concat nick "!" (liece-nick-get-user-at-host nick)))))
392 (setq ban (liece-minibuffer-completing-default-read
393 (_ "Ban pattern: ") uahs nil nil
394 (concat nick "!" (liece-nick-get-user-at-host nick))))
396 (liece-send "MODE %s :+b %s"
397 (liece-channel-real liece-current-channel) ban))
399 (defun liece-command-ban-kick (ban nick &optional msg)
400 "BAN kick this NICK out with MSG."
402 (let* ((completion-ignore-case t)
403 (nicks (liece-channel-get-nicks))
408 (concat nick "!" (liece-nick-get-user-at-host nick)))))
411 (setq nick (completing-read (_ "Kick out nickname: ")
412 (list-to-alist nicks))
413 ban (liece-minibuffer-completing-default-read
414 (_ "Ban pattern: ") uahs nil nil
415 (concat nick "!" (liece-nick-get-user-at-host nick))))
416 (if current-prefix-arg
417 (setq msg (concat " :" (read-string (_ "Kick Message: "))))
419 (list ban nick msg)))
420 (liece-send "MODE %s :+b %s"
421 (liece-channel-real liece-current-channel) ban)
422 (liece-send "KICK %s %s%s"
423 (liece-channel-real liece-current-channel)
426 (defun liece-command-list (&optional channel)
427 "List the given CHANNEL and its topics.
428 If you enter only Control-U as argument, list the current channel.
429 With - as argument, list all channels."
431 (if (or current-prefix-arg (null liece-current-channel))
432 (if (eq current-prefix-arg '-)
433 (list current-prefix-arg))
434 (let ((completion-ignore-case t) channel)
435 (setq channel (liece-minibuffer-completing-default-read
437 liece-channel-alist nil nil liece-current-channel))
438 (unless (string-equal "" channel)
442 (if liece-current-channel
443 (liece-send "LIST %s"
444 (liece-channel-real liece-current-channel))))
445 ((and (eq channel '-)
446 (y-or-n-p (_ "Do you really query LIST without argument?")))
448 ((not (string-equal channel ""))
449 (liece-send "LIST %s" (liece-channel-real channel))
452 (defun liece-command-lusers ()
453 "List the number of users and servers."
455 (liece-send "LUSERS"))
457 (defun liece-command-modec (chnl change)
458 "Send a MODE command to this CHNL.
461 (let ((completion-ignore-case t)
462 (chnl liece-current-channel)
463 liece-minibuffer-complete-function prompt)
464 (if current-prefix-arg
466 (liece-minibuffer-completing-default-read
468 (append liece-channel-alist liece-nick-alist)
469 nil nil liece-current-channel)))
471 ((liece-channel-p (liece-channel-real chnl))
473 (_ "Mode for channel %s [%s]: ")
474 chnl (or (liece-channel-get-modes chnl) ""))
475 liece-minibuffer-complete-function
476 (function liece-minibuffer-complete-channel-modes)))
479 (_ "Mode for user %s [%s]: ")
480 chnl (or (liece-nick-get-modes chnl) ""))
481 liece-minibuffer-complete-function
482 (function liece-minibuffer-complete-user-modes))))
483 (list chnl (read-from-minibuffer prompt nil liece-minibuffer-map))))
484 (liece-send "MODE %s %s" (liece-channel-real chnl) change))
486 (defun liece-command-mode+o (opers)
487 "Send a MODE +o OPERS command."
489 (let ((opers (liece-channel-get-operators)) oper
490 (nicks (liece-channel-get-nicks))
491 (completion-ignore-case t))
492 (setq nicks (filter-elements
494 (not (liece-nick-member nick opers)))
495 opers (liece-minibuffer-completing-sequential-read
496 (_ "Set Operator for") 0
497 (list-to-alist nicks)))
502 (when (= (length ops) liece-compress-mode-length)
503 (liece-send "MODE %s +%s %s"
504 (liece-channel-real liece-current-channel)
505 (string-times "o" liece-compress-mode-length)
506 (string-join ops " "))
509 (liece-send "MODE %s +%s %s"
510 (liece-channel-real liece-current-channel)
511 (string-times "o" (length ops))
512 (string-join ops " ")))))
514 (defun liece-command-mode-o (opers)
515 "Send a MODE -o OPERS command."
517 (let ((completion-ignore-case t)
518 (opers (liece-channel-get-operators)) oper nicks)
519 (setq nicks (liece-minibuffer-completing-sequential-read
520 (_ "Unset Operator for") 0
521 (list-to-alist opers)))
526 (when (= (length ops) liece-compress-mode-length)
527 (liece-send "MODE %s -%s %s"
528 (liece-channel-real liece-current-channel)
529 (string-times "o" liece-compress-mode-length)
530 (string-join ops " "))
533 (liece-send "MODE %s -%s %s"
534 (liece-channel-real liece-current-channel)
535 (string-times "o" (length ops))
536 (string-join ops " ")))))
538 (defun liece-command-mode+v (voices)
539 "Send a MODE +v VOICES command."
541 (let ((voices (append (liece-channel-get-voices)
542 (liece-channel-get-operators)))
544 (nicks (liece-channel-get-nicks))
545 (completion-ignore-case t)
547 (setq nicks (filter-elements nick nicks
548 (not (string-assoc-ignore-case nick voices)))
549 voices (liece-minibuffer-completing-sequential-read
550 (_ "Set Voice for") 0 (list-to-alist nicks)))
553 (dolist (voice voices)
555 (when (= (length vcs) liece-compress-mode-length)
556 (liece-send "MODE %s +%s %s"
557 (liece-channel-real liece-current-channel)
558 (string-times "v" liece-compress-mode-length)
559 (string-join vcs " "))
562 (liece-send "MODE %s +%s %s"
563 (liece-channel-real liece-current-channel)
564 (string-times "v" (length vcs))
565 (string-join vcs " ")))))
567 (defun liece-command-mode-v (voices)
568 "Send a MODE -v VOICES command."
570 (let ((completion-ignore-case t)
571 (voices (liece-channel-get-voices)) voice nicks)
572 (setq nicks (liece-minibuffer-completing-sequential-read
573 (_ "Unset Voice for") 0 (list-to-alist voices)))
576 (dolist (voice voices)
578 (when (= (length vcs) liece-compress-mode-length)
579 (liece-send "MODE %s -%s %s"
580 (liece-channel-real liece-current-channel)
581 (string-times "v" liece-compress-mode-length)
582 (string-join vcs " "))
585 (liece-send "MODE %s -%s %s"
586 (liece-channel-real liece-current-channel)
587 (string-times "v" (length vcs))
588 (string-join vcs " ")))))
590 (defun liece-command-message (address message)
591 "Send ADDRESS a private MESSAGE."
593 (let ((completion-ignore-case t) address)
595 (liece-channel-virtual
596 (liece-minibuffer-completing-default-read
597 (_ "Private message to: ")
598 (append liece-nick-alist liece-channel-alist)
599 nil nil liece-privmsg-partner)))
603 (_ "Private message to %s: ")
605 (if (funcall liece-message-empty-predicate message)
606 (progn (liece-message (_ "No text to send")) nil)
607 (let ((chnl (liece-channel-real address)))
608 (liece-send "PRIVMSG %s :%s" chnl message)
609 (if (liece-channel-p chnl)
610 (liece-own-channel-message message
611 (liece-channel-virtual address))
612 (liece-own-private-message message address)))))
614 (defun liece-command-mta-private (partner)
615 "Send a private message (current line) to PARTNER."
617 (let ((completion-ignore-case t))
618 (setq liece-privmsg-partner
619 (liece-channel-virtual
620 (liece-minibuffer-completing-default-read
622 (append liece-nick-alist liece-channel-alist)
623 nil nil liece-privmsg-partner)))
624 (list liece-privmsg-partner)))
625 (let ((message (buffer-substring (progn (beginning-of-line) (point))
626 (progn (end-of-line) (point)))))
627 (if (> (length message) 0)
629 (liece-command-message liece-privmsg-partner message)
631 (liece-message (_ "No text to send")))))
633 (defun liece-command-names (&optional expr)
634 "List the nicknames of the current IRC users on given EXPR.
635 With an Control-U as argument, only the current channel is listed.
636 With - as argument, list all channels."
638 (if (or current-prefix-arg (null liece-current-channel))
639 (if (eq current-prefix-arg '-)
640 (list current-prefix-arg))
641 (let ((completion-ignore-case t) expr)
642 (setq expr (liece-minibuffer-completing-default-read
643 (_ "Names on channel: ")
644 liece-channel-alist nil nil liece-current-channel))
645 (unless (string-equal "" expr)
647 (when (or (and (eq expr '-)
649 (_ "Do you really query NAMES without argument?")))
651 (if liece-current-channel
652 (setq expr (liece-channel-real
653 liece-current-channel))))))
656 (liece-send "NAMES %s" expr)))
658 (defun liece-command-nickname (nick)
659 "Set your nickname to NICK."
660 (interactive "sEnter your nickname: ")
661 (let ((nickname (truncate-string nick liece-nick-max-length)))
662 (if (zerop (length nickname))
663 (liece-message (_ "illegal nickname \"%s\"; not changed") nickname)
664 (liece-send "NICK %s" nick))))
666 (defun liece-command-who (&optional expr)
667 "Lists tue users that match the given expression EXPR.
668 If you enter only Control-U as argument, list the current channel.
669 With - as argument, list all users."
671 (if (or current-prefix-arg (null liece-current-channel))
672 (if (eq current-prefix-arg '-)
673 (list current-prefix-arg))
674 (let ((completion-ignore-case t) expr)
675 (setq expr (liece-minibuffer-completing-default-read
676 (_ "WHO expression: ")
677 (append liece-channel-alist liece-nick-alist)))
678 (unless (string-equal "" expr)
680 (when (or (and (eq expr '-)
682 (_ "Do you really query WHO without argument?")))
684 (if liece-current-channel
685 (setq expr (liece-channel-real
686 liece-current-channel))))))
689 (liece-send "WHO %s" expr)
690 (setq liece-who-expression expr)))
692 (defun liece-command-finger (finger-nick-var &optional server)
693 "Get information about a specific user FINGER-NICK-VAR.
694 If called with optional argument SERVER or any prefix argument,
695 query information to the foreign server."
697 (let (finger-nick-var (completion-ignore-case t))
698 (setq finger-nick-var
699 (completing-read (_ "Finger whom: ") liece-nick-alist))
700 (list finger-nick-var (and current-prefix-arg finger-nick-var))))
702 (liece-send "WHOIS %s %s" server finger-nick-var)
703 (liece-send "WHOIS %s" finger-nick-var)))
705 (defun liece-command-topic (topic)
706 "Change TOPIC of the current channel."
708 (list (read-from-minibuffer
709 "Topic: " (cons (or (liece-channel-get-topic) "") 0))))
710 (liece-send "TOPIC %s :%s"
711 (liece-channel-real liece-current-channel) topic))
713 (defun liece-command-invite (&optional invite-nick-var invite-channel-var)
714 "Invite INVITE-NICK-VAR to INVITE-CHANNEL-VAR."
716 (let ((completion-ignore-case t) invite-channel-var invite-nick-var)
717 (if current-prefix-arg
718 (setq invite-channel-var
719 (liece-channel-virtual
721 (_ "Invite channel: ")
722 (list-to-alist liece-current-channels)))))
723 (setq invite-nick-var
727 (list invite-nick-var invite-channel-var)))
728 (or invite-channel-var
729 (setq invite-channel-var liece-current-channel))
730 (liece-send "INVITE %s %s"
731 invite-nick-var (liece-channel-real invite-channel-var)))
733 (defun liece-command-away (awaymsg)
734 "Mark/unmark yourself as being away.
735 Leave message AWAYMSG."
736 (interactive "sAway message: ")
737 (liece-send "AWAY :%s" awaymsg)
738 (setq liece-away-message awaymsg))
740 (defun liece-command-scroll-down (lines)
741 "Scroll LINES down dialogue buffer from command buffer."
743 (let ((other-window-scroll-buffer
744 (if liece-channel-buffer-mode
746 liece-dialogue-buffer)))
747 (when (liece-get-buffer-window other-window-scroll-buffer)
749 (scroll-other-window-down lines)
751 (message "Beginning of buffer"))))))
753 (defun liece-command-scroll-up (lines)
754 "Scroll LINES up dialogue buffer from command buffer."
756 (let* ((other-window-scroll-buffer
757 (if liece-channel-buffer-mode
759 liece-dialogue-buffer)))
760 (when (liece-get-buffer-window other-window-scroll-buffer)
762 (scroll-other-window lines)
764 (message "End of buffer"))))))
766 (defun liece-command-nick-scroll-down (lines)
767 "Scroll LINES down nick buffer from command buffer."
769 (let ((other-window-scroll-buffer liece-nick-buffer))
770 (when (liece-get-buffer-window other-window-scroll-buffer)
772 (scroll-other-window-down lines)
774 (message "Beginning of buffer"))))))
776 (defun liece-command-nick-scroll-up (lines)
777 "Scroll LINES up nick buffer from command buffer."
779 (let* ((other-window-scroll-buffer liece-nick-buffer))
780 (when (liece-get-buffer-window other-window-scroll-buffer)
782 (scroll-other-window lines)
784 (message "End of buffer"))))))
786 (defun liece-command-freeze (&optional arg)
787 "Prevent automatic scrolling of the dialogue window.
788 If prefix argument ARG is non-nil, toggle frozen status."
790 (liece-freeze (if liece-channel-buffer-mode
792 liece-dialogue-buffer)
793 (if arg (prefix-numeric-value arg))))
795 (defun liece-command-own-freeze (&optional arg)
796 "Prevent automatic scrolling of the dialogue window.
797 The difference from `liece-command-freeze' is that your messages are hidden.
798 If prefix argument ARG is non-nil, toggle frozen status."
800 (liece-own-freeze (if liece-channel-buffer-mode
802 liece-dialogue-buffer)
803 (if arg (prefix-numeric-value arg))))
805 (defun liece-command-beep (&optional arg)
806 "Toggle the automatic beep notice when the channel message is received."
808 (liece-set-beep (if liece-channel-buffer-mode
810 liece-dialogue-buffer)
811 (if arg (prefix-numeric-value arg))))
813 (defun liece-command-quit (&optional arg)
815 If prefix argument ARG is non-nil, leave signoff message."
817 (when (and (liece-server-opened)
818 (y-or-n-p (_ "Quit IRC? ")))
821 (if arg (read-string (_ "Signoff message: "))
822 (or liece-signoff-message
823 (product-name (product-find 'liece-version))))))
824 (liece-send "QUIT :%s" quit-string))
827 (if liece-save-variables-are-dirty
828 (liece-command-save-vars))
830 (liece-window-configuration-pop))
831 (run-hooks 'liece-exit-hook)))
833 (defun liece-command-generic (message)
834 "Enter a generic IRC MESSAGE, which is sent to the server.
835 A ? lists the useful generic messages."
836 (interactive "sIRC command (? to help): ")
837 (if (string-equal message "?")
838 (with-output-to-temp-buffer "*IRC Help*"
839 (princ "The following generic IRC messages may be of interest to you:
840 TOPIC <new topic> set the topic of your channel
841 INVITE <nickname> invite another user to join your channel
842 LINKS lists the currently reachable IRC servers
843 SUMMON <user@host> invites an user not currently in IRC
844 USERS <host> lists the users on a host
845 AWAY <reason> marks you as not really actively using IRC
846 (an empty reason clears it)
847 WALL <message> send to everyone on IRC
848 NAMES <channel> lists users per channel
850 (liece-send "%s" message)))
852 (defun liece-command-irc-compatible ()
853 "If entered at column 0, allow you to enter a generic IRC message."
855 (if (zerop (current-column))
856 (call-interactively (function liece-command-generic))
857 (self-insert-command 1)))
859 (defun liece-command-exec (command)
860 "Execute COMMAND, stdout to dialogue."
861 (interactive "sShell command: ")
862 (shell-command command t)
863 (let ((opoint (point)))
864 (while (< (point) (mark))
865 (liece-command-enter-message)
866 (set-buffer liece-command-buffer))
867 (push-mark opoint t)))
869 (defun liece-command-yank-send (&optional arg)
870 "Send message from yank buffer.
871 Prefix argument ARG is regarded as distance from yank pointer."
873 (when (y-or-n-p (_ "Really SEND from Yank Buffer?"))
875 (narrow-to-region (point) (point))
876 (insert (car kill-ring-yank-pointer))
877 (goto-char (point-min))
879 (liece-command-enter-message)
880 (set-buffer liece-command-buffer)))))
882 (defun liece-command-complete ()
883 "Complete word before point from userlist."
885 (let ((completion-ignore-case t)
886 (alist (if liece-current-channel
887 (list-to-alist (liece-channel-get-nicks))
889 candidate completion all)
890 (setq candidate (current-word)
891 completion (try-completion candidate alist)
892 all (all-completions candidate alist))
893 (liece-minibuffer-finalize-completion completion candidate all)))
895 (defun liece-command-load-vars ()
896 "Load configuration from liece-variables-file."
898 (let ((nick liece-real-nickname))
900 (liece-read-variables-files)
901 (setq liece-real-nickname nick)
902 (liece-command-reconfigure-windows))))
904 (defun liece-command-save-vars ()
905 "Save current settings to `liece-variables-file'."
907 (let* ((output-buffer
909 (expand-file-name liece-variables-file)))
912 (set-buffer output-buffer)
913 (goto-char (point-min))
914 (cond ((re-search-forward "^;; Saved Settings *\n" nil 'move)
915 (setq p (match-beginning 0))
917 (or (re-search-forward
918 "^;; End of Saved Settings *\\(\n\\|\\'\\)" nil t)
920 (concat "can't find END of saved state in "
921 liece-variables-file)))
922 (delete-region p (match-end 0)))
924 (goto-char (point-max))
926 (setq output-marker (point-marker))
927 (let ((print-readably t)
928 (print-escape-newlines t)
929 (standard-output output-marker))
930 (princ ";; Saved Settings\n")
931 (dolist (var liece-saved-forms)
933 (prin1 (list 'setq var
934 (let ((val (symbol-value var)))
935 (if (memq val '(t nil))
937 (list 'quote val)))))
938 (setq var (eval var))
939 (cond ((eq (car-safe var) 'progn)
940 (while (setq var (cdr var))
943 (if (cdr var) (princ " "))))
945 (prin1 "xx")(prin1 var))))
946 (if var (princ "\n")))
948 (princ ";; End of Saved Settings\n")))
949 (set-marker output-marker nil)
951 (set-buffer output-buffer)
953 (setq liece-save-variables-are-dirty nil))
955 (defun liece-command-reconfigure-windows ()
956 "Rearrange window splitting."
958 (let ((command-window (liece-get-buffer-window liece-command-buffer))
959 (dialogue-window (liece-get-buffer-window liece-dialogue-buffer))
960 (obuffer (current-buffer)))
961 (if (and command-window dialogue-window)
962 (let ((ch (window-height command-window))
963 (dh (window-height dialogue-window)))
964 (delete-window command-window)
965 (pop-to-buffer liece-dialogue-buffer)
966 (enlarge-window (+ ch dh (- dh))))
967 (pop-to-buffer liece-dialogue-buffer))
968 (liece-configure-windows)
969 (if liece-one-buffer-mode
970 (pop-to-buffer liece-dialogue-buffer)
971 (pop-to-buffer obuffer))))
973 (defun liece-command-end-of-buffer ()
974 "Get end of the dialogue buffer."
977 (setq buffer (if liece-channel-buffer-mode
979 liece-dialogue-buffer))
980 (or (setq window (liece-get-buffer-window buffer))
981 (setq window (liece-get-buffer-window liece-dialogue-buffer)
982 buffer liece-dialogue-buffer))
984 (save-selected-window
985 (select-window window)
986 (goto-char (point-max))))))
988 (defun liece-command-private-conversation (arg)
989 "Toggle between private conversation mode and channel mode.
990 User can then join and part to a private conversation as he would
991 join or part to a channel.
993 If there are no private conversations or argument is given user is
994 prompted the partner/channel (return as partner/channel means toggle
995 mode, the current channel and current chat partner are not altered)
996 Argument ARG is prefix argument of toggle status."
998 (let ((completion-ignore-case t))
1000 (if current-prefix-arg
1001 ;; prefixed, ask where to continue
1002 (if (eq liece-command-buffer-mode 'chat)
1003 (liece-minibuffer-completing-default-read
1004 (_ "Return to channel: ")
1005 (append liece-channel-alist liece-nick-alist)
1006 nil nil liece-current-channel)
1008 (_ "Start private conversation with: ")
1009 liece-nick-alist nil nil))
1010 ;; no prefix, see if going to chat
1011 (if (eq liece-command-buffer-mode 'channel)
1012 ;; and if we have chat partner, select that
1013 (if liece-current-chat-partner
1014 liece-current-chat-partner
1016 (_ "Start private conversation with: ")
1017 liece-nick-alist )))))))
1019 (liece-toggle-command-buffer-mode)
1020 (if (and arg (not (string-equal arg "")))
1021 (liece-command-join arg))
1022 (liece-set-channel-indicator)
1023 ;; refresh mode line
1024 (force-mode-line-update))
1026 (defun liece-command-next-channel ()
1027 "Select next channel or chat partner, and *DONT* rotate list."
1029 (let ((rest (copy-sequence
1030 (if (eq liece-command-buffer-mode 'chat)
1031 liece-current-chat-partners
1032 liece-current-channels)))
1033 (chnl (if (eq liece-command-buffer-mode 'chat)
1034 liece-current-chat-partner
1035 liece-current-channel)))
1036 (liece-switch-to-channel
1037 (or (cadr (liece-channel-member chnl (delq nil rest)))
1038 (car (delq nil rest))
1041 (defun liece-command-previous-channel ()
1042 "Select previous channel or chat partner, and *DONT* rotate list."
1046 (if (eq liece-command-buffer-mode 'chat)
1047 liece-current-chat-partners
1048 liece-current-channels)))
1050 (if (eq liece-command-buffer-mode 'chat)
1051 liece-current-chat-partner
1052 liece-current-channel)))
1053 (liece-switch-to-channel
1054 (or (cadr (liece-channel-member chnl (delq nil rest)))
1055 (car (delq nil rest))
1058 (defun liece-command-unread-channel ()
1059 "Select unread channel or chat partner."
1061 (let ((chnl (car liece-channel-unread-list)))
1063 (liece-switch-to-channel chnl)
1064 (liece-message (_ "No unread channel or chat partner.")))))
1066 (defun liece-command-push ()
1067 "Select next channel or chat partner, and rotate list."
1070 (if (eq liece-command-buffer-mode 'chat)
1071 liece-current-chat-partners
1072 liece-current-channels))
1073 (temp (car (last rest)))
1074 (len (length rest)))
1077 (setcar (nthcdr (1- len) rest) (nth (- len 2) rest))
1080 (setcar rest temp)))
1081 (liece-channel-change)))
1083 (defun liece-command-pop ()
1084 "Select previous channel or chat partner, and rotate list."
1087 (if (eq liece-command-buffer-mode 'chat)
1088 liece-current-chat-partners
1089 liece-current-channels))
1091 (len (length rest)))
1094 (setcar (nthcdr i rest) (nth (1+ i) rest)))
1096 (setcar (last rest) temp)))
1097 (liece-channel-change)))
1099 (defvar liece-redisplay-buffer-functions
1100 '(liece-channel-redisplay-buffer
1101 liece-nick-redisplay-buffer
1102 liece-channel-list-redisplay-buffer))
1104 (defun liece-switch-to-channel (chnl)
1105 "Switch the current channel to CHNL."
1106 (if (liece-channel-p (liece-channel-real chnl))
1108 (liece-toggle-command-buffer-mode 'channel)
1109 (setq liece-current-channel chnl)
1110 (liece-set-channel-indicator))
1111 (liece-toggle-command-buffer-mode 'chat)
1112 (setq liece-current-chat-partner chnl)
1113 (liece-set-channel-indicator))
1115 (run-hook-with-args 'liece-redisplay-buffer-functions chnl)))
1117 (defun liece-switch-to-channel-no (num)
1118 "Switch the current channel to NUM."
1119 (let* ((mode liece-command-buffer-mode)
1120 (chnls (if (eq mode 'chat)
1121 liece-current-chat-partners
1122 liece-current-channels)))
1123 (if (and (integerp num)
1124 (stringp (nth num chnls)))
1125 (let ((chnl (nth num chnls)))
1128 (liece-toggle-command-buffer-mode 'chat)
1129 (setq liece-current-chat-partner chnl)
1130 (liece-set-channel-indicator))
1131 (liece-toggle-command-buffer-mode 'channel)
1132 (setq liece-current-channel chnl)
1133 (liece-set-channel-indicator))
1135 (run-hook-with-args 'liece-redisplay-buffer-functions chnl)))
1136 (message "Invalid channel!"))))
1138 (defun liece-command-ping ()
1139 "Send PING to server."
1141 (if (stringp liece-server-name)
1142 (liece-send "PING %s" liece-server-name)))
1144 (defun liece-command-ison (nicks)
1147 (let (nicks (completion-ignore-case t))
1148 (setq nicks (liece-minibuffer-completing-sequential-read
1149 "IsON" 0 liece-nick-alist))
1151 (liece-send "ISON :%s" (mapconcat #'identity nicks " ")))
1153 (defun liece-command-activate-friends (nicks)
1154 "Register NICKS to the frinends list."
1156 (let (nicks (completion-ignore-case t))
1158 (liece-minibuffer-completing-sequential-read
1160 (filter-elements nick liece-nick-alist
1161 (not (string-list-member-ignore-case
1162 (car nick) liece-friends)))))
1164 (setq liece-friends (append nicks liece-friends)))
1166 (defun liece-command-deactivate-friends ()
1167 "Clear current friends list."
1169 (setq liece-friends nil))
1171 (defun liece-command-display-friends ()
1172 "Display status of the friends."
1174 (with-output-to-temp-buffer " *IRC Friends*"
1175 (set-buffer standard-output)
1176 (insert "Friends status: \n\n")
1177 (dolist (friend liece-friends)
1178 (if (string-list-member-ignore-case friend liece-friends-last)
1179 (insert "+ " friend "\n")
1180 (insert "- " friend "\n")))))
1182 (defun liece-command-userhost (nicks)
1183 "Ask for the hostnames of NICKS."
1185 (let (nicks (completion-ignore-case t))
1186 (setq nicks (liece-minibuffer-completing-sequential-read
1187 (_ "Userhost nick") 0
1188 (list-to-alist liece-nick-alist)))
1190 (liece-send "USERHOST :%s" (mapconcat 'identity nicks ",")))
1192 (defun liece-command-show-last-kill ()
1193 "Dig last kill from KILL and show it."
1196 (append liece-D-buffer liece-O-buffer)
1198 (set-buffer liece-KILLS-buffer)
1199 (goto-char (point-max))
1201 (concat (buffer-substring (point) (point-max)) "\n"))))
1203 (defun liece-command-toggle-private ()
1204 "Toggle private mode / channel mode."
1206 (case (prog1 liece-command-buffer-mode
1207 (liece-toggle-command-buffer-mode))
1209 (if liece-current-channel
1210 (liece-switch-to-channel liece-current-channel))
1211 (setq liece-command-buffer-mode-indicator "Channels"))
1213 (if liece-current-chat-partner
1214 (liece-switch-to-channel liece-current-chat-partner))
1215 (setq liece-command-buffer-mode-indicator "Partners")))
1216 (liece-channel-change))
1218 (defun liece-command-tag-region (start end)
1219 "Move current region between START and END to `kill-ring'."
1221 (if (region-active-p)
1222 (list (region-beginning)(region-end))
1223 (list (line-beginning-position)(line-end-position))))
1224 (static-if (fboundp 'extent-property)
1225 (kill-ring-save start end)
1226 (let ((start (set-marker (make-marker) start))
1227 (end (set-marker (make-marker) end))
1228 (inhibit-read-only t)
1231 (liece-remove-properties-region start end)
1232 (kill-ring-save start end)
1233 (push nil buffer-undo-list)
1236 (provide 'liece-commands)
1238 ;;; liece-commands.el ends here