Files
mu4e/toys/mua/mua-view.el
Dirk-Jan C. Binnema 76c8d21c73 * mua updates
2011-08-16 00:09:34 +03:00

253 lines
7.4 KiB
EmacsLisp

;;; mua-view.el -- part of mua, the mu mail user agent
;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Keywords: email
;; Version: 0.0
;; This file is not part of GNU Emacs.
;;
;; GNU Emacs 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 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs 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. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; mu
;;; Code:
(eval-when-compile (require 'cl))
(require 'mua-common)
(require 'mua-msg)
(defconst mua/view-buffer-name " *mua-view*"
"buffer name for mua/view buffers")
(defvar mua/view-headers
'(:from :to :cc :subject :flags :date :maildir :path :attachments)
"Fields to display in the message view buffer.")
(defvar mua/hdrs-buffer nil
"Headers buffer for the view in this buffer.")
(defvar mua/view-uid nil
"The UID for the message being viewed in this buffer.")
(defun mua/view (uid headersbuf)
"display message identified by UID in a new buffer. Note that
the action of viewing a message may cause it to be moved/renamed;
this function returns the resulting name. PARENTBUF refers to the
buffer who invoked this view; this allows us to return there when
we quit from this view. Also, if PARENTBUF is a find buffer (ie.,
has mu-headers-mode as its major mode), this allows various
commands (navigation, marking etc.) to be applied to this
buffer.
For the reasoning to use UID here instead of just the path, see
`mua/msg-file-map'.
"
(let* ((path (mua/msg-file-get-path uid))
(sexp (and path (mua/mu-view-sexp path)))
(msg (and sexp (mua/msg-from-string sexp))))
(if (not msg)
(mua/warn "Cannot view message %S %S" uid path)
(progn
(switch-to-buffer (get-buffer-create mua/view-buffer-name))
(let ((inhibit-read-only t))
(erase-buffer)
(insert (mua/view-message msg)))
(mua/view-mode)
(setq ;; these are buffer-local
mua/view-uid uid
mua/hdrs-buffer headersbuf
mua/parent-buffer headersbuf)
(goto-char (point-min))
(mua/msg-file-mark-as-read uid)))))
(defun mua/view-message (msg)
"construct a display string for the message"
(let ((hdrs
(mapconcat
(lambda (field)
(case field
(:subject (mua/view-header msg "Subject" :subject))
(:path (mua/view-header msg "Path" :path))
(:to (mua/view-contacts msg field))
(:from (mua/view-contacts msg field))
(:cc (mua/view-contacts msg field))
(:bcc (mua/view-contacts msg field))
(:date (mua/view-date msg))
(:flags (mua/view-flags msg))
(:maildir (mua/view-header msg "Maildir" :maildir))
(:size (mua/view-size msg))
(:attachments (mua/view-attachments msg))
(t (error "Unsupported field: %S" field))))
mua/view-headers ""))
(body (mua/msg-body-txt-or-html msg)))
(concat hdrs "\n" body)))
(defun mua/view-header-string (key val face)
(if val
(concat
(propertize key 'face 'mua/header-title-face) ": "
(propertize val 'face face) "\n")
""))
(defun mua/view-header (msg key field)
"show header FIELD for MSG with KEY. ie. <KEY>: value-of-FIELD\n"
(mua/view-header-string key (mua/msg-field msg field) 'mua/header-face))
(defun mua/view-contacts (msg field)
(unless (member field '(:to :from :bcc :cc))
(error "Illegal type for contact"))
(let* ((lst (mua/msg-field msg field))
(contacts
(when lst
(mapconcat
(lambda(c) (let ((name (car c)) (email (cdr c)))
(if name
(format "%s <%s>" name email)
(format "%s" email)))) lst ", "))))
(if contacts
(mua/view-header-string
(case field (:to "To") (:from "From") (:bcc "Bcc") (:cc "Cc"))
contacts 'mua/contacts-face)
"")))
(defun mua/view-date (msg)
(let* ((date (mua/msg-field msg :date))
(datestr (when date (format-time-string "%c" date))))
(mua/view-header-string "Date" datestr 'mua/header-face)))
(defun mua/view-size (msg)
(let* ((size (mua/msg-field msg :size))
(sizestr (when size (format "%d bytes"))))
(mua/view-header-string "Size" sizestr 'mua-header-face)))
(defun mua/view-flags (msg)
""
"" ;; todo
)
(defun mua/view-attachments (msg)
""
"" ;; todo
)
(defvar mua/view-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "q" 'mua/quit-buffer)
(define-key map "s" 'mua/view-search)
(define-key map "f" 'mua/view-forward)
(define-key map "r" 'mua/view-reply)
(define-key map "c" 'mua/view-compose)
;; navigation between messages
(define-key map "n" 'mua/view-next)
(define-key map "p" 'mua/view-prev)
;; marking/unmarking
(define-key map "d" '(lambda() (mua/view-mark 'trash)))
(define-key map "D" '(lambda() (mua/view-mark 'delete)))
(define-key map "m" '(lambda() (mua/view-mark 'move)))
(define-key map "u" '(lambda() (mua/view-mark 'unmark)))
(define-key map "x" 'mua/view-marked-execute)
map)
"Keymap for \"*mua-view*\" buffers.")
(fset 'mua/view-mode-map mua/view-mode-map)
(defun mua/view-mode ()
"major mode for viewing an e-mail message"
(interactive)
(kill-all-local-variables)
(use-local-map mua/view-mode-map)
(make-local-variable 'mua/parent-buffer)
(make-local-variable 'mua/hdrs-buffer)
(make-local-variable 'mua/view-uid)
(setq major-mode 'mua/view-mode mode-name "*mu-view*")
(setq truncate-lines t buffer-read-only t))
(defmacro mua/with-hdrs-buffer (&rest body)
"Execute the forms in BODY with the mua/hdrs-buffer temporarily current.
Note that this actually switches the buffer, and changes to point
etc. persist."
(declare (indent 1) (debug t))
`(let ((oldbuf (current-buffer)))
(if (buffer-live-p mua/hdrs-buffer)
(progn
(set-buffer mua/hdrs-buffer)
(progn ,@body)
(set-buffer oldbuf))
(mua/warn "hdrs buffer is dead"))))
(defun mua/view-mark (action)
"Set/unset marks for the current message."
(interactive)
(mua/with-hdrs-buffer (mua/hdrs-mark action)))
(defun mua/view-marked-execute ()
"Warn user that marks cannot be executed from here (for his/her
own safety)."
(interactive)
(mua/warn "You cannot execute marks from here"))
(defun mua/view-search()
"Start a new search."
(interactive)
(mua/with-hdrs-buffer
(call-interactively 'mua/hdrs-search)))
(defun mua/view-next ()
"move to the next message; note, this will replace the current
buffer"
(interactive)
(mua/with-hdrs-buffer
(when (mua/hdrs-next) (mua/hdrs-view))))
(defun mua/view-prev ()
"move to the previous message; note, this will replace the
current buffer"
(interactive)
(mua/with-hdrs-buffer
(when (mua/hdrs-prev) (mua/hdrs-view))))
(defun mua/view-reply ()
"Reply to the current message."
(interactive) (mua/with-hdrs-buffer (mua/hdrs-reply)))
(defun mua/view-forward ()
"Reply to the current message."
(interactive) (mua/with-hdrs-buffer (mua/hdrs-forward)))
(defun mua/view-compose ()
"Write a new message."
(interactive) (mua/with-hdrs-buffer (mua/hdrs-compose)))
(provide 'mua-view)