Repository: mbrt/gmailctl (go)

Issue:
Add bcc filter operator
So that a user can write `bcc: 'someone@something'` instead of `query: 'bcc: "someone@something"'`.

Pull request description:
Add bcc operator.
Close #65.

Patch:
diff --git a/README.md b/README.md
index 419c489..e10fcef 100644
--- a/README.md
+++ b/README.md
@@ -182,6 +182,7 @@ the following common operators:
 
 * `list`: the mail is directed to the given mail list
 * `cc`: the mail has the given address as CC destination
+* `bcc`: the mail has the given address as BCC destination
 
 One more special function is given if you need to use less common operators<sup
 id="a1">[1](#f1)</sup>, or want to compose your query manually:
@@ -573,13 +574,13 @@ local directlyTo(recipient) = {
   and: [
     { to: recipient },
     { not: { cc: recipient } },
+    { not: { bcc: recipient } },
   ],
 };
 ```
 
 So, from all emails where your mail is a recipient, we remove the ones where
-your mail is in the CC field. Note that we don't need to remove BCC emails,
-because no mail matches that filter.
+your mail is in the CC field.
 
 This trick is conveniently provided by the `gmailctl` library, so you can use it
 for example in this way:
diff --git a/cmd/gmailctl/cmd/bindata.go b/cmd/gmailctl/cmd/bindata.go
index f4c0524..623e8f9 100644
--- a/cmd/gmailctl/cmd/bindata.go
+++ b/cmd/gmailctl/cmd/bindata.go
@@ -78,7 +78,7 @@ func (fi bindataFileInfo) Sys() interface{} {
 	return nil
 }
 
-var _GmailctlLibsonnet = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x55\x4f\x6f\xe3\xb6\x13\xbd\xeb\x53\x3c\xec\xc5\x12\xa2\x9f\xbd\xb9\x3a\xc8\x0f\xd8\x6e\x51\xf4\x50\x6c\x7b\x08\xd0\x83\xa0\x03\x2d\x8d\xac\x29\x68\xd2\x25\x47\x71\x8c\x20\xdf\xbd\xe0\x1f\xc9\x4a\x76\x7b\xe9\xc5\x90\x39\x33\xef\x91\xef\xcd\x90\xbb\x1d\x8e\x27\xc5\xba\x13\x0d\x2f\xca\xf4\xca\xf5\xd0\x7c\x70\xca\x5d\x8b\xdd\xae\xd8\xed\xf0\x34\xb2\x9f\x97\xd0\x59\x23\x8a\x8d\xc7\x24\xac\x59\x98\x3c\x06\xeb\xd0\xd9\xd3\xc9\x1a\x0c\xac\x85\x1c\xec\x99\x9c\x12\xb6\xc6\x6f\x8b\xe2\xb5\x00\x76\x3b\x74\xa3\x62\xf3\x4b\x8c\x7b\xb0\x87\xc2\x30\x99\x2e\x24\x41\x46\x25\x35\x8e\xfc\x4c\x06\x0a\x9a\xbd\xc0\x0e\x70\x93\x26\x5f\xa7\x62\x47\x32\x39\x13\x8a\x0c\x5d\x52\xc6\x65\x24\x47\x90\x91\x52\x22\x94\xa3\xc4\x41\x3d\xc4\x1e\x47\x12\x72\xb9\xfa\x32\x72\x37\xe2\x44\xca\xf8\xc8\x15\xaa\xae\xe8\x94\xc1\x81\xc0\x46\xc8\x9d\x1d\x09\xf5\x50\x81\x21\x82\xa4\x42\x3b\xe0\x13\x0f\x20\xed\xe7\xdf\x4f\xdb\x14\x79\x0a\xbc\xe4\x27\x2d\xe1\x2c\x07\xe5\xb9\x53\x5a\x5f\x3f\x6e\x3f\xef\x92\x54\x37\x66\x6d\x52\x39\x7b\x9c\x6c\xcf\x03\x53\x8f\xc3\x15\xaa\xef\xd9\x1c\xa1\x0c\xbe\x7c\xfb\x19\x17\x96\x31\x1e\xcc\xd0\x31\xaa\x18\xe0\x94\xd6\x61\x2d\x95\x9f\x1d\x3d\xb3\x9d\x7c\xc6\xf4\x61\x53\x6b\x7d\xcb\xc1\x57\xfb\x7d\x01\xc4\xec\xe4\xd4\x35\x1d\x7d\x56\x39\x6c\x0f\x2c\x8b\xb2\x2c\x3e\xf1\x51\x9f\x51\xb7\xb1\x5e\xdb\x4e\xe9\x1c\x29\x5d\x85\x47\xbc\xc2\x58\xd9\xc3\x6d\xb3\xd9\x6f\x0f\x33\x91\xa3\x6e\x72\x9e\x9f\x29\x53\x59\xf2\x10\x67\xa7\xe3\x18\xb7\x4f\x9a\x4e\x64\xc4\xc7\xe3\x38\xb7\x82\x57\xd3\x4b\xa9\x9c\xab\xc1\xf5\xbc\x89\x1a\x6e\x32\x86\xcd\xb1\xc2\x63\xcc\x04\x78\x00\xe3\xff\x8f\xf0\xd2\x6f\x35\x99\xa3\x8c\xa1\xa8\x0a\xb2\x98\x9c\x82\xb9\x2a\xff\x27\xed\x69\x09\xed\x76\x59\xd5\x4b\x3e\xbd\x9f\x15\xb7\xc3\x7e\x9d\xf5\xbf\x7f\x53\xff\x26\x7c\x74\xf7\xfb\x9a\x6e\x72\x8e\x8c\xc4\xf0\x12\x9d\x25\xbc\xb8\xa0\xde\xb2\x8c\xac\xf3\xfe\xdd\x1a\xa0\x4c\xbf\x5f\xac\xb8\x43\xa3\x9c\x6b\xb8\xcd\x6a\xb7\xf5\x2a\xf7\x6d\xfd\x47\xc5\x59\xf2\x7b\xe4\xfc\xfc\xff\x96\x92\x7d\x8a\xb9\x8b\xde\xb8\xc3\x7d\xbd\x66\xcb\x4e\x27\x90\xaa\x5d\x6c\x48\xb1\x8b\x6b\x2b\x88\x62\xed\xc5\x71\x27\x0f\x45\x91\x8d\x59\x79\x32\xf8\x0a\x8f\x8f\xf8\x1c\x7d\x41\xd3\x16\xb3\x11\x91\x76\xf0\x75\x60\x9c\x79\x06\xdf\x7c\x8e\x34\x4d\xfc\x6a\xab\xba\x48\x2d\xde\xb3\xa3\x4e\xf4\xf5\xc9\xe2\xa4\xa4\x1b\xc9\xc3\x1a\x7d\x05\x85\xcb\x6a\x3d\xfc\xd4\xf1\x99\x83\xe6\xec\xc1\x26\xae\x6d\x9e\x7e\xdf\x24\x94\x81\x49\xf7\x75\x68\xd8\x14\xf8\xfa\x75\x03\xeb\xb0\xf9\x29\x7e\x18\x8a\x93\x73\xa3\x2a\x17\xb4\x6a\x3f\xdb\x12\xed\x68\xb2\x74\xaf\x10\xbb\x5f\x71\x2e\x0e\xe4\xa1\x78\x45\xd7\xbd\x8b\xcf\x19\xd1\xb7\xb7\x78\xb8\xd4\x0e\xf4\x22\x64\xfa\x3f\x59\xc6\x3f\x54\x68\x19\x5f\x6a\x75\x20\xed\xe7\x76\x5f\x67\x95\xe7\xdb\x10\xa4\xf5\xce\x9e\xce\x1e\x69\x14\xfc\x59\xb3\x94\xe7\x1a\x9b\xdd\xa6\x7a\x78\x97\x16\x04\x0f\x2d\x59\xc3\xd1\xe9\x86\xf1\xd1\xb1\x14\x9c\x2d\x5b\xf5\x54\x13\x8a\xdb\x65\xe1\xdd\x34\x61\x41\xc7\x5d\xa0\xc6\x5d\x20\x69\x3e\xb7\x91\xac\xb9\xdf\xb7\x55\xe8\x99\x88\xf0\x50\xfc\x88\x36\x1e\x22\x12\xdf\xe7\x5e\x39\xb7\xab\xb9\x4d\xf8\x21\x27\x82\xa6\xaf\x00\x9b\xd0\x02\xd0\xa0\x95\x08\x99\x2f\xce\xa9\xab\x2f\x9b\xac\x96\xae\xe2\x93\xa4\x43\x3b\x24\x51\x6f\x6d\x15\x06\xf3\xb7\xb8\x76\x7b\x53\xf2\x6c\xa7\x54\x18\xa2\x3e\xdd\xca\xf3\xdb\xb2\x5d\x4c\xbb\x55\x97\xe1\x73\x56\x34\x1f\xcb\x1e\xfe\xa2\x4e\x7e\x55\x29\xb8\x0c\x20\x36\x09\x79\xf3\xee\xa6\xfa\xde\xff\x75\xd1\x36\x37\x43\xf1\x41\xf6\xa6\xfd\xaf\x07\x49\xf7\x7e\xbc\xb6\xd2\x13\x96\x60\xbe\x59\xc9\xb7\xb5\xb1\xb0\x32\x92\xc3\xd9\x85\xe7\x3b\xbc\xec\x75\x5e\x91\x51\xa5\xc1\x32\xea\x44\x75\x7c\x69\x95\x88\xea\x46\xea\x13\x8a\xd8\x35\x71\xc9\x5b\xda\xa6\xeb\xd0\x6a\xeb\xaa\xc0\x17\x89\x57\xd2\x2d\xef\x53\x12\x36\x57\xa6\x86\x9e\x0c\xff\x5d\xc6\xce\xb6\x4e\xca\x1f\xf8\xbc\xb2\xe1\x25\x79\xfd\x12\xbc\x8e\xb8\x6d\x55\xe5\x06\x69\x5e\xe3\x7e\xf7\x78\xc1\xdb\x2d\x29\x37\x44\x5d\xbc\x15\xff\x04\x00\x00\xff\xff\x26\x10\xc5\x46\xfb\x08\x00\x00")
+var _GmailctlLibsonnet = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x55\x4d\x6f\xe3\x36\x10\xbd\xeb\x57\x3c\xec\xc5\x12\xa2\xda\xbb\x57\x07\x29\xb0\xdd\xa2\xe8\xa1\xd8\xf6\x10\xa0\x07\x41\x07\x5a\x1a\x59\x53\xd0\xa4\x4b\x8e\xd6\x31\x82\xfc\xf7\x82\x1f\x92\x95\x6c\xf6\xd2\x8b\x21\x73\x66\xde\x23\xdf\x9b\x21\x77\x3b\x1c\x4f\x8a\x75\x27\x1a\x5e\x94\xe9\x95\xeb\xa1\xf9\xe0\x94\xbb\x16\xbb\x5d\xb1\xdb\xe1\x71\x64\x3f\x2f\xa1\xb3\x46\x14\x1b\x8f\x49\x58\xb3\x30\x79\x0c\xd6\xa1\xb3\xa7\x93\x35\x18\x58\x0b\x39\xd8\x33\x39\x25\x6c\x8d\xdf\x16\xc5\x73\x01\xec\x76\xe8\x46\xc5\xe6\xb7\x18\xf7\x60\x0f\x85\x61\x32\x5d\x48\x82\x8c\x4a\x6a\x1c\xf9\x1b\x19\x28\x68\xf6\x02\x3b\xc0\x4d\x9a\x7c\x9d\x8a\x1d\xc9\xe4\x4c\x28\x32\x74\x49\x19\x97\x91\x1c\x41\x46\x4a\x89\x50\x8e\x12\x07\xf5\x10\x7b\x1c\x49\xc8\xe5\xea\xcb\xc8\xdd\x88\x13\x29\xe3\x23\x57\xa8\xba\xa2\x53\x06\x07\x02\x1b\x21\x77\x76\x24\xd4\x43\x05\x86\x08\x92\x0a\xed\x80\x0f\x3c\x80\xb4\x9f\x7f\x3f\x6c\x53\xe4\x31\xf0\x92\x9f\xb4\x84\xb3\x1c\x94\xe7\x4e\x69\x7d\x7d\xbb\xfd\xbc\x4b\x52\xdd\x98\xb5\x49\xe5\xec\x71\xb2\x3d\x0f\x4c\x3d\x0e\x57\xa8\xbe\x67\x73\x84\x32\xf8\xfc\xf5\x57\x5c\x58\xc6\x78\x30\x43\xc7\xa8\x62\x80\x53\x5a\x87\xb5\x54\x7e\x76\xf4\x8d\xed\xe4\x33\xa6\x0f\x9b\x5a\xeb\x5b\x0e\xbe\xda\xef\x0b\x20\x66\x27\xa7\xae\xe9\xe8\xb3\xca\x61\x7b\x60\x59\x94\x65\xf1\x89\x8f\xfa\x8c\xba\x8d\xf5\xda\x76\x4a\xe7\x48\xe9\x2a\x3c\xe0\x19\xc6\xca\x1e\x6e\x9b\xcd\x7e\xb9\x9f\x89\x1c\x75\x93\xf3\xfc\x8d\x32\x95\x25\x0f\x71\x76\x3a\x8e\x71\xfb\xa4\xe9\x44\x46\x7c\x3c\x8e\x73\x2b\x78\x35\x3d\x95\xca\xb9\x1a\x5c\xcf\x9b\xa8\xe1\x26\x63\xd8\x1c\x2b\x3c\xc4\x4c\x80\x07\x30\x7e\x7e\x80\x97\x7e\xab\xc9\x1c\x65\x0c\x45\x55\x90\xc5\xe4\x14\xcc\x55\xf9\x3f\x69\x4f\x4b\x68\xb7\xcb\xaa\x5e\xf2\xe9\xfd\xac\xb8\x1d\xf6\xeb\xac\x9f\x7e\xa4\xfe\x4d\xf8\xe8\xee\xf7\x35\xdd\xe4\x1c\x19\x89\xe1\x25\x3a\x4b\x78\x71\x41\xbd\x65\x19\x59\xe7\xfd\xab\x35\x40\x99\x7e\xbf\x58\x71\x87\x46\x39\xd7\x70\x9b\xd5\x6e\xeb\x55\xee\xcb\xfa\x8f\x8a\xb3\xe4\xf7\xc8\xf9\xf9\xff\x2d\x25\xfb\x14\x73\x17\xbd\x71\x87\x4f\xf5\x9a\x2d\x3b\x9d\x40\xaa\x76\xb1\x21\xc5\x2e\xae\xad\x20\x8a\xb5\x17\xc7\x9d\xdc\x17\x45\x36\x66\xe5\xc9\xe0\x2b\x3c\x3c\xe0\x63\xf4\x05\x4d\x5b\xcc\x46\x44\xda\xc1\xd7\x81\x71\xe6\x19\x7c\xf3\x31\xd2\x34\xf1\xab\xad\xea\x22\xb5\x78\xcf\x8e\x3a\xd1\xd7\x47\x8b\x93\x92\x6e\x24\x0f\x6b\xf4\x15\x14\x2e\xab\xf5\xf0\x53\xc7\x67\x0e\x9a\xb3\x07\x9b\xb8\xb6\x79\xfc\x73\x93\x50\x06\x26\xdd\xd7\xa1\x61\x53\xe0\xcb\x97\x0d\xac\xc3\xe6\x97\xf8\x61\x28\x4e\xce\x8d\xaa\x5c\xd0\xaa\xfd\x6c\x4b\xb4\xa3\xc9\xd2\x3d\x43\xec\x7e\xc5\xb9\x38\x90\x87\xe2\x19\x5d\xf7\x2a\xfe\x4e\xc6\xe1\x07\x29\xd1\xda\x97\x78\xfe\xd4\x31\xf4\x24\x64\xfa\xbf\x59\xc6\xbf\x54\xe8\x2a\x5f\x6a\x75\x20\xed\xe7\x89\x58\x67\x95\xe7\xdb\x9c\xa4\xf5\xce\x9e\xce\x1e\x69\x5a\xfc\x59\xb3\x94\xe7\x1a\x9b\xdd\xa6\xba\x7f\x95\x16\x3c\x09\x5d\x5b\xc3\xd1\xe9\x86\xf1\xd6\xd4\x14\x9c\x5d\x5d\xb5\x5d\x13\x8a\xdb\x65\xe1\xd5\xc0\x61\x41\xc7\x5d\xa0\xc6\x5d\x20\x69\x3e\xb6\x91\xac\xf9\xb4\x6f\xab\xd0\x56\x11\xe1\xbe\x78\x8f\x36\x1e\x22\x12\x7f\xca\xed\x74\x6e\x57\xa3\x9d\xf0\x43\x4e\x04\x4d\x5f\x01\x36\xa1\x05\xa0\x41\x2b\x11\x32\x9f\x9d\x53\x57\x5f\x36\x59\x2d\x5d\xc5\x57\x4b\x87\x8e\x49\xa2\xde\x3a\x2f\xcc\xee\x1f\x71\xed\xf6\xec\xe4\xf1\x4f\xa9\x30\x44\x7d\xba\xb8\xe7\xe7\x67\xbb\x98\x76\xab\x2e\xc3\xe7\xac\x68\x3e\x96\x3d\xfc\x43\x9d\xfc\xae\x52\x70\x99\x51\x6c\x12\xf2\xe6\xd5\x65\xf6\xbd\xff\xeb\xa2\x6d\x6e\x86\xe2\x8d\xec\x4d\xfb\x7f\x0f\x92\x9e\x86\x78\xb3\xa5\x57\x2e\xc1\x7c\xb5\x92\x2f\x74\x63\x61\x65\x24\x87\xb3\x0b\x2f\x7c\x78\xfc\xeb\xbc\x22\xa3\x4a\xb3\x67\xd4\x89\xea\xf8\x18\x2b\x11\xd5\x8d\xd4\x27\x14\xb1\x6b\xe2\x92\xb7\xb4\x4d\x37\xa6\xd5\xd6\x55\x81\x2f\x12\xaf\xa4\x5b\x9e\xb0\x24\x6c\xae\x4c\x0d\x3d\x19\xfe\xb7\x8c\x9d\x6d\x9d\x94\xef\xf8\xbc\xb2\xe1\x29\x79\xfd\x14\xbc\x8e\xb8\x6d\x55\xe5\x06\x69\x9e\xe3\x7e\xf7\x78\xc2\xcb\x2d\x29\x37\x44\x5d\xbc\x14\xff\x05\x00\x00\xff\xff\x5e\x41\xc2\xaf\x1e\x09\x00\x00")
 
 func GmailctlLibsonnetBytes() ([]byte, error) {
 	return bindataRead(
diff --git a/gmailctl.libsonnet b/gmailctl.libsonnet
index 1679bd3..5b5d4a4 100644
--- a/gmailctl.libsonnet
+++ b/gmailctl.libsonnet
@@ -38,6 +38,7 @@
     and: [
       { to: recipient },
       { not: { cc: recipient } },
+      { not: { bcc: recipient } },
     ],
   },
 
diff --git a/pkg/config/v1alpha3/config.go b/pkg/config/v1alpha3/config.go
index 90d497b..6eeb866 100644
--- a/pkg/config/v1alpha3/config.go
+++ b/pkg/config/v1alpha3/config.go
@@ -33,6 +33,7 @@ type FilterNode struct {
 	From    string `json:"from,omitempty"`
 	To      string `json:"to,omitempty"`
 	Cc      string `json:"cc,omitempty"`
+	Bcc     string `json:"bcc,omitempty"`
 	Subject string `json:"subject,omitempty"`
 	List    string `json:"list,omitempty"`
 	Has     string `json:"has,omitempty"`
@@ -143,7 +144,6 @@ type Actions struct {
 	Labels   []string       `json:"labels,omitempty"`
 
 	// Forward actions
-	// TODO(#56) Unused for now.
 	Forward string `json:"forward,omitempty"`
 }
 
diff --git a/pkg/filter/convert.go b/pkg/filter/convert.go
index 44d3749..2615e45 100644
--- a/pkg/filter/convert.go
+++ b/pkg/filter/convert.go
@@ -120,6 +120,10 @@ func generateLeaf(leaf *parser.Leaf) (Criteria, error) {
 		return Criteria{
 			Query: fmt.Sprintf("cc:%s", query),
 		}, nil
+	case parser.FunctionBcc:
+		return Criteria{
+			Query: fmt.Sprintf("bcc:%s", query),
+		}, nil
 	case parser.FunctionList:
 		return Criteria{
 			Query: fmt.Sprintf("list:%s", query),
diff --git a/pkg/parser/ast.go b/pkg/parser/ast.go
index 4246ca4..fcf9027 100644
--- a/pkg/parser/ast.go
+++ b/pkg/parser/ast.go
@@ -34,6 +34,7 @@ const (
 	FunctionFrom
 	FunctionTo
 	FunctionCc
+	FunctionBcc
 	FunctionSubject
 	FunctionList
 	FunctionHas
@@ -53,6 +54,8 @@ func (f FunctionType) String() string {
 		return "to"
 	case FunctionCc:
 		return "cc"
+	case FunctionBcc:
+		return "bcc"
 	case FunctionSubject:
 		return "subject"
 	case FunctionList:
diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go
index 87053eb..4ad67fe 100644
--- a/pkg/parser/parser.go
+++ b/pkg/parser/parser.go
@@ -122,6 +122,9 @@ func parseFunction(f cfg.FilterNode) (FunctionType, string) {
 	if f.Cc != "" {
 		return FunctionCc, f.Cc
 	}
+	if f.Bcc != "" {
+		return FunctionBcc, f.Bcc
+	}
 	if f.Subject != "" {
 		return FunctionSubject, f.Subject
 	}


Test patch:
diff --git a/pkg/config/testdata/chainfilters.json b/pkg/config/testdata/chainfilters.json
index 52a1154..f91eddf 100644
--- a/pkg/config/testdata/chainfilters.json
+++ b/pkg/config/testdata/chainfilters.json
@@ -15,6 +15,11 @@
             "not": {
               "cc": "pippo@gmail.com"
             }
+          },
+          {
+            "not": {
+              "bcc": "pippo@gmail.com"
+            }
           }
         ]
       },
diff --git a/testdata/local.bigdiffj.diff b/testdata/local.bigdiffj.diff
index 86f829d..404c2e8 100644
--- a/testdata/local.bigdiffj.diff
+++ b/testdata/local.bigdiffj.diff
@@ -1,16 +1,17 @@
 Filters:
 --- Current
 +++ TO BE APPLIED
-@@ -1,32 +1,51 @@
+@@ -1,32 +1,52 @@
  * Criteria:
--    query: {"buy this thing" "very important!!!"}
-+    query: list:foobaz.mail.com -"action needed"
++    from: spammer1
+     subject: "spam mail"
++    query: cc:foo@baz.com bcc:bar@baz.com
    Actions:
      delete
  
  * Criteria:
-+    from: spammer1
-     subject: "spam mail"
+-    query: {"buy this thing" "very important!!!"}
++    query: list:foobaz.mail.com -"action needed"
    Actions:
      delete
  
diff --git a/testdata/local.bigdiffj.jsonnet b/testdata/local.bigdiffj.jsonnet
index 5db0137..f866470 100644
--- a/testdata/local.bigdiffj.jsonnet
+++ b/testdata/local.bigdiffj.jsonnet
@@ -24,6 +24,8 @@ local filters = {
         and: [
           {from: 'spammer1'},
           {subject: 'spam mail'},
+          {cc: 'foo@baz.com' },
+          {bcc: 'bar@baz.com' },
         ],
       },
       {from: 'spammer2'},