Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Imap4flags #4

Merged
merged 2 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/sieve-run/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"log"
"net/textproto"
"os"
"strings"
"time"

"github.com/foxcpp/go-sieve"
Expand Down Expand Up @@ -76,4 +77,5 @@ func main() {
fmt.Println("redirect:", data.RedirectAddr)
fmt.Println("fileinfo:", data.Mailboxes)
fmt.Println("keep:", data.ImplicitKeep || data.Keep)
fmt.Printf("flags: %s\n", strings.Join(data.Flags, " "))
}
126 changes: 126 additions & 0 deletions execute_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package sieve

import (
"bufio"
"context"
"net/textproto"
"reflect"
"strings"
"testing"

"github.com/foxcpp/go-sieve/interp"
)

var eml string = `Date: Tue, 1 Apr 1997 09:06:31 -0800 (PST)
From: [email protected]
To: [email protected]
Subject: I have a present for you

Look, I'm sorry about the whole anvil thing, and I really
didn't mean to try and drop it on you from the top of the
cliff. I want to try to make it up to you. I've got some
great birdseed over here at my place--top of the line
stuff--and if you come by, I'll have it all wrapped up
for you. I'm really sorry for all the problems I've caused
for you over the years, but I know we can work this out.
--
Wile E. Coyote "Super Genius" [email protected]
`

type result struct {
redirect []string
fileinto []string
implicitKeep bool
keep bool
flags []string
}

func testExecute(t *testing.T, in string, eml string, intendedResult result) {
t.Run("case", func(t *testing.T) {

msgHdr, err := textproto.NewReader(bufio.NewReader(strings.NewReader(eml))).ReadMIMEHeader()
if err != nil {
t.Fatal(err)
}

script := bufio.NewReader(strings.NewReader(in))

loadedScript, err := Load(script, DefaultOptions())
if err != nil {
t.Fatal(err)
}
data := interp.NewRuntimeData(loadedScript, interp.Callback{
RedirectAllowed: func(ctx context.Context, d *interp.RuntimeData, addr string) (bool, error) {
return true, nil
},
HeaderGet: func(key string) (string, bool, error) {
vals, ok := msgHdr[key]
if !ok {
return "", false, nil
}
return vals[0], true, nil
},
})
data.MessageSize = len(eml)
data.SMTP.From = "[email protected]"
data.SMTP.To = "[email protected]"

ctx := context.Background()
if err := loadedScript.Execute(ctx, data); err != nil {
t.Fatal(err)
}

r := result{
redirect: data.RedirectAddr,
fileinto: data.Mailboxes,
keep: data.Keep,
implicitKeep: data.ImplicitKeep,
flags: data.Flags,
}

if !reflect.DeepEqual(r, intendedResult) {
t.Log("Wrong Execute output")
t.Log("Actual: ", r)
t.Log("Expected:", intendedResult)
t.Fail()
}
})
}

func TestFileinto(t *testing.T) {
testExecute(t, `require ["fileinto"];
fileinto "test";
`, eml,
result{
fileinto: []string{"test"},
})
testExecute(t, `require ["fileinto"];
fileinto "test";
fileinto "test2";
`, eml,
result{
fileinto: []string{"test", "test2"},
})
}

func TestFlags(t *testing.T) {
testExecute(t, `require ["fileinto", "imap4flags"];
setflag ["flag1", "flag2"];
addflag ["flag2", "flag3"];
removeflag ["flag1"];
fileinto "test";
`, eml,
result{
fileinto: []string{"test"},
flags: []string{"flag2", "flag3"},
})
testExecute(t, `require ["fileinto", "imap4flags"];
addflag ["flag2", "flag3"];
removeflag ["flag3", "flag4"];
fileinto "test";
`, eml,
result{
fileinto: []string{"test"},
flags: []string{"flag2"},
})
}
52 changes: 51 additions & 1 deletion interp/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ func (c CmdStop) Execute(ctx context.Context, d *RuntimeData) error {

type CmdFileInto struct {
Mailbox string
Flags *Flags
}

func (c CmdFileInto) Execute(ctx context.Context, d *RuntimeData) error {
Expand All @@ -27,6 +28,9 @@ func (c CmdFileInto) Execute(ctx context.Context, d *RuntimeData) error {
}
d.Mailboxes = append(d.Mailboxes, c.Mailbox)
d.ImplicitKeep = false
if c.Flags != nil {
d.Flags = *canonicalFlags(make([]string, len(*c.Flags)), nil, d.FlagAliases)
}
return nil
}

Expand All @@ -53,16 +57,62 @@ func (c CmdRedirect) Execute(ctx context.Context, d *RuntimeData) error {
return nil
}

type CmdKeep struct{}
type CmdKeep struct {
Flags *Flags
}

func (c CmdKeep) Execute(_ context.Context, d *RuntimeData) error {
d.Keep = true
if c.Flags != nil {
d.Flags = *canonicalFlags(make([]string, len(*c.Flags)), nil, d.FlagAliases)
}
return nil
}

type CmdDiscard struct{}

func (c CmdDiscard) Execute(_ context.Context, d *RuntimeData) error {
d.ImplicitKeep = false
d.Flags = make([]string, 0)
return nil
}

type CmdSetFlag struct {
Flags *Flags
}

func (c CmdSetFlag) Execute(_ context.Context, d *RuntimeData) error {
if c.Flags != nil {
d.Flags = *canonicalFlags(*c.Flags, nil, d.FlagAliases)
}
return nil
}

type CmdAddFlag struct {
Flags *Flags
}

func (c CmdAddFlag) Execute(_ context.Context, d *RuntimeData) error {
if c.Flags != nil {
if d.Flags == nil {
d.Flags = make([]string, len(*c.Flags))
copy(d.Flags, *c.Flags)
} else {
// Use canonicalFlags to remove duplicates
d.Flags = *canonicalFlags(append(d.Flags, *c.Flags...), nil, d.FlagAliases)
}
}
return nil
}

type CmdRemoveFlag struct {
Flags *Flags
}

func (c CmdRemoveFlag) Execute(_ context.Context, d *RuntimeData) error {
if c.Flags != nil {
// Use canonicalFlags to remove duplicates
d.Flags = *canonicalFlags(d.Flags, c.Flags, d.FlagAliases)
}
return nil
}
9 changes: 7 additions & 2 deletions interp/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import (
)

var supportedExtensions = map[string]struct{}{
"fileinto": {},
"envelope": {},
"fileinto": {},
"envelope": {},
"imap4flags": {},
}

var (
Expand All @@ -32,6 +33,10 @@ func init() {
"redirect": loadRedirect,
"keep": loadKeep,
"discard": loadDiscard,
// RFC 5232 Actions
"setflag": loadSetFlag, // imap4flags extension
"addflag": loadAddFlag, // imap4flags extension
"removeflag": loadRemoveFlag, // imap4flags extension
}
tests = map[string]func(*Script, parser.Test) (Test, error){
// RFC 5228 Tests
Expand Down
Loading
Loading