Implement new SearchCriteria from latest go-imap
This commit is contained in:
parent
cabcb3ae2b
commit
313e803fdd
1
go.sum
1
go.sum
|
@ -60,6 +60,7 @@ github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a h1:bM
|
|||
github.com/emersion/go-imap-appendlimit v0.0.0-20190308131241-25671c986a6a/go.mod h1:ikgISoP7pRAolqsVP64yMteJa2FIpS6ju88eBT6K1yQ=
|
||||
github.com/emersion/go-imap-idle v0.0.0-20190519112320-2704abd7050e h1:L7bswVJZcf2YHofgom49oFRwVqmBj/qZqDy9/SJpZMY=
|
||||
github.com/emersion/go-imap-idle v0.0.0-20190519112320-2704abd7050e/go.mod h1:o14zPKCmEH5WC1vU5SdPoZGgNvQx7zzKSnxPQlobo78=
|
||||
github.com/emersion/go-imap-move v0.0.0-20190710073258-6e5a51a5b342/go.mod h1:QuMaZcKFDVI0yCrnAbPLfbwllz1wtOrZH8/vZ5yzp4w=
|
||||
github.com/emersion/go-imap-quota v0.0.0-20171113212021-e883a2bc54d6 h1:CQ9z5Gk5HBUI8+kM5XNZXUoAv8RF1GnXmYrN4OkDvZU=
|
||||
github.com/emersion/go-imap-quota v0.0.0-20171113212021-e883a2bc54d6/go.mod h1:iApyhIQBiU4XFyr+3kdJyyGqle82TbQyuP2o+OZHrV0=
|
||||
github.com/emersion/go-imap-quota v0.0.0-20200423100218-dcfd1b7d2b41 h1:z5lDGnSURauBEDdNLj3o0+HogVYKQCGeY3Anl/xyRfU=
|
||||
|
|
|
@ -170,20 +170,15 @@ func (im *imapMailbox) SearchMessages(isUID bool, criteria *imap.SearchCriteria)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var apiIDsFromUID []string
|
||||
if criteria.Uid != nil {
|
||||
if apiIDs, err := im.apiIDsFromSeqSet(true, criteria.Uid); err == nil {
|
||||
apiIDsFromUID = append(apiIDsFromUID, apiIDs...)
|
||||
apiIDsByUID, err := im.apiIDsFromSeqSet(true, criteria.Uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apiIDs = arrayIntersection(apiIDs, apiIDsByUID)
|
||||
}
|
||||
|
||||
// Apply filters.
|
||||
for _, apiID := range apiIDs {
|
||||
// Filter on UIDs.
|
||||
if len(apiIDsFromUID) > 0 && !isStringInList(apiIDsFromUID, apiID) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get message.
|
||||
storeMessage, err := im.storeMailbox.GetMessage(apiID)
|
||||
if err != nil {
|
||||
|
@ -192,79 +187,7 @@ func (im *imapMailbox) SearchMessages(isUID bool, criteria *imap.SearchCriteria)
|
|||
}
|
||||
m := storeMessage.Message()
|
||||
|
||||
// Filter addresses.
|
||||
/*if criteria.From != "" && !addressMatch([]*mail.Address{m.Sender}, criteria.From) {
|
||||
continue
|
||||
}
|
||||
if criteria.To != "" && !addressMatch(m.ToList, criteria.To) {
|
||||
continue
|
||||
}
|
||||
if criteria.Cc != "" && !addressMatch(m.CCList, criteria.Cc) {
|
||||
continue
|
||||
}
|
||||
if criteria.Bcc != "" && !addressMatch(m.BCCList, criteria.Bcc) {
|
||||
continue
|
||||
}*/
|
||||
|
||||
// Filter strings.
|
||||
/*if criteria.Subject != "" && !strings.Contains(strings.ToLower(m.Subject), strings.ToLower(criteria.Subject)) {
|
||||
continue
|
||||
}
|
||||
if criteria.Keyword != "" && !hasKeyword(m, criteria.Keyword) {
|
||||
continue
|
||||
}
|
||||
if criteria.Unkeyword != "" && hasKeyword(m, criteria.Unkeyword) {
|
||||
continue
|
||||
}
|
||||
if criteria.Header[0] != "" {
|
||||
h := message.GetHeader(m)
|
||||
if val := h.Get(criteria.Header[0]); val == "" {
|
||||
continue // Field is not in header.
|
||||
} else if criteria.Header[1] != "" && !strings.Contains(strings.ToLower(val), strings.ToLower(criteria.Header[1])) {
|
||||
continue // Field is in header, second criteria is non-zero and field value not matched (case insensitive).
|
||||
}
|
||||
}
|
||||
|
||||
// Filter flags.
|
||||
if criteria.Flagged && !isStringInList(m.LabelIDs, pmapi.StarredLabel) {
|
||||
continue
|
||||
}
|
||||
if criteria.Unflagged && isStringInList(m.LabelIDs, pmapi.StarredLabel) {
|
||||
continue
|
||||
}
|
||||
if criteria.Seen && m.Unread == 1 {
|
||||
continue
|
||||
}
|
||||
if criteria.Unseen && m.Unread == 0 {
|
||||
continue
|
||||
}
|
||||
if criteria.Deleted {
|
||||
continue
|
||||
}
|
||||
// if criteria.Undeleted { // All messages matches this criteria }
|
||||
if criteria.Draft && (m.Has(pmapi.FlagSent) || m.Has(pmapi.FlagReceived)) {
|
||||
continue
|
||||
}
|
||||
if criteria.Undraft && !(m.Has(pmapi.FlagSent) || m.Has(pmapi.FlagReceived)) {
|
||||
continue
|
||||
}
|
||||
if criteria.Answered && !(m.Has(pmapi.FlagReplied) || m.Has(pmapi.FlagRepliedAll)) {
|
||||
continue
|
||||
}
|
||||
if criteria.Unanswered && (m.Has(pmapi.FlagReplied) || m.Has(pmapi.FlagRepliedAll)) {
|
||||
continue
|
||||
}
|
||||
if criteria.Recent && m.Has(pmapi.FlagOpened) { // opened means not recent
|
||||
continue
|
||||
}
|
||||
if criteria.Old && !m.Has(pmapi.FlagOpened) {
|
||||
continue
|
||||
}
|
||||
if criteria.New && !(!m.Has(pmapi.FlagOpened) && m.Unread == 1) {
|
||||
continue
|
||||
}*/
|
||||
|
||||
// Filter internal date.
|
||||
// Filter by time.
|
||||
if !criteria.Before.IsZero() {
|
||||
if truncated := criteria.Before.Truncate(24 * time.Hour); m.Time > truncated.Unix() {
|
||||
continue
|
||||
|
@ -275,15 +198,8 @@ func (im *imapMailbox) SearchMessages(isUID bool, criteria *imap.SearchCriteria)
|
|||
continue
|
||||
}
|
||||
}
|
||||
/*if !criteria.On.IsZero() {
|
||||
truncated := criteria.On.Truncate(24 * time.Hour)
|
||||
if m.Time < truncated.Unix() || m.Time > truncated.Add(24*time.Hour).Unix() {
|
||||
continue
|
||||
}
|
||||
}*/
|
||||
if !(criteria.SentBefore.IsZero() && criteria.SentSince.IsZero() /*&& criteria.SentOn.IsZero()*/) {
|
||||
if !criteria.SentBefore.IsZero() || !criteria.SentSince.IsZero() {
|
||||
if t, err := m.Header.Date(); err == nil && !t.IsZero() {
|
||||
// Filter header date.
|
||||
if !criteria.SentBefore.IsZero() {
|
||||
if truncated := criteria.SentBefore.Truncate(24 * time.Hour); t.Unix() > truncated.Unix() {
|
||||
continue
|
||||
|
@ -294,16 +210,81 @@ func (im *imapMailbox) SearchMessages(isUID bool, criteria *imap.SearchCriteria)
|
|||
continue
|
||||
}
|
||||
}
|
||||
/*if !criteria.SentOn.IsZero() {
|
||||
truncated := criteria.SentOn.Truncate(24 * time.Hour)
|
||||
if t.Unix() < truncated.Unix() || t.Unix() > truncated.Add(24*time.Hour).Unix() {
|
||||
continue
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
// Filter size (only if size was already calculated).
|
||||
// Filter by headers.
|
||||
header := message.GetHeader(m)
|
||||
headerMatch := true
|
||||
for criteriaKey, criteriaValues := range criteria.Header {
|
||||
for _, criteriaValue := range criteriaValues {
|
||||
if criteriaValue == "" {
|
||||
continue
|
||||
}
|
||||
switch criteriaKey {
|
||||
case "From":
|
||||
headerMatch = addressMatch([]*mail.Address{m.Sender}, criteriaValue)
|
||||
case "To":
|
||||
headerMatch = addressMatch(m.ToList, criteriaValue)
|
||||
case "Cc":
|
||||
headerMatch = addressMatch(m.CCList, criteriaValue)
|
||||
case "Bcc":
|
||||
headerMatch = addressMatch(m.BCCList, criteriaValue)
|
||||
default:
|
||||
if messageValue := header.Get(criteriaKey); messageValue == "" {
|
||||
headerMatch = false // Field is not in header.
|
||||
} else if !strings.Contains(strings.ToLower(messageValue), strings.ToLower(criteriaValue)) {
|
||||
headerMatch = false // Field is in header but value not matched (case insensitive).
|
||||
}
|
||||
}
|
||||
if !headerMatch {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !headerMatch {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !headerMatch {
|
||||
continue
|
||||
}
|
||||
|
||||
// Filter by flags.
|
||||
messageFlagsMap := make(map[string]bool)
|
||||
if isStringInList(m.LabelIDs, pmapi.StarredLabel) {
|
||||
messageFlagsMap[imap.FlaggedFlag] = true
|
||||
}
|
||||
if m.Unread == 0 {
|
||||
messageFlagsMap[imap.SeenFlag] = true
|
||||
}
|
||||
if m.Has(pmapi.FlagReplied) || m.Has(pmapi.FlagRepliedAll) {
|
||||
messageFlagsMap[imap.AnsweredFlag] = true
|
||||
}
|
||||
if m.Has(pmapi.FlagSent) || m.Has(pmapi.FlagReceived) {
|
||||
messageFlagsMap[imap.DraftFlag] = true
|
||||
}
|
||||
if !m.Has(pmapi.FlagOpened) {
|
||||
messageFlagsMap[imap.RecentFlag] = true
|
||||
}
|
||||
|
||||
flagMatch := true
|
||||
for _, flag := range criteria.WithFlags {
|
||||
if !messageFlagsMap[flag] {
|
||||
flagMatch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, flag := range criteria.WithoutFlags {
|
||||
if messageFlagsMap[flag] {
|
||||
flagMatch = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if !flagMatch {
|
||||
continue
|
||||
}
|
||||
|
||||
// Filter by size (only if size was already calculated).
|
||||
if m.Size > 0 {
|
||||
if criteria.Larger != 0 && m.Size <= int64(criteria.Larger) {
|
||||
continue
|
||||
|
@ -452,13 +433,17 @@ func (im *imapMailbox) apiIDsFromSeqSet(uid bool, seqSet *imap.SeqSet) ([]string
|
|||
return apiIDs, nil
|
||||
}
|
||||
|
||||
func isAddressInList(addrs []*mail.Address, query string) bool { //nolint[deadcode]
|
||||
for _, addr := range addrs {
|
||||
if strings.Contains(addr.Address, query) || strings.Contains(addr.Name, query) {
|
||||
return true
|
||||
func arrayIntersection(a, b []string) (c []string) {
|
||||
m := make(map[string]bool)
|
||||
for _, item := range a {
|
||||
m[item] = true
|
||||
}
|
||||
for _, item := range b {
|
||||
if _, ok := m[item]; ok {
|
||||
c = append(c, item)
|
||||
}
|
||||
}
|
||||
return false
|
||||
return
|
||||
}
|
||||
|
||||
func isStringInList(list []string, s string) bool {
|
||||
|
@ -478,12 +463,3 @@ func addressMatch(addresses []*mail.Address, criteria string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasKeyword(m *pmapi.Message, keyword string) bool {
|
||||
for _, v := range message.GetHeader(m) {
|
||||
if strings.Contains(strings.ToLower(strings.Join(v, " ")), strings.ToLower(keyword)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -2,28 +2,79 @@ Feature: IMAP search messages
|
|||
Background:
|
||||
Given there is connected user "user"
|
||||
Given there are messages in mailbox "INBOX" for "user"
|
||||
| from | to | subject | body |
|
||||
| john.doe@mail.com | user@pm.me | foo | hello |
|
||||
| jane.doe@mail.com | name@pm.me | bar | world |
|
||||
| from | to | cc | subject | read | starred | body |
|
||||
| john.doe@email.com | user@pm.me | | foo | false | false | hello |
|
||||
| jane.doe@email.com | user@pm.me | name@pm.me | bar | true | true | world |
|
||||
| jane.doe@email.com | name@pm.me | | baz | true | false | bye |
|
||||
And there is IMAP client logged in as "user"
|
||||
And there is IMAP client selected in "INBOX"
|
||||
|
||||
Scenario: Search by subject
|
||||
Scenario: Search by Sequence numbers
|
||||
When IMAP client searches for "1"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 1[^0-9]*$"
|
||||
|
||||
Scenario: Search by UID
|
||||
When IMAP client searches for "UID 2"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 2[^0-9]*$"
|
||||
|
||||
Scenario: Search by Sequence numbers and UID
|
||||
When IMAP client searches for "1 UID 1"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 1[^0-9]*$"
|
||||
|
||||
Scenario: Search by Sequence numbers and UID without match
|
||||
When IMAP client searches for "1 UID 2"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH[^0-9]*$"
|
||||
|
||||
Scenario: Search by Subject
|
||||
When IMAP client searches for "SUBJECT foo"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response has 1 message
|
||||
And IMAP response contains "SEARCH 3[^0-9]*$"
|
||||
|
||||
Scenario: Search by text
|
||||
When IMAP client searches for "TEXT world"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response has 1 message
|
||||
|
||||
Scenario: Search by from
|
||||
Scenario: Search by From
|
||||
When IMAP client searches for "FROM jane.doe@email.com"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response has 1 message
|
||||
And IMAP response contains "SEARCH 1 2[^0-9]*$"
|
||||
|
||||
Scenario: Search by to
|
||||
Scenario: Search by To
|
||||
When IMAP client searches for "TO user@pm.me"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response has 1 message
|
||||
And IMAP response contains "SEARCH 2 3[^0-9]*$"
|
||||
|
||||
Scenario: Search by CC
|
||||
When IMAP client searches for "CC name@pm.me"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 2[^0-9]*$"
|
||||
|
||||
Scenario: Search flagged messages
|
||||
When IMAP client searches for "FLAGGED"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 2[^0-9]*$"
|
||||
|
||||
Scenario: Search not flagged messages
|
||||
When IMAP client searches for "UNFLAGGED"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 1 3[^0-9]*$"
|
||||
|
||||
Scenario: Search seen messages
|
||||
When IMAP client searches for "SEEN"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 1 2[^0-9]*$"
|
||||
|
||||
Scenario: Search unseen messages
|
||||
When IMAP client searches for "UNSEEN"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 3[^0-9]*$"
|
||||
|
||||
Scenario: Search recent messages
|
||||
When IMAP client searches for "RECENT"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 1 2 3[^0-9]*$"
|
||||
|
||||
Scenario: Search by more criterias
|
||||
When IMAP client searches for "SUBJECT baz TO name@pm.me SEEN UNFLAGGED"
|
||||
Then IMAP response is "OK"
|
||||
And IMAP response contains "SEARCH 1[^0-9]*$"
|
||||
|
|
|
@ -97,6 +97,11 @@ func thereAreMessagesInMailboxesForAddressOfUser(mailboxNames, bddAddressID, bdd
|
|||
message.ToList = []*mail.Address{{
|
||||
Address: ctx.EnsureAddress(account.Username(), cell.Value),
|
||||
}}
|
||||
case "cc":
|
||||
message.AddressID = ctx.EnsureAddressID(account.Username(), cell.Value)
|
||||
message.CCList = []*mail.Address{{
|
||||
Address: ctx.EnsureAddress(account.Username(), cell.Value),
|
||||
}}
|
||||
case "subject":
|
||||
message.Subject = cell.Value
|
||||
case "body":
|
||||
|
|
Loading…
Reference in New Issue