;;; see file irchat-copyright.el for change log and copyright info

;; irchat-2.4jp version by kick@wide.ad.jp (1994/03/17 - 1998/12/21)
;; Copyright (C) 1994,1995,1996,1997,1998 KIKUCHI Takahiro

;; irchat-pj 2.4.24.x version by simm@irc.fan.gr.jp (1999/01/16-2002/07/19)
;; Copyright (C) 1998-2002 irchat-PJ Project

;; modified by simm@irc.fan.gr.jp, Wed, 05 Jan 2000 02:51:10 +0900
(or (fboundp 'defsubst)
    (fset 'defsubst 'defun))

(require 'irchat-commands)
(require 'irchat-handle)
(require 'irchat-inlines)
(require 'irchat-filter)
(require 'irchat-vars)
(require 'irchat-pj-jisx0201)
(require 'irchat-pj-modeline)
(require 'irchat-pj-coding-system)
(require 'irchat-pj-version-string)
(require 'irchat-pj-sound)
(require 'irchat-pj-action)

(provide 'irchat)

(defconst irchat-ctcp-error-msg "Unrecognized command: '%s'"
  "*Error message given to anyone asking wrong CTCP command.")

(defvar irchat-ctcp-lastcommand nil
  "*Place to keep last entered command")

(defvar irchat-ctcp-lastnick nil
  "*Place to keep last queried nick")

(defvar kanji-flag nil) ;; for original emacs and mule
(defun irchat-mule-version ()
    (and (boundp 'MULE)
	 (string-match "^[0-9.]*" mule-version)
	 (concat "Mule-"
		 (substring mule-version (match-beginning 0) (match-end 0)))))

(defvar irchat-system-fqdname (system-name)
  "*The fully qualified domain name of the system.
Default is what (system-name) returns.")

(if irchat-want-traditional
    (defvar irchat-command-window-on-top nil
      "*If non-nil, the Command window will be put at the top of the screen.
Else it is put at the bottom.")

  (defvar irchat-command-window-on-top t
    "*If non-nil, the Command window will be put at the top of the screen.
Else it is put at the bottom."))
  
(defvar irchat-use-full-window t
  "*If non-nil, IRCHAT will use whole emacs window. Annoying for GNUS-
users, therefore added by nam.")

(defvar irchat-ignore-changes nil
  "*Ignore changes? Good in topic-wars/link troubles.")

(defvar irchat-ignore-noauths nil
  "*If non nil, ignore no-auth notices if receiving them.")

(defvar irchat-ignore-fakes nil
  "*If non nil, ignore fake notices if receiving them.")

(defvar irchat-ignore-kills nil
  "*If non nil, ignore kill notices if receiving them.")

(defvar irchat-display-channel-always nil
  "*If non nil, display channel name still in channel buffer.")

(defvar irchat-default-freeze-local t
  "*If non nil, channel buffer local freeze flag is on at starting.")

(defsubst irchat-channel-freeze-local (chan value)
  (put (intern chan) 'freeze value))

(defvar irchat-default-beep-local nil
  "*If non nil, channel buffer local beep flag is on at starting.")

(defsubst irchat-channel-beep-local (chan value)
  (put (intern chan) 'beep value))

(defvar irchat-default-suppress-local nil
  "*If non nil, channel buffer local suppress flag is on at starting.")

(defsubst irchat-channel-suppress-local (chan value)
  (put (intern chan) 'suppress value))

(defvar irchat-message-try-to-connect-server nil
  "*If non nil, notify to mini buffer when trying to connect server.")

(defvar irchat-reconnect-automagic nil
  "*Automatic reconnection, default is disabled")

(defvar irchat-ask-for-nickname nil
  "*Ask for nickname if irchat was entered with \\[universal-argument].")

(defvar irchat-ask-for-password nil
  "*Ask for password when connecting to server.")

(defvar irchat-ask-for-channel-password nil
  "*Ask for channel password when joining channel with password.")

(defvar irchat-reconnect-with-password nil
  "*auto recconect to server with password after incorrect password.")

(defvar irchat-blink-parens t
  "*Should we blink matching parenthesis in irchat command buffer?")

(defvar irchat-one-buffer-mode nil
  "*When non-nil, irchat will put up only a dialogue-buffer (on the
screen). Useful for those (perverts) who use 24 line terminals.")

(defvar irchat-channel-buffer-mode nil
  "*When non-nil, irchat will display a channel buffer.")

(defvar irchat-channel-filter "" 
  "*Enables use of \\[universal-argument] with NAMES and TOPIC.")

(defvar irchat-how-to-show-links-reply nil
  "*how to show LINKS reply.")

(defvar irchat-links-reply-count 0
  "*the number of LINKS reply.")

(defvar irchat-long-reply-count 0
  "*the number of NAMES/LIST/WHO reply.")

(defvar irchat-no-configure-windows t
  "*not yet configure windows")

(defvar irchat-fatal-error-message nil
  "*ERROR message")

(defvar irchat-while-whois-reply nil
  "*true while whois reply.")

(defvar irchat-auto-whois-nick ""
  "*nick which automatically whois.")

(defvar irchat-nickname-already-in-use nil
  "*Need ask another nickname.")

(defvar irchat-nickname-erroneus nil
  "*Need ask another nickname.")

(defvar irchat-grow-tail "_"
  "*Add irchat-grow-tail to nick when reconnecting. Otherwise you might get
killed again if automagic reconnect is too fast.")

(defvar irchat-shorten-kills t
  "*Shorten KILL messages to about one line.")

(defvar irchat-invited-channel)
(setq irchat-invited-channel nil)

(defvar irchat-Command-mode-hook nil
  "*A hook for IRCHAT Command mode.")

(defvar irchat-Dialogue-mode-hook nil
  "*A hook for IRCHAT Dialogue mode.")

(defvar irchat-Others-mode-hook nil
  "*A hook for IRCHAT Others mode.")

(defvar irchat-Channel-mode-hook nil
  "*A hook for IRCHAT Current channel mode.")

(defvar irchat-Exit-hook nil
  "*A hook executed when signing off IRC.")

(defvar irchat-ignore-nickname nil
  "*A list of nicknames, as symbols, to ignore.  Messages from these people
won't be displayed.")

(defvar irchat-kill-realname nil
  "*A list of real names of people to ignore. Messages from them
won't be displayed.")

(defvar irchat-kill-logon nil
  "*A list of logon names (user@host.dom.ain). Messages from them
won't be displayed.")

(defvar irchat-buggy-emacs-pos-visible-in-window-p nil
  "*You should set non-nil if your emacs has buggy pos-visible-in-window-p.")

(defvar irchat-trying-nickname nil
  "the nickname that I'm trying to be.")

;; add by simm@irc.fan.gr.jp, Mon, 08 Nov 1999 02:57:29 +0900
(defvar irchat-pj-startup-nickname-rest nil
  "rest nickname list when startup")

(defvar irchat-old-window-configuration nil
  "the window configuration before starting irchat.")

(defvar irchat-after-registration nil
  "after my registration")

(defvar irchat-debugging nil
  "for debugging only")

;; Define hooks for each IRC message the server might send us.
;; The newer IRC servers use numeric reply codes instead of words.

(defvar irchat-msg-list
  '(channel error invite linreply msg namreply nick ping pong quit2
    privmsg quit topic wall whoreply kill wallops mode kick part join
    200 203 204 205 206 209 211 212 213 214 215 216 217 218 219
    301 311 312 313 314 315 317 318 321 322 323 331 332 341 
    351 352 353 361 364 365 366 367 368 371 372 381 382 391
    401 402 403 411 412 421 431 432 433 441 451 461 462 463 
    464 465 471 472 473 474 481 482 491)
  "A list of the IRC messages and numeric reply codes irchat can handle.")


(mapcar (function
	 (lambda (sym)
	   (eval (list 'defvar (intern (concat "irchat-"
					       (prin1-to-string sym)
					       "-hook"))
		       nil
		       (concat "*A hook that is executed when the IRC "
				 "message \"" (upcase (prin1-to-string sym))
				 "\" is received.
The hook function is called with two arguments, PREFIX and REST-OF-LINE.
It should return non NIL if no further processing of the message is to be
carried out.")))))
	irchat-msg-list)

(defvar irchat-current-channel nil
  "The channel you currently have joined.")

(defvar irchat-current-channels nil
  "The channels you have currently joined.")

(defvar irchat-chanbuf-num 0
  "The channel buffer you currently have selected.")

(defvar irchat-chanbuf-list nil
  "The channel buffers list you have currently joined.")

(defvar irchat-chanbuf-indicator "Private"
  "The current channel buffer, \"pretty-printed.\"")

(defvar irchat-chanbufs-indicator "No channel"
  "The channel buffers list, \"pretty-printed.\"")

(defvar irchat-polling nil
  "T when we are automatically polling the server.")

(defvar irchat-last-poll-minute nil
  "The minute when we last polled the server.")

(defvar irchat-last-timestamp 0
  "The minute we inserted the previous timestamp")

(defvar irchat-previous-pattern nil )

(defvar irchat-freeze nil
  "If non-nil the Dialogue window will not be scrolled automatically to bring
new entries into view.")

(defvar irchat-privmsg-partner nil
  "The person who got your last private message.")

(defvar irchat-current-chat-partner nil
  "The person you are in a private conversation with.")

(defvar irchat-current-chat-partners nil
  "An list containing nics user is chatting with.")

(defvar irchat-chat-partner-alist nil
  "An alist containing nics user is chatting with.")

(defvar irchat-command-buffer-mode 'channel
  "symbol chat or channel depending on which is current mode at 
command buffer.")

(defvar irchat-nick-alist nil
  "An alist containing the nicknames of users known to currently be on IRC.
Each element in the list is a list containing a nickname.")

(defvar irchat-channel-alist nil 
  "An alist containing the channels on IRC.  Each element in the list is 
a list containing a channel name.")

(defvar irchat-userhost ""
  "The user@host for the current line.")

(defvar irchat-debug-buffer nil)
(defvar irchat-server-buffer nil)
(defvar irchat-server-name nil)
(defvar irchat-my-userhost nil)
(defvar irchat-my-user nil)
(defvar irchat-my-host nil)
(defvar irchat-my-server nil)

;; begin: modified by simm@irc.fan.gr.jp, Wed, 21 Jul 1999
(defvar irchat-buffer-base " IRC:")
(defvar irchat-Command-buffer "*IRC*")
(defvar irchat-Dialogue-buffer (concat irchat-buffer-base " Dialogue"))
(defvar irchat-Others-buffer (concat irchat-buffer-base " Others"))
(defvar irchat-Private-buffer (concat irchat-buffer-base " Private"))
(defvar irchat-Channel-buffer nil)
(defvar irchat-KILLS-buffer  (concat irchat-buffer-base " KILLS"))
(defvar irchat-IGNORED-buffer (concat irchat-buffer-base " IGNORED"))
(defvar irchat-WALLOPS-buffer (concat irchat-buffer-base " WALLOPS"))
(defvar irchat-pj-CONVERT-buffer (concat irchat-buffer-base " CONVERT"))
(defvar irchat-show-wallops t)
;; end

(defvar irchat-server-process nil)
(defvar irchat-status-message-string nil)

(defvar irchat-command-map nil)
(defvar irchat-Command-mode-map nil)
(defvar irchat-Dialogue-mode-map nil)
(defvar irchat-Others-mode-map nil)
(defvar irchat-Channel-mode-map nil)
(defvar irchat-CTCP-command-map nil)
(defvar irchat-DCC-command-map nil)
(defvar irchat-STATS-command-map nil)
(defvar irchat-buffer-switch-map nil)

(put 'irchat-Command-mode 'mode-class 'special)
(put 'irchat-Dialogue-mode 'mode-class 'special)
(put 'irchat-Others-mode 'mode-class 'special)
(put 'irchat-Channel-mode 'mode-class 'special)

(if irchat-command-map
    nil
  (define-prefix-command 'irchat-command-map)
  (setq irchat-command-map (make-keymap))
  (fset 'irchat-command-prefix irchat-command-map)
  (define-key irchat-command-map "0" 'irchat-Command-jump-channel0)
  (define-key irchat-command-map "1" 'irchat-Command-jump-channel1)
  (define-key irchat-command-map "2" 'irchat-Command-jump-channel2)
  (define-key irchat-command-map "3" 'irchat-Command-jump-channel3)
  (define-key irchat-command-map "4" 'irchat-Command-jump-channel4)
  (define-key irchat-command-map "5" 'irchat-Command-jump-channel5)
  (define-key irchat-command-map "6" 'irchat-Command-jump-channel6)
  (define-key irchat-command-map "7" 'irchat-Command-jump-channel7)
  (define-key irchat-command-map "8" 'irchat-Command-jump-channel8)
  (define-key irchat-command-map "9" 'irchat-Command-jump-channel9)
  (define-key irchat-command-map "\C-a" 'irchat-Command-alternative-channel)
  (define-key irchat-command-map "A" 'irchat-Command-admin)
  (define-key irchat-command-map "a" 'irchat-Command-away)
  (define-key irchat-command-map "\C-b" 'irchat-buffer-switch-prefix)
  (define-key irchat-command-map "B" 'irchat-Command-beep-on-message)
  (define-key irchat-command-map "b" 'irchat-Command-scroll-down)
  (define-key irchat-command-map "\C-c" 'irchat-CTCP-command-prefix)
  (define-key irchat-command-map "c" 'irchat-Command-inline)
  (define-key irchat-command-map "\C-d" 'irchat-DCC-command-prefix)
  (define-key irchat-command-map "D" 'irchat-Command-debug)
  (define-key irchat-command-map "\C-f" 'irchat-Command-scroll-freeze)
  (define-key irchat-command-map "F" 'irchat-Command-finger-direct)
  (define-key irchat-command-map "f" 'irchat-Command-finger)
  (define-key irchat-command-map "\C-i" 'irchat-Command-ignore)
  (define-key irchat-command-map "i" 'irchat-Command-invite)
  (define-key irchat-command-map "\C-j" 'irchat-Command-next-channel)
  (define-key irchat-command-map "j" 'irchat-Command-join)
  (define-key irchat-command-map "\C-k" 'irchat-Command-kick)
  (define-key irchat-command-map "\C-l" 'irchat-Command-redisplay)
  (define-key irchat-command-map "L" 'irchat-Command-load-vars)
  (define-key irchat-command-map "l" 'irchat-Command-list)
  (define-key irchat-command-map "M" 'irchat-pj-Command-broadcast-minibuffer)
  (define-key irchat-command-map "m" 'irchat-Command-send-minibuffer)
  (define-key irchat-command-map "\C-m" 'irchat-Command-modec)
  (define-key irchat-command-map "\C-n" 'irchat-Command-names)
  (define-key irchat-command-map "n" 'irchat-Command-nickname)
  (define-key irchat-command-map "\C-o" 'irchat-Command-toggle-display-mode)
  (define-key irchat-command-map "o" 'irchat-Command-ison)
  (define-key irchat-command-map "\C-p" 'irchat-Command-part)
  (define-key irchat-command-map "P" 'irchat-Channel-ctcp-ping)
  (define-key irchat-command-map "p" 'irchat-Command-send-private)
  (define-key irchat-command-map "q" 'irchat-Command-quit)
  (define-key irchat-command-map "\C-r" 'irchat-Command-caesar-line)
  (define-key irchat-command-map "r" 'irchat-Command-reconfigure-windows)
  (define-key irchat-command-map "\C-s" 'irchat-STATS-command-prefix)
  (define-key irchat-command-map "S" 'irchat-Command-suppress-others)
  (define-key irchat-command-map "s" 'irchat-Command-servers)
  (define-key irchat-command-map "\C-t" 'irchat-Command-trace)
  (define-key irchat-command-map "T" 'irchat-Channel-ctcp-time)
  (define-key irchat-command-map "t" 'irchat-Command-topic)
  (define-key irchat-command-map "\C-u" 'irchat-Command-userhost)
  (define-key irchat-command-map "U" 'irchat-Channel-ctcp-userinfo)
  (define-key irchat-command-map "u" 'irchat-Command-users)
  (define-key irchat-command-map "V" 'irchat-Channel-ctcp-version)
  (define-key irchat-command-map "v" 'irchat-Command-version)
  (define-key irchat-command-map "w" 'irchat-Command-who)
  (define-key irchat-command-map "W" 'irchat-Command-wait)
  (define-key irchat-command-map "\C-y" 'irchat-Command-send-yank)
  (define-key irchat-command-map "Y" 'irchat-Command-debug-user)
  (define-key irchat-command-map "z" 'irchat-pj-Command-broadcast-message)
  (define-key irchat-command-map "\C-?" 'irchat-Command-scroll-down)
  (define-key irchat-command-map " " 'irchat-Command-scroll-up)
  (define-key irchat-command-map "!" 'irchat-Command-send-exec)
  (define-key irchat-command-map "$" 'irchat-Command-eod-buffer)
  (define-key irchat-command-map ">" 'irchat-Command-next-channel)
  (define-key irchat-command-map "<" 'irchat-Command-previous-channel)
  (define-key irchat-command-map "/" 'irchat-Command-generic))

(if irchat-CTCP-command-map
    nil
  (define-prefix-command 'irchat-CTCP-command-map)
  (setq irchat-CTCP-command-map (make-keymap))
  (fset 'irchat-CTCP-command-prefix irchat-CTCP-command-map)
  (define-key irchat-CTCP-command-map "0" 'irchat-Command-jump-channel10)
  (define-key irchat-CTCP-command-map "1" 'irchat-Command-jump-channel11)
  (define-key irchat-CTCP-command-map "2" 'irchat-Command-jump-channel12)
  (define-key irchat-CTCP-command-map "3" 'irchat-Command-jump-channel13)
  (define-key irchat-CTCP-command-map "4" 'irchat-Command-jump-channel14)
  (define-key irchat-CTCP-command-map "5" 'irchat-Command-jump-channel15)
  (define-key irchat-CTCP-command-map "6" 'irchat-Command-jump-channel16)
  (define-key irchat-CTCP-command-map "7" 'irchat-Command-jump-channel17)
  (define-key irchat-CTCP-command-map "8" 'irchat-Command-jump-channel18) 
  (define-key irchat-CTCP-command-map "9" 'irchat-Command-jump-channel19)
  (define-key irchat-CTCP-command-map "g" 'irchat-Command-ctcp-generic)
  (define-key irchat-CTCP-command-map "v" 'irchat-Command-ctcp-version)
  (define-key irchat-CTCP-command-map "t" 'irchat-Command-ctcp-time)
  (define-key irchat-CTCP-command-map "f" 'irchat-Command-ctcp-finger)
  (define-key irchat-CTCP-command-map "a" 'irchat-Command-ctcp-action)
  (define-key irchat-CTCP-command-map "r" 'irchat-Command-ctcp-caesar)
  (define-key irchat-CTCP-command-map "u" 'irchat-Command-ctcp-userinfo)
  (define-key irchat-CTCP-command-map "p" 'irchat-Command-ctcp-ping)
  (define-key irchat-CTCP-command-map "c" 'irchat-Command-ctcp-clientinfo)
  (define-key irchat-CTCP-command-map "\C-c"
    'irchat-Command-ctcp-clientinfo-generic)
  (define-key irchat-CTCP-command-map "U" 
    'irchat-Command-ctcp-userinfo-from-minibuffer)
  (define-key irchat-CTCP-command-map "\C-u" 
    'irchat-Command-ctcp-userinfo-from-commandbuffer)
  )


(if irchat-DCC-command-map
    nil
  (define-prefix-command 'irchat-DCC-command-map)
  (setq irchat-DCC-command-map (make-keymap))
  (fset 'irchat-DCC-command-prefix irchat-DCC-command-map)
  (define-key irchat-DCC-command-map "c" 'irchat-Command-dcc-chat)
  (define-key irchat-DCC-command-map "g" 'irchat-Command-dcc-get)
  (define-key irchat-DCC-command-map "k" 'irchat-Command-dcc-kill)
  (define-key irchat-DCC-command-map "l" 'irchat-Command-dcc-list)
  (define-key irchat-DCC-command-map "s" 'irchat-Command-dcc-send)
  )

(if irchat-STATS-command-map
    nil
  (define-prefix-command 'irchat-STATS-command-map)
  (setq irchat-STATS-command-map (make-keymap))
  (fset 'irchat-STATS-command-prefix irchat-STATS-command-map)
  (define-key irchat-STATS-command-map "c" 'irchat-Command-stats-connection)
  )
(defun irchat-Command-stats-connection ()
  (interactive)
  (if current-prefix-arg
      (irchat-send "STATS C %s" "")
    (irchat-send "STATS C")))


(if irchat-buffer-switch-map
    nil
  (define-prefix-command 'irchat-buffer-switch-map)
  (setq irchat-buffer-switch-map (make-keymap))
  (fset 'irchat-buffer-switch-prefix irchat-buffer-switch-map)
  (define-key irchat-buffer-switch-map "k" 'irchat-buffer-switch-kill)
  )
(defun irchat-buffer-switch-kill ()
  (interactive)
  (switch-to-buffer-other-window irchat-KILLS-buffer)
  nil)


(if irchat-Others-mode-map
    nil
  (setq irchat-Others-mode-map (make-keymap))
  (suppress-keymap irchat-Others-mode-map t)
  (let ((i 0))
    (while (< i 128)
      (define-key irchat-Others-mode-map (format "%c" i) 'other-window)
      (setq i (1+ i))))
  (define-key irchat-Others-mode-map "\C-[" nil))

(if irchat-Channel-mode-map
    nil
  (setq irchat-Channel-mode-map (make-keymap))
  (suppress-keymap irchat-Channel-mode-map)
  (define-key irchat-Channel-mode-map "0" 'irchat-Command-jump-channel0)
  (define-key irchat-Channel-mode-map "1" 'irchat-Command-jump-channel1)
  (define-key irchat-Channel-mode-map "2" 'irchat-Command-jump-channel2)
  (define-key irchat-Channel-mode-map "3" 'irchat-Command-jump-channel3)
  (define-key irchat-Channel-mode-map "4" 'irchat-Command-jump-channel4)
  (define-key irchat-Channel-mode-map "5" 'irchat-Command-jump-channel5)
  (define-key irchat-Channel-mode-map "6" 'irchat-Command-jump-channel6)
  (define-key irchat-Channel-mode-map "7" 'irchat-Command-jump-channel7)
  (define-key irchat-Channel-mode-map "8" 'irchat-Command-jump-channel8)
  (define-key irchat-Channel-mode-map "9" 'irchat-Command-jump-channel9)
  (define-key irchat-Channel-mode-map "a" 'irchat-Command-away)
  (define-key irchat-Channel-mode-map "A" 'irchat-Command-alternative-channel)
  (define-key irchat-Channel-mode-map "B" 'irchat-Command-beep-on-message)
  (define-key irchat-Channel-mode-map "b" 'irchat-Current-scroll-down)
  (define-key irchat-Channel-mode-map "F" 'irchat-Command-finger-direct)
  (define-key irchat-Channel-mode-map "f" 'irchat-Channel-freeze)
  (define-key irchat-Channel-mode-map "i" 'irchat-Command-invite)
  (define-key irchat-Channel-mode-map "J" 'irchat-Command-next-channel)
  (define-key irchat-Channel-mode-map "j" 'irchat-Command-join)
  (define-key irchat-Channel-mode-map "L" 'irchat-Command-load-vars)
  (define-key irchat-Channel-mode-map "l" 'irchat-Command-list)
  (define-key irchat-Channel-mode-map "m" 'irchat-Command-modec)
  (define-key irchat-Channel-mode-map "n" 'irchat-Command-names)
  (define-key irchat-Channel-mode-map "o" 'other-window)
  (define-key irchat-Channel-mode-map "p" 'irchat-Command-part)
  (define-key irchat-Channel-mode-map "r" 'irchat-Command-reconfigure-windows)
  (define-key irchat-Channel-mode-map "S" 'irchat-Command-suppress-others)
  (define-key irchat-Channel-mode-map "t" 'irchat-Command-topic)
  (define-key irchat-Channel-mode-map "u" 'irchat-Command-users)
  (define-key irchat-Channel-mode-map "v" 'irchat-Command-version)
  (define-key irchat-Channel-mode-map "w" 'irchat-Command-who)
  (define-key irchat-Channel-mode-map "!" 'irchat-Command-send-exec)
  (define-key irchat-Channel-mode-map "$" 'end-of-buffer)
  (define-key irchat-Channel-mode-map "/" 'irchat-Command-generic)
  (define-key irchat-Channel-mode-map ">" 'irchat-Command-next-channel)
  (define-key irchat-Channel-mode-map "<" 'irchat-Command-previous-channel)
  (define-key irchat-Channel-mode-map " " 'irchat-Current-scroll-up)
  (define-key irchat-Channel-mode-map "\C-?" 'irchat-Current-scroll-down)
  (define-key irchat-Channel-mode-map "\C-n" 'forward-line)
  (define-key irchat-Channel-mode-map "\C-m" 'irchat-Command-enter-message)
  (define-key irchat-Channel-mode-map "\C-c" 'irchat-command-prefix))

(if irchat-Dialogue-mode-map
    nil
  (setq irchat-Dialogue-mode-map (make-keymap))
  (suppress-keymap irchat-Dialogue-mode-map)
  (define-key irchat-Dialogue-mode-map "0" 'irchat-Command-jump-channel0)
  (define-key irchat-Dialogue-mode-map "1" 'irchat-Command-jump-channel1)
  (define-key irchat-Dialogue-mode-map "2" 'irchat-Command-jump-channel2)
  (define-key irchat-Dialogue-mode-map "3" 'irchat-Command-jump-channel3)
  (define-key irchat-Dialogue-mode-map "4" 'irchat-Command-jump-channel4)
  (define-key irchat-Dialogue-mode-map "5" 'irchat-Command-jump-channel5)
  (define-key irchat-Dialogue-mode-map "6" 'irchat-Command-jump-channel6)
  (define-key irchat-Dialogue-mode-map "7" 'irchat-Command-jump-channel7)
  (define-key irchat-Dialogue-mode-map "8" 'irchat-Command-jump-channel8)
  (define-key irchat-Dialogue-mode-map "9" 'irchat-Command-jump-channel9)
  (define-key irchat-Dialogue-mode-map "A" 'irchat-Command-alternative-channel)
  (define-key irchat-Dialogue-mode-map "a" 'irchat-Command-away)
  (define-key irchat-Dialogue-mode-map "b" 'irchat-Current-scroll-down)
  (define-key irchat-Dialogue-mode-map "F" 'irchat-Command-finger-direct)
  (define-key irchat-Dialogue-mode-map "f" 'irchat-Dialogue-freeze)
  (define-key irchat-Dialogue-mode-map "i" 'irchat-Command-invite)
  (define-key irchat-Dialogue-mode-map "J" 'irchat-Command-next-channel)
  (define-key irchat-Dialogue-mode-map "j" 'irchat-Command-join)
  (define-key irchat-Dialogue-mode-map "L" 'irchat-Command-load-vars)
  (define-key irchat-Dialogue-mode-map "l" 'irchat-Command-list)
  (define-key irchat-Dialogue-mode-map "m" 'irchat-Command-modec)
  (define-key irchat-Dialogue-mode-map "n" 'irchat-Command-names)
  (define-key irchat-Dialogue-mode-map "o" 'other-window)
  (define-key irchat-Dialogue-mode-map "p" 'irchat-Command-part)
  (define-key irchat-Dialogue-mode-map "r" 'irchat-Command-reconfigure-windows)
  (define-key irchat-Dialogue-mode-map "t" 'irchat-Command-topic)
  (define-key irchat-Dialogue-mode-map "u" 'irchat-Command-users)
  (define-key irchat-Dialogue-mode-map "v" 'irchat-Command-version)
  (define-key irchat-Dialogue-mode-map "w" 'irchat-Command-who)
  (define-key irchat-Dialogue-mode-map "!" 'irchat-Command-send-exec)
  (define-key irchat-Dialogue-mode-map "$" 'end-of-buffer)
  (define-key irchat-Dialogue-mode-map "/" 'irchat-Command-generic)
  (define-key irchat-Dialogue-mode-map ">" 'irchat-Command-next-channel)
  (define-key irchat-Dialogue-mode-map "<" 'irchat-Command-previous-channel)
  (define-key irchat-Dialogue-mode-map " " 'irchat-Current-scroll-up)
  (define-key irchat-Dialogue-mode-map "\C-?" 'irchat-Current-scroll-down)
  (define-key irchat-Dialogue-mode-map "\C-n" 'forward-line)
  (define-key irchat-Dialogue-mode-map "\C-m" 'irchat-Command-enter-message)
  (define-key irchat-Dialogue-mode-map "\C-c" 'irchat-command-prefix))

(if irchat-Command-mode-map
    nil
  (setq irchat-Command-mode-map (make-sparse-keymap))
;;(define-key irchat-Command-mode-map "/" 'irchat-Command-irc-compatible)
  (define-key irchat-Command-mode-map "\C-[\C-i" 'lisp-complete-symbol)
  (define-key irchat-Command-mode-map "\C-i" 'irchat-Command-complete)
  (define-key irchat-Command-mode-map "\C-m" 'irchat-pj-Command-send-line)
  (define-key irchat-Command-mode-map "\C-c" 'irchat-command-prefix))

;;;
;;;
;;;

(defun irchat (&optional confirm)
  "Connect to the IRC server and start chatting.
If optional argument CONFIRM is non-nil, ask which IRC server to connect.
If already connected, just pop up the windows."
  (interactive "P")
  (if (fboundp 'add-hook)
      (add-hook 'kill-emacs-hook 'irchat-quit))
  (if (file-exists-p (expand-file-name irchat-variables-file))
      (load (expand-file-name irchat-variables-file)))
  (if (irchat-server-opened)
      (irchat-configure-windows)
    (unwind-protect
	(progn
	  (setq irchat-fatal-error-message nil)
	  (irchat-Command-setup-buffer)
	  (irchat-start-server confirm))
      (if (not (irchat-server-opened))
	  (irchat-Command-quit 'error)
	;; IRC server is successfully open. 
	(irchat-pj-window-init)
	(setq irchat-pj-initialize-p  t
	      irchat-current-channels nil
	      irchat-chanbuf-list     nil)
	(run-hooks 'irchat-Startup-hook)
	(irchat-pj-startup-check-nick)
	(irchat-pj-startup-join)
	(irchat-Channel-select 0)
	(irchat-Channel-change)
	(irchat-Command-describe-briefly)))))

;; split by simm@irc.fan.gr.jp, Mon, 24 Jan 2000 19:12:24 +0900
(defun irchat-pj-window-init ()
  "Window initialization for irchat-pj"
  (if (not  irchat-old-window-configuration)
      (setq irchat-old-window-configuration
	    (current-window-configuration)))
  (set-buffer irchat-Command-buffer)
  (let ((buffer-read-only nil))
    (erase-buffer)
    (sit-for 0))
  (make-variable-buffer-local 'irchat-freeze-local)
  (set-default 'irchat-freeze-local irchat-default-freeze-local)
  (make-variable-buffer-local 'irchat-beep-local)
  (set-default 'irchat-beep-local irchat-default-beep-local)
  (make-variable-buffer-local 'irchat-suppress-local)
  (set-default 'irchat-suppress-local irchat-default-suppress-local)
  (make-variable-buffer-local 'irchat-previous-pattern)
  (irchat-Dialogue-setup-buffer)
  (irchat-Others-setup-buffer)
  (irchat-Private-setup-buffer)
  (irchat-KILLS-setup-buffer)
  (irchat-IGNORED-setup-buffer)
  (irchat-WALLOPS-setup-buffer)
  (setq irchat-no-configure-windows t))


;; split by simm@irc.fan.gr.jp, Mon, 08 Nov 1999 02:28:38 +0900
(defun irchat-pj-startup-check-nick ()
  "Nick check when startup"
  (let (ok)
    (while (and (not ok) (irchat-server-opened))
      (accept-process-output irchat-server-process)
      (if (or irchat-nickname-already-in-use irchat-nickname-erroneus)
	  (progn
	    (if irchat-pj-startup-nickname-rest
		(setq irchat-trying-nickname          (car irchat-pj-startup-nickname-rest)
		      irchat-pj-startup-nickname-rest (cdr irchat-pj-startup-nickname-rest))
	      ;; modified by simm@irc.fan.gr.jp, Mon, 20 Dec 1999 21:44:10 +0900
	      (funcall irchat-pj-sound-error-function)
	      (setq irchat-trying-nickname
		    (read-from-minibuffer
		     (format
		      (if irchat-nickname-already-in-use
			  "IRC: Nickname \"%s\" already in use. Choose another one: "
			"IRC: Erroneus nickname \"%s\". Choose another one: ")
		      irchat-trying-nickname))))
	    (if (irchat-server-opened)
		(irchat-send "NICK %s" irchat-trying-nickname)
	      (setq irchat-nickname irchat-trying-nickname)
	      (setq irchat-nickname-already-in-use nil
		    irchat-nickname-erroneus nil)
	      (irchat 'always))))
      (setq irchat-nickname-already-in-use nil
	    irchat-nickname-erroneus nil)
      (if (not irchat-no-configure-windows)
	  (setq ok t)))))

(defun irchat-pj-startup-join ()
  "Join channels when startup"
  (let ((chans (or irchat-current-channels irchat-startup-channel-list)))
    (if chans
	(while chans
	  (and (stringp (car chans))
	       (irchat-Command-join (car chans)))
	  (setq chans (cdr chans)))
      (and (stringp irchat-startup-channel)
	   (irchat-Command-join irchat-startup-channel)))))
;; end

(defun irchat-Command-mode ()
  "Major mode for IRCHAT.  Normal edit function are available.
Typing Return or Linefeed enters the current line in the dialogue.
The following special commands are available:
For a list of the generic commands type \\[irchat-Command-generic] ? RET.
\\{irchat-Command-mode-map}"
  (interactive)
  (kill-all-local-variables)

  ;; modified by negi@KU3G.org, 1 Jun 1999
  (define-abbrev-table 'irchat-pj-abbrev-table ())

  (setq irchat-nick-alist (list (list irchat-nickname))
	major-mode 'irchat-Command-mode
	mode-name "IRC Commands"
	irchat-privmsg-partner nil
	irchat-pj-away-p nil
	;; modified by negi@KU3G.org, 1 Jun 1999
	local-abbrev-table irchat-pj-abbrev-table)
  (irchat-pj-modeline-set
   irchat-pj-modeline-global-status
   irchat-pj-modeline-Command-buffer
   'irchat-pj-modeline-Command)
  (use-local-map irchat-Command-mode-map)
  (if irchat-blink-parens
      nil
    (make-variable-buffer-local 'blink-matching-paren)
    (set-default 'blink-matching-paren t)
    (setq blink-matching-paren nil))
  (run-hooks 'irchat-Command-mode-hook))
  

(defun irchat-Dialogue-mode ()
  "Major mode for displaying the IRC dialogue.
All normal editing commands are turned off.
Instead, these commands are available:
\\{irchat-Dialogue-mode-map}"
  (kill-all-local-variables)
  (setq major-mode 'irchat-Dialogue-mode
	mode-name "IRC Dialogue")
  (irchat-pj-modeline-set
   irchat-pj-modeline-global-status
   irchat-pj-modeline-Dialogue-buffer
   'irchat-pj-modeline-Dialogue)
  (use-local-map irchat-Dialogue-mode-map)
  (set-buffer irchat-Dialogue-buffer)
  (setq buffer-read-only t)
  (run-hooks 'irchat-Dialogue-mode-hook))


(defun irchat-Others-mode ()
  "Major mode for displaying the IRC others message except current channel.
All normal editing commands are turned off.
Instead, these commands are available:
\\{irchat-Others-mode-map}"
  (kill-all-local-variables)
  (setq major-mode 'irchat-Others-mode
	mode-name "IRC Others")
  (irchat-pj-modeline-set
   irchat-pj-modeline-global-status
   irchat-pj-modeline-Others-buffer
   'irchat-pj-modeline-Others)
  (use-local-map irchat-Others-mode-map)
  (set-buffer irchat-Others-buffer)
  (setq buffer-read-only t)
  (run-hooks 'irchat-Others-mode-hook))


(defun irchat-Channel-mode ()
  "Major mode for displaying the IRC current channel buffer.
All normal editing commands are turned off.
Instead, these commands are available:
\\{irchat-Channel-mode-map}"
  (kill-all-local-variables)
  (setq major-mode 'irchat-Channel-mode
	mode-name "IRC Current channel")
  (irchat-pj-modeline-set
   irchat-pj-modeline-local-status
   irchat-pj-modeline-Channel-buffer
   'irchat-pj-modeline-Channel)
  (use-local-map irchat-Channel-mode-map)
  (setq buffer-read-only t)
  (run-hooks 'irchat-Channel-mode-hook))


(defun irchat-configure-windows ()
  "Configure Command mode and Dialogue mode windows.
One is for entering commands and text, the other displays the IRC dialogue."
  (setq irchat-no-configure-windows nil)
  (let ((obuf (current-buffer)))
    (if (or (one-window-p t)
	    (null (get-buffer-window irchat-Command-buffer))
	    (null (get-buffer-window irchat-Dialogue-buffer))
	    (and irchat-channel-buffer-mode
		 (or (null (get-buffer-window irchat-Channel-buffer))
		     (null (get-buffer-window irchat-Others-buffer))))
	    (and (null irchat-channel-buffer-mode)
		 (or (get-buffer-window irchat-Channel-buffer)
		     (get-buffer-window irchat-Others-buffer))))
	(progn
	  (if irchat-command-window-on-top
	      (progn
		(if (not irchat-use-full-window)
		    (set-window-configuration irchat-old-window-configuration))
		(switch-to-buffer irchat-Command-buffer)
		(if irchat-use-full-window
		    (delete-other-windows))
		(if irchat-one-buffer-mode
		    (switch-to-buffer irchat-Dialogue-buffer)
		  (split-window-vertically (max window-min-height 
						(or (and (featurep 'xemacs)
							 (irchat-pj-tab-supported-xemacs-p)
							 (+ 2 irchat-command-window-height))
						    irchat-command-window-height)))
		  (other-window 1)
		  (if irchat-channel-buffer-mode
		      (progn
			(split-window-vertically
			 (max window-min-height 
			      (/ (* (window-height)
				    irchat-channel-window-height-percent)
				 100)))
			(switch-to-buffer irchat-Channel-buffer)
			(other-window 1)
			(switch-to-buffer irchat-Others-buffer)
			(goto-char (point-max))
			(recenter (- (window-height) 1))
			(select-window
			 (get-buffer-window irchat-Command-buffer)))
		    (switch-to-buffer irchat-Dialogue-buffer)
		    (if (not irchat-freeze)
			(progn
			  (goto-char (point-max))
			  (recenter (- (window-height) 1))))
		    (select-window
		     (get-buffer-window irchat-Command-buffer)))))
	    ;; mta@tut.fi wants it like this
	    (switch-to-buffer irchat-Dialogue-buffer)
	    (if (not irchat-freeze)
		(progn
		  (goto-char (point-max))
		  (recenter (- (window-height) 1))))
	    (if irchat-use-full-window
		(delete-other-windows))
	    (if irchat-one-buffer-mode
		nil
	      (split-window-vertically
	       (- (window-height) (max window-min-height 
				       irchat-command-window-height)))
	      (if irchat-channel-buffer-mode
		  (progn
		    (split-window-vertically
		     (max window-min-height 
			  (/ (* (window-height)
				(- 100 irchat-channel-window-height-percent))
			     100)))
		    (switch-to-buffer irchat-Others-buffer)
		    (goto-char (point-max))
		    (recenter (- (window-height) 1))
		    (other-window 1)
		    (switch-to-buffer irchat-Channel-buffer)))
	      (other-window 1)
	      (switch-to-buffer irchat-Command-buffer)
	      (if (not irchat-channel-buffer-mode)
		  (progn
		    (select-window
		     (get-buffer-window irchat-Dialogue-buffer))
		    (if (not irchat-freeze)
			(progn
			  (goto-char (point-max))
			  (recenter (- (window-height) 1))))))
	      (select-window
	       (get-buffer-window irchat-Command-buffer))))))
    (set-buffer obuf)))


(defun irchat-Command-setup-buffer ()
  "Initialize Command mode buffer."
  (or (get-buffer irchat-Command-buffer)
      (save-excursion
	(set-buffer (get-buffer-create irchat-Command-buffer))
	(irchat-Command-mode))))

(defun irchat-Dialogue-setup-buffer ()
  "Initialize Dialogue mode buffer."
  (or (get-buffer irchat-Dialogue-buffer)
      (save-excursion
	(set-buffer (get-buffer-create irchat-Dialogue-buffer))
	(irchat-Dialogue-mode))))

(defun irchat-Others-setup-buffer ()
  "Initialize Others mode buffer."
  (or (get-buffer irchat-Others-buffer)
      (save-excursion
	(set-buffer (get-buffer-create irchat-Others-buffer))
	(irchat-Others-mode))))

(defun irchat-Private-setup-buffer ()
  "Initialize private conversation buffer."
  (or (get-buffer irchat-Private-buffer)
      (save-excursion
	(set-buffer (get-buffer-create irchat-Private-buffer))
	(insert "This is my private buffer.\n")
	(irchat-Channel-mode)))
  (setq irchat-Private-buffer (get-buffer irchat-Private-buffer))
  (setq irchat-Channel-buffer irchat-Private-buffer))

(defun irchat-KILLS-setup-buffer ()
  "Initialize KILLS buffer."
  (or (get-buffer irchat-KILLS-buffer)
      (save-excursion
	(set-buffer (get-buffer-create irchat-KILLS-buffer)))))

(defun irchat-IGNORED-setup-buffer ()
  "Initialize IGNORED buffer."
  (or (get-buffer irchat-IGNORED-buffer)
      (save-excursion
	(set-buffer (get-buffer-create irchat-IGNORED-buffer)))))

(defun irchat-WALLOPS-setup-buffer ()
  "Initialize WALLOPS buffer."
  (or (get-buffer irchat-WALLOPS-buffer)
      (save-excursion
	(set-buffer (get-buffer-create irchat-WALLOPS-buffer)))))

(defun irchat-clear-system ()
  "Clear all IRCHAT variables and buffers."
  (interactive)
  (if (and irchat-Command-buffer (get-buffer irchat-Command-buffer))
      (bury-buffer irchat-Command-buffer))
  (if (and irchat-Dialogue-buffer (get-buffer irchat-Dialogue-buffer))
      (bury-buffer irchat-Dialogue-buffer))
  (if (and irchat-KILLS-buffer (get-buffer irchat-KILLS-buffer))
      (bury-buffer irchat-KILLS-buffer))
  (if (and irchat-IGNORED-buffer (get-buffer irchat-IGNORED-buffer))
      (bury-buffer irchat-IGNORED-buffer))
  (if (and irchat-WALLOPS-buffer (get-buffer irchat-WALLOPS-buffer))
      (bury-buffer irchat-WALLOPS-buffer))
  (if (and irchat-debug-buffer (get-buffer irchat-debug-buffer))
      (bury-buffer irchat-debug-buffer))
  (setq irchat-debug-buffer nil))

(defun irchat-start-server (&optional confirm)
  "Open network stream to remote irc server.
If optional argument CONFIRM is non-nil, ask the host that the server
is running on."
  (if (irchat-server-opened)
      ;; Stream is already opened.
      nil
    ;; Open IRC server.
    (if (or
	 (and confirm
	      (not (eq confirm 'always)))
	 (null irchat-server))
	(setq irchat-server
	      (irchat-completing-default-read	
	       "IRC server: "
	       irchat-server-alist
	       '(lambda (s) t) nil irchat-server)))
    ;; modified by simm@irc.fan.gr.jp, Mon, 08 Nov 1999 02:59:18 +0900
    (cond ((and confirm
		(not (eq confirm 'always))
		irchat-ask-for-nickname)
	   (setq irchat-nickname
		 (read-string "Enter your nickname: " irchat-nickname)))
	  (irchat-pj-startup-nickname-list
	   (setq irchat-nickname (car irchat-pj-startup-nickname-list)
		 irchat-pj-startup-nickname-rest (cdr irchat-pj-startup-nickname-list))))
    ;; If no server name is given, local host is assumed.
    (if (string-equal irchat-server "")
	(setq irchat-server (system-name)))
    (or (irchat-open-server irchat-server irchat-service)
	(and (stringp irchat-status-message-string)
	     (string= irchat-status-message-string "Searching for program")
	     (error "ERROR: Cannot execute \"%s\" -- Cannot connect IRC server \"%s\""
		    irchat-dcc-program (irchat-pj-server-name)))
	(and (stringp irchat-status-message-string)
	     (< 0 (length irchat-status-message-string))
	     (error "ERROR: %s -- Cannot connect IRC server \"%s\""
		    irchat-status-message-string (irchat-pj-server-name)))
	(error "ERROR: Cannot connect IRC server \"%s\"" (irchat-pj-server-name)))))

(defun irchat-pj-server-name ()
  "`serverhost:port'-formatted server name.
When display message of irchat-server.
If port is omitted, only `serverhost' displays."
  (if (string-match "\\([^:]+\\):\\([^:]+\\):.*" irchat-server)
      (format "%s:%s"
	      (substring irchat-server (match-beginning 1) (match-end 1))
	      (substring irchat-server (match-beginning 2) (match-end 2)))
    irchat-server))

(defun irchat-open-server (host &optional service)
  "Open chat server on HOST.
If HOST is nil, use value of environment variable \"IRCSERVER\".
If optional argument SERVICE is non-nil, open by the service name."
  (let (status
	tmp
	(host (or host (getenv "IRCSERVER"))))
    (setq irchat-status-message-string "")
    (if (and host (assoc host irchat-server-alist)
	     (cdr (assoc host irchat-server-alist)))
	(setq host (cdr (assoc host irchat-server-alist))))
    (if (string-match "^\\([^:]+\\):\\([0-9]+\\)\\(.*\\)" host)
	(progn
	  (setq tmp (matching-substring host 3))
	  (setq service (string-to-int (matching-substring host 2)))
	  (setq host (matching-substring host 1))
	  (if (string-match "^:\\(.*\\)" tmp)
	      (if (string= (matching-substring tmp 1) "")
		  (setq irchat-ask-for-password t)
		(setq irchat-ask-for-password nil)
		(setq irchat-password (matching-substring tmp 1))))))
    (setq irchat-servername host) ;; temporary
    (message "Connecting to IRC server %s..." host)
    (if (not host)
	(setq irchat-status-message-string "IRC server is not specified.")
      (if (irchat-open-server-internal host service)
	  (let (password)
	    (setq irchat-after-registration nil)
	    (if irchat-pj-enable-undernet-server
		(setq status t)
	      (irchat-send "PING :%s" host)
	      (setq status (irchat-wait-for-response "^:[^ ]+ [4P][5O][1N][ G]")))
	    (if (not status)
		;; We have to close connection here, since the function
		;;  `irchat-server-opened' may return incorrect status.
		(irchat-close-server-internal)
	      (setq irchat-after-registration t)
	      (set-process-sentinel irchat-server-process 'irchat-sentinel)
	      (set-process-filter   irchat-server-process 'irchat-filter)
	      (setq password
		    (if (or irchat-ask-for-password irchat-reconnect-with-password)
			(irchat-read-passwd "Server Password: ")

		      irchat-password))
	      (and password
		   (stringp password)
		   (not (string= "" password))
		   (irchat-send "PASS %s" password))
	      (setq irchat-reconnect-with-password nil)
	      (irchat-send "USER %s * * :%s" 
			   (or (user-real-login-name) "Nobody")
			   (if (and irchat-name (not (string= irchat-name "")))
			       irchat-name "Nanashi no Gombei"))
	      (setq irchat-trying-nickname irchat-nickname)
	      (irchat-send "NICK %s" irchat-nickname)
	      (setq irchat-after-registration t)))))
    status))


(defun irchat-close-server ()
  "Close chat server."
  (unwind-protect
      (progn
	;; Un-set default sentinel function before closing connection.
	(and irchat-server-process
	     (eq 'irchat-sentinel
		 (process-sentinel irchat-server-process))
	     (set-process-sentinel irchat-server-process nil))
	;; We cannot send QUIT command unless the process is running.
	(if (irchat-server-opened)
	    (irchat-send "QUIT")))
    (irchat-close-server-internal)))


(defun irchat-server-opened ()
  "Return server process status, T or NIL.
If the stream is opened, return T, otherwise return NIL."
  (and irchat-server-process
       (memq (process-status irchat-server-process) '(open run))))


(defun irchat-open-server-internal (host service)
  "Open connection to chat server on HOST by SERVICE (default is irc)."
  (irchat-pj-define-service-coding-system service)
  (condition-case err 
      (save-excursion
	;; Initialize communication buffer.
	(setq irchat-server-buffer (get-buffer-create " *IRC*"))
	(set-buffer irchat-server-buffer)
	(kill-all-local-variables)
	(erase-buffer)
	(if (string-match "^[^\\[]" host)
	    (setq irchat-server-process
		  (open-network-stream "IRC" (current-buffer)
				       host service))
	  (if (not (string-match
		    "^\\[\\([0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+\\)\\]$" host))
	      (setq irchat-status-message-string "Use [nnn.nnn.nnn.nnn]"
		    irchat-server-process nil)
	    (setq irchat-server-process
		  (start-process "IRC" (current-buffer)
				 irchat-dcc-program "tcp" "connect"
				 (matching-substring host 1) 
				 (format "%s" service)))
	    (set-process-sentinel irchat-server-process
				  'irchat-sentinel)))
	(setq irchat-server-name host)
	(run-hooks 'irchat-server-hook)
	;; Return the server process.
	irchat-server-process)
    (error (setq irchat-status-message-string (car (cdr err)))
	   nil)))


(defun irchat-close-server-internal ()
  "Close connection to chat server."
  (if irchat-server-process
      (delete-process irchat-server-process))
  (if irchat-server-buffer
      (kill-buffer irchat-server-buffer))
  (setq irchat-server-buffer nil
	irchat-server-process nil))


(defun irchat-wait-for-response (regexp)
  "Wait for server response which matches REGEXP."
  (save-excursion
    (let ((status t)
	  (wait t))
      (set-buffer irchat-server-buffer)
      (irchat-accept-response)
      (while wait
	(goto-char (point-min))
	(cond ((looking-at "ERROR")
	       (setq status nil)
	       (setq wait nil))
	      ((looking-at ".")
	       (setq wait nil))
	      (t (irchat-accept-response))))
      ;; Save status message.
      (end-of-line)
      (setq irchat-status-message-string
	    (buffer-substring (point-min) (point)))
      (if status
	  (progn
	    (setq wait t)
	    (while wait
	      (goto-char (point-max))
	      (forward-line -1)		;(beginning-of-line)
	      (if (looking-at regexp)
		  (setq wait nil)
		(message "IRCHAT: Reading...")
		(irchat-accept-response)
		(message "")))
	    ;; Successfully received server response.
	    (delete-region (point-min) (point-max))
	    t)))))


(defun irchat-accept-response ()
  "Read response of server. Only used at startup time"
  ;; To deal with server process exiting before accept-process-output is called.
  (or (memq (process-status irchat-server-process) '(open run))
      (if (not irchat-reconnect-automagic)
	  (error "IRCHAT: Connection closed.")
	(if irchat-grow-tail
	    (irchat 'always)
	  (irchat))))
  (condition-case errorcode
      (accept-process-output irchat-server-process)
    (error
     (cond ((string-equal "select error: Invalid argument" (nth 1 errorcode))
	    ;; Ignore select error.
	    nil)
	   (t (signal (car errorcode) (cdr errorcode)))))))


(defun irchat-send-poll (now)
  (setq irchat-last-poll-minute now
        irchat-nick-alist nil
        irchat-channel-alist nil)
  (irchat-send "PING irchat-polling")
  (irchat-send "NAMES"))

(defun irchat-send-pong (&optional msg)
  (irchat-send "PONG :%s" (or msg irchat-servername)))

;;; As the server PINGs us regularly, we can be sure that we will 
;;; have the opportunity to poll it with a NAMES as often.
;;; We do this so that we can keep the irchat-nick-alist up-to-date.
;;; We send a PING after the NAMES so that we notice when the final
;;; NAMREPLY has come.
(defun irchat-maybe-poll ()
  (let* ((now (substring (current-time-string) 14 16))
         (nowint (string-to-int now))
         (stampint (mod (+ irchat-last-timestamp
                           (or irchat-timestamp-interval 0))
                        60)))
    ;; Print timestamp, this should use timer.el or something
    (if (or (not irchat-timestamp-interval)
            (> stampint nowint)
            (> (- nowint stampint) 30))
        nil
      (let ((obuf (current-buffer)))
        (if (get-buffer irchat-Dialogue-buffer)
            (progn
              (set-buffer irchat-Dialogue-buffer)
              (setq irchat-last-timestamp stampint)
              (insert (format "%s\n" (format irchat-timestamp-format 
                                             (current-time-string))))
              (set-buffer obuf)))))
    ;; Update names lists
    (if (or (not irchat-global-names) irchat-pj-away-p)
        ;; not polling or away, forget it
        nil
      ;; polling, see if enoung time has  passed since last poll, or this is 
      ;; the first poll
      (if (not irchat-last-poll-minute)
          (irchat-send-poll nowint)
        (if (and (numberp irchat-global-names) 
                 (> irchat-global-names 0))
            (if (>= (mod (+ irchat-last-poll-minute irchat-global-names) 60)
                    nowint)
                (irchat-send-poll nowint))
          (if (not (= nowint irchat-last-poll-minute))
              (irchat-send-poll nowint)))))))

(defun irchat-ischannel (chan)
  (string-match "^[+&#!]" chan))

(defun irchat-send (&rest args)
  (let ((item (apply 'format args)) ditem)
    ;; add by simm@irc.fan.gr.jp, Thu, 19 Nov 1998
    (if (and item irchat-pj-katakana-convert)
	(setq item (irchat-pj-zenkaku-katakana-string item)))
    (process-send-string irchat-server-process
			 (concat (irchat-string-out item) "\n"))
    (if (and irchat-debug-buffer (get-buffer irchat-debug-buffer))
	(let ((obuf (current-buffer)) opoint)
	  (set-buffer irchat-debug-buffer)
	  (setq opoint (point))
	  (goto-char (point-max))
	  (insert (concat item "\n"))
	  (goto-char opoint)
	  (set-buffer obuf)))
    (setq ditem (downcase item))
    (if (string-match "^list" (downcase ditem))
	(if (string-match "\\(^list\\) \\([^ ,]+\\)$" ditem)
	    (setq irchat-channel-filter (matching-substring ditem 2))
	  (setq irchat-channel-filter "")))))

(defun irchat-scroll-if-visible (window)
  (if window (set-window-point window (point-max))))


(defun irchat-insert0 (message)
  (irchat-insert message nil t))


(defun irchat-insert-special (string &optional pattern)
  (irchat-insert string irchat-Private-buffer pattern))


(defun irchat-insert-allchan (string &optional pattern)
  (irchat-insert string (cons irchat-Private-buffer
			      (get (intern irchat-nickname) 'chnl)) pattern))

(defun irchat-insert (body &optional chans pattern flag head)
  (let ((obuf (current-buffer)) opoint chan buf win visible )
    (while chans
      (setq chan (if (listp chans) (car chans) chans))
      (setq chans (if (listp chans) (cdr chans) nil))
      (if (setq buf (if (bufferp chan) chan (irchat-Channel-exist chan)))
	  (progn
	    (set-buffer buf)
	    (setq opoint (point))
	    (goto-char (point-max))
	    (if (setq win (get-buffer-window buf))
		  (if (or irchat-buggy-emacs-pos-visible-in-window-p
			  (pos-visible-in-window-p (point-max) win))
		      (setq visible t)))
	    (let* ((buffer-read-only nil))
	      (setq irchat-hoge (point))
	      (if (and (stringp pattern)
                       (stringp irchat-previous-pattern)
		       (string= pattern irchat-previous-pattern))
		  (progn
		    (previous-line 1)
		    (if flag
			(if irchat-print-time (forward-char 6))
		      (end-of-line))
		    (insert head)
		    (goto-char (point-max)))
                (and (eq pattern 'privmsg)
                     irchat-beep-local
                     (funcall irchat-pj-sound-bell-function))
                (if irchat-print-time
                    (insert (substring (current-time-string) 11 16) " "))
                (if (and (not irchat-display-channel-always)
                         (string-match "^\\([<>(]\\)[^ ]+:\\([^ :]+ .*\\)" body))
                    (insert (matching-substring body 1) (matching-substring body 2) "\n")
                  (insert body))
                (setq irchat-previous-pattern pattern)))
	    (if irchat-freeze-local
		(goto-char opoint))
            ;; modified by simm@irc.fan.gr.jp, Sun, 27 Jun 1999
	    (if (setq win (get-buffer-window buf irchat-pj-scroll-condition))
		(progn
		  (if (or irchat-buggy-emacs-pos-visible-in-window-p
			  (pos-visible-in-window-p (point-max) win))
		      (setq visible t))
		  (if (not irchat-freeze-local)
		      (set-window-point win (point-max)))))
	    (if irchat-suppress-local
		(setq visible t))
	    (set-buffer obuf))))
    (if (not visible)
	(progn
	  (set-buffer irchat-Others-buffer)
	  (if (> (point-max) irchat-others-high-watermark)
	      (let ((buffer-read-only nil))
		(delete-region 1 (- (point-max) irchat-others-low-watermark))))
	  (goto-char (point-max))
	  (let ((buffer-read-only nil))
	    (if irchat-print-time
		(insert (substring (current-time-string) 11 16) " "))
	    (insert body))
	  (setq irchat-previous-pattern nil)
          ;; begin: modified by simm@irc.fan.gr.jp, Sun, 27 Jun 1999
          ;;        last-modified by simm@irc.fan.gr.jp, Sat, 3 Jul 1999 
          (if (setq win (get-buffer-window irchat-Others-buffer irchat-pj-scroll-condition))
              (let ((cwin nil)
                    (owin (selected-window)))
                (set-window-point win (point-max))
                (select-window win)
                (recenter (- (window-height) 1))
                (and irchat-pj-scroll-condition
                     (setq cwin (get-buffer-window irchat-Command-buffer
                                                   irchat-pj-scroll-condition))
                     (select-window cwin))
                (select-window owin)))
	  (set-buffer obuf)))
          ;; end
    (set-buffer irchat-Dialogue-buffer)
    (let ((opoint (point)))
      (goto-char (point-max))
      (let ((buffer-read-only nil))
	(if irchat-print-time
	    (insert (substring (current-time-string) 11 16) " "))
	(insert body))
      (setq irchat-previous-pattern nil)
      ;; modified by simm@irc.fan.gr.jp, Sun, 27 Jun 1999
      (if (setq win (get-buffer-window irchat-Dialogue-buffer irchat-pj-scroll-condition))
	  (if irchat-freeze
	      (goto-char opoint)
	    ;;(set-window-point win (point-max))
	    (if (not (pos-visible-in-window-p (point-max) win))
		(let ((owin (selected-window)))
		  (select-window win)
		  (goto-char (point-max))
		  (recenter (- (window-height) 1))
		  (select-window owin))))))
    (set-buffer obuf)))


(defun irchat-insert-private (to-me partner xmsg)
  (if (not (irchat-ischannel partner))
      (if (null to-me)
	  ;; my message to partner
	  (irchat-insert (format ">%s< %s\n" partner xmsg)
			 (or (irchat-Channel-exist partner) irchat-Private-buffer)
			 'my-privmsg)
	;; message from partner
	;; begin sound extension: modified by kaoru@kaisei.org
	(if irchat-pj-sound-when-private
	    (or (irchat-Channel-exist partner)
		(funcall irchat-pj-sound-private-function)))
	(irchat-insert (format "=%s= %s\n" partner xmsg)
		       (or (irchat-Channel-exist partner) irchat-Private-buffer)
		       'privmsg))
    ;; my message to channel (partner is channel)
    (irchat-insert (format ">%s:%s< %s\n"
			   (irchat-chan-virtual partner)
			   irchat-nickname xmsg)
		   partner 'my-privmsg)))

;;;
;;; this function handles default arguments more user friendly
;;;
(defun irchat-pj-cut-nil-from-list (table)
  (let ((tmp table) (result nil))
    (while tmp
      (if (car (car tmp))
	  (setq result (append result (list (car tmp)))))
      (setq tmp (cdr tmp)))
    result))

(defun irchat-pj-completing-read
  (prompt table &optional predicate require-match initial-input)
  (if (boundp 'xemacs-logo)
      (completing-read prompt (irchat-pj-cut-nil-from-list table)
		       predicate require-match initial-input)
    (completing-read prompt table predicate require-match initial-input)))

(defun irchat-completing-default-read
  (prompt table predicate require-match initial-input)
  "completing-read w/ default argument like in 'kill-buffer'"
  (let ((default-read
	  (irchat-pj-completing-read
	   (if initial-input
	       (format "%s(default %s) "
		       prompt initial-input)
	     (format "%s" prompt))
	   table predicate require-match nil)))
    (if (and (string= default-read "") initial-input)
	initial-input
      default-read)))

;;; caesar-region written by phr@prep.ai.mit.edu  Nov 86
;;; modified by tower@prep Nov 86
;;; Modified by umerin@flab.flab.Fujitsu.JUNET for ROT47.

;;; irchat-pj-caesar-region by simm@irc.fan.gr.jp for ROT5-13-47-48
;;; on Sun, 29 Aug 1999 22:25:51 +0900
;;; from mule-caesar-region (in APEL)
;;; so, irchat-caesar-region is obsolete.

(cond ((and (fboundp 'charset-chars) (fboundp 'char-charset))
       (defsubst irchat-pj-get-rotate-times (chr)
         (lsh (charset-chars (char-charset chr)) -1)))
      ((fboundp 'char-leading-char)
       (defsubst irchat-pj-get-rotate-times (chr)
         (if (= (logand (nth 2 (character-set (char-leading-char chr))) 1) 1) 48 47)))
      (t
       (defsubst irchat-pj-get-rotate-times (chr)
         47)))

(if (fboundp 'split-char)
    (defalias 'irchat-pj-split-char 'split-char)
  (defun irchat-pj-split-char (chr)
    "Return list charset and wone or two position-codes-of CHR."
    (let (dst (p (1- (char-bytes chr))))
      (while (>= p 1)
        (setq dst (cons (- (char-component chr p) 128) dst)
              p (1- p)))
      (cons (char-leading-char chr) dst))))

(cond ((and (fboundp 'make-char) (fboundp 'char-charset))
       (defsubst irchat-pj-rotate-result (chr ret)
         (make-char (char-charset chr) (car ret) (car (cdr ret)))))
      ((and (fboundp 'make-character) (fboundp 'char-leading-char))
       (defsubst irchat-pj-rotate-result (chr ret)
         (make-character (char-leading-char chr) (car ret) (car (cdr ret)))))
      (t
       (defsubst irchat-pj-rotate-result (chr ret)
         (+ 128 ret))))

(defun irchat-pj-caesar-region (start end &optional num-rotate ascii-rotate)
  "Caesar rotation of current region.
Optional argument NUM-ROTATE is rotation-size for Latin number \(0-9).
Optional argument ASCII-ROTATE is rotation-size for Latin alphabet
\(A-Z and a-z).  For non-ASCII text, ROT-N/2 will be performed in any
case (N=charset-chars; 94 for 94 or 94x94 graphic character set; 96
for 96 or 96x96 graphic character set).

Default NUM-ROTATE is 5, and ASCII-ROTATE is 13, so this performes ROT5-13-47-48."
  (interactive "r\nP")
  (setq ascii-rotate (if ascii-rotate
			 (mod ascii-rotate 26)
		       13)
        num-rotate (if num-rotate
                       (mod num-rotate 10)
                     5))
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char start)
      (while (< (point)(point-max))
	(let* ((chr (char-after (point))))
	  (cond ((and (<= ?A chr) (<= chr ?Z))
		 (setq chr (+ chr ascii-rotate))
		 (if (> chr ?Z)
		     (setq chr (- chr 26)))
		 (delete-char 1)
		 (insert chr))
		((and (<= ?a chr) (<= chr ?z))
		 (setq chr (+ chr ascii-rotate))
		 (if (> chr ?z)
		     (setq chr (- chr 26)))
		 (delete-char 1)
		 (insert chr))
                ((and (<= ?0 chr) (<= chr ?9))
                 (setq chr (+ chr num-rotate))
                 (if (> chr ?9)
                     (setq chr (- chr 10))))
		((<= chr ?\x9f)
		 (forward-char))
		(t
		 (let* ((multi-rotate (irchat-pj-get-rotate-times chr))
			(ret (mapcar (function
				      (lambda (octet)
					(if (< octet 80)
					    (+ octet multi-rotate)
					  (- octet multi-rotate))))
				     (cdr (irchat-pj-split-char chr)))))
		   (delete-char 1)
                   (insert (irchat-pj-rotate-result chr ret)))))))))
  (goto-char end))

(defun irchat-pj-caesar-string (string &optional num-rotate ascii-rotate)
  (interactive)
  (let (beg end str)
    (save-excursion
      (if (get-buffer irchat-pj-CONVERT-buffer)
          (set-buffer irchat-pj-CONVERT-buffer)
        (get-buffer-create irchat-pj-CONVERT-buffer))
      (setq beg (point))
      (insert string)
      (setq end (point))
      (irchat-pj-caesar-region beg end num-rotate ascii-rotate)
      (setq str (buffer-substring beg end))
      (delete-region beg end))
    str))

; (defun irchat-caesar-region (&optional n)
;   "Caesar rotation of region by N, default 13, for decrypting netnews.
; ROT47 will be performed for Japanese text in any case."
;   (interactive (if current-prefix-arg	; Was there a prefix arg?
; 		   (list (prefix-numeric-value current-prefix-arg))
; 		 (list nil)))
;   (cond ((not (numberp n)) (setq n 13))
; 	((< n 0) (setq n (- 26 (% (- n) 26))))
; 	(t (setq n (% n 26))))		;canonicalize N
;   (if (not (zerop n))		; no action needed for a rot of 0
;       (progn
; 	(if (or (not (boundp 'caesar-translate-table))
; 		(/= (aref caesar-translate-table ?a) (+ ?a n)))
; 	    (let ((i 0) (lower "abcdefghijklmnopqrstuvwxyz") upper)
; 	      (message "Building caesar-translate-table...")
; 	      (setq caesar-translate-table (make-vector 256 0))
; 	      (while (< i 256)
; 		(aset caesar-translate-table i i)
; 		(setq i (1+ i)))
; 	      (setq lower (concat lower lower) upper (upcase lower) i 0)
; 	      (while (< i 26)
; 		(aset caesar-translate-table (+ ?a i) (aref lower (+ i n)))
; 		(aset caesar-translate-table (+ ?A i) (aref upper (+ i n)))
; 		(setq i (1+ i)))
; 	      ;; ROT47 for Japanese text.
; 	      ;; Thanks to ichikawa@flab.fujitsu.junet.
; 	      (setq i 161)
; 	      (let ((t1 (logior ?O 128))
; 		    (t2 (logior ?! 128))
; 		    (t3 (logior ?~ 128)))
; 		(while (< i 256)
; 		  (aset caesar-translate-table i
; 			(let ((v (aref caesar-translate-table i)))
; 			  (if (<= v t1) (if (< v t2) v (+ v 47))
; 			    (if (<= v t3) (- v 47) v))))
; 		  (setq i (1+ i))))
; 	      (message "Building caesar-translate-table... done")))
; 	(let ((from (region-beginning))
; 	      (to (region-end))
; 	      (i 0) str len)
; 	  (setq str (buffer-substring from to))
; 	  (setq len (length str))
; 	  (while (< i len)
; 	    (aset str i (aref caesar-translate-table (aref str i)))
; 	    (setq i (1+ i)))
; 	  (goto-char from)
; 	  (delete-region from to)
; 	  (insert str)))))

;;;
;;; this function from ange-ftp.el by Andy Norman (ange@hplb.hpl.hp.com)
;;;
(defun irchat-read-passwd (prompt)
  "Read a password from the user. Echos a . for each character typed.
End with RET, LFD, or ESC. DEL or C-h rubs out."
  (let ((pass "")
	(c 0)
	(echo-keystrokes 0)
	(cursor-in-echo-area t))
    (while (and (/= c ?\r) (/= c ?\n) (/= c ?\e))
      (message "%s%s"
	       prompt
	       (make-string (length pass) ?.))
      (setq c (read-char))
      (if (and (/= c ?\b) (/= c ?\177))
	  (setq pass (concat pass (char-to-string c)))
	(if (> (length pass) 0)
	    (setq pass (substring pass 0 -1)))))
    (substring pass 0 -1)))

;;;
;;; save log by negi@KU3G.org, Tue, 1 Jun 1999
;;;   last modify by simm@irc.fan.gr.jp, Sat, 5 Jun 1999
;;;

(defun irchat-pj-save-log ()
  "Save log according to irchat-pj-save-log-channel-alist.
See also irchat-pj-save-log-channel-alist."
  (interactive)
  (let ((cur nil)
        (backup (current-buffer)))
    (or (eq ?/ (elt irchat-pj-save-log-directory
                    (1- (length irchat-pj-save-log-directory))))
        (setq irchat-pj-save-log-directory
              (concat irchat-pj-save-log-directory "/")))
    (unwind-protect
        (mapcar
         '(lambda (buf-list)
            (setq cur (or (get-buffer (concat " IRC:" (car buf-list)))
                          (get-buffer (concat " IRC: " (car buf-list)))))
            (if cur
                (progn
                  (set-buffer cur)
                  (append-to-file
                   (point-min) (point-max)
                   (concat (expand-file-name irchat-pj-save-log-directory)
                           (cdr buf-list)
                           "-"
                           (format-time-string "%m%d" (current-time)))))))
         irchat-pj-save-log-channel-alist)
      (set-buffer backup)
      (message ""))))
                     
;;;
;;; eof
;;;
