diff --git a/mu4e/mu4e-proc.el b/mu4e/mu4e-proc.el index 9190ab24..0bfc902b 100644 --- a/mu4e/mu4e-proc.el +++ b/mu4e/mu4e-proc.el @@ -1,6 +1,6 @@ ;; mu4e-proc.el -- part of mu4e, the mu mail user agent ;; -;; Copyright (C) 2011-2017 Dirk-Jan C. Binnema +;; Copyright (C) 2011-2019 Dirk-Jan C. Binnema ;; Author: Dirk-Jan C. Binnema ;; Maintainer: Dirk-Jan C. Binnema @@ -37,13 +37,11 @@ ;; dealing with the length cookie that precedes expressions (defconst mu4e~cookie-pre "\376" - "Each expression we get from the backend (mu server) starts with -a length cookie: - <`mu4e~cookie-pre'><`mu4e~cookie-post'>.") + "Each expression starts with a length cookie: +<`mu4e~cookie-pre'><`mu4e~cookie-post'>.") (defconst mu4e~cookie-post "\377" - "Each expression we get from the backend (mu server) starts with -a length cookie: - <`mu4e~cookie-pre'><`mu4e~cookie-post'>.") + "Each expression starts with a length cookie: +<`mu4e~cookie-pre'><`mu4e~cookie-post'>.") (defconst mu4e~cookie-matcher-rx (concat mu4e~cookie-pre "\\([[:xdigit:]]+\\)" mu4e~cookie-post) "Regular expression matching the length cookie. @@ -56,12 +54,11 @@ Match 1 will be the length (in hex).") (defvar mu4e~proc-process nil "The mu-server process.") - (defun mu4e~proc-running-p () "Whether the mu process is running." (when (and mu4e~proc-process - (memq (process-status mu4e~proc-process) - '(run open listen connect stop))) + (memq (process-status mu4e~proc-process) + '(run open listen connect stop))) t)) (defsubst mu4e~proc-eat-sexp-from-buf () @@ -76,36 +73,37 @@ removed." ;; 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)) + (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))))))) + (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))))))) (defun mu4e~proc-filter (proc str) - "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. + "Filter string STR from PROC. +This process the the 'mu server' output. It accumulates the +strings into valid sexps by checking of the ';;eox' `end-of-sexp' +marker, and then evaluating them. The server output is as follows: 1. an error (:error 2 :message \"unknown command\") ;; eox - => this will be passed to `mu4e-error-func'. + => passed to `mu4e-error-func'. 2a. a message sexp looks something like: \( @@ -156,92 +154,92 @@ The server output is as follows: (let ((sexp (mu4e~proc-eat-sexp-from-buf))) (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)) + (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))) + ;; 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))) + ;; 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 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))) + ;; receive a :sent message + ((plist-get sexp :sent) + (funcall mu4e-sent-func + (plist-get sexp :docid) + (plist-get sexp :path))) - ;; received a pong message - ((plist-get sexp :pong) - (funcall mu4e-pong-func - (plist-get sexp :props))) + ;; received a pong message + ((plist-get sexp :pong) + (funcall mu4e-pong-func + (plist-get sexp :props))) - ;; received a contacts message - ;; note: we use 'member', to match (:contacts nil) - ((plist-member sexp :contacts) - (funcall mu4e-contacts-func - (plist-get sexp :contacts))) + ;; received a contacts message + ;; note: we use 'member', to match (:contacts nil) + ((plist-member sexp :contacts) + (funcall mu4e-contacts-func + (plist-get sexp :contacts))) - ;; something got moved/flags changed - ((plist-get sexp :update) + ;; something got moved/flags changed + ((plist-get sexp :update) (funcall mu4e-update-func - (plist-get sexp :update) - (plist-get sexp :move) - (plist-get sexp :maybe-view))) + (plist-get sexp :update) + (plist-get sexp :move) + (plist-get sexp :maybe-view))) - ;; a message got removed - ((plist-get sexp :remove) - (funcall mu4e-remove-func (plist-get sexp :remove))) + ;; 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))) + ;; 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 - (plist-get sexp :what) ;; what to do with it - ;; (pipe|emacs|open-with...) - (plist-get sexp :docid) ;; docid of the message - (plist-get sexp :param)));; parameter for the action + ;; do something with a temporary file + ((plist-get sexp :temp) + (funcall mu4e-temp-func + (plist-get sexp :temp) ;; name of the temp file + (plist-get sexp :what) ;; what to do with it + ;; (pipe|emacs|open-with...) + (plist-get sexp :docid) ;; docid of the message + (plist-get sexp :param)));; parameter for the action - ;; get some info - ((plist-get sexp :info) - (funcall mu4e-info-func sexp)) + ;; 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))) + ;; receive an error + ((plist-get sexp :error) + (funcall mu4e-error-func + (plist-get sexp :error) + (plist-get sexp :message))) - (t (mu4e-message "Unexpected data from server [%S]" sexp))) + (t (mu4e-message "Unexpected data from server [%S]" sexp))) - (setq sexp (mu4e~proc-eat-sexp-from-buf)))))) + (setq sexp (mu4e~proc-eat-sexp-from-buf)))))) (defun mu4e~escape (str) - "Escape STRING for transport -- put it in quotes, and escape -existing quotation. In particular, backslashes and -double-quotes." + "Escape string STR for transport. +Put it in quotes, and escape existing quotation. In particular, +backslashes and double-quotes." (let ((esc (replace-regexp-in-string "\\\\" "\\\\\\\\" str))) (format "\"%s\"" (replace-regexp-in-string "\"" "\\\\\"" esc)))) (defun mu4e~proc-send-command (frm &rest args) - "Send as command to the mu server process. + "Send string from FRM and ARGS to the mu server process. Start the process if needed." (unless (mu4e~proc-running-p) (mu4e~proc-start)) @@ -254,13 +252,13 @@ Start the process if needed." (unless (file-executable-p mu4e-mu-binary) (mu4e-error (format "`mu4e-mu-binary' (%S) not found" mu4e-mu-binary))) (let* ((process-connection-type nil) ;; use a pipe - (args '("server")) - (args (append args (when mu4e-mu-home - (list (concat "--muhome=" mu4e-mu-home)))))) + (args '("server")) + (args (append args (when mu4e-mu-home + (list (concat "--muhome=" mu4e-mu-home)))))) (setq mu4e~proc-buf "") (setq mu4e~proc-process (apply 'start-process - mu4e~proc-name mu4e~proc-name - mu4e-mu-binary args)) + mu4e~proc-name mu4e~proc-name + mu4e-mu-binary args)) ;; register a function for (:info ...) sexps (unless mu4e~proc-process (mu4e-error "Failed to start the mu4e backend")) @@ -272,14 +270,14 @@ Start the process if needed." (defun mu4e~proc-kill () "Kill the mu server process." (let* ((buf (get-buffer mu4e~proc-name)) - (proc (and (buffer-live-p buf) (get-buffer-process buf)))) + (proc (and (buffer-live-p buf) (get-buffer-process buf)))) (when proc (let ((delete-exited-processes t)) - ;; the mu server signal handler will make it quit after 'quit' - (mu4e~proc-send-command "cmd:quit")) - ;; try sending SIGINT (C-c) to process, so it can exit gracefully + ;; the mu server signal handler will make it quit after 'quit' + (mu4e~proc-send-command "cmd:quit")) + ;; try sending SIGINT (C-c) to process, so it can exit gracefully (ignore-errors - (signal-process proc 'SIGINT)))) + (signal-process proc 'SIGINT)))) (setq mu4e~proc-process nil mu4e~proc-buf nil)) @@ -288,29 +286,29 @@ Start the process if needed." ;;(defconst mu4e-xapian-empty 19 "Error code: xapian is empty/non-existent") (defun mu4e~proc-sentinel (proc msg) - "Function that will be called when the mu-server process terminates." + "Function called when the server process PROC terminates with MSG." (let ((status (process-status proc)) (code (process-exit-status proc))) (setq mu4e~proc-process nil) (setq mu4e~proc-buf "") ;; clear any half-received sexps (cond ((eq status 'signal) - (cond - ((or(eq code 9) (eq code 2)) (message nil)) - ;;(message "the mu server process has been stopped")) - (t (error (format "mu server process received signal %d" code))))) + (cond + ((or(eq code 9) (eq code 2)) (message nil)) + ;;(message "the mu server process has been stopped")) + (t (error (format "mu server process received signal %d" code))))) ((eq status 'exit) - (cond - ((eq code 0) - (message nil)) ;; don't do anything - ((eq code 11) - (error "Database is locked by another process")) - ((eq code 15) - (error "Database needs upgrade; try `mu index --rebuild'")) - ((eq code 19) - (error "Database empty; try indexing some messages")) - (t (error "mu server process ended with exit code %d" code)))) + (cond + ((eq code 0) + (message nil)) ;; don't do anything + ((eq code 11) + (error "Database is locked by another process")) + ((eq code 15) + (error "Database needs upgrade; try `mu index --rebuild'")) + ((eq code 19) + (error "Database empty; try indexing some messages")) + (t (error "Mu server process ended with exit code %d" code)))) (t - (error "Something bad happened to the mu server process"))))) + (error "Something bad happened to the mu server process"))))) (defun mu4e~docid-msgid-param (docid-or-msgid) "Construct a backend parameter based on DOCID-OR-MSGID." @@ -319,15 +317,15 @@ Start the process if needed." (format "docid:%d" docid-or-msgid))) (defun mu4e~proc-find (query threads sortfield sortdir maxnum skip-dups - include-related) - "Start a database query for QUERY. + include-related) + "Run QUERY with THREADS SORTFIELD SORTDIR MAXNUM SKIP-DUPS INCLUDE-RELATED. If THREADS is non-nil, show results in threaded fasion, SORTFIELD is a symbol describing the field to sort by (or nil); see `mu4e~headers-sortfield-choices'. If SORT is `descending', sort -Z->A, if it's `ascending', sort A->Z. MAXNUM determines the maximum -number of results to return, or nil for 'unlimited'. If SKIP-DUPS -is non-nil, show only one of duplicate messages (see -`mu4e-headers-skip-duplicates'). If INCLUDE-RELATED is non-nil, +Z->A, if it's `ascending', sort A->Z. MAXNUM determines the +maximum number of results to return, or nil for 'unlimited'. If +SKIP-DUPS is non-nil, show only one of duplicate messages (see +`mu4e-headers-skip-duplicates'). If INCLUDE-RELATED is non-nil, include messages related to the messages matching the search query (see `mu4e-headers-include-related'). @@ -351,9 +349,9 @@ or an error." (if include-related "true" "false"))) (defun mu4e~proc-move (docid-or-msgid &optional maildir flags no-view) - "Move message identified by DOCID-OR-MSGID to optional MAILDIR -and optionally setting FLAGS. If MAILDIR is nil, message will be -moved within the same maildir. + "Move message identified by DOCID-OR-MSGID. +Optionally to MAILDIR and optionally setting FLAGS. If MAILDIR is +nil, message will be moved within the same maildir. At least one of MAILDIR and FLAGS must be specified. Note that even when MAILDIR is nil, this is still a filesystem move, since @@ -386,19 +384,19 @@ Returns either (:update ... ) or (:error ) sexp, which are handled my (unless (or maildir flags) (mu4e-error "At least one of maildir and flags must be specified")) (unless (or (not maildir) - (file-exists-p (concat mu4e-maildir "/" maildir "/"))) + (file-exists-p (concat mu4e-maildir "/" maildir "/"))) (mu4e-error "Target dir does not exist")) (let* ((idparam (mu4e~docid-msgid-param docid-or-msgid)) - (flagstr - (when flags - (concat " flags:" - (if (stringp flags) flags (mu4e-flags-to-string flags))))) - (path - (when maildir - (format " maildir:%s" (mu4e~escape maildir)))) - (rename - (if (and maildir mu4e-change-filenames-when-moving) - "true" "false"))) + (flagstr + (when flags + (concat " flags:" + (if (stringp flags) flags (mu4e-flags-to-string flags))))) + (path + (when maildir + (format " maildir:%s" (mu4e~escape maildir)))) + (rename + (if (and maildir mu4e-change-filenames-when-moving) + "true" "false"))) (mu4e~proc-send-command "cmd:move %s %s %s %s %s" idparam (or flagstr "") @@ -407,15 +405,20 @@ Returns either (:update ... ) or (:error ) sexp, which are handled my (format "noview:%s" (if no-view "true" "false"))))) (defun mu4e~proc-index (path my-addresses cleanup lazy-check) - "Update the message database for filesystem PATH, which should -point to some maildir directory structure. MY-ADDRESSES is a list -of 'my' email addresses (see `mu4e-user-mail-address-list')." + "Index messages on PATH with possible CLEANUP and LAZY-CHECK. +PATH should point to some maildir directory structure. +MY-ADDRESSES is a list of 'my' email addresses (see +`mu4e-user-mail-address-list')." (let ((path (mu4e~escape path)) - (addrs (when my-addresses (mapconcat 'identity my-addresses ",")))) + (addrs (when my-addresses (mapconcat 'identity my-addresses ",")))) (if addrs (mu4e~proc-send-command - "cmd:index path:%s my-addresses:%s cleanup:%s lazy-check:%s" - path addrs (if cleanup "true" : "false") (if lazy-check "true")) + "cmd:index path:%s my-addresses:%s cleanup:%s lazy-check:%s contacts:%s" + path + addrs + (if cleanup "true" : "false") + (if lazy-check "true") + (if mu4e-compose-complete-addresses "true")) (mu4e~proc-send-command "cmd:index path:%s" path)))) (defun mu4e~proc-add (path maildir) @@ -441,12 +444,12 @@ e.g. '/drafts'. (defun mu4e~proc-compose (type decrypt &optional docid) - "Start composing a message of certain TYPE (a symbol, either -`forward', `reply', `edit', `resend' or `new', based on an -original message (ie, replying to, forwarding, editing, -resending) with DOCID or nil for type `new'. + "Compose a message of TYPE, DECRYPT it and use DOCID. +TYPE is a symbol, either `forward', `reply', `edit', `resend' or +`new', based on an original message (ie, replying to, forwarding, +editing, resending) with DOCID or nil for type `new'. -The result will be delivered to the function registered as +The result is delivered to the function registered as `mu4e-compose-func'." (unless (member type '(forward reply edit resend new)) (mu4e-error "Unsupported compose-type %S" type)) @@ -461,34 +464,33 @@ The result will be delivered to the function registered as (mu4e~proc-send-command "cmd:mkdir path:%s" (mu4e~escape path))) (defun mu4e~proc-extract (action docid partidx decrypt - &optional path what param) - "Extract an attachment with index PARTIDX from message with DOCID -and perform ACTION on it (as symbol, either `save', `open', `temp') which -mean: - * save: save the part to PARAM1 (a path) (non-optional for save)$ - * open: open the part with the default application registered for doing so - * temp: save to a temporary file, then respond with + &optional path what param) + "Perform ACTION on part with DOCID PARTIDX DECRYPT PATH WHAT PARAM. +Use a message with DOCID and perform ACTION on it (as symbol, +either `save', `open', `temp') which mean: * save: save the part +to PATH (a path) (non-optional for save)$ * open: open the part +with the default application registered for doing so * temp: save +to a temporary file, then respond with (:temp :what :param )." (let ((cmd - (concat "cmd:extract " - (cl-case action - (save - (format "action:save docid:%d index:%d path:%s extract-encrypted:%s use-agent:true" - docid partidx (mu4e~escape path) (if decrypt "true" "false"))) - (open (format "action:open docid:%d index:%d extract-encrypted:%s use-agent:true" - docid partidx (if decrypt "true" "false"))) - (temp - (format "action:temp docid:%d index:%d what:%s%s extract-encrypted:%s use-agent:true" - docid partidx what - (if param - (if (stringp param) - (format " param:%s" (mu4e~escape param)) - (format " param:%S" param)) "") (if decrypt "true" "false"))) - (otherwise (mu4e-error "Unsupported action %S" action)))) - )) + (concat "cmd:extract " + (cl-case action + (save + (format "action:save docid:%d index:%d path:%s extract-encrypted:%s use-agent:true" + docid partidx (mu4e~escape path) (if decrypt "true" "false"))) + (open (format "action:open docid:%d index:%d extract-encrypted:%s use-agent:true" + docid partidx (if decrypt "true" "false"))) + (temp + (format "action:temp docid:%d index:%d what:%s%s extract-encrypted:%s use-agent:true" + docid partidx what + (if param + (if (stringp param) + (format " param:%s" (mu4e~escape param)) + (format " param:%S" param)) "") (if decrypt "true" "false"))) + (otherwise (mu4e-error "Unsupported action %S" action)))) + )) (mu4e~proc-send-command "%s" cmd))) - (defun mu4e~proc-ping () "Sends a ping to the mu server, expecting a (:pong ...) in response." (mu4e~proc-send-command "cmd:ping")) @@ -504,11 +506,11 @@ only contacts seen AFTER (the time_t value)." (or after 0))) (defun mu4e~proc-view (docid-or-msgid &optional images decrypt) - "Get one particular message based on its DOCID-OR-MSGID. + "Get a message DOCID-OR-MSGID. Optionally, if IMAGES is non-nil, backend will any images -attached to the message, and return them as temp files. -The result will be delivered to the function registered as -`mu4e-view-func'." +attached to the message, and return them as temp files. DECRYPT +if necessary. The result will be delivered to the function +registered as `mu4e-view-func'." (mu4e~proc-send-command "cmd:view %s extract-images:%s extract-encrypted:%s use-agent:true" (mu4e~docid-msgid-param docid-or-msgid) @@ -516,11 +518,11 @@ The result will be delivered to the function registered as (if decrypt "true" "false"))) (defun mu4e~proc-view-path (path &optional images decrypt) - "View message at PATH (keyword argument). + "View message at PATH.. Optionally, if IMAGES is non-nil, backend will any images attached to the message, and return them as temp files. The result will be delivered to the function registered as -`mu4e-view-func'." +`mu4e-view-func'. Optionally DECRYPT." (mu4e~proc-send-command "cmd:view path:%s extract-images:%s extract-encrypted:%s use-agent:true" (mu4e~escape path) @@ -528,12 +530,11 @@ result will be delivered to the function registered as (if decrypt "true" "false"))) (defun mu4e~proc-remove (docid) - "Remove message identified by docid. -The results are reporter through either (:update ... ) or (:error) -sexp, which are handled my `mu4e-error-func', respectively." + "Remove message with DOCID. +The results are reporter through either (:update ... ) +or (:error) sexp, which are handled my `mu4e-error-func', +respectively." (mu4e~proc-send-command "cmd:remove docid:%d" docid)) - (provide 'mu4e-proc) - -;; End of mu4e-proc.el +;;; mu4e-proc.el ends here