From a393429f01e63aa37f58f8cbe4a810e59852fa61 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 29 Oct 2020 15:18:36 -0400 Subject: Implement JavaScript UI for attachments This one is a bit of a doozy. A summary of the changes: - Session has grown storage for attachments which have been uploaded but not yet sent. - The list of attachments on a message is refcounted so that we can clean up the temporary files only after it's done with - i.e. after copying to Sent and after all of the SMTP attempts are done. - Abandoned attachments are cleared out on process shutdown. Future work: - Add a limit to the maximum number of pending attachments the user can have in the session. - Periodically clean out abandoned attachments? --- plugins/base/smtp.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'plugins/base/smtp.go') diff --git a/plugins/base/smtp.go b/plugins/base/smtp.go index dc8211e..a6cfd3d 100644 --- a/plugins/base/smtp.go +++ b/plugins/base/smtp.go @@ -53,6 +53,37 @@ func (att *formAttachment) Filename() string { return att.FileHeader.Filename } +type refcountedAttachment struct { + *multipart.FileHeader + *multipart.Form + refs int +} + +func (att *refcountedAttachment) Open() (io.ReadCloser, error) { + return att.FileHeader.Open() +} + +func (att *refcountedAttachment) MIMEType() string { + // TODO: retain params, e.g. "charset"? + t, _, _ := mime.ParseMediaType(att.FileHeader.Header.Get("Content-Type")) + return t +} + +func (att *refcountedAttachment) Filename() string { + return att.FileHeader.Filename +} + +func (att *refcountedAttachment) Ref() { + att.refs += 1 +} + +func (att *refcountedAttachment) Unref() { + att.refs -= 1 + if att.refs == 0 { + att.Form.RemoveAll() + } +} + type imapAttachment struct { Mailbox string Uid uint32 @@ -176,6 +207,22 @@ func (msg *OutgoingMessage) WriteTo(w io.Writer) error { return nil } +func (msg *OutgoingMessage) Ref() { + for _, a := range msg.Attachments { + if a, ok := a.(*refcountedAttachment); ok { + a.Ref() + } + } +} + +func (msg *OutgoingMessage) Unref() { + for _, a := range msg.Attachments { + if a, ok := a.(*refcountedAttachment); ok { + a.Unref() + } + } +} + func sendMessage(c *smtp.Client, msg *OutgoingMessage) error { if err := c.Mail(msg.From, nil); err != nil { return fmt.Errorf("MAIL FROM failed: %v", err) -- cgit v1.2.3