You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
241 lines
9.0 KiB
EmacsLisp
241 lines
9.0 KiB
EmacsLisp
10 years ago
|
;;; mu4e-multi.el --- Multiple account facilities for mu4e
|
||
|
|
||
|
;; Copyright (C) 2013 Free Software Foundation, Inc.
|
||
|
|
||
|
;; Authors: Fabián Ezequiel Gallina <fgallina@gnu.org>
|
||
|
|
||
|
;; This file is NOT part of mu4e.
|
||
|
|
||
|
;; mu4e-multi.el 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, or
|
||
|
;; (at your option) any later version.
|
||
|
|
||
|
;; mu4e-multi.el 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 mu4e-multi.el; see the file COPYING. If not,
|
||
|
;; write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
|
||
|
;; Floor, Boston, MA 02110-1301, USA.
|
||
|
|
||
|
;;; Commentary:
|
||
|
|
||
|
;; See the README.md file for details on how to install and use this
|
||
|
;; package.
|
||
|
|
||
|
;;; Code:
|
||
|
(require 'cl-lib)
|
||
|
(require 'message)
|
||
|
(require 'mu4e-actions)
|
||
|
(require 'mu4e-headers)
|
||
|
(require 'thingatpt)
|
||
|
|
||
|
|
||
|
(defvar mu4e-multi-last-read-account ""
|
||
|
"Holds the last selected account from minibuffer.
|
||
|
This is just for `mu4e-multi-minibuffer-read-account' to prompt
|
||
|
always the latest used account as default.")
|
||
|
|
||
|
(defvar mu4e-multi-account-alist nil
|
||
|
"Alist containing all information of email accounts.
|
||
|
Here's an example for two accounts:
|
||
|
|
||
|
'((\"account-1\"
|
||
|
(user-mail-address . \"user1@server.com\")
|
||
|
(mu4e-sent-folder . \"/account-1/Sent Mail\")
|
||
|
(mu4e-drafts-folder . \"/account-1/Drafts\")
|
||
|
(mu4e-refile-folder . \"/account-1/Archive\")
|
||
|
(mu4e-trash-folder . \"/account-1/Trash\"))
|
||
|
(\"account-2\"
|
||
|
(user-mail-address . \"user2@server.com\")
|
||
|
(mu4e-sent-folder . \"/account-2/Sent Mail\")
|
||
|
(mu4e-drafts-folder . \"/account-2/Drafts\")
|
||
|
(mu4e-refile-folder . \"/account-2/Archive\")
|
||
|
(mu4e-trash-folder . \"/account-2/Trash\")))
|
||
|
|
||
|
The names \"account-1\" and \"account-2\" are used as identifiers
|
||
|
to access an account's data. IMPORTANT: maildirs must match
|
||
|
their prefix with the identifier given, as in the example
|
||
|
above.")
|
||
|
|
||
|
(defvar mu4e-multi-standard-folders '(mu4e-drafts-folder
|
||
|
mu4e-refile-folder
|
||
|
mu4e-sent-folder
|
||
|
mu4e-trash-folder)
|
||
|
"List of standard mu4e folders.")
|
||
|
|
||
|
(defun mu4e-multi-account-name-list (&optional account-alist)
|
||
|
"Return account names from ACCOUNT-ALIST.
|
||
|
When ACCOUNT-ALIST is nil, the value of
|
||
|
`mu4e-multi-account-alist' is used."
|
||
|
(mapcar #'car (or account-alist mu4e-multi-account-alist)))
|
||
|
|
||
|
(defun mu4e-multi-minibuffer-read-account ()
|
||
|
"Read account name from minibuffer."
|
||
|
(let ((account-list (mu4e-multi-account-name-list)))
|
||
|
(setq
|
||
|
mu4e-multi-last-read-account
|
||
|
(completing-read
|
||
|
(format "Compose with account: (%s) "
|
||
|
(mapconcat
|
||
|
#'(lambda (acc)
|
||
|
(if (string= acc mu4e-multi-last-read-account)
|
||
|
(format "[%s]" acc)
|
||
|
acc))
|
||
|
account-list "/"))
|
||
|
account-list nil t nil nil mu4e-multi-last-read-account))))
|
||
|
|
||
|
(defun mu4e-multi-get-msg-account (msg &optional account)
|
||
|
"Get account from MSG.
|
||
|
If no account can be found from MSG then use ACCOUNT as default."
|
||
|
(let ((maildir (when msg (mu4e-msg-field msg :maildir)))
|
||
|
(account-list (mu4e-multi-account-name-list)))
|
||
|
(cond ((and maildir
|
||
|
(string-match
|
||
|
(concat
|
||
|
"/\\("
|
||
|
(regexp-opt account-list)
|
||
|
"\\)/?")
|
||
|
maildir))
|
||
|
(match-string-no-properties 1 maildir))
|
||
|
((and account (car (member account account-list)))))))
|
||
|
|
||
|
(defun mu4e-multi-set-folder (folder msg)
|
||
|
"Set FOLDER using MSG as detection element."
|
||
|
(let ((varval (assoc
|
||
|
folder
|
||
|
(cdr
|
||
|
(assoc (or (mu4e-multi-get-msg-account msg)
|
||
|
mu4e-multi-last-read-account)
|
||
|
mu4e-multi-account-alist)))))
|
||
|
(if varval
|
||
|
(set (make-local-variable folder) (cdr varval))
|
||
|
(mu4e-error "Cannot set folder %s, account for MSG %s not detected"
|
||
|
folder msg))))
|
||
|
|
||
|
(defmacro mu4e-multi-make-set-folder-fn (folder)
|
||
|
"Make a setter for FOLDER.
|
||
|
This is just a wrapper over `mu4e-multi-set-folder' and can be
|
||
|
used to set you mu4e-*-folder vars. Example:
|
||
|
|
||
|
(setq mu4e-sent-folder
|
||
|
(mu4e-multi-make-folder-fn mu4e-sent-folder))
|
||
|
|
||
|
Normally used to set `mu4e-sent-folder', `mu4e-drafts-folder',
|
||
|
`mu4e-trash-folder' and `mu4e-refile-folder'."
|
||
|
`(apply-partially #'mu4e-multi-set-folder ',folder))
|
||
|
|
||
|
(defmacro mu4e-multi-make-mark-for-command (folder)
|
||
|
"Generate command to mark current message to move to FOLDER.
|
||
|
The command is named after the prefix \"mu4e-multi-mark-for-\"
|
||
|
and what's in between of \"mu4e-\" and \"-folder\" parts of the
|
||
|
FOLDER symbol. Here's an example on how to use this:
|
||
|
|
||
|
(mu4e-multi-make-mark-for-command mu4e-hold-folder)
|
||
|
(define-key 'mu4e-headers-mode-map \"h\" 'mu4e-multi-mark-for-hold)
|
||
|
|
||
|
OR:
|
||
|
|
||
|
(define-key 'mu4e-headers-mode-map \"h\"
|
||
|
(mu4e-multi-make-mark-for-command mu4e-hold-folder))"
|
||
|
(let ((name (mapconcat
|
||
|
'identity
|
||
|
(butlast
|
||
|
(cdr (split-string
|
||
|
(symbol-name folder) "-")))
|
||
|
"-")))
|
||
|
`(defun ,(intern (format "mu4e-multi-mark-for-%s" name)) ()
|
||
|
,(format "Mark message to be moved to `%s'." ',folder)
|
||
|
(interactive)
|
||
|
(mu4e-mark-set
|
||
|
'move
|
||
|
(cdr (assoc ',folder
|
||
|
(cdr (assoc (mu4e-multi-get-msg-account
|
||
|
(mu4e-message-at-point))
|
||
|
mu4e-multi-account-alist)))))
|
||
|
(mu4e-headers-next))))
|
||
|
|
||
|
(defun mu4e-multi-compose-set-account (&optional account)
|
||
|
"Set the ACCOUNT for composing.
|
||
|
With Optional Argument ACCOUNT, set all variables for that given
|
||
|
identifier, else it tries to retrieve the message in context and
|
||
|
detect ACCOUNT from it."
|
||
|
(interactive)
|
||
|
(let* ((msg (or mu4e-compose-parent-message
|
||
|
(ignore-errors (mu4e-message-at-point))))
|
||
|
(account (or account
|
||
|
(mu4e-multi-get-msg-account msg)))
|
||
|
(account-vars (cdr (assoc account mu4e-multi-account-alist))))
|
||
|
(when account-vars
|
||
|
(mapc #'(lambda (var)
|
||
|
(set (make-local-variable (car var)) (cdr var)))
|
||
|
account-vars))
|
||
|
(when (memq major-mode '(mu4e-compose-mode message-mode))
|
||
|
(message-remove-header "from")
|
||
|
(message-add-header (format "From: %s\n" (message-make-from)))
|
||
|
(message "Using account %s" account))))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun mu4e-multi-compose-new ()
|
||
|
"Start writing a new message.
|
||
|
This is a simple wrapper over `mu4e-compose-new' that asks for an
|
||
|
account to be used to compose the new message."
|
||
|
(interactive)
|
||
|
(let ((account (mu4e-multi-minibuffer-read-account)))
|
||
|
(mu4e-compose-new)
|
||
|
(mu4e-multi-compose-set-account account)))
|
||
|
|
||
|
(defun mu4e-multi-smtpmail-set-msmtp-account ()
|
||
|
"Set the account for msmtp.
|
||
|
This function is intended to added in the
|
||
|
`message-send-mail-hook'. Searches for the account in the
|
||
|
`mu4e-multi-account-alist' variable by matching the email given
|
||
|
in the \"from\" field. Note that all msmtp accounts should
|
||
|
defined in the ~/.msmtprc file and names should be matching the
|
||
|
keys of the `mu4e-multi-account-alist'."
|
||
|
(setq message-sendmail-extra-arguments
|
||
|
(list
|
||
|
"-a"
|
||
|
(catch 'exit
|
||
|
(let* ((from (message-fetch-field "from"))
|
||
|
(email (and from
|
||
|
(string-match thing-at-point-email-regexp from)
|
||
|
(match-string-no-properties 0 from))))
|
||
|
(if email
|
||
|
(cl-dolist (alist mu4e-multi-account-alist)
|
||
|
(when (string= email (cdr (assoc 'user-mail-address (cdr alist))))
|
||
|
(throw 'exit (car alist))))
|
||
|
(catch 'exit (mu4e-multi-minibuffer-read-account))))))))
|
||
|
|
||
|
(defun mu4e-multi-enable ()
|
||
|
"Enable mu4e multiple account setup."
|
||
|
(setq mu4e-sent-folder (mu4e-multi-make-set-folder-fn mu4e-sent-folder)
|
||
|
mu4e-drafts-folder (mu4e-multi-make-set-folder-fn mu4e-drafts-folder)
|
||
|
mu4e-trash-folder (mu4e-multi-make-set-folder-fn mu4e-trash-folder)
|
||
|
mu4e-refile-folder (mu4e-multi-make-set-folder-fn mu4e-refile-folder))
|
||
|
(add-hook 'message-mode-hook 'mu4e-multi-compose-set-account))
|
||
|
|
||
|
(defun mu4e-multi-disable ()
|
||
|
"Disable mu4e multiple account setup."
|
||
|
(cl-dolist (variable mu4e-multi-standard-folders)
|
||
|
(let* ((sv (get variable 'standard-value))
|
||
|
(origval (and (consp sv)
|
||
|
(condition-case nil
|
||
|
(eval (car sv))
|
||
|
(error :help-eval-error)))))
|
||
|
(when (not (equal (symbol-value variable) origval))
|
||
|
(set variable origval))))
|
||
|
(remove-hook 'message-mode-hook 'mu4e-multi-compose-set-account))
|
||
|
|
||
|
(provide 'mu4e-multi)
|
||
|
|
||
|
;; Local Variables:
|
||
|
;; coding: utf-8
|
||
|
;; indent-tabs-mode: nil
|
||
|
;; End:
|
||
|
|
||
|
;;; mu4e-multi.el ends here
|