diff lisp/hyperbole/hvm.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 4103f0995bd7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/hyperbole/hvm.el	Mon Aug 13 08:45:50 2007 +0200
@@ -0,0 +1,467 @@
+;;!emacs
+;;
+;; FILE:         hvm.el
+;; SUMMARY:      Support Hyperbole buttons in mail reader: Vm.
+;; USAGE:        GNU Emacs Lisp Library
+;; KEYWORDS:     hypermedia, mail
+;;
+;; AUTHOR:       Bob Weiner
+;; ORG:          Brown U.
+;;
+;; ORIG-DATE:    10-Oct-91 at 01:51:12
+;; LAST-MOD:     23-Jun-95 at 14:55:05 by Bob Weiner
+;;
+;; This file is part of Hyperbole.
+;; Available for use and distribution under the same terms as GNU Emacs.
+;;
+;; Copyright (C) 1991-1995, Free Software Foundation, Inc.
+;; Developed with support from Motorola Inc.
+;;
+;; DESCRIPTION:  
+;;
+;;   Automatically configured for use in "hyperbole.el".
+;;   If hsite loading fails prior to initializing Hyperbole Vm support,
+;;
+;;       {M-x Vm-init RTN}
+;;
+;;   will do it.
+;;
+;; DESCRIP-END.
+
+;;; ************************************************************************
+;;; Other required Elisp libraries
+;;; ************************************************************************
+
+(require 'hmail)
+(load "hsmail")
+(require 'vm)
+(or (and (fboundp 'vm-edit-message) (fboundp 'vm-edit-message-end))
+    (load "vm-edit"))
+(vm-session-initialization)
+
+;;; ************************************************************************
+;;; Public variables
+;;; ************************************************************************
+
+;;; Current versions of VM define this next variable in "vm-vars.el".  We
+;;; define it here for earlier VM versions.
+(defvar vm-edit-message-mode nil
+  "*Major mode to use when editing messages in VM.")
+
+;;; "hmail.el" procedures will branch improperly if a regular mode, like VM's
+;;; default 'text-mode', is used for editing.
+(setq vm-edit-message-mode 'vm-edit-mode)
+
+(defun vm-edit-mode ()
+  "Major mode for editing vm mail messages.
+  Special commands:\\{vm-edit-message-map}
+Turning on vm-edit-mode calls the value of the variable vm-edit-message-hook,
+if that value is non-nil."
+  (interactive)
+  (kill-all-local-variables)
+  (use-local-map vm-edit-message-map)
+  (setq mode-name "VM Edit")
+  (setq major-mode 'vm-edit-mode)
+  (setq local-abbrev-table text-mode-abbrev-table)
+  (set-syntax-table text-mode-syntax-table)
+  (run-hooks 'vm-edit-message-hook))
+
+;;; ************************************************************************
+;;; Public functions
+;;; ************************************************************************
+
+(defun Vm-init ()
+  "Initializes Hyperbole support for Vm mail reading."
+  (interactive)
+  (setq hmail:composer  'mail-mode
+	hmail:lister    'vm-summary-mode
+	hmail:modifier  'vm-edit-mode
+	hmail:reader    'vm-mode)
+  ;;
+  ;; Setup public abstract interface to Hyperbole defined mail
+  ;; reader-specific functions used in "hmail.el".
+  ;;
+  (rmail:init)
+  ;;
+  ;; Setup private abstract interface to mail reader-specific functions
+  ;; used in "hmail.el".
+  ;;
+  (fset 'rmail:get-new       'vm-get-new-mail)
+  (fset 'rmail:msg-forward   'vm-forward-message)
+  (fset 'rmail:summ-msg-to   'vm-follow-summary-cursor)
+  (fset 'rmail:summ-new      'vm-summarize)
+  (if (interactive-p)
+      (message "Hyperbole VM mail reader support initialized."))
+  )
+
+(defun Vm-msg-hdrs-full (toggled)
+  "If TOGGLED is non-nil, toggle full/hidden headers, else show full headers."
+  (save-excursion
+    (if (or toggled
+	    (let ((exposed (= (point-min)
+			      (vm-start-of (car vm-message-pointer)))))
+	      (not exposed)))
+	(progn (vm-expose-hidden-headers)
+	       (setq toggled t)))
+    toggled))
+
+(defun Vm-msg-narrow ()
+  "Narrows mail reader buffer to current message.
+This includes Hyperbole button data."
+  (save-excursion
+    (vm-select-folder-buffer)
+    (narrow-to-region (point-min) (Vm-msg-end))))
+
+(defun Vm-msg-next ()           (vm-next-message 1))
+
+(defun Vm-msg-num ()
+  "Returns number of vm mail message that point is within, in physical message order."
+  (interactive)
+  (let ((count 1)
+	(case-fold-search))
+    (save-excursion
+      (save-restriction
+	(widen)
+	(while (re-search-backward Vm-msg-start-regexp nil t)
+	  (setq count (1+ count)))))
+    count))
+
+(defun Vm-msg-prev ()           (vm-previous-message 1))
+
+(defun Vm-msg-to-p (mail-msg-id mail-file)
+  "Sets current buffer to start of msg with MAIL-MSG-ID in MAIL-FILE.
+Returns t if successful, else nil or signals error."
+  (if (not (file-readable-p mail-file))
+      nil
+    (vm-visit-folder mail-file)
+    (widen)
+    (goto-char 1)
+      (if (let ((case-fold-search))
+	    (re-search-forward (concat rmail:msg-hdr-prefix
+				       (regexp-quote mail-msg-id)) nil t))
+	  ;; Found matching msg
+	  (progn
+	    (setq buffer-read-only t)
+	    (vm-goto-message-at-point)
+	    t))))
+
+(defun Vm-msg-widen ()
+  "Widens buffer to full current message including Hyperbole button data."
+  (save-excursion
+    (vm-select-folder-buffer)
+    (narrow-to-region (point-min) (Vm-msg-end))))
+
+(defun Vm-to ()
+  "Sets current buffer to a mail reader buffer."
+  (and (eq major-mode 'vm-summary-mode) (set-buffer vm-mail-buffer)))
+
+(defun Vm-Summ-delete ()
+  (vm-follow-summary-cursor)
+  (vm-delete-message 1))
+
+(fset 'Vm-Summ-expunge          'vm-expunge-folder)
+
+(fset 'Vm-Summ-goto             'vm-follow-summary-cursor)
+
+(defun Vm-Summ-to ()
+  "Sets current buffer to a mail listing buffer."
+  (and (eq major-mode 'vm-mode) (set-buffer vm-summary-buffer)))
+
+(defun Vm-Summ-undelete-all ()
+  (message
+   "(Vm-Summ-undelete-all: Vm doesn't have an undelete all msgs function."))
+
+;;; ************************************************************************
+;;; Private functions
+;;; ************************************************************************
+
+(defun Vm-msg-end ()
+  "Returns end point for current Vm message, including Hyperbole button data.
+Has side-effect of widening buffer."
+  (save-excursion
+    (goto-char (point-min))
+    (widen)
+    (if (let ((case-fold-search))
+	  (re-search-forward Vm-msg-start-regexp nil t))
+	(match-beginning 0)
+      (point-max))))
+
+;;; Overlay version of this function from "vm-page.el" to hide any
+;;; Hyperbole button data whenever a message is displayed in its entirety.
+(defun vm-show-current-message ()
+  (save-excursion
+    (save-excursion
+      (goto-char (point-min))
+      (hmail:msg-narrow (point-min) (Vm-msg-end)))
+    (and vm-honor-page-delimiters
+	 (save-excursion
+	   (if (search-forward page-delimiter nil t)
+	       (progn
+		 (goto-char (match-beginning 0))
+		 (not (looking-at (regexp-quote hmail:hbdata-sep))))))
+	 (progn
+	   (if (looking-at page-delimiter)
+	       (forward-page 1))
+	   (vm-narrow-to-page))))
+  ;; don't mark the message as read if the user can't see it!
+  (if (vm-get-buffer-window (current-buffer))
+      (progn
+	(setq vm-system-state 'showing)
+	(cond ((vm-new-flag (car vm-message-pointer))
+	       (vm-set-new-flag (car vm-message-pointer) nil)))
+	(cond ((vm-unread-flag (car vm-message-pointer))
+	       (vm-set-unread-flag (car vm-message-pointer) nil)))
+	(vm-update-summary-and-mode-line)
+	(vm-howl-if-eom))
+    (if (fboundp 'hproperty:but-create) (hproperty:but-create))
+    (vm-update-summary-and-mode-line)))
+
+;;; Overlay version of this function from "vm-page.el" to treat end of
+;;; text (excluding Hyperbole button data) as end of message.
+(defun vm-scroll-forward-internal (arg)
+  (let ((direction (prefix-numeric-value arg))
+	(w (selected-window)))
+    (condition-case error-data
+	(progn (scroll-up arg) nil)
+      (error
+       (if (or (and (< direction 0)
+		    (> (point-min) (vm-text-of (car vm-message-pointer))))
+	       (and (>= direction 0)
+		    (/= (point-max)
+			(save-restriction
+			  (hmail:hbdata-start
+			   (point-min)
+			   (vm-text-end-of
+			    (car vm-message-pointer)))))))
+	   (progn
+	     (vm-widen-page)
+	     (if (>= direction 0)
+		 (progn
+		   (forward-page 1)
+		   (set-window-start w (point))
+		   nil )
+	       (if (or (bolp)
+		       (not (save-excursion
+			      (beginning-of-line)
+			      (looking-at page-delimiter))))
+		   (forward-page -1))
+	       (beginning-of-line)
+	       (set-window-start w (point))
+	       'tryagain))
+	 (if (eq (car error-data) 'end-of-buffer)
+	     (if vm-auto-next-message
+		 'next-message
+	       (set-window-point w (point))
+	       'end-of-message)))))))
+
+;;; Overlay version of this function from "vm-page.el" (called by
+;;; vm-scroll-* functions).  Make it keep Hyperbole button data hidden.
+(defun vm-widen-page ()
+  (if (or (> (point-min) (vm-text-of (car vm-message-pointer)))
+	  (/= (point-max) (vm-text-end-of (car vm-message-pointer))))
+      (hmail:msg-narrow (vm-vheaders-of (car vm-message-pointer))
+			(if (or (vm-new-flag (car vm-message-pointer))
+				(vm-unread-flag (car vm-message-pointer)))
+			    (vm-text-of (car vm-message-pointer))
+			  (vm-text-end-of (car vm-message-pointer))))))
+
+;;; Overlay version of this function from "vm-edit.el" to hide
+;;; Hyperbole button data when insert edited message from temporary buffer.
+(hypb:function-overload 'vm-edit-message nil '(hmail:msg-narrow))
+
+;;; Overlay version of this function from "vm-edit.el" to hide
+;;; Hyperbole button data when insert edited message from temporary buffer.
+(defun vm-edit-message-end ()
+  "End the edit of a message and copy the result to its folder."
+  (interactive)
+  (if (null vm-message-pointer)
+      (error "This is not a VM message edit buffer."))
+  (if (null (buffer-name (vm-buffer-of (car vm-message-pointer))))
+      (error "The folder buffer for this message has been killed."))
+  ;; make sure the message ends with a newline
+  (goto-char (point-max))
+  (and (/= (preceding-char) ?\n) (insert ?\n))
+  ;; munge message separators found in the edited message to
+  ;; prevent message from being split into several messages.
+  (vm-munge-message-separators (vm-message-type-of (car vm-message-pointer))
+			       (point-min) (point-max))
+  ;; for From_-with-Content-Length recompute the Content-Length header
+  (if (eq (vm-message-type-of (car vm-message-pointer))
+	  'From_-with-Content-Length)
+      (let ((buffer-read-only nil)
+	    length)
+	(goto-char (point-min))
+	;; first delete all copies of Content-Length
+	(while (and (re-search-forward vm-content-length-search-regexp nil t)
+		    (null (match-beginning 1))
+		    (progn (goto-char (match-beginning 0))
+			   (vm-match-header vm-content-length-header)))
+	  (delete-region (vm-matched-header-start) (vm-matched-header-end)))
+	;; now compute the message body length
+	(goto-char (point-min))
+	(search-forward "\n\n" nil 0)
+	(setq length (- (point-max) (point)))
+	;; insert the header
+	(goto-char (point-min))
+	(insert vm-content-length-header " " (int-to-string length) "\n")))
+  (let ((edit-buf (current-buffer))
+	(mp vm-message-pointer))
+    (if (buffer-modified-p)
+	(progn
+	  (widen)
+	  (save-excursion
+	    (set-buffer (vm-buffer-of (vm-real-message-of (car mp))))
+	    (if (not (memq (vm-real-message-of (car mp)) vm-message-list))
+		(error "The original copy of this message has been expunged."))
+	    (vm-save-restriction
+	     (widen)
+	     (goto-char (vm-headers-of (vm-real-message-of (car mp))))
+	     (let ((vm-message-pointer mp)
+		   (buffer-read-only nil))
+	       (insert-buffer-substring edit-buf)
+	       (delete-region
+		(point) (vm-text-end-of (vm-real-message-of (car mp))))
+	       (vm-discard-cached-data)
+	       (hmail:msg-narrow))
+	     (vm-set-edited-flag-of (car mp) t)
+	     (vm-mark-for-summary-update (car mp))
+	     (if (eq vm-flush-interval t)
+		 (vm-stuff-virtual-attributes (car mp))
+	       (vm-set-modflag-of (car mp) t))
+	     (vm-set-buffer-modified-p t)
+	     (vm-clear-modification-flag-undos)
+	     (vm-set-edit-buffer-of (car mp) nil))
+	    (set-buffer (vm-buffer-of (car mp)))
+	    (if (eq (vm-real-message-of (car mp))
+		    (vm-real-message-of (car vm-message-pointer)))
+		(vm-preview-current-message)
+	      (vm-update-summary-and-mode-line))))
+      (message "No change."))
+    (vm-display edit-buf nil '(vm-edit-message-end)
+		'(vm-edit-message-end reading-message startup))
+    (set-buffer-modified-p nil)
+    (kill-buffer edit-buf)))
+
+;;; Define this function if VM version in use doesn't have it.
+(or (fboundp 'vm-goto-message-at-point)
+(defun vm-goto-message-at-point ()
+  "In a VM folder buffer, select the message that contains point."
+  (cond ((fboundp 'vm-update-search-position)
+	 (vm-update-search-position t)
+	 ;; vm-show-current-message only adjusts (point-max),
+	 ;; it doesn't change (point-min).
+	 (narrow-to-region
+	  (vm-vheaders-of (car vm-message-pointer))
+	  (point-max))
+	 (vm-show-current-message)
+	 (setq vm-system-state 'reading))
+	((fboundp 'vm-isearch-update)
+	 (vm-isearch-update)
+	 (narrow-to-region
+	  (vm-vheaders-of (car vm-message-pointer))
+	  (point-max))
+	 (vm-show-current-message)
+	 (setq vm-system-state 'reading))
+	(t (error "vm search code is missing, can't continue"))))
+)
+
+;;; Hide any Hyperbole button data when reply to or forward a message.
+;;; See "vm-reply.el".
+(var:append 'vm-mail-mode-hook '(hmail:msg-narrow))
+
+;;; Overlay this function from "vm-folder.el" called whenever new mail is
+;;; incorporated so that it will highlight Hyperbole buttons when possible.
+;;  Returns non-nil if there were any new messages.
+(defun vm-assimilate-new-messages (&optional dont-read-attributes gobble-order)
+  (let ((tail-cons (vm-last vm-message-list))
+	b-list new-messages)
+    (save-excursion
+      (vm-save-restriction
+       (widen)
+       (if (fboundp 'hproperty:but-create)
+	   (hproperty:but-create))
+       (vm-build-message-list)
+       (if (or (null tail-cons) (cdr tail-cons))
+	   (progn
+	     (setq vm-ml-sort-keys nil)
+	     (if dont-read-attributes
+		 (vm-set-default-attributes (cdr tail-cons))
+	       (vm-read-attributes (cdr tail-cons)))
+	     ;; Yuck.  This has to be done here instead of in the
+	     ;; vm function because this needs to be done before
+	     ;; any initial thread sort (so that if the thread
+	     ;; sort matches the saved order the folder won't be
+	     ;; modified) but after the message list is created.
+	     ;; Since thread sorting is done here this has to be
+	     ;; done here too.
+	     (if gobble-order
+		 (vm-gobble-message-order))
+	     (if vm-thread-obarray
+		 (vm-build-threads (cdr tail-cons))))))
+      (setq new-messages (if tail-cons (cdr tail-cons) vm-message-list))
+      (vm-set-numbering-redo-start-point new-messages)
+      (vm-set-summary-redo-start-point new-messages))
+    (if vm-summary-show-threads
+	(progn
+	  ;; get numbering and summary of new messages done now
+	  ;; so that the sort code only has to worry about the
+	  ;; changes it needs to make.
+	  (vm-update-summary-and-mode-line)
+	  ;; copy the new-messages list because sorting might
+	  ;; scramble it.  vm-assimilate-new-messages returns
+	  ;; this value.
+	  (setq new-messages (copy-sequence new-messages))
+	  (vm-sort-messages "thread")))
+    (if (and new-messages vm-virtual-buffers)
+	(save-excursion
+	  (setq b-list vm-virtual-buffers)
+	  (while b-list
+	    ;; buffer might be dead
+	    (if (buffer-name (car b-list))
+		(let (tail-cons)
+		  (set-buffer (car b-list))
+		  (setq tail-cons (vm-last vm-message-list))
+		  (vm-build-virtual-message-list new-messages)
+		  (if (or (null tail-cons) (cdr tail-cons))
+		      (progn
+			(setq vm-ml-sort-keys nil)
+			(if vm-thread-obarray
+			    (vm-build-threads (cdr tail-cons)))
+			(vm-set-summary-redo-start-point
+			 (or (cdr tail-cons) vm-message-list))
+			(vm-set-numbering-redo-start-point
+			 (or (cdr tail-cons) vm-message-list))
+			(if (null vm-message-pointer)
+			    (progn (setq vm-message-pointer vm-message-list
+					 vm-need-summary-pointer-update t)
+				   (if vm-message-pointer
+				       (vm-preview-current-message))))
+			(if vm-summary-show-threads
+			    (progn
+			      (vm-update-summary-and-mode-line)
+			      (vm-sort-messages "thread")))))))
+	    (setq b-list (cdr b-list)))))
+    new-messages ))
+
+;;; Overlay version of 'vm-force-mode-line-update' from "vm-folder.el"
+;;; to highlight Hyperbole buttons in summary buffers.
+(defun vm-force-mode-line-update ()
+  "Force a mode line update in all frames."
+  (if vm-summary-buffer
+      (save-excursion
+	(set-buffer vm-summary-buffer)
+	(if (fboundp 'hproperty:but-create) (hproperty:but-create))))
+  (if (fboundp 'force-mode-line-update)
+      (force-mode-line-update t)
+    (save-excursion
+      (set-buffer (other-buffer))
+      (set-buffer-modified-p (buffer-modified-p)))))
+
+;;; ************************************************************************
+;;; Private variables
+;;; ************************************************************************
+
+(defvar Vm-msg-start-regexp "\n\nFrom \\|\n\001\001\001\001"
+  "Regular expression that begins a Vm mail message.")
+
+(provide 'hvm)