* 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:
@ -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
|
||||||
|
|||||||
@ -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,27 +409,25 @@ 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
|
(let ((in-reply-to (message-fetch-field "in-reply-to"))
|
||||||
`message-sent-hook'."
|
(forwarded-from)
|
||||||
(let ((in-reply-to (message-fetch-field "in-reply-to"))
|
(references (message-fetch-field "references")))
|
||||||
(forwarded-from)
|
(unless in-reply-to
|
||||||
(references (message-fetch-field "references")))
|
(when references
|
||||||
(unless in-reply-to
|
(with-temp-buffer ;; inspired by `message-shorten-references'.
|
||||||
(when references
|
(insert references)
|
||||||
(with-temp-buffer ;; inspired by `message-shorten-references'.
|
(goto-char (point-min))
|
||||||
(insert references)
|
(let ((refs))
|
||||||
(goto-char (point-min))
|
(while (re-search-forward "<[^ <]+@[^ <]+>" nil t)
|
||||||
(let ((refs))
|
(push (match-string 0) refs))
|
||||||
(while (re-search-forward "<[^ <]+@[^ <]+>" nil t)
|
;; the last will the first
|
||||||
(push (match-string 0) refs))
|
(setq forwarded-from (first refs))))))
|
||||||
;; the last will the first
|
;; remove the <>
|
||||||
(setq forwarded-from (first refs))))))
|
(when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to))
|
||||||
;; remove the <>
|
(mu4e-proc-flag (match-string 1 in-reply-to) "+R"))
|
||||||
(when (and in-reply-to (string-match "<\\(.*\\)>" in-reply-to))
|
(when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from))
|
||||||
(mu4e-proc-flag (match-string 1 in-reply-to) "+R"))
|
(mu4e-proc-flag (match-string 1 forwarded-from) "+P")))))
|
||||||
(when (and forwarded-from (string-match "<\\(.*\\)>" forwarded-from))
|
|
||||||
(mu4e-proc-flag (match-string 1 forwarded-from) "+P"))))
|
|
||||||
|
|
||||||
(provide 'mu4e-send)
|
(provide 'mu4e-send)
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user