diff options
-rw-r--r-- | app/account.go | 2 | ||||
-rw-r--r-- | app/compose.go | 4 | ||||
-rw-r--r-- | commands/compose/send.go | 40 | ||||
-rw-r--r-- | commands/msg/bounce.go | 2 | ||||
-rw-r--r-- | commands/msg/reply.go | 7 | ||||
-rw-r--r-- | config/accounts.go | 1 | ||||
-rw-r--r-- | doc/aerc-accounts.5.scd | 6 | ||||
-rw-r--r-- | lib/msgstore.go | 4 | ||||
-rw-r--r-- | lib/send/jmap.go | 3 | ||||
-rw-r--r-- | lib/send/sender.go | 3 | ||||
-rw-r--r-- | models/models.go | 1 | ||||
-rw-r--r-- | worker/jmap/send.go | 14 | ||||
-rw-r--r-- | worker/types/messages.go | 5 |
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(), ©Buf, - composer) + errch := copyToSent(copyTo, copyToReplied, copyBuf.Len(), + ©Buf, 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 |