* don't save drafts immediately, and do the post-sending stuff not in hooks,

but rather by a special 'sent-' message handler
This commit is contained in:
djcb
2012-03-27 21:15:47 +03:00
parent 86a1424b17
commit c2e3eac1de
4 changed files with 92 additions and 71 deletions

View File

@ -53,24 +53,14 @@
"Keymap for the *mu4e-main* buffer.") "Keymap for the *mu4e-main* buffer.")
(fset 'mu4e-main-mode-map mu4e-main-mode-map) (fset 'mu4e-main-mode-map mu4e-main-mode-map)
(defun mu4e-main-mode () (define-derived-mode mu4e-main-mode special-mode "mu4e:main"
"Major mode for the mu4e main screen. "Major mode for the mu4e main screen.
\\{mu4e-main-mode-map}." \\{mu4e-main-mode-map}."
(interactive)
(kill-all-local-variables)
(use-local-map mu4e-main-mode-map) (use-local-map mu4e-main-mode-map)
(setq (setq
major-mode 'mu4e-main-mode
mode-name "mu4e-main"
truncate-lines t truncate-lines t
buffer-read-only t
overwrite-mode 'overwrite-mode-binary)) overwrite-mode 'overwrite-mode-binary))
(put 'mu4e-main-mode 'mode-class 'special)
(defun mu4e-action-str (str &optional func-or-shortcut) (defun mu4e-action-str (str &optional func-or-shortcut)
"Highlight the first occurence of [..] in STR. If "Highlight the first occurence of [..] in STR. If

View File

@ -282,15 +282,9 @@ use the new docid. Returns the full path to the new message."
(new (mu4e-send-create-new)) (new (mu4e-send-create-new))
(t (error "unsupported compose-type %S" compose-type))))) (t (error "unsupported compose-type %S" compose-type)))))
(when str (when str
(with-temp-file draft (with-current-buffer (find-file-noselect draft)
(insert str) (insert str)))
(write-file draft))) draft)) ;; return the draft buffer file
;; save our file immediately, add add it to the db; thus, we can retrieve
;; the new docid from `mu4e-path-docid-map'.
(mu4e-proc-add draft mu4e-drafts-folder)
draft))
(defun mu4e-send-compose-handler (compose-type &optional original-msg includes) (defun mu4e-send-compose-handler (compose-type &optional original-msg includes)
"Create a new draft message, or open an existing one. "Create a new draft message, or open an existing one.
@ -330,9 +324,6 @@ using Gnus' `message-mode'."
(plist-get original-msg :path) (plist-get original-msg :path)
(error "unsupported compose-type %S" compose-type))))) (error "unsupported compose-type %S" compose-type)))))
(unless (file-readable-p draft)
(error "Cannot read %s" draft))
(find-file draft) (find-file draft)
(message-mode) (message-mode)
@ -344,15 +335,21 @@ using Gnus' `message-mode'."
(mml-attach-file (mml-attach-file
(plist-get att :file-name) (plist-get att :mime-type)))) (plist-get att :file-name) (plist-get att :mime-type))))
(make-local-variable 'write-file-functions) (make-local-variable 'after-save-hook)
;; update the db when the file is saved...] ;; update the db when the file is saved...]
(add-to-list 'write-file-functions (add-hook 'after-save-hook
(lambda() (mu4e-proc-add (buffer-file-name) mu4e-drafts-folder))) (lambda() (mu4e-proc-add (buffer-file-name) mu4e-drafts-folder)))
;; hook our functions up with sending of the message ;; notify the backend that a message has been sent. The backend will respond
(add-hook 'message-sent-hook 'mu4e-send-save-copy-maybe nil t) ;; with (:sent ...) sexp, which is handled in .
(add-hook 'message-sent-hook 'mu4e-send-set-parent-flag nil t) (add-hook 'message-sent-hook
(lambda ()
(mu4e-proc-sent (buffer-file-name) mu4e-drafts-folder)))
;; register the function; this function will be called when the '(:sent...)'
;; message is received (see mu4e-proc.el) with parameters docid and path
(setq mu4e-proc-sent-func 'mu4e-sent-handler)
(let ((message-hidden-headers (let ((message-hidden-headers
`("^References:" "^Face:" "^X-Face:" "^X-Draft-From:" `("^References:" "^Face:" "^X-Face:" "^X-Draft-From:"
@ -365,18 +362,27 @@ using Gnus' `message-mode'."
(defun mu4e-send-save-copy-maybe () (defun mu4e-sent-handler (docid path)
"If `mu4e-save-sent-messages-behavior' is a symbol 'delete, move "Handler function, called with DOCID and PATH for the just-sent
the message in this buffer to the sent folder. Otherwise, delete message."
the draft message. This is meant to be called from message mode's ;; for Forward ('Passed') and Replied messages, try to set the appropriate
`message-sent-hook'." ;; flag at the message forwarded or replied-to
(let ((docid (gethash (buffer-file-name) mu4e-path-docid-map))) (mu4e-send-set-parent-flag docid path)
(unless docid (error "unknown message (%S)" (buffer-file-name))) ;; handle the draft -- should it be moved to the send folder, or elsewhere?
(mu4e-send-save-copy-maybe docid path))
(defun mu4e-send-save-copy-maybe (docid path)
"Handler function, called with DOCID and PATH for the just-sent
message."
;; first, what to do with the draft message in PATH?
(with-current-buffer (find-file-noselect path)
(if (eq mu4e-sent-messages-behavior 'delete) (if (eq mu4e-sent-messages-behavior 'delete)
(progn (progn
(save-buffer) (save-buffer)
(mu4e-proc-remove-msg docid)) ;; remove it (mu4e-proc-remove-msg docid)) ;; remove it
(progn ;; try to save the message the sent folder ;; otherwise,
(progn ;; prepare the message for saving
(save-excursion (save-excursion
(goto-char (point-min)) (goto-char (point-min))
;; remove the --text follows this line-- separator ;; remove the --text follows this line-- separator
@ -390,10 +396,9 @@ using Gnus' `message-mode'."
(mu4e-proc-move-msg docid mu4e-sent-folder "-T-D+S"))))))) (mu4e-proc-move-msg docid mu4e-sent-folder "-T-D+S")))))))
(defun mu4e-send-set-parent-flag (docid path)
(defun mu4e-send-set-parent-flag () "Set the 'replied' \"R\" flag on messages we replied to, and the
"Set the 'replied' flag on messages we replied to, and the 'passed' \"F\" flag on message we have forwarded.
'passed' flag on message we have forwarded.
If a message has a 'in-reply-to' header, it is considered a reply If a message has a 'in-reply-to' header, it is considered a reply
to the message with the corresponding message id. If it does not to the message with the corresponding message id. If it does not
@ -404,10 +409,8 @@ corresponding with the /last/ message-id in the references header.
Now, if the message has been determined to be either a forwarded Now, if the message has been determined to be either a forwarded
message or a reply, we instruct the server to update that message message or a reply, we instruct the server to update that message
with resp. the 'P' (passed) flag for a forwarded message, or the with resp. the 'P' (passed) flag for a forwarded message, or the
'R' flag for a replied message. 'R' flag for a replied message."
(with-current-buffer (find-file-noselect path)
This is meant to be called from message mode's
`message-sent-hook'."
(let ((in-reply-to (message-fetch-field "in-reply-to")) (let ((in-reply-to (message-fetch-field "in-reply-to"))
(forwarded-from) (forwarded-from)
(references (message-fetch-field "references"))) (references (message-fetch-field "references")))
@ -425,6 +428,6 @@ This is meant to be called from message mode's
(when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to)) (when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to))
(mu4e-proc-flag (match-string 1 in-reply-to) "+R")) (mu4e-proc-flag (match-string 1 in-reply-to) "+R"))
(when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from)) (when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from))
(mu4e-proc-flag (match-string 1 forwarded-from) "+P")))) (mu4e-proc-flag (match-string 1 forwarded-from) "+P")))))
(provide 'mu4e-send) (provide 'mu4e-send)

View File

@ -189,6 +189,22 @@ Using the \fBadd\fR command, we can add a message to the database.
<- (:info add :path <path> :docid <docid>) <- (:info add :path <path> :docid <docid>)
.fi .fi
.TP
.B sent
With the \fBsent\fR command, we tell the backend that a message will be sent.
.nf
-> sent <path> <maildir>
<- (:sent :path <path> :docid <docid>)
.fi
In the frontend, this message can then be used to trigger moving the message
from the draft folder to the sent folder, setting the Replied/Passed flags on
the parent messages.
.TP .TP
.B mkdir .B mkdir

View File

@ -170,6 +170,7 @@ enum _Cmd {
CMD_QUIT, CMD_QUIT,
CMD_REMOVE, CMD_REMOVE,
CMD_SAVE, CMD_SAVE,
CMD_SENT,
CMD_PING, CMD_PING,
CMD_VIEW, CMD_VIEW,
@ -197,6 +198,7 @@ cmd_from_string (const char *str)
{ CMD_QUIT, "quit"}, { CMD_QUIT, "quit"},
{ CMD_REMOVE, "remove" }, { CMD_REMOVE, "remove" },
{ CMD_SAVE, "save"}, { CMD_SAVE, "save"},
{ CMD_SENT, "sent"},
{ CMD_PING, "ping"}, { CMD_PING, "ping"},
{ CMD_VIEW, "view"} { CMD_VIEW, "view"}
}; };
@ -856,7 +858,7 @@ index_msg_cb (MuIndexStats *stats, void *user_data)
if (MU_CAUGHT_SIGNAL) if (MU_CAUGHT_SIGNAL)
return MU_STOP; return MU_STOP;
if (stats->_processed % 500) if (stats->_processed % 1000)
return MU_OK; return MU_OK;
send_expr ("(:info index :status running " send_expr ("(:info index :status running "
@ -867,14 +869,16 @@ index_msg_cb (MuIndexStats *stats, void *user_data)
} }
static MuError static MuError
cmd_add (MuStore *store, GSList *args, GError **err) cmd_add_or_sent (MuStore *store, Cmd add_or_sent, GSList *args, GError **err)
{ {
unsigned docid; unsigned docid;
const char *path, *maildir; const char *path, *maildir;
gchar *escpath; gchar *escpath;
g_return_val_if_fail (add_or_sent == CMD_ADD || add_or_sent == CMD_SENT,
MU_ERROR_INTERNAL);
return_if_fail_param_num (args, 2, 2, return_if_fail_param_num (args, 2, 2,
"usage: add <path> <maildir>"); "usage: add|sent <path> <maildir>");
path = (const char*)args->data; path = (const char*)args->data;
maildir = (const char*)g_slist_nth (args, 1)->data; maildir = (const char*)g_slist_nth (args, 1)->data;
@ -885,15 +889,20 @@ cmd_add (MuStore *store, GSList *args, GError **err)
"failed to add path '%s'", path); "failed to add path '%s'", path);
escpath = mu_str_escape_c_literal (path, TRUE); escpath = mu_str_escape_c_literal (path, TRUE);
send_expr ("(:info add :path %s :docid %u)", escpath, docid);
if (add_or_sent == CMD_ADD)
send_expr ("(:info add :path %s :docid %u)",
escpath, docid);
else
send_expr ("(:sent t :path %s :docid %u)",
escpath, docid);
g_free (escpath); g_free (escpath);
return MU_OK; return MU_OK;
} }
static MuError static MuError
cmd_index (MuStore *store, GSList *args, GError **err) cmd_index (MuStore *store, GSList *args, GError **err)
{ {
@ -953,7 +962,8 @@ handle_command (Cmd cmd, MuStore *store, MuQuery *query, GSList *args,
switch (cmd) { switch (cmd) {
case CMD_ADD: rv = cmd_add (store, args, err); break; case CMD_ADD: rv = cmd_add_or_sent (store, CMD_ADD,
args, err); break;
case CMD_COMPOSE: rv = cmd_compose (store, args, err); break; case CMD_COMPOSE: rv = cmd_compose (store, args, err); break;
case CMD_FIND: rv = cmd_find (store, query, args, err); break; case CMD_FIND: rv = cmd_find (store, query, args, err); break;
case CMD_FLAG: rv = cmd_flag (store, query, args, err); break; case CMD_FLAG: rv = cmd_flag (store, query, args, err); break;
@ -964,6 +974,8 @@ handle_command (Cmd cmd, MuStore *store, MuQuery *query, GSList *args,
case CMD_QUIT: rv = cmd_quit (args, err); break; case CMD_QUIT: rv = cmd_quit (args, err); break;
case CMD_REMOVE: rv = cmd_remove (store, args, err); break; case CMD_REMOVE: rv = cmd_remove (store, args, err); break;
case CMD_SAVE: rv = cmd_save (store, args, err); break; case CMD_SAVE: rv = cmd_save (store, args, err); break;
case CMD_SENT: rv = cmd_add_or_sent (store, CMD_SENT,
args, err); break;
case CMD_PING: rv = cmd_ping (store, args, err); break; case CMD_PING: rv = cmd_ping (store, args, err); break;
case CMD_VIEW: rv = cmd_view (store, query, args, err); break; case CMD_VIEW: rv = cmd_view (store, query, args, err); break;