aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/account.go2
-rw-r--r--app/compose.go4
-rw-r--r--commands/compose/send.go40
-rw-r--r--commands/msg/bounce.go2
-rw-r--r--commands/msg/reply.go7
-rw-r--r--config/accounts.go1
-rw-r--r--doc/aerc-accounts.5.scd6
-rw-r--r--lib/msgstore.go4
-rw-r--r--lib/send/jmap.go3
-rw-r--r--lib/send/sender.go3
-rw-r--r--models/models.go1
-rw-r--r--worker/jmap/send.go14
-rw-r--r--worker/types/messages.go5
13 files changed, 71 insertions, 21 deletions
diff --git a/app/account.go b/app/account.go
index 9786b930..0f0a58bd 100644
--- a/app/account.go
+++ b/app/account.go
@@ -248,7 +248,7 @@ func (acct *AccountView) newStore(name string) *lib.MessageStore {
role = string(dir.Role)
}
backend := acct.AccountConfig().Backend
- store := lib.NewMessageStore(acct.worker,
+ store := lib.NewMessageStore(acct.worker, name,
acct.sortCriteria(uiConf),
uiConf.ThreadingEnabled,
uiConf.ForceClientThreads,
diff --git a/app/compose.go b/app/compose.go
index 38d94359..7c580032 100644
--- a/app/compose.go
+++ b/app/compose.go
@@ -132,6 +132,10 @@ func (c *Composer) SelectedDirectory() string {
return c.seldir
}
+func (c *Composer) Parent() *models.OriginalMail {
+ return c.parent
+}
+
func (c *Composer) SwitchAccount(newAcct *AccountView) error {
if c.acct == newAcct {
log.Tracef("same accounts: no switch")
diff --git a/commands/compose/send.go b/commands/compose/send.go
index d8930056..9af8dc37 100644
--- a/commands/compose/send.go
+++ b/commands/compose/send.go
@@ -25,6 +25,9 @@ import (
type Send struct {
Archive string `opt:"-a" action:"ParseArchive" metavar:"flat|year|month" complete:"CompleteArchive"`
CopyTo string `opt:"-t" complete:"CompleteFolders"`
+
+ CopyToReplied bool `opt:"-r"`
+ NoCopyToReplied bool `opt:"-R"`
}
func init() {
@@ -74,6 +77,7 @@ func (s Send) Execute(args []string) error {
if s.CopyTo == "" {
s.CopyTo = config.CopyTo
}
+ copyToReplied := config.CopyToReplied || (s.CopyToReplied && !s.NoCopyToReplied)
outgoing, err := config.Outgoing.ConnectionString()
if err != nil {
@@ -131,7 +135,7 @@ func (s Send) Execute(args []string) error {
if text == "n" || text == "N" {
sendHelper(composer, header, uri, domain,
from, rcpts, tab.Name, s.CopyTo,
- s.Archive)
+ s.Archive, copyToReplied)
}
}, func(cmd string) ([]string, string) {
if cmd == "" {
@@ -145,7 +149,7 @@ func (s Send) Execute(args []string) error {
app.PushPrompt(prompt)
} else {
sendHelper(composer, header, uri, domain, from, rcpts, tab.Name,
- s.CopyTo, s.Archive)
+ s.CopyTo, s.Archive, copyToReplied)
}
return nil
@@ -153,7 +157,7 @@ func (s Send) Execute(args []string) error {
func sendHelper(composer *app.Composer, header *mail.Header, uri *url.URL, domain string,
from *mail.Address, rcpts []*mail.Address, tabName string, copyTo string,
- archive string,
+ archive string, copyToReplied bool,
) {
// we don't want to block the UI thread while we are sending
// so we do everything in a goroutine and hide the composer from the user
@@ -171,7 +175,12 @@ func sendHelper(composer *app.Composer, header *mail.Header, uri *url.URL, domai
go func() {
defer log.PanicHandler()
- sender, err := send.NewSender(composer.Worker(), uri, domain, from, rcpts)
+ var parentDir string
+ if copyToReplied && composer.Parent() != nil {
+ parentDir = composer.Parent().Folder
+ }
+ sender, err := send.NewSender(
+ composer.Worker(), uri, domain, from, rcpts, parentDir)
if err != nil {
failCh <- errors.Wrap(err, "send:")
return
@@ -206,8 +215,8 @@ func sendHelper(composer *app.Composer, header *mail.Header, uri *url.URL, domai
}
if shouldCopy {
app.PushStatus("Copying to "+copyTo, 10*time.Second)
- errch := copyToSent(copyTo, copyBuf.Len(), &copyBuf,
- composer)
+ errch := copyToSent(copyTo, copyToReplied, copyBuf.Len(),
+ &copyBuf, composer)
err = <-errch
if err != nil {
errmsg := fmt.Sprintf(
@@ -246,7 +255,7 @@ func listRecipients(h *mail.Header) ([]*mail.Address, error) {
return rcpts, nil
}
-func copyToSent(dest string, n int, msg io.Reader, composer *app.Composer) <-chan error {
+func copyToSent(dest string, copyToReplied bool, n int, msg io.Reader, composer *app.Composer) <-chan error {
errCh := make(chan error, 1)
acct := composer.Account()
if acct == nil {
@@ -273,5 +282,22 @@ func copyToSent(dest string, n int, msg io.Reader, composer *app.Composer) <-cha
}
},
)
+ if copyToReplied && composer.Parent() != nil {
+ store.Append(
+ composer.Parent().Folder,
+ models.SeenFlag,
+ time.Now(),
+ msg,
+ n,
+ func(msg types.WorkerMessage) {
+ switch msg := msg.(type) {
+ case *types.Done:
+ errCh <- nil
+ case *types.Error:
+ errCh <- msg.Error
+ }
+ },
+ )
+ }
return errCh
}
diff --git a/commands/msg/bounce.go b/commands/msg/bounce.go
index a268a15f..1460951d 100644
--- a/commands/msg/bounce.go
+++ b/commands/msg/bounce.go
@@ -155,7 +155,7 @@ func (b Bounce) Execute(args []string) error {
msg.Envelope.MessageId, addresses)
if sender, err = send.NewSender(acct.Worker(), uri,
- domain, config.From, rcpts); err != nil {
+ domain, config.From, rcpts, ""); err != nil {
return
}
defer func() {
diff --git a/commands/msg/reply.go b/commands/msg/reply.go
index acc0d6fa..e55b5d4b 100644
--- a/commands/msg/reply.go
+++ b/commands/msg/reply.go
@@ -165,10 +165,13 @@ func (r reply) Execute(args []string) error {
store := widget.Store()
noStore := store == nil
- if noStore && isMsgViewer {
+ switch {
+ case noStore && isMsgViewer:
app.PushWarning("No message store found: answered flag cannot be set")
- } else if noStore {
+ case noStore:
return errors.New("Cannot perform action. Messages still loading")
+ default:
+ original.Folder = store.Name
}
addTab := func() error {
diff --git a/config/accounts.go b/config/accounts.go
index 77afa0f9..5bbae39f 100644
--- a/config/accounts.go
+++ b/config/accounts.go
@@ -76,6 +76,7 @@ type AccountConfig struct {
Archive string `ini:"archive" default:"Archive"`
CopyTo string `ini:"copy-to"`
+ CopyToReplied bool `ini:"copy-to-replied" default:"false"`
Default string `ini:"default" default:"INBOX"`
Postpone string `ini:"postpone" default:"Drafts"`
From *mail.Address `ini:"from"`
diff --git a/doc/aerc-accounts.5.scd b/doc/aerc-accounts.5.scd
index 14502409..9f52ef8a 100644
--- a/doc/aerc-accounts.5.scd
+++ b/doc/aerc-accounts.5.scd
@@ -53,6 +53,12 @@ Note that many of these configuration options are written for you, such as
*copy-to* = _<folder>_
Specifies a folder to copy sent mails to, usually _Sent_.
+*copy-to-replied* = _true_|_false_
+ In addition of *copy-to*, also copy replies to the folder in which the
+ replied message is.
+
+ Default: _false_
+
*default* = _<folder>_
Specifies the default folder to open in the message list when aerc
configures this account.
diff --git a/lib/msgstore.go b/lib/msgstore.go
index d5501a4c..c64f933d 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -18,6 +18,7 @@ import (
// Accesses to fields must be guarded by MessageStore.Lock/Unlock
type MessageStore struct {
sync.Mutex
+ Name string
Deleted map[uint32]interface{}
Messages map[uint32]*models.MessageInfo
Sorting bool
@@ -88,7 +89,7 @@ type MessageStore struct {
const MagicUid = 0xFFFFFFFF
-func NewMessageStore(worker *types.Worker,
+func NewMessageStore(worker *types.Worker, name string,
defaultSortCriteria []*types.SortCriterion,
thread bool, clientThreads bool, clientThreadsDelay time.Duration,
selectLast bool, threadBySubject bool,
@@ -105,6 +106,7 @@ func NewMessageStore(worker *types.Worker,
}
return &MessageStore{
+ Name: name,
Deleted: make(map[uint32]interface{}),
Messages: make(map[uint32]*models.MessageInfo),
diff --git a/lib/send/jmap.go b/lib/send/jmap.go
index 9682629e..5f679b43 100644
--- a/lib/send/jmap.go
+++ b/lib/send/jmap.go
@@ -11,12 +11,13 @@ import (
func newJmapSender(
worker *types.Worker, from *mail.Address, rcpts []*mail.Address,
+ copyTo string,
) (io.WriteCloser, error) {
var writer io.WriteCloser
done := make(chan error)
worker.PostAction(
- &types.StartSendingMessage{From: from, Rcpts: rcpts},
+ &types.StartSendingMessage{From: from, Rcpts: rcpts, CopyTo: copyTo},
func(msg types.WorkerMessage) {
switch msg := msg.(type) {
case *types.Done:
diff --git a/lib/send/sender.go b/lib/send/sender.go
index a1e03da5..87ca4745 100644
--- a/lib/send/sender.go
+++ b/lib/send/sender.go
@@ -16,6 +16,7 @@ import (
func NewSender(
worker *types.Worker, uri *url.URL, domain string,
from *mail.Address, rcpts []*mail.Address,
+ copyTo string,
) (io.WriteCloser, error) {
protocol, auth, err := parseScheme(uri)
if err != nil {
@@ -26,7 +27,7 @@ func NewSender(
case "smtp", "smtp+insecure", "smtps":
return newSmtpSender(protocol, auth, uri, domain, from, rcpts)
case "jmap":
- return newJmapSender(worker, from, rcpts)
+ return newJmapSender(worker, from, rcpts, copyTo)
case "":
return newSendmailSender(uri, rcpts)
default:
diff --git a/models/models.go b/models/models.go
index 7642579a..d5a6bd61 100644
--- a/models/models.go
+++ b/models/models.go
@@ -244,6 +244,7 @@ type OriginalMail struct {
Text string
MIMEType string
RFC822Headers *mail.Header
+ Folder string
}
type SignatureValidity int32
diff --git a/worker/jmap/send.go b/worker/jmap/send.go
index 0791419c..757e5420 100644
--- a/worker/jmap/send.go
+++ b/worker/jmap/send.go
@@ -66,6 +66,14 @@ func (w *JMAPWorker) handleStartSend(msg *types.StartSendingMessage) error {
})
}
envelope := &emailsubmission.Envelope{MailFrom: from, RcptTo: rcpts}
+ onSuccess := jmap.Patch{
+ "keywords/$draft": nil,
+ w.rolePatch(mailbox.RoleSent): true,
+ w.rolePatch(mailbox.RoleDrafts): nil,
+ }
+ if copyTo := w.dir2mbox[msg.CopyTo]; copyTo != "" {
+ onSuccess[w.mboxPatch(copyTo)] = true
+ }
// Create the submission
req.Invoke(&emailsubmission.Set{
Account: w.AccountId(),
@@ -77,11 +85,7 @@ func (w *JMAPWorker) handleStartSend(msg *types.StartSendingMessage) error {
},
},
OnSuccessUpdateEmail: map[jmap.ID]jmap.Patch{
- "#sub": {
- "keywords/$draft": nil,
- w.rolePatch(mailbox.RoleSent): true,
- w.rolePatch(mailbox.RoleDrafts): nil,
- },
+ "#sub": onSuccess,
},
})
diff --git a/worker/types/messages.go b/worker/types/messages.go
index 9a2d43f8..3fd018b2 100644
--- a/worker/types/messages.go
+++ b/worker/types/messages.go
@@ -218,8 +218,9 @@ type CheckMail struct {
type StartSendingMessage struct {
Message
- From *mail.Address
- Rcpts []*mail.Address
+ From *mail.Address
+ Rcpts []*mail.Address
+ CopyTo string
}
// Messages