summaryrefslogtreecommitdiff
path: root/worker/maildir
diff options
context:
space:
mode:
authorTim Culverhouse <tim@timculverhouse.com>2022-05-30 07:34:18 -0500
committerRobin Jarry <robin@jarry.cc>2022-05-31 14:32:51 +0200
commit2551dd1bfa2c68a6ba8644a0c45b24fce8874674 (patch)
treeed752720e1a08708505fd9574b49629d5df84997 /worker/maildir
parent30d57889741cfa8284eec9b32b29144fe01002a2 (diff)
downloadaerc-2551dd1bfa2c68a6ba8644a0c45b24fce8874674.zip
feat: add background mail polling option for all workers
Check for new mail (recent, unseen, exists counts) with an external command, or for imap with the STATUS command, at start or on reconnection and every X time duration IMAP: The selected folder is skipped, per specification. Additional config options are included for including/excluding folders explicitly. Maildir/Notmuch: An external command will be run in the background to check for new mail. An optional timeout can be used with maildir/notmuch. Default is 10s New account options: check-mail check-mail-cmd (maildir/notmuch only) check-mail-timeout (maildir/notmuch only), default 10s check-mail-include (IMAP only) check-mail-exclude (IMAP only) If unset, or set less than or equal to 0, check-mail will be ignored Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Tested-by: Moritz Poldrack <moritz@poldrack.dev> Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'worker/maildir')
-rw-r--r--worker/maildir/worker.go53
1 files changed, 42 insertions, 11 deletions
diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go
index 4a2a19b..d3de844 100644
--- a/worker/maildir/worker.go
+++ b/worker/maildir/worker.go
@@ -2,12 +2,14 @@ package maildir
import (
"bytes"
+ "context"
"errors"
"fmt"
"io"
"io/ioutil"
"net/url"
"os"
+ "os/exec"
"path/filepath"
"sort"
"strings"
@@ -60,17 +62,25 @@ func (w *Worker) Run() {
func (w *Worker) handleAction(action types.WorkerMessage) {
msg := w.worker.ProcessAction(action)
- if err := w.handleMessage(msg); err == errUnsupported {
- w.worker.PostMessage(&types.Unsupported{
- Message: types.RespondTo(msg),
- }, nil)
- } else if err != nil {
- w.worker.PostMessage(&types.Error{
- Message: types.RespondTo(msg),
- Error: err,
- }, nil)
- } else {
- w.done(msg)
+ switch msg := msg.(type) {
+ // Explicitly handle all asynchronous actions. Async actions are
+ // responsible for posting their own Done message
+ case *types.CheckMail:
+ go w.handleCheckMail(msg)
+ default:
+ // Default handling, will be performed synchronously
+ if err := w.handleMessage(msg); err == errUnsupported {
+ w.worker.PostMessage(&types.Unsupported{
+ Message: types.RespondTo(msg),
+ }, nil)
+ } else if err != nil {
+ w.worker.PostMessage(&types.Error{
+ Message: types.RespondTo(msg),
+ Error: err,
+ }, nil)
+ } else {
+ w.done(msg)
+ }
}
}
@@ -672,3 +682,24 @@ func (w *Worker) msgInfoFromUid(uid uint32) (*models.MessageInfo, error) {
}
return info, nil
}
+
+func (w *Worker) handleCheckMail(msg *types.CheckMail) {
+ ctx, cancel := context.WithTimeout(context.Background(), msg.Timeout)
+ defer cancel()
+ cmd := exec.CommandContext(ctx, "sh", "-c", msg.Command)
+ ch := make(chan error)
+ go func() {
+ err := cmd.Run()
+ ch <- err
+ }()
+ select {
+ case <-ctx.Done():
+ w.err(msg, fmt.Errorf("checkmail: timed out"))
+ case err := <-ch:
+ if err != nil {
+ w.err(msg, fmt.Errorf("checkmail: error running command: %v", err))
+ } else {
+ w.done(msg)
+ }
+ }
+}