compose: append text parts
Append text parts to emails in the composer as multipart/alternative. Display the mime-type of the parts in the review window. Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
parent
527f602f36
commit
6f5c6e148f
1 changed files with 58 additions and 13 deletions
|
@ -30,6 +30,12 @@ import (
|
||||||
"git.sr.ht/~rjarry/aerc/worker/types"
|
"git.sr.ht/~rjarry/aerc/worker/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Part struct {
|
||||||
|
MimeType string
|
||||||
|
Params map[string]string
|
||||||
|
Body io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
type Composer struct {
|
type Composer struct {
|
||||||
editors map[string]*headerEditor // indexes in lower case (from / cc / bcc)
|
editors map[string]*headerEditor // indexes in lower case (from / cc / bcc)
|
||||||
header *mail.Header
|
header *mail.Header
|
||||||
|
@ -61,6 +67,8 @@ type Composer struct {
|
||||||
onClose []func(ti *Composer)
|
onClose []func(ti *Composer)
|
||||||
|
|
||||||
width int
|
width int
|
||||||
|
|
||||||
|
textParts []*Part
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewComposer(aerc *Aerc, acct *AccountView, conf *config.AercConfig,
|
func NewComposer(aerc *Aerc, acct *AccountView, conf *config.AercConfig,
|
||||||
|
@ -297,6 +305,14 @@ func (c *Composer) AppendContents(reader io.Reader) {
|
||||||
c.email.Sync()
|
c.email.Sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Composer) AppendPart(mimetype string, params map[string]string, body io.Reader) error {
|
||||||
|
if !strings.HasPrefix(mimetype, "text") {
|
||||||
|
return fmt.Errorf("can only append text mimetypes")
|
||||||
|
}
|
||||||
|
c.textParts = append(c.textParts, &Part{MimeType: mimetype, Params: params, Body: body})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Composer) AddTemplate(template string, data interface{}) error {
|
func (c *Composer) AddTemplate(template string, data interface{}) error {
|
||||||
if template == "" {
|
if template == "" {
|
||||||
return nil
|
return nil
|
||||||
|
@ -592,7 +608,7 @@ func (c *Composer) WriteMessage(header *mail.Header, writer io.Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeMsgImpl(c *Composer, header *mail.Header, writer io.Writer) error {
|
func writeMsgImpl(c *Composer, header *mail.Header, writer io.Writer) error {
|
||||||
if len(c.attachments) == 0 && !c.attachKey {
|
if len(c.attachments) == 0 && !c.attachKey && len(c.textParts) == 0 {
|
||||||
// no attachements
|
// no attachements
|
||||||
return writeInlineBody(header, c.email, writer)
|
return writeInlineBody(header, c.email, writer)
|
||||||
} else {
|
} else {
|
||||||
|
@ -601,7 +617,14 @@ func writeMsgImpl(c *Composer, header *mail.Header, writer io.Writer) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "CreateWriter")
|
return errors.Wrap(err, "CreateWriter")
|
||||||
}
|
}
|
||||||
if err := writeMultipartBody(c.email, w); err != nil {
|
parts := []*Part{
|
||||||
|
&Part{
|
||||||
|
MimeType: "text/plain",
|
||||||
|
Params: map[string]string{"Charset": "UTF-8"},
|
||||||
|
Body: c.email,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := writeMultipartBody(append(parts, c.textParts...), w); err != nil {
|
||||||
return errors.Wrap(err, "writeMultipartBody")
|
return errors.Wrap(err, "writeMultipartBody")
|
||||||
}
|
}
|
||||||
for _, a := range c.attachments {
|
for _, a := range c.attachments {
|
||||||
|
@ -634,24 +657,26 @@ func writeInlineBody(header *mail.Header, body io.Reader, writer io.Writer) erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// write the message body to the multipart message
|
// write the message body to the multipart message
|
||||||
func writeMultipartBody(body io.Reader, w *mail.Writer) error {
|
func writeMultipartBody(parts []*Part, w *mail.Writer) error {
|
||||||
bh := mail.InlineHeader{}
|
|
||||||
bh.SetContentType("text/plain", map[string]string{"charset": "UTF-8"})
|
|
||||||
|
|
||||||
bi, err := w.CreateInline()
|
bi, err := w.CreateInline()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "CreateInline")
|
return errors.Wrap(err, "CreateInline")
|
||||||
}
|
}
|
||||||
defer bi.Close()
|
defer bi.Close()
|
||||||
|
|
||||||
|
for _, part := range parts {
|
||||||
|
bh := mail.InlineHeader{}
|
||||||
|
bh.SetContentType(part.MimeType, part.Params)
|
||||||
bw, err := bi.CreatePart(bh)
|
bw, err := bi.CreatePart(bh)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "CreatePart")
|
return errors.Wrap(err, "CreatePart")
|
||||||
}
|
}
|
||||||
defer bw.Close()
|
defer bw.Close()
|
||||||
if _, err := io.Copy(bw, body); err != nil {
|
if _, err := io.Copy(bw, part.Body); err != nil {
|
||||||
return errors.Wrap(err, "io.Copy")
|
return errors.Wrap(err, "io.Copy")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1084,6 +1109,13 @@ func newReviewMessage(composer *Composer, err error) *reviewMessage {
|
||||||
if composer.attachKey {
|
if composer.attachKey {
|
||||||
spec = append(spec, ui.GridSpec{Strategy: ui.SIZE_EXACT, Size: ui.Const(1)})
|
spec = append(spec, ui.GridSpec{Strategy: ui.SIZE_EXACT, Size: ui.Const(1)})
|
||||||
}
|
}
|
||||||
|
if len(composer.textParts) > 0 {
|
||||||
|
spec = append(spec, ui.GridSpec{Strategy: ui.SIZE_EXACT, Size: ui.Const(1)})
|
||||||
|
spec = append(spec, ui.GridSpec{Strategy: ui.SIZE_EXACT, Size: ui.Const(1)})
|
||||||
|
for i := 0; i < len(composer.textParts); i++ {
|
||||||
|
spec = append(spec, ui.GridSpec{Strategy: ui.SIZE_EXACT, Size: ui.Const(1)})
|
||||||
|
}
|
||||||
|
}
|
||||||
// make the last element fill remaining space
|
// make the last element fill remaining space
|
||||||
spec = append(spec, ui.GridSpec{Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)})
|
spec = append(spec, ui.GridSpec{Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)})
|
||||||
|
|
||||||
|
@ -1117,6 +1149,7 @@ func newReviewMessage(composer *Composer, err error) *reviewMessage {
|
||||||
if len(composer.attachments) == 0 && !composer.attachKey {
|
if len(composer.attachments) == 0 && !composer.attachKey {
|
||||||
grid.AddChild(ui.NewText("(none)",
|
grid.AddChild(ui.NewText("(none)",
|
||||||
uiConfig.GetStyle(config.STYLE_DEFAULT))).At(i, 0)
|
uiConfig.GetStyle(config.STYLE_DEFAULT))).At(i, 0)
|
||||||
|
i += 1
|
||||||
} else {
|
} else {
|
||||||
for _, a := range composer.attachments {
|
for _, a := range composer.attachments {
|
||||||
grid.AddChild(ui.NewText(a, uiConfig.GetStyle(config.STYLE_DEFAULT))).
|
grid.AddChild(ui.NewText(a, uiConfig.GetStyle(config.STYLE_DEFAULT))).
|
||||||
|
@ -1124,6 +1157,18 @@ func newReviewMessage(composer *Composer, err error) *reviewMessage {
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(composer.textParts) > 0 {
|
||||||
|
grid.AddChild(ui.NewText("Parts:",
|
||||||
|
uiConfig.GetStyle(config.STYLE_TITLE))).At(i, 0)
|
||||||
|
i += 1
|
||||||
|
grid.AddChild(ui.NewText("text/plain", uiConfig.GetStyle(config.STYLE_DEFAULT))).At(i, 0)
|
||||||
|
i += 1
|
||||||
|
for _, p := range composer.textParts {
|
||||||
|
grid.AddChild(ui.NewText(p.MimeType, uiConfig.GetStyle(config.STYLE_DEFAULT))).At(i, 0)
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &reviewMessage{
|
return &reviewMessage{
|
||||||
|
|
Loading…
Reference in a new issue