123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- ;;; Code:
- (require 'mu4e)
- (require 'mu4e-contrib)
- (require 'mu4e-icalendar)
- (require 'message-view-patch)
- (require 'smtpmail-async)
- (require 'buffer-defuns)
- (require 'mml-sec)
- (require 'shr-color)
- ;; Custom vars
- (defcustom distopico:mu4e-inbox-update-modeline-interval 300
- "Inbox update interval."
- :type 'integer
- :group 'mu4e)
- (defcustom distopico:message-attachment-reminder
- "Are you sure you want to send this message without any attachment? "
- "Message to display and ask when there is a missing attachment.
- The default question asked when trying to send a message
- if contain `distopico:message-attachment-intent-re' without an
- actual attachment."
- :type 'string
- :group 'mu4e)
- (defcustom distopico:message-attachment-intent-re
- (regexp-opt '("I attach"
- "I have attached"
- "I've attached"
- "I have included"
- "I've included"
- "see the attached"
- "see the attachment"
- "attached file"
- "archivo incluido"
- "adjunto archivo"
- "ver adjunto"
- "adjunto va"
- "archivo adjunto"))
- "Regex of words that if are found will show warning and prevent send the message.
- If any of those are found in the message and if there is no attachment - should
- launch the no-attachment warning message defined in
- `distopico:message-attachment-reminder'."
- :type 'list
- :group 'mu4e)
- (defvar distopico:mu4e-get-mail-command
- (concat "flock -E 0 /tmp/offlineimap.lock python "
- (in-emacs-d "scripts/offlineimap-notify/offlineimap_notify.py"))
- "The default mu4e command to get emails.")
- (defvar distopico:mu4e-new-mail nil
- "Boolean to represent if there is new mail.")
- (defvar distopico:mu4e-mode-line-format nil
- "String to display in the mode line.")
- (defvar distopico:mu4e-update-timer nil
- "Interval timer object.")
- (defvar distopico:mu4e-contexts)
- (defvar distopico:mu4e-account-alist)
- ;; General mu4e config
- (setq mu4e-mu-home (concat (getenv "HOME") "/.mu")
- mu4e-get-mail-command distopico:mu4e-get-mail-command
- mu4e-confirm-quit nil
- mu4e-compose-keep-self-cc nil
- mu4e-compose-complete-addresses t
- mu4e-compose-dont-reply-to-self t
- ;; mu4e-change-filenames-when-moving - enable after migrate to mbsync
- mu4e-hide-index-messages t
- mu4e-headers-auto-update t
- mu4e-notification-support t
- mu4e-use-fancy-chars t
- mu4e-split-view 'horizontal
- mu4e-update-interval 300
- mu4e-context-policy 'pick-first
- mu4e-headers-visible-lines 20
- mu4e-headers-leave-behavior 'ask
- mu4e-headers-fields '((:human-date . 12)
- (:flags . 10)
- (:mailing-list . 10)
- (:from . 22)
- (:subject . nil)))
- ;; Set mu4e as default email emacs email composing client
- (setq mail-user-agent #'mu4e-user-agent
- message-mail-user-agent t)
- ;; Compose mail with gnus.
- (setq read-mail-command 'gnus
- mail-user-agent 'gnus-user-agent);;gnus-user-agent mu4e-user-agent
- ;; Bookmarks and shortcuts
- (setq mu4e-maildir-shortcuts
- '(("/1-Distopico/INBOX" . ?d)
- ("/2-vXcamiloXv/INBOX" . ?c)
- ("/3-AccionVisual/INBOX" . ?a)
- ("/4-RadioLiberacion/INBOX" . ?r)
- ("/5-TienditaVegan/INBOX" . ?t)))
- (setq mu4e-bookmarks
- '(("maildir:/\/*\/INBOX/" "All Inbox" ?i)
- ("maildir:/1-Distopico/INBOX" "[Distopico] All" ?D)
- ("flag:unread AND maildir:/1-Distopico/INBOX" "[Distopico] Unread Inbox" ?d)
- ("maildir:/2-vXcamiloXv/INBOX" "[vXcamiloXv] All" ?C)
- ("flag:unread AND maildir:/2-vXcamiloXv/INBOX" "[vXcamiloXv] Unread Inbox" ?c)
- ("flag:unread AND NOT flag:trashed AND NOT maildir:/\/*\/Spam*/ AND NOT maildir:/\/*\/Trash*/" "Unread All Inbox" ?u)
- ("flag:unread" "Unread All" ?U)
- ("date:today..now AND NOT maildir:/\/*\/Spam*/" "Today's messages" ?t)
- ("date:7d..now AND NOT maildir:/\/*\/Spam*/" "Last 7 days" ?w)
- ("maildir:/\/*\/Sent*/" "Sent messages" ?s)
- ("maildir:/\/*\/Trash/ OR maildir:/\/*\/Junk/" "All Trash" ?T)
- ("mime:image/* AND NOT maildir:/\/*\/Spam*/" "Messages with images" ?p)
- ("flag:unread AND maildir:/\/*\/Spam*/" "Unread spam" ?S)))
- ;; Custom marks
- (setq mu4e-headers-draft-mark '("D" . "⚒ ")
- mu4e-headers-flagged-mark '("F" . "✚ ")
- mu4e-headers-new-mark '("N" . "✱ ")
- mu4e-headers-passed-mark '("P" . "❯ ")
- mu4e-headers-replied-mark '("R" . "❮ ")
- mu4e-headers-seen-mark '("S" . "✔ ")
- mu4e-headers-trashed-mark '("T" . "⏚ ")
- mu4e-headers-attach-mark '("a" . "✉ ")
- mu4e-headers-encrypted-mark '("x" . "⚴ ")
- mu4e-headers-signed-mark '("s" . "☡ ")
- mu4e-headers-unread-mark '("u" . "⚐ "))
- ;; Config Messages
- (setq message-kill-buffer-on-exit t
- message-signature-insert-empty-line t
- message-citation-line-function 'message-insert-formatted-citation-line
- ;; Other format: message-citation-line-format "%N @ %Y-%m-%d %H:%M %Z:\n" "On %Y-%m-%d, %f wrote:" "On %Y-%m-%d %a at %H:%M %Z, %f wrote:\n"
- message-citation-line-format "On %Y-%m-%d, %f wrote:\n")
- (when (fboundp 'org-mime-htmlize)
- (add-hook 'message-mode-hook (lambda () (local-set-key "\C-c\M-o" 'org-mime-htmlize))))
- ;; use imagemagick, if available
- (when (fboundp 'imagemagick-register-types)
- (imagemagick-register-types))
- ;;Org config
- (defalias 'org-mail 'org-mu4e-compose-org-mode)
- (setq mu4e-org-contacts-file "~/Documents/org/contacts.org")
- ;; Actions
- (add-to-list 'mu4e-view-actions
- '("View in browser" . mu4e-action-view-in-browser) t)
- (add-to-list 'mu4e-view-actions
- '("add contact org" . distopico:mu4e-action-add-org-contact) t)
- (add-to-list 'mu4e-headers-actions
- '("add contact org" . distopico:mu4e-action-add-org-contact) t)
- ;; Default dir attachment
- (setq mu4e-attachment-dir "~/Downloads")
- ;; Send async
- (setq message-send-mail-function 'smtpmail-send-it) ;; allow: async-smtpmail-send-it or smtpmail-send-it
- ;; Not start in queuing mode
- (setq smtpmail-queue-mail nil
- smtpmail-smtp-user t)
- ;; Config by mu4e Account
- (ignore-errors
- (load (expand-file-name ".conf-private.gpg" "~/") t))
- ;; Default Account
- (setq mu4e-sent-folder "/1-Distopico/Sent"
- mu4e-drafts-folder "/1-Distopico/Drafts"
- mu4e-trash-folder "/1-Distopico/Trash"
- mu4e-refile-folder "/1-Distopico/Archive")
- ;; Sign/Encrypt
- (setq mml-secure-openpgp-encrypt-to-self t
- mml-secure-openpgp-sign-with-sender t)
- ;; Calendar support
- (mu4e-icalendar-setup)
- (gnus-icalendar-org-setup)
- ;; Custom keymap
- (define-key mu4e-main-mode-map "r" 'distopico:mu4e-maildirs-force-update)
- (define-key mu4e-main-mode-map (kbd "q") 'distopico:mu4e-close)
- (define-key mu4e-main-mode-map (kbd "C-q") 'distopico:mu4e-close)
- (define-key mu4e-headers-mode-map (kbd "C-q") 'distopico:mu4e-kill-close)
- (define-key mu4e-headers-mode-map (kbd "C-x k") 'distopico:mu4e-kill-close)
- (define-key mu4e-headers-mode-map (kbd "C-c o c") 'mu4e-org-store-and-capture)
- (define-key mu4e-headers-mode-map "o" 'distopico:mu4e-toggle-headers-include-related)
- (define-key mu4e-view-mode-map (kbd "C-q") 'distopico:mu4e-kill-close)
- (define-key mu4e-view-mode-map (kbd "C-x k") 'distopico:mu4e-kill-close)
- (define-key mu4e-view-mode-map (kbd "C-c o c") 'mu4e-org-store-and-capture)
- ;;------------------
- ;; Functions
- ;;------------------
- (defun distopico:mu4e--default-folders (acc-path settings)
- "Get default folders based in `ACC-PATH' and merge it with `SETTINGS'."
- (append `((mu4e-sent-folder . ,(format "/%s/Sent" acc-path))
- (mu4e-drafts-folder . ,(format "/%s/Drafts" acc-path))
- (mu4e-trash-folder . ,(format "/%s/Trash" acc-path))
- (mu4e-refile-folder . ,(format "/%s/Archive" acc-path)))
- settings))
- (defun distopico:mu4e--maildir-matches-p (maildir-rx)
- "Determine if the `maildir' match with `MAILDIR-RX' regexp."
- (apply-partially
- (lambda (maildir-rx msg)
- (when msg
- (string-match-p maildir-rx (mu4e-message-field msg :maildir))))
- maildir-rx))
- (defun mu4e-in-new-frame ()
- "Start mu4e in new frame."
- (interactive)
- (select-frame (make-frame))
- (mu4e))
- (defun distopico:mu4e-open ()
- "Open mu4e and remove other windows, save the state."
- (interactive)
- (open-buffer-delete-others mu4e-main-buffer-name :mu4e-fullscreen 'mu4e))
- (defun distopico:mu4e-close ()
- "Restore the previous window configuration and burry buffer."
- (interactive)
- (bury-buffer-restore-prev :mu4e-fullscreen))
- (defun distopico:mu4e-kill-close ()
- "Kill buffer and reload maildirs if headers."
- (interactive)
- (if (equal (buffer-name) "*mu4e-headers*")
- (progn
- (unless (eq major-mode 'mu4e-headers-mode)
- (mu4e-error "Must be in mu4e-headers-mode (%S)" major-mode))
- (mu4e-mark-handle-when-leaving)
- (let ((curbuf (current-buffer)) (curwin (selected-window))
- (headers-visible))
- (walk-windows
- (lambda (win)
- (with-selected-window win
- ;; if we the view window connected to this one, kill it
- (when (and (not (one-window-p win)) (eq mu4e~headers-view-win win))
- (delete-window win)
- (setq mu4e~headers-view-win nil)))
- ;; and kill any _other_ (non-selected) window that shows the current
- ;; buffer
- (when (and
- (eq curbuf (window-buffer win)) ;; does win show curbuf?
- (not (eq curwin win)) ;; it's not the curwin?
- (not (one-window-p))) ;; and not the last one?
- (delete-window win))))
- (kill-buffer (current-buffer))
- (mu4e~main-view))
- (distopico:mu4e-maildirs-force-update))
- (if (equal (buffer-name) "*mu4e-view*")
- (progn
- (kill-buffer (current-buffer))
- (delete-other-windows))
- (kill-buffer (current-buffer)))))
- (defun distopico:mu4e-toggle-headers-include-related ()
- "Toggle related `mu4e-headers-include-related' and refresh."
- (interactive)
- (setq mu4e-search-include-related
- (not mu4e-search-include-related))
- (mu4e-search-rerun))
- (defun distopico:mu4e-action-add-org-contact (msg)
- "Add an org-contact entry based address.
- From: address of the \
- current message `MSG' (in headers or view), You need to set
- `mu4e-org-contacts-file' to the full path to the file where you
- store your org-contacts."
- (unless (require 'org-capture nil 'noerror)
- (mu4e-error "The org-capture is not available"))
- (unless mu4e-org-contacts-file
- (mu4e-error "`mu4e-org-contacts-file' is not defined"))
- (let* ((sender (car-safe (mu4e-message-field msg :from)))
- (name (mu4e-contact-name sender))
- (email (mu4e-contact-email sender))
- (blurb
- (format
- (concat
- "** %s%%? \n"
- ":PROPERTIES:\n"
- ":EMAIL: %s\n"
- ":NICK: \n"
- ":END:\n\n")
- (or name email "")
- (or email "")))
- (key "mu4e-add-org-contact-key")
- (head "General")
- (org-capture-templates
- (append org-capture-templates
- (list (list key "contacts" 'entry
- (list 'file+headline mu4e-org-contacts-file head) blurb)))))
- (message "%S" org-capture-templates)
- (when (fboundp 'org-capture)
- (org-capture nil key))))
- (defun distopico:mu4e-new-mail-p ()
- "Predicate for if there is new mail or not in Boolean."
- (not (eq 0 (string-to-number
- (distopico:mu4e-get-unread-command)))))
- (defun distopico:mu4e-get-unread-command ()
- "Get unread messages fro mu4e binary."
- (replace-regexp-in-string
- "[\t\n\r]" ""
- (shell-command-to-string
- (concat "echo -n $( " mu4e-mu-binary " find "
- "--muhome " mu4e-mu-home " "
- "flag:unread AND maildir:'/\/*\/INBOX*/'"
- " 2>/dev/null | wc -l )"))))
- (defun distopico:mu4e-inbox-update ()
- "Print tooltip help and icon for unread messages."
- (interactive)
- (setq distopico:mu4e-mode-line-format
- (let ((unread (distopico:mu4e-get-unread-command)))
- (let ((unread-string
- (if (string= "0" unread) ""
- (format "[✉ %s]" unread))))
- (propertize
- unread-string
- 'display (if (boundp 'img:tron-email)
- img:tron-email
- nil)
- 'local-map (make-mode-line-mouse-map 'mouse-1 #'distopico:mu4e-open)
- 'help-echo (format "mu4e :: %s unread messages" unread)))))
- (force-mode-line-update)
- (sit-for 0))
- (defun distopico:mu4e-maildirs-force-update()
- "Clear cache and insert maildirs summary and reload."
- (interactive)
- (mu4e-message "Updating index & cache...")
- (mu4e-update-index)
- (distopico:mu4e-inbox-update))
- (defun distopico:message-attachment-present-p ()
- "Return t if an attachment is found in the current message."
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (when (search-forward "<#part" nil t) t))))
- (defun distopico:message-warn-if-no-attachments ()
- "Ask the user if wants to send the message even though \
- there are no attachments.
- from: http://mbork.pl/2016-02-06_An_attachment_reminder_in_mu4e"
- (when (and (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (re-search-forward distopico:message-attachment-intent-re nil t)))
- (not (distopico:message-attachment-present-p)))
- (unless (y-or-n-p distopico:message-attachment-reminder)
- (keyboard-quit))))
- (defun distopico:mu4e-index-updated-hook ()
- "Hook when it get new message."
- (let ((updated (plist-get mu4e-index-update-status :updated)))
- (when (> updated 0)
- ;; Sync command to show notification
- ;; (call-process "/bin/bash" nil 0 nil (in-emacs-d "/scripts/notify_mail.sh") (number-to-string mu4e-update-interval))
- ;; Async command to show notification
- ;;(start-process "mu4e-update" nil (in-emacs-d "/scripts/notify_mail.sh") (number-to-string mu4e-update-interval))
- ;; Sync command to show notification
- (shell-command-to-string (concat (in-emacs-d "/scripts/notify_mail.sh") " " (number-to-string mu4e-update-interval)))
- (distopico:mu4e-inbox-update))))
- (defun distopico:mu4e-view-mode-hook ()
- "Enable/disable some mode in `mu4e-view-mode'."
- ;; to easier read html in dark themes
- (setq shr-color-visible-luminance-min 80)
- (tabbar-local-mode +1)
- (footnote-mode +1)
- (visual-line-mode +1))
- (defun distopico:mu4e-compose-mode-hook ()
- "Enable/disable some mode in `mu4e-compose-mode'."
- (distopico:mu4e-view-mode-hook)
- (mml-secure-message-sign-pgpmime))
- (defun distopico:mu4e-init-load-hook ()
- "Run mu4e in startup."
- (setq-default mu4e-contexts (eval distopico:mu4e-contexts))
- (mu4e t)
- (distopico:mu4e-mode-line t))
- ;; Custom modes
- (define-minor-mode distopico:mu4e-mode-line
- "Minor mode Toggle inbox status display in mode line."
- :global t :group 'hardware
- (setq distopico:mu4e-mode-line-format "")
- (and distopico:mu4e-update-timer (cancel-timer distopico:mu4e-update-timer))
- (if (not distopico:mu4e-mode-line-format)
- (message "Disabled mu4e mode line..")
- (setq distopico:mu4e-update-timer
- (run-at-time nil distopico:mu4e-inbox-update-modeline-interval #'distopico:mu4e-inbox-update))
- (distopico:mu4e-inbox-update)))
- ;;-------------------
- ;; Hooks
- ;;-------------------
- (add-hook 'mu4e-index-updated-hook #'distopico:mu4e-index-updated-hook)
- (add-hook 'mu4e-view-mode-hook #'distopico:mu4e-view-mode-hook)
- (add-hook 'mu4e-compose-mode-hook #'distopico:mu4e-compose-mode-hook)
- (add-hook 'message-send-hook #'distopico:message-warn-if-no-attachments)
- (add-hook 'gnus-part-display-hook 'message-view-patch-highlight)
- (add-hook 'mu4e--update-mail-and-index-real 'distopico:inhibit-message-advisor)
- (add-hook 'distopico:after-init-load-hook #'distopico:mu4e-init-load-hook)
- (provide 'conf-mu4e)
- ;;; conf-mu4e.el ends here
|