;;;
;;; $Id: irchat-filter.el,v 1.3 1993/07/13 18:34:59 tmo Exp $
;;;
;;; see file irchat-copyright.el for change log and copyright info

(require 'defsubst)

(provide 'irchat-filter)

(defvar irchat-debug-buffer)
(defvar irchat-receive-convert-list)
(defvar irchat-userathost)
(defvar irchat-Dialogue-buffer)
(defvar irchat-freeze)
(defvar irchat-kill-nickname)
(defvar irchat-current-channel)
(defvar irchat-format-string2)
(defvar irchat-format-string3)
(defvar irchat-beep-on-bells)
(defvar irchat-server-process)
(defvar irchat-reconnect-automagic)
(defvar irchat-grow-tail)

;;;
;;;  These are defsubst just for speed, as it is expensive to call funtions at
;;;  emacs lisp (also evals are expensive)
;;;
(defsubst irchat-handle-msg-msg (prefix rest)
  (if (or (and prefix
	       (memq (intern prefix) irchat-kill-nickname)
	       (irchat-msg-from-ignored prefix rest))
	  (and (not prefix)
	       (string= "> " rest)))
      nil
    (if prefix 
	(let ((oma (get (intern prefix) 'chnl)))
	  (if oma
	      (while (string= "#" (substring (car oma) 0 1))
		(setq oma (cdr oma)))
	    (setq oma (list irchat-current-channel)))
	  (if (string= (car oma) irchat-current-channel)
	      (insert (format irchat-format-string2 prefix))
	    (insert 
	     (format irchat-format-string3 prefix (car oma))))
	  (insert " ")))
    (insert rest)
    (if (and (string-match "\007" rest) irchat-beep-on-bells)
	(progn
	  (if (not (get-buffer-window irchat-Dialogue-buffer))
	      (progn
		(beep t)
		(message "IRCHAT: %s is trying to get attention" prefix)))
	  (if (eq irchat-beep-on-bells 'always)
	      (beep t))))
    (newline)))


(defsubst irchat-handle-message-2 (prefix message rest-of-line)
  "Helper function (actually a macro) for irchat-handle-message."
  (let ((hook (intern (concat "irchat-" message "-hook")))
	buffer-read-only fun)
    (goto-char (point-max))
    (if (and (boundp hook)
	     (eval hook)
	     (eval (list (eval hook) prefix rest-of-line)))
	;; If we have a hook, and it returns T, do nothing more
	nil
      ;; else call the handler
      (if (string= message "msg")
	  (irchat-handle-msg-msg prefix rest-of-line)
	(if (fboundp (setq fun (intern
				(concat "irchat-handle-" message "-msg"))))
	  (progn
	    (apply fun (list prefix rest-of-line))
	    (if (not irchat-freeze)
		(irchat-scroll-if-visible 
		 (get-buffer-window (current-buffer)))))
	  (let* ((message-number (string-to-int message))
		 (default-number (/ message-number 100)))
	    (if (and (> message-number 0)
		     (fboundp (setq fun (intern
					 (concat "irchat-handle-"
						 (format "%d00" default-number)
						 "-msgs")))))
		(progn
		  (apply fun (list message-number prefix rest-of-line))
		  (if (not irchat-freeze)
		      (irchat-scroll-if-visible
		       (get-buffer-window (current-buffer)))))
	      (message "IRCHAT: Unknown IRC message \":%s %s %s\"" prefix
		       (upcase message) rest-of-line)
	      (insert (format "MESSAGE: %s, %s, %s" 
			      prefix message rest-of-line))
	      (newline))))))))


(defsubst irchat-handle-message ()
  "Called when we have at least one line of output from the IRC server."
  (let ((obuf (current-buffer))
	beg end prefix message rest-of-line)
    (while (or
	    (looking-at "\\(:[^! \n]*\\)!\\([^ \n]*\\) \\([^ \n]+\\) :?\\(.*\\)\r\n")
	    (looking-at "\\(:[^ \n]*\\)?\\(\\) *\\([^ \n]+\\) :?\\(.*\\)\r\n"))

      (setq beg (match-beginning 0)
	    end (match-end 0)
	    prefix (if (match-beginning 1)
		       (buffer-substring (1+ (match-beginning 1)) 
					 (match-end 1)))
	    irchat-userathost (buffer-substring (match-beginning 2)
						(match-end 2))
	    rest-of-line (buffer-substring (match-beginning 4) (match-end 4))
	    message (downcase 
		     (buffer-substring (match-beginning 3) (match-end 3))))

      (set-buffer irchat-Dialogue-buffer)
      (if irchat-freeze
	  (save-excursion
	    (irchat-handle-message-2 prefix message rest-of-line))
	(irchat-handle-message-2 prefix message rest-of-line))
      (set-buffer obuf)
      (delete-region beg end))))


(defun irchat-filter (process output)
  "Filter function for IRC server process."
  (let ((obuf (current-buffer))
	(data (match-data))
	bol)
    (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 
		 (get-buffer-window irchat-debug-buffer))))))
    (set-buffer (process-buffer process))
    (goto-char (point-max))
    (let ((conv-list irchat-receive-convert-list))
      (while conv-list
	(setq output (replace-in-string output (car (car conv-list))
				     (car (cdr (car conv-list)))))
	(setq conv-list (cdr conv-list))))

    (insert output)
    (goto-char (point-min))
    (while (re-search-forward "\n\n" (point-max) t)
      (delete-char -1)) ;;; This hack (from mta) is for 2.4
    (goto-char (point-min))

    (if (string-match "\n" output)
	(irchat-handle-message))
    (set-buffer obuf)
    (store-match-data data)))


(defun irchat-sentinel (proc status)
  "Sentinel function for IRC server process."
  (if (and irchat-server-process
	   (not (irchat-server-opened)))
      (if (not irchat-reconnect-automagic)
	  (error "IRCHAT: Connection closed.")
	(if irchat-grow-tail
	    (irchat 'always)
	  (irchat)))))

;;;
;;; eof
;;;
