summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2019-05-14 13:07:48 -0400
committerDrew DeVault <sir@cmpwn.com>2019-05-14 13:07:48 -0400
commit6c36e04c1f7f7e222c71c5c8e7e7337744fe9c34 (patch)
tree52695aa088a565808275582f138cf673c0066d76
parentd5e82ecfe05065a84f1e13bee44e309b8e1559bd (diff)
downloadaerc-6c36e04c1f7f7e222c71c5c8e7e7337744fe9c34.tar.gz
Add :send-message, prepares & writes email to /tmp
-rw-r--r--commands/compose/send-message.go29
-rw-r--r--go.mod3
-rw-r--r--go.sum5
-rw-r--r--widgets/compose.go79
-rw-r--r--widgets/msgviewer.go11
5 files changed, 121 insertions, 6 deletions
diff --git a/commands/compose/send-message.go b/commands/compose/send-message.go
new file mode 100644
index 0000000..b9fc9d2
--- /dev/null
+++ b/commands/compose/send-message.go
@@ -0,0 +1,29 @@
+package compose
+
+import (
+	"errors"
+	"os"
+
+	"git.sr.ht/~sircmpwn/aerc2/widgets"
+)
+
+func init() {
+	register("send-message", SendMessage)
+}
+
+func SendMessage(aerc *widgets.Aerc, args []string) error {
+	if len(args) > 1 {
+		return errors.New("Usage: send-message")
+	}
+	composer, _ := aerc.SelectedTab().(*widgets.Composer)
+	//config := composer.Config()
+	f, err := os.Create("/tmp/test.eml")
+	if err != nil {
+		panic(err)
+	}
+	_, err = composer.Message(f)
+	if err != nil {
+		panic(err)
+	}
+	return nil
+}
diff --git a/go.mod b/go.mod
index 8e6b573..3d61fa4 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964
 	github.com/emersion/go-imap v1.0.0-beta.4
 	github.com/emersion/go-imap-idle v0.0.0-20180114101550-2af93776db6b
-	github.com/emersion/go-message v0.9.2
+	github.com/emersion/go-message v0.10.0
 	github.com/gdamore/encoding v0.0.0-20151215212835-b23993cbb635 // indirect
 	github.com/gdamore/tcell v1.0.0
 	github.com/go-ini/ini v1.42.0
@@ -20,6 +20,5 @@ require (
 	github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a // indirect
 	github.com/stretchr/testify v1.3.0
 	golang.org/x/sys v0.0.0-20190426135247-a129542de9ae // indirect
-	golang.org/x/text v0.3.2 // indirect
 	gopkg.in/ini.v1 v1.42.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 2baeb49..0134760 100644
--- a/go.sum
+++ b/go.sum
@@ -10,9 +10,14 @@ github.com/emersion/go-imap v1.0.0-beta.4 h1:QglkDofK1RhU471SqcHxzRlSuPsCL6YpFc+
 github.com/emersion/go-imap v1.0.0-beta.4/go.mod h1:mOPegfAgLVXbhRm1bh2JTX08z2Y3HYmKYpbrKDeAzsQ=
 github.com/emersion/go-imap-idle v0.0.0-20180114101550-2af93776db6b h1:q4qkNe/W10qFGD3RWd4meQTkD0+Zrz0L4ekMvlptg60=
 github.com/emersion/go-imap-idle v0.0.0-20180114101550-2af93776db6b/go.mod h1:o14zPKCmEH5WC1vU5SdPoZGgNvQx7zzKSnxPQlobo78=
+github.com/emersion/go-message v0.9.1 h1:s6HoJ6t+1wHWEs0G/QVR1r5bb6nvx2/b6DuQfknit14=
 github.com/emersion/go-message v0.9.1/go.mod h1:m3cK90skCWxm5sIMs1sXxly4Tn9Plvcf6eayHZJ1NzM=
 github.com/emersion/go-message v0.9.2 h1:rJmtGZO1Z71PJDQXbC31EwzlJCsA/8kya6GnebSGp6I=
 github.com/emersion/go-message v0.9.2/go.mod h1:m3cK90skCWxm5sIMs1sXxly4Tn9Plvcf6eayHZJ1NzM=
+github.com/emersion/go-message v0.9.3-0.20190413201152-1e345aac1fa8 h1:yFBYnt6PWNC+PQO70xOI3oayW6alYPRmCN1y0oOfgmQ=
+github.com/emersion/go-message v0.9.3-0.20190413201152-1e345aac1fa8/go.mod h1:XQBEXJJ+6gGcjLsa3rYvGwTC7IJAIWQuxiTIcUKcIbc=
+github.com/emersion/go-message v0.10.0 h1:V8hwhZPNIuAIGNLcMZiCzzavUIiODG3COYLsQMBLvG4=
+github.com/emersion/go-message v0.10.0/go.mod h1:7d2eJfhjiJSnlaKcUPq7sEC7ekWELG6F5Lw2BxOGj6Y=
 github.com/emersion/go-sasl v0.0.0-20161116183048-7e096a0a6197 h1:rDJPbyliyym8ZL/Wt71kdolp6yaD4fLIQz638E6JEt0=
 github.com/emersion/go-sasl v0.0.0-20161116183048-7e096a0a6197/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k=
 github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe h1:40SWqY0zE3qCi6ZrtTf5OUdNm5lDnGnjRSq9GgmeTrg=
diff --git a/widgets/compose.go b/widgets/compose.go
index 5b7a1ba..318bfc4 100644
--- a/widgets/compose.go
+++ b/widgets/compose.go
@@ -1,10 +1,15 @@
 package widgets
 
 import (
+	"io"
 	"io/ioutil"
+	gomail "net/mail"
 	"os"
 	"os/exec"
+	"time"
 
+	"github.com/emersion/go-message"
+	"github.com/emersion/go-message/mail"
 	"github.com/gdamore/tcell"
 	"github.com/mattn/go-runewidth"
 
@@ -79,6 +84,9 @@ func NewComposer(conf *config.AccountConfig) *Composer {
 		focused:   1,
 		focusable: []ui.DrawableInteractive{from, to, subject, term},
 	}
+	c.headers.to = to
+	c.headers.from = from
+	c.headers.subject = subject
 
 	term.OnClose = c.termClosed
 
@@ -107,6 +115,77 @@ func (c *Composer) Focus(focus bool) {
 	c.focusable[c.focused].Focus(focus)
 }
 
+func (c *Composer) Config() *config.AccountConfig {
+	return c.config
+}
+
+// Writes the email to the given writer, and returns a list of recipients
+func (c *Composer) Message(writeto io.Writer) ([]string, error) {
+	// Extract headers from the email, if present
+	c.email.Seek(0, os.SEEK_SET)
+	var (
+		rcpts  []string
+		header mail.Header
+		body   io.Reader
+	)
+	reader, err := mail.CreateReader(c.email)
+	if err == nil {
+		header = reader.Header
+		// TODO: Do we want to let users write a full blown multipart email
+		// into the editor? If so this needs to change
+		part, err := reader.NextPart()
+		if err != nil {
+			return nil, err
+		}
+		body = part.Body
+		defer reader.Close()
+	} else {
+		c.email.Seek(0, os.SEEK_SET)
+		body = c.email
+	}
+	// Update headers
+	// TODO: Custom header fields
+	mhdr := (*message.Header)(&header.Header)
+	mhdr.SetContentType("text/plain", map[string]string{"charset": "UTF-8"})
+	if subject, _ := header.Subject(); subject == "" {
+		header.SetSubject(c.headers.subject.input.String())
+	}
+	if date, err := header.Date(); err != nil && date != (time.Time{}) {
+		header.SetDate(time.Now())
+	}
+	if from, _ := mhdr.Text("From"); from == "" {
+		mhdr.SetText("From", c.headers.from.input.String())
+	}
+	if to := c.headers.to.input.String(); to != "" {
+		// Dammit Simon, this branch is 3x as long as it ought to be because
+		// your types aren't compatible enough with each other
+		to_rcpts, err := gomail.ParseAddressList(to)
+		if err != nil {
+			return nil, err
+		}
+		ed_rcpts, err := header.AddressList("To")
+		if err != nil {
+			return nil, err
+		}
+		for _, addr := range to_rcpts {
+			ed_rcpts = append(ed_rcpts, (*mail.Address)(addr))
+		}
+		header.SetAddressList("To", ed_rcpts)
+		for _, addr := range ed_rcpts {
+			rcpts = append(rcpts, addr.Address)
+		}
+	}
+	// TODO: Add cc, bcc to rcpts
+	// TODO: attachments
+	writer, err := mail.CreateSingleInlineWriter(writeto, header)
+	if err != nil {
+		return nil, err
+	}
+	defer writer.Close()
+	io.Copy(writer, body)
+	return rcpts, nil
+}
+
 func (c *Composer) termClosed(err error) {
 	// TODO: do we care about that error (note: yes, we do)
 	c.grid.RemoveChild(c.editor)
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index ba99911..3eda27d 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -10,6 +10,7 @@ import (
 	"github.com/danwakefield/fnmatch"
 	"github.com/emersion/go-imap"
 	"github.com/emersion/go-message"
+	_ "github.com/emersion/go-message/charset"
 	"github.com/emersion/go-message/mail"
 	"github.com/gdamore/tcell"
 	"github.com/google/shlex"
@@ -109,7 +110,8 @@ func NewMessageViewer(conf *config.AercConfig, store *lib.MessageStore,
 	pager = exec.Command(cmd[0], cmd[1:]...)
 
 	for _, f := range conf.Filters {
-		mime := strings.ToLower(msg.BodyStructure.MIMEType) + "/" + strings.ToLower(msg.BodyStructure.MIMESubType)
+		mime := strings.ToLower(msg.BodyStructure.MIMEType) +
+			"/" + strings.ToLower(msg.BodyStructure.MIMESubType)
 		switch f.FilterType {
 		case config.FILTER_MIMETYPE:
 			if fnmatch.Match(f.Filter, mime, 0) {
@@ -181,11 +183,12 @@ handle_error:
 
 func (mv *MessageViewer) attemptCopy() {
 	if mv.source != nil && mv.pager.Process != nil {
-		header := make(message.Header)
-		header.Set("Content-Transfer-Encoding", mv.msg.BodyStructure.Encoding)
+		header := message.Header{}
+		header.SetText("Content-Transfer-Encoding",
+			mv.msg.BodyStructure.Encoding)
 		header.SetContentType(
 			mv.msg.BodyStructure.MIMEType, mv.msg.BodyStructure.Params)
-		header.SetContentDescription(mv.msg.BodyStructure.Description)
+		header.SetText("Content-Description", mv.msg.BodyStructure.Description)
 		if mv.filter != nil {
 			stdout, _ := mv.filter.StdoutPipe()
 			mv.filter.Start()