Implement (basic form) of :reply
This commit is contained in:
parent
2b3e123cb8
commit
475b697bdf
6 changed files with 139 additions and 7 deletions
83
commands/account/reply.go
Normal file
83
commands/account/reply.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package account
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/emersion/go-imap"
|
||||
|
||||
"git.sr.ht/~sircmpwn/aerc2/widgets"
|
||||
)
|
||||
|
||||
func init() {
|
||||
register("reply", Reply)
|
||||
}
|
||||
|
||||
func Reply(aerc *widgets.Aerc, args []string) error {
|
||||
if len(args) != 1 {
|
||||
return errors.New("Usage: reply [-aq]")
|
||||
}
|
||||
// TODO: Reply all (w/ getopt)
|
||||
|
||||
acct := aerc.SelectedAccount()
|
||||
msg := acct.Messages().Selected()
|
||||
acct.Logger().Println("Replying to email " + msg.Envelope.MessageId)
|
||||
|
||||
var (
|
||||
to []string
|
||||
cc []string
|
||||
toList []*imap.Address
|
||||
)
|
||||
if len(msg.Envelope.ReplyTo) != 0 {
|
||||
toList = msg.Envelope.ReplyTo
|
||||
} else {
|
||||
toList = msg.Envelope.From
|
||||
}
|
||||
for _, addr := range toList {
|
||||
if addr.PersonalName != "" {
|
||||
to = append(to, fmt.Sprintf("%s <%s@%s>",
|
||||
addr.PersonalName, addr.MailboxName, addr.HostName))
|
||||
} else {
|
||||
to = append(to, fmt.Sprintf("<%s@%s>",
|
||||
addr.MailboxName, addr.HostName))
|
||||
}
|
||||
}
|
||||
// TODO: Only if reply all
|
||||
for _, addr := range msg.Envelope.Cc {
|
||||
if addr.PersonalName != "" {
|
||||
cc = append(cc, fmt.Sprintf("%s <%s@%s>",
|
||||
addr.PersonalName, addr.MailboxName, addr.HostName))
|
||||
} else {
|
||||
cc = append(cc, fmt.Sprintf("<%s@%s>",
|
||||
addr.MailboxName, addr.HostName))
|
||||
}
|
||||
}
|
||||
|
||||
subject := "Re: " + msg.Envelope.Subject
|
||||
|
||||
composer := widgets.NewComposer(
|
||||
aerc.Config(), acct.AccountConfig(), acct.Worker()).
|
||||
Defaults(map[string]string{
|
||||
"To": strings.Join(to, ","),
|
||||
"Cc": strings.Join(cc, ","),
|
||||
"Subject": subject,
|
||||
"In-Reply-To": msg.Envelope.MessageId,
|
||||
}).
|
||||
FocusTerminal()
|
||||
|
||||
tab := aerc.NewTab(composer, subject)
|
||||
|
||||
composer.OnSubjectChange(func(subject string) {
|
||||
if subject == "" {
|
||||
tab.Name = "New email"
|
||||
} else {
|
||||
tab.Name = subject
|
||||
}
|
||||
tab.Content.Invalidate()
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
1
go.mod
1
go.mod
|
@ -15,6 +15,7 @@ require (
|
|||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||
github.com/kyoh86/xdg v0.0.0-20171127140545-8db68a8ea76a
|
||||
github.com/lucasb-eyer/go-colorful v0.0.0-20180531031333-d9cec903b20c // indirect
|
||||
github.com/martinlindhe/base36 v0.0.0-20190418230009-7c6542dfbb41
|
||||
github.com/mattn/go-isatty v0.0.3
|
||||
github.com/mattn/go-runewidth v0.0.2
|
||||
github.com/miolini/datacounter v0.0.0-20171104152933-fd4e42a1d5e0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -40,6 +40,8 @@ github.com/kyoh86/xdg v0.0.0-20171127140545-8db68a8ea76a h1:vLFQnHOnCnmlySdpHAKF
|
|||
github.com/kyoh86/xdg v0.0.0-20171127140545-8db68a8ea76a/go.mod h1:Z5mDqe0fxyxn3W2yTxsBAOQqIrXADQIh02wrTnaRM38=
|
||||
github.com/lucasb-eyer/go-colorful v0.0.0-20180531031333-d9cec903b20c h1:b11Y3yxg40v2/9KUz76a4mSC1DMlgnPGAt+4pJSgmyU=
|
||||
github.com/lucasb-eyer/go-colorful v0.0.0-20180531031333-d9cec903b20c/go.mod h1:NXg0ArsFk0Y01623LgUqoqcouGDB+PwCCQlrwrG6xJ4=
|
||||
github.com/martinlindhe/base36 v0.0.0-20190418230009-7c6542dfbb41 h1:CVsnY46BCLkX9XOhALJ/S7yb9ayc4eqjXSXO3tyB66A=
|
||||
github.com/martinlindhe/base36 v0.0.0-20190418230009-7c6542dfbb41/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8=
|
||||
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-pointer v0.0.0-20180825124634-49522c3f3791 h1:PfHMsLQJwoc0ccjK0sam6J0wQo4s8mOuAo2yQGw+T2U=
|
||||
|
|
34
lib/msgid.go
Normal file
34
lib/msgid.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package lib
|
||||
|
||||
// TODO: Remove this pending merge into github.com/emersion/go-message
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/martinlindhe/base36"
|
||||
)
|
||||
|
||||
// Generates an RFC 2822-complaint Message-Id based on the informational draft
|
||||
// "Recommendations for generating Message IDs", for lack of a better
|
||||
// authoritative source.
|
||||
func GenerateMessageId() string {
|
||||
var (
|
||||
now bytes.Buffer
|
||||
nonce bytes.Buffer
|
||||
)
|
||||
binary.Write(&now, binary.BigEndian, time.Now().UnixNano())
|
||||
binary.Write(&nonce, binary.BigEndian, rand.Uint64())
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
hostname = "localhost"
|
||||
}
|
||||
return fmt.Sprintf("<%s.%s@%s>",
|
||||
base36.EncodeBytes(now.Bytes()),
|
||||
base36.EncodeBytes(nonce.Bytes()),
|
||||
hostname)
|
||||
}
|
|
@ -84,6 +84,14 @@ func (acct *AccountView) AccountConfig() *config.AccountConfig {
|
|||
return acct.acct
|
||||
}
|
||||
|
||||
func (acct *AccountView) Worker() *types.Worker {
|
||||
return acct.worker
|
||||
}
|
||||
|
||||
func (acct *AccountView) Logger() *log.Logger {
|
||||
return acct.logger
|
||||
}
|
||||
|
||||
func (acct *AccountView) Name() string {
|
||||
return acct.acct.Name
|
||||
}
|
||||
|
@ -110,10 +118,6 @@ func (acct *AccountView) Focus(focus bool) {
|
|||
// TODO: Unfocus children I guess
|
||||
}
|
||||
|
||||
func (acct *AccountView) Worker() *types.Worker {
|
||||
return acct.worker
|
||||
}
|
||||
|
||||
func (acct *AccountView) connected(msg types.WorkerMessage) {
|
||||
switch msg := msg.(type) {
|
||||
case *types.Done:
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/mattn/go-runewidth"
|
||||
|
||||
"git.sr.ht/~sircmpwn/aerc2/config"
|
||||
"git.sr.ht/~sircmpwn/aerc2/lib"
|
||||
"git.sr.ht/~sircmpwn/aerc2/lib/ui"
|
||||
"git.sr.ht/~sircmpwn/aerc2/worker/types"
|
||||
)
|
||||
|
@ -123,6 +124,13 @@ func (c *Composer) Defaults(defaults map[string]string) *Composer {
|
|||
return c
|
||||
}
|
||||
|
||||
func (c *Composer) FocusTerminal() *Composer {
|
||||
c.focusable[c.focused].Focus(false)
|
||||
c.focused = 3
|
||||
c.focusable[c.focused].Focus(true)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Composer) OnSubjectChange(fn func(subject string)) {
|
||||
c.headers.subject.OnChange(func() {
|
||||
fn(c.headers.subject.input.String())
|
||||
|
@ -197,9 +205,9 @@ func (c *Composer) PrepareHeader() (*mail.Header, []string, error) {
|
|||
c.email.Seek(0, os.SEEK_SET)
|
||||
}
|
||||
// Update headers
|
||||
// TODO: Custom header fields
|
||||
mhdr := (*message.Header)(&header.Header)
|
||||
mhdr.SetContentType("text/plain", map[string]string{"charset": "UTF-8"})
|
||||
mhdr.SetText("Message-Id", lib.GenerateMessageId())
|
||||
if subject, _ := header.Subject(); subject == "" {
|
||||
header.SetSubject(c.headers.subject.input.String())
|
||||
}
|
||||
|
@ -228,14 +236,14 @@ func (c *Composer) PrepareHeader() (*mail.Header, []string, error) {
|
|||
rcpts = append(rcpts, addr.Address)
|
||||
}
|
||||
}
|
||||
// TODO: Add cc, bcc to rcpts
|
||||
// Merge in additional headers
|
||||
txthdr := mhdr.Header
|
||||
for key, value := range c.defaults {
|
||||
if !txthdr.Has(key) {
|
||||
if !txthdr.Has(key) && value != "" {
|
||||
mhdr.SetText(key, value)
|
||||
}
|
||||
}
|
||||
// TODO: Add cc, bcc to rcpts
|
||||
return &header, rcpts, nil
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue