From 20ec2c8eeb2e071f28358814935a0f56672a9f49 Mon Sep 17 00:00:00 2001 From: Reto Brunner Date: Tue, 10 Nov 2020 20:27:30 +0100 Subject: compose: use a proper header instead of a string map Prior to this commit, the composer was based on a map[string]string. While this approach was very versatile, it lead to a constant encoding / decoding of addresses and other headers. This commit switches to a different model, where the composer is based on a header. Commands which want to interact with it can simply set some defaults they would like to have. Users can overwrite them however they like. In order to get access to the functions generating / getting the msgid go-message was upgraded. --- commands/compose/header.go | 7 +++---- commands/compose/postpone.go | 2 +- commands/compose/send.go | 32 ++++++++++++++++++++++++++++---- commands/msg/forward.go | 26 +++++++++++++++----------- commands/msg/recall.go | 10 ++-------- commands/msg/reply.go | 20 ++++++++++---------- commands/msg/unsubscribe.go | 12 ++++++++---- 7 files changed, 67 insertions(+), 42 deletions(-) (limited to 'commands') diff --git a/commands/compose/header.go b/commands/compose/header.go index 5188a8a..dd0adee 100644 --- a/commands/compose/header.go +++ b/commands/compose/header.go @@ -57,18 +57,17 @@ func (Header) Execute(aerc *widgets.Aerc, args []string) error { composer, _ := aerc.SelectedTab().(*widgets.Composer) if !force { - headers, _, err := composer.PrepareHeader() + headers, err := composer.PrepareHeader() if err != nil { return err } - if headers.Has(strings.Title(args[optind])) { + if headers.Has(args[optind]) { return fmt.Errorf("Header %s already exists", args[optind]) } } - composer.AddEditor(strings.Title(args[optind]), - strings.Join(args[optind+1:], " "), false) + composer.AddEditor(args[optind], strings.Join(args[optind+1:], " "), false) return nil } diff --git a/commands/compose/postpone.go b/commands/compose/postpone.go index 60c9df1..365b683 100644 --- a/commands/compose/postpone.go +++ b/commands/compose/postpone.go @@ -40,7 +40,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error { aerc.Logger().Println("Postponing mail") - header, _, err := composer.PrepareHeader() + header, err := composer.PrepareHeader() if err != nil { return errors.Wrap(err, "PrepareHeader") } diff --git a/commands/compose/send.go b/commands/compose/send.go index abbcb54..70446da 100644 --- a/commands/compose/send.go +++ b/commands/compose/send.go @@ -4,7 +4,6 @@ import ( "crypto/tls" "fmt" "io" - "net/mail" "net/url" "os/exec" "strings" @@ -17,9 +16,11 @@ import ( "github.com/pkg/errors" "git.sr.ht/~sircmpwn/aerc/lib" + "git.sr.ht/~sircmpwn/aerc/lib/format" "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/widgets" "git.sr.ht/~sircmpwn/aerc/worker/types" + "github.com/emersion/go-message/mail" "golang.org/x/oauth2" ) @@ -71,15 +72,19 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error { } } - header, rcpts, err := composer.PrepareHeader() + header, err := composer.PrepareHeader() if err != nil { return errors.Wrap(err, "PrepareHeader") } + rcpts, err := listRecipients(header) + if err != nil { + return errors.Wrap(err, "listRecipients") + } if config.From == "" { return errors.New("No 'From' configured for this account") } - from, err := mail.ParseAddress(config.From) + from, err := format.ParseAddress(config.From) if err != nil { return errors.Wrap(err, "ParseAddress(config.From)") } @@ -288,7 +293,12 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error { composer.Close() } }) - header, _, _ := composer.PrepareHeader() + header, err := composer.PrepareHeader() + if err != nil { + aerc.PushError(" " + err.Error()) + w.Close() + return + } composer.WriteMessage(header, w) w.Close() } else { @@ -299,3 +309,17 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error { }() return nil } + +func listRecipients(h *mail.Header) ([]string, error) { + var rcpts []string + for _, key := range []string{"to", "cc", "bcc"} { + list, err := h.AddressList(key) + if err != nil { + return nil, err + } + for _, addr := range list { + rcpts = append(rcpts, addr.Address) + } + } + return rcpts, nil +} diff --git a/commands/msg/forward.go b/commands/msg/forward.go index b17482f..475d680 100644 --- a/commands/msg/forward.go +++ b/commands/msg/forward.go @@ -15,6 +15,7 @@ import ( "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/widgets" "git.sr.ht/~sircmpwn/aerc/worker/types" + "github.com/emersion/go-message/mail" "git.sr.ht/~sircmpwn/getopt" ) @@ -49,11 +50,6 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error { } } - to := "" - if len(args) != 1 { - to = strings.Join(args[optind:], ", ") - } - widget := aerc.SelectedTab().(widgets.ProvidesMessage) acct := widget.SelectedAccount() if acct == nil { @@ -69,11 +65,19 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error { } acct.Logger().Println("Forwarding email " + msg.Envelope.MessageId) + h := &mail.Header{} subject := "Fwd: " + msg.Envelope.Subject - defaults := map[string]string{ - "To": to, - "Subject": subject, + h.SetSubject(subject) + + if len(args) != 1 { + to := strings.Join(args[optind:], ", ") + tolist, err := mail.ParseAddressList(to) + if err != nil { + return fmt.Errorf("invalid to address(es): %v", err) + } + h.SetAddressList("to", tolist) } + original := models.OriginalMail{ From: format.FormatAddresses(msg.Envelope.From), Date: msg.Envelope.Date, @@ -81,15 +85,15 @@ func (forward) Execute(aerc *widgets.Aerc, args []string) error { } addTab := func() (*widgets.Composer, error) { - composer, err := widgets.NewComposer(aerc, acct, aerc.Config(), acct.AccountConfig(), - acct.Worker(), template, defaults, original) + composer, err := widgets.NewComposer(aerc, acct, aerc.Config(), + acct.AccountConfig(), acct.Worker(), template, h, original) if err != nil { aerc.PushError("Error: " + err.Error()) return nil, err } tab := aerc.NewTab(composer, subject) - if to == "" { + if !h.Has("to") { composer.FocusRecipient() } else { composer.FocusTerminal() diff --git a/commands/msg/recall.go b/commands/msg/recall.go index 5212041..b6c7f65 100644 --- a/commands/msg/recall.go +++ b/commands/msg/recall.go @@ -53,15 +53,9 @@ func (Recall) Execute(aerc *widgets.Aerc, args []string) error { } acct.Logger().Println("Recalling message " + msgInfo.Envelope.MessageId) - // copy the headers to the defaults map for addition to the composition - defaults := make(map[string]string) - headerFields := msgInfo.RFC822Headers.Fields() - for headerFields.Next() { - defaults[headerFields.Key()] = headerFields.Value() - } - composer, err := widgets.NewComposer(aerc, acct, aerc.Config(), - acct.AccountConfig(), acct.Worker(), "", defaults, models.OriginalMail{}) + acct.AccountConfig(), acct.Worker(), "", msgInfo.RFC822Headers, + models.OriginalMail{}) if err != nil { return errors.Wrap(err, "Cannot open a new composer") } diff --git a/commands/msg/reply.go b/commands/msg/reply.go index 0298ac2..863c7d2 100644 --- a/commands/msg/reply.go +++ b/commands/msg/reply.go @@ -145,22 +145,22 @@ func (reply) Execute(aerc *widgets.Aerc, args []string) error { subject = msg.Envelope.Subject } - defaults := map[string]string{ - "To": format.FormatAddresses(to), - "Cc": format.FormatAddresses(cc), - "From": format.AddressForHumans(from), - "Subject": subject, - "In-Reply-To": msg.Envelope.MessageId, - } + h := &mail.Header{} + h.SetAddressList("to", to) + h.SetAddressList("cc", cc) + h.SetAddressList("from", []*mail.Address{from}) + h.SetSubject(subject) + h.SetMsgIDList("in-reply-to", []string{msg.Envelope.MessageId}) + //TODO: references header original := models.OriginalMail{ - From: format.FormatAddresses(msg.Envelope.From), - Date: msg.Envelope.Date, + From: format.FormatAddresses(msg.Envelope.From), + Date: msg.Envelope.Date, RFC822Headers: msg.RFC822Headers, } addTab := func() error { composer, err := widgets.NewComposer(aerc, acct, aerc.Config(), - acct.AccountConfig(), acct.Worker(), template, defaults, original) + acct.AccountConfig(), acct.Worker(), template, h, original) if err != nil { aerc.PushError("Error: " + err.Error()) return err diff --git a/commands/msg/unsubscribe.go b/commands/msg/unsubscribe.go index dec90d5..205a255 100644 --- a/commands/msg/unsubscribe.go +++ b/commands/msg/unsubscribe.go @@ -9,6 +9,7 @@ import ( "git.sr.ht/~sircmpwn/aerc/lib" "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/widgets" + "github.com/emersion/go-message/mail" ) // Unsubscribe helps people unsubscribe from mailing lists by way of the @@ -84,10 +85,13 @@ func parseUnsubscribeMethods(header string) (methods []*url.URL) { func unsubscribeMailto(aerc *widgets.Aerc, u *url.URL) error { widget := aerc.SelectedTab().(widgets.ProvidesMessage) acct := widget.SelectedAccount() - defaults := map[string]string{ - "To": u.Opaque, - "Subject": u.Query().Get("subject"), + + h := &mail.Header{} + h.SetSubject(u.Query().Get("subject")) + if to, err := mail.ParseAddressList(u.Opaque); err == nil { + h.SetAddressList("to", to) } + composer, err := widgets.NewComposer( aerc, acct, @@ -95,7 +99,7 @@ func unsubscribeMailto(aerc *widgets.Aerc, u *url.URL) error { acct.AccountConfig(), acct.Worker(), "", - defaults, + h, models.OriginalMail{}, ) if err != nil { -- cgit 1.4.1-2-gfad0