summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--go.mod1
-rw-r--r--go.sum2
-rw-r--r--worker/maildir/worker.go81
-rw-r--r--worker/worker.go6
4 files changed, 76 insertions, 14 deletions
diff --git a/go.mod b/go.mod
index 2fb4ac8..74ad22d 100644
--- a/go.mod
+++ b/go.mod
@@ -14,6 +14,7 @@ require (
 	github.com/emersion/go-message v0.10.4
 	github.com/emersion/go-sasl v0.0.0-20190704090222-36b50694675c
 	github.com/emersion/go-smtp v0.11.1
+	github.com/fsnotify/fsnotify v1.4.7
 	github.com/gdamore/tcell v1.1.2
 	github.com/go-ini/ini v1.42.0
 	github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
diff --git a/go.sum b/go.sum
index 31f0d5e..79628de 100644
--- a/go.sum
+++ b/go.sum
@@ -39,6 +39,8 @@ github.com/emersion/go-smtp v0.11.1 h1:2IBWhU2zjrfOOmZal3qRxVsfYnf0rN+ccImZrjnMT
 github.com/emersion/go-smtp v0.11.1/go.mod h1:CfUbM5NgspbOMHFEgCdoK2PVrKt48HAPtL8hnahwfYg=
 github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe h1:40SWqY0zE3qCi6ZrtTf5OUdNm5lDnGnjRSq9GgmeTrg=
 github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
 github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
 github.com/go-ini/ini v1.42.0 h1:TWr1wGj35+UiWHlBA8er89seFXxzwFn11spilrrj+38=
diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go
index a5416cc..1e68a2e 100644
--- a/worker/maildir/worker.go
+++ b/worker/maildir/worker.go
@@ -8,6 +8,7 @@ import (
 	"path/filepath"
 
 	"github.com/emersion/go-maildir"
+	"github.com/fsnotify/fsnotify"
 
 	"git.sr.ht/~sircmpwn/aerc/models"
 	"git.sr.ht/~sircmpwn/aerc/worker/types"
@@ -20,31 +21,68 @@ type Worker struct {
 	c        *Container
 	selected *maildir.Dir
 	worker   *types.Worker
+	watcher  *fsnotify.Watcher
 }
 
 // NewWorker creates a new maildir worker with the provided worker.
-func NewWorker(worker *types.Worker) *Worker {
-	return &Worker{worker: worker}
+func NewWorker(worker *types.Worker) (*Worker, error) {
+	watch, err := fsnotify.NewWatcher()
+	if err != nil {
+		return nil, fmt.Errorf("could not create file system watcher: %v", err)
+	}
+	return &Worker{worker: worker, watcher: watch}, nil
 }
 
 // Run starts the worker's message handling loop.
 func (w *Worker) Run() {
 	for {
-		action := <-w.worker.Actions
-		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)
+		select {
+		case action := <-w.worker.Actions:
+			w.handleAction(action)
+		case ev := <-w.watcher.Events:
+			w.handleFSEvent(ev)
 		}
 	}
 }
 
+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)
+	}
+}
+
+func (w *Worker) handleFSEvent(ev fsnotify.Event) {
+	// we only care about files being created
+	if ev.Op != fsnotify.Create {
+		return
+	}
+	// if there's not a selected directory to rescan, ignore
+	if w.selected == nil {
+		return
+	}
+	_, err := w.selected.Unseen()
+	if err != nil {
+		w.worker.Logger.Printf("could not move new to cur : %v", err)
+		return
+	}
+	uids, err := w.c.UIDs(*w.selected)
+	if err != nil {
+		w.worker.Logger.Printf("could not scan UIDs: %v", err)
+		return
+	}
+	w.worker.PostMessage(&types.DirectoryContents{
+		Uids: uids,
+	}, nil)
+}
+
 func (w *Worker) done(msg types.WorkerMessage) {
 	w.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil)
 }
@@ -139,11 +177,28 @@ func (w *Worker) handleListDirectories(msg *types.ListDirectories) error {
 func (w *Worker) handleOpenDirectory(msg *types.OpenDirectory) error {
 	defer w.done(msg)
 	w.worker.Logger.Printf("opening %s", msg.Directory)
+
+	// remove existing watch path
+	if w.selected != nil {
+		prevDir := filepath.Join(string(*w.selected), "new")
+		if err := w.watcher.Remove(prevDir); err != nil {
+			return fmt.Errorf("could not unwatch previous directory: %v", err)
+		}
+	}
+
+	// open the directory
 	dir, err := w.c.OpenDirectory(msg.Directory)
 	if err != nil {
 		return err
 	}
 	w.selected = &dir
+
+	// add watch path
+	newDir := filepath.Join(string(*w.selected), "new")
+	if err := w.watcher.Add(newDir); err != nil {
+		return fmt.Errorf("could not add watch to directory: %v", err)
+	}
+
 	// TODO: why does this need to be sent twice??
 	info := &types.DirectoryInfo{
 		Info: &models.DirectoryInfo{
diff --git a/worker/worker.go b/worker/worker.go
index dd14a23..a37927e 100644
--- a/worker/worker.go
+++ b/worker/worker.go
@@ -29,7 +29,11 @@ func NewWorker(source string, logger *log.Logger) (*types.Worker, error) {
 	case "imaps":
 		worker.Backend = imap.NewIMAPWorker(worker)
 	case "maildir":
-		worker.Backend = maildir.NewWorker(worker)
+		if w, err := maildir.NewWorker(worker); err != nil {
+			return nil, fmt.Errorf("could not create maildir worker: %v", err)
+		} else {
+			worker.Backend = w
+		}
 	default:
 		return nil, fmt.Errorf("Unknown backend %s", u.Scheme)
 	}