;;; pure-pr-dcc-irchat.el --- interface for irchat-dcc process

;; Copyright (C) 2000 Project Pure / irchat-PJ Project.

;; Author: SHIMADA Mitsunobu <simm@pure.fan.gr.jp>
;; Keywords: PURE, IRC, process, DCC, irchat, dcc.c

;; $Id: pure-pr-dcc-irchat.el,v 1.1 2001/04/30 15:12:36 simm Exp $

;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; PURE means "Primitive Universal Relay-chat Environment"

;;; Code:

(require 'pure-pr-filter)
(require 'pure-irc-dcc-info)

(defvar pure-pr-dcc-irchat-program "dcc"
  "Filename of DCC program of irchat.")

(defvar pure-pr-dcc-irchat-support-resume 'unknown)

;; start DCC CHAT server process
(defun pure-pr-dcc-irchat-start-chat-server (dinfo &optional resume)
  "Start dcc process of irchat: DCC CHAT listen"
  (let* ((host (pure-irc-dcc-info-get-host dinfo))
	 (port (pure-irc-dcc-info-get-port dinfo))
	 (proc (cond (host
		      (start-process
		       pure-pr-dcc-irchat-program (pure-irc-dcc-info-get-buffer dinfo)
		       pure-pr-dcc-irchat-program "chat" "listen" port host))
		     (port
		      (start-process
		       pure-pr-dcc-irchat-program (pure-irc-dcc-info-get-buffer dinfo)
		       pure-pr-dcc-irchat-program "chat" "listen" port))
		     (t
		      (start-process
		       pure-pr-dcc-irchat-program (pure-irc-dcc-info-get-buffer dinfo)
		       pure-pr-dcc-irchat-program "chat" "listen")))))
    (if proc (pure-pr-filter-set-filter proc 'pure-pr-dcc-irchat-chat-parser))
    proc))

;; start DCC CHAT client process
(defun pure-pr-dcc-irchat-start-chat-client (dinfo &optional resume)
  "Start dcc process of irchat: DCC CHAT connect"
  (let* ((host (pure-irc-dcc-info-get-host dinfo))
	 (port (pure-irc-dcc-info-get-port dinfo))
	 (proc (start-process
		pure-pr-dcc-irchat-program (pure-irc-dcc-info-get-buffer dinfo)
		pure-pr-dcc-irchat-program "chat" "connect" host port)))
    (if proc (pure-pr-filter-set-filter proc 'pure-pr-dcc-irchat-chat-parser))
    proc))

;; start DCC SEND server process
(defun pure-pr-dcc-irchat-start-file-server (dinfo &optional resume)
  "Start dcc process of irchat: DCC file server listen"
  (let* ((host (pure-irc-dcc-info-get-host dinfo))
	 (port (pure-irc-dcc-info-get-port dinfo))
	 (file (pure-irc-dcc-info-get-file dinfo))
	 (proc (cond (host
		      (start-process
		       pure-pr-dcc-irchat-program (pure-irc-dcc-info-get-buffer dinfo)
		       pure-pr-dcc-irchat-program "file" "send" file port host))
		     (port
		      (start-process
		       pure-pr-dcc-irchat-program (pure-irc-dcc-info-get-buffer dinfo)
		       pure-pr-dcc-irchat-program "file" "send" file port))
		     (t
		      (start-process
		       pure-pr-dcc-irchat-program (pure-irc-dcc-info-get-buffer dinfo)
		       pure-pr-dcc-irchat-program "file" "send" file)))))
    (if proc (pure-pr-filter-set-filter proc 'pure-pr-dcc-irchat-file-parser))
    proc))

;; start DCC FILE get process
(defun pure-pr-dcc-irchat-start-file-client (dinfo &optional resume)
  "Start dcc process of irchat: DCC CHAT connect"
  (let* ((host (pure-irc-dcc-info-get-host dinfo))
	 (port (pure-irc-dcc-info-get-port dinfo))
	 (file (pure-irc-dcc-info-get-file dinfo))
	 (size (pure-irc-dcc-info-get-size dinfo))
	 (proc (start-process
		pure-pr-dcc-irchat-program (pure-irc-dcc-info-get-buffer dinfo)
		pure-pr-dcc-irchat-program "file"
		(if resume "rget" "get") host port size file)))
    (if proc
	(pure-pr-filter-set-filter proc 'pure-pr-dcc-irchat-file-parser))
    proc))

;;
;; DCC RESUME operation
;;

;; check whether DCC RESUME enable
(defun pure-pr-dcc-irchat-resumep (dinfo)
  "Check dcc process supports DCC RESUME feature"
  (if (eq 'unknown pure-pr-dcc-irchat-support-resume)
      (let (path rest)
	(if (file-executable-p pure-pr-dcc-irchat-program)
	    (setq path pure-pr-dcc-irchat-program)
	  (setq rest exec-path)
	  (while rest
	    (setq path (expand-file-name pure-pr-dcc-irchat-program (car rest))
		  rest (cdr rest))
	    (if (file-executable-p path)
		(setq rest nil))))
	(if path
	    (setq pure-pr-dcc-irchat-support-resume
		  (= 0 (call-process pure-pr-dcc-irchat-program
				     nil nil nil "check" "resume")))))
    pure-pr-dcc-irchat-support-resume))

(defun pure-pr-dcc-irchat-check-resume (&rest args)
  "Check dcc process supports DCC RESUME feature manually"
  (interactive)
  (setq pure-pr-dcc-irchat-support-resume 'unknown)
  (pure-pr-dcc-irchat-resumep nil))

;; Accept DCC RESUME request
(defun pure-pr-dcc-irchat-resume-accept (dinfo)
  "Accept DCC RESUME request"
  (process-send-string
   (pure-irc-dcc-info-get-proc dinfo)
   (format "DCC RESUME %s %s %s\n"
	   (pure-irc-dcc-info-get-file dinfo)
	   (pure-irc-dcc-info-get-port dinfo)
	   (pure-irc-dcc-info-get-xpos dinfo))))

;; Start DCC RESUME client process
(defun pure-pr-dcc-irchat-resume-start (dinfo)
  "Start DCC RESUME client process"
  (process-send-string
   (pure-irc-dcc-info-get-proc dinfo)
   (format "DCC ACCEPT %s %s %s\n"
	   (pure-irc-dcc-info-get-file dinfo)
	   (pure-irc-dcc-info-get-port dinfo)
	   (pure-irc-dcc-info-get-xpos dinfo))))

;;
;; Parser functions for dcc.c
;;
(defun pure-pr-dcc-irchat-file-parser (proc)
  "DCC parser function for DCC SEND/get."
  (cond ((looking-at "DCC SEND \\([^ ]+\\) \\([^ ]+\\) \\([^ ]+\\)")
	 (pure-irc-dcc-info-send-server-info
	  pure-irc-dcc-info
	  (buffer-substring (match-beginning 1) (match-end 1))
	  (buffer-substring (match-beginning 2) (match-end 2))
	  (buffer-substring (match-beginning 3) (match-end 3))))
	((looking-at "DCC RESUME \\([^ ]+\\) \\([^ ]+\\) \\([^ ]+\\)")
	 (if (not (pure-pr-dcc-irchat-resumep pure-irc-dcc-info))
	     (message "DCC WARNING: not support DCC RESUME")
	   (pure-irc-dcc-info-put-xpos
	    pure-irc-dcc-info (buffer-substring (match-beginning 3) (match-end 3)))
	   (pure-irc-dcc-info-resume-request pure-irc-dcc-info)))
	((looking-at "DCC ACCEPT \\([^ ]+\\) \\([^ ]+\\) \\([^ ]+\\)")
	 (if (not (pure-pr-dcc-irchat-resumep pure-irc-dcc-info))
	     (message "DCC WARNING: not support DCC RESUME")
	   (pure-irc-dcc-info-put-xpos
	    pure-irc-dcc-info (buffer-substring (match-beginning 3) (match-end 3)))
	   (pure-irc-dcc-info-resume-accept pure-irc-dcc-info)))
	((looking-at "DCC SENDING")
	 (pure-irc-dcc-info-put-status pure-irc-dcc-info 'server)
	 (funcall pure-irc-dcc-log-interface
		  "DCC SEND to %s established (%s, %s bytes)."
		  (pure-irc-dcc-info-get-nick pure-irc-dcc-info)
		  (pure-irc-dcc-info-get-file pure-irc-dcc-info)
		  (pure-irc-dcc-info-get-size pure-irc-dcc-info)))
	((looking-at "DCC GETTING")
	 (pure-irc-dcc-info-put-status pure-irc-dcc-info 'client)
	 (funcall pure-irc-dcc-log-interface
		  "DCC GET from %s established (%s, %s bytes)."
		  (pure-irc-dcc-info-get-nick pure-irc-dcc-info)
		  (pure-irc-dcc-info-get-file pure-irc-dcc-info)
		  (pure-irc-dcc-info-get-size pure-irc-dcc-info)))
	((looking-at "DCC REPORT ")
	 (message "DCC REPORT: %s" (buffer-substring (match-end 0) end)))
	((looking-at "DCC WARNING Not Support Send Resume")
	 (message "DCC WARNING: not support send resume"))
	(t (pure-pr-dcc-irchat-error-parser proc))))

(defun pure-pr-dcc-irchat-chat-parser (proc)
  "DCC parser function for DCC CHAT."
  (cond ((looking-at "DCC CHAT \\([^ ]+\\) \\([^ ]+\\)")
	 (let ((pure-pr-my-addr (buffer-substring (match-beginning 1) (match-end 1)))
	       (pure-pr-my-port (buffer-substring (match-beginning 2) (match-end 2))))
	   (pure-irc-dcc-chat-listen)))
	((looking-at "DCC CHATTING")
	 (pure-irc-dcc-chat-connect
	  proc
	  (if (eq 'connect (pure-irc-dcc-info-get-status pure-irc-dcc-info)) 'client 'server))
	 (pure-pr-filter-set-parser proc 'pure-irc-dcc-chat-parser))
	(t (pure-pr-dcc-irchat-error-parser proc))))

(defun pure-pr-dcc-irchat-error-parser (proc)
  "DCC parser function for errors."
  (cond ((looking-at "DCC WARNINIG ")
	 (message "DCC WARNINIG: %s" (buffer-substring (match-end 0) (point-max))))
	((looking-at "DCC WARN ")
	 (message "DCC WARNINIG: %s" (buffer-substring (match-end 0) (point-max))))
	((looking-at "DCC ERROR1 ")
	 (funcall pure-irc-dcc-log-interface
		  "DCC ERROR: %s" (buffer-substring (match-end 0) (point-max)))
	 (pure-ds-add-list pure-irc-dcc-info pure-irc-dcc-offer-list))
	((looking-at "DCC ERROR ")
	 (funcall pure-irc-dcc-log-interface
		  "DCC ERROR: %s" (buffer-substring (match-end 0) (point-max))))
	(t ; unknown
	 (funcall pure-irc-dcc-log-interface
		  "DCC FATAL ERROR: %s" (buffer-substring (point-min) (point-max))))))

;; That's all
(provide 'pure-pr-dcc-irchat)

;;; pure-pr-dcc-irchat.el ends here