aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/account.go9
-rw-r--r--commands/account/import-mbox.go44
-rw-r--r--commands/compose/postpone.go37
-rw-r--r--commands/compose/send.go48
-rw-r--r--config/aerc.conf4
-rw-r--r--config/hooks.go1
-rw-r--r--doc/aerc-config.5.scd15
-rw-r--r--lib/hooks/mail-added.go23
-rw-r--r--lib/msgstore.go30
9 files changed, 151 insertions, 60 deletions
diff --git a/app/account.go b/app/account.go
index b5bed86e..734ba37a 100644
--- a/app/account.go
+++ b/app/account.go
@@ -265,6 +265,15 @@ func (acct *AccountView) newStore(name string) *lib.MessageStore {
msg := fmt.Sprintf("mail-deleted hook: %s", err)
PushError(msg)
}
+ }, func(dest string) {
+ err := hooks.RunHook(&hooks.MailAdded{
+ Account: acct.Name(),
+ Folder: dest,
+ })
+ if err != nil {
+ msg := fmt.Sprintf("mail-added hook: %s", err)
+ PushError(msg)
+ }
},
acct.updateSplitView,
acct.dirlist.UiConfig(name).ThreadContext,
diff --git a/commands/account/import-mbox.go b/commands/account/import-mbox.go
index 774dfa8f..7aa393b6 100644
--- a/commands/account/import-mbox.go
+++ b/commands/account/import-mbox.go
@@ -65,7 +65,6 @@ func (i ImportMbox) Execute(args []string) error {
app.PushError(err.Error())
return
}
- worker := acct.Worker()
var appended uint32
for i, m := range messages {
@@ -79,27 +78,28 @@ func (i ImportMbox) Execute(args []string) error {
break
}
nbytes, _ := io.Copy(&buf, r)
- worker.PostAction(&types.AppendMessage{
- Destination: folder,
- Flags: models.SeenFlag,
- Date: time.Now(),
- Reader: &buf,
- Length: int(nbytes),
- }, func(msg types.WorkerMessage) {
- switch msg := msg.(type) {
- case *types.Unsupported:
- errMsg := fmt.Sprintf("%s: AppendMessage is unsupported", args[0])
- log.Errorf(errMsg)
- app.PushError(errMsg)
- return
- case *types.Error:
- log.Errorf("AppendMessage failed: %v", msg.Error)
- done <- false
- case *types.Done:
- atomic.AddUint32(&appended, 1)
- done <- true
- }
- })
+ store.Append(
+ folder,
+ models.SeenFlag,
+ time.Now(),
+ &buf,
+ int(nbytes),
+ func(msg types.WorkerMessage) {
+ switch msg := msg.(type) {
+ case *types.Unsupported:
+ errMsg := fmt.Sprintf("%s: AppendMessage is unsupported", args[0])
+ log.Errorf(errMsg)
+ app.PushError(errMsg)
+ return
+ case *types.Error:
+ log.Errorf("AppendMessage failed: %v", msg.Error)
+ done <- false
+ case *types.Done:
+ atomic.AddUint32(&appended, 1)
+ done <- true
+ }
+ },
+ )
select {
case ok := <-done:
diff --git a/commands/compose/postpone.go b/commands/compose/postpone.go
index 3ce9cc84..098b7039 100644
--- a/commands/compose/postpone.go
+++ b/commands/compose/postpone.go
@@ -34,6 +34,10 @@ func (p Postpone) Execute(args []string) error {
if acct == nil {
return errors.New("No account selected")
}
+ store := acct.Store()
+ if store == nil {
+ return errors.New("No message store selected")
+ }
tab := app.SelectedTab()
if tab == nil {
return errors.New("No tab selected")
@@ -98,22 +102,23 @@ func (p Postpone) Execute(args []string) error {
handleErr(errors.Wrap(err, "WriteMessage"))
return
}
- worker.PostAction(&types.AppendMessage{
- Destination: targetFolder,
- Flags: models.SeenFlag,
- Date: time.Now(),
- Reader: buf,
- Length: buf.Len(),
- }, func(msg types.WorkerMessage) {
- switch msg := msg.(type) {
- case *types.Done:
- app.PushStatus("Message postponed.", 10*time.Second)
- composer.SetPostponed()
- composer.Close()
- case *types.Error:
- handleErr(msg.Error)
- }
- })
+ store.Append(
+ targetFolder,
+ models.SeenFlag,
+ time.Now(),
+ buf,
+ buf.Len(),
+ func(msg types.WorkerMessage) {
+ switch msg := msg.(type) {
+ case *types.Done:
+ app.PushStatus("Message postponed.", 10*time.Second)
+ composer.SetPostponed()
+ composer.Close()
+ case *types.Error:
+ handleErr(msg.Error)
+ }
+ },
+ )
}()
if !alreadyCreated {
diff --git a/commands/compose/send.go b/commands/compose/send.go
index 1047ebad..91fd42bd 100644
--- a/commands/compose/send.go
+++ b/commands/compose/send.go
@@ -228,8 +228,7 @@ func send(composer *app.Composer, ctx sendCtx,
}
if ctx.copyto != "" && ctx.scheme != "jmap" {
app.PushStatus("Copying to "+ctx.copyto, 10*time.Second)
- errch := copyToSent(composer.Worker(), ctx.copyto,
- copyBuf.Len(), &copyBuf)
+ errch := copyToSent(ctx.copyto, copyBuf.Len(), &copyBuf)
err = <-errch
if err != nil {
errmsg := fmt.Sprintf(
@@ -558,23 +557,32 @@ func newJmapSender(
return writer, err
}
-func copyToSent(worker *types.Worker, dest string,
- n int, msg io.Reader,
-) <-chan error {
- errCh := make(chan error)
- worker.PostAction(&types.AppendMessage{
- Destination: dest,
- Flags: models.SeenFlag,
- Date: time.Now(),
- Reader: msg,
- Length: n,
- }, func(msg types.WorkerMessage) {
- switch msg := msg.(type) {
- case *types.Done:
- errCh <- nil
- case *types.Error:
- errCh <- msg.Error
- }
- })
+func copyToSent(dest string, n int, msg io.Reader) <-chan error {
+ errCh := make(chan error, 1)
+ acct := app.SelectedAccount()
+ if acct == nil {
+ errCh <- errors.New("No account selected")
+ return errCh
+ }
+ store := acct.Store()
+ if store == nil {
+ errCh <- errors.New("No message store selected")
+ return errCh
+ }
+ store.Append(
+ dest,
+ 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/config/aerc.conf b/config/aerc.conf
index cf9aafa2..d8142197 100644
--- a/config/aerc.conf
+++ b/config/aerc.conf
@@ -585,6 +585,10 @@ message/rfc822=colorize
#mail-deleted=mbsync "$AERC_ACCOUNT:$AERC_FOLDER" &
#
+# Executed when aerc adds mail to a folder
+#mail-added=mbsync "$AERC_ACCOUNT:$AERC_FOLDER" &
+
+#
# Executed when aerc starts
#aerc-startup=aerc :terminal calcurse && aerc :next-tab
diff --git a/config/hooks.go b/config/hooks.go
index 7a6047c1..b1b71a25 100644
--- a/config/hooks.go
+++ b/config/hooks.go
@@ -12,6 +12,7 @@ type HooksConfig struct {
AercShutdown string `ini:"aerc-shutdown"`
MailReceived string `ini:"mail-received"`
MailDeleted string `ini:"mail-deleted"`
+ MailAdded string `ini:"mail-added"`
}
var Hooks HooksConfig
diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index 200c0609..34bfb882 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -971,6 +971,21 @@ They are configured in the *[hooks]* section of aerc.conf.
*mail-deleted* = _mbsync "$AERC_ACCOUNT:$AERC_FOLDER"_
+*mail-added* = _<command>_
+ Executed when a message is added to a folder. Note that this hook is not
+ triggered when a new message is received (use *mail-received* for that) but
+ rather is only triggered when aerc itself adds a message to a folder, e.g.
+ when moving or copying a message.
+
+ Variables:
+
+ - *AERC_ACCOUNT*
+ - *AERC_FOLDER*
+
+ Example:
+
+ *mail-added* = _mbsync "$AERC_ACCOUNT:$AERC_FOLDER"_
+
*aerc-shutdown* = _<command>_
Executed when aerc shuts down. Aerc will wait for the command to finish
before exiting.
diff --git a/lib/hooks/mail-added.go b/lib/hooks/mail-added.go
new file mode 100644
index 00000000..f146d010
--- /dev/null
+++ b/lib/hooks/mail-added.go
@@ -0,0 +1,23 @@
+package hooks
+
+import (
+ "fmt"
+
+ "git.sr.ht/~rjarry/aerc/config"
+)
+
+type MailAdded struct {
+ Account string
+ Folder string
+}
+
+func (m *MailAdded) Cmd() string {
+ return config.Hooks.MailAdded
+}
+
+func (m *MailAdded) Env() []string {
+ return []string{
+ fmt.Sprintf("AERC_ACCOUNT=%s", m.Account),
+ fmt.Sprintf("AERC_FOLDER=%s", m.Folder),
+ }
+}
diff --git a/lib/msgstore.go b/lib/msgstore.go
index 9c6b750d..cb81abef 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -69,6 +69,7 @@ type MessageStore struct {
triggerNewEmail func(*models.MessageInfo)
triggerDirectoryChange func()
triggerMailDeleted func()
+ triggerMailAdded func(string)
threadBuilderDebounce *time.Timer
threadBuilderDelay time.Duration
@@ -89,7 +90,8 @@ func NewMessageStore(worker *types.Worker,
reverseOrder bool, reverseThreadOrder bool, sortThreadSiblings bool,
triggerNewEmail func(*models.MessageInfo),
triggerDirectoryChange func(), triggerMailDeleted func(),
- onSelect func(*models.MessageInfo), threadContext bool,
+ triggerMailAdded func(string), onSelect func(*models.MessageInfo),
+ threadContext bool,
) *MessageStore {
if !worker.Backend.Capabilities().Thread {
clientThreads = true
@@ -124,6 +126,7 @@ func NewMessageStore(worker *types.Worker,
triggerNewEmail: triggerNewEmail,
triggerDirectoryChange: triggerDirectoryChange,
triggerMailDeleted: triggerMailDeleted,
+ triggerMailAdded: triggerMailAdded,
threadBuilderDelay: clientThreadsDelay,
@@ -608,7 +611,12 @@ func (store *MessageStore) Copy(uids []uint32, dest string, createDest bool,
store.worker.PostAction(&types.CopyMessages{
Destination: dest,
Uids: uids,
- }, cb)
+ }, func(msg types.WorkerMessage) {
+ if _, ok := msg.(*types.Done); ok {
+ store.triggerMailAdded(dest)
+ }
+ cb(msg)
+ })
}
func (store *MessageStore) Move(uids []uint32, dest string, createDest bool,
@@ -635,11 +643,29 @@ func (store *MessageStore) Move(uids []uint32, dest string, createDest bool,
cb(msg)
case *types.Done:
store.triggerMailDeleted()
+ store.triggerMailAdded(dest)
cb(msg)
}
})
}
+func (store *MessageStore) Append(dest string, flags models.Flags, date time.Time,
+ reader io.Reader, length int, cb func(msg types.WorkerMessage),
+) {
+ store.worker.PostAction(&types.AppendMessage{
+ Destination: dest,
+ Flags: flags,
+ Date: date,
+ Reader: reader,
+ Length: length,
+ }, func(msg types.WorkerMessage) {
+ if _, ok := msg.(*types.Done); ok {
+ store.triggerMailAdded(dest)
+ }
+ cb(msg)
+ })
+}
+
func (store *MessageStore) Flag(uids []uint32, flags models.Flags,
enable bool, cb func(msg types.WorkerMessage),
) {