diff options
| author | Shivesh Mandalia <mail@shivesh.org> | 2021-10-23 18:37:06 +0100 |
|---|---|---|
| committer | Shivesh Mandalia <mail@shivesh.org> | 2021-10-23 18:37:06 +0100 |
| commit | 5c7d4873908f28dde33013d10543e4cf1417525b (patch) | |
| tree | 50c381fd5ab776d2dbecfc8e590fd224e0f3c044 | |
| parent | 57292f268a961e559618d0b5007dbda4df33f00c (diff) | |
| download | aerc-5c7d4873908f28dde33013d10543e4cf1417525b.tar.gz aerc-5c7d4873908f28dde33013d10543e4cf1417525b.zip | |
Implement interface for my custom IMAP flags
| -rw-r--r-- | commands/msg/read.go | 25 | ||||
| -rw-r--r-- | doc/aerc-search.1.scd | 32 | ||||
| -rw-r--r-- | doc/aerc.1.scd | 16 | ||||
| -rw-r--r-- | lib/format/format.go | 35 | ||||
| -rw-r--r-- | lib/msgstore.go | 73 | ||||
| -rw-r--r-- | models/models.go | 10 | ||||
| -rw-r--r-- | worker/imap/flags.go | 257 | ||||
| -rw-r--r-- | worker/imap/imap.go | 18 | ||||
| -rw-r--r-- | worker/imap/search.go | 17 | ||||
| -rw-r--r-- | worker/imap/worker.go | 17 | ||||
| -rw-r--r-- | worker/types/messages.go | 49 |
11 files changed, 548 insertions, 1 deletions
diff --git a/commands/msg/read.go b/commands/msg/read.go index 95becf7..2b7537b 100644 --- a/commands/msg/read.go +++ b/commands/msg/read.go @@ -96,6 +96,31 @@ func (FlagMsg) Execute(aerc *widgets.Aerc, args []string) error { case "Flagged": flag = models.FlaggedFlag flagName = "flagged" + // NOTE(shivesh): my custom flags + case "important": + flag = models.ImportantFlag + flagName = "important" + case "list": + flag = models.ListFlag + flagName = "list" + case "food": + flag = models.FoodFlag + flagName = "food" + case "personal": + flag = models.PersonalFlag + flagName = "personal" + case "work": + flag = models.WorkFlag + flagName = "work" + case "physics": + flag = models.PhysicsFlag + flagName = "physics" + case "todo": + flag = models.TodoFlag + flagName = "todo" + case "later": + flag = models.LaterFlag + flagName = "later" default: return fmt.Errorf("Unknown / Prohibited flag \"%v\"", opt.Value) } diff --git a/doc/aerc-search.1.scd b/doc/aerc-search.1.scd index b90a934..35b0026 100644 --- a/doc/aerc-search.1.scd +++ b/doc/aerc-search.1.scd @@ -30,6 +30,22 @@ aerc-search(1) Flagged Flagged messages + important + + list + + food + + personal + + work + + physics + + todo + + later + *-b*: Search in the body of the messages *-a*: Search in the entire text of the messages @@ -70,6 +86,22 @@ aerc-search(1) Flagged Flagged messages + important + + list + + food + + personal + + work + + physics + + todo + + later + *-b*: Search in the body of the messages *-a*: Search in the entire text of the messages diff --git a/doc/aerc.1.scd b/doc/aerc.1.scd index f678a0a..03dcadd 100644 --- a/doc/aerc.1.scd +++ b/doc/aerc.1.scd @@ -181,6 +181,22 @@ message list, the message in the message viewer, etc). Flagged Message is flagged for urgent/special attention + important + + list + + food + + personal + + work + + physics + + todo + + later + *unflag* [-t] <flag> Operates exactly like *flag*, defaulting to unsetting (disabling) flags. diff --git a/lib/format/format.go b/lib/format/format.go index 30e8be7..96a19b9 100644 --- a/lib/format/format.go +++ b/lib/format/format.go @@ -297,6 +297,15 @@ func ParseMessageFormat(format string, timeFmt string, ctx Ctx) (string, seen := false recent := false answered := false + // NOTE(shivesh): my custom flags + var importantFlag = "" + var listFlag = "" + var foodFlag = "" + var personalFlag = "" + var workFlag = "" + var physicsFlag = "" + var todoFlag = "" + var laterFlag = "" for _, flag := range ctx.MsgInfo.Flags { if flag == models.SeenFlag { seen = true @@ -305,6 +314,30 @@ func ParseMessageFormat(format string, timeFmt string, ctx Ctx) (string, } else if flag == models.AnsweredFlag { answered = true } + if flag == models.ImportantFlag { + importantFlag = "I" + } + if flag == models.ListFlag { + listFlag = "l" + } + if flag == models.FoodFlag { + foodFlag = "F" + } + if flag == models.PersonalFlag { + personalFlag = "P" + } + if flag == models.WorkFlag { + workFlag = "W" + } + if flag == models.PhysicsFlag { + physicsFlag = "X" + } + if flag == models.TodoFlag { + todoFlag = "T" + } + if flag == models.LaterFlag { + laterFlag = "L" + } if flag == models.DeletedFlag { delFlag = "D" // TODO: check if attachments @@ -329,7 +362,7 @@ func ParseMessageFormat(format string, timeFmt string, ctx Ctx) (string, markedFlag = "*" } retval = append(retval, '4', 's') - args = append(args, readReplyFlag+delFlag+flaggedFlag+markedFlag) + args = append(args, readReplyFlag+delFlag+flaggedFlag+markedFlag+importantFlag+listFlag+foodFlag+personalFlag+workFlag+physicsFlag+todoFlag+laterFlag) // Move the below cases to proper alphabetical positions once // implemented diff --git a/lib/msgstore.go b/lib/msgstore.go index 7af9fd2..222c9fc 100644 --- a/lib/msgstore.go +++ b/lib/msgstore.go @@ -361,6 +361,79 @@ func (store *MessageStore) Answered(uids []uint32, answered bool, }, cb) } +// NOTE(shivesh): my custom flags +func (store *MessageStore) Important(uids []uint32, important bool, + cb func(msg types.WorkerMessage)) { + + store.worker.PostAction(&types.ImportantMessages{ + Important: important, + Uids: uids, + }, cb) +} + +func (store *MessageStore) List(uids []uint32, list bool, + cb func(msg types.WorkerMessage)) { + + store.worker.PostAction(&types.ListMessages{ + List: list, + Uids: uids, + }, cb) +} + +func (store *MessageStore) Food(uids []uint32, food bool, + cb func(msg types.WorkerMessage)) { + + store.worker.PostAction(&types.FoodMessages{ + Food: food, + Uids: uids, + }, cb) +} + +func (store *MessageStore) Personal(uids []uint32, personal bool, + cb func(msg types.WorkerMessage)) { + + store.worker.PostAction(&types.PersonalMessages{ + Personal: personal, + Uids: uids, + }, cb) +} + +func (store *MessageStore) Work(uids []uint32, work bool, + cb func(msg types.WorkerMessage)) { + + store.worker.PostAction(&types.WorkMessages{ + Work: work, + Uids: uids, + }, cb) +} + +func (store *MessageStore) Physics(uids []uint32, physics bool, + cb func(msg types.WorkerMessage)) { + + store.worker.PostAction(&types.PhysicsMessages{ + Physics: physics, + Uids: uids, + }, cb) +} + +func (store *MessageStore) Todo(uids []uint32, todo bool, + cb func(msg types.WorkerMessage)) { + + store.worker.PostAction(&types.TodoMessages{ + Todo: todo, + Uids: uids, + }, cb) +} + +func (store *MessageStore) Later(uids []uint32, later bool, + cb func(msg types.WorkerMessage)) { + + store.worker.PostAction(&types.LaterMessages{ + Later: later, + Uids: uids, + }, cb) +} + func (store *MessageStore) Uids() []uint32 { if store.filter { return store.results diff --git a/models/models.go b/models/models.go index 45f3b9d..dabb00b 100644 --- a/models/models.go +++ b/models/models.go @@ -27,6 +27,16 @@ const ( // FlaggedFlag marks a message with a user flag FlaggedFlag + + // NOTE(shivesh): my custom flags + ImportantFlag + ListFlag + FoodFlag + PersonalFlag + WorkFlag + PhysicsFlag + TodoFlag + LaterFlag ) type Directory struct { diff --git a/worker/imap/flags.go b/worker/imap/flags.go index aef1019..d71e3bb 100644 --- a/worker/imap/flags.go +++ b/worker/imap/flags.go @@ -76,6 +76,263 @@ func (imapw *IMAPWorker) handleAnsweredMessages(msg *types.AnsweredMessages) { }) } +// NOTE(shivesh): my custom flags +func (imapw *IMAPWorker) handleImportantMessages(msg *types.ImportantMessages) { + item := imap.FormatFlagsOp(imap.AddFlags, true) + flags := []interface{}{"important"} + if !msg.Important { + item = imap.FormatFlagsOp(imap.RemoveFlags, true) + flags = []interface{}{"important"} + } + uids := toSeqSet(msg.Uids) + emitErr := func(err error) { + imapw.worker.PostMessage(&types.Error{ + Message: types.RespondTo(msg), + Error: err, + }, nil) + } + if err := imapw.client.UidStore(uids, item, flags, nil); err != nil { + emitErr(err) + return + } + imapw.worker.PostAction(&types.FetchMessageHeaders{ + Uids: msg.Uids, + }, func(_msg types.WorkerMessage) { + switch m := _msg.(type) { + case *types.Error: + err := fmt.Errorf("handleImportantMessages: %v", m.Error) + imapw.worker.Logger.Printf("could not fetch headers: %s", err) + emitErr(err) + case *types.Done: + imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) + } + }) +} + +func (imapw *IMAPWorker) handleListMessages(msg *types.ListMessages) { + item := imap.FormatFlagsOp(imap.AddFlags, true) + flags := []interface{}{"list"} + if !msg.List { + item = imap.FormatFlagsOp(imap.RemoveFlags, true) + flags = []interface{}{"list"} + } + uids := toSeqSet(msg.Uids) + emitErr := func(err error) { + imapw.worker.PostMessage(&types.Error{ + Message: types.RespondTo(msg), + Error: err, + }, nil) + } + if err := imapw.client.UidStore(uids, item, flags, nil); err != nil { + emitErr(err) + return + } + imapw.worker.PostAction(&types.FetchMessageHeaders{ + Uids: msg.Uids, + }, func(_msg types.WorkerMessage) { + switch m := _msg.(type) { + case *types.Error: + err := fmt.Errorf("handleListMessages: %v", m.Error) + imapw.worker.Logger.Printf("could not fetch headers: %s", err) + emitErr(err) + case *types.Done: + imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) + } + }) +} + +func (imapw *IMAPWorker) handleFoodMessages(msg *types.FoodMessages) { + item := imap.FormatFlagsOp(imap.AddFlags, true) + flags := []interface{}{"food"} + if !msg.Food { + item = imap.FormatFlagsOp(imap.RemoveFlags, true) + flags = []interface{}{"food"} + } + uids := toSeqSet(msg.Uids) + emitErr := func(err error) { + imapw.worker.PostMessage(&types.Error{ + Message: types.RespondTo(msg), + Error: err, + }, nil) + } + if err := imapw.client.UidStore(uids, item, flags, nil); err != nil { + emitErr(err) + return + } + imapw.worker.PostAction(&types.FetchMessageHeaders{ + Uids: msg.Uids, + }, func(_msg types.WorkerMessage) { + switch m := _msg.(type) { + case *types.Error: + err := fmt.Errorf("handleFoodMessages: %v", m.Error) + imapw.worker.Logger.Printf("could not fetch headers: %s", err) + emitErr(err) + case *types.Done: + imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) + } + }) +} + +func (imapw *IMAPWorker) handlePersonalMessages(msg *types.PersonalMessages) { + item := imap.FormatFlagsOp(imap.AddFlags, true) + flags := []interface{}{"personal"} + if !msg.Personal { + item = imap.FormatFlagsOp(imap.RemoveFlags, true) + flags = []interface{}{"personal"} + } + uids := toSeqSet(msg.Uids) + emitErr := func(err error) { + imapw.worker.PostMessage(&types.Error{ + Message: types.RespondTo(msg), + Error: err, + }, nil) + } + if err := imapw.client.UidStore(uids, item, flags, nil); err != nil { + emitErr(err) + return + } + imapw.worker.PostAction(&types.FetchMessageHeaders{ + Uids: msg.Uids, + }, func(_msg types.WorkerMessage) { + switch m := _msg.(type) { + case *types.Error: + err := fmt.Errorf("handlePersonalMessages: %v", m.Error) + imapw.worker.Logger.Printf("could not fetch headers: %s", err) + emitErr(err) + case *types.Done: + imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) + } + }) +} + +func (imapw *IMAPWorker) handleWorkMessages(msg *types.WorkMessages) { + item := imap.FormatFlagsOp(imap.AddFlags, true) + flags := []interface{}{"work"} + if !msg.Work { + item = imap.FormatFlagsOp(imap.RemoveFlags, true) + flags = []interface{}{"work"} + } + uids := toSeqSet(msg.Uids) + emitErr := func(err error) { + imapw.worker.PostMessage(&types.Error{ + Message: types.RespondTo(msg), + Error: err, + }, nil) + } + if err := imapw.client.UidStore(uids, item, flags, nil); err != nil { + emitErr(err) + return + } + imapw.worker.PostAction(&types.FetchMessageHeaders{ + Uids: msg.Uids, + }, func(_msg types.WorkerMessage) { + switch m := _msg.(type) { + case *types.Error: + err := fmt.Errorf("handleWorkMessages: %v", m.Error) + imapw.worker.Logger.Printf("could not fetch headers: %s", err) + emitErr(err) + case *types.Done: + imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) + } + }) +} + +func (imapw *IMAPWorker) handlePhysicsMessages(msg *types.PhysicsMessages) { + item := imap.FormatFlagsOp(imap.AddFlags, true) + flags := []interface{}{"physics"} + if !msg.Physics { + item = imap.FormatFlagsOp(imap.RemoveFlags, true) + flags = []interface{}{"physics"} + } + uids := toSeqSet(msg.Uids) + emitErr := func(err error) { + imapw.worker.PostMessage(&types.Error{ + Message: types.RespondTo(msg), + Error: err, + }, nil) + } + if err := imapw.client.UidStore(uids, item, flags, nil); err != nil { + emitErr(err) + return + } + imapw.worker.PostAction(&types.FetchMessageHeaders{ + Uids: msg.Uids, + }, func(_msg types.WorkerMessage) { + switch m := _msg.(type) { + case *types.Error: + err := fmt.Errorf("handlePhysicsMessages: %v", m.Error) + imapw.worker.Logger.Printf("could not fetch headers: %s", err) + emitErr(err) + case *types.Done: + imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) + } + }) +} + +func (imapw *IMAPWorker) handleTodoMessages(msg *types.TodoMessages) { + item := imap.FormatFlagsOp(imap.AddFlags, true) + flags := []interface{}{"todo"} + if !msg.Todo { + item = imap.FormatFlagsOp(imap.RemoveFlags, true) + flags = []interface{}{"todo"} + } + uids := toSeqSet(msg.Uids) + emitErr := func(err error) { + imapw.worker.PostMessage(&types.Error{ + Message: types.RespondTo(msg), + Error: err, + }, nil) + } + if err := imapw.client.UidStore(uids, item, flags, nil); err != nil { + emitErr(err) + return + } + imapw.worker.PostAction(&types.FetchMessageHeaders{ + Uids: msg.Uids, + }, func(_msg types.WorkerMessage) { + switch m := _msg.(type) { + case *types.Error: + err := fmt.Errorf("handleTodoMessages: %v", m.Error) + imapw.worker.Logger.Printf("could not fetch headers: %s", err) + emitErr(err) + case *types.Done: + imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) + } + }) +} + +func (imapw *IMAPWorker) handleLaterMessages(msg *types.LaterMessages) { + item := imap.FormatFlagsOp(imap.AddFlags, true) + flags := []interface{}{"later"} + if !msg.Later { + item = imap.FormatFlagsOp(imap.RemoveFlags, true) + flags = []interface{}{"later"} + } + uids := toSeqSet(msg.Uids) + emitErr := func(err error) { + imapw.worker.PostMessage(&types.Error{ + Message: types.RespondTo(msg), + Error: err, + }, nil) + } + if err := imapw.client.UidStore(uids, item, flags, nil); err != nil { + emitErr(err) + return + } + imapw.worker.PostAction(&types.FetchMessageHeaders{ + Uids: msg.Uids, + }, func(_msg types.WorkerMessage) { + switch m := _msg.(type) { + case *types.Error: + err := fmt.Errorf("handleLaterMessages: %v", m.Error) + imapw.worker.Logger.Printf("could not fetch headers: %s", err) + emitErr(err) + case *types.Done: + imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) + } + }) +} + func (imapw *IMAPWorker) handleFlagMessages(msg *types.FlagMessages) { flags := []interface{}{flagToImap[msg.Flag]} item := imap.FormatFlagsOp(imap.AddFlags, true) diff --git a/worker/imap/imap.go b/worker/imap/imap.go index 29dbc10..e625374 100644 --- a/worker/imap/imap.go +++ b/worker/imap/imap.go @@ -85,6 +85,15 @@ var imapToFlag = map[string]models.Flag{ imap.AnsweredFlag: models.AnsweredFlag, imap.DeletedFlag: models.DeletedFlag, imap.FlaggedFlag: models.FlaggedFlag, + // NOTE(shivesh): my custom flags + "important": models.ImportantFlag, + "list": models.ListFlag, + "food": models.FoodFlag, + "personal": models.PersonalFlag, + "work": models.WorkFlag, + "physics": models.PhysicsFlag, + "todo": models.TodoFlag, + "later": models.LaterFlag, } var flagToImap = map[models.Flag]string{ @@ -93,6 +102,15 @@ var flagToImap = map[models.Flag]string{ models.AnsweredFlag: imap.AnsweredFlag, models.DeletedFlag: imap.DeletedFlag, models.FlaggedFlag: imap.FlaggedFlag, + // NOTE(shivesh): my custom flags + models.ImportantFlag: "important", + models.ListFlag: "list", + models.FoodFlag: "food", + models.PersonalFlag: "personal", + models.WorkFlag: "work", + models.PhysicsFlag: "physics", + models.TodoFlag: "todo", + models.LaterFlag: "later", } func translateImapFlags(imapFlags []string) []models.Flag { diff --git a/worker/imap/search.go b/worker/imap/search.go index f866b1c..d27648b 100644 --- a/worker/imap/search.go +++ b/worker/imap/search.go @@ -66,6 +66,23 @@ func getParsedFlag(name string) (string, error) { return imap.FlaggedFlag, nil case "answered": return imap.AnsweredFlag, nil + // NOTE(shivesh): my custom flags + case "important": + return name, nil + case "list": + return name, nil + case "food": + return name, nil + case "personal": + return name, nil + case "work": + return name, nil + case "physics": + return name, nil + case "todo": + return name, nil + case "later": + return name, nil } return imap.FlaggedFlag, errors.New("Flag not suppored") } diff --git a/worker/imap/worker.go b/worker/imap/worker.go index dab0afb..d5d4421 100644 --- a/worker/imap/worker.go +++ b/worker/imap/worker.go @@ -181,6 +181,23 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { w.handleFlagMessages(msg) case *types.AnsweredMessages: w.handleAnsweredMessages(msg) + // NOTE(shivesh): my custom flags + case *types.ImportantMessages: + w.handleImportantMessages(msg) + case *types.ListMessages: + w.handleListMessages(msg) + case *types.FoodMessages: + w.handleFoodMessages(msg) + case *types.PersonalMessages: + w.handlePersonalMessages(msg) + case *types.WorkMessages: + w.handleWorkMessages(msg) + case *types.PhysicsMessages: + w.handlePhysicsMessages(msg) + case *types.TodoMessages: + w.handleTodoMessages(msg) + case *types.LaterMessages: + w.handleLaterMessages(msg) case *types.CopyMessages: w.handleCopyMessages(msg) case *types.AppendMessage: diff --git a/worker/types/messages.go b/worker/types/messages.go index ab0e545..ea61211 100644 --- a/worker/types/messages.go +++ b/worker/types/messages.go @@ -133,6 +133,55 @@ type AnsweredMessages struct { Uids []uint32 } +// NOTE(shivesh): my custom flags +type ImportantMessages struct { + Message + Important bool + Uids []uint32 +} + +type ListMessages struct { + Message + List bool + Uids []uint32 +} + +type FoodMessages struct { + Message + Food bool + Uids []uint32 +} + +type PersonalMessages struct { + Message + Personal bool + Uids []uint32 +} + +type WorkMessages struct { + Message + Work bool + Uids []uint32 +} + +type PhysicsMessages struct { + Message + Physics bool + Uids []uint32 +} + +type TodoMessages struct { + Message + Todo bool + Uids []uint32 +} + +type LaterMessages struct { + Message + Later bool + Uids []uint32 +} + type CopyMessages struct { Message Destination string |
