diff --git a/emacs/mu4e-proc.el b/emacs/mu4e-proc.el index 43f09258..dcc8af60 100644 --- a/emacs/mu4e-proc.el +++ b/emacs/mu4e-proc.el @@ -275,10 +275,11 @@ updated as well, with all processed sexp data removed." (funcall mu4e-proc-remove-func (plist-get sexp :remove))) ;; start composing a new message - ((plist-get sexp :compose) + ((plist-get sexp :compose-type) (funcall mu4e-proc-compose-func (plist-get sexp :compose-type) - (plist-get sexp :compose))) + (plist-get sexp :original) + (plist-get sexp :include))) ;; get some info ((plist-get sexp :info) diff --git a/emacs/mu4e-send.el b/emacs/mu4e-send.el index d659c33c..4965c369 100644 --- a/emacs/mu4e-send.el +++ b/emacs/mu4e-send.el @@ -283,7 +283,7 @@ use the new docid. Returns the full path to the new message." draft)) -(defun mu4e-send-compose-handler (compose-type &optional msg) +(defun mu4e-send-compose-handler (compose-type &optional original-msg includes) "Create a new draft message, or open an existing one. COMPOSE-TYPE determines the kind of message to compose and is a @@ -293,6 +293,15 @@ editing existing messages. When COMPOSE-TYPE is `reply' or `forward', MSG should be a message plist. If COMPOSE-TYPE is `new', MSG should be nil. +Optionally (when forwarding, replying) ORIGINAL-MSG is the original +message we will forward / reply to. + +Optionally (when forwarding) INCLUDES contains a list of + (:file-name :mime-type :disposition ) +for the attachements to include; file-name refers to +a file which our backend has conveniently saved for us (as a +tempfile). + The name of the draft folder is constructed from the concatenation of `mu4e-maildir' and `mu4e-drafts-folder' (therefore, these must be set). @@ -307,17 +316,25 @@ using Gnus' `message-mode'." (unless mu4e-drafts-folder (error "mu4e-drafts-folder not set")) (let ((draft (if (member compose-type '(reply forward new)) - (mu4e-send-open-draft compose-type msg) + (mu4e-send-open-draft compose-type original-msg) (if (eq compose-type 'edit) - (plist-get msg :path) + (plist-get original-msg :path) (error "unsupported compose-type %S" compose-type))))) (unless (file-readable-p draft) - (error "Cannot read %s" path)) + (error "Cannot read %s" draft)) (find-file draft) (message-mode) + ;; include files -- e.g. when forwarding a message with attachments, + ;; we take those from the original. + (save-excursion + (goto-char (point-max)) ;; put attachments at the end + (dolist (att includes) + (mml-attach-file + (plist-get att :file-name) (plist-get att :mime-type)))) + (make-local-variable 'write-file-functions) ;; update the db when the file is saved...] @@ -333,7 +350,7 @@ using Gnus' `message-mode'." "^User-agent:"))) (message-hide-headers)) - (if (eq compose-type 'new) + (if (member compose-type '(new forward)) (message-goto-to) (message-goto-body)))) diff --git a/man/mu-server.1 b/man/mu-server.1 index 7f22d053..43c9b9a9 100644 --- a/man/mu-server.1 +++ b/man/mu-server.1 @@ -64,7 +64,6 @@ and finally, we receive: .fi - .TP .B move @@ -138,13 +137,21 @@ particular e-mail message. .TP .B compose -Using the \fBcompose\fR command, we get the (unchanged) message, and tell what -to do with it. The user-interface is then expect to pre-process the message, +Using the \fBcompose\fR command, we get the (original) message, and tell what +to do with it. The user-interface is then expected to pre-process the message, e.g. set the subject, sender and recipient for a reply message. .nf -> compose -<- (:compose :compose-type ) +<- (:compose-type :original :include ( is an s-expression describing the attachments to +include in the message; this currently only applies to message we are +forwarding. This s-exprssion looks like: + +.nf + (:file-name :mime-type :disposition ) .fi diff --git a/src/mu-cmd-server.c b/src/mu-cmd-server.c index f594ad1b..4f4cc876 100644 --- a/src/mu-cmd-server.c +++ b/src/mu-cmd-server.c @@ -749,6 +749,72 @@ cmd_view (MuStore *store, MuQuery *query, GSList *args, GError **err) return MU_OK; } +static void +each_part (MuMsg *msg, MuMsgPart *part, GSList **attlist) +{ + char *att, *cachefile; + GError *err; + + /* exclude things that don't look like proper attachments */ + if (!mu_msg_part_looks_like_attachment(part, TRUE)) + return; + + /* save the attachment to some temp file */ + cachefile = mu_msg_part_filepath_cache (msg, part->index); + if (!cachefile) { + server_error (NULL, MU_ERROR_FILE, + "could not determine cachefile name"); + return; + } + + err = NULL; + if (!mu_msg_part_save (msg, cachefile, part->index, FALSE, TRUE, &err)) { + server_error (&err, MU_ERROR_FILE, + "could not save %s", cachefile); + goto leave; + } + + att = g_strdup_printf ( + "(:file-name \"%s\" :mime-type \"%s/%s\" :disposition \"%s\")", + cachefile, + part->type, part->subtype, + part->disposition ? part->disposition : "attachment"); + + *attlist = g_slist_append (*attlist, att); + +leave: + g_clear_error (&err); + g_free (cachefile); +} + + +/* take the attachments of msg, save them as tmp files, and return + * as sexp (as a string) describing them + * + * ((:name :mime-type :disposition + * ) ... ) + * + */ +static gchar* +include_attachments (MuMsg *msg) +{ + GSList *attlist, *cur; + GString *gstr; + + attlist = NULL; + mu_msg_part_foreach (msg,(MuMsgPartForeachFunc)each_part, + &attlist); + + gstr = g_string_sized_new (512); + gstr = g_string_append_c (gstr, '('); + for (cur = attlist; cur; cur = g_slist_next (cur)) + g_string_append (gstr, (gchar*)cur->data); + gstr = g_string_append_c (gstr, ')'); + + mu_str_free_list (attlist); + + return g_string_free (gstr, FALSE); +} static MuError @@ -756,7 +822,7 @@ cmd_compose (MuStore *store, GSList *args, GError **err) { MuMsg *msg; unsigned docid; - char *sexp; + char *sexp, *atts; const char* ctype; return_if_fail_param_num (args, 2, 2, @@ -779,11 +845,17 @@ cmd_compose (MuStore *store, GSList *args, GError **err) "failed to get message"); sexp = mu_msg_to_sexp (msg, docid, NULL, FALSE); - mu_msg_unref (msg); + if (strcmp(ctype, "forward") == 0) + atts = include_attachments (msg); + else + atts = NULL; - send_expr ("(:compose %s :compose-type %s)", sexp, ctype); + mu_msg_unref (msg); + send_expr ("(:compose-type %s :original %s :include %s)", + ctype, sexp, atts ? atts : "()"); g_free (sexp); + g_free (atts); return MU_OK; } diff --git a/src/mu-msg-part.c b/src/mu-msg-part.c index f6f98843..bc061110 100644 --- a/src/mu-msg-part.c +++ b/src/mu-msg-part.c @@ -527,7 +527,7 @@ mu_msg_part_looks_like_attachment (MuMsgPart *part, gboolean include_inline) { g_return_val_if_fail (part, FALSE); - if (!part->disposition) + if (!part->disposition||!part->type || !part->file_name) return FALSE; if (g_ascii_strcasecmp (part->disposition,