;;;
;;; $Id: irchat-filter.el,v 1.5 1993/10/07 12:44:59 tmo Exp $
;;;
;;; see file irchat-copyright.el for change log and copyright info

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

(provide 'irchat-filter)

;;;
;;;  These are defsubst just for speed, as it is expensive to call funtions at
;;;  emacs lisp (also evals are expensive)
;;;
(defsubst irchat-current-minute ()
  (string-to-int (substring (current-time-string) 14 16)))
(defvar irchat-minute 0)

(defun irchat-handle (line)
  "Called when we have at least one line of output from the IRC server."
  (let ((obuf (current-buffer))
	prefix userhost (cmd "") arg)
    (while (string-match "^\\([^\r]*\\)\r+\\(.*\\)" line)
      (setq line (concat (matching-substring line 1)
			 (matching-substring line 2))))
    (if (string-match "^:\\([^ ]+\\) *\\(.*\\)" line)
	(setq prefix (matching-substring line 1)
	      line (matching-substring line 2)))
    (if (and prefix (string-match "^\\([^!]*\\)!\\(.*\\)" prefix))
	(setq userhost (matching-substring prefix 2)
	      prefix (matching-substring prefix 1)))
    (if (string-match "^ *\\([^ ]+\\) *\\(.*\\)" line)
	(setq arg (list (matching-substring line 1))
	      line (matching-substring line 2)))
    (while (string-match "^\\([^:][^ ]*\\) +\\(.*\\)" line)
      (nconc arg (list (matching-substring line 1)))
      (setq line (matching-substring line 2)))
    (if (not (string= line ""))
	(if (string-match "^:\\(.*\\)" line)
	    (nconc arg (list (matching-substring line 1)))
	  (nconc arg (list line))))
    (if (and prefix userhost
	     (not (string= (get (intern prefix) 'userhost) userhost)))
	(put (intern prefix) 'userhost userhost))
    (if (car arg)
	(setq cmd (downcase (car arg))
	      arg (cdr arg)))
    (if (and (boundp (setq hook
			   (intern (concat "irchat-handle-" cmd "-hook"))))
	     (eval hook)
	     (eval (list (eval hook) (cons prefix arg))))
	nil
      (setq fun (intern (concat "irchat-handle-" cmd)))
      ;; modified by simm@irc.fan.gr.jp, Thu, 10 Jun 1999
      (if (or (eq fun 'irchat-handle-join)
              (eq fun 'irchat-handle-nick)
              (eq fun 'irchat-handle-part)
              (eq fun 'irchat-handle-quit))
          (apply fun prefix userhost arg)
        (if (fboundp fun)
            (apply fun prefix arg)
          (if irchat-debugging
              (irchat-insert-special (format "No handle-%s (%s) %s\n" cmd prefix
                                             (prin1-to-string arg))))
          (let* ((cmd-number (string-to-int cmd))
                 (default-number (/ cmd-number 100)) tmp)
            (setq fun (intern (concat "irchat-handle-"
                                      (format "%d00s" default-number))))
            (if (and (> cmd-number 0)
                     (fboundp fun))
                (apply fun cmd-number prefix arg)
              (setq tmp (format "Unknown MESSAGE: [%s] [%s] [%s]\n" 
                                prefix cmd (prin1-to-string arg)))
              (message tmp)
              (irchat-insert0 tmp))))))
    (set-buffer obuf)))

(defun irchat-filter (process output)
  "Filter function for IRC server process."
  (let ((obuf (current-buffer))
	(data (match-data))
	end)
    ;;
    ;; C-c D creates debug buffer for incoming messages...
    ;;
    (if (and irchat-debug-buffer (get-buffer irchat-debug-buffer))
	(progn
	  (set-buffer irchat-debug-buffer)
	  (let* ((dbgwin (get-buffer-window irchat-debug-buffer))
		 (wp (if dbgwin (window-point dbgwin) nil))
		 (pm (point-max)))
	    (save-excursion
	      (goto-char (point-max))
	      (insert output))
	    (if (and wp (>= wp pm))
		(irchat-scroll-if-visible dbgwin)))))

    ;; begin: modified by simm@irc.fan.gr.jp, 25 Jan 1999
    (let ((tmp "") (cur nil) (prev nil) (i 0) (len (length output)))
      (while (< i len)
	(setq cur (elt output i))
	(cond ((null cur))
	      ((= 0 cur))
	      ((null prev)
	       (setq tmp (format "%s%c" tmp cur)))
	      ((and (= 10 cur) (= 13 prev)))
	      ((or (= 10 cur) (= 13 cur))
	       (setq tmp (concat tmp "\012")))
	      (t
	       (setq tmp (format "%s%c" tmp cur))))
	(setq prev cur
	      i (1+ i)))
      (setq irchat-pj-filter-queue (concat irchat-pj-filter-queue tmp)))
    (while (and (boundp 'irchat-pj-filter-queue)
		(string-match "\012" irchat-pj-filter-queue))
      (setq end (match-end 0))
      (if (< 1 end)
        (irchat-handle (irchat-string-in (substring irchat-pj-filter-queue 0 (1- end)))))
      (setq irchat-pj-filter-queue (substring irchat-pj-filter-queue end)))
    ;; end
    (if (/= (irchat-current-minute) irchat-minute)
	(let (fun)
	  (setq irchat-minute (irchat-current-minute))
	  (if (fboundp (setq fun (intern "irchat-minutely")))
	      (apply fun nil))))
    (set-buffer obuf)
    (store-match-data data)))

(defun irchat-sentinel (proc status)
  "Sentinel function for IRC server process."
  (and irchat-server-process
       (not (irchat-server-opened))
       (cond ((or irchat-reconnect-automagic irchat-reconnect-with-password)
	      (or (and irchat-grow-tail
		       (not irchat-reconnect-with-password)
		       (setq irchat-nickname (concat irchat-nickname irchat-grow-tail))
		       (irchat 'always))
		  (irchat)))
	     (irchat-fatal-error-message
	      (error (format "IRC ERROR: %s" irchat-fatal-error-message)))
	     ((process-id proc)
	      (irchat-sentinel2 proc status))
	     (t
	      (error (format "IRC ERROR: Connection closed. (%s)"
			     (substring status 0 (1- (length status)))))))))

(defun irchat-sentinel2 (proc status)
  (if (string-match "^exited abnormally with code \\([0-9]+\\)" status)
      (let ((status (string-to-int (matching-substring status 1))))
	(cond
	 ((= 99 status);; unsupported command
	  (error (format "IRC ERROR: Please use a newer \"%s\"."
			 irchat-dcc-program)))
	 ((= 98 status);; bad argment number
	  (error (format "IRC ERROR: Please use a newer \"%s\"."
			 irchat-dcc-program)))
	 ((= 97 status)
	  (error (format "IRC ERROR: Cannot connect to IRC server.")))
	 (t
	  (error (format "IRC ERROR: Server connection closed.")))))
    (error (format "IRC ERROR: Connection closed. (%s)"
		   (substring status 0 (1- (length status)))))))

;;;
;;; eof
;;;
