Add flag based search options

Provide search and filter with the option to specify more flag based
conditions.
Use '-x <flag>' to search for messages with a flag (seen, answered,
flagged) and '-X <flag>' to search for messages without a flag.
This commit is contained in:
Tobias Wölfel 2020-07-24 10:36:19 +02:00 committed by Reto Brunner
parent 126c9437e8
commit 494bd674a9
3 changed files with 76 additions and 4 deletions

View file

@ -2,7 +2,7 @@ aerc-search(1)
# IMAP # IMAP
*search* [-ruba] [-f <from>] [-t <to>] [-c <cc>] [terms...] *search* [-ruba] [-x <flag>] [-X <flag>] [-f <from>] [-t <to>] [-c <cc>] [terms...]
Searches the current folder for messages matching the given set of Searches the current folder for messages matching the given set of
conditions. conditions.
@ -14,6 +14,22 @@ aerc-search(1)
*-u*: Search for unread messages *-u*: Search for unread messages
*-x <flag>*, *-X <flag>*: Restrict search to messages with or without <flag>
Use *-x* to search for messages with the flag set.
Use *-X* to search for messages without the flag set.
Possible values are:
Seen
Read messages
Answered
Replied messages
Flagged
Flagged messages
*-b*: Search in the body of the messages *-b*: Search in the body of the messages
*-a*: Search in the entire text of the messages *-a*: Search in the entire text of the messages
@ -26,7 +42,7 @@ aerc-search(1)
# MAILDIR # MAILDIR
*search* [-ruba] [-f <from>] [-t <to>] [-c <cc>] [terms...] *search* [-ruba] [-x <flag>] [-X <flag>] [-f <from>] [-t <to>] [-c <cc>] [terms...]
Searches the current folder for messages matching the given set of Searches the current folder for messages matching the given set of
conditions. conditions.
@ -38,6 +54,22 @@ aerc-search(1)
*-u*: Search for unread messages *-u*: Search for unread messages
*-x <flag>*, *-X <flag>*: Restrict search to messages with or without <flag>
Use *-x* to search for messages with the flag set.
Use *-X* to search for messages without the flag set.
Possible values are:
Seen
Read messages
Answered
Replied messages
Flagged
Flagged messages
*-b*: Search in the body of the messages *-b*: Search in the body of the messages
*-a*: Search in the entire text of the messages *-a*: Search in the entire text of the messages

View file

@ -1,6 +1,9 @@
package imap package imap
import ( import (
"errors"
"strings"
"github.com/emersion/go-imap" "github.com/emersion/go-imap"
"git.sr.ht/~sircmpwn/getopt" "git.sr.ht/~sircmpwn/getopt"
@ -9,7 +12,7 @@ import (
func parseSearch(args []string) (*imap.SearchCriteria, error) { func parseSearch(args []string) (*imap.SearchCriteria, error) {
criteria := imap.NewSearchCriteria() criteria := imap.NewSearchCriteria()
opts, optind, err := getopt.Getopts(args, "rubat:H:f:c:") opts, optind, err := getopt.Getopts(args, "rubax:X:t:H:f:c:")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -21,6 +24,14 @@ func parseSearch(args []string) (*imap.SearchCriteria, error) {
criteria.WithFlags = append(criteria.WithFlags, imap.SeenFlag) criteria.WithFlags = append(criteria.WithFlags, imap.SeenFlag)
case 'u': case 'u':
criteria.WithoutFlags = append(criteria.WithoutFlags, imap.SeenFlag) criteria.WithoutFlags = append(criteria.WithoutFlags, imap.SeenFlag)
case 'x':
if f, err := getParsedFlag(opt.Value); err == nil {
criteria.WithFlags = append(criteria.WithFlags, f)
}
case 'X':
if f, err := getParsedFlag(opt.Value); err == nil {
criteria.WithoutFlags = append(criteria.WithoutFlags, f)
}
case 'H': case 'H':
// TODO // TODO
case 'f': case 'f':
@ -46,3 +57,15 @@ func parseSearch(args []string) (*imap.SearchCriteria, error) {
} }
return criteria, nil return criteria, nil
} }
func getParsedFlag(name string) (string, error) {
switch strings.ToLower(name) {
case "seen":
return imap.SeenFlag, nil
case "flagged":
return imap.FlaggedFlag, nil
case "answered":
return imap.AnsweredFlag, nil
}
return imap.FlaggedFlag, errors.New("Flag not suppored")
}

View file

@ -29,7 +29,7 @@ func newSearchCriteria() *searchCriteria {
func parseSearch(args []string) (*searchCriteria, error) { func parseSearch(args []string) (*searchCriteria, error) {
criteria := newSearchCriteria() criteria := newSearchCriteria()
opts, optind, err := getopt.Getopts(args, "rubat:H:f:c:") opts, optind, err := getopt.Getopts(args, "rux:X:bat:H:f:c:")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -41,6 +41,10 @@ func parseSearch(args []string) (*searchCriteria, error) {
criteria.WithFlags = append(criteria.WithFlags, maildir.FlagSeen) criteria.WithFlags = append(criteria.WithFlags, maildir.FlagSeen)
case 'u': case 'u':
criteria.WithoutFlags = append(criteria.WithoutFlags, maildir.FlagSeen) criteria.WithoutFlags = append(criteria.WithoutFlags, maildir.FlagSeen)
case 'x':
criteria.WithFlags = append(criteria.WithFlags, getParsedFlag(opt.Value))
case 'X':
criteria.WithoutFlags = append(criteria.WithoutFlags, getParsedFlag(opt.Value))
case 'H': case 'H':
// TODO // TODO
case 'f': case 'f':
@ -67,6 +71,19 @@ func parseSearch(args []string) (*searchCriteria, error) {
return criteria, nil return criteria, nil
} }
func getParsedFlag(name string) maildir.Flag {
var f maildir.Flag
switch strings.ToLower(name) {
case "seen":
f = maildir.FlagSeen
case "answered":
f = maildir.FlagReplied
case "flagged":
f = maildir.FlagFlagged
}
return f
}
func (w *Worker) search(criteria *searchCriteria) ([]uint32, error) { func (w *Worker) search(criteria *searchCriteria) ([]uint32, error) {
requiredParts := getRequiredParts(criteria) requiredParts := getRequiredParts(criteria)
w.worker.Logger.Printf("Required parts bitmask for search: %b", requiredParts) w.worker.Logger.Printf("Required parts bitmask for search: %b", requiredParts)