* renamed mm -> mu4e

This commit is contained in:
djcb
2011-12-13 09:07:38 +02:00
parent aaaf49928d
commit b9805567ed
9 changed files with 895 additions and 896 deletions

View File

@ -18,18 +18,17 @@ include $(top_srcdir)/gtest.mk
SUBDIRS= SUBDIRS=
BUILT_SOURCES=mm-version.el BUILT_SOURCES=mu4e-version.el
mm-version.el: mu4e-version.el:
@echo -e ";; auto-generated\n\ @echo -e ";; auto-generated\n\
(defconst mm/mu-version \"$(VERSION)\" \"Required mu binary version.\")\n\ (defconst mu4e-mu-version \"$(VERSION)\" \"Required mu binary version.\")\n\
(provide 'mm-version)\n" >$@ (provide 'mu4e-version)\n" >$@
EXTRA_DIST= \ EXTRA_DIST= \
mm.el \ mu4e.el \
mm-hdrs.el \ mu4e-hdrs.el \
mm-view.el \ mu4e-view.el \
mm-proc.el \ mu4e-proc.el \
mm-send.el \ mu4e-send.el \
mm-version.el mu4e-version.el

View File

@ -1,4 +1,4 @@
;; mm-hdrs.el -- part of mm, the mu mail user agent ;; mu4e-hdrs.el -- part of mm, the mu mail user agent
;; ;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema ;; Copyright (C) 2011 Dirk-Jan C. Binnema
@ -34,55 +34,53 @@
(eval-when-compile (require 'cl)) (eval-when-compile (require 'cl))
(require 'mm-proc) (require 'mu4e-proc)
;;;; internal variables/constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; internal variables/constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar mm/last-expr nil (defvar mu4e-last-expr nil
"*internal* The most recent search expression.") "*internal* The most recent search expression.")
(defvar mm/sortfield nil (defvar mu4e-sortfield nil
"*internal* Field to sort headers by") "*internal* Field to sort headers by")
(defvar mm/sort-descending nil (defvar mu4e-sort-descending nil
"*internal Whether to sort in descending order") "*internal Whether to sort in descending order")
(defconst mm/hdrs-buffer-name "*mm-headers*" (defconst mu4e-hdrs-buffer-name "*mu4e-headers*"
"*internal* Name of the buffer for message headers.") "*internal* Name of the buffer for message headers.")
(defvar mm/hdrs-buffer nil (defvar mu4e-hdrs-buffer nil
"*internal* Buffer for message headers") "*internal* Buffer for message headers")
(defun mm/hdrs-search (expr &optional full-search) (defun mu4e-hdrs-search (expr &optional full-search)
"Search in the mu database for EXPR, and switch to the output "Search in the mu database for EXPR, and switch to the output
buffer for the results. If FULL-SEARCH is non-nil return all buffer for the results. If FULL-SEARCH is non-nil return all
results, otherwise, limit number of results to results, otherwise, limit number of results to
`mm/search-results-limit'." `mu4e-search-results-limit'."
(let ((buf (get-buffer-create mm/hdrs-buffer-name)) (let ((buf (get-buffer-create mu4e-hdrs-buffer-name))
(inhibit-read-only t)) (inhibit-read-only t))
(with-current-buffer buf (with-current-buffer buf
(erase-buffer) (erase-buffer)
(mm/hdrs-mode) (mu4e-hdrs-mode)
(setq (setq
mm/mm/marks-map nil
mm/msg-map (make-hash-table :size 1024 :rehash-size 2 :weakness nil)
mode-name expr mode-name expr
mm/last-expr expr mu4e-last-expr expr
mm/hdrs-buffer buf))) mu4e-hdrs-buffer buf)))
(switch-to-buffer mm/hdrs-buffer) (switch-to-buffer mu4e-hdrs-buffer)
(mm/proc-find expr ;; '-1' means 'unlimited search' (mu4e-proc-find expr ;; '-1' means 'unlimited search'
(if full-search -1 mm/search-results-limit))) (if full-search -1 mu4e-search-results-limit)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; handler functions ;; handler functions
;; ;;
;; next are a bunch of handler functions; those will be called from mm-proc in ;; next are a bunch of handler functions; those will be called from mu4e-proc in
;; response to output from the server process ;; response to output from the server process
(defun mm/hdrs-view-handler (msg) (defun mu4e-hdrs-view-handler (msg)
"Handler function for displaying a message." "Handler function for displaying a message."
(mm/view msg mm/hdrs-buffer)) (mu4e-view msg mu4e-hdrs-buffer))
(defun mm/hdrs-error-handler (err) (defun mu4e-hdrs-error-handler (err)
"Handler function for showing an error." "Handler function for showing an error."
(let ((errcode (plist-get err :error)) (let ((errcode (plist-get err :error))
(errmsg (plist-get err :error-message))) (errmsg (plist-get err :error-message)))
@ -90,57 +88,57 @@ results, otherwise, limit number of results to
(4 (message "No matches for this search query.")) (4 (message "No matches for this search query."))
(t (message (format "Error %d: %s" errcode errmsg)))))) (t (message (format "Error %d: %s" errcode errmsg))))))
(defun mm/hdrs-update-handler (msg is-move) (defun mu4e-hdrs-update-handler (msg is-move)
"Update handler, will be called when a message has been updated "Update handler, will be called when a message has been updated
in the database. This function will update the current list of in the database. This function will update the current list of
headers." headers."
(when (buffer-live-p mm/hdrs-buffer) (when (buffer-live-p mu4e-hdrs-buffer)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(let* ((docid (plist-get msg :docid)) (let* ((docid (plist-get msg :docid))
(marker (gethash docid mm/msg-map)) (marker (gethash docid mu4e-msg-map))
(point (when marker (marker-position marker)))) (point (when marker (marker-position marker))))
(when point ;; is the message present in this list? (when point ;; is the message present in this list?
;; if it's marked, unmark it now ;; if it's marked, unmark it now
(when (mm/hdrs-docid-is-marked docid) (mm/hdrs-mark 'unmark)) (when (mu4e-hdrs-docid-is-marked docid) (mu4e-hdrs-mark 'unmark))
;; first, remove the old one (otherwise, we'd have to headers with ;; first, remove the old one (otherwise, we'd have to headers with
;; the same docid... ;; the same docid...
(mm/hdrs-remove-handler docid) (mu4e-hdrs-remove-handler docid)
;; if we we're actually viewing this message (in mm/view mode), we ;; if we we're actually viewing this message (in mu4e-view mode), we
;; update the `mm/current-msg' there as well; that way, the flags can ;; update the `mu4e-current-msg' there as well; that way, the flags can
;; be updated, as well as the path (which is useful for viewing the ;; be updated, as well as the path (which is useful for viewing the
;; raw message) ;; raw message)
(let ((viewbuf (get-buffer mm/view-buffer-name))) (let ((viewbuf (get-buffer mu4e-view-buffer-name)))
(when (and viewbuf (buffer-live-p viewbuf)) (when (and viewbuf (buffer-live-p viewbuf))
(with-current-buffer viewbuf (with-current-buffer viewbuf
(when (eq docid (plist-get mm/current-msg :docid)) (when (eq docid (plist-get mu4e-current-msg :docid))
(setq mm/current-msg msg))))) (setq mu4e-current-msg msg)))))
;; now, if this update was about *moving* a message, we don't show it ;; now, if this update was about *moving* a message, we don't show it
;; anymore (of course, we cannot be sure if the message really no ;; anymore (of course, we cannot be sure if the message really no
;; longer matches the query, but this seem a good heuristic. ;; longer matches the query, but this seem a good heuristic.
;; if it was only a flag-change, show the message with its updated flags. ;; if it was only a flag-change, show the message with its updated flags.
(unless is-move (unless is-move
(mm/hdrs-header-handler msg point))))))) (mu4e-hdrs-header-handler msg point)))))))
(defun mm/hdrs-remove-handler (docid) (defun mu4e-hdrs-remove-handler (docid)
"Remove handler, will be called when a message has been removed "Remove handler, will be called when a message has been removed
from the database. This function will hide the remove message in from the database. This function will hide the remove message in
the current list of headers." the current list of headers."
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(let* ((marker (gethash docid mm/msg-map)) (let* ((marker (gethash docid mu4e-msg-map))
(pos (and marker (marker-position marker))) (pos (and marker (marker-position marker)))
(docid-at-pos (and pos (mm/hdrs-get-docid pos)))) (docid-at-pos (and pos (mu4e-hdrs-get-docid pos))))
(unless marker (error "Message %d not found" docid)) (unless marker (error "Message %d not found" docid))
(unless (eq docid docid-at-pos) (unless (eq docid docid-at-pos)
(error "At point %d, expected docid %d, but got %d" (error "At point %d, expected docid %d, but got %d"
pos docid docid-at-pos)) pos docid docid-at-pos))
(mm/hdrs-remove-header docid pos)))) (mu4e-hdrs-remove-header docid pos))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mm/hdrs-contact-str (contacts) (defun mu4e-hdrs-contact-str (contacts)
"Turn the list of contacts CONTACTS (with elements (NAME . EMAIL) "Turn the list of contacts CONTACTS (with elements (NAME . EMAIL)
into a string." into a string."
(mapconcat (mapconcat
@ -148,7 +146,7 @@ into a string."
(let ((name (car ct)) (email (cdr ct))) (let ((name (car ct)) (email (cdr ct)))
(or name email "?"))) contacts ", ")) (or name email "?"))) contacts ", "))
(defun mm/thread-prefix (thread) (defun mu4e-thread-prefix (thread)
"Calculate the thread prefix based on thread info THREAD." "Calculate the thread prefix based on thread info THREAD."
(if thread (if thread
(let ( (level (plist-get thread :level)) (let ( (level (plist-get thread :level))
@ -167,12 +165,12 @@ into a string."
;; FIXME: when updating an header line, we don't know the thread ;; FIXME: when updating an header line, we don't know the thread
;; stuff ;; stuff
(defun mm/hdrs-header-handler (msg &optional point) (defun mu4e-hdrs-header-handler (msg &optional point)
"Create a one line description of MSG in this buffer, at POINT, "Create a one line description of MSG in this buffer, at POINT,
if provided, or at the end of the buffer otherwise." if provided, or at the end of the buffer otherwise."
(let* ( (docid (plist-get msg :docid)) (let* ( (docid (plist-get msg :docid))
(thread-info (thread-info
(or (plist-get msg :thread) (gethash docid mm/thread-info-map))) (or (plist-get msg :thread) (gethash docid mu4e-thread-info-map)))
(line (line
(mapconcat (mapconcat
(lambda (f-w) (lambda (f-w)
@ -180,50 +178,50 @@ if provided, or at the end of the buffer otherwise."
(val (plist-get msg field)) (val (plist-get msg field))
(str (str
(case field (case field
(:subject (concat (mm/thread-prefix thread-info) val)) (:subject (concat (mu4e-thread-prefix thread-info) val))
((:maildir :path) val) ((:maildir :path) val)
((:to :from :cc :bcc) (mm/hdrs-contact-str val)) ((:to :from :cc :bcc) (mu4e-hdrs-contact-str val))
;; if we (ie. `user-mail-address' is the 'From', show ;; if we (ie. `user-mail-address' is the 'From', show
;; 'To', otherwise show From ;; 'To', otherwise show From
(:from-or-to (:from-or-to
(let* ((from-lst (plist-get msg :from)) (let* ((from-lst (plist-get msg :from))
(from (and from-lst (cdar from-lst)))) (from (and from-lst (cdar from-lst))))
(if (and from (string-match (if (and from (string-match
mm/user-mail-address-regexp from)) mu4e-user-mail-address-regexp from))
(concat "To " (concat "To "
(mm/hdrs-contact-str (plist-get msg :to))) (mu4e-hdrs-contact-str (plist-get msg :to)))
(mm/hdrs-contact-str from-lst)))) (mu4e-hdrs-contact-str from-lst))))
(:date (format-time-string mm/headers-date-format val)) (:date (format-time-string mu4e-headers-date-format val))
(:flags (mm/flags-to-string val)) (:flags (mu4e-flags-to-string val))
(:size (mm/display-size val)) (:size (mu4e-display-size val))
(t (error "Unsupported header field (%S)" field))))) (t (error "Unsupported header field (%S)" field)))))
(when str (when str
(if (not width) (if (not width)
str str
(truncate-string-to-width str width 0 ?\s t))))) (truncate-string-to-width str width 0 ?\s t)))))
mm/headers-fields " ")) mu4e-headers-fields " "))
(flags (plist-get msg :flags)) (flags (plist-get msg :flags))
(line (cond (line (cond
((member 'draft flags) ((member 'draft flags)
(propertize line 'face 'mm/draft-face 'draft t)) (propertize line 'face 'mu4e-draft-face 'draft t))
((member 'trashed flags) ((member 'trashed flags)
(propertize line 'face 'mm/trashed-face)) (propertize line 'face 'mu4e-trashed-face))
((member 'unread flags) ((member 'unread flags)
(propertize line 'face 'mm/unread-face)) (propertize line 'face 'mu4e-unread-face))
(t ;; else (t ;; else
(propertize line 'face 'mm/header-face))))) (propertize line 'face 'mu4e-header-face)))))
;; store the thread info, so we can use it when updating the message ;; store the thread info, so we can use it when updating the message
(when thread-info (when thread-info
(puthash docid thread-info mm/thread-info-map)) (puthash docid thread-info mu4e-thread-info-map))
(mm/hdrs-add-header line (plist-get msg :docid) (mu4e-hdrs-add-header line (plist-get msg :docid)
(if point point (point-max))))) (if point point (point-max)))))
(defun mm/hdrs-found-handler (count) (defun mu4e-hdrs-found-handler (count)
"Create a one line description of the number of headers found "Create a one line description of the number of headers found
after the end of the search results." after the end of the search results."
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(save-excursion (save-excursion
(goto-char (point-max)) (goto-char (point-max))
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
@ -235,7 +233,7 @@ after the end of the search results."
(otherwise "End of search results")) (otherwise "End of search results"))
;; (1 "Found 1 message") ;; (1 "Found 1 message")
;; (otherwise (format "Found %d messages" count))) ;; (otherwise (format "Found %d messages" count)))
'face 'mm/system-face 'intangible t)))))) 'face 'mu4e-system-face 'intangible t))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -243,115 +241,116 @@ after the end of the search results."
;;; hdrs-mode and mode-map ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; hdrs-mode and mode-map ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq mm/hdrs-mode-map nil) (setq mu4e-hdrs-mode-map nil)
(defvar mm/hdrs-mode-map nil (defvar mu4e-hdrs-mode-map nil
"Keymap for *mm-headers* buffers.") "Keymap for *mu4e-headers* buffers.")
(unless mm/hdrs-mode-map (unless mu4e-hdrs-mode-map
(setq mm/hdrs-mode-map (setq mu4e-hdrs-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map "s" 'mm/search) (define-key map "s" 'mu4e-search)
(define-key map "S" 'mm/search-full) (define-key map "S" 'mu4e-search-full)
(define-key map "b" 'mm/search-bookmark) (define-key map "b" 'mu4e-search-bookmark)
(define-key map "q" 'mm/quit-buffer) (define-key map "q" 'mu4e-quit-buffer)
;; (define-key map "o" 'mm/change-sort) ;; (define-key map "o" 'mu4e-change-sort)
(define-key map "g" 'mm/rerun-search) (define-key map "g" 'mu4e-rerun-search)
;; navigation ;; navigation
(define-key map "n" 'mm/next-header) (define-key map "n" 'mu4e-next-header)
(define-key map "p" 'mm/prev-header) (define-key map "p" 'mu4e-prev-header)
;; marking/unmarking/executing ;; marking/unmarking/executing
(define-key map (kbd "<backspace>") 'mm/mark-for-trash) (define-key map (kbd "<backspace>") 'mu4e-mark-for-trash)
(define-key map "d" 'mm/mark-for-trash) (define-key map "d" 'mu4e-mark-for-trash)
(define-key map (kbd "<delete>") 'mm/mark-for-delete) (define-key map (kbd "<delete>") 'mu4e-mark-for-delete)
(define-key map "D" 'mm/mark-for-delete) (define-key map "D" 'mu4e-mark-for-delete)
(define-key map "j" 'mm/jump-to-maildir) (define-key map "j" 'mu4e-jump-to-maildir)
(define-key map "m" 'mm/mark-for-move) (define-key map "m" 'mu4e-mark-for-move)
(define-key map "u" 'mm/unmark) (define-key map "u" 'mu4e-unmark)
(define-key map "U" 'mm/unmark-all) (define-key map "U" 'mu4e-unmark-all)
(define-key map "x" 'mm/execute-marks) (define-key map "x" 'mu4e-execute-marks)
;; message composition ;; message composition
(define-key map "r" 'mm/compose-reply) (define-key map "r" 'mu4e-compose-reply)
(define-key map "f" 'mm/compose-forward) (define-key map "f" 'mu4e-compose-forward)
(define-key map "c" 'mm/compose-new) (define-key map "c" 'mu4e-compose-new)
(define-key map "e" 'mm/edit-draft) (define-key map "e" 'mu4e-edit-draft)
(define-key map (kbd "RET") 'mm/view-message) (define-key map (kbd "RET") 'mu4e-view-message)
;; menu ;; menu
(define-key map [menu-bar] (make-sparse-keymap)) (define-key map [menu-bar] (make-sparse-keymap))
(let ((menumap (make-sparse-keymap "Headers"))) (let ((menumap (make-sparse-keymap "Headers")))
(define-key map [menu-bar headers] (cons "Headers" menumap)) (define-key map [menu-bar headers] (cons "Headers" menumap))
(define-key menumap [quit-buffer] '("Quit view" . mm/quit-buffer)) (define-key menumap [quit-buffer] '("Quit view" . mu4e-quit-buffer))
(define-key menumap [sepa0] '("--")) (define-key menumap [sepa0] '("--"))
(define-key menumap [execute-marks] '("Execute marks" . mm/execute-marks)) (define-key menumap [execute-marks] '("Execute marks" . mu4e-execute-marks))
(define-key menumap [unmark-all] '("Unmark all" . mm/unmark-all)) (define-key menumap [unmark-all] '("Unmark all" . mu4e-unmark-all))
(define-key menumap [unmark] '("Unmark" . mm/unmark)) (define-key menumap [unmark] '("Unmark" . mu4e-unmark))
(define-key menumap [mark-delete] '("Mark for deletion" . mm/mark-for-delete)) (define-key menumap [mark-delete] '("Mark for deletion" . mu4e-mark-for-delete))
(define-key menumap [mark-trash] '("Mark for trash" . mm/mark-for-trash)) (define-key menumap [mark-trash] '("Mark for trash" . mu4e-mark-for-trash))
(define-key menumap [mark-move] '("Mark for move" . mm/mark-for-move)) (define-key menumap [mark-move] '("Mark for move" . mu4e-mark-for-move))
(define-key menumap [sepa1] '("--")) (define-key menumap [sepa1] '("--"))
(define-key menumap [compose-new] '("Compose new" . mm/compose-new)) (define-key menumap [compose-new] '("Compose new" . mu4e-compose-new))
(define-key menumap [forward] '("Forward" . mm/compose-forward)) (define-key menumap [forward] '("Forward" . mu4e-compose-forward))
(define-key menumap [reply] '("Reply" . mm/compose-reply)) (define-key menumap [reply] '("Reply" . mu4e-compose-reply))
(define-key menumap [sepa2] '("--")) (define-key menumap [sepa2] '("--"))
(define-key menumap [refresh] '("Refresh" . mm/rerun-search)) (define-key menumap [refresh] '("Refresh" . mu4e-rerun-search))
(define-key menumap [search] '("Search" . mm/search)) (define-key menumap [search] '("Search" . mu4e-search))
(define-key menumap [search-full] '("Search full" . mm/search-full)) (define-key menumap [search-full] '("Search full" . mu4e-search-full))
(define-key menumap [jump] '("Jump to maildir" . mm/jump-to-maildir)) (define-key menumap [jump] '("Jump to maildir" . mu4e-jump-to-maildir))
(define-key menumap [sepa3] '("--")) (define-key menumap [sepa3] '("--"))
(define-key menumap [view] '("View" . mm/view-message)) (define-key menumap [view] '("View" . mu4e-view-message))
(define-key menumap [next] '("Next" . mm/next-header)) (define-key menumap [next] '("Next" . mu4e-next-header))
(define-key menumap [previous] '("Previous" . mm/prev-header)) (define-key menumap [previous] '("Previous" . mu4e-prev-header))
(define-key menumap [sepa4] '("--"))) (define-key menumap [sepa4] '("--")))
;;(define-key menumap [draft] '("Edit draft" . mm/compose-new)) ;;(define-key menumap [draft] '("Edit draft" . mu4e-compose-new))
map))) map)))
(fset 'mm/hdrs-mode-map mm/hdrs-mode-map) (fset 'mu4e-hdrs-mode-map mu4e-hdrs-mode-map)
(defun mm/hdrs-mode () (defun mu4e-hdrs-mode ()
"Major mode for displaying mua search results." "Major mode for displaying mua search results."
(interactive) (interactive)
(kill-all-local-variables) (kill-all-local-variables)
(use-local-map mm/hdrs-mode-map) (use-local-map mu4e-hdrs-mode-map)
(make-local-variable 'mm/last-expr) (make-local-variable 'mu4e-last-expr)
(make-local-variable 'mm/hdrs-proc) (make-local-variable 'mu4e-hdrs-proc)
(make-local-variable 'mm/marks-map) (make-local-variable 'mu4e-marks-map)
(make-local-variable 'mm/msg-map) (make-local-variable 'mu4e-msg-map)
(make-local-variable 'mm/thread-info-map) (make-local-variable 'mu4e-thread-info-map)
;; we register our handler functions for the mm-proc (mu server) output ;; we register our handler functions for the mu4e-proc (mu server) output
(setq mm/proc-error-func 'mm/hdrs-error-handler) (setq mu4e-proc-error-func 'mu4e-hdrs-error-handler)
(setq mm/proc-update-func 'mm/hdrs-update-handler) (setq mu4e-proc-update-func 'mu4e-hdrs-update-handler)
(setq mm/proc-header-func 'mm/hdrs-header-handler) (setq mu4e-proc-header-func 'mu4e-hdrs-header-handler)
(setq mm/proc-found-func 'mm/hdrs-found-handler) (setq mu4e-proc-found-func 'mu4e-hdrs-found-handler)
(setq mm/proc-view-func 'mm/hdrs-view-handler) (setq mu4e-proc-view-func 'mu4e-hdrs-view-handler)
(setq mm/proc-remove-func 'mm/hdrs-remove-handler) (setq mu4e-proc-remove-func 'mu4e-hdrs-remove-handler)
;; this last one is defined in mm-send.el ;; this last one is defined in mu4e-send.el
(setq mm/proc-compose-func 'mm/send-compose-handler) (setq mu4e-proc-compose-func 'mu4e-send-compose-handler)
(setq (setq
mm/marks-map (make-hash-table :size 16 :rehash-size 2) mu4e-marks-map (make-hash-table :size 16 :rehash-size 2)
mm/thread-info-map (make-hash-table :size 512 :rehash-size 2) mu4e-msg-map (make-hash-table :size 1024 :rehash-size 2 :weakness nil)
major-mode 'mm/hdrs-mode mu4e-thread-info-map (make-hash-table :size 512 :rehash-size 2)
major-mode 'mu4e-hdrs-mode
mode-name "mm: message headers" mode-name "mm: message headers"
truncate-lines t truncate-lines t
buffer-read-only t buffer-read-only t
@ -361,17 +360,17 @@ after the end of the search results."
(cons "* " (cons "* "
(map 'list (map 'list
(lambda (item) ;; FIXME (lambda (item) ;; FIXME
(let ((field (cdr (assoc (car item) mm/header-names))) (let ((field (cdr (assoc (car item) mu4e-header-names)))
(width (cdr item))) (width (cdr item)))
(concat (concat
(propertize (propertize
(if width (if width
(truncate-string-to-width field width 0 ?\s t) (truncate-string-to-width field width 0 ?\s t)
field) field)
'face 'mm/title-face) " "))) 'face 'mu4e-title-face) " ")))
mm/headers-fields)))) mu4e-headers-fields))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar mm/msg-map nil (defvar mu4e-msg-map nil
"*internal* A map (hashtable) which maps a database (Xapian) "*internal* A map (hashtable) which maps a database (Xapian)
docid (which uniquely identifies a message to a marker. where docid (which uniquely identifies a message to a marker. where
marker points to the buffer position for the message. marker points to the buffer position for the message.
@ -380,71 +379,71 @@ Using this map, we can update message headers which are currently
on the screen, when we receive (:update ) notices from the mu on the screen, when we receive (:update ) notices from the mu
server.") server.")
(defun mm/hdrs-add-header (str docid point) (defun mu4e-hdrs-add-header (str docid point)
"Add header STR with DOCID to the buffer at POINT." "Add header STR with DOCID to the buffer at POINT."
(unless docid (error "Invalid message")) (unless docid (error "Invalid message"))
(when (buffer-live-p mm/hdrs-buffer) (when (buffer-live-p mu4e-hdrs-buffer)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
(save-excursion (save-excursion
(goto-char point) (goto-char point)
;; Update `mm/msg-map' with MSG, and MARKER pointing to the buffer ;; Update `mu4e-msg-map' with MSG, and MARKER pointing to the buffer
;; position for the message header." ;; position for the message header."
(insert (propertize (concat " " str "\n") 'docid docid)) (insert (propertize (concat " " str "\n") 'docid docid))
(puthash docid (copy-marker point t) mm/msg-map)))))) (puthash docid (copy-marker point t) mu4e-msg-map))))))
(defun mm/hdrs-remove-header (docid point) (defun mu4e-hdrs-remove-header (docid point)
"Remove header with DOCID at POINT." "Remove header with DOCID at POINT."
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(goto-char point) (goto-char point)
;; sanity check ;; sanity check
(unless (eq docid (mm/hdrs-get-docid)) (unless (eq docid (mu4e-hdrs-get-docid))
(error "%d: Expected %d, but got %d" (error "%d: Expected %d, but got %d"
(line-number-at-pos) docid (mm/hdrs-get-docid))) (line-number-at-pos) docid (mu4e-hdrs-get-docid)))
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
;; (put-text-property (line-beginning-position line-beginning-positio 2) ;; (put-text-property (line-beginning-position line-beginning-positio 2)
;; 'invisible t)) ;; 'invisible t))
(delete-region (line-beginning-position) (line-beginning-position 2))) (delete-region (line-beginning-position) (line-beginning-position 2)))
(remhash docid mm/msg-map))) (remhash docid mu4e-msg-map)))
(defun mm/hdrs-mark-header (docid mark) (defun mu4e-hdrs-mark-header (docid mark)
"(Visually) mark the header for DOCID with character MARK." "(Visually) mark the header for DOCID with character MARK."
(let ((marker (gethash docid mm/msg-map))) (let ((marker (gethash docid mu4e-msg-map)))
;; (unless marker (error "Unregistered message")) ;; (unless marker (error "Unregistered message"))
(when marker (when marker
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(save-excursion (save-excursion
(let ((inhibit-read-only t) (pos (marker-position marker))) (let ((inhibit-read-only t) (pos (marker-position marker)))
(goto-char pos) (goto-char pos)
(delete-char 2) (delete-char 2)
(insert (propertize mark 'face 'mm/hdrs-marks-face) " ") (insert (propertize mark 'face 'mu4e-hdrs-marks-face) " ")
(put-text-property pos (put-text-property pos
(line-beginning-position 2) 'docid docid) (line-beginning-position 2) 'docid docid)
;; update the msg-map, ie., move it back to the start of the line ;; update the msg-map, ie., move it back to the start of the line
(puthash docid (puthash docid
(copy-marker (line-beginning-position) t) (copy-marker (line-beginning-position) t)
mm/msg-map))))))) mu4e-msg-map)))))))
(defun mm/hdrs-get-docid (&optional point) (defun mu4e-hdrs-get-docid (&optional point)
"Get the docid for the message at POINT, if provided, or (point), otherwise." "Get the docid for the message at POINT, if provided, or (point), otherwise."
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(get-text-property (if point point (point)) 'docid))) (get-text-property (if point point (point)) 'docid)))
(defun mm/dump-msg-map () (defun mu4e-dump-msg-map ()
"*internal* dump the message map (for debugging)." "*internal* dump the message map (for debugging)."
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(message "msg-map (%d)" (hash-table-count mm/msg-map)) (message "msg-map (%d)" (hash-table-count mu4e-msg-map))
(maphash (maphash
(lambda (k v) (lambda (k v)
(message "%s => %s" k v)) (message "%s => %s" k v))
mm/msg-map))) mu4e-msg-map)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; threadinfo-map ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; threadinfo-map ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar mm/thread-info-map nil (defvar mu4e-thread-info-map nil
"Map (hash) of docid->threadinfo; when filling the list of "Map (hash) of docid->threadinfo; when filling the list of
messages, we fill a map of thread info, such that when a header messages, we fill a map of thread info, such that when a header
changes (e.g., it's read-flag gets set) through some (:update changes (e.g., it's read-flag gets set) through some (:update
@ -456,7 +455,7 @@ server.")
;;; marks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; marks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar mm/marks-map nil (defvar mu4e-marks-map nil
"Map (hash) of docid->markinfo; when a message is marked, the "Map (hash) of docid->markinfo; when a message is marked, the
information is added here. information is added here.
@ -467,7 +466,7 @@ where
MARK is the type of mark (move, trash, delete) MARK is the type of mark (move, trash, delete)
TARGET (optional) is the target directory (for 'move')") TARGET (optional) is the target directory (for 'move')")
(defun mm/hdrs-mark-message (mark &optional target) (defun mu4e-hdrs-mark-message (mark &optional target)
"Mark (or unmark) message at point. MARK specifies the "Mark (or unmark) message at point. MARK specifies the
mark-type. For `move'-marks there is also the TARGET argument, mark-type. For `move'-marks there is also the TARGET argument,
which specifies to which maildir the message is to be moved. which specifies to which maildir the message is to be moved.
@ -477,10 +476,10 @@ The following marks are available, and the corresponding props:
MARK TARGET description MARK TARGET description
---------------------------------------------------------- ----------------------------------------------------------
`move' y move the message to some folder `move' y move the message to some folder
`trash' n move the message to `mm/trash-folder' `trash' n move the message to `mu4e-trash-folder'
`delete' n remove the message `delete' n remove the message
`unmark' n unmark this message" `unmark' n unmark this message"
(let* ((docid (mm/hdrs-get-docid)) (let* ((docid (mu4e-hdrs-get-docid))
(markkar (markkar
(case mark ;; the visual mark (case mark ;; the visual mark
('move "m") ('move "m")
@ -491,45 +490,45 @@ The following marks are available, and the corresponding props:
(t (error "Invalid mark %S" mark))))) (t (error "Invalid mark %S" mark)))))
(unless docid (error "No message on this line")) (unless docid (error "No message on this line"))
(save-excursion (save-excursion
(when (mm/hdrs-mark-header docid markkar)) (when (mu4e-hdrs-mark-header docid markkar))
;; update the hash -- remove everything current, and if add the new stuff, ;; update the hash -- remove everything current, and if add the new stuff,
;; unless we're unmarking ;; unless we're unmarking
(remhash docid mm/marks-map) (remhash docid mu4e-marks-map)
;; remove possible overlays ;; remove possible overlays
(remove-overlays (line-beginning-position) (line-end-position)) (remove-overlays (line-beginning-position) (line-end-position))
;; now, let's set a mark (unless we were unmarking) ;; now, let's set a mark (unless we were unmarking)
(unless (eql mark 'unmark) (unless (eql mark 'unmark)
(puthash docid (list (point-marker) mark target) mm/marks-map) (puthash docid (list (point-marker) mark target) mu4e-marks-map)
;; when we have a target (ie., when moving), show the target folder in ;; when we have a target (ie., when moving), show the target folder in
;; an overlay ;; an overlay
(when target (when target
(let* ((targetstr (propertize (concat "-> " target " ") (let* ((targetstr (propertize (concat "-> " target " ")
'face 'mm/system-face)) 'face 'mu4e-system-face))
(start (+ 2 (line-beginning-position))) ;; +2 for the marker fringe (start (+ 2 (line-beginning-position))) ;; +2 for the marker fringe
(overlay (make-overlay start (+ start (length targetstr))))) (overlay (make-overlay start (+ start (length targetstr)))))
(overlay-put overlay 'display targetstr))))))) (overlay-put overlay 'display targetstr)))))))
(defun mm/hdrs-mark (mark &optional target) (defun mu4e-hdrs-mark (mark &optional target)
"Mark the header at point, or, if "Mark the header at point, or, if
region is active, mark all headers in the region. Als see region is active, mark all headers in the region. Als see
`mm/hdrs-mark-message'." `mu4e-hdrs-mark-message'."
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(if (use-region-p) (if (use-region-p)
;; mark all messages in the region. ;; mark all messages in the region.
(save-excursion (save-excursion
(let ((b (region-beginning)) (e (region-end))) (let ((b (region-beginning)) (e (region-end)))
(goto-char b) (goto-char b)
(while (<= (line-beginning-position) e) (while (<= (line-beginning-position) e)
(mm/hdrs-mark-message mark target) (mu4e-hdrs-mark-message mark target)
(forward-line 1)))) (forward-line 1))))
;; just a single message ;; just a single message
(mm/hdrs-mark-message mark target)))) (mu4e-hdrs-mark-message mark target))))
(defun mm/hdrs-marks-execute () (defun mu4e-hdrs-marks-execute ()
"Execute the actions for all marked messages in this "Execute the actions for all marked messages in this
buffer. After the actions have been executed succesfully, the buffer. After the actions have been executed succesfully, the
affected messages are *hidden* from the current header list. Since affected messages are *hidden* from the current header list. Since
@ -539,47 +538,47 @@ certainty, we need to rerun the search, but we don't want to do
that automatically, as it may be too slow and/or break the users that automatically, as it may be too slow and/or break the users
flow. Therefore, we hide the message, which in practice seems to flow. Therefore, we hide the message, which in practice seems to
work well." work well."
(if (= 0 (hash-table-count mm/marks-map)) (if (= 0 (hash-table-count mu4e-marks-map))
(message "Nothing is marked") (message "Nothing is marked")
(maphash (maphash
(lambda (docid val) (lambda (docid val)
(let ((marker (nth 0 val)) (mark (nth 1 val)) (target (nth 2 val))) (let ((marker (nth 0 val)) (mark (nth 1 val)) (target (nth 2 val)))
(case mark (case mark
(move (move
(mm/proc-move-msg docid target)) (mu4e-proc-move-msg docid target))
(trash (trash
(unless mm/trash-folder (unless mu4e-trash-folder
(error "`mm/trash-folder' not set")) (error "`mu4e-trash-folder' not set"))
(mm/proc-move-msg docid mm/trash-folder "+T")) (mu4e-proc-move-msg docid mu4e-trash-folder "+T"))
(delete (delete
(mm/proc-remove-msg docid))))) (mu4e-proc-remove-msg docid)))))
mm/marks-map) mu4e-marks-map)
(mm/hdrs-unmark-all))) (mu4e-hdrs-unmark-all)))
(defun mm/hdrs-unmark-all () (defun mu4e-hdrs-unmark-all ()
"Unmark all marked messages." "Unmark all marked messages."
(unless (/= 0 (hash-table-count mm/marks-map)) (unless (/= 0 (hash-table-count mu4e-marks-map))
(error "Nothing is marked")) (error "Nothing is marked"))
(maphash (maphash
(lambda (docid val) (lambda (docid val)
(save-excursion (save-excursion
(goto-char (marker-position (nth 0 val))) (goto-char (marker-position (nth 0 val)))
(mm/hdrs-mark 'unmark))) (mu4e-hdrs-mark 'unmark)))
mm/marks-map)) mu4e-marks-map))
(defun mm/hdrs-view () (defun mu4e-hdrs-view ()
"View message at point." "View message at point."
(let ((docid (mm/hdrs-get-docid))) (let ((docid (mu4e-hdrs-get-docid)))
(unless docid (error "No message at point.")) (unless docid (error "No message at point."))
(mm/proc-view-msg docid))) (mu4e-proc-view-msg docid)))
(defun mm/hdrs-compose (compose-type) (defun mu4e-hdrs-compose (compose-type)
"Compose either a reply/forward based on the message at point. or "Compose either a reply/forward based on the message at point. or
start editing it. COMPOSE-TYPE is either `reply', `forward' or start editing it. COMPOSE-TYPE is either `reply', `forward' or
`edit'." `edit'."
(if (eq compose-type 'new) (if (eq compose-type 'new)
(mm/send-compose-handler 'new) (mu4e-send-compose-handler 'new)
(let ((docid (mm/hdrs-get-docid)) (let ((docid (mu4e-hdrs-get-docid))
;; note, the first two chars of the line (the mark margin) does *not* ;; note, the first two chars of the line (the mark margin) does *not*
;; have the 'draft property; thus, we check one char before the end of ;; have the 'draft property; thus, we check one char before the end of
;; the current line instead ;; the current line instead
@ -588,17 +587,17 @@ start editing it. COMPOSE-TYPE is either `reply', `forward' or
(error "No message at point.")) (error "No message at point."))
(cond (cond
((member compose-type '(reply forward)) ((member compose-type '(reply forward))
(mm/proc-compose compose-type docid)) (mu4e-proc-compose compose-type docid))
((eq compose-type 'edit) ((eq compose-type 'edit)
(unless is-draft (unless is-draft
(error "Cannot edit a non-draft message")) (error "Cannot edit a non-draft message"))
(mm/proc-compose 'edit docid)) (mu4e-proc-compose 'edit docid))
(t (error "invalid compose type %S" compose-type)))))) (t (error "invalid compose type %S" compose-type))))))
(defun mm/hdrs-docid-is-marked (docid) (defun mu4e-hdrs-docid-is-marked (docid)
"Is the given docid marked?" "Is the given docid marked?"
(when (gethash docid mm/marks-map) t)) (when (gethash docid mu4e-marks-map) t))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -606,174 +605,174 @@ start editing it. COMPOSE-TYPE is either `reply', `forward' or
;;; interactive functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; interactive functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mm/ignore-marks () (defun mu4e-ignore-marks ()
(let* (let*
((num ((num
(hash-table-count mm/marks-map)) (hash-table-count mu4e-marks-map))
(unmark (or (= 0 num) (unmark (or (= 0 num)
(y-or-n-p (y-or-n-p
(format "Sure you want to unmark %d message(s)?" num))))) (format "Sure you want to unmark %d message(s)?" num)))))
(message nil) (message nil)
unmark)) unmark))
(defun mm/search (expr) (defun mu4e-search (expr)
"Start a new mu search, limited to `mm/search-results-limit' "Start a new mu search, limited to `mu4e-search-results-limit'
results." results."
(interactive "s[mu] search for: ") (interactive "s[mu] search for: ")
(when (mm/ignore-marks) (mm/hdrs-search expr))) (when (mu4e-ignore-marks) (mu4e-hdrs-search expr)))
(defun mm/search-full (expr) (defun mu4e-search-full (expr)
"Start a new mu search; resturn *all* results." "Start a new mu search; resturn *all* results."
(interactive "s[mu] full search for: ") (interactive "s[mu] full search for: ")
(when (mm/ignore-marks) (when (mu4e-ignore-marks)
(mm/hdrs-search expr t))) (mu4e-hdrs-search expr t)))
(defun mm/search-bookmark () (defun mu4e-search-bookmark ()
"Search using some bookmarked query." "Search using some bookmarked query."
(interactive) (interactive)
(let ((query (mm/ask-bookmark "Bookmark: "))) (let ((query (mu4e-ask-bookmark "Bookmark: ")))
(when query (when query
(mm/hdrs-search query)))) (mu4e-hdrs-search query))))
(defun mm/quit-buffer () (defun mu4e-quit-buffer ()
"Quit the current buffer." "Quit the current buffer."
(interactive) (interactive)
(when (mm/ignore-marks) (when (mu4e-ignore-marks)
(mm/kill-proc) ;; hmmm... (mu4e-kill-proc) ;; hmmm...
(kill-buffer) (kill-buffer)
(mm))) (mm)))
(defun mm/rerun-search () (defun mu4e-rerun-search ()
"Rerun the search for the last search expression; if none exists, "Rerun the search for the last search expression; if none exists,
do a new search." do a new search."
(interactive) (interactive)
(when (mm/ignore-marks) (when (mu4e-ignore-marks)
(if mm/last-expr (if mu4e-last-expr
(mm/hdrs-search mm/last-expr) (mu4e-hdrs-search mu4e-last-expr)
(mm/search)))) (mu4e-search))))
(defun mm/view-message () (defun mu4e-view-message ()
"View the message at point." "View the message at point."
(interactive) (interactive)
(mm/hdrs-view)) (mu4e-hdrs-view))
(defun mm/next-header () (defun mu4e-next-header ()
"Move point to the next message header. If this succeeds, return "Move point to the next message header. If this succeeds, return
the new docid. Otherwise, return nil." the new docid. Otherwise, return nil."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(when (= 0 (forward-line 1)) (when (= 0 (forward-line 1))
(or (mm/hdrs-get-docid) (mm/next-header)) ;; skip non-headers (or (mu4e-hdrs-get-docid) (mu4e-next-header)) ;; skip non-headers
;; trick to move point, even if this function is called when this window ;; trick to move point, even if this function is called when this window
;; is not visible ;; is not visible
(set-window-point (get-buffer-window mm/hdrs-buffer) (point))))) (set-window-point (get-buffer-window mu4e-hdrs-buffer) (point)))))
(defun mm/prev-header () (defun mu4e-prev-header ()
"Move point to the previous message header. If this succeeds, "Move point to the previous message header. If this succeeds,
return the new docid. Otherwise, return nil." return the new docid. Otherwise, return nil."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(when (= 0 (forward-line -1)) (when (= 0 (forward-line -1))
(or (mm/hdrs-get-docid) (mm/prev-header)) ;; skip non-headers (or (mu4e-hdrs-get-docid) (mu4e-prev-header)) ;; skip non-headers
;; trick to move point, even if this function is called when this window ;; trick to move point, even if this function is called when this window
;; is not visible ;; is not visible
(set-window-point (get-buffer-window mm/hdrs-buffer) (point))))) (set-window-point (get-buffer-window mu4e-hdrs-buffer) (point)))))
(defun mm/jump-to-maildir () (defun mu4e-jump-to-maildir ()
"Show the messages in maildir TARGET. If TARGET is not provided, "Show the messages in maildir TARGET. If TARGET is not provided,
ask user for it." ask user for it."
(interactive) (interactive)
(let ((fld (mm/ask-maildir "Jump to maildir: "))) (let ((fld (mu4e-ask-maildir "Jump to maildir: ")))
(when fld (when fld
(mm/hdrs-search (concat "maildir:" fld))))) (mu4e-hdrs-search (concat "maildir:" fld)))))
(defun mm/mark-for-move (&optional target) (defun mu4e-mark-for-move (&optional target)
"Mark message at point for moving to maildir TARGET. If target is "Mark message at point for moving to maildir TARGET. If target is
not provided, function asks for it." not provided, function asks for it."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(let* ((target (or target (mm/ask-maildir "Move message to: "))) (let* ((target (or target (mu4e-ask-maildir "Move message to: ")))
(fulltarget (concat mm/maildir target))) (fulltarget (concat mu4e-maildir target)))
(when (or (file-directory-p fulltarget) (when (or (file-directory-p fulltarget)
(and (yes-or-no-p (and (yes-or-no-p
(format "%s does not exist. Create now?" fulltarget)) (format "%s does not exist. Create now?" fulltarget))
(mm/proc-mkdir fulltarget))) (mu4e-proc-mkdir fulltarget)))
(mm/hdrs-mark 'move target) (mu4e-hdrs-mark 'move target)
(mm/next-header))))) (mu4e-next-header)))))
(defun mm/mark-for-trash () (defun mu4e-mark-for-trash ()
"Mark message at point for moving to the trash "Mark message at point for moving to the trash
folder (`mm/trash-folder')." folder (`mu4e-trash-folder')."
(interactive) (interactive)
(unless mm/trash-folder (unless mu4e-trash-folder
(error "`mm/trash-folder' is not set")) (error "`mu4e-trash-folder' is not set"))
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(mm/hdrs-mark 'trash) (mu4e-hdrs-mark 'trash)
(mm/next-header))) (mu4e-next-header)))
(defun mm/mark-for-delete () (defun mu4e-mark-for-delete ()
"Mark message at point for direct deletion." "Mark message at point for direct deletion."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(mm/hdrs-mark 'delete) (mu4e-hdrs-mark 'delete)
(mm/next-header))) (mu4e-next-header)))
(defun mm/unmark () (defun mu4e-unmark ()
"Unmark message at point." "Unmark message at point."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(mm/hdrs-mark 'unmark) (mu4e-hdrs-mark 'unmark)
(mm/next-header))) (mu4e-next-header)))
(defun mm/unmark-all () (defun mu4e-unmark-all ()
"Unmark all messages." "Unmark all messages."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(if (= 0 (hash-table-count mm/marks-map)) (if (= 0 (hash-table-count mu4e-marks-map))
(message "Nothing is marked") (message "Nothing is marked")
(when (mm/ignore-marks) (when (mu4e-ignore-marks)
(mm/hdrs-unmark-all))))) (mu4e-hdrs-unmark-all)))))
(defun mm/execute-marks () (defun mu4e-execute-marks ()
"Execute the actions for the marked messages." "Execute the actions for the marked messages."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(if (= 0 (hash-table-count mm/marks-map)) (if (= 0 (hash-table-count mu4e-marks-map))
(message "Nothing is marked") (message "Nothing is marked")
(when (y-or-n-p (format "Sure you want to execute marks on %d message(s)?" (when (y-or-n-p (format "Sure you want to execute marks on %d message(s)?"
(hash-table-count mm/marks-map))) (hash-table-count mu4e-marks-map)))
(mm/hdrs-marks-execute) (mu4e-hdrs-marks-execute)
(message nil))))) (message nil)))))
(defun mm/compose-reply () (defun mu4e-compose-reply ()
"Start composing a reply to the current message." "Start composing a reply to the current message."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(mm/hdrs-compose 'reply))) (mu4e-hdrs-compose 'reply)))
(defun mm/compose-forward () (defun mu4e-compose-forward ()
"Start composing a forward to the current message." "Start composing a forward to the current message."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(mm/hdrs-compose 'forward))) (mu4e-hdrs-compose 'forward)))
(defun mm/compose-new () (defun mu4e-compose-new ()
"Compose a new, empty message." "Compose a new, empty message."
(interactive) (interactive)
(mm/hdrs-compose 'new)) (mu4e-hdrs-compose 'new))
(defun mm/edit-draft () (defun mu4e-edit-draft ()
"Start editing the existing draft message at point." "Start editing the existing draft message at point."
(interactive) (interactive)
(with-current-buffer mm/hdrs-buffer (with-current-buffer mu4e-hdrs-buffer
(mm/hdrs-compose 'edit))) (mu4e-hdrs-compose 'edit)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(provide 'mm-hdrs) (provide 'mu4e-hdrs)

View File

@ -1,4 +1,4 @@
;;; mm-main.el -- part of mm, the mu mail user agent ;;; mu4e-main.el -- part of mm, the mu mail user agent
;; ;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema ;; Copyright (C) 2011 Dirk-Jan C. Binnema
@ -29,85 +29,85 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; mm main view mode + keybindings ;; mm main view mode + keybindings
(defconst mm/main-buffer-name "*mm*" (defconst mu4e-main-buffer-name "*mu4e-main*"
"*internal* Name of the mm main view buffer.") "*internal* Name of the mm main buffer.")
(defvar mm/mm-mode-map (defvar mu4e-main-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map "b" 'mm/search-bookmark) (define-key map "b" 'mu4e-search-bookmark)
(define-key map "s" 'mm/search) (define-key map "s" 'mu4e-search)
(define-key map "S" 'mm/search-full) (define-key map "S" 'mu4e-search-full)
(define-key map "q" 'mm/quit-mm) (define-key map "q" 'mu4e-quit-mm)
(define-key map "j" 'mm/jump-to-maildir) (define-key map "j" 'mu4e-jump-to-maildir)
(define-key map "c" 'mm/compose-new) (define-key map "c" 'mu4e-compose-new)
(define-key map "m" 'mm/toggle-mail-sending-mode) (define-key map "m" 'mu4e-toggle-mail-sending-mode)
(define-key map "f" 'smtpmail-send-queued-mail) (define-key map "f" 'smtpmail-send-queued-mail)
(define-key map "u" 'mm/retrieve-mail-update-db) (define-key map "u" 'mu4e-retrieve-mail-update-db)
map) map)
"Keymap for the *mm* buffer.") "Keymap for the *mm* buffer.")
(fset 'mm/mm-mode-map mm/mm-mode-map) (fset 'mu4e-main-mode-map mu4e-main-mode-map)
(defun mm/mm-mode () (defun mu4e-main-mode ()
"Major mode for the mm main screen." "Major mode for the mm main screen."
(interactive) (interactive)
(kill-all-local-variables) (kill-all-local-variables)
(use-local-map mm/mm-mode-map) (use-local-map mu4e-main-mode-map)
(setq (setq
mm/marks-map (make-hash-table :size 16 :rehash-size 2) mu4e-marks-map (make-hash-table :size 16 :rehash-size 2)
major-mode 'mm/mm-mode major-mode 'mu4e-main-mode
mode-name "mm: main view" mode-name "mu for emacs"
truncate-lines t truncate-lines t
buffer-read-only t buffer-read-only t
overwrite-mode 'overwrite-mode-binary)) overwrite-mode 'overwrite-mode-binary))
(defun mm/action-str (str) (defun mu4e-action-str (str)
"Highlight the first occurence of [..] in STR." "Highlight the first occurence of [..] in STR."
(if (string-match "\\[\\(\\w+\\)\\]" str) (if (string-match "\\[\\(\\w+\\)\\]" str)
(let* ((key (match-string 1 str)) (let* ((key (match-string 1 str))
(keystr (propertize key 'face 'mm/highlight-face))) (keystr (propertize key 'face 'mu4e-highlight-face)))
(replace-match keystr nil t str 1)) (replace-match keystr nil t str 1))
str)) str))
(defun mm/main-view() (defun mu4e-main-view()
"Show the mm main view." "Show the mm main view."
(let ((buf (get-buffer-create mm/main-buffer-name)) (let ((buf (get-buffer-create mu4e-main-buffer-name))
(inhibit-read-only t)) (inhibit-read-only t))
(with-current-buffer buf (with-current-buffer buf
(erase-buffer) (erase-buffer)
(insert (insert
"* " "* "
(propertize "mm - mu mail for emacs version " 'face 'mm/title-face) (propertize "mu4e - mu for emacs version " 'face 'mu4e-title-face)
(propertize mm/mu-version 'face 'mm/view-header-key-face) (propertize mu4e-mu-version 'face 'mu4e-view-header-key-face)
"\n\n" "\n\n"
(propertize " Basics\n\n" 'face 'mm/title-face) (propertize " Basics\n\n" 'face 'mu4e-title-face)
(mm/action-str "\t* [j]ump to some maildir\n") (mu4e-action-str "\t* [j]ump to some maildir\n")
(mm/action-str "\t* enter a [s]earch query\n") (mu4e-action-str "\t* enter a [s]earch query\n")
(mm/action-str "\t* [c]ompose a new message\n") (mu4e-action-str "\t* [c]ompose a new message\n")
"\n" "\n"
(propertize " Bookmarks\n\n" 'face 'mm/title-face) (propertize " Bookmarks\n\n" 'face 'mu4e-title-face)
(mapconcat (mapconcat
(lambda (bm) (lambda (bm)
(let* ((query (nth 0 bm)) (title (nth 1 bm)) (key (nth 2 bm))) (let* ((query (nth 0 bm)) (title (nth 1 bm)) (key (nth 2 bm)))
(mm/action-str (mu4e-action-str
(concat "\t* [b" (make-string 1 key) "] " title)))) (concat "\t* [b" (make-string 1 key) "] " title))))
mm/bookmarks "\n") mu4e-bookmarks "\n")
"\n" "\n"
(propertize " Misc\n\n" 'face 'mm/title-face) (propertize " Misc\n\n" 'face 'mu4e-title-face)
(mm/action-str "\t* [u]pdate email & database\n") (mu4e-action-str "\t* [u]pdate email & database\n")
(mm/action-str "\t* toggle [m]ail sending mode ") (mu4e-action-str "\t* toggle [m]ail sending mode ")
"(" (propertize (if smtpmail-queue-mail "queued" "direct") "(" (propertize (if smtpmail-queue-mail "queued" "direct")
'face 'mm/view-header-key-face) ")\n" 'face 'mu4e-view-header-key-face) ")\n"
(mm/action-str "\t* [f]lush queued mail\n") (mu4e-action-str "\t* [f]lush queued mail\n")
"\n" "\n"
(mm/action-str "\t* [q]uit mm\n")) (mu4e-action-str "\t* [q]uit mm\n"))
(mm/mm-mode) (mu4e-main-mode)
(switch-to-buffer buf)))) (switch-to-buffer buf))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -115,12 +115,12 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Interactive functions ;; Interactive functions
(defun mm/retrieve-mail-update-db () (defun mu4e-retrieve-mail-update-db ()
"Get new mail and update the database." "Get new mail and update the database."
(interactive) (interactive)
(mm/proc-retrieve-mail-update-db)) (mu4e-proc-retrieve-mail-update-db))
(defun mm/toggle-mail-sending-mode () (defun mu4e-toggle-mail-sending-mode ()
"Toggle sending mail mode, either queued or direct." "Toggle sending mail mode, either queued or direct."
(interactive) (interactive)
(setq smtpmail-queue-mail (not smtpmail-queue-mail)) (setq smtpmail-queue-mail (not smtpmail-queue-mail))
@ -131,12 +131,12 @@
(mm)) (mm))
(defun mm/quit-mm() (defun mu4e-quit-mm()
"Quit the mm session." "Quit the mm session."
(interactive) (interactive)
(when (y-or-n-p "Are you sure you want to quit mm? ") (when (y-or-n-p "Are you sure you want to quit mm? ")
(message nil) (message nil)
(mm/kill-proc) (mu4e-kill-proc)
(kill-buffer))) (kill-buffer)))
(provide 'mm-main) (provide 'mu4e-main)

View File

@ -1,4 +1,4 @@
;;; mm-proc.el -- part of mm, the mu mail user agent ;;; mu4e-proc.el -- part of mm, the mu mail user agent
;; ;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema ;; Copyright (C) 2011 Dirk-Jan C. Binnema
@ -30,65 +30,65 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; internal vars ;; internal vars
(defvar mm/mu-proc nil (defvar mu4e-mu-proc nil
"*internal* The mu-server process") "*internal* The mu-server process")
(defvar mm/proc-error-func 'mm/default-handler (defvar mu4e-proc-error-func 'mu4e-default-handler
"*internal* A function called for each error returned from the "*internal* A function called for each error returned from the
server process; the function is passed an error plist as server process; the function is passed an error plist as
argument. See `mm/proc-filter' for the format.") argument. See `mu4e-proc-filter' for the format.")
(defvar mm/proc-update-func 'mm/default-handler (defvar mu4e-proc-update-func 'mu4e-default-handler
"*internal* A function called for each :update sexp returned from "*internal* A function called for each :update sexp returned from
the server process; the function is passed a msg sexp as the server process; the function is passed a msg sexp as
argument. See `mm/proc-filter' for the format.") argument. See `mu4e-proc-filter' for the format.")
(defvar mm/proc-remove-func 'mm/default-handler (defvar mu4e-proc-remove-func 'mu4e-default-handler
"*internal* A function called for each :remove sexp returned from "*internal* A function called for each :remove sexp returned from
the server process, when some message has been deleted. The the server process, when some message has been deleted. The
function is passed the docid of the removed message.") function is passed the docid of the removed message.")
(defvar mm/proc-view-func 'mm/default-handler (defvar mu4e-proc-view-func 'mu4e-default-handler
"*internal* A function called for each single message sexp "*internal* A function called for each single message sexp
returned from the server process. The function is passed a message returned from the server process. The function is passed a message
sexp as argument. See `mm/proc-filter' for the sexp as argument. See `mu4e-proc-filter' for the
format.") format.")
(defvar mm/proc-header-func 'mm/default-handler (defvar mu4e-proc-header-func 'mu4e-default-handler
"*internal* A function called for each message returned from the "*internal* A function called for each message returned from the
server process; the function is passed a msg plist as argument. See server process; the function is passed a msg plist as argument. See
`mm/proc-filter' for the format.") `mu4e-proc-filter' for the format.")
(defvar mm/proc-found-func 'mm/default-handler (defvar mu4e-proc-found-func 'mu4e-default-handler
"*internal* A function called for when we received a :found sexp "*internal* A function called for when we received a :found sexp
after the headers have returns, to report on the number of after the headers have returns, to report on the number of
matches. See `mm/proc-filter' for the format.") matches. See `mu4e-proc-filter' for the format.")
(defvar mm/proc-compose-func 'mm/default-handler (defvar mu4e-proc-compose-func 'mu4e-default-handler
"*internal* A function called for each message returned from the "*internal* A function called for each message returned from the
server process that is used as basis for composing a new server process that is used as basis for composing a new
message (ie., either a reply or a forward); the function is passed message (ie., either a reply or a forward); the function is passed
msg and a symbol (either reply or forward). See `mm/proc-filter' msg and a symbol (either reply or forward). See `mu4e-proc-filter'
for the format of <msg-plist>.") for the format of <msg-plist>.")
(defvar mm/proc-info-func 'mm/default-handler (defvar mu4e-proc-info-func 'mu4e-default-handler
"*internal* A function called for each (:info type ....) sexp "*internal* A function called for each (:info type ....) sexp
received from the server process.") received from the server process.")
(defvar mm/proc-pong-func 'mm/default-handler (defvar mu4e-proc-pong-func 'mu4e-default-handler
"*internal* A function called for each (:pong type ....) sexp "*internal* A function called for each (:pong type ....) sexp
received from the server process.") received from the server process.")
(defvar mm/buf nil (defvar mu4e-buf nil
"*internal* Buffer for results data.") "*internal* Buffer for results data.")
(defvar mm/path-docid-map (defvar mu4e-path-docid-map
(make-hash-table :size 32 :rehash-size 2 :test 'equal :weakness nil) (make-hash-table :size 32 :rehash-size 2 :test 'equal :weakness nil)
"*internal* hash we use to keep a path=>docid mapping for message "*internal* hash we use to keep a path=>docid mapping for message
we added ourselves (ie., draft messages), so we can e.g. move them we added ourselves (ie., draft messages), so we can e.g. move them
to the sent folder using their docid") to the sent folder using their docid")
(defun mm/proc-info-handler (info) (defun mu4e-proc-info-handler (info)
"Handler function for (:info ...) sexps received from the server "Handler function for (:info ...) sexps received from the server
process." process."
(let ((type (plist-get info :info))) (let ((type (plist-get info :info)))
@ -97,12 +97,12 @@ process."
((eq type 'add) ((eq type 'add)
;; update our path=>docid map; we use this when composing messages to ;; update our path=>docid map; we use this when composing messages to
;; add draft messages to the db, so when we're sending them, we can move ;; add draft messages to the db, so when we're sending them, we can move
;; to the sent folder using the `mm/proc-move'. ;; to the sent folder using the `mu4e-proc-move'.
(puthash (plist-get info :path) (plist-get info :docid) mm/path-docid-map)) (puthash (plist-get info :path) (plist-get info :docid) mu4e-path-docid-map))
((eq type 'version) ((eq type 'version)
(setq (setq
mm/version (plist-get info :version) mu4e-version (plist-get info :version)
mm/doccount (plist-get-info :doccount))) mu4e-doccount (plist-get-info :doccount)))
((eq type 'index) ((eq type 'index)
(if (eq (plist-get info :status) 'running) (if (eq (plist-get info :status) 'running)
(message (format "Indexing... processed %d, updated %d" (message (format "Indexing... processed %d, updated %d"
@ -114,78 +114,79 @@ process."
((plist-get info :message) (message "%s" (plist-get info :message)))))) ((plist-get info :message) (message "%s" (plist-get info :message))))))
(defun mm/default-handler (&rest args) (defun mu4e-default-handler (&rest args)
"Dummy handler function." "Dummy handler function."
(error "Not handled: %S" args)) (error "Not handled: %S" args))
(defconst mm/server-name "*mm-server" (defconst mu4e-server-name "*mu4e-server"
"*internal* Name of the server process, buffer.") "*internal* Name of the server process, buffer.")
(defun mm/start-proc () (defun mu4e-start-proc ()
"Start the mu server process." "Start the mu server process."
;; TODO: add version check ;; TODO: add version check
(unless (file-executable-p mm/mu-binary) (unless (file-executable-p mu4e-mu-binary)
(error (format "%S not found" mm/mu-binary))) (error (format "%S not found" mu4e-mu-binary)))
(let* ((process-connection-type nil) ;; use a pipe (let* ((process-connection-type nil) ;; use a pipe
(args '("server")) (args '("server"))
(args (append args (when mm/mu-home (args (append args (when mu4e-mu-home
(list (concat "--muhome=" mm/mu-home)))))) (list (concat "--muhome=" mu4e-mu-home))))))
(setq mm/buf "") (setq mu4e-buf "")
(setq mm/mu-proc (apply 'start-process mm/server-name mm/server-name (setq mu4e-mu-proc (apply 'start-process
mm/mu-binary args)) mu4e-server-name mu4e-server-name
mu4e-mu-binary args))
;; register a function for (:info ...) sexps ;; register a function for (:info ...) sexps
(setq mm/proc-info-func 'mm/proc-info-handler) (setq mu4e-proc-info-func 'mu4e-proc-info-handler)
(when mm/mu-proc (when mu4e-mu-proc
(set-process-coding-system mm/mu-proc 'binary 'utf-8-unix) (set-process-coding-system mu4e-mu-proc 'binary 'utf-8-unix)
(set-process-filter mm/mu-proc 'mm/proc-filter) (set-process-filter mu4e-mu-proc 'mu4e-proc-filter)
(set-process-sentinel mm/mu-proc 'mm/proc-sentinel)))) (set-process-sentinel mu4e-mu-proc 'mu4e-proc-sentinel))))
(defun mm/kill-proc () (defun mu4e-kill-proc ()
"Kill the mu server process." "Kill the mu server process."
(let* ((buf (get-buffer mm/server-name)) (let* ((buf (get-buffer mu4e-server-name))
(proc (and buf (get-buffer-process buf)))) (proc (and buf (get-buffer-process buf))))
(when proc (when proc
(let ((delete-exited-processes t)) (let ((delete-exited-processes t))
;; the mu server signal handler will make it quit after 'quit' ;; the mu server signal handler will make it quit after 'quit'
(mm/proc-send-command "quit")) (mu4e-proc-send-command "quit"))
;; try sending SIGINT (C-c) to process, so it can exit gracefully ;; try sending SIGINT (C-c) to process, so it can exit gracefully
(ignore-errors (ignore-errors
(signal-process proc 'SIGINT)))) (signal-process proc 'SIGINT))))
(setq (setq
mm/mu-proc nil mu4e-mu-proc nil
mm/buf nil)) mu4e-buf nil))
(defun mm/proc-is-running () (defun mu4e-proc-is-running ()
(and mm/mu-proc (eq (process-status mm/mu-proc) 'run))) (and mu4e-mu-proc (eq (process-status mu4e-mu-proc) 'run)))
(defun mm/proc-eat-sexp-from-buf () (defun mu4e-proc-eat-sexp-from-buf ()
"'Eat' the next s-expression from `mm/buf'. `mm/buf gets its "'Eat' the next s-expression from `mu4e-buf'. `mu4e-buf gets its
contents from the mu-servers in the following form: contents from the mu-servers in the following form:
\376<len-of-sexp>\376<sexp> \376<len-of-sexp>\376<sexp>
Function returns this sexp, or nil if there was none. `mm/buf' is Function returns this sexp, or nil if there was none. `mu4e-buf' is
updated as well, with all processed sexp data removed." updated as well, with all processed sexp data removed."
(when mm/buf (when mu4e-buf
;; TODO: maybe try a non-regexp solution? ;; TODO: maybe try a non-regexp solution?
(let* ((b (string-match "\376\\([0-9]+\\)\376" mm/buf)) (let* ((b (string-match "\376\\([0-9]+\\)\376" mu4e-buf))
(sexp-len (sexp-len
(when b (string-to-number (match-string 1 mm/buf))))) (when b (string-to-number (match-string 1 mu4e-buf)))))
;; does mm/buf contain the full sexp? ;; does mu4e-buf contain the full sexp?
(when (and b (>= (length mm/buf) (+ sexp-len (match-end 0)))) (when (and b (>= (length mu4e-buf) (+ sexp-len (match-end 0))))
;; clear-up start ;; clear-up start
(setq mm/buf (substring mm/buf (match-end 0))) (setq mu4e-buf (substring mu4e-buf (match-end 0)))
;; note: we read the input in binary mode -- here, we take the part that ;; note: we read the input in binary mode -- here, we take the part that
;; is the sexp, and convert that to utf-8, before we interpret it. ;; is the sexp, and convert that to utf-8, before we interpret it.
(let ((objcons (let ((objcons
(ignore-errors ;; note: this may fail if we killed the process (ignore-errors ;; note: this may fail if we killed the process
;; in the middle ;; in the middle
(read-from-string (read-from-string
(decode-coding-string (substring mm/buf 0 sexp-len) 'utf-8))))) (decode-coding-string (substring mu4e-buf 0 sexp-len) 'utf-8)))))
(when objcons (when objcons
(setq mm/buf (substring mm/buf sexp-len)) (setq mu4e-buf (substring mu4e-buf sexp-len))
(car objcons))))))) (car objcons)))))))
(defun mm/proc-filter (proc str) (defun mu4e-proc-filter (proc str)
"A process-filter for the 'mu server' output; it accumulates the "A process-filter for the 'mu server' output; it accumulates the
strings into valid sexps by checking of the ';;eox' end-of-sexp strings into valid sexps by checking of the ';;eox' end-of-sexp
marker, and then evaluating them. marker, and then evaluating them.
@ -195,7 +196,7 @@ updated as well, with all processed sexp data removed."
1. an error 1. an error
(:error 2 :error-message \"unknown command\") (:error 2 :error-message \"unknown command\")
;; eox ;; eox
=> this will be passed to `mm/proc-error-func'. => this will be passed to `mu4e-proc-error-func'.
2a. a message sexp looks something like: 2a. a message sexp looks something like:
\( \(
@ -216,87 +217,87 @@ updated as well, with all processed sexp data removed."
:body-txt \" <message body>\" :body-txt \" <message body>\"
\) \)
;; eox ;; eox
=> this will be passed to `mm/proc-header-func'. => this will be passed to `mu4e-proc-header-func'.
2b. After the list of message sexps has been returned (see 2a.), 2b. After the list of message sexps has been returned (see 2a.),
we'll receive a sexp that looks like we'll receive a sexp that looks like
(:found <n>) with n the number of messages found. The <n> will be (:found <n>) with n the number of messages found. The <n> will be
passed to `mm/proc-found-func'. passed to `mu4e-proc-found-func'.
3. a view looks like: 3. a view looks like:
(:view <msg-sexp>) (:view <msg-sexp>)
=> the <msg-sexp> (see 2.) will be passed to `mm/proc-view-func'. => the <msg-sexp> (see 2.) will be passed to `mu4e-proc-view-func'.
4. a database update looks like: 4. a database update looks like:
(:update <msg-sexp> :move <nil-or-t>) (:update <msg-sexp> :move <nil-or-t>)
=> the <msg-sexp> (see 2.) will be passed to => the <msg-sexp> (see 2.) will be passed to
`mm/proc-update-func', :move tells us whether this is a move to `mu4e-proc-update-func', :move tells us whether this is a move to
another maildir, or merely a flag change. another maildir, or merely a flag change.
5. a remove looks like: 5. a remove looks like:
(:remove <docid>) (:remove <docid>)
=> the docid will be passed to `mm/proc-remove-func' => the docid will be passed to `mu4e-proc-remove-func'
6. a compose looks like: 6. a compose looks like:
(:compose <msg-sexp> :action <reply|forward>) => the <msg-sexp> (:compose <msg-sexp> :action <reply|forward>) => the <msg-sexp>
and either 'reply or 'forward will be passed and either 'reply or 'forward will be passed
`mm/proc-compose-func'." `mu4e-proc-compose-func'."
(mm/proc-log "* Received %d byte(s)" (length str)) (mu4e-proc-log "* Received %d byte(s)" (length str))
(setq mm/buf (concat mm/buf str)) ;; update our buffer (setq mu4e-buf (concat mu4e-buf str)) ;; update our buffer
(let ((sexp (mm/proc-eat-sexp-from-buf))) (let ((sexp (mu4e-proc-eat-sexp-from-buf)))
(while sexp (while sexp
(mm/proc-log "<- %S" sexp) (mu4e-proc-log "<- %S" sexp)
(cond (cond
;; a header plist can be recognized by the existence of a :date field ;; a header plist can be recognized by the existence of a :date field
((plist-get sexp :date) ((plist-get sexp :date)
(funcall mm/proc-header-func sexp)) (funcall mu4e-proc-header-func sexp))
;; the found sexp, we receive after getting all the headers ;; the found sexp, we receive after getting all the headers
((plist-get sexp :found) ((plist-get sexp :found)
(funcall mm/proc-found-func (plist-get sexp :found))) (funcall mu4e-proc-found-func (plist-get sexp :found)))
;; viewin a specific message ;; viewin a specific message
((plist-get sexp :view) ((plist-get sexp :view)
(funcall mm/proc-view-func (plist-get sexp :view))) (funcall mu4e-proc-view-func (plist-get sexp :view)))
;; receive a pong message ;; receive a pong message
((plist-get sexp :pong) ((plist-get sexp :pong)
(funcall mm/proc-pong-func (funcall mu4e-proc-pong-func
(plist-get sexp :version) (plist-get sexp :doccount))) (plist-get sexp :version) (plist-get sexp :doccount)))
;; something got moved/flags changed ;; something got moved/flags changed
((plist-get sexp :update) ((plist-get sexp :update)
(funcall mm/proc-update-func (funcall mu4e-proc-update-func
(plist-get sexp :update) (plist-get sexp :move))) (plist-get sexp :update) (plist-get sexp :move)))
;; a message got removed ;; a message got removed
((plist-get sexp :remove) ((plist-get sexp :remove)
(funcall mm/proc-remove-func (plist-get sexp :remove))) (funcall mu4e-proc-remove-func (plist-get sexp :remove)))
;; start composing a new message ;; start composing a new message
((plist-get sexp :compose) ((plist-get sexp :compose)
(funcall mm/proc-compose-func (funcall mu4e-proc-compose-func
(plist-get sexp :compose-type) (plist-get sexp :compose-type)
(plist-get sexp :compose))) (plist-get sexp :compose)))
;; get some info ;; get some info
((plist-get sexp :info) ((plist-get sexp :info)
(funcall mm/proc-info-func sexp)) (funcall mu4e-proc-info-func sexp))
;; receive an error ;; receive an error
((plist-get sexp :error) ((plist-get sexp :error)
(funcall mm/proc-error-func sexp)) (funcall mu4e-proc-error-func sexp))
(t (message "Unexpected data from server [%S]" sexp))) (t (message "Unexpected data from server [%S]" sexp)))
(setq sexp (mm/proc-eat-sexp-from-buf))))) (setq sexp (mu4e-proc-eat-sexp-from-buf)))))
(defun mm/proc-sentinel (proc msg) (defun mu4e-proc-sentinel (proc msg)
"Function that will be called when the mu-server process "Function that will be called when the mu-server process
terminates." terminates."
(let ((status (process-status proc)) (code (process-exit-status proc))) (let ((status (process-status proc)) (code (process-exit-status proc)))
(setq mm/mu-proc nil) (setq mu4e-mu-proc nil)
(setq mm/buf "") ;; clear any half-received sexps (setq mu4e-buf "") ;; clear any half-received sexps
(cond (cond
((eq status 'signal) ((eq status 'signal)
(cond (cond
@ -316,44 +317,44 @@ terminates."
(message "something bad happened to the mu server process"))))) (message "something bad happened to the mu server process")))))
(defconst mm/proc-log-buffer-name "*mm-log*" (defconst mu4e-proc-log-buffer-name "*mu4e-log*"
"*internal* Name of the logging buffer.") "*internal* Name of the logging buffer.")
(defun mm/proc-log (frm &rest args) (defun mu4e-proc-log (frm &rest args)
"Write something in the *mm-log* buffer - mainly useful for debugging." "Write something in the *mu4e-log* buffer - mainly useful for debugging."
(when mm/debug (when mu4e-debug
(with-current-buffer (get-buffer-create mm/proc-log-buffer-name) (with-current-buffer (get-buffer-create mu4e-proc-log-buffer-name)
(goto-char (point-max)) (goto-char (point-max))
(insert (apply 'format (concat (format-time-string "%Y-%m-%d %T " (insert (apply 'format (concat (format-time-string "%Y-%m-%d %T "
(current-time)) frm "\n") args))))) (current-time)) frm "\n") args)))))
(defun mm/proc-send-command (frm &rest args) (defun mu4e-proc-send-command (frm &rest args)
"Send as command to the mu server process; start the process if needed." "Send as command to the mu server process; start the process if needed."
(unless (mm/proc-is-running) (unless (mu4e-proc-is-running)
(mm/start-proc)) (mu4e-start-proc))
(let ((cmd (apply 'format frm args))) (let ((cmd (apply 'format frm args)))
(mm/proc-log (concat "-> " cmd)) (mu4e-proc-log (concat "-> " cmd))
(process-send-string mm/mu-proc (concat cmd "\n")))) (process-send-string mu4e-mu-proc (concat cmd "\n"))))
(defun mm/proc-remove-msg (docid) (defun mu4e-proc-remove-msg (docid)
"Remove message identified by DOCID. The results are reporter "Remove message identified by DOCID. The results are reporter
through either (:update ... ) or (:error ) sexp, which are handled through either (:update ... ) or (:error ) sexp, which are handled
my `mm/proc-update-func' and `mm/proc-error-func', respectively." my `mu4e-proc-update-func' and `mu4e-proc-error-func', respectively."
(mm/proc-send-command "remove %d" docid)) (mu4e-proc-send-command "remove %d" docid))
(defun mm/proc-find (expr &optional maxnum) (defun mu4e-proc-find (expr &optional maxnum)
"Start a database query for EXPR, getting up to MAXNUM "Start a database query for EXPR, getting up to MAXNUM
results (or -1 for unlimited). For each result found, a function is results (or -1 for unlimited). For each result found, a function is
called, depending on the kind of result. The variables called, depending on the kind of result. The variables
`mm/proc-header-func' and `mm/proc-error-func' contain the function `mu4e-proc-header-func' and `mu4e-proc-error-func' contain the function
that will be called for, resp., a message (header row) or an that will be called for, resp., a message (header row) or an
error." error."
(mm/proc-send-command "find \"%s\" %d" (mu4e-proc-send-command "find \"%s\" %d"
expr (if maxnum maxnum -1))) expr (if maxnum maxnum -1)))
(defun mm/proc-move-msg (docid targetmdir &optional flags) (defun mu4e-proc-move-msg (docid targetmdir &optional flags)
"Move message identified by DOCID to TARGETMDIR, optionally "Move message identified by DOCID to TARGETMDIR, optionally
setting FLAGS in the process. setting FLAGS in the process.
@ -369,82 +370,82 @@ The FLAGS parameter can have the following forms:
The flags are any of `deleted', `flagged', `new', `passed', `replied' `seen' or The flags are any of `deleted', `flagged', `new', `passed', `replied' `seen' or
`trashed', or the corresponding \"DFNPRST\" as defined in [1]. See `trashed', or the corresponding \"DFNPRST\" as defined in [1]. See
`mm/string-to-flags' and `mm/flags-to-string'. `mu4e-string-to-flags' and `mu4e-flags-to-string'.
The server reports the results for the operation through The server reports the results for the operation through
`mm/proc-update-func'. `mu4e-proc-update-func'.
The results are reported through either (:update ... ) The results are reported through either (:update ... )
or (:error ) sexp, which are handled my `mm/proc-update-func' and or (:error ) sexp, which are handled my `mu4e-proc-update-func' and
`mm/proc-error-func', respectively." `mu4e-proc-error-func', respectively."
(let (let
((flagstr (if (stringp flags) flags (mm/flags-to-string flags))) ((flagstr (if (stringp flags) flags (mu4e-flags-to-string flags)))
(fullpath (concat mm/maildir targetmdir))) (fullpath (concat mu4e-maildir targetmdir)))
(unless (and (file-directory-p fullpath) (file-writable-p fullpath)) (unless (and (file-directory-p fullpath) (file-writable-p fullpath))
(error "Not a writable directory: %s" fullpath)) (error "Not a writable directory: %s" fullpath))
;; note, we send the maildir, *not* the full path ;; note, we send the maildir, *not* the full path
(mm/proc-send-command "move %d \"%s\" %s" docid (mu4e-proc-send-command "move %d \"%s\" %s" docid
targetmdir flagstr))) targetmdir flagstr)))
(defun mm/proc-flag (docid-or-msgid flags) (defun mu4e-proc-flag (docid-or-msgid flags)
"Set FLAGS for the message identified by either DOCID-OR-MSGID." "Set FLAGS for the message identified by either DOCID-OR-MSGID."
(let ((flagstr (if (stringp flags) flags (mm/flags-to-string flags)))) (let ((flagstr (if (stringp flags) flags (mu4e-flags-to-string flags))))
(mm/proc-send-command "flag %S %s" docid-or-msgid flagstr))) (mu4e-proc-send-command "flag %S %s" docid-or-msgid flagstr)))
(defun mm/proc-index (maildir) (defun mu4e-proc-index (maildir)
"Update the message database for MAILDIR." "Update the message database for MAILDIR."
(mm/proc-send-command "index \"%s\"" maildir)) (mu4e-proc-send-command "index \"%s\"" maildir))
(defun mm/proc-add (path maildir) (defun mu4e-proc-add (path maildir)
"Add the message at PATH to the database, with MAILDIR "Add the message at PATH to the database, with MAILDIR
set to e.g. '/drafts'; if this works, we will receive (:info :path set to e.g. '/drafts'; if this works, we will receive (:info :path
<path> :docid <docid>)." <path> :docid <docid>)."
(mm/proc-send-command "add \"%s\" \"%s\"" path maildir)) (mu4e-proc-send-command "add \"%s\" \"%s\"" path maildir))
(defun mm/proc-save (docid partidx path) (defun mu4e-proc-save (docid partidx path)
"Save attachment PARTIDX from message with DOCID to PATH." "Save attachment PARTIDX from message with DOCID to PATH."
(mm/proc-send-command "save %d %d \"%s\"" docid partidx path)) (mu4e-proc-send-command "save %d %d \"%s\"" docid partidx path))
(defun mm/proc-open (docid partidx) (defun mu4e-proc-open (docid partidx)
"Open attachment PARTIDX from message with DOCID." "Open attachment PARTIDX from message with DOCID."
(mm/proc-send-command "open %d %d" docid partidx)) (mu4e-proc-send-command "open %d %d" docid partidx))
(defun mm/proc-ping () (defun mu4e-proc-ping ()
"Sends a ping to the mu server, expecting a (:pong ...) in "Sends a ping to the mu server, expecting a (:pong ...) in
response." response."
(mm/proc-send-command "ping")) (mu4e-proc-send-command "ping"))
(defun mm/proc-view-msg (docid) (defun mu4e-proc-view-msg (docid)
"Get one particular message based on its DOCID. The result will "Get one particular message based on its DOCID. The result will
be delivered to the function registered as `mm/proc-message-func'." be delivered to the function registered as `mu4e-proc-message-func'."
(mm/proc-send-command "view %d" docid)) (mu4e-proc-send-command "view %d" docid))
(defun mm/proc-compose (compose-type docid) (defun mu4e-proc-compose (compose-type docid)
"Start composing a message with DOCID and COMPOSE-TYPE (a symbol, "Start composing a message with DOCID and COMPOSE-TYPE (a symbol,
either `forward', `reply' or `edit'. either `forward', `reply' or `edit'.
The result will be delivered to the function registered as The result will be delivered to the function registered as
`mm/proc-compose-func'." `mu4e-proc-compose-func'."
(unless (member compose-type '(forward reply edit)) (unless (member compose-type '(forward reply edit))
(error "Unsupported compose-type")) (error "Unsupported compose-type"))
(mm/proc-send-command "compose %s %d" (symbol-name compose-type) docid)) (mu4e-proc-send-command "compose %s %d" (symbol-name compose-type) docid))
(defconst mm/update-buffer-name "*update*" (defconst mu4e-update-buffer-name "*update*"
"*internal* Name of the buffer to download mail") "*internal* Name of the buffer to download mail")
(defun mm/proc-retrieve-mail-update-db () (defun mu4e-proc-retrieve-mail-update-db ()
"Try to retrieve mail (using the user-provided shell command), "Try to retrieve mail (using the user-provided shell command),
and update the database afterwards." and update the database afterwards."
(unless mm/get-mail-command (unless mu4e-get-mail-command
(error "`mm/get-mail-command' is not defined")) (error "`mu4e-get-mail-command' is not defined"))
(let ((buf (get-buffer-create mm/update-buffer-name))) (let ((buf (get-buffer-create mu4e-update-buffer-name)))
(split-window-vertically -8) (split-window-vertically -8)
(switch-to-buffer-other-window buf) (switch-to-buffer-other-window buf)
(with-current-buffer buf (with-current-buffer buf
(erase-buffer)) (erase-buffer))
(message "Retrieving mail...") (message "Retrieving mail...")
(call-process mm/get-mail-command nil buf t) (call-process mu4e-get-mail-command nil buf t)
(message "Updating the database...") (message "Updating the database...")
(mm/proc-index mm/maildir) (mu4e-proc-index mu4e-maildir)
(with-current-buffer buf (with-current-buffer buf
(kill-buffer-and-window)))) (kill-buffer-and-window))))
(provide 'mm-proc) (provide 'mu4e-proc)

View File

@ -1,4 +1,4 @@
;; mm-send.el -- part of mm, the mu mail user agent ;; mu4e-send.el -- part of mm, the mu mail user agent
;; ;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema ;; Copyright (C) 2011 Dirk-Jan C. Binnema
@ -39,23 +39,23 @@
;; internal variables / constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; internal variables / constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defconst mm/msg-draft-name "*mm-draft*" (defconst mu4e-msg-draft-name "*mu4e-draft*"
"Name for draft messages.") "Name for draft messages.")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; FIXME ;; FIXME
(defun mm/mu-binary-version () "0.98pre") (defun mu4e-mu-binary-version () "0.98pre")
(defun mm/msg-user-agent () (defun mu4e-msg-user-agent ()
"Return the User-Agent string for mm. This is either the value "Return the User-Agent string for mm. This is either the value
of `mm/user-agent', or, if not set, a string based on the of `mu4e-user-agent', or, if not set, a string based on the
version of mm and emacs." version of mm and emacs."
(or mm/user-agent (or mu4e-user-agent
(format "mu %s; emacs %s" (mm/mu-binary-version) emacs-version))) (format "mu %s; emacs %s" (mu4e-mu-binary-version) emacs-version)))
(defun mm/view-body (msg) (defun mu4e-view-body (msg)
"Get the body for this message, which is either :body-txt, "Get the body for this message, which is either :body-txt,
or if not available, :body-html converted to text)." or if not available, :body-html converted to text)."
(or (plist-get msg :body-txt) (or (plist-get msg :body-txt)
@ -65,12 +65,12 @@ or if not available, :body-html converted to text)."
(buffer-string)) (buffer-string))
"No body found")) "No body found"))
(defun mm/msg-cite-original (msg) (defun mu4e-msg-cite-original (msg)
"Cite the body text of MSG, with a \"On %s, %s wrote:\" "Cite the body text of MSG, with a \"On %s, %s wrote:\"
line (with the %s's replaced with the date of MSG and the name line (with the %s's replaced with the date of MSG and the name
or e-mail address of its sender (or 'someone' if nothing or e-mail address of its sender (or 'someone' if nothing
else)), followed of the quoted body of MSG, constructed by by else)), followed of the quoted body of MSG, constructed by by
prepending `mm/msg-citation-prefix' to each line. If there is prepending `mu4e-msg-citation-prefix' to each line. If there is
no body in MSG, return nil." no body in MSG, return nil."
(let* ((from (plist-get msg :from)) (let* ((from (plist-get msg :from))
;; first try plain-text, then html ;; first try plain-text, then html
@ -90,7 +90,7 @@ or if not available, :body-html converted to text)."
"\n\n" "\n\n"
(replace-regexp-in-string "^" " > " body))))) (replace-regexp-in-string "^" " > " body)))))
(defun mm/msg-recipients-remove (lst email-to-remove) (defun mu4e-msg-recipients-remove (lst email-to-remove)
"Remove the recipient with EMAIL from the recipient list (of form "Remove the recipient with EMAIL from the recipient list (of form
'( (\"A\" . \"a@example.com\") (\"B\" . \"B@example.com\"))." '( (\"A\" . \"a@example.com\") (\"B\" . \"B@example.com\"))."
(remove-if (remove-if
@ -98,7 +98,7 @@ or if not available, :body-html converted to text)."
(let ((email (cdr name-email))) (let ((email (cdr name-email)))
(when email (string= email-to-remove (downcase email))))) lst)) (when email (string= email-to-remove (downcase email))))) lst))
(defun mm/msg-recipients-to-string (lst) (defun mu4e-msg-recipients-to-string (lst)
"Convert a recipient list (of form '( (\"A\" "Convert a recipient list (of form '( (\"A\"
. \"a@example.com\") (\"B\" . \"B@example.com\") (nil . \"a@example.com\") (\"B\" . \"B@example.com\") (nil
. \"c@example.com\")) into a string of form \"A <@aexample.com>, B . \"c@example.com\")) into a string of form \"A <@aexample.com>, B
@ -112,12 +112,12 @@ or if not available, :body-html converted to text)."
(format "%s" email)))) lst ", "))) (format "%s" email)))) lst ", ")))
(defun mm/msg-header (hdr val) (defun mu4e-msg-header (hdr val)
"Return a header line of the form HDR: VAL\n. If VAL is nil, "Return a header line of the form HDR: VAL\n. If VAL is nil,
return nil." return nil."
(when val (format "%s: %s\n" hdr val))) (when val (format "%s: %s\n" hdr val)))
(defun mm/msg-references-create (msg) (defun mu4e-msg-references-create (msg)
"Construct the value of the References: header based on MSG as a "Construct the value of the References: header based on MSG as a
comma-separated string. Normally, this the concatenation of the comma-separated string. Normally, this the concatenation of the
existing References (which may be empty) and the message-id. If the existing References (which may be empty) and the message-id. If the
@ -131,7 +131,7 @@ return nil."
(lambda (msgid) (format "<%s>" msgid)) (lambda (msgid) (format "<%s>" msgid))
refs ",")))) refs ","))))
(defun mm/msg-to-create (msg) (defun mu4e-msg-to-create (msg)
"Construct the To: header for a reply-message based on some "Construct the To: header for a reply-message based on some
message MSG. This takes the Reply-To address of MSG if it exist, or message MSG. This takes the Reply-To address of MSG if it exist, or
the From:-address otherwise. The result is either nil or a string the From:-address otherwise. The result is either nil or a string
@ -140,10 +140,10 @@ Reply-To contains a string of one or more addresses,
comma-separated." comma-separated."
(or (or
(plist-get msg :reply-to) (plist-get msg :reply-to)
(mm/msg-recipients-to-string (plist-get msg :from)))) (mu4e-msg-recipients-to-string (plist-get msg :from))))
(defun mm/msg-cc-create (msg reply-all) (defun mu4e-msg-cc-create (msg reply-all)
"Get the list of Cc-addresses for the reply to MSG. If REPLY-ALL "Get the list of Cc-addresses for the reply to MSG. If REPLY-ALL
is nil this is simply empty, otherwise it is the old CC-list is nil this is simply empty, otherwise it is the old CC-list
together with the old TO-list, minus `user-mail-address'. The together with the old TO-list, minus `user-mail-address'. The
@ -154,11 +154,11 @@ the Cc: field."
(when reply-all (when reply-all
(setq cc-lst (append cc-lst to-lst))) (setq cc-lst (append cc-lst to-lst)))
;; remove myself from cc ;; remove myself from cc
(setq cc-lst (mm/msg-recipients-remove cc-lst user-mail-address)) (setq cc-lst (mu4e-msg-recipients-remove cc-lst user-mail-address))
(mm/msg-recipients-to-string cc-lst))) (mu4e-msg-recipients-to-string cc-lst)))
(defun mm/msg-from-create () (defun mu4e-msg-from-create ()
"Construct a value for the From:-field of the reply to MSG, "Construct a value for the From:-field of the reply to MSG,
based on `user-full-name' and `user-mail-address'; if the latter is based on `user-full-name' and `user-mail-address'; if the latter is
nil, function returns nil." nil, function returns nil."
@ -167,25 +167,25 @@ nil, function returns nil."
(format "%s <%s>" user-full-name user-mail-address) (format "%s <%s>" user-full-name user-mail-address)
(format "%s" user-mail-address)))) (format "%s" user-mail-address))))
(defun mm/msg-create-reply (msg) (defun mu4e-msg-create-reply (msg)
"Create a draft message as a reply to MSG. "Create a draft message as a reply to MSG.
A reply message has fields: A reply message has fields:
From: - see `mu-msg-from-create' From: - see `mu-msg-from-create'
To: - see `mm/msg-to-create' To: - see `mu4e-msg-to-create'
Cc: - see `mm/msg-cc-create' Cc: - see `mu4e-msg-cc-create'
Subject: - `mm/msg-reply-prefix' + subject of MSG Subject: - `mu4e-msg-reply-prefix' + subject of MSG
then, the following fields, normally hidden from user: then, the following fields, normally hidden from user:
Reply-To: - if `mail-reply-to' has been set Reply-To: - if `mail-reply-to' has been set
References: - see `mm/msg-references-create' References: - see `mu4e-msg-references-create'
In-Reply-To: - message-id of MSG In-Reply-To: - message-id of MSG
User-Agent - see `mm/msg-user-agent' User-Agent - see `mu4e-msg-user-agent'
Then follows `mail-header-separator' (for `message-mode' to separate Then follows `mail-header-separator' (for `message-mode' to separate
body from headers) body from headers)
And finally, the cited body of MSG, as per `mm/msg-cite-original'." And finally, the cited body of MSG, as per `mu4e-msg-cite-original'."
(let* ((recipnum (+ (length (plist-get msg :to)) (let* ((recipnum (+ (length (plist-get msg :to))
(length (plist-get msg :cc)))) (length (plist-get msg :cc))))
(reply-all (when (> recipnum 1) (reply-all (when (> recipnum 1)
@ -193,60 +193,60 @@ And finally, the cited body of MSG, as per `mm/msg-cite-original'."
(format "Reply to all ~%d recipients? " (format "Reply to all ~%d recipients? "
(+ recipnum)))))) (+ recipnum))))))
(concat (concat
(mm/msg-header "From" (or (mm/msg-from-create) "")) (mu4e-msg-header "From" (or (mu4e-msg-from-create) ""))
(when (boundp 'mail-reply-to) (when (boundp 'mail-reply-to)
(mm/msg-header "Reply-To" mail-reply-to)) (mu4e-msg-header "Reply-To" mail-reply-to))
(mm/msg-header "To" (or (mm/msg-to-create msg) "")) (mu4e-msg-header "To" (or (mu4e-msg-to-create msg) ""))
(mm/msg-header "Cc" (mm/msg-cc-create msg reply-all)) (mu4e-msg-header "Cc" (mu4e-msg-cc-create msg reply-all))
(mm/msg-header "User-agent" (mm/msg-user-agent)) (mu4e-msg-header "User-agent" (mu4e-msg-user-agent))
(mm/msg-header "References" (mm/msg-references-create msg)) (mu4e-msg-header "References" (mu4e-msg-references-create msg))
(mm/msg-header "In-reply-to" (format "<%s>" (plist-get msg :message-id))) (mu4e-msg-header "In-reply-to" (format "<%s>" (plist-get msg :message-id)))
(mm/msg-header "Subject" (mu4e-msg-header "Subject"
(concat mm/msg-reply-prefix (plist-get msg :subject))) (concat mu4e-msg-reply-prefix (plist-get msg :subject)))
(propertize mail-header-separator 'read-only t 'intangible t) '"\n" (propertize mail-header-separator 'read-only t 'intangible t) '"\n"
"\n\n" "\n\n"
(mm/msg-cite-original msg)))) (mu4e-msg-cite-original msg))))
;; TODO: attachments ;; TODO: attachments
(defun mm/msg-create-forward (msg) (defun mu4e-msg-create-forward (msg)
"Create a draft forward message for MSG. "Create a draft forward message for MSG.
A forward message has fields: A forward message has fields:
From: - see `mm/msg-from-create' From: - see `mu4e-msg-from-create'
To: - empty To: - empty
Subject: - `mm/msg-forward-prefix' + subject of MSG Subject: - `mu4e-msg-forward-prefix' + subject of MSG
then, the following fields, normally hidden from user: then, the following fields, normally hidden from user:
Reply-To: - if `mail-reply-to' has been set Reply-To: - if `mail-reply-to' has been set
References: - see `mm/msg-references-create' References: - see `mu4e-msg-references-create'
User-Agent - see `mm/msg-user-agent' User-Agent - see `mu4e-msg-user-agent'
Then follows `mail-header-separator' (for `message-mode' to separate Then follows `mail-header-separator' (for `message-mode' to separate
body from headers) body from headers)
And finally, the cited body of MSG, as per `mm/msg-cite-original'." And finally, the cited body of MSG, as per `mu4e-msg-cite-original'."
(concat (concat
(mm/msg-header "From" (or (mm/msg-from-create) "")) (mu4e-msg-header "From" (or (mu4e-msg-from-create) ""))
(when (boundp 'mail-reply-to) (when (boundp 'mail-reply-to)
(mm/msg-header "Reply-To" mail-reply-to)) (mu4e-msg-header "Reply-To" mail-reply-to))
(mm/msg-header "To" "") (mu4e-msg-header "To" "")
(mm/msg-header "User-agent" (mm/msg-user-agent)) (mu4e-msg-header "User-agent" (mu4e-msg-user-agent))
(mm/msg-header "References" (mm/msg-references-create msg)) (mu4e-msg-header "References" (mu4e-msg-references-create msg))
(mm/msg-header"Subject" (mu4e-msg-header"Subject"
(concat mm/msg-forward-prefix (plist-get msg :subject))) (concat mu4e-msg-forward-prefix (plist-get msg :subject)))
(propertize mail-header-separator 'read-only t 'intangible t) "\n" (propertize mail-header-separator 'read-only t 'intangible t) "\n"
"\n\n" "\n\n"
(mm/msg-cite-original msg))) (mu4e-msg-cite-original msg)))
(defun mm/msg-create-new () (defun mu4e-msg-create-new ()
"Create a new message. "Create a new message.
A new draft message has fields: A new draft message has fields:
@ -256,24 +256,24 @@ A new draft message has fields:
then, the following fields, normally hidden from user: then, the following fields, normally hidden from user:
Reply-To: - if `mail-reply-to' has been set Reply-To: - if `mail-reply-to' has been set
User-Agent - see `mm/msg-user-agent' User-Agent - see `mu4e-msg-user-agent'
Then follows `mail-header-separator' (for `message-mode' to separate Then follows `mail-header-separator' (for `message-mode' to separate
body from headers)." body from headers)."
(concat (concat
(mm/msg-header "From" (or (mm/msg-from-create) "")) (mu4e-msg-header "From" (or (mu4e-msg-from-create) ""))
(when (boundp 'mail-reply-to) (when (boundp 'mail-reply-to)
(mm/msg-header "Reply-To" mail-reply-to)) (mu4e-msg-header "Reply-To" mail-reply-to))
(mm/msg-header "To" "") (mu4e-msg-header "To" "")
(mm/msg-header "User-agent" (mm/msg-user-agent)) (mu4e-msg-header "User-agent" (mu4e-msg-user-agent))
(mm/msg-header "Subject" "") (mu4e-msg-header "Subject" "")
(propertize mail-header-separator 'read-only t 'intangible t) "\n")) (propertize mail-header-separator 'read-only t 'intangible t) "\n"))
(defun mm/msg-open-draft (compose-type &optional msg) (defun mu4e-msg-open-draft (compose-type &optional msg)
"Open a draft file for a new message, creating it if it does not "Open a draft file for a new message, creating it if it does not
already exist, and optionally fill it with STR. Function also adds already exist, and optionally fill it with STR. Function also adds
the new message to the database. When the draft message is added to the new message to the database. When the draft message is added to
the database, `mm/path-docid-map' will be updated, so that we can the database, `mu4e-path-docid-map' will be updated, so that we can
use the new docid. Returns the full path to the new message." use the new docid. Returns the full path to the new message."
(let* ((hostname (let* ((hostname
(downcase (downcase
@ -281,14 +281,14 @@ use the new docid. Returns the full path to the new message."
(substring system-name (substring system-name
(string-match "^[^.]+" system-name) (match-end 0))))) (string-match "^[^.]+" system-name) (match-end 0)))))
(draft (draft
(concat mm/maildir mm/drafts-folder "/cur/" (concat mu4e-maildir mu4e-drafts-folder "/cur/"
(format "%s-%x%x.%s:2,D" ;; 'D': rarely used, but hey, it's available (format "%s-%x%x.%s:2,D" ;; 'D': rarely used, but hey, it's available
(format-time-string "%Y%m%d" (current-time)) (format-time-string "%Y%m%d" (current-time))
(emacs-pid) (random t) hostname))) (emacs-pid) (random t) hostname)))
(str (case compose-type (str (case compose-type
(reply (mm/msg-create-reply msg)) (reply (mu4e-msg-create-reply msg))
(forward (mm/msg-create-forward msg)) (forward (mu4e-msg-create-forward msg))
(new (mm/msg-create-new)) (new (mu4e-msg-create-new))
(t (error "unsupported compose-type %S" compose-type))))) (t (error "unsupported compose-type %S" compose-type)))))
(when str (when str
(with-temp-file draft (with-temp-file draft
@ -296,12 +296,12 @@ use the new docid. Returns the full path to the new message."
(write-file draft))) (write-file draft)))
;; save our file immediately, add add it to the db; thus, we can retrieve ;; save our file immediately, add add it to the db; thus, we can retrieve
;; the new docid from `mm/path-docid-map'. ;; the new docid from `mu4e-path-docid-map'.
(mm/proc-add draft mm/drafts-folder) (mu4e-proc-add draft mu4e-drafts-folder)
draft)) draft))
(defun mm/send-compose-handler (compose-type &optional msg) (defun mu4e-send-compose-handler (compose-type &optional msg)
"Create a new draft message, or open an existing one. "Create a new draft message, or open an existing one.
COMPOSE-TYPE determines the kind of message to compose and is a COMPOSE-TYPE determines the kind of message to compose and is a
@ -312,20 +312,20 @@ When COMPOSE-TYPE is `reply' or `forward', MSG should be a message
plist. If COMPOSE-TYPE is `new', MSG should be nil. plist. If COMPOSE-TYPE is `new', MSG should be nil.
The name of the draft folder is constructed from the concatenation The name of the draft folder is constructed from the concatenation
of `mm/maildir' and `mm/drafts-folder' (therefore, these must be of `mu4e-maildir' and `mu4e-drafts-folder' (therefore, these must be
set). set).
The message file name is a unique name determined by The message file name is a unique name determined by
`mm/msg-draft-file-name'. `mu4e-msg-draft-file-name'.
The initial STR would be created from either `mm/msg-create-reply', The initial STR would be created from either `mu4e-msg-create-reply',
ar`mm/msg-create-forward' or `mm/msg-create-new'. The editing buffer is ar`mu4e-msg-create-forward' or `mu4e-msg-create-new'. The editing buffer is
using Gnus' `message-mode'." using Gnus' `message-mode'."
(unless mm/maildir (error "mm/maildir not set")) (unless mu4e-maildir (error "mu4e-maildir not set"))
(unless mm/drafts-folder (error "mm/drafts-folder not set")) (unless mu4e-drafts-folder (error "mu4e-drafts-folder not set"))
(let ((draft (let ((draft
(if (member compose-type '(reply forward new)) (if (member compose-type '(reply forward new))
(mm/msg-open-draft compose-type msg) (mu4e-msg-open-draft compose-type msg)
(if (eq compose-type 'edit) (if (eq compose-type 'edit)
(plist-get msg :path) (plist-get msg :path)
(error "unsupported compose-type %S" compose-type))))) (error "unsupported compose-type %S" compose-type)))))
@ -340,11 +340,11 @@ using Gnus' `message-mode'."
;; update the db when the file is saved...] ;; update the db when the file is saved...]
(add-to-list 'write-file-functions (add-to-list 'write-file-functions
(lambda() (mm/proc-add (buffer-file-name) mm/drafts-folder))) (lambda() (mu4e-proc-add (buffer-file-name) mu4e-drafts-folder)))
;; hook our functions up with sending of the message ;; hook our functions up with sending of the message
(add-hook 'message-sent-hook 'mm/msg-save-to-sent nil t) (add-hook 'message-sent-hook 'mu4e-msg-save-to-sent nil t)
(add-hook 'message-sent-hook 'mm/send-set-parent-flag nil t) (add-hook 'message-sent-hook 'mu4e-send-set-parent-flag nil t)
(let ((message-hidden-headers (let ((message-hidden-headers
`("^References:" "^Face:" "^X-Face:" "^X-Draft-From:" `("^References:" "^Face:" "^X-Face:" "^X-Draft-From:"
@ -356,10 +356,10 @@ using Gnus' `message-mode'."
(message-goto-body)))) (message-goto-body))))
(defun mm/msg-save-to-sent () (defun mu4e-msg-save-to-sent ()
"Move the message in this buffer to the sent folder. This is "Move the message in this buffer to the sent folder. This is
meant to be called from message mode's `message-sent-hook'." meant to be called from message mode's `message-sent-hook'."
(unless mm/sent-folder (error "mm/sent-folder not set")) (unless mu4e-sent-folder (error "mu4e-sent-folder not set"))
(save-excursion (save-excursion
(goto-char (point-min)) (goto-char (point-min))
;; remove the --text follows this line-- separator ;; remove the --text follows this line-- separator
@ -368,10 +368,10 @@ using Gnus' `message-mode'."
(error "cannot find mail-header-separator")) (error "cannot find mail-header-separator"))
(save-buffer) (save-buffer)
(let ((docid (gethash (buffer-file-name) mm/path-docid-map))) (let ((docid (gethash (buffer-file-name) mu4e-path-docid-map)))
(unless docid (error "unknown message (%S)" (buffer-file-name))) (unless docid (error "unknown message (%S)" (buffer-file-name)))
;; ok, all seems well, well move the message to the sent-folder ;; ok, all seems well, well move the message to the sent-folder
(mm/proc-move-msg docid mm/sent-folder "-T-D+S") (mu4e-proc-move-msg docid mu4e-sent-folder "-T-D+S")
;; we can remove the value from the hash now, if we can establish there ;; we can remove the value from the hash now, if we can establish there
;; are not other compose buffers using this very same docid... ;; are not other compose buffers using this very same docid...
@ -382,7 +382,7 @@ using Gnus' `message-mode'."
(defun mm/send-set-parent-flag () (defun mu4e-send-set-parent-flag ()
"Set the 'replied' flag on messages we replied to, and the "Set the 'replied' flag on messages we replied to, and the
'passed' flag on message we have forwarded. 'passed' flag on message we have forwarded.
@ -413,8 +413,8 @@ This is meant to be called from message mode's
(setq forwarded-from (car-safe (last refs))))))) (setq forwarded-from (car-safe (last refs)))))))
;; remove the <> ;; remove the <>
(when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to)) (when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to))
(mm/proc-flag (match-string 1 in-reply-to) "+R")) (mu4e-proc-flag (match-string 1 in-reply-to) "+R"))
(when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from)) (when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from))
(mm/proc-flag (match-string 1 forwarded-from) "+P")))) (mu4e-proc-flag (match-string 1 forwarded-from) "+P"))))
(provide 'mm-send) (provide 'mu4e-send)

View File

@ -1,4 +1,4 @@
;; mm-view.el -- part of mm, the mu mail user agent ;; mu4e-view.el -- part of mm, the mu mail user agent
;; ;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema ;; Copyright (C) 2011 Dirk-Jan C. Binnema
@ -36,20 +36,20 @@
(require 'filladapt) (require 'filladapt)
(require 'comint) (require 'comint)
(defconst mm/view-buffer-name "*mm-view*" (defconst mu4e-view-buffer-name "*mu4e-view*"
"*internal* Name for the message view buffer") "*internal* Name for the message view buffer")
(defconst mm/view-raw-buffer-name "*mm-view-raw*" (defconst mu4e-view-raw-buffer-name "*mu4e-view-raw*"
"*internal* Name for the raw message view buffer") "*internal* Name for the raw message view buffer")
;; some buffer-local variables ;; some buffer-local variables
(defvar mm/hdrs-buffer nil (defvar mu4e-hdrs-buffer nil
"*internal* Headers buffer connected to this view.") "*internal* Headers buffer connected to this view.")
(defvar mm/current-msg nil (defvar mu4e-current-msg nil
"*internal* The plist describing the current message.") "*internal* The plist describing the current message.")
(defun mm/view (msg hdrsbuf &optional update) (defun mu4e-view (msg hdrsbuf &optional update)
"Display the message MSG in a new buffer, and keep in sync with HDRSBUF. "Display the message MSG in a new buffer, and keep in sync with HDRSBUF.
'In sync' here means that moving to the next/previous message in 'In sync' here means that moving to the next/previous message in
the the message view affects HDRSBUF, as does marking etc. If the the message view affects HDRSBUF, as does marking etc. If
@ -57,72 +57,72 @@ UPDATE is non-nil, the current message will be (visually) updated.
As a side-effect, a message that is being viewed loses its 'unread' As a side-effect, a message that is being viewed loses its 'unread'
marking if it still had that." marking if it still had that."
(let ((buf (get-buffer-create mm/view-buffer-name)) (let ((buf (get-buffer-create mu4e-view-buffer-name))
(inhibit-read-only t)) (inhibit-read-only t))
(with-current-buffer buf (with-current-buffer buf
(erase-buffer) (erase-buffer)
(insert (insert
(mapconcat (mapconcat
(lambda (field) (lambda (field)
(let ((fieldname (cdr (assoc field mm/header-names))) (let ((fieldname (cdr (assoc field mu4e-header-names)))
(fieldval (plist-get msg field))) (fieldval (plist-get msg field)))
(case field (case field
(:subject (mm/view-header fieldname fieldval)) (:subject (mu4e-view-header fieldname fieldval))
(:path (mm/view-header fieldname fieldval)) (:path (mu4e-view-header fieldname fieldval))
(:maildir (mm/view-header fieldname fieldval)) (:maildir (mu4e-view-header fieldname fieldval))
(:flags (mm/view-header fieldname (:flags (mu4e-view-header fieldname
(if fieldval (format "%S" fieldval) ""))) (if fieldval (format "%S" fieldval) "")))
;; contact fields ;; contact fields
(:to (mm/view-contacts msg field)) (:to (mu4e-view-contacts msg field))
(:from (mm/view-contacts msg field)) (:from (mu4e-view-contacts msg field))
(:cc (mm/view-contacts msg field)) (:cc (mu4e-view-contacts msg field))
(:bcc (mm/view-contacts msg field)) (:bcc (mu4e-view-contacts msg field))
;; if we (`user-mail-address' are the From, show To, otherwise, ;; if we (`user-mail-address' are the From, show To, otherwise,
;; show From ;; show From
(:from-or-to (:from-or-to
(let* ((from (plist-get msg :from)) (let* ((from (plist-get msg :from))
(from (and from (cdar from)))) (from (and from (cdar from))))
(if (and from (string-match mm/user-mail-address-regexp from)) (if (and from (string-match mu4e-user-mail-address-regexp from))
(mm/view-contacts msg :to) (mu4e-view-contacts msg :to)
(mm/view-contacts msg :from)))) (mu4e-view-contacts msg :from))))
;; date ;; date
(:date (:date
(let ((datestr (let ((datestr
(when fieldval (format-time-string mm/view-date-format fieldval)))) (when fieldval (format-time-string mu4e-view-date-format fieldval))))
(if datestr (mm/view-header fieldname datestr) ""))) (if datestr (mu4e-view-header fieldname datestr) "")))
;; size ;; size
(:size (mm/view-size msg) (:size (mu4e-view-size msg)
(let ((sizestr (when size (format "%d bytes")))) (let ((sizestr (when size (format "%d bytes"))))
(if sizestr (mm/view-header fieldname sizestr)))) (if sizestr (mu4e-view-header fieldname sizestr))))
;; attachments ;; attachments
(:attachments (mm/view-attachments msg)) (:attachments (mu4e-view-attachments msg))
(t (error "Unsupported field: %S" field))))) (t (error "Unsupported field: %S" field)))))
mm/view-fields "") mu4e-view-fields "")
"\n" "\n"
(mm/view-body msg)) (mu4e-view-body msg))
;; initialize view-mode ;; initialize view-mode
(mm/view-mode) (mu4e-view-mode)
(setq ;; these are buffer-local (setq ;; these are buffer-local
mode-name (if (plist-get msg :subject) mode-name (if (plist-get msg :subject)
(truncate-string-to-width (plist-get msg :subject) 16 0 nil t) (truncate-string-to-width (plist-get msg :subject) 16 0 nil t)
(propertize "No subject" 'face 'mm/system-face)) (propertize "No subject" 'face 'mu4e-system-face))
mm/current-msg msg mu4e-current-msg msg
mm/hdrs-buffer hdrsbuf mu4e-hdrs-buffer hdrsbuf
mm/link-map (make-hash-table :size 32 :rehash-size 2 :weakness nil)) mu4e-link-map (make-hash-table :size 32 :rehash-size 2 :weakness nil))
(switch-to-buffer buf) (switch-to-buffer buf)
(goto-char (point-min)) (goto-char (point-min))
(mm/view-beautify) (mu4e-view-beautify)
(unless update (unless update
(mm/view-mark-as-read-maybe))))) (mu4e-view-mark-as-read-maybe)))))
(defun mm/view-body (msg) (defun mu4e-view-body (msg)
"Get the body for this message, which is either :body-txt, "Get the body for this message, which is either :body-txt,
or if not available, :body-html converted to text)." or if not available, :body-html converted to text)."
(or (plist-get msg :body-txt) (or (plist-get msg :body-txt)
@ -133,22 +133,22 @@ or if not available, :body-html converted to text)."
"No body found")) "No body found"))
(defun mm/view-header (key val &optional dont-propertize-val) (defun mu4e-view-header (key val &optional dont-propertize-val)
"Show header FIELD for MSG with KEY. ie. <KEY>: value-of-FIELD." "Show header FIELD for MSG with KEY. ie. <KEY>: value-of-FIELD."
(if val (if val
(concat (concat
(propertize key 'face 'mm/view-header-key-face) ": " (propertize key 'face 'mu4e-view-header-key-face) ": "
(if dont-propertize-val (if dont-propertize-val
val val
(propertize val 'face 'mm/view-header-value-face)) (propertize val 'face 'mu4e-view-header-value-face))
"\n") "\n")
"")) ""))
(defun mm/view-contacts (msg field) (defun mu4e-view-contacts (msg field)
"Add a header for a contact field (ie., :to, :from, :cc, :bcc)." "Add a header for a contact field (ie., :to, :from, :cc, :bcc)."
(let* ((lst (plist-get msg field)) (let* ((lst (plist-get msg field))
(fieldname (cdr (assoc field mm/header-names))) (fieldname (cdr (assoc field mu4e-header-names)))
(contacts (contacts
(and lst (and lst
(mapconcat (mapconcat
@ -158,20 +158,20 @@ or if not available, :body-html converted to text)."
(format "%s <%s>" name email) (format "%s <%s>" name email)
(format "%s" email)))) lst ", ")))) (format "%s" email)))) lst ", "))))
(if contacts (if contacts
(mm/view-header fieldname contacts) (mu4e-view-header fieldname contacts)
""))) "")))
(defvar mm/attach-map nil (defvar mu4e-attach-map nil
"*internal* Hash which maps a number to a (part-id name mime-type).") "*internal* Hash which maps a number to a (part-id name mime-type).")
(defun mm/view-attachments (msg) (defun mu4e-view-attachments (msg)
"Display attachment information; the field looks like something like: "Display attachment information; the field looks like something like:
:attachments ((:index 4 :name \"test123.doc\" :attachments ((:index 4 :name \"test123.doc\"
:mime-type \"application/msword\" :size 1234))." :mime-type \"application/msword\" :size 1234))."
(let ((atts (plist-get msg :attachments))) (let ((atts (plist-get msg :attachments)))
(when atts (when atts
(setq mm/attach-map (setq mu4e-attach-map
(make-hash-table :size 32 :rehash-size 2 :weakness nil)) (make-hash-table :size 32 :rehash-size 2 :weakness nil))
(let* ((id 0) (let* ((id 0)
(vals (vals
@ -182,42 +182,42 @@ or if not available, :body-html converted to text)."
(mime-type (plist-get att :mime-type)) (mime-type (plist-get att :mime-type))
(size (plist-get att :size))) (size (plist-get att :size)))
(incf id) (incf id)
(puthash id att mm/attach-map) (puthash id att mu4e-attach-map)
(concat (concat
(propertize (format "[%d]" id) 'face 'mm/view-attach-number-face) (propertize (format "[%d]" id) 'face 'mu4e-view-attach-number-face)
(propertize name 'face 'mm/view-link-face) (propertize name 'face 'mu4e-view-link-face)
(if size (if size
(concat (concat
"(" (propertize (mm/display-size size) 'face 'mm/view-header-key-face) "(" (propertize (mu4e-display-size size) 'face 'mu4e-view-header-key-face)
")") ")")
"") "")
))) )))
atts ", "))) atts ", ")))
(mm/view-header (format "Attachments(%d)" id) vals t))))) (mu4e-view-header (format "Attachments(%d)" id) vals t)))))
(defvar mm/view-mode-map nil (defvar mu4e-view-mode-map nil
"Keymap for \"*mm-view*\" buffers.") "Keymap for \"*mu4e-view*\" buffers.")
(unless mm/view-mode-map (unless mu4e-view-mode-map
(setq mm/view-mode-map (setq mu4e-view-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map "q" 'mm/view-quit-buffer) (define-key map "q" 'mu4e-view-quit-buffer)
(define-key map "s" 'mm/search) (define-key map "s" 'mu4e-search)
(define-key map "S" 'mm/search-full) (define-key map "S" 'mu4e-search-full)
(define-key map "b" 'mm/search-bookmark) (define-key map "b" 'mu4e-search-bookmark)
(define-key map "j" 'mm/jump-to-maildir) (define-key map "j" 'mu4e-jump-to-maildir)
(define-key map "g" 'mm/view-go-to-url) (define-key map "g" 'mu4e-view-go-to-url)
(define-key map "f" 'mm/compose-forward) (define-key map "f" 'mu4e-compose-forward)
(define-key map "r" 'mm/compose-reply) (define-key map "r" 'mu4e-compose-reply)
(define-key map "c" 'mm/compose-new) (define-key map "c" 'mu4e-compose-new)
(define-key map "e" 'mm/edit-draft) (define-key map "e" 'mu4e-edit-draft)
(define-key map "." 'mm/view-raw) (define-key map "." 'mu4e-view-raw)
(define-key map "|" 'mm/view-pipe) (define-key map "|" 'mu4e-view-pipe)
;; (define-key map "I" 'mm/inspect-message) ;; (define-key map "I" 'mu4e-inspect-message)
;; intra-message navigation ;; intra-message navigation
(define-key map (kbd "SPC") 'scroll-up) (define-key map (kbd "SPC") 'scroll-up)
@ -232,109 +232,109 @@ or if not available, :body-html converted to text)."
;; navigation between messages ;; navigation between messages
(define-key map "n" 'mm/view-next-header) (define-key map "n" 'mu4e-view-next-header)
(define-key map "p" 'mm/view-prev-header) (define-key map "p" 'mu4e-view-prev-header)
;; attachments ;; attachments
(define-key map "e" 'mm/view-extract-attachment) (define-key map "e" 'mu4e-view-extract-attachment)
(define-key map "o" 'mm/view-open-attachment) (define-key map "o" 'mu4e-view-open-attachment)
;; marking/unmarking ;; marking/unmarking
(define-key map (kbd "<backspace>") 'mm/mark-for-trash) (define-key map (kbd "<backspace>") 'mu4e-mark-for-trash)
(define-key map "d" 'mm/view-mark-for-trash) (define-key map "d" 'mu4e-view-mark-for-trash)
(define-key map (kbd "<delete>") 'mm/view-mark-for-delete) (define-key map (kbd "<delete>") 'mu4e-view-mark-for-delete)
(define-key map "D" 'mm/view-mark-for-delete) (define-key map "D" 'mu4e-view-mark-for-delete)
(define-key map "a" 'mm/mark-for-move-quick) (define-key map "a" 'mu4e-mark-for-move-quick)
(define-key map "m" 'mm/view-mark-for-move) (define-key map "m" 'mu4e-view-mark-for-move)
;; misc ;; misc
(define-key map "w" 'mm/view-toggle-wrap-lines) (define-key map "w" 'mu4e-view-toggle-wrap-lines)
(define-key map "h" 'mm/view-toggle-hide-cited) (define-key map "h" 'mu4e-view-toggle-hide-cited)
(define-key map "R" 'mm/view-refresh) (define-key map "R" 'mu4e-view-refresh)
;; next 3 only warn user when attempt in the message view ;; next 3 only warn user when attempt in the message view
(define-key map "u" 'mm/view-unmark) (define-key map "u" 'mu4e-view-unmark)
(define-key map "U" 'mm/view-unmark) (define-key map "U" 'mu4e-view-unmark)
(define-key map "x" 'mm/view-marked-execute) (define-key map "x" 'mu4e-view-marked-execute)
;; menu ;; menu
(define-key map [menu-bar] (make-sparse-keymap)) (define-key map [menu-bar] (make-sparse-keymap))
(let ((menumap (make-sparse-keymap "View"))) (let ((menumap (make-sparse-keymap "View")))
(define-key map [menu-bar headers] (cons "View" menumap)) (define-key map [menu-bar headers] (cons "View" menumap))
(define-key menumap [quit-buffer] '("Quit view" . mm/view-quit-buffer)) (define-key menumap [quit-buffer] '("Quit view" . mu4e-view-quit-buffer))
(define-key menumap [sepa0] '("--")) (define-key menumap [sepa0] '("--"))
(define-key menumap [wrap-lines] (define-key menumap [wrap-lines]
'("Toggle wrap lines" . mm/view-toggle-wrap-lines)) '("Toggle wrap lines" . mu4e-view-toggle-wrap-lines))
(define-key menumap [hide-cited] (define-key menumap [hide-cited]
'("Toggle hide cited" . mm/view-toggle-hide-cited)) '("Toggle hide cited" . mu4e-view-toggle-hide-cited))
(define-key menumap [view-raw] (define-key menumap [view-raw]
'("View raw message" . mm/view-raw)) '("View raw message" . mu4e-view-raw))
(define-key menumap [pipe] (define-key menumap [pipe]
'("Pipe through shell" . mm/view-pipe)) '("Pipe through shell" . mu4e-view-pipe))
(define-key menumap [inspect] (define-key menumap [inspect]
'("Inspect with guile" . mm/inspect-message)) '("Inspect with guile" . mu4e-inspect-message))
(define-key menumap [sepa8] '("--")) (define-key menumap [sepa8] '("--"))
(define-key menumap [open-att] (define-key menumap [open-att]
'("Open attachment" . mm/view-open-attachment)) '("Open attachment" . mu4e-view-open-attachment))
(define-key menumap [extract-att] (define-key menumap [extract-att]
'("Extract attachment" . mm/view-extract-attachment)) '("Extract attachment" . mu4e-view-extract-attachment))
(define-key menumap [goto-url] (define-key menumap [goto-url]
'("Visit URL" . mm/view-go-to-url)) '("Visit URL" . mu4e-view-go-to-url))
(define-key menumap [sepa1] '("--")) (define-key menumap [sepa1] '("--"))
(define-key menumap [mark-delete] (define-key menumap [mark-delete]
'("Mark for deletion" . mm/view-mark-for-delete)) '("Mark for deletion" . mu4e-view-mark-for-delete))
(define-key menumap [mark-trash] (define-key menumap [mark-trash]
'("Mark for trash" . mm/view-mark-for-trash)) '("Mark for trash" . mu4e-view-mark-for-trash))
(define-key menumap [mark-move] (define-key menumap [mark-move]
'("Mark for move" . mm/view-mark-for-move)) '("Mark for move" . mu4e-view-mark-for-move))
(define-key menumap [sepa2] '("--")) (define-key menumap [sepa2] '("--"))
(define-key menumap [compose-new] '("Compose new" . mm/compose-new)) (define-key menumap [compose-new] '("Compose new" . mu4e-compose-new))
(define-key menumap [forward] '("Forward" . mm/compose-forward)) (define-key menumap [forward] '("Forward" . mu4e-compose-forward))
(define-key menumap [reply] '("Reply" . mm/compose-reply)) (define-key menumap [reply] '("Reply" . mu4e-compose-reply))
(define-key menumap [sepa3] '("--")) (define-key menumap [sepa3] '("--"))
(define-key menumap [search] '("Search" . mm/search)) (define-key menumap [search] '("Search" . mu4e-search))
(define-key menumap [jump] '("Jump to maildir" . mm/jump-to-maildir)) (define-key menumap [jump] '("Jump to maildir" . mu4e-jump-to-maildir))
(define-key menumap [sepa4] '("--")) (define-key menumap [sepa4] '("--"))
(define-key menumap [next] '("Next" . mm/view-next-header)) (define-key menumap [next] '("Next" . mu4e-view-next-header))
(define-key menumap [previous] '("Previous" . mm/view-prev-header))) (define-key menumap [previous] '("Previous" . mu4e-view-prev-header)))
map))) map)))
(fset 'mm/view-mode-map mm/view-mode-map) (fset 'mu4e-view-mode-map mu4e-view-mode-map)
(defvar mm/wrap-lines nil (defvar mu4e-wrap-lines nil
"*internal* Whether to wrap lines or not (variable controlled by "*internal* Whether to wrap lines or not (variable controlled by
`mm/view-toggle-wrap-lines').") `mu4e-view-toggle-wrap-lines').")
(defvar mm/hide-cited nil (defvar mu4e-hide-cited nil
"*internal* Whether to hide cited lines or not (the variable can "*internal* Whether to hide cited lines or not (the variable can
be changed with `mm/view-toggle-hide-cited').") be changed with `mu4e-view-toggle-hide-cited').")
(defun mm/view-mode () (defun mu4e-view-mode ()
"Major mode for viewing an e-mail message." "Major mode for viewing an e-mail message."
(interactive) (interactive)
(kill-all-local-variables) (kill-all-local-variables)
(use-local-map mm/view-mode-map) (use-local-map mu4e-view-mode-map)
(make-local-variable 'mm/hdrs-buffer) (make-local-variable 'mu4e-hdrs-buffer)
(make-local-variable 'mm/current-msg) (make-local-variable 'mu4e-current-msg)
(make-local-variable 'mm/link-map) (make-local-variable 'mu4e-link-map)
(make-local-variable 'mm/wrap-lines) (make-local-variable 'mu4e-wrap-lines)
(make-local-variable 'mm/hide-cited) (make-local-variable 'mu4e-hide-cited)
(setq major-mode 'mm/view-mode mode-name mm/view-buffer-name) (setq major-mode 'mu4e-view-mode mode-name mu4e-view-buffer-name)
(setq truncate-lines t buffer-read-only t)) (setq truncate-lines t buffer-read-only t))
;;;;;; ;;;;;;
@ -343,21 +343,21 @@ or if not available, :body-html converted to text)."
;; we mark messages are as read when we leave the message; ie., when skipping to ;; we mark messages are as read when we leave the message; ie., when skipping to
;; the next/previous one, or leaving the view buffer altogether. ;; the next/previous one, or leaving the view buffer altogether.
(defun mm/view-mark-as-read-maybe () (defun mu4e-view-mark-as-read-maybe ()
"Clear the current message's New/Unread status and set it to "Clear the current message's New/Unread status and set it to
Seen; if the message is not New/Unread, do nothing." Seen; if the message is not New/Unread, do nothing."
(when mm/current-msg (when mu4e-current-msg
(let ((flags (plist-get mm/current-msg :flags)) (let ((flags (plist-get mu4e-current-msg :flags))
(docid (plist-get mm/current-msg :docid))) (docid (plist-get mu4e-current-msg :docid)))
;; is it a new message? ;; is it a new message?
(when (or (member 'unread flags) (member 'new flags)) (when (or (member 'unread flags) (member 'new flags))
(mm/proc-flag docid "+S-u-N"))))) (mu4e-proc-flag docid "+S-u-N")))))
(defvar mm/link-map nil (defvar mu4e-link-map nil
"*internal* A map of some number->url so we can jump to url by number.") "*internal* A map of some number->url so we can jump to url by number.")
(defun mm/view-beautify () (defun mu4e-view-beautify ()
"Improve the message view a bit, by making URLs clickable, "Improve the message view a bit, by making URLs clickable,
removing '^M' etc." removing '^M' etc."
(let ((num 0)) (let ((num 0))
@ -370,47 +370,47 @@ removing '^M' etc."
(goto-char (point-min)) (goto-char (point-min))
(let ((p (search-forward "\n-- \n" nil t))) (let ((p (search-forward "\n-- \n" nil t)))
(when p (when p
(add-text-properties p (point-max) '(face mm/view-footer-face)))) (add-text-properties p (point-max) '(face mu4e-view-footer-face))))
;; this is fairly simplistic... ;; this is fairly simplistic...
(goto-char (point-min)) (goto-char (point-min))
(while (re-search-forward "\\(https?://[-a-zA-Z0-9?_.$%/=+&#@!~,:;]*\\)\\>" (while (re-search-forward "\\(https?://[-a-zA-Z0-9?_.$%/=+&#@!~,:;]*\\)\\>"
nil t) nil t)
(let ((subst (propertize (match-string-no-properties 0) (let ((subst (propertize (match-string-no-properties 0)
'face 'mm/view-link-face))) 'face 'mu4e-view-link-face)))
(incf num) (incf num)
(puthash num (match-string-no-properties 0) mm/link-map) (puthash num (match-string-no-properties 0) mu4e-link-map)
(replace-match (concat subst (replace-match (concat subst
(propertize (format "[%d]" num) (propertize (format "[%d]" num)
'face 'mm/view-url-number-face)))))))) 'face 'mu4e-view-url-number-face))))))))
;; raw mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; raw mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; some buffer-local variables ;; some buffer-local variables
(defvar mm/view-buffer nil (defvar mu4e-view-buffer nil
"*internal* View buffer connected to this raw view.") "*internal* View buffer connected to this raw view.")
(defun mm/view-raw-mode () (defun mu4e-view-raw-mode ()
"Major mode for viewing of raw e-mail message." "Major mode for viewing of raw e-mail message."
(interactive) (interactive)
(kill-all-local-variables) (kill-all-local-variables)
(use-local-map mm/view-raw-mode-map) (use-local-map mu4e-view-raw-mode-map)
(make-local-variable 'mm/view-buffer) (make-local-variable 'mu4e-view-buffer)
(setq major-mode 'mm/view-raw-mode (setq major-mode 'mu4e-view-raw-mode
mode-name "mm: raw view") mode-name "mm: raw view")
(setq truncate-lines t buffer-read-only t)) (setq truncate-lines t buffer-read-only t))
(defvar mm/view-raw-mode-map nil (defvar mu4e-view-raw-mode-map nil
"Keymap for \"*mm-view-raw*\" buffers.") "Keymap for \"*mu4e-view-raw*\" buffers.")
(unless mm/view-raw-mode-map (unless mu4e-view-raw-mode-map
(setq mm/view-raw-mode-map (setq mu4e-view-raw-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
(define-key map "q" 'mm/view-raw-quit-buffer) (define-key map "q" 'mu4e-view-raw-quit-buffer)
(define-key map "." 'mm/view-raw-quit-buffer) (define-key map "." 'mu4e-view-raw-quit-buffer)
;; intra-message navigation ;; intra-message navigation
(define-key map (kbd "SPC") 'scroll-up) (define-key map (kbd "SPC") 'scroll-up)
@ -428,15 +428,15 @@ removing '^M' etc."
(let ((menumap (make-sparse-keymap "Raw view"))) (let ((menumap (make-sparse-keymap "Raw view")))
(define-key map [menu-bar headers] (cons "Raw view" menumap)) (define-key map [menu-bar headers] (cons "Raw view" menumap))
(define-key menumap [quit-buffer] '("Quit" . (define-key menumap [quit-buffer] '("Quit" .
mm/view-raw-quit-buffer)) mu4e-view-raw-quit-buffer))
map)))) map))))
(fset 'mm/view-raw-mode-map mm/view-raw-mode-map) (fset 'mu4e-view-raw-mode-map mu4e-view-raw-mode-map)
(defun mm/view-raw-message (msg view-buffer) (defun mu4e-view-raw-message (msg view-buffer)
"Display the raw contents of message MSG in a new buffer." "Display the raw contents of message MSG in a new buffer."
(let ((buf (get-buffer-create mm/view-raw-buffer-name)) (let ((buf (get-buffer-create mu4e-view-raw-buffer-name))
(inhibit-read-only t) (inhibit-read-only t)
(file (plist-get msg :path))) (file (plist-get msg :path)))
(unless (and file (file-readable-p file)) (unless (and file (file-readable-p file))
@ -445,15 +445,15 @@ removing '^M' etc."
(erase-buffer) (erase-buffer)
(insert-file file) (insert-file file)
;; initialize view-mode ;; initialize view-mode
(mm/view-raw-mode) (mu4e-view-raw-mode)
(setq mm/view-buffer view-buffer) (setq mu4e-view-buffer view-buffer)
(switch-to-buffer buf) (switch-to-buffer buf)
(goto-char (point-min))))) (goto-char (point-min)))))
(defun mm/view-shell-command-on-raw-message (msg view-buffer cmd) (defun mu4e-view-shell-command-on-raw-message (msg view-buffer cmd)
"Process the raw message with shell command CMD." "Process the raw message with shell command CMD."
(let ((buf (get-buffer-create mm/view-raw-buffer-name)) (let ((buf (get-buffer-create mu4e-view-raw-buffer-name))
(inhibit-read-only t) (inhibit-read-only t)
(file (plist-get msg :path))) (file (plist-get msg :path)))
(unless (and file (file-readable-p file)) (unless (and file (file-readable-p file))
@ -461,41 +461,41 @@ removing '^M' etc."
(with-current-buffer buf (with-current-buffer buf
(erase-buffer) (erase-buffer)
(process-file-shell-command cmd file buf) (process-file-shell-command cmd file buf)
(mm/view-raw-mode) (mu4e-view-raw-mode)
(setq mm/view-buffer view-buffer) (setq mu4e-view-buffer view-buffer)
(switch-to-buffer buf) (switch-to-buffer buf)
(goto-char (point-min))))) (goto-char (point-min)))))
(defun mm/view-raw-quit-buffer () (defun mu4e-view-raw-quit-buffer ()
"Quit the raw view and return to the message." "Quit the raw view and return to the message."
(interactive) (interactive)
(if (buffer-live-p mm/view-buffer) (if (buffer-live-p mu4e-view-buffer)
(switch-to-buffer mm/view-buffer) (switch-to-buffer mu4e-view-buffer)
(kill-buffer))) (kill-buffer)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; functions for org-contacts ;; functions for org-contacts
(defun mm/org-contacts-from (name-or-email) (defun mu4e-org-contacts-from (name-or-email)
"Get a message field if we are in view mode; NAME-OR-EMAIL should "Get a message field if we are in view mode; NAME-OR-EMAIL should
be either 'name or 'email to get the corresponding field. If the be either 'name or 'email to get the corresponding field. If the
field is not found, \"\" is returned. Use this with org-contact field is not found, \"\" is returned. Use this with org-contact
with a template like: with a template like:
(\"c\" \"Contacts\" entry (file \"~/Org/contacts.org\") (\"c\" \"Contacts\" entry (file \"~/Org/contacts.org\")
\"* %(mm/org-contacts-from 'name) \"* %(mu4e-org-contacts-from 'name)
:PROPERTIES: :PROPERTIES:
:EMAIL: %(mm/org-contacts-from 'email) :EMAIL: %(mu4e-org-contacts-from 'email)
:END:\"))) :END:\")))
See the `org-contacts' documentation for more details." See the `org-contacts' documentation for more details."
(with-current-buffer mm/view-buffer-name ;; hackish... (with-current-buffer mu4e-view-buffer-name ;; hackish...
(unless (eq major-mode 'mm/view-mode) (unless (eq major-mode 'mu4e-view-mode)
(error "Not in mm/view mode.")) (error "Not in mu4e-view mode."))
(unless mm/current-msg (unless mu4e-current-msg
(error "No current message.")) (error "No current message."))
(let ((from (car-safe (plist-get mm/current-msg :from)))) (let ((from (car-safe (plist-get mu4e-current-msg :from))))
(cond (cond
((not from) "") ;; nothing found ((not from) "") ;; nothing found
((eq name-or-email 'name) ((eq name-or-email 'name)
@ -511,85 +511,85 @@ See the `org-contacts' documentation for more details."
;; Interactive functions ;; Interactive functions
(defun mm/view-toggle-wrap-lines () (defun mu4e-view-toggle-wrap-lines ()
"Toggle line wrap in the message body." "Toggle line wrap in the message body."
(interactive) (interactive)
(if mm/wrap-lines (if mu4e-wrap-lines
(progn (progn
(setq mm/wrap-lines nil) (setq mu4e-wrap-lines nil)
(mm/view-refresh)) ;; back to normal (mu4e-view-refresh)) ;; back to normal
(save-excursion (save-excursion
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
(setq mm/wrap-lines t) (setq mu4e-wrap-lines t)
(goto-char (point-min)) (goto-char (point-min))
(when (search-forward "\n\n") ;; search for the message body (when (search-forward "\n\n") ;; search for the message body
(fill-region (point) (point-max))))))) (fill-region (point) (point-max)))))))
(defun mm/view-toggle-hide-cited () (defun mu4e-view-toggle-hide-cited ()
"Toggle hiding of cited lines in the message body." "Toggle hiding of cited lines in the message body."
(interactive) (interactive)
(if mm/hide-cited (if mu4e-hide-cited
(progn (progn
(setq mm/hide-cited nil) (setq mu4e-hide-cited nil)
(mm/view-refresh)) (mu4e-view-refresh))
(save-excursion (save-excursion
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
(goto-char (point-min)) (goto-char (point-min))
(flush-lines "^[:blank:]*>") (flush-lines "^[:blank:]*>")
(setq mm/hide-cited t))))) (setq mu4e-hide-cited t)))))
(defun mm/view-refresh () (defun mu4e-view-refresh ()
"Redisplay the current message." "Redisplay the current message."
(interactive) (interactive)
(mm/view mm/current-msg mm/hdrs-buffer t)) (mu4e-view mu4e-current-msg mu4e-hdrs-buffer t))
(defun mm/view-quit-buffer () (defun mu4e-view-quit-buffer ()
"Quit the message view and return to the headers." "Quit the message view and return to the headers."
(interactive) (interactive)
(if (buffer-live-p mm/hdrs-buffer) (if (buffer-live-p mu4e-hdrs-buffer)
(switch-to-buffer mm/hdrs-buffer) (switch-to-buffer mu4e-hdrs-buffer)
(kill-buffer))) (kill-buffer)))
(defun mm/view-next-header () (defun mu4e-view-next-header ()
"View the next header." "View the next header."
(interactive) (interactive)
(when (mm/next-header) (when (mu4e-next-header)
(mm/view-message))) (mu4e-view-message)))
(defun mm/view-prev-header () (defun mu4e-view-prev-header ()
"View the previous header." "View the previous header."
(interactive) (interactive)
(when (mm/prev-header) (when (mu4e-prev-header)
(mm/view-message))) (mu4e-view-message)))
(defun mm/view-mark-for-move () (defun mu4e-view-mark-for-move ()
"Mark the current message for moving." "Mark the current message for moving."
(interactive) (interactive)
(when (mm/mark-for-move) (when (mu4e-mark-for-move)
(mm/view-message))) (mu4e-view-message)))
(defun mm/view-mark-for-trash () (defun mu4e-view-mark-for-trash ()
"Mark the current message for moving to the trash folder." "Mark the current message for moving to the trash folder."
(interactive) (interactive)
(when (mm/mark-for-trash) (when (mu4e-mark-for-trash)
(mm/view-message))) (mu4e-view-message)))
(defun mm/view-mark-for-delete () (defun mu4e-view-mark-for-delete ()
"Mark the current message for deletion." "Mark the current message for deletion."
(interactive) (interactive)
(when (mm/mark-for-delete) (when (mu4e-mark-for-delete)
(mm/view-message))) (mu4e-view-message)))
(defun mm/view-extract-attachment (attnum) (defun mu4e-view-extract-attachment (attnum)
"Extract the attachment with ATTNUM." "Extract the attachment with ATTNUM."
(unless mm/attachment-dir (error "`mm/attachment-dir' is not set")) (unless mu4e-attachment-dir (error "`mu4e-attachment-dir' is not set"))
(when (or (null mm/attach-map) (zerop (hash-table-count mm/attach-map))) (when (or (null mu4e-attach-map) (zerop (hash-table-count mu4e-attach-map)))
(error "No attachments for this message")) (error "No attachments for this message"))
(interactive "nAttachment to extract:") (interactive "nAttachment to extract:")
(let* ((att (gethash attnum mm/attach-map)) (let* ((att (gethash attnum mu4e-attach-map))
(path (and att (concat mm/attachment-dir (path (and att (concat mu4e-attachment-dir
"/" (plist-get att :name)))) "/" (plist-get att :name))))
(id (and att (plist-get att :index))) (id (and att (plist-get att :index)))
(retry t)) (retry t))
@ -599,74 +599,74 @@ See the `org-contacts' documentation for more details."
(setq retry (setq retry
(and (file-exists-p path) (and (file-exists-p path)
(not (y-or-n-p (concat "Overwrite " path "?")))))) (not (y-or-n-p (concat "Overwrite " path "?"))))))
(mm/proc-save (plist-get mm/current-msg :docid) id path))) (mu4e-proc-save (plist-get mu4e-current-msg :docid) id path)))
(defun mm/view-open-attachment (attnum) (defun mu4e-view-open-attachment (attnum)
"Extract the attachment with ATTNUM" "Extract the attachment with ATTNUM"
(unless mm/attach-map (unless mu4e-attach-map
(error "No attachments for this message")) (error "No attachments for this message"))
(interactive "nAttachment to open:") (interactive "nAttachment to open:")
(let* ((att (gethash attnum mm/attach-map)) (let* ((att (gethash attnum mu4e-attach-map))
(id (and att (plist-get att :index)))) (id (and att (plist-get att :index))))
(unless id (error "Not a valid attachment number")) (unless id (error "Not a valid attachment number"))
(mm/proc-open (plist-get mm/current-msg :docid) id))) (mu4e-proc-open (plist-get mu4e-current-msg :docid) id)))
(defun mm/view-unmark () (defun mu4e-view-unmark ()
"Warn user that unmarking only works in the header list." "Warn user that unmarking only works in the header list."
(interactive) (interactive)
(message "Unmarking needs to be done in the header list view")) (message "Unmarking needs to be done in the header list view"))
(defun mm/view-marked-execute () (defun mu4e-view-marked-execute ()
"Warn user that execution can only take place in n the header "Warn user that execution can only take place in n the header
list." list."
(interactive) (interactive)
(message "Execution needs to be done in the header list view")) (message "Execution needs to be done in the header list view"))
(defun mm/view-go-to-url (num) (defun mu4e-view-go-to-url (num)
"Go to a numbered url." "Go to a numbered url."
(interactive "nGo to url with number: ") (interactive "nGo to url with number: ")
(let ((url (gethash num mm/link-map))) (let ((url (gethash num mu4e-link-map)))
(unless url (error "Invalid number for URL")) (unless url (error "Invalid number for URL"))
(browse-url url))) (browse-url url)))
(defun mm/view-raw () (defun mu4e-view-raw ()
"Show the the raw text of the current message." "Show the the raw text of the current message."
(interactive) (interactive)
(unless mm/current-msg (unless mu4e-current-msg
(error "No current message")) (error "No current message"))
(mm/view-raw-message mm/current-msg (current-buffer))) (mu4e-view-raw-message mu4e-current-msg (current-buffer)))
(defun mm/view-pipe (cmd) (defun mu4e-view-pipe (cmd)
"Pipe the message through shell command CMD, and display the "Pipe the message through shell command CMD, and display the
results." results."
(interactive "sShell command: ") (interactive "sShell command: ")
(unless mm/current-msg (unless mu4e-current-msg
(error "No current message")) (error "No current message"))
(mm/view-shell-command-on-raw-message mm/current-msg (current-buffer) cmd)) (mu4e-view-shell-command-on-raw-message mu4e-current-msg (current-buffer) cmd))
(defconst mm/muile-buffer-name "*muile*" (defconst mu4e-muile-buffer-name "*muile*"
"Name of the buffer to execute muile.") "Name of the buffer to execute muile.")
(defconst mm/muile-process-name "*muile*" (defconst mu4e-muile-process-name "*muile*"
"Name of the muile process.") "Name of the muile process.")
;; note, implementation is very basic/primitive; we probably need comint to do ;; note, implementation is very basic/primitive; we probably need comint to do
;; something like geiser does (http://www.nongnu.org/geiser/). Desirable ;; something like geiser does (http://www.nongnu.org/geiser/). Desirable
;; features: a) the output is not editable b) tab-completions work ;; features: a) the output is not editable b) tab-completions work
(defun mm/inspect-message () (defun mu4e-inspect-message ()
"Inspect the current message in the Guile/Muile shell." "Inspect the current message in the Guile/Muile shell."
(interactive) (interactive)
(unless mm/muile-binary (error "`mm/muile-binary' is not defined")) (unless mu4e-muile-binary (error "`mu4e-muile-binary' is not defined"))
(unless (or (file-executable-p mm/muile-binary) (unless (or (file-executable-p mu4e-muile-binary)
(executable-find mm/muile-binary)) (executable-find mu4e-muile-binary))
(error "%S not found" mm/muile-binary)) (error "%S not found" mu4e-muile-binary))
(unless mm/current-msg (unless mu4e-current-msg
(error "No current message")) (error "No current message"))
(get-buffer-create mm/muile-buffer-name) (get-buffer-create mu4e-muile-buffer-name)
(start-process mm/muile-buffer-name mm/muile-process-name (start-process mu4e-muile-buffer-name mu4e-muile-process-name
mm/muile-binary "--msg" (plist-get mm/current-msg :path)) mu4e-muile-binary "--msg" (plist-get mu4e-current-msg :path))
(switch-to-buffer mm/muile-buffer-name) (switch-to-buffer mu4e-muile-buffer-name)
(shell-mode)) (shell-mode))
(provide 'mm-view) (provide 'mu4e-view)

View File

@ -1,4 +1,4 @@
;;; mm.el -- part of mm, the mu mail user agent ;;; mu4e.el -- part of mu4e, the mu mail user agent
;; ;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema ;; Copyright (C) 2011 Dirk-Jan C. Binnema
@ -28,75 +28,75 @@
(eval-when-compile (require 'cl)) (eval-when-compile (require 'cl))
(require 'mm-hdrs) (require 'mu4e-hdrs)
(require 'mm-view) (require 'mu4e-view)
(require 'mm-main) (require 'mu4e-main)
(require 'mm-send) (require 'mu4e-send)
(require 'mm-proc) (require 'mu4e-proc)
(require 'mm-version) ;; auto-generated (require 'mu4e-version) ;; auto-generated
;; mm-version.el is autogenerated, and defines mm/mu-version ;; mu4e-version.el is autogenerated, and defines mu4e-mu-version
(require 'mm-version) (require 'mu4e-version)
;; Customization ;; Customization
(defgroup mm nil (defgroup mu4e nil
"mm - the mu mail client" "mu4e - mu for emacs"
:group 'local) :group 'local)
(defcustom mm/mu-home nil (defcustom mu4e-mu-home nil
"Location of the mu homedir, or nil for the default." "Location of the mu homedir, or nil for the default."
:type 'directory :type 'directory
:group 'mm :group 'mu4e
:safe 'stringp) :safe 'stringp)
(defcustom mm/mu-binary "mu" (defcustom mu4e-mu-binary "mu"
"Name of the mu-binary to use; if it cannot be found in your "Name of the mu-binary to use; if it cannot be found in your
PATH, you can specify the full path." PATH, you can specify the full path."
:type 'file :type 'file
:group 'mm :group 'mu4e
:safe 'stringp) :safe 'stringp)
(defcustom mm/maildir nil (defcustom mu4e-maildir nil
"Your Maildir directory. When `nil', mu will try to find it." "Your Maildir directory. When `nil', mu will try to find it."
:type 'directory :type 'directory
:safe 'stringp :safe 'stringp
:group 'mm) :group 'mu4e)
(defcustom mm/get-mail-command nil (defcustom mu4e-get-mail-command nil
"Shell command to run to retrieve new mail; e.g. 'offlineimap' or "Shell command to run to retrieve new mail; e.g. 'offlineimap' or
'fetchmail'." 'fetchmail'."
:type 'string :type 'string
:group 'mm :group 'mu4e
:safe 'stringp) :safe 'stringp)
(defcustom mm/attachment-dir (expand-file-name "~/") (defcustom mu4e-attachment-dir (expand-file-name "~/")
"Default directory for saving attachments." "Default directory for saving attachments."
:type 'string :type 'string
:group 'mm :group 'mu4e
:safe 'stringp) :safe 'stringp)
(defvar mm/user-mail-address-regexp "$^" (defvar mu4e-user-mail-address-regexp "$^"
"Regular expression matching the user's mail address(es). This is "Regular expression matching the user's mail address(es). This is
used to distinguish ourselves from others, e.g. when replying and used to distinguish ourselves from others, e.g. when replying and
in :from-or-to headers. By default, match nothing.") in :from-or-to headers. By default, match nothing.")
(defvar mm/date-format-long "%c" (defvar mu4e-date-format-long "%c"
"Date format to use in the message view, in the format of "Date format to use in the message view, in the format of
`format-time-string'.") `format-time-string'.")
(defvar mm/search-results-limit 500 (defvar mu4e-search-results-limit 500
"Maximum number of search results (or -1 for unlimited). Since "Maximum number of search results (or -1 for unlimited). Since
limiting search results speeds up searches significantly, it's limiting search results speeds up searches significantly, it's
useful to limit this. Note, to ignore the limit, use a prefix useful to limit this. Note, to ignore the limit, use a prefix
argument (C-u) before invoking the search.") argument (C-u) before invoking the search.")
(defvar mm/debug nil (defvar mu4e-debug nil
"When set to non-nil, log debug information to the *mm-log* buffer.") "When set to non-nil, log debug information to the *mu4e-log* buffer.")
(defvar mm/bookmarks (defvar mu4e-bookmarks
'( ("flag:unread AND NOT flag:trashed" "Unread messages" ?u) '( ("flag:unread AND NOT flag:trashed" "Unread messages" ?u)
("date:today..now" "Today's messages" ?t) ("date:today..now" "Today's messages" ?t)
("date:7d..now" "Last 7 days" ?w) ("date:7d..now" "Last 7 days" ?w)
@ -110,56 +110,56 @@ show up in the UI), and KEY is a shortcut key for the query.")
;; Folders ;; Folders
(defgroup mm/folders nil (defgroup mu4e-folders nil
"Special folders for mm." "Special folders for mm."
:group 'mm) :group 'mu4e)
;; (defcustom mm/inbox-folder nil ;; (defcustom mu4e-inbox-folder nil
;; "Your Inbox folder, relative to `mm/maildir', e.g. \"/Inbox\"." ;; "Your Inbox folder, relative to `mu4e-maildir', e.g. \"/Inbox\"."
;; :type 'string ;; :type 'string
;; :safe 'stringp ;; :safe 'stringp
;; :group 'mm/folders) ;; :group 'mu4e-folders)
(defcustom mm/sent-folder nil (defcustom mu4e-sent-folder nil
"Your folder for sent messages, relative to `mm/maildir', "Your folder for sent messages, relative to `mu4e-maildir',
e.g. \"/Sent Items\"." e.g. \"/Sent Items\"."
:type 'string :type 'string
:safe 'stringp :safe 'stringp
:group 'mm/folders) :group 'mu4e-folders)
(defcustom mm/draft-folder nil (defcustom mu4e-draft-folder nil
"Your folder for draft messages, relative to `mm/maildir', "Your folder for draft messages, relative to `mu4e-maildir',
e.g. \"/drafts\"" e.g. \"/drafts\""
:type 'string :type 'string
:safe 'stringp :safe 'stringp
:group 'mm/folders) :group 'mu4e-folders)
(defcustom mm/trash-folder nil (defcustom mu4e-trash-folder nil
"Your folder for trashed messages, relative to `mm/maildir', "Your folder for trashed messages, relative to `mu4e-maildir',
e.g. \"/trash\"." e.g. \"/trash\"."
:type 'string :type 'string
:safe 'stringp :safe 'stringp
:group 'mm/folders) :group 'mu4e-folders)
(defcustom mm/maildir-shortcuts nil (defcustom mu4e-maildir-shortcuts nil
"A list of maildir shortcuts to enable quickly going to the "A list of maildir shortcuts to enable quickly going to the
particular for, or quickly moving messages towards them (i.e., particular for, or quickly moving messages towards them (i.e.,
archiving or refiling). The list contains elements of the form archiving or refiling). The list contains elements of the form
(maildir . shortcut), where MAILDIR is a maildir (such as (maildir . shortcut), where MAILDIR is a maildir (such as
\"/archive/\"), and shortcut a single shortcut character. With \"/archive/\"), and shortcut a single shortcut character. With
this, in the header buffer and view buffer you can execute this, in the header buffer and view buffer you can execute
`mm/mark-for-move-quick' (or 'm', by default) or `mu4e-mark-for-move-quick' (or 'm', by default) or
`mm/jump-to-maildir-quick' (or 'j', by default), followed by the `mu4e-jump-to-maildir-quick' (or 'j', by default), followed by the
designated shortcut character for the maildir.") designated shortcut character for the maildir.")
;; the headers view ;; the headers view
(defgroup mm/headers nil (defgroup mu4e-headers nil
"Settings for the headers view." "Settings for the headers view."
:group 'mm) :group 'mu4e)
(defcustom mm/headers-fields (defcustom mu4e-headers-fields
'( (:date . 25) '( (:date . 25)
(:flags . 6) (:flags . 6)
(:from . 22) (:from . 22)
@ -167,152 +167,152 @@ designated shortcut character for the maildir.")
"A list of header fields to show in the headers buffer, and their "A list of header fields to show in the headers buffer, and their
respective widths in characters. A width of `nil' means respective widths in characters. A width of `nil' means
'unrestricted', and this is best reserved fo the rightmost (last) 'unrestricted', and this is best reserved fo the rightmost (last)
field. For the complete list of available headers, see `mm/header-names'" field. For the complete list of available headers, see `mu4e-header-names'"
:type (list 'symbol) :type (list 'symbol)
:group 'mm/headers) :group 'mu4e-headers)
(defcustom mm/headers-date-format "%x %X" (defcustom mu4e-headers-date-format "%x %X"
"Date format to use in the headers view, in the format of "Date format to use in the headers view, in the format of
`format-time-string'." `format-time-string'."
:type 'string :type 'string
:group 'mm/headers) :group 'mu4e-headers)
;; the message view ;; the message view
(defgroup mm/view nil (defgroup mu4e-view nil
"Settings for the message view." "Settings for the message view."
:group 'mm) :group 'mu4e)
(defcustom mm/view-fields (defcustom mu4e-view-fields
'(:from :to :cc :subject :flags :date :maildir :path :attachments) '(:from :to :cc :subject :flags :date :maildir :path :attachments)
"Header fields to display in the message view buffer. For the "Header fields to display in the message view buffer. For the
complete list of available headers, see `mm/header-names'." complete list of available headers, see `mu4e-header-names'."
:type (list 'symbol) :type (list 'symbol)
:group 'mm/view) :group 'mu4e-view)
(defcustom mm/view-date-format "%c" (defcustom mu4e-view-date-format "%c"
"Date format to use in the message view, in the format of "Date format to use in the message view, in the format of
`format-time-string'." `format-time-string'."
:type 'string :type 'string
:group 'mm/headers) :group 'mu4e-headers)
;; Composing / Sending messages ;; Composing / Sending messages
(defgroup mm/compose nil (defgroup mu4e-compose nil
"Customizations for composing/sending messages." "Customizations for composing/sending messages."
:group 'mm) :group 'mu4e)
(defcustom mm/msg-citation-prefix "> " (defcustom mu4e-msg-citation-prefix "> "
"String to prefix cited message parts with." "String to prefix cited message parts with."
:type 'string :type 'string
:group 'mm/compose) :group 'mu4e-compose)
(defcustom mm/msg-reply-prefix "Re: " (defcustom mu4e-msg-reply-prefix "Re: "
"String to prefix the subject of replied messages with." "String to prefix the subject of replied messages with."
:type 'string :type 'string
:group 'mm/compose) :group 'mu4e-compose)
(defcustom mm/msg-forward-prefix "Fwd: " (defcustom mu4e-msg-forward-prefix "Fwd: "
"String to prefix the subject of forwarded messages with." "String to prefix the subject of forwarded messages with."
:type 'string :type 'string
:group 'mm/compose) :group 'mu4e-compose)
(defcustom mm/user-agent nil (defcustom mu4e-user-agent nil
"The user-agent string; leave at `nil' for the default." "The user-agent string; leave at `nil' for the default."
:type 'string :type 'string
:group 'mm/compose) :group 'mu4e-compose)
;; Faces ;; Faces
(defgroup mm/faces nil (defgroup mu4e-faces nil
"Faces used in by mm." "Faces used in by mm."
:group 'mm :group 'mu4e
:group 'faces) :group 'faces)
(defface mm/unread-face (defface mu4e-unread-face
'((t :inherit font-lock-keyword-face :bold t)) '((t :inherit font-lock-keyword-face :bold t))
"Face for an unread mm message header." "Face for an unread mm message header."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/moved-face (defface mu4e-moved-face
'((t :inherit font-lock-comment-face :slant italic)) '((t :inherit font-lock-comment-face :slant italic))
"Face for an mm message header that has been moved to some "Face for an mm message header that has been moved to some
folder (it's still visible in the search results, since we cannot folder (it's still visible in the search results, since we cannot
be sure it no longer matches)." be sure it no longer matches)."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/trashed-face (defface mu4e-trashed-face
'((t :inherit font-lock-comment-face :strike-through t)) '((t :inherit font-lock-comment-face :strike-through t))
"Face for an message header in the trash folder." "Face for an message header in the trash folder."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/draft-face (defface mu4e-draft-face
'((t :inherit font-lock-string-face)) '((t :inherit font-lock-string-face))
"Face for a draft message header (i.e., a message with the draft "Face for a draft message header (i.e., a message with the draft
flag set)." flag set)."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/header-face (defface mu4e-header-face
'((t :inherit default)) '((t :inherit default))
"Face for an mm header without any special flags." "Face for an mm header without any special flags."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/title-face (defface mu4e-title-face
'((t :inherit font-lock-type-face)) '((t :inherit font-lock-type-face))
"Face for an mm title." "Face for an mm title."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/view-header-key-face (defface mu4e-view-header-key-face
'((t :inherit font-lock-builtin-face)) '((t :inherit font-lock-builtin-face))
"Face for the header title (such as \"Subject\" in the message view)." "Face for the header title (such as \"Subject\" in the message view)."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/view-header-value-face (defface mu4e-view-header-value-face
'((t :inherit font-lock-doc-face)) '((t :inherit font-lock-doc-face))
"Face for the header value (such as \"Re: Hello!\" in the message view)." "Face for the header value (such as \"Re: Hello!\" in the message view)."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/view-link-face (defface mu4e-view-link-face
'((t :inherit font-lock-type-face :underline t)) '((t :inherit font-lock-type-face :underline t))
"Face for showing URLs and attachments in the message view." "Face for showing URLs and attachments in the message view."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/highlight-face (defface mu4e-highlight-face
'((t :inherit font-lock-pseudo-keyword-face :bold t)) '((t :inherit font-lock-pseudo-keyword-face :bold t))
"Face for highlighting things." "Face for highlighting things."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/view-url-number-face (defface mu4e-view-url-number-face
'((t :inherit font-lock-reference-face :bold t)) '((t :inherit font-lock-reference-face :bold t))
"Face for the number tags for URLs." "Face for the number tags for URLs."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/view-attach-number-face (defface mu4e-view-attach-number-face
'((t :inherit font-lock-variable-name-face :bold t)) '((t :inherit font-lock-variable-name-face :bold t))
"Face for the number tags for attachments." "Face for the number tags for attachments."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/view-footer-face (defface mu4e-view-footer-face
'((t :inherit font-lock-comment-face)) '((t :inherit font-lock-comment-face))
"Face for message footers (signatures)." "Face for message footers (signatures)."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/hdrs-marks-face (defface mu4e-hdrs-marks-face
'((t :inherit font-lock-preprocessor-face)) '((t :inherit font-lock-preprocessor-face))
"Face for the mark in the headers list." "Face for the mark in the headers list."
:group 'mm/faces) :group 'mu4e-faces)
(defface mm/system-face (defface mu4e-system-face
'((t :inherit font-lock-comment-face :slant italic)) '((t :inherit font-lock-comment-face :slant italic))
"Face for system message (such as the footers for message "Face for system message (such as the footers for message
headers)." headers)."
:group 'mm/faces) :group 'mu4e-faces)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; internal variables / constants ;; internal variables / constants
(defconst mm/header-names (defconst mu4e-header-names
'( (:attachments . "Attach") '( (:attachments . "Attach")
(:bcc . "Bcc") (:bcc . "Bcc")
(:cc . "Cc") (:cc . "Cc")
@ -332,69 +332,69 @@ in which case it will be equal to `:to'.)")
;; mm startup function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; mm startup function ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mm () (defun mu4e ()
"Start mm. We do this by sending a 'ping' to the mu server "Start mm. We do this by sending a 'ping' to the mu server
process, and start the main view if the 'pong' we receive from the process, and start the main view if the 'pong' we receive from the
server has the expected values." server has the expected values."
(interactive) (interactive)
(if (buffer-live-p mm/main-buffer-name) (if (buffer-live-p mu4e-main-buffer-name)
(switch-to-buffer mm/main-buffer-name) (switch-to-buffer mu4e-main-buffer-name)
(setq mm/proc-pong-func (setq mu4e-proc-pong-func
(lambda (version doccount) (lambda (version doccount)
(unless (string= version mm/mu-version) (unless (string= version mu4e-mu-version)
(error "mu server has version %s, but we need %s" (error "mu server has version %s, but we need %s"
version mm/mu-version)) version mu4e-mu-version))
(mm/main-view))) (mu4e-main-view)))
(mm/proc-ping))) (mu4e-proc-ping)))
(defun mm/ask-maildir (prompt) (defun mu4e-ask-maildir (prompt)
"Ask the user for a shortcut (using PROMPT) as defined in "Ask the user for a shortcut (using PROMPT) as defined in
`mm/maildir-shortcuts', then return the corresponding folder `mu4e-maildir-shortcuts', then return the corresponding folder
name. If the special shortcut 'o' (for _o_ther) is used, or if name. If the special shortcut 'o' (for _o_ther) is used, or if
`mm/maildir-shortcuts is not defined, let user choose from all `mu4e-maildir-shortcuts is not defined, let user choose from all
maildirs under `mm/maildir." maildirs under `mu4e-maildir."
(unless mm/maildir (error "`mm/maildir' is not defined")) (unless mu4e-maildir (error "`mu4e-maildir' is not defined"))
(if (not mm/maildir-shortcuts) (if (not mu4e-maildir-shortcuts)
(ido-completing-read prompt (mm/get-sub-maildirs mm/maildir)) (ido-completing-read prompt (mu4e-get-sub-maildirs mu4e-maildir))
(let* ((mlist (append mm/maildir-shortcuts '(("ther" . ?o)))) (let* ((mlist (append mu4e-maildir-shortcuts '(("ther" . ?o))))
(fnames (fnames
(mapconcat (mapconcat
(lambda (item) (lambda (item)
(concat (concat
"[" "["
(propertize (make-string 1 (cdr item)) 'face 'mm/view-link-face) (propertize (make-string 1 (cdr item)) 'face 'mu4e-view-link-face)
"]" "]"
(car item))) (car item)))
mlist ", ")) mlist ", "))
(kar (read-char (concat prompt fnames)))) (kar (read-char (concat prompt fnames))))
(if (= kar ?o) ;; user chose 'other'? (if (= kar ?o) ;; user chose 'other'?
(ido-completing-read prompt (mm/get-sub-maildirs mm/maildir)) (ido-completing-read prompt (mu4e-get-sub-maildirs mu4e-maildir))
(or (or
(car-safe (find-if (lambda (item) (= kar (cdr item))) mm/maildir-shortcuts)) (car-safe (find-if (lambda (item) (= kar (cdr item))) mu4e-maildir-shortcuts))
(error "Invalid shortcut '%c'" kar)))))) (error "Invalid shortcut '%c'" kar))))))
(defun mm/ask-bookmark (prompt) (defun mu4e-ask-bookmark (prompt)
"Ask the user for a bookmark (using PROMPT) as defined in "Ask the user for a bookmark (using PROMPT) as defined in
`mm/bookmarks', then return the corresponding query." `mu4e-bookmarks', then return the corresponding query."
(unless mm/bookmarks (error "`mm/bookmarks' is not defined")) (unless mu4e-bookmarks (error "`mu4e-bookmarks' is not defined"))
(let* ((bmarks (let* ((bmarks
(mapconcat (mapconcat
(lambda (bm) (lambda (bm)
(let ((query (nth 0 bm)) (title (nth 1 bm)) (key (nth 2 bm))) (let ((query (nth 0 bm)) (title (nth 1 bm)) (key (nth 2 bm)))
(concat (concat
"[" (propertize (make-string 1 key) 'face 'mm/view-link-face) "]" "[" (propertize (make-string 1 key) 'face 'mu4e-view-link-face) "]"
title))) mm/bookmarks ", ")) title))) mu4e-bookmarks ", "))
(kar (read-char (concat prompt bmarks))) (kar (read-char (concat prompt bmarks)))
(chosen-bm (chosen-bm
(find-if (lambda (bm) (= kar (nth 2 bm))) mm/bookmarks))) (find-if (lambda (bm) (= kar (nth 2 bm))) mu4e-bookmarks)))
(unless chosen-bm (error "Invalid shortcut '%c'" kar)) (unless chosen-bm (error "Invalid shortcut '%c'" kar))
(nth 0 chosen-bm))) (nth 0 chosen-bm)))
(defun mm/new-buffer (bufname) (defun mu4e-new-buffer (bufname)
"Return a new buffer BUFNAME; if such already exists, kill the "Return a new buffer BUFNAME; if such already exists, kill the
old one first." old one first."
(when (get-buffer bufname) (when (get-buffer bufname)
@ -407,19 +407,19 @@ old one first."
;;; converting flags->string and vice-versa ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; converting flags->string and vice-versa ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun mm/flags-to-string (flags) (defun mu4e-flags-to-string (flags)
"Remove duplicates and sort the output of `mm/flags-to-string-raw'." "Remove duplicates and sort the output of `mu4e-flags-to-string-raw'."
(concat (concat
(sort (remove-duplicates (append (mm/flags-to-string-raw flags) nil)) '>))) (sort (remove-duplicates (append (mu4e-flags-to-string-raw flags) nil)) '>)))
(defun mm/flags-to-string-raw (flags) (defun mu4e-flags-to-string-raw (flags)
"Convert a list of flags into a string as seen in Maildir "Convert a list of flags into a string as seen in Maildir
message files; flags are symbols draft, flagged, new, passed, message files; flags are symbols draft, flagged, new, passed,
replied, seen, trashed and the string is the concatenation of the replied, seen, trashed and the string is the concatenation of the
uppercased first letters of these flags, as per [1]. Other flags uppercased first letters of these flags, as per [1]. Other flags
than the ones listed here are ignored. than the ones listed here are ignored.
Also see `mm/flags-to-string'. Also see `mu4e-flags-to-string'.
\[1\]: http://cr.yp.to/proto/maildir.html" \[1\]: http://cr.yp.to/proto/maildir.html"
(when flags (when flags
@ -436,14 +436,14 @@ Also see `mm/flags-to-string'.
('signed ?s) ('signed ?s)
('unread ?u)))) ('unread ?u))))
(concat (and kar (string kar)) (concat (and kar (string kar))
(mm/flags-to-string-raw (cdr flags)))))) (mu4e-flags-to-string-raw (cdr flags))))))
(defun mm/string-to-flags (str) (defun mu4e-string-to-flags (str)
"Remove duplicates from the output of `mm/string-to-flags-1'" "Remove duplicates from the output of `mu4e-string-to-flags-1'"
(remove-duplicates (mm/string-to-flags-1 str))) (remove-duplicates (mu4e-string-to-flags-1 str)))
(defun mm/string-to-flags-1 (str) (defun mu4e-string-to-flags-1 (str)
"Convert a string with message flags as seen in Maildir "Convert a string with message flags as seen in Maildir
messages into a list of flags in; flags are symbols draft, messages into a list of flags in; flags are symbols draft,
flagged, new, passed, replied, seen, trashed and the string is flagged, new, passed, replied, seen, trashed and the string is
@ -462,10 +462,10 @@ Also see `mu/flags-to-string'.
(?S 'seen) (?S 'seen)
(?T 'trashed)))) (?T 'trashed))))
(append (when flag (list flag)) (append (when flag (list flag))
(mm/string-to-flags-1 (substring str 1)))))) (mu4e-string-to-flags-1 (substring str 1))))))
(defun mm/display-size (size) (defun mu4e-display-size (size)
"Get a string representation of SIZE (in bytes)." "Get a string representation of SIZE (in bytes)."
(cond (cond
((>= size 1000000) (format "%2.1fM" (/ size 1000000.0))) ((>= size 1000000) (format "%2.1fM" (/ size 1000000.0)))
@ -476,4 +476,4 @@ Also see `mu/flags-to-string'.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(provide 'mm) (provide 'mu4e)