mu4e: use the new command-parser

Update mu4e-proc to use the new mu4e <-> mu protocol
This commit is contained in:
Dirk-Jan C. Binnema 2020-01-19 17:23:24 +02:00
parent c71f683e39
commit d2ec85f01c
7 changed files with 116 additions and 104 deletions

View File

@ -445,6 +445,33 @@ Mu::size_to_string (const std::string& val, bool is_first)
}
std::string
Mu::quoted (const std::string& str)
{
std::string res{"\""};
for (auto&& c : str) {
if (c == '\\' || c == '\"')
res += '\\';
res += c;
}
return res + '"';
}
// std::string
// Mu::quoted (const char* str)
// {
// if (!str)
// return str;
// char *s{g_strescape(str, NULL)};
// auto res = format("\"%s\"", s ? s : "");
// g_free(s);
// return res;
// }
void
Mu::assert_equal(const std::string& s1, const std::string& s2)
{

View File

@ -93,6 +93,17 @@ std::string format (const char *frm, ...) __attribute__((format(printf, 1, 2)));
std::string format (const char *frm, va_list args) __attribute__((format(printf, 1, 0)));
/**
* Quote a string -- put in "" and escape any special characters by putting '\'
* in front of them.
*
* @param str
*
* @return
*/
std::string quoted (const std::string& str);
/**
* Convert an ISO date to the corresponding time expressed as a string
* with a 10-digit time_t

View File

@ -696,7 +696,11 @@ mu_cmd_execute (MuConfig *opts, GError **err)
case MU_CONFIG_CMD_TICKLE:
merr = with_store (mu_cmd_tickle, opts, FALSE, err); break;
case MU_CONFIG_CMD_SERVER:
merr = with_store (mu_cmd_server, opts, FALSE, err); break;
if (opts->commands)
merr = mu_cmd_server (NULL, opts, err);
else
merr = with_store (mu_cmd_server, opts, FALSE, err);
break;
default:
merr = MU_ERROR_IN_PARAMETERS; break;
}

View File

@ -441,8 +441,8 @@ config_options_group_server (void)
GOptionEntry entries[] = {
{"maildir", 'm', 0, G_OPTION_ARG_FILENAME, &MU_CONFIG.maildir,
"top of the maildir", "<maildir>"},
{"list-commands", 0, 0, G_OPTION_ARG_NONE, &MU_CONFIG.list_commands,
"overwrite existing files (false)", NULL},
{"commands", 0, 0, G_OPTION_ARG_NONE, &MU_CONFIG.commands,
"list the available command and their parameters, then exit", NULL},
{NULL, 0, 0, 0, NULL, NULL, NULL}
};
@ -760,7 +760,6 @@ mu_config_uninit (MuConfig *opts)
memset (opts, 0, sizeof(MU_CONFIG));
}
size_t
mu_config_param_num (MuConfig *opts)
{

View File

@ -179,8 +179,8 @@ struct _MuConfig {
gboolean play; /* after saving, try to 'play'
* (open) the attmnt using xdgopen */
/* for server */
gboolean list_commands; /* dump documentations for server
* commands */
gboolean commands; /* dump documentations for server
* commands */
/* options for mu-script */
gchar *script; /* script to run */

View File

@ -118,16 +118,9 @@ clicked."
"* "
(propertize "mu4e - mu for emacs version " 'face 'mu4e-title-face)
(propertize mu4e-mu-version 'face 'mu4e-header-key-face)
;; show some server properties; in this case; a big C when there's
;; crypto support, a big G when there's Guile support
" "
(propertize
(concat
(when (plist-get mu4e~server-props :crypto) "C")
(when (plist-get mu4e~server-props :guile) "G")
(when (plist-get mu4e~server-props :mux) "X"))
'face 'mu4e-title-face)
(propertize "; (in store: " 'face 'mu4e-title-face)
(propertize (format "%s" (plist-get mu4e~server-props :doccount)) 'face 'mu4e-header-key-face)
(propertize " messages)" 'face 'mu4e-title-face)
"\n\n"
(propertize " Basics\n\n" 'face 'mu4e-title-face)

View File

@ -274,8 +274,7 @@ Start the process if needed."
(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"))
(mu4e~call-mu '(quit)))
;; try sending SIGINT (C-c) to process, so it can exit gracefully
(ignore-errors
(signal-process proc 'SIGINT))))
@ -307,11 +306,18 @@ Start the process if needed."
(t
(error "Something bad happened to the mu server process")))))
(defun mu4e~call-mu (form)
"Call 'mu' with some command."
(unless (mu4e~proc-running-p) (mu4e~proc-start))
(let ((cmd (format "%S" form)))
(mu4e-log 'to-server "%s" cmd)
(process-send-string mu4e~proc-process (concat cmd "\n"))))
(defun mu4e~docid-msgid-param (docid-or-msgid)
"Construct a backend parameter based on DOCID-OR-MSGID."
(if (stringp docid-or-msgid)
(concat "msgid:" (mu4e~escape docid-or-msgid))
(format "docid:%d" docid-or-msgid)))
`(:msgid ,(mu4e~escape docid-or-msgid))
`(:docid ,docid-or-msgid)))
(defun mu4e~proc-find (query threads sortfield sortdir maxnum skip-dups
include-related)
@ -330,20 +336,14 @@ For each result found, a function is called, depending on the
kind of result. The variables `mu4e-error-func' contain the
function that will be called for, resp., a message (header row)
or an error."
(mu4e~proc-send-command
(concat
"cmd:find query:%s threads:%s sortfield:%s reverse:%s maxnum:%d "
"skip-dups:%s include-related:%s")
(base64-encode-string (encode-coding-string query 'utf-8 t) t)
(if threads "true" "false")
;; sortfield is e.g. ':subject'; this removes the ':'
(if (null sortfield) "nil" (substring (symbol-name sortfield) 1))
;; TODO: use ascending/descending in backend too (it's clearer than
;; 'reverse'
(if (eq sortdir 'descending) "true" "false")
(if maxnum maxnum -1)
(if skip-dups "true" "false")
(if include-related "true" "false")))
(mu4e~call-mu `(find
:query ,query
:threads ,threads
;; :sortfield ,sortfield
:sortdir ,sortdir
:maxnum ,maxnum
:skip-dups ,skip-dups
:include-related ,include-related)))
(defun mu4e~proc-move (docid-or-msgid &optional maildir flags no-view)
"Move message identified by DOCID-OR-MSGID.
@ -394,40 +394,32 @@ Returns either (:update ... ) or (:error ) sexp, which are handled my
(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 "")
(or path "")
(format "newname:%s" rename)
(format "noview:%s" (if no-view "true" "false")))))
(mu4e~call-mu `(move
:docid ,(if (stringp docid-or-msgid) nil docid-or-msgid)
:msgid ,(if (stringp docid-or-msgid) docid-or-msgid nil)
:flags ,(or flags nil)
:maildir ,(or maildir nil)
:rename ,(and maildir mu4e-change-filenames-when-moving)
:noview ,no-view))))
(defun mu4e~proc-index (path my-addresses cleanup lazy-check)
"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 ","))))
(if addrs
(mu4e~proc-send-command
"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))))
(mu4e~call-mu `(index
:my-addresses ,my-addresses
:cleanup ,cleanup
:lazy-check ,lazy-check)))
(defun mu4e~proc-add (path maildir)
"Add the message at PATH to the database.
With MAILDIR set to the maildir this message resides in,
e.g. '/drafts'; if this works, we will receive (:info add :path
<path> :docid <docid>) as well as (:update <msg-sexp>)."
(mu4e~proc-send-command "cmd:add path:%s %s"
(mu4e~escape path)
(if maildir
(format "maildir:%s" (mu4e~escape maildir))
"")))
(mu4e~call-mu `(add
:path ,path
:maildir ,maildir)))
(defun mu4e~proc-sent (path maildir)
"Add the message at PATH to the database.
@ -436,9 +428,9 @@ e.g. '/drafts'.
if this works, we will receive (:info add :path <path> :docid
<docid> :fcc <path>)."
(mu4e~proc-send-command "cmd:sent path:%s maildir:%s"
(mu4e~escape path) (mu4e~escape maildir)))
(mu4e~call-mu `(sent
:path ,path
:maildir ,maildir)))
(defun mu4e~proc-compose (type decrypt &optional docid)
"Compose a message of TYPE, DECRYPT it and use DOCID.
@ -448,49 +440,37 @@ editing, resending) with DOCID or nil for type `new'.
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))
(unless (eq (null docid) (eq type 'new))
(mu4e-error "`new' implies docid not-nil, and vice-versa"))
(mu4e~proc-send-command
"cmd:compose type:%s docid:%d extract-encrypted:%s use-agent:true"
(symbol-name type) docid (if decrypt "true" "false")))
(mu4e~call-mu `(compose
:type ,type
:decrypt ,decrypt
:docid ,docid)))
(defun mu4e~proc-mkdir (path)
"Create a new maildir-directory at filesystem PATH."
(mu4e~proc-send-command "cmd:mkdir path:%s" (mu4e~escape path)))
;;(mu4e~proc-send-command "cmd:mkdir path:%s" (mu4e~escape path))
(mu4e~call-mu `(mkdir :path ,path)))
(defun mu4e~proc-extract (action docid partidx decrypt
(defun mu4e~proc-extract (action docid index decrypt
&optional path what param)
"Perform ACTION on part with DOCID PARTIDX DECRYPT PATH WHAT PARAM.
"Perform ACTION on part with DOCID INDEX 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 <path> :what <what> :param <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))))
))
(mu4e~proc-send-command "%s" cmd)))
(mu4e~call-mu `(extract
:action ,action
:docid ,docid
:index ,index
:decrypt ,decrypt
:path ,path
:what ,what
:param ,param)))
(defun mu4e~proc-ping ()
"Sends a ping to the mu server, expecting a (:pong ...) in response."
(mu4e~proc-send-command "cmd:ping"))
(mu4e~call-mu '(ping)))
(defun mu4e~proc-contacts (personal after tstamp)
"Ask for contacts with PERSONAL AFTER TSTAMP.
@ -498,11 +478,10 @@ S-expression (:contacts (<list>) :tstamp \"<tstamp>\") is expected in
response. If PERSONAL is non-nil, only get personal contacts, if
AFTER is non-nil, get only contacts seen AFTER (the time_t
value)."
(mu4e~proc-send-command
"cmd:contacts personal:%s after:%d tstamp:%s"
(if personal "true" "false")
(or after 0)
(or tstamp "0")))
(mu4e~call-mu `(contacts
:personal ,personal
;; :after ,(or after nil)
:tstamp ,(or tstamp nil))))
(defun mu4e~proc-view (docid-or-msgid &optional images decrypt)
"Get a message DOCID-OR-MSGID.
@ -510,11 +489,11 @@ Optionally, if IMAGES is non-nil, backend will any images
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)
(if images "true" "false")
(if decrypt "true" "false")))
(mu4e~call-mu `(view
:docid ,(if (stringp docid-or-msgid) nil docid-or-msgid)
:msgid ,(if (stringp docid-or-msgid) docid-or-msgid nil)
:extract-images ,images
:extract-encrypt ,decrypt)))
(defun mu4e~proc-view-path (path &optional images decrypt)
"View message at PATH..
@ -522,18 +501,17 @@ 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'. Optionally DECRYPT."
(mu4e~proc-send-command
"cmd:view path:%s extract-images:%s extract-encrypted:%s use-agent:true"
(mu4e~escape path)
(if images "true" "false")
(if decrypt "true" "false")))
(mu4e~call-mu `(view-path
:path ,path
:images ,images
:decrypt ,decrypt)))
(defun mu4e~proc-remove (docid)
"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))
(mu4e~call-mu `(remove :docid ,docid)))
(provide 'mu4e-proc)
;;; mu4e-proc.el ends here