2012-04-16 17:31:48 +02:00
|
|
|
;; mu4e-proc.el -- part of mu4e, the mu mail user agent
|
2011-09-12 19:52:32 +02:00
|
|
|
;;
|
2017-09-17 12:18:06 +02:00
|
|
|
;; Copyright (C) 2011-2017 Dirk-Jan C. Binnema
|
2011-09-12 19:52:32 +02:00
|
|
|
|
|
|
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
|
|
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
|
|
|
|
|
|
|
;; 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:
|
2012-04-09 15:34:52 +02:00
|
|
|
(require 'mu4e-vars)
|
|
|
|
(require 'mu4e-utils)
|
2012-04-21 11:47:13 +02:00
|
|
|
(require 'mu4e-meta)
|
2012-04-15 13:21:59 +02:00
|
|
|
|
2017-01-03 16:49:31 +01:00
|
|
|
(require 'mu4e-proc-mu)
|
|
|
|
|
2012-04-09 15:34:52 +02:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
2011-09-12 19:52:32 +02:00
|
|
|
;; internal vars
|
2012-04-19 07:30:42 +02:00
|
|
|
|
2017-01-03 16:49:31 +01:00
|
|
|
(defconst mu4e~proc-name "*mu4e-proc*"
|
2012-06-14 08:58:13 +02:00
|
|
|
"Name of the server process, buffer.")
|
|
|
|
(defvar mu4e~proc-process nil
|
|
|
|
"The mu-server process.")
|
2011-09-18 22:57:46 +02:00
|
|
|
|
2012-04-28 08:05:05 +02:00
|
|
|
;; dealing with the length cookie that precedes expressions
|
|
|
|
(defconst mu4e~cookie-pre "\376"
|
|
|
|
"Each expression we get from the backend (mu server) starts with
|
2012-11-10 14:01:17 +01:00
|
|
|
a length cookie:
|
|
|
|
<`mu4e~cookie-pre'><length-in-hex><`mu4e~cookie-post'>.")
|
2012-04-28 08:05:05 +02:00
|
|
|
(defconst mu4e~cookie-post "\377"
|
|
|
|
"Each expression we get from the backend (mu server) starts with
|
2012-11-10 14:01:17 +01:00
|
|
|
a length cookie:
|
|
|
|
<`mu4e~cookie-pre'><length-in-hex><`mu4e~cookie-post'>.")
|
2012-10-27 13:39:42 +02:00
|
|
|
(defconst mu4e~cookie-matcher-rx
|
2015-12-15 06:02:24 +01:00
|
|
|
(concat mu4e~cookie-pre "\\([[:xdigit:]]+\\)" mu4e~cookie-post)
|
2012-11-10 14:01:17 +01:00
|
|
|
"Regular expression matching the length cookie.
|
|
|
|
Match 1 will be the length (in hex).")
|
2012-04-28 08:05:05 +02:00
|
|
|
|
2012-10-06 21:22:11 +02:00
|
|
|
(defun mu4e~proc-running-p ()
|
2012-04-26 16:59:34 +02:00
|
|
|
"Whether the mu process is running."
|
2012-09-15 17:04:39 +02:00
|
|
|
(when (and mu4e~proc-process
|
|
|
|
(memq (process-status mu4e~proc-process)
|
|
|
|
'(run open listen connect stop)))
|
|
|
|
t))
|
2012-04-26 16:59:34 +02:00
|
|
|
|
2012-08-27 17:06:27 +02:00
|
|
|
(defsubst mu4e~proc-eat-sexp-from-buf ()
|
2012-11-10 14:01:17 +01:00
|
|
|
"'Eat' the next s-expression from `mu4e~proc-buf'.
|
|
|
|
Note: this is a string, not an emacs-buffer. `mu4e~proc-buf gets
|
|
|
|
its contents from the mu-servers in the following form:
|
2012-04-28 08:05:05 +02:00
|
|
|
<`mu4e~cookie-pre'><length-in-hex><`mu4e~cookie-post'>
|
2012-11-10 14:01:17 +01:00
|
|
|
Function returns this sexp, or nil if there was none.
|
|
|
|
`mu4e~proc-buf' is updated as well, with all processed sexp data
|
|
|
|
removed."
|
2012-09-28 16:11:58 +02:00
|
|
|
(ignore-errors ;; the server may die in the middle...
|
|
|
|
;; mu4e~cookie-matcher-rx:
|
|
|
|
;; (concat mu4e~cookie-pre "\\([[:xdigit:]]+\\)]" mu4e~cookie-post)
|
|
|
|
(let ((b (string-match mu4e~cookie-matcher-rx mu4e~proc-buf))
|
|
|
|
(sexp-len) (objcons))
|
|
|
|
(when b
|
|
|
|
(setq sexp-len (string-to-number (match-string 1 mu4e~proc-buf) 16))
|
|
|
|
;; does mu4e~proc-buf contain the full sexp?
|
|
|
|
(when (>= (length mu4e~proc-buf) (+ sexp-len (match-end 0)))
|
|
|
|
;; clear-up start
|
|
|
|
(setq mu4e~proc-buf (substring mu4e~proc-buf (match-end 0)))
|
|
|
|
;; 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.
|
|
|
|
(setq objcons (read-from-string
|
|
|
|
(decode-coding-string
|
|
|
|
(substring mu4e~proc-buf 0 sexp-len)
|
|
|
|
'utf-8 t)))
|
|
|
|
(when objcons
|
|
|
|
(setq mu4e~proc-buf (substring mu4e~proc-buf sexp-len))
|
|
|
|
(car objcons)))))))
|
2011-09-18 13:39:36 +02:00
|
|
|
|
2011-09-12 19:52:32 +02:00
|
|
|
|
2013-06-03 20:09:20 +02:00
|
|
|
(defun mu4e~proc-filter (proc str)
|
2012-11-10 14:01:17 +01:00
|
|
|
"A process-filter for the 'mu server' output.
|
|
|
|
It accumulates the strings into valid sexps by checking of the
|
|
|
|
';;eox' end-of-sexp marker, and then evaluating them.
|
2011-09-12 19:52:32 +02:00
|
|
|
|
2012-04-26 16:59:34 +02:00
|
|
|
The server output is as follows:
|
2011-09-12 19:52:32 +02:00
|
|
|
|
2011-09-18 13:39:36 +02:00
|
|
|
1. an error
|
2012-04-15 13:21:59 +02:00
|
|
|
(:error 2 :message \"unknown command\")
|
2011-09-18 13:39:36 +02:00
|
|
|
;; eox
|
2012-04-11 21:31:52 +02:00
|
|
|
=> this will be passed to `mu4e-error-func'.
|
2011-09-12 19:52:32 +02:00
|
|
|
|
2011-10-25 07:43:24 +02:00
|
|
|
2a. a message sexp looks something like:
|
2011-09-12 19:52:32 +02:00
|
|
|
\(
|
|
|
|
:docid 1585
|
|
|
|
:from ((\"Donald Duck\" . \"donald@example.com\"))
|
|
|
|
:to ((\"Mickey Mouse\" . \"mickey@example.com\"))
|
|
|
|
:subject \"Wicked stuff\"
|
|
|
|
:date (20023 26572 0)
|
|
|
|
:size 15165
|
|
|
|
:references (\"200208121222.g7CCMdb80690@msg.id\")
|
|
|
|
:in-reply-to \"200208121222.g7CCMdb80690@msg.id\"
|
|
|
|
:message-id \"foobar32423847ef23@pluto.net\"
|
|
|
|
:maildir: \"/archive\"
|
|
|
|
:path \"/home/mickey/Maildir/inbox/cur/1312254065_3.32282.pluto,4cd5bd4e9:2,\"
|
|
|
|
:priority high
|
|
|
|
:flags (new unread)
|
|
|
|
:attachments ((2 \"hello.jpg\" \"image/jpeg\") (3 \"laah.mp3\" \"audio/mp3\"))
|
|
|
|
:body-txt \" <message body>\"
|
|
|
|
\)
|
|
|
|
;; eox
|
2012-04-11 21:31:52 +02:00
|
|
|
=> this will be passed to `mu4e-header-func'.
|
2011-09-18 13:39:36 +02:00
|
|
|
|
2011-10-25 07:43:24 +02:00
|
|
|
2b. After the list of message sexps has been returned (see 2a.),
|
|
|
|
we'll receive a sexp that looks like
|
|
|
|
(:found <n>) with n the number of messages found. The <n> will be
|
2012-04-11 21:31:52 +02:00
|
|
|
passed to `mu4e-found-func'.
|
2011-10-25 07:43:24 +02:00
|
|
|
|
2011-09-18 13:39:36 +02:00
|
|
|
3. a view looks like:
|
|
|
|
(:view <msg-sexp>)
|
2012-04-11 21:31:52 +02:00
|
|
|
=> the <msg-sexp> (see 2.) will be passed to `mu4e-view-func'.
|
2011-09-18 13:39:36 +02:00
|
|
|
|
|
|
|
4. a database update looks like:
|
|
|
|
(:update <msg-sexp> :move <nil-or-t>)
|
|
|
|
|
|
|
|
=> the <msg-sexp> (see 2.) will be passed to
|
2012-04-11 21:31:52 +02:00
|
|
|
`mu4e-update-func', :move tells us whether this is a move to
|
2011-09-18 13:39:36 +02:00
|
|
|
another maildir, or merely a flag change.
|
|
|
|
|
|
|
|
5. a remove looks like:
|
|
|
|
(:remove <docid>)
|
2012-04-11 21:31:52 +02:00
|
|
|
=> the docid will be passed to `mu4e-remove-func'
|
2011-09-18 13:39:36 +02:00
|
|
|
|
|
|
|
6. a compose looks like:
|
2012-04-15 13:21:59 +02:00
|
|
|
(:compose <reply|forward|edit|new> [:original<msg-sexp>] [:include <attach>])
|
2012-04-11 21:31:52 +02:00
|
|
|
`mu4e-compose-func'."
|
2012-04-16 17:31:48 +02:00
|
|
|
(mu4e-log 'misc "* Received %d byte(s)" (length str))
|
2012-04-23 19:35:14 +02:00
|
|
|
(setq mu4e~proc-buf (concat mu4e~proc-buf str)) ;; update our buffer
|
|
|
|
(let ((sexp (mu4e~proc-eat-sexp-from-buf)))
|
2012-05-07 20:59:06 +02:00
|
|
|
(with-local-quit
|
|
|
|
(while sexp
|
|
|
|
(mu4e-log 'from-server "%S" sexp)
|
|
|
|
(cond
|
|
|
|
;; a header plist can be recognized by the existence of a :date field
|
|
|
|
((plist-get sexp :date)
|
|
|
|
(funcall mu4e-header-func sexp))
|
|
|
|
|
|
|
|
;; the found sexp, we receive after getting all the headers
|
|
|
|
((plist-get sexp :found)
|
|
|
|
(funcall mu4e-found-func (plist-get sexp :found)))
|
|
|
|
|
|
|
|
;; viewing a specific message
|
|
|
|
((plist-get sexp :view)
|
|
|
|
(funcall mu4e-view-func (plist-get sexp :view)))
|
|
|
|
|
|
|
|
;; receive an erase message
|
|
|
|
((plist-get sexp :erase)
|
|
|
|
(funcall mu4e-erase-func))
|
|
|
|
|
|
|
|
;; receive a :sent message
|
|
|
|
((plist-get sexp :sent)
|
|
|
|
(funcall mu4e-sent-func
|
|
|
|
(plist-get sexp :docid)
|
|
|
|
(plist-get sexp :path)))
|
|
|
|
|
2012-06-18 17:03:24 +02:00
|
|
|
;; received a pong message
|
2012-05-07 20:59:06 +02:00
|
|
|
((plist-get sexp :pong)
|
|
|
|
(funcall mu4e-pong-func
|
2012-08-01 16:07:11 +02:00
|
|
|
(plist-get sexp :props)))
|
2012-05-07 20:59:06 +02:00
|
|
|
|
2012-06-18 17:03:24 +02:00
|
|
|
;; received a contacts message
|
2013-03-09 16:38:07 +01:00
|
|
|
;; note: we use 'member', to match (:contacts nil)
|
|
|
|
((plist-member sexp :contacts)
|
2012-06-18 17:03:24 +02:00
|
|
|
(funcall mu4e-contacts-func
|
|
|
|
(plist-get sexp :contacts)))
|
|
|
|
|
2012-05-07 20:59:06 +02:00
|
|
|
;; something got moved/flags changed
|
|
|
|
((plist-get sexp :update)
|
|
|
|
(funcall mu4e-update-func
|
|
|
|
(plist-get sexp :update) (plist-get sexp :move)))
|
|
|
|
|
|
|
|
;; a message got removed
|
|
|
|
((plist-get sexp :remove)
|
|
|
|
(funcall mu4e-remove-func (plist-get sexp :remove)))
|
|
|
|
|
|
|
|
;; start composing a new message
|
|
|
|
((plist-get sexp :compose)
|
|
|
|
(funcall mu4e-compose-func
|
|
|
|
(plist-get sexp :compose)
|
|
|
|
(plist-get sexp :original)
|
|
|
|
(plist-get sexp :include)))
|
|
|
|
|
|
|
|
;; do something with a temporary file
|
|
|
|
((plist-get sexp :temp)
|
|
|
|
(funcall mu4e-temp-func
|
|
|
|
(plist-get sexp :temp) ;; name of the temp file
|
2012-09-20 20:34:19 +02:00
|
|
|
(plist-get sexp :what) ;; what to do with it
|
2017-09-17 12:18:06 +02:00
|
|
|
;; (pipe|emacs|open-with...)
|
2012-09-23 10:42:00 +02:00
|
|
|
(plist-get sexp :docid) ;; docid of the message
|
2012-05-07 20:59:06 +02:00
|
|
|
(plist-get sexp :param)));; parameter for the action
|
|
|
|
|
|
|
|
;; get some info
|
|
|
|
((plist-get sexp :info)
|
|
|
|
(funcall mu4e-info-func sexp))
|
|
|
|
|
|
|
|
;; receive an error
|
|
|
|
((plist-get sexp :error)
|
|
|
|
(funcall mu4e-error-func
|
|
|
|
(plist-get sexp :error)
|
|
|
|
(plist-get sexp :message)))
|
2013-05-13 22:02:26 +02:00
|
|
|
|
2012-05-07 20:59:06 +02:00
|
|
|
(t (mu4e-message "Unexpected data from server [%S]" sexp)))
|
|
|
|
|
|
|
|
(setq sexp (mu4e~proc-eat-sexp-from-buf))))))
|
2011-09-18 13:39:36 +02:00
|
|
|
|
2017-01-03 16:49:31 +01:00
|
|
|
(defun mu4e~escape (str)
|
2017-09-17 12:18:06 +02:00
|
|
|
"Escape STRING for transport -- put it in quotes, and escape
|
|
|
|
existing quotation. In particular, backslashes and
|
|
|
|
double-quotes."
|
2013-05-20 04:14:57 +02:00
|
|
|
(let ((esc (replace-regexp-in-string "\\\\" "\\\\\\\\" str)))
|
|
|
|
(format "\"%s\"" (replace-regexp-in-string "\"" "\\\\\"" esc))))
|
2012-11-02 08:26:12 +01:00
|
|
|
|
2011-12-13 08:07:38 +01:00
|
|
|
(provide 'mu4e-proc)
|
2012-01-06 11:31:28 +01:00
|
|
|
;; End of mu4e-proc.el
|