* add support for org-mode links to messages/queries

- org-mu4e.el: add "mu4e:"-link type and handlers to org-mode
  - Makefile.am: add org-mu4e.el to package
  - mu4e-hdrs.el: register handler functions for server data *outside* header
    mode, so they can be used independently (and we can link to messages even
    when mu4e is not active already)
  - mu4e-view.el, mu-server.1, mu-proc.el, mu-cmd-server.c: support viewing
    messages by msgid (rather than only by docid); document it
This commit is contained in:
djcb 2012-01-06 12:31:28 +02:00
parent e4d5d6de8a
commit 4dbb05f33c
7 changed files with 143 additions and 72 deletions

View File

@ -1,4 +1,4 @@
## Copyright (C) 2008-2011 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
## Copyright (C) 2008-2012 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
@ -35,6 +35,7 @@ elisp_DATA= \
mu4e-view.el \
mu4e-proc.el \
mu4e-send.el \
mu4e-version.el
mu4e-version.el \
org-mu4e.el
EXTRA_DIST=$(elisp_DATA)

View File

@ -1,11 +1,9 @@
;; mu4e-hdrs.el -- part of mm, the mu mail user agent
;; mu4e-hdrs.el -- part of mu4e, the mu mail user agent
;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema
;; Copyright (C) 2011-2012 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Keywords: email
;; Version: 0.0
;; This file is not part of GNU Emacs.
;;
@ -28,8 +26,6 @@
;; descriptions of emails, aka 'headers' (not to be confused with headers like
;; 'To:' or 'Subject:')
;; mm
;; Code:
(eval-when-compile (require 'cl))
@ -39,7 +35,6 @@
;;;; internal variables/constants ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defvar mu4e-last-expr nil
"*internal* The most recent search expression.")
(defconst mu4e-hdrs-buffer-name "*mu4e-headers*"
"*internal* Name of the buffer for message headers.")
@ -322,6 +317,15 @@ after the end of the search results."
(fset 'mu4e-hdrs-mode-map mu4e-hdrs-mode-map)
;; we register our handler functions for the mu4e-proc (mu server) output
(setq mu4e-proc-error-func 'mu4e-hdrs-error-handler)
(setq mu4e-proc-update-func 'mu4e-hdrs-update-handler)
(setq mu4e-proc-header-func 'mu4e-hdrs-header-handler)
(setq mu4e-proc-found-func 'mu4e-hdrs-found-handler)
(setq mu4e-proc-view-func 'mu4e-hdrs-view-handler)
(setq mu4e-proc-remove-func 'mu4e-hdrs-remove-handler)
;; this last one is defined in mu4e-send.el
(setq mu4e-proc-compose-func 'mu4e-send-compose-handler)
(defun mu4e-hdrs-mode ()
"Major mode for displaying mua search results."
@ -336,16 +340,6 @@ after the end of the search results."
(make-local-variable 'mu4e-msg-map)
(make-local-variable 'mu4e-thread-info-map)
;; we register our handler functions for the mu4e-proc (mu server) output
(setq mu4e-proc-error-func 'mu4e-hdrs-error-handler)
(setq mu4e-proc-update-func 'mu4e-hdrs-update-handler)
(setq mu4e-proc-header-func 'mu4e-hdrs-header-handler)
(setq mu4e-proc-found-func 'mu4e-hdrs-found-handler)
(setq mu4e-proc-view-func 'mu4e-hdrs-view-handler)
(setq mu4e-proc-remove-func 'mu4e-hdrs-remove-handler)
;; this last one is defined in mu4e-send.el
(setq mu4e-proc-compose-func 'mu4e-send-compose-handler)
(setq
mu4e-marks-map (make-hash-table :size 16 :rehash-size 2)
mu4e-msg-map (make-hash-table :size 1024 :rehash-size 2 :weakness nil)
@ -356,7 +350,7 @@ after the end of the search results."
buffer-undo-list t ;; don't record undo information
buffer-read-only t
overwrite-mode 'overwrite-mode-binary)
(setq header-line-format
(cons
(make-string (floor (fringe-columns 'left t)) ?\s)
@ -583,6 +577,7 @@ work well."
(unless docid (error "No message at point."))
(mu4e-proc-view-msg docid)))
(defun mu4e-hdrs-compose (compose-type)
"Compose either a reply/forward based on the message at point. or
start editing it. COMPOSE-TYPE is either `reply', `forward' or
@ -619,12 +614,10 @@ start editing it. COMPOSE-TYPE is either `reply', `forward' or
(defun mu4e-ignore-marks ()
"If there are still marks in the header list, warn the user."
(if mu4e-marks-map
(let*
((num
(hash-table-count mu4e-marks-map))
(unmark (or (= 0 num)
(y-or-n-p
(format "Sure you want to unmark %d message(s)?" num)))))
(let* ((num (hash-table-count mu4e-marks-map))
(unmark (or (= 0 num)
(y-or-n-p
(format "Sure you want to unmark %d message(s)?" num)))))
(message nil)
unmark))
t)

View File

@ -1,11 +1,9 @@
;;; mu4e-proc.el -- part of mm, the mu mail user agent
;;; mu4e-proc.el -- part of mu4e, the mu mail user agent
;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema
;; Copyright (C) 2011-2012 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Keywords: email
;; Version: 0.0
;; This file is not part of GNU Emacs.
;;
@ -418,10 +416,12 @@ set to e.g. '/drafts'; if this works, we will receive (:info :path
response."
(mu4e-proc-send-command "ping"))
(defun mu4e-proc-view-msg (docid)
"Get one particular message based on its DOCID. The result will
(defun mu4e-proc-view-msg (docid-or-msgid)
"Get one particular message based on its DOCID-OR-MSGID. The result will
be delivered to the function registered as `mu4e-proc-message-func'."
(mu4e-proc-send-command "view %d" docid))
(if (stringp docid-or-msgid)
(mu4e-proc-send-command "view %s" docid-or-msgid)
(mu4e-proc-send-command "view %d" docid-or-msgid)))
(defun mu4e-proc-compose (compose-type docid)
"Start composing a message with DOCID and COMPOSE-TYPE (a symbol,
@ -452,5 +452,6 @@ and update the database afterwards."
(with-current-buffer buf
(kill-buffer-and-window))))
(provide 'mu4e-proc)
;; End of mu4e-proc.el

View File

@ -1,11 +1,9 @@
;; mu4e-view.el -- part of mu4e, the mu mail user agent
;;
;; Copyright (C) 2011 Dirk-Jan C. Binnema
;; Copyright (C) 2011-2012 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Keywords: email
;; Version: 0.0
;; This file is not part of GNU Emacs.
;;
@ -49,6 +47,12 @@
(defvar mu4e-current-msg nil
"*internal* The plist describing the current message.")
(defun mu4e-view-message-with-msgid (msgid)
"View message with MSGID. This is meant for external programs
wanting to show specific messages - for example, `mu4e-org'."
(mu4e-proc-view-msg msgid))
(defun mu4e-view (msg hdrsbuf &optional update)
"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
@ -118,7 +122,7 @@ marking if it still had that."
(mu4e-mark-footer)
(mu4e-make-urls-clickable)
(unless update
(mu4e-view-mark-as-read-maybe)))))
@ -387,7 +391,7 @@ Seen; if the message is not New/Unread, do nothing."
(lexical-let ((url url))
(lambda ()
(interactive)
(browse-url url))))
(browse-url url))))
@ -411,7 +415,7 @@ number them so they can be opened using `mu4e-view-go-to-url'."
(replace-match (concat url
(propertize (format "[%d]" num)
'face 'mu4e-view-url-number-face))))))))
;; raw mode ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -506,37 +510,34 @@ number them so they can be opened using `mu4e-view-go-to-url'."
;; functions for org-contacts
(defun mu4e-org-contacts-from (name-or-email)
"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
field is not found, \"\" is returned. Use this with org-contact
with a template like:
(defun mu4e-view-snarf-from (name-or-email)
"Get the From:-data for the current message; NAME-OR-EMAIL should
be a symbol 'name or 'email to get the corresponding field. If the
field is not found, \"\" is returned.
You can use this with e.g. org-contact with a template like:
(\"c\" \"Contacts\" entry (file \"~/Org/contacts.org\")
\"* %(mu4e-org-contacts-from 'name)
\"* %(mu4e-view-snarf-from 'name)
:PROPERTIES:
:EMAIL: %(mu4e-org-contacts-from 'email)
:EMAIL: %(mu4e-view-snarf-from 'email)
:END:\")))
See the `org-contacts' documentation for more details."
(with-current-buffer mu4e-view-buffer-name ;; hackish...
(unless (eq major-mode 'mu4e-view-mode)
(error "Not in mu4e-view mode."))
(unless mu4e-current-msg
(error "No current message."))
(let ((from (car-safe (plist-get mu4e-current-msg :from))))
(cond
((not from) "") ;; nothing found
((eq name-or-email 'name)
(or (car-safe from) ""))
((eq name-or-email 'email)
(or (cdr-safe from) ""))
(t (error "Not supported: %S" name-or-email))))))
(unless (eq major-mode 'mu4e-view-mode)
(error "Not in mu4e-view mode."))
(unless mu4e-current-msg
(error "No current message."))
(let ((from (car-safe (plist-get mu4e-current-msg :from))))
(cond
((not from) "") ;; nothing found
((eq name-or-email 'name)
(or (car-safe from) ""))
((eq name-or-email 'email)
(or (cdr-safe from) ""))
(t (error "Not supported: %S" name-or-email)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Interactive functions

77
emacs/org-mu4e.el Normal file
View File

@ -0,0 +1,77 @@
;;; org-mu4e -- Support for links to mu4e messages/queries from within org-mode
;;
;; Copyright (C) 2012 Dirk-Jan C. Binnema
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
;; Keywords: outlines, hypermedia, calendar, mail
;; Version: 0.0
;; This file is not part of GNU Emacs.
;;
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'org)
(eval-when-compile (require 'cl))
(eval-when-compile (require 'mu4e))
(defun org-mu4e-store-link ()
"Store a link to a mu4e query or message."
(cond
;; storing links to queries
((eq major-mode 'mu4e-hdrs-mode)
(let* ((query mu4e-last-expr)
desc link)
(org-store-link-props :type "mu4e" :query query)
(setq
desc (org-make-link "mu4e:query:" query)
link desc)
(org-add-link-props :link link :description desc)
link))
;; storing links to messages
((eq major-mode 'mu4e-view-mode)
(let* ((msg mu4e-current-msg)
(msgid (or (plist-get msg :message-id) "<none>"))
(subject (or (plist-get msg :subject) "No subject"))
link)
(org-store-link-props :type "mu4e" :link link
:message-id msgid :subject subject)
(setq link (org-make-link "mu4e:msgid:" msgid))
(org-add-link-props :link link :description subject)
link))))
(org-add-link-type "mu4e" 'org-mu4e-open)
(add-hook 'org-store-link-functions 'org-mu4e-store-link)
(defun org-mu4e-open (path)
"Open the mu4e message (for paths starting with 'msgid:') or run
the query (for paths starting with 'query:')."
(require 'mu4e)
(cond
((string-match "^msgid:\\(.+\\)" path)
(mu4e-view-message-with-msgid (match-string 1 path)))
((string-match "^query:\\(.+\\)" path)
(mu4e-search (match-string 1 path)))
(t (message "mu4e: unrecognized link type '%s'" path))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(provide 'org-mu4e)
;;; org-mu4e.el ends here

View File

@ -1,8 +1,8 @@
.TH MU-SERVER 1 "December 2011" "User Manuals"
.TH MU-SERVER 1 "January 2012" "User Manuals"
.SH NAME
mu server \- the mu backend for the mm e-mail cleint
mu server \- the mu backend for the mu4e e-mail cleint
.SH DESCRIPTION
@ -131,7 +131,7 @@ Using the \fBview\fR command, we can all information (including the body) of a
particular e-mail message.
.nf
-> view <docid>
-> view <docid-or-msgid>
<- (:view <s-exp>)
.fi

View File

@ -1,6 +1,6 @@
/* -*-mode: c; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-*/
/*
** Copyright (C) 2010-2011 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
** Copyright (C) 2011-2012 Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
@ -441,8 +441,6 @@ get_docid_from_msgid (MuQuery *query, const char *str, GError **err)
}
/* the string contains either a number (docid) or a message-id if it
* doesn't look like a number, and the query param is non-nil, try to
* locale the message with message-id in the database, and return its
@ -720,15 +718,15 @@ cmd_open (MuStore *store, GSList *args, GError **err)
static MuError
cmd_view (MuStore *store, GSList *args, GError **err)
cmd_view (MuStore *store, MuQuery *query, GSList *args, GError **err)
{
MuMsg *msg;
unsigned docid;
char *sexp;
return_if_fail_param_num (args, 1, 1, "view <docid>");
return_if_fail_param_num (args, 1, 1, "view <docid>|<msgid>");
docid = get_docid (NULL, (const char*)args->data, err);
docid = get_docid (query, (const char*)args->data, err);
if (docid == MU_STORE_INVALID_DOCID)
return server_error (err, MU_ERROR_IN_PARAMETERS,
"invalid docid");
@ -901,7 +899,7 @@ handle_command (Cmd cmd, MuStore *store, MuQuery *query, GSList *args,
case CMD_REMOVE: rv = cmd_remove (store, args, err); break;
case CMD_SAVE: rv = cmd_save (store, args, err); break;
case CMD_PING: rv = cmd_ping (store, args, err); break;
case CMD_VIEW: rv = cmd_view (store, args, err); break;
case CMD_VIEW: rv = cmd_view (store, query, args, err); break;
case CMD_IGNORE: return TRUE;
default: