;;!emacs
;; $Id:
;;
;; FILE:         hmail.el
;; SUMMARY:      Support for Hyperbole buttons embedded in e-mail messages.
;; USAGE:        GNU Emacs Lisp Library
;;
;; AUTHOR:       Bob Weiner
;; ORG:          Brown U.
;;
;; ORIG-DATE:     9-Oct-91 at 18:38:05
;; LAST-MOD:     29-Oct-92 at 13:46:04 by Bob Weiner
;;
;; This file is part of Hyperbole.
;; 
;; Copyright (C) 1991, Brown University, Providence, RI
;; Developed with support from Motorola Inc.
;; 
;; Permission to use, modify and redistribute this software and its
;; documentation for any purpose other than its incorporation into a
;; commercial product is hereby granted without fee.  A distribution fee
;; may be charged with any redistribution.  Any distribution requires
;; that the above copyright notice appear in all copies, that both that
;; copyright notice and this permission notice appear in supporting
;; documentation, and that neither the name of Brown University nor the
;; author's name be used in advertising or publicity pertaining to
;; distribution of the software without specific, written prior permission.
;; 
;; Brown University makes no representations about the suitability of this
;; software for any purpose.  It is provided "as is" without express or
;; implied warranty.
;;
;;
;; DESCRIPTION:  
;;
;;   The 'hmail' class provides an abstract interface for connecting
;;   GNU Emacs-based mail readers and composers to Hyperbole.  Its
;;   public variables together with supporting classes determine the
;;   mail tools that Hyperbole will support.
;;
;;   The 'rmail' and 'lmail' classes provide a set of feature names
;;   that Hyperbole packages can call to interface to a user's selected
;;   mail reader.  Eventually, a full abstract calling interface may be
;;   developed.  The public features (the ones above the line of dashes)
;;   must be redefined for any mail reader.  The private features are
;;   used only by a particular mail reader.
;;
;;   The 'smail' class is similar; it connects a mail composer for use
;;   with Hyperbole.
;;
;; DESCRIP-END.

;;; ************************************************************************
;;; Public variables
;;; ************************************************************************

(defvar hnews:composer  nil
 "Major mode for composing USENET news to be sent with Hyperbole buttons.")
(defvar hnews:lister    nil
 "Major mode for listing USENET news header summaries with Hyperbole buttons.")
(defvar hnews:reader    nil
 "Major mode for reading USENET news with Hyperbole buttons.")

(defvar hmail:composer  nil
 "Major mode for composing mail to be sent with Hyperbole buttons.")
(defvar hmail:lister    nil
 "Major mode for listing mail header summaries with Hyperbole buttons.")
(defvar hmail:modifier  nil
 "Major mode for editing received mail with Hyperbole buttons.")
(defvar hmail:reader    nil
 "Major mode for reading mail with Hyperbole buttons.")

;;; ************************************************************************
;;; Public functions
;;; ************************************************************************

;;; ========================================================================
;;; hmail class - abstract
;;; ========================================================================

(defun hmail:hbdata-start (&optional msg-start msg-end)
  "Returns point immediately before any Hyperbole button data in current msg.
Returns message end point when no button data is found.
Has side-effect of widening buffer. 
Message's displayable part begins at optional MSG-START and ends at or before
MSG-END."
  (widen)
  (or msg-end (setq msg-end (point-max)))
  (save-excursion
    (goto-char msg-end)
    (if (search-backward hmail:hbdata-sep msg-start t) (1- (point)) msg-end)))

(defun hmail:hbdata-to-p ()
  "Moves point to Hyperbole but data start in an e-mail msg.
Returns t if button data is found."
  (and (cond ((memq major-mode (list hmail:reader hmail:modifier))
	      (rmail:msg-narrow) t)
	     ((or (hmail:lister-p) (hnews:lister-p)) t)
	     ((memq major-mode (list hmail:composer hnews:reader
				     hnews:composer))
	      (widen) t))
       (progn
	 (goto-char (point-max))
	 (if (search-backward hmail:hbdata-sep nil t)
	     (progn (forward-line 1) t)))))

(defun hmail:browser-p ()
  "Returns t iff current major mode helps browse received e-mail messages."
  (memq major-mode (list hmail:reader hmail:lister)))

(defun hmail:composing-dir (key-src)
  "If button KEY-SRC is a mail/news composure buffer, returns composure directory, else nil."
  (save-excursion
    (and (bufferp key-src)
	 (progn (set-buffer key-src)
		(or (eq major-mode hmail:composer)
		    (eq major-mode hnews:composer)))
	 default-directory)))

(defun hmail:editor-p ()
  "Returns t iff current major mode edits Hyperbole e-mail/news messages."
  (memq major-mode (list hmail:composer hnews:composer hmail:modifier)))

(defun hmail:init (class-prefix func-suffix-list)
  "Sets up CLASS-PREFIX functions with aliases for FUNC-SUFFIX-LIST.
'hmail:reader' should be set appropriately before this is called."
  (if (null hmail:reader)
      nil
    (let* ((reader-name (symbol-name hmail:reader))
	   (reader-prefix (capitalize
			   (substring reader-name
				      0 (string-match "-" reader-name))))
	   hmail-func)
      (mapcar '(lambda (func-suffix)
		 (setq hmail-func (hypb:replace-match-string
				   "Summ-" func-suffix ""))
		 (fset (intern (concat class-prefix hmail-func))
		       (intern (concat reader-prefix "-" func-suffix))))
	      func-suffix-list))))

(defun hmail:lister-p ()
  "Returns t iff current major mode is a Hyperbole e-mail lister mode."
  (eq major-mode hmail:lister))

(defun hnews:lister-p ()
  "Returns t iff current major mode is a Hyperbole news summary lister mode."
  (eq major-mode hnews:lister))

(defun hmail:mode-is-p ()
  "Returns current major mode if a Hyperbole e-mail mode, else nil."
  (car (memq major-mode
	     (list hmail:reader hmail:composer hmail:lister hmail:modifier
		   hnews:reader hnews:composer hnews:lister)
	     )))

(defun hmail:msg-narrow (&optional msg-start msg-end)
  "Narrows buffer to displayable part of current message.
Its displayable part begins at optional MSG-START and ends at or before
MSG-END."
  (if (hmail:reader-p) (rmail:msg-widen))
  (setq msg-start (or msg-start (point-min))
	msg-end (or msg-end (point-max)))
  (narrow-to-region msg-start (hmail:hbdata-start msg-start msg-end)))

(defun hmail:reader-p ()
  "Returns t iff current major mode shows received Hyperbole e-mail messages."
  (memq major-mode (list hmail:reader hmail:modifier)))

;;; ========================================================================
;;; rmail class - mail reader interface - abstract
;;; ========================================================================

(defun rmail:init ()
  "Initializes Hyperbole abstract mail interface for a particular mail reader.
'hmail:reader' should be set appropriately before this is called."
  (hmail:init "rmail:" '("msg-hdrs-full" "msg-narrow" "msg-num"
			 "msg-prev" "msg-next"
			 "msg-to-p"  ;; 2 args: (mail-msg-id mail-file)
			 "msg-widen" "to"))
  (hmail:init "lmail:" '("Summ-delete" "Summ-expunge" "Summ-goto" "Summ-to"
			 "Summ-undelete-all")))

(defvar rmail:msg-hdr-prefix "\\(^Date: \\|\n\nFrom [^ \n]+ \\)"
  "String header preceding an e-mail received message-id.")

(defun rmail:msg-id-get ()
  "Returns current msg id for an 'hmail:reader' buffer as a string, else nil.
Signals error when current mail reader is not supported."
  (let* ((reader (symbol-name hmail:reader))
	 (toggled))
    (or (fboundp 'rmail:msg-hdrs-full)
	(error "(rmail:msg-id-get): Invalid mail reader: %s" reader))
    (save-excursion
      (unwind-protect
	  (progn
	    ;; (setq toggled (rmail:msg-hdrs-full nil))
	    (goto-char (point-min))
	    (if (re-search-forward (concat rmail:msg-hdr-prefix
					   "\\(.+\\)"))
		;; Found matching msg
		(buffer-substring (match-beginning 2) (match-end 2))))
	;; (rmail:msg-hdrs-full toggled)
	()
	))))

;;; ------------------------------------------------------------------------
;;; Each mail reader-specific Hyperbole support module must also define
;;; the following functions, commonly aliased to existing mail reader
;;; functions within the "-init" function of the Hyperbole module.
;;; See "hrmail.el" for examples.
;;;
;;; rmail:get-new, rmail:msg-forward, rmail:summ-msg-to, rmail:summ-new

;;; ************************************************************************
;;; Private variables
;;; ************************************************************************

(defvar hmail:hbdata-sep "\^Lbd"
  "Text separating e-mail msg from any trailing Hyperbole button data.")

(provide 'hmail)
