aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--commands/account/search.go1
-rw-r--r--commands/completion_helpers.go2
-rw-r--r--commands/compose/postpone.go2
-rw-r--r--commands/msg/read.go5
-rw-r--r--commands/msg/recall.go12
-rw-r--r--config/templates.go1
-rw-r--r--config/ui.go3
-rw-r--r--doc/aerc-config.5.scd7
-rw-r--r--doc/aerc-search.1.scd2
-rw-r--r--doc/aerc-templates.7.scd3
-rw-r--r--doc/aerc.1.scd2
-rw-r--r--lib/state/templates.go10
-rw-r--r--models/models.go3
-rw-r--r--models/templates.go1
-rw-r--r--worker/imap/imap.go2
-rw-r--r--worker/jmap/jmap.go5
-rw-r--r--worker/lib/maildir.go4
-rw-r--r--worker/notmuch/notmuch.go3
-rw-r--r--worker/notmuch/worker.go27
19 files changed, 82 insertions, 13 deletions
diff --git a/commands/account/search.go b/commands/account/search.go
index be3b125f..0246a9eb 100644
--- a/commands/account/search.go
+++ b/commands/account/search.go
@@ -73,6 +73,7 @@ var flagValues = map[string]models.Flags{
"seen": models.SeenFlag,
"answered": models.AnsweredFlag,
"flagged": models.FlaggedFlag,
+ "draft": models.DraftFlag,
}
func (s *SearchFilter) ParseFlag(arg string) error {
diff --git a/commands/completion_helpers.go b/commands/completion_helpers.go
index e4556594..b7ba6780 100644
--- a/commands/completion_helpers.go
+++ b/commands/completion_helpers.go
@@ -45,7 +45,7 @@ func GetAddress(search string) []string {
// GetFlagList returns a list of available flags for completion
func GetFlagList() []string {
- return []string{"Seen", "Answered", "Flagged"}
+ return []string{"Seen", "Answered", "Flagged", "Draft"}
}
// GetDateList returns a list of date terms for completion
diff --git a/commands/compose/postpone.go b/commands/compose/postpone.go
index a869417b..3c23eda3 100644
--- a/commands/compose/postpone.go
+++ b/commands/compose/postpone.go
@@ -108,7 +108,7 @@ func (p Postpone) Execute(args []string) error {
}
store.Append(
targetFolder,
- models.SeenFlag,
+ models.SeenFlag|models.DraftFlag,
time.Now(),
buf,
buf.Len(),
diff --git a/commands/msg/read.go b/commands/msg/read.go
index b487d8a8..5b4bd073 100644
--- a/commands/msg/read.go
+++ b/commands/msg/read.go
@@ -41,13 +41,16 @@ func (f *FlagMsg) ParseFlag(arg string) error {
case "flagged":
f.Flag = models.FlaggedFlag
f.FlagName = "flagged"
+ case "draft":
+ f.Flag = models.DraftFlag
+ f.FlagName = "draft"
default:
return fmt.Errorf("Unknown flag %q", arg)
}
return nil
}
-var validFlags = []string{"seen", "answered", "flagged"}
+var validFlags = []string{"seen", "answered", "flagged", "draft"}
func (*FlagMsg) CompleteFlag(arg string) []string {
return commands.FilterList(validFlags, arg, nil)
diff --git a/commands/msg/recall.go b/commands/msg/recall.go
index 059fe558..e5cd2ed1 100644
--- a/commands/msg/recall.go
+++ b/commands/msg/recall.go
@@ -15,6 +15,7 @@ import (
"git.sr.ht/~rjarry/aerc/config"
"git.sr.ht/~rjarry/aerc/lib"
"git.sr.ht/~rjarry/aerc/log"
+ "git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -44,10 +45,6 @@ func (r Recall) Execute(args []string) error {
if acct == nil {
return errors.New("No account selected")
}
- if acct.SelectedDirectory() != acct.AccountConfig().Postpone && !r.Force {
- return errors.New("Use -f to recall from outside the " +
- acct.AccountConfig().Postpone + " directory.")
- }
store := widget.Store()
if store == nil {
return errors.New("Cannot perform action. Messages still loading")
@@ -57,6 +54,13 @@ func (r Recall) Execute(args []string) error {
if err != nil {
return errors.Wrap(err, "Recall failed")
}
+
+ if acct.SelectedDirectory() != acct.AccountConfig().Postpone &&
+ !msgInfo.Flags.Has(models.DraftFlag) && !r.Force {
+ return errors.New("Use -f to recall non-draft messages from outside the " +
+ acct.AccountConfig().Postpone + " directory.")
+ }
+
log.Debugf("Recalling message <%s>", msgInfo.Envelope.MessageId)
addTab := func(composer *app.Composer) {
diff --git a/config/templates.go b/config/templates.go
index c5d11478..61c411fb 100644
--- a/config/templates.go
+++ b/config/templates.go
@@ -94,6 +94,7 @@ func (d *dummyData) HasAttachment() bool { return true }
func (d *dummyData) IsRecent() bool { return false }
func (d *dummyData) IsUnread() bool { return false }
func (d *dummyData) IsFlagged() bool { return false }
+func (d *dummyData) IsDraft() bool { return false }
func (d *dummyData) IsMarked() bool { return false }
func (d *dummyData) MessageId() string { return "123456789@foo.org" }
func (d *dummyData) Size() int { return 420 }
diff --git a/config/ui.go b/config/ui.go
index ed0b4a33..83b45230 100644
--- a/config/ui.go
+++ b/config/ui.go
@@ -55,9 +55,10 @@ type UIConfig struct {
IconReplied string `ini:"icon-replied" default:"r"`
IconNew string `ini:"icon-new" default:"N"`
IconOld string `ini:"icon-old" default:"O"`
+ IconDraft string `ini:"icon-draft" default:"d"`
IconFlagged string `ini:"icon-flagged" default:"!"`
IconMarked string `ini:"icon-marked" default:"*"`
- IconDeleted string `ini:"icon-deleted" default:"D"`
+ IconDeleted string `ini:"icon-deleted" default:"X"`
DirListDelay time.Duration `ini:"dirlist-delay" default:"200ms"`
DirListTree bool `ini:"dirlist-tree"`
DirListCollapse int `ini:"dirlist-collapse"`
diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index 043b738a..1aa9da5f 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -405,10 +405,15 @@ These options are configured in the *[ui]* section of _aerc.conf_.
Default: _\*_
+*icon-draft* = _<string>_
+ The icon to display in *column-flags* when the message is a draft.
+
+ Default: _d_
+
*icon-deleted* = _<string>_
The icon to display in *column-flags* when the message has been deleted.
- Default: _D_
+ Default: _X_
*fuzzy-complete* = _true_|_false_
When typing a command or option, the popover will now show not only the
diff --git a/doc/aerc-search.1.scd b/doc/aerc-search.1.scd
index 161a632f..fa630c1d 100644
--- a/doc/aerc-search.1.scd
+++ b/doc/aerc-search.1.scd
@@ -34,6 +34,8 @@ This syntax is common to all backends.
Replied messages
_Flagged_
Flagged messages
+ _Draft_
+ Draft messages
*-H*: Search in the headers of the messages, for a specific header
Syntax: _Header: Value_
diff --git a/doc/aerc-templates.7.scd b/doc/aerc-templates.7.scd
index 160fb77f..6e87c616 100644
--- a/doc/aerc-templates.7.scd
+++ b/doc/aerc-templates.7.scd
@@ -116,7 +116,8 @@ available always.
{{.Flags | join ""}}
```
-*IsReplied*, *HasAttachment*, *IsFlagged*, *IsRecent*, *IsUnread*, *IsMarked*
+*IsReplied*, *HasAttachment*, *IsFlagged*, *IsRecent*, *IsUnread*, *IsMarked*,
+*IsDraft*
Individual boolean flags. not available when composing, replying nor
forwarding.
diff --git a/doc/aerc.1.scd b/doc/aerc.1.scd
index d77bbf03..1ee61060 100644
--- a/doc/aerc.1.scd
+++ b/doc/aerc.1.scd
@@ -418,6 +418,8 @@ message list, the message in the message viewer, etc).
Message has been answered
_Flagged_
Message is flagged for urgent/special attention
+ _Draft_
+ Message is a draft
*:unflag* [*-t*] _<flag>_
Operates exactly like *:flag*, defaulting to unsetting (disabling) flags.
diff --git a/lib/state/templates.go b/lib/state/templates.go
index ac701e9f..d039f1b6 100644
--- a/lib/state/templates.go
+++ b/lib/state/templates.go
@@ -393,6 +393,9 @@ func (d *templateData) Flags() []string {
default:
flags = append(flags, d.ui().IconOld) // message is unread and old
}
+ if d.info.Flags.Has(models.DraftFlag) {
+ flags = append(flags, d.ui().IconDraft)
+ }
if d.info.Flags.Has(models.DeletedFlag) {
flags = append(flags, d.ui().IconDeleted)
}
@@ -452,6 +455,13 @@ func (d *templateData) IsFlagged() bool {
return false
}
+func (d *templateData) IsDraft() bool {
+ if d.info != nil && d.info.Flags.Has(models.DraftFlag) {
+ return true
+ }
+ return false
+}
+
func (d *templateData) IsMarked() bool {
return d.marked
}
diff --git a/models/models.go b/models/models.go
index 55dd2347..80bc0db1 100644
--- a/models/models.go
+++ b/models/models.go
@@ -30,6 +30,9 @@ const (
// FlaggedFlag marks a message with a user flag
FlaggedFlag
+
+ // DraftFlag marks a message as a draft
+ DraftFlag
)
func (f Flags) Has(flags Flags) bool {
diff --git a/models/templates.go b/models/templates.go
index a6a85371..5caed158 100644
--- a/models/templates.go
+++ b/models/templates.go
@@ -38,6 +38,7 @@ type TemplateData interface {
IsRecent() bool
IsUnread() bool
IsMarked() bool
+ IsDraft() bool
MessageId() string
Role() string
Size() int
diff --git a/worker/imap/imap.go b/worker/imap/imap.go
index 82ee2e2e..fbdcb2b9 100644
--- a/worker/imap/imap.go
+++ b/worker/imap/imap.go
@@ -85,6 +85,7 @@ var imapToFlag = map[string]models.Flags{
imap.AnsweredFlag: models.AnsweredFlag,
imap.DeletedFlag: models.DeletedFlag,
imap.FlaggedFlag: models.FlaggedFlag,
+ imap.DraftFlag: models.DraftFlag,
}
var flagToImap = map[models.Flags]string{
@@ -93,6 +94,7 @@ var flagToImap = map[models.Flags]string{
models.AnsweredFlag: imap.AnsweredFlag,
models.DeletedFlag: imap.DeletedFlag,
models.FlaggedFlag: imap.FlaggedFlag,
+ models.DraftFlag: imap.DraftFlag,
}
func translateImapFlags(imapFlags []string) models.Flags {
diff --git a/worker/jmap/jmap.go b/worker/jmap/jmap.go
index 8012b6e4..bb0f75f9 100644
--- a/worker/jmap/jmap.go
+++ b/worker/jmap/jmap.go
@@ -67,6 +67,9 @@ func flagsToKeywords(flags models.Flags) map[string]bool {
if flags.Has(models.FlaggedFlag) {
kw["$flagged"] = true
}
+ if flags.Has(models.DraftFlag) {
+ kw["$draft"] = true
+ }
return kw
}
@@ -81,6 +84,8 @@ func keywordsToFlags(kw map[string]bool) models.Flags {
f |= models.AnsweredFlag
case "$flagged":
f |= models.FlaggedFlag
+ case "$draft":
+ f |= models.DraftFlag
}
}
}
diff --git a/worker/lib/maildir.go b/worker/lib/maildir.go
index 43d3b820..a4a0ecd5 100644
--- a/worker/lib/maildir.go
+++ b/worker/lib/maildir.go
@@ -118,7 +118,7 @@ var MaildirToFlag = map[maildir.Flag]models.Flags{
maildir.FlagSeen: models.SeenFlag,
maildir.FlagTrashed: models.DeletedFlag,
maildir.FlagFlagged: models.FlaggedFlag,
- // maildir.FlagDraft Flag = 'D'
+ maildir.FlagDraft: models.DraftFlag,
// maildir.FlagPassed Flag = 'P'
}
@@ -127,7 +127,7 @@ var FlagToMaildir = map[models.Flags]maildir.Flag{
models.SeenFlag: maildir.FlagSeen,
models.DeletedFlag: maildir.FlagTrashed,
models.FlaggedFlag: maildir.FlagFlagged,
- // maildir.FlagDraft Flag = 'D'
+ models.DraftFlag: maildir.FlagDraft,
// maildir.FlagPassed Flag = 'P'
}
diff --git a/worker/notmuch/notmuch.go b/worker/notmuch/notmuch.go
index 5610cac0..1d064fd2 100644
--- a/worker/notmuch/notmuch.go
+++ b/worker/notmuch/notmuch.go
@@ -8,17 +8,20 @@ import "git.sr.ht/~rjarry/aerc/models"
var tagToFlag = map[string]models.Flags{
"unread": models.SeenFlag,
"replied": models.AnsweredFlag,
+ "draft": models.DraftFlag,
"flagged": models.FlaggedFlag,
}
var flagToTag = map[models.Flags]string{
models.SeenFlag: "unread",
models.AnsweredFlag: "replied",
+ models.DraftFlag: "draft",
models.FlaggedFlag: "flagged",
}
var flagToInvert = map[models.Flags]bool{
models.SeenFlag: true,
models.AnsweredFlag: false,
+ models.DraftFlag: false,
models.FlaggedFlag: false,
}
diff --git a/worker/notmuch/worker.go b/worker/notmuch/worker.go
index 374a20b7..80a8d720 100644
--- a/worker/notmuch/worker.go
+++ b/worker/notmuch/worker.go
@@ -894,9 +894,16 @@ func (w *worker) handleAppendMessage(msg *types.AppendMessage) error {
return err
}
writer.Close()
- if _, err := w.db.IndexFile(filename); err != nil {
+ id, err := w.db.IndexFile(filename)
+ if err != nil {
return err
}
+
+ err = w.addFlags(id, msg.Flags)
+ if err != nil {
+ return err
+ }
+
w.w.PostMessage(&types.DirectoryInfo{
Info: w.getDirectoryInfo(w.currentQueryName, w.query),
}, nil)
@@ -973,3 +980,21 @@ func (w *worker) processNewMaildirFiles(dir string) error {
return nil
}
+
+func (w *worker) addFlags(id string, flags models.Flags) error {
+ addTags := []string{}
+ removeTags := []string{}
+ for flag, tag := range flagToTag {
+ if !flags.Has(flag) {
+ continue
+ }
+
+ if flagToInvert[flag] {
+ removeTags = append(removeTags, tag)
+ } else {
+ addTags = append(addTags, tag)
+ }
+ }
+
+ return w.db.MsgModifyTags(id, addTags, removeTags)
+}