* when forwarding, include attachments from original

This commit is contained in:
djcb 2012-01-14 12:55:50 +02:00
parent ff04b20712
commit 6e3e425c66
5 changed files with 112 additions and 15 deletions

View File

@ -275,10 +275,11 @@ updated as well, with all processed sexp data removed."
(funcall mu4e-proc-remove-func (plist-get sexp :remove))) (funcall mu4e-proc-remove-func (plist-get sexp :remove)))
;; start composing a new message ;; start composing a new message
((plist-get sexp :compose) ((plist-get sexp :compose-type)
(funcall mu4e-proc-compose-func (funcall mu4e-proc-compose-func
(plist-get sexp :compose-type) (plist-get sexp :compose-type)
(plist-get sexp :compose))) (plist-get sexp :original)
(plist-get sexp :include)))
;; get some info ;; get some info
((plist-get sexp :info) ((plist-get sexp :info)

View File

@ -283,7 +283,7 @@ use the new docid. Returns the full path to the new message."
draft)) 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. "Create a new draft message, or open an existing one.
COMPOSE-TYPE determines the kind of message to compose and is a 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 When COMPOSE-TYPE is `reply' or `forward', MSG should be a message
plist. If COMPOSE-TYPE is `new', MSG should be nil. 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 <filename> :mime-type <mime-type> :disposition <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 The name of the draft folder is constructed from the concatenation
of `mu4e-maildir' and `mu4e-drafts-folder' (therefore, these must be of `mu4e-maildir' and `mu4e-drafts-folder' (therefore, these must be
set). set).
@ -307,17 +316,25 @@ using Gnus' `message-mode'."
(unless mu4e-drafts-folder (error "mu4e-drafts-folder not set")) (unless mu4e-drafts-folder (error "mu4e-drafts-folder not set"))
(let ((draft (let ((draft
(if (member compose-type '(reply forward new)) (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) (if (eq compose-type 'edit)
(plist-get 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) (unless (file-readable-p draft)
(error "Cannot read %s" path)) (error "Cannot read %s" draft))
(find-file draft) (find-file draft)
(message-mode) (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) (make-local-variable 'write-file-functions)
;; update the db when the file is saved...] ;; update the db when the file is saved...]
@ -333,7 +350,7 @@ using Gnus' `message-mode'."
"^User-agent:"))) "^User-agent:")))
(message-hide-headers)) (message-hide-headers))
(if (eq compose-type 'new) (if (member compose-type '(new forward))
(message-goto-to) (message-goto-to)
(message-goto-body)))) (message-goto-body))))

View File

@ -64,7 +64,6 @@ and finally, we receive:
.fi .fi
.TP .TP
.B move .B move
@ -138,13 +137,21 @@ particular e-mail message.
.TP .TP
.B compose .B compose
Using the \fBcompose\fR command, we get the (unchanged) message, and tell what Using the \fBcompose\fR command, we get the (original) message, and tell what
to do with it. The user-interface is then expect to pre-process the message, 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. e.g. set the subject, sender and recipient for a reply message.
.nf .nf
-> compose <reply|forward|edit> <docid> -> compose <reply|forward|edit> <docid>
<- (:compose <s-exp> :compose-type <reply|forward|edit>) <- (:compose-type <reply|forward|edit> :original <s-exp> :include (<list-of-attachments))
.fi
The <list-of-attachments> 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 <filename> :mime-type <mime-type> :disposition <disposition>)
.fi .fi

View File

@ -749,6 +749,72 @@ cmd_view (MuStore *store, MuQuery *query, GSList *args, GError **err)
return MU_OK; 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 <filename> :mime-type <mime-type> :disposition
* <attachment|inline>) ... )
*
*/
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 static MuError
@ -756,7 +822,7 @@ cmd_compose (MuStore *store, GSList *args, GError **err)
{ {
MuMsg *msg; MuMsg *msg;
unsigned docid; unsigned docid;
char *sexp; char *sexp, *atts;
const char* ctype; const char* ctype;
return_if_fail_param_num (args, 2, 2, return_if_fail_param_num (args, 2, 2,
@ -779,11 +845,17 @@ cmd_compose (MuStore *store, GSList *args, GError **err)
"failed to get message"); "failed to get message");
sexp = mu_msg_to_sexp (msg, docid, NULL, FALSE); 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 (sexp);
g_free (atts);
return MU_OK; return MU_OK;
} }

View File

@ -527,7 +527,7 @@ mu_msg_part_looks_like_attachment (MuMsgPart *part, gboolean include_inline)
{ {
g_return_val_if_fail (part, FALSE); g_return_val_if_fail (part, FALSE);
if (!part->disposition) if (!part->disposition||!part->type || !part->file_name)
return FALSE; return FALSE;
if (g_ascii_strcasecmp (part->disposition, if (g_ascii_strcasecmp (part->disposition,