Compare commits

...

11 Commits

Author SHA1 Message Date
70645c1732 Import-Export Elbe 1.2.1
• Further improvements to address and date parsing
• Better handling and displaying of skipped messages
• Improved error reporting
2020-11-11 14:03:00 +01:00
1055e60d27 Fixing time order in changelog. 2020-11-11 12:02:56 +01:00
e04196f8a0 feat: switch to public go-rfc5322 parser 2020-11-10 09:27:07 +00:00
11a0dec047 Using atomic bool 2020-11-10 07:50:29 +00:00
b9740e1b7d Close connection before deleting labels to prevent panics accessing deleted bucket 2020-11-10 07:50:29 +00:00
f0695eb870 add test gui 2020-11-09 11:58:32 +00:00
a40018cdf9 Percentage available on progress count struct 2020-11-09 11:58:32 +00:00
5b7eabe21a Skipped messages do not change total counts but shows as separate number 2020-11-09 11:58:32 +00:00
d5d60aa11b feat: remove tls upgrade error notification 2020-11-09 10:59:42 +00:00
a62fa132e6 rename build tag 2020-11-06 16:02:30 +01:00
052395f917 test: add benchmarks for rfc5322 address/date parser 2020-11-04 15:00:18 +01:00
104 changed files with 245 additions and 20637 deletions

View File

@ -20,9 +20,6 @@ issues:
- gochecknoglobals - gochecknoglobals
- gochecknoinits - gochecknoinits
- gosec - gosec
- path: pkg/message/rfc5322
linters:
- dupl
linters-settings: linters-settings:
godox: godox:

View File

@ -1,9 +1,21 @@
# ProtonMail Bridge Changelog # ProtonMail Bridge and Import-Export app Changelog
Changelog [format](http://keepachangelog.com/en/1.0.0/) Changelog [format](http://keepachangelog.com/en/1.0.0/)
## Unreleased ## [IE 1.2.1] Elbe
### Added
* GODT-799 Skipped messages do not change total counts but shows as separate number.
## Fixed
* GODT-799 Fix skipping unwanted folders importing from mbox files.
* GODT-769 Close connection before deleting labels to prevent panics accessing deleted bucket.
### Removed
* GODT-766 Remove GUI popup for IMAP TLS error.
## [Bridge 1.5.0] Golden Gate
### Changed ### Changed
* Updated go-mbox dependency back to upstream. * Updated go-mbox dependency back to upstream.
@ -11,6 +23,8 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/)
* GODT-847 Waiting for unilateral update during deleting the message. * GODT-847 Waiting for unilateral update during deleting the message.
* GODT-849 Show in error counts in the end also lost messages. * GODT-849 Show in error counts in the end also lost messages.
* GODT-835 Do not include conversation ID in references to show properly conversation threads in clients. * GODT-835 Do not include conversation ID in references to show properly conversation threads in clients.
* GODT-685 Improve deb packaging regarding dejavu font
## [IE 1.2.0] Elbe ## [IE 1.2.0] Elbe

View File

@ -11,7 +11,7 @@ TARGET_OS?=${GOOS}
# Keep version hardcoded so app build works also without Git repository. # Keep version hardcoded so app build works also without Git repository.
BRIDGE_APP_VERSION?=1.5.0-git BRIDGE_APP_VERSION?=1.5.0-git
IE_APP_VERSION?=1.2.0-git IE_APP_VERSION?=1.2.1-git
APP_VERSION:=${BRIDGE_APP_VERSION} APP_VERSION:=${BRIDGE_APP_VERSION}
SRC_ICO:=logo.ico SRC_ICO:=logo.ico
SRC_ICNS:=Bridge.icns SRC_ICNS:=Bridge.icns
@ -280,8 +280,3 @@ clean: clean-vendor
rm -rf cmd/Import-Export/deploy rm -rf cmd/Import-Export/deploy
rm -f build last.log mem.pprof main.go rm -f build last.log mem.pprof main.go
rm -rf logo.ico icon.rc icon_windows.syso internal/frontend/qt/icon_windows.syso rm -rf logo.ico icon.rc icon_windows.syso internal/frontend/qt/icon_windows.syso
.PHONY: generate
generate:
go generate ./...
$(MAKE) add-license

6
go.mod
View File

@ -18,13 +18,13 @@ require (
github.com/ProtonMail/go-apple-mobileconfig v0.0.0-20160701194735-7ea9927a11f6 github.com/ProtonMail/go-apple-mobileconfig v0.0.0-20160701194735-7ea9927a11f6
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a
github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde
github.com/ProtonMail/go-rfc5322 v0.2.0
github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5 github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5
github.com/ProtonMail/gopenpgp/v2 v2.0.1 github.com/ProtonMail/gopenpgp/v2 v2.0.1
github.com/PuerkitoBio/goquery v1.5.1 github.com/PuerkitoBio/goquery v1.5.1
github.com/abiosoft/ishell v2.0.0+incompatible github.com/abiosoft/ishell v2.0.0+incompatible
github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect
github.com/allan-simon/go-singleinstance v0.0.0-20160830203053-79edcfdc2dfc github.com/allan-simon/go-singleinstance v0.0.0-20160830203053-79edcfdc2dfc
github.com/antlr/antlr4 v0.0.0-20201020194047-0a7eaede42b0
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 // indirect github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 // indirect
github.com/chzyer/logex v1.1.10 // indirect github.com/chzyer/logex v1.1.10 // indirect
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 // indirect
@ -60,7 +60,7 @@ require (
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce
github.com/olekukonko/tablewriter v0.0.4 // indirect github.com/olekukonko/tablewriter v0.0.4 // indirect
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.6.0 github.com/sirupsen/logrus v1.7.0
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/stretchr/testify v1.6.1 github.com/stretchr/testify v1.6.1
@ -75,7 +75,7 @@ require (
replace ( replace (
github.com/docker/docker-credential-helpers => github.com/ProtonMail/docker-credential-helpers v1.1.0 github.com/docker/docker-credential-helpers => github.com/ProtonMail/docker-credential-helpers v1.1.0
github.com/emersion/go-imap => github.com/ProtonMail/go-imap v0.0.0-20201016095853-a7520cc904d3 github.com/emersion/go-imap => github.com/ProtonMail/go-imap v0.0.0-20201102134601-418cd74e9474
github.com/emersion/go-smtp => github.com/ProtonMail/go-smtp v0.0.0-20181206232543-8261df20d309 github.com/emersion/go-smtp => github.com/ProtonMail/go-smtp v0.0.0-20181206232543-8261df20d309
github.com/jameskeane/bcrypt => github.com/ProtonMail/bcrypt v0.0.0-20170924085257-7509ea014998 github.com/jameskeane/bcrypt => github.com/ProtonMail/bcrypt v0.0.0-20170924085257-7509ea014998
golang.org/x/crypto => github.com/ProtonMail/crypto v0.0.0-20200818122824-ed5d25e28db8 golang.org/x/crypto => github.com/ProtonMail/crypto v0.0.0-20200818122824-ed5d25e28db8

16
go.sum
View File

@ -15,12 +15,14 @@ github.com/ProtonMail/go-apple-mobileconfig v0.0.0-20160701194735-7ea9927a11f6 h
github.com/ProtonMail/go-apple-mobileconfig v0.0.0-20160701194735-7ea9927a11f6/go.mod h1:EtDfBMIDWmVe4viZCuBTEfe3OIIo0ghbpOaAZVO+hVg= github.com/ProtonMail/go-apple-mobileconfig v0.0.0-20160701194735-7ea9927a11f6/go.mod h1:EtDfBMIDWmVe4viZCuBTEfe3OIIo0ghbpOaAZVO+hVg=
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a h1:fXK2KsfnkBV9Nh+9SKzHchYjuE9s0vI20JG1mbtEAcc= github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a h1:fXK2KsfnkBV9Nh+9SKzHchYjuE9s0vI20JG1mbtEAcc=
github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-autostart v0.0.0-20181114175602-c5272053443a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4=
github.com/ProtonMail/go-imap v0.0.0-20201016095853-a7520cc904d3 h1:Jvv9t3rSg/ID3Fh+uYsxgmvNI9fYnlab4vtBsbPtmq8= github.com/ProtonMail/go-imap v0.0.0-20201102134601-418cd74e9474 h1:D0RwDtkBw0Gt7hmbb1ivdEulplJAwu1i2jzh4HM45fo=
github.com/ProtonMail/go-imap v0.0.0-20201016095853-a7520cc904d3/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU= github.com/ProtonMail/go-imap v0.0.0-20201102134601-418cd74e9474/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU=
github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde h1:5koQozTDELymYOyFbQ/VSubexAEXzDR8qGM5mO8GRdw= github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde h1:5koQozTDELymYOyFbQ/VSubexAEXzDR8qGM5mO8GRdw=
github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde/go.mod h1:795VPXcRUIQ9JyMNHP4el582VokQfippgjkQP3Gk0r0= github.com/ProtonMail/go-imap-id v0.0.0-20190926060100-f94a56b9ecde/go.mod h1:795VPXcRUIQ9JyMNHP4el582VokQfippgjkQP3Gk0r0=
github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a h1:W6RrgN/sTxg1msqzFFb+G80MFmpjMw61IU+slm+wln4= github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a h1:W6RrgN/sTxg1msqzFFb+G80MFmpjMw61IU+slm+wln4=
github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4= github.com/ProtonMail/go-mime v0.0.0-20190923161245-9b5a4261663a/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4=
github.com/ProtonMail/go-rfc5322 v0.2.0 h1:tndoDGFtiCvESta9KLUeMksojz8qf76PefnkoQ+fqeg=
github.com/ProtonMail/go-rfc5322 v0.2.0/go.mod h1:mzZWlMWnQJuYLL7JpzuPF5+FimV2lZ9f0jeq24kJjpU=
github.com/ProtonMail/go-smtp v0.0.0-20181206232543-8261df20d309 h1:2pzfKjhBjSnw3BgmfTYRFQr1rFGxhfhUY0KKkg+RYxE= github.com/ProtonMail/go-smtp v0.0.0-20181206232543-8261df20d309 h1:2pzfKjhBjSnw3BgmfTYRFQr1rFGxhfhUY0KKkg+RYxE=
github.com/ProtonMail/go-smtp v0.0.0-20181206232543-8261df20d309/go.mod h1:6UoBvDAMA/cTBwS3Y7tGpKnY5RH1F1uYHschT6eqAkI= github.com/ProtonMail/go-smtp v0.0.0-20181206232543-8261df20d309/go.mod h1:6UoBvDAMA/cTBwS3Y7tGpKnY5RH1F1uYHschT6eqAkI=
github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5 h1:Uga1DHFN4GUxuDQr0F71tpi8I9HqPIlZodZAI1lR6VQ= github.com/ProtonMail/go-vcard v0.0.0-20180326232728-33aaa0a0c8a5 h1:Uga1DHFN4GUxuDQr0F71tpi8I9HqPIlZodZAI1lR6VQ=
@ -37,8 +39,8 @@ github.com/allan-simon/go-singleinstance v0.0.0-20160830203053-79edcfdc2dfc h1:m
github.com/allan-simon/go-singleinstance v0.0.0-20160830203053-79edcfdc2dfc/go.mod h1:qqsTQiwdyqxU05iDCsi0oN3P4nrVxAmn8xCtODDSf/U= github.com/allan-simon/go-singleinstance v0.0.0-20160830203053-79edcfdc2dfc/go.mod h1:qqsTQiwdyqxU05iDCsi0oN3P4nrVxAmn8xCtODDSf/U=
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/antlr/antlr4 v0.0.0-20201020194047-0a7eaede42b0 h1:7RW94Pqb4Twsfpz42ALQ+sD0cUUpN8HF4uzKyQf2D8Y= github.com/antlr/antlr4 v0.0.0-20201029161626-9a95f0cc3d7c h1:j/C2kxPfyE0d87/ggAjIsCV5Cdkqmjb+O0W8W+1J+IY=
github.com/antlr/antlr4 v0.0.0-20201020194047-0a7eaede42b0/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y= github.com/antlr/antlr4 v0.0.0-20201029161626-9a95f0cc3d7c/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 h1:JLaf/iINcLyjwbtTsCJjc6rtlASgHeIJPrB6QmwURnA= github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894 h1:JLaf/iINcLyjwbtTsCJjc6rtlASgHeIJPrB6QmwURnA=
github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20200211180108-c7c1fbc02894/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
@ -109,8 +111,6 @@ github.com/keybase/go-keychain v0.0.0-20200502122510-cda31fe0c86d/go.mod h1:W6Eb
github.com/keybase/go.dbus v0.0.0-20200324223359-a94be52c0b03/go.mod h1:a8clEhrrGV/d76/f9r2I41BwANMihfZYV9C223vaxqE= github.com/keybase/go.dbus v0.0.0-20200324223359-a94be52c0b03/go.mod h1:a8clEhrrGV/d76/f9r2I41BwANMihfZYV9C223vaxqE=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -148,8 +148,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5I
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=

View File

@ -15,8 +15,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Code generated by ./credits.sh at Wed Nov 4 12:24:36 PM CET 2020. DO NOT EDIT. // Code generated by ./credits.sh at Wed Nov 4 13:57:47 CET 2020. DO NOT EDIT.
package bridge package bridge
const Credits = "github.com/0xAX/notificator;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/antlr/antlr4;github.com/certifi/gocertifi;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/raven-go;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/go-resty/resty/v2;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/Masterminds/semver/v3;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/gopenpgp/v2;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/PuerkitoBio/goquery;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" const Credits = "github.com/0xAX/notificator;github.com/Masterminds/semver/v3;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/ProtonMail/gopenpgp/v2;github.com/PuerkitoBio/goquery;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/antlr/antlr4;github.com/certifi/gocertifi;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/raven-go;github.com/go-resty/resty/v2;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;"

View File

@ -40,7 +40,6 @@ const (
NoActiveKeyForRecipientEvent = "noActiveKeyForRecipient" NoActiveKeyForRecipientEvent = "noActiveKeyForRecipient"
UpgradeApplicationEvent = "upgradeApplication" UpgradeApplicationEvent = "upgradeApplication"
TLSCertIssue = "tlsCertPinningIssue" TLSCertIssue = "tlsCertPinningIssue"
IMAPTLSBadCert = "imapTLSBadCert"
// LogoutEventTimeout is the minimum time to permit between logout events being sent. // LogoutEventTimeout is the minimum time to permit between logout events being sent.
LogoutEventTimeout = 3 * time.Minute LogoutEventTimeout = 3 * time.Minute

View File

@ -184,9 +184,17 @@ func (f *frontendCLI) setTransferRules(t *transfer.Transfer) bool {
} }
func (f *frontendCLI) printTransferProgress(progress *transfer.Progress) { func (f *frontendCLI) printTransferProgress(progress *transfer.Progress) {
failed, imported, exported, added, total := progress.GetCounts() counts := progress.GetCounts()
if total != 0 { if counts.Total != 0 {
f.Println(fmt.Sprintf("Progress update: %d (%d / %d) / %d, failed: %d", imported, exported, added, total, failed)) f.Println(fmt.Sprintf(
"Progress update: %d (%d / %d) / %d, skipped: %d, failed: %d",
counts.Imported,
counts.Exported,
counts.Added,
counts.Total,
counts.Skipped,
counts.Failed,
))
} }
if progress.IsPaused() { if progress.IsPaused() {

View File

@ -237,13 +237,6 @@ Item {
winMain.tlsBarState="notOK" winMain.tlsBarState="notOK"
} }
onShowIMAPCertTroubleshoot : {
go.notifyBubble(1, qsTr(
"Bridge was unable to establish a connection with your Email client. <br> <a href=\"https://protonmail.com/support/knowledge-base/bridge-ssl-connection-issue\">Learn more</a> <br>",
"notification message"
))
}
} }

View File

@ -599,7 +599,7 @@ Dialog {
} }
Text { Text {
text: qsTr("<b>Import summary:</b><br>Total number of emails: %1<br>Imported emails: %2<br>Errors: %3").arg(go.total).arg(finalReport.imported).arg(go.progressFails) text: qsTr("<b>Import summary:</b><br>Total number of emails: %1<br>Imported emails: %2<br>Filtered out emails: %3<br>Errors: %4").arg(go.total).arg(go.progressImported).arg(go.progressSkipped).arg(go.progressFails)
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
textFormat: Text.RichText textFormat: Text.RichText
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter

View File

@ -122,7 +122,6 @@ Window {
ListElement { title: "Minimize this" } ListElement { title: "Minimize this" }
ListElement { title: "SendAlertPopup" } ListElement { title: "SendAlertPopup" }
ListElement { title: "TLSCertError" } ListElement { title: "TLSCertError" }
ListElement { title: "IMAPCertError" }
} }
ListView { ListView {
@ -209,9 +208,6 @@ Window {
case "TLSCertError" : case "TLSCertError" :
go.showCertIssue() go.showCertIssue()
break; break;
case "IMAPCertError" :
go.showIMAPCertTroubleshoot()
break;
default : default :
console.log("Not implemented " + data) console.log("Not implemented " + data)
} }
@ -314,7 +310,6 @@ Window {
signal failedAutostartCode(string code) signal failedAutostartCode(string code)
signal showCertIssue() signal showCertIssue()
signal showIMAPCertTroubleshoot()
signal updateFinished(bool hasError) signal updateFinished(bool hasError)

View File

@ -840,6 +840,8 @@ Window {
property real progress: 0.0 property real progress: 0.0
property int progressFails: 0 property int progressFails: 0
property int progressImported: 0
property int progressSkipped: 0
property string progressDescription: "nothing" property string progressDescription: "nothing"
property string progressInit: "init" property string progressInit: "init"
property int total: 42 property int total: 42
@ -1011,6 +1013,8 @@ Window {
property SequentialAnimation animateProgressBar : SequentialAnimation { property SequentialAnimation animateProgressBar : SequentialAnimation {
id: apb id: apb
property real speedup : 1.0; property real speedup : 1.0;
PropertyAnimation{ target: go; properties: "progressSkipped"; to: 0; duration: 1; }
PropertyAnimation{ target: go; properties: "progressImported"; to: 0; duration: 1; }
PropertyAnimation{ target: go; properties: "importLogFileName"; to: ""; duration: 1; } PropertyAnimation{ target: go; properties: "importLogFileName"; to: ""; duration: 1; }
PropertyAnimation{ target: go; properties: "progressDescription"; to: go.progressInit; duration: 1; } PropertyAnimation{ target: go; properties: "progressDescription"; to: go.progressInit; duration: 1; }
PropertyAnimation{ duration: 2000/apb.speedup; } PropertyAnimation{ duration: 2000/apb.speedup; }
@ -1024,6 +1028,8 @@ Window {
PropertyAnimation{ target: go; properties: "progress"; to: 0.01; duration: 1; } PropertyAnimation{ target: go; properties: "progress"; to: 0.01; duration: 1; }
PropertyAnimation{ duration: 1000/apb.speedup; } PropertyAnimation{ duration: 1000/apb.speedup; }
PropertyAnimation{ target: go; properties: "progress"; to: 0.1; duration: 1; } PropertyAnimation{ target: go; properties: "progress"; to: 0.1; duration: 1; }
PropertyAnimation{ target: go; properties: "progressSkipped"; to: 12; duration: 1; }
PropertyAnimation{ target: go; properties: "progressImported"; to: 13.1; duration: 1; }
PropertyAnimation{ duration: 1000/apb.speedup; } PropertyAnimation{ duration: 1000/apb.speedup; }
PropertyAnimation{ target: go; properties: "progress"; to: 0.3; duration: 1; } PropertyAnimation{ target: go; properties: "progress"; to: 0.3; duration: 1; }
PropertyAnimation{ target: go; properties: "progressFails"; to: 1; duration: 1; } PropertyAnimation{ target: go; properties: "progressFails"; to: 1; duration: 1; }

View File

@ -21,6 +21,7 @@ package qtcommon
import ( import (
"fmt" "fmt"
"github.com/therecipe/qt/core" "github.com/therecipe/qt/core"
) )

View File

@ -337,12 +337,14 @@ func (f *FrontendQt) setProgressManager(progress *transfer.Progress) {
if progress.IsStopped() { if progress.IsStopped() {
break break
} }
failed, imported, _, _, total := progress.GetCounts() counts := progress.GetCounts()
f.Qml.SetTotal(int(total)) f.Qml.SetTotal(int(counts.Total))
f.Qml.SetProgressFails(int(failed)) f.Qml.SetProgressImported(int(counts.Imported))
f.Qml.SetProgressSkipped(int(counts.Skipped))
f.Qml.SetProgressFails(int(counts.Failed))
f.Qml.SetProgressDescription(progress.PauseReason()) f.Qml.SetProgressDescription(progress.PauseReason())
if total > 0 { if counts.Total > 0 {
newProgress := float32(imported+failed) / float32(total) newProgress := counts.Progress()
if newProgress >= 0 && newProgress != f.Qml.Progress() { if newProgress >= 0 && newProgress != f.Qml.Progress() {
f.Qml.SetProgress(newProgress) f.Qml.SetProgress(newProgress)
f.Qml.ProgressChanged(newProgress) f.Qml.ProgressChanged(newProgress)
@ -350,8 +352,10 @@ func (f *FrontendQt) setProgressManager(progress *transfer.Progress) {
} }
} }
// Counts will add lost messages only once the progress is completeled. // Counts will add lost messages only once the progress is completeled.
failed, _, _, _, _ := progress.GetCounts() counts := progress.GetCounts()
f.Qml.SetProgressFails(int(failed)) f.Qml.SetProgressImported(int(counts.Imported))
f.Qml.SetProgressSkipped(int(counts.Skipped))
f.Qml.SetProgressFails(int(counts.Failed))
if err := progress.GetFatalError(); err != nil { if err := progress.GetFatalError(); err != nil {
f.Qml.SetProgressDescription(err.Error()) f.Qml.SetProgressDescription(err.Error())

View File

@ -77,6 +77,8 @@ func (f *FrontendQt) StartImport(email string) { // TODO email not needed
log.Trace("Starting import") log.Trace("Starting import")
f.Qml.SetProgressDescription("init") // TODO use const f.Qml.SetProgressDescription("init") // TODO use const
f.Qml.SetProgressImported(0)
f.Qml.SetProgressSkipped(0)
f.Qml.SetProgressFails(0) f.Qml.SetProgressFails(0)
f.Qml.SetProgress(0.0) f.Qml.SetProgress(0.0)
f.Qml.SetTotal(1) f.Qml.SetTotal(1)

View File

@ -43,6 +43,8 @@ type GoQMLInterface struct {
_ string `property:lastError` _ string `property:lastError`
_ float32 `property:progress` _ float32 `property:progress`
_ string `property:progressDescription` _ string `property:progressDescription`
_ int `property:progressImported`
_ int `property:progressSkipped`
_ int `property:progressFails` _ int `property:progressFails`
_ int `property:total` _ int `property:total`
_ string `property:importLogFileName` _ string `property:importLogFileName`

View File

@ -40,17 +40,17 @@ import (
"github.com/ProtonMail/proton-bridge/internal/bridge" "github.com/ProtonMail/proton-bridge/internal/bridge"
"github.com/ProtonMail/proton-bridge/internal/events" "github.com/ProtonMail/proton-bridge/internal/events"
"github.com/ProtonMail/proton-bridge/internal/frontend/autoconfig" "github.com/ProtonMail/proton-bridge/internal/frontend/autoconfig"
"github.com/ProtonMail/proton-bridge/internal/frontend/qt-common" qtcommon "github.com/ProtonMail/proton-bridge/internal/frontend/qt-common"
"github.com/ProtonMail/proton-bridge/internal/frontend/types" "github.com/ProtonMail/proton-bridge/internal/frontend/types"
"github.com/ProtonMail/proton-bridge/internal/preferences" "github.com/ProtonMail/proton-bridge/internal/preferences"
"github.com/ProtonMail/proton-bridge/internal/updates" "github.com/ProtonMail/proton-bridge/internal/updates"
"github.com/ProtonMail/proton-bridge/pkg/config" "github.com/ProtonMail/proton-bridge/pkg/config"
"github.com/ProtonMail/proton-bridge/pkg/ports"
"github.com/ProtonMail/proton-bridge/pkg/useragent"
"github.com/ProtonMail/proton-bridge/pkg/listener" "github.com/ProtonMail/proton-bridge/pkg/listener"
"github.com/ProtonMail/proton-bridge/pkg/pmapi" "github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/sirupsen/logrus" "github.com/ProtonMail/proton-bridge/pkg/ports"
"github.com/ProtonMail/proton-bridge/pkg/useragent"
"github.com/kardianos/osext" "github.com/kardianos/osext"
"github.com/sirupsen/logrus"
"github.com/skratchdot/open-golang/open" "github.com/skratchdot/open-golang/open"
"github.com/therecipe/qt/core" "github.com/therecipe/qt/core"
"github.com/therecipe/qt/gui" "github.com/therecipe/qt/gui"
@ -187,7 +187,6 @@ func (s *FrontendQt) watchEvents() {
updateApplicationCh := s.getEventChannel(events.UpgradeApplicationEvent) updateApplicationCh := s.getEventChannel(events.UpgradeApplicationEvent)
newUserCh := s.getEventChannel(events.UserRefreshEvent) newUserCh := s.getEventChannel(events.UserRefreshEvent)
certIssue := s.getEventChannel(events.TLSCertIssue) certIssue := s.getEventChannel(events.TLSCertIssue)
imapCertIssue := s.getEventChannel(events.IMAPTLSBadCert)
for { for {
select { select {
case errorDetails := <-errorCh: case errorDetails := <-errorCh:
@ -227,8 +226,6 @@ func (s *FrontendQt) watchEvents() {
s.Qml.LoadAccounts() s.Qml.LoadAccounts()
case <-certIssue: case <-certIssue:
s.Qml.ShowCertIssue() s.Qml.ShowCertIssue()
case <-imapCertIssue:
s.Qml.ShowIMAPCertTroubleshoot()
} }
} }
} }

View File

@ -135,7 +135,6 @@ type GoQMLInterface struct {
_ func(x, y float32) `slot:"saveOutgoingNoEncPopupCoord"` _ func(x, y float32) `slot:"saveOutgoingNoEncPopupCoord"`
_ func(recipient string) `signal:"showNoActiveKeyForRecipient"` _ func(recipient string) `signal:"showNoActiveKeyForRecipient"`
_ func() `signal:"showCertIssue"` _ func() `signal:"showCertIssue"`
_ func() `signal:"ShowIMAPCertTroubleshoot"`
_ func() `slot:"startUpdate"` _ func() `slot:"startUpdate"`
_ func(hasError bool) `signal:"updateFinished"` _ func(hasError bool) `signal:"updateFinished"`

View File

@ -28,7 +28,6 @@ import (
"github.com/ProtonMail/proton-bridge/pkg/listener" "github.com/ProtonMail/proton-bridge/pkg/listener"
"github.com/emersion/go-imap" "github.com/emersion/go-imap"
goIMAPBackend "github.com/emersion/go-imap/backend" goIMAPBackend "github.com/emersion/go-imap/backend"
"github.com/sirupsen/logrus"
) )
type panicHandler interface { type panicHandler interface {
@ -198,11 +197,3 @@ func (ib *imapBackend) monitorDisconnectedUsers() {
ib.deleteUser(address) ib.deleteUser(address)
} }
} }
func (ib *imapBackend) upgradeError(err error) {
logrus.WithError(err).Error("IMAP connection couldn't be upgraded to TLS during STARTTLS")
if strings.Contains(err.Error(), "remote error: tls: bad certificate") {
ib.eventListener.Emit(events.IMAPTLSBadCert, err.Error())
}
}

View File

@ -58,7 +58,6 @@ func NewIMAPServer(debugClient, debugServer bool, port int, tls *tls.Config, ima
s.AllowInsecureAuth = true s.AllowInsecureAuth = true
s.ErrorLog = newServerErrorLogger("server-imap") s.ErrorLog = newServerErrorLogger("server-imap")
s.AutoLogout = 30 * time.Minute s.AutoLogout = 30 * time.Minute
s.UpgradeError = imapBackend.upgradeError
serverID := imapid.ID{ serverID := imapid.ID{
imapid.FieldName: "ProtonMail Bridge", imapid.FieldName: "ProtonMail Bridge",

View File

@ -15,8 +15,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Code generated by ./credits.sh at Wed Nov 4 12:24:36 PM CET 2020. DO NOT EDIT. // Code generated by ./credits.sh at Wed Nov 4 13:57:47 CET 2020. DO NOT EDIT.
package importexport package importexport
const Credits = "github.com/0xAX/notificator;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/antlr/antlr4;github.com/certifi/gocertifi;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/raven-go;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/go-resty/resty/v2;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/Masterminds/semver/v3;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/gopenpgp/v2;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/PuerkitoBio/goquery;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" const Credits = "github.com/0xAX/notificator;github.com/Masterminds/semver/v3;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/ProtonMail/gopenpgp/v2;github.com/PuerkitoBio/goquery;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/antlr/antlr4;github.com/certifi/gocertifi;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/raven-go;github.com/go-resty/resty/v2;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;"

View File

@ -15,18 +15,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Code generated by ./release-notes.sh at 'Wed Nov 4 12:24:35 PM CET 2020'. DO NOT EDIT. // Code generated by ./release-notes.sh at 'Wed Nov 11 01:57:14 PM CET 2020'. DO NOT EDIT.
package importexport package importexport
const ReleaseNotes = `Improvements to the import from large mbox files with multiple labels const ReleaseNotes = `Further improvements to address and date parsing
Not allow to run multiple instances of the app or transfers at the same time Better handling and displaying of skipped messages
Various enhancements of the import process related to parsing Improved error reporting
• Cosmetic GUI changes
• Better error handling
` `
const ReleaseFixedBugs = `• Linux font issues - Fedora specific const ReleaseFixedBugs = `
• App response to the user pausing and canceling import or export
• Handling errors during update
` `

View File

@ -21,6 +21,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings" "strings"
"sync/atomic"
"github.com/ProtonMail/proton-bridge/pkg/pmapi" "github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -38,6 +39,8 @@ type Mailbox struct {
color string color string
log *logrus.Entry log *logrus.Entry
isDeleting atomic.Value
} }
func newMailbox(storeAddress *Address, labelID, labelPrefix, labelName, color string) (mb *Mailbox, err error) { func newMailbox(storeAddress *Address, labelID, labelPrefix, labelName, color string) (mb *Mailbox, err error) {
@ -59,6 +62,7 @@ func txNewMailbox(tx *bolt.Tx, storeAddress *Address, labelID, labelPrefix, labe
color: color, color: color,
log: l, log: l,
} }
mb.isDeleting.Store(false)
err := initMailboxBucket(tx, mb.getBucketName()) err := initMailboxBucket(tx, mb.getBucketName())
if err != nil { if err != nil {
@ -215,6 +219,7 @@ func (storeMailbox *Mailbox) Rename(newName string) error {
// Deletion has to be propagated to all the same mailboxes in all addresses. // Deletion has to be propagated to all the same mailboxes in all addresses.
// The propagation is processed by the event loop. // The propagation is processed by the event loop.
func (storeMailbox *Mailbox) Delete() error { func (storeMailbox *Mailbox) Delete() error {
storeMailbox.isDeleting.Store(true)
return storeMailbox.storeAddress.deleteMailbox(storeMailbox.labelID) return storeMailbox.storeAddress.deleteMailbox(storeMailbox.labelID)
} }
@ -226,6 +231,14 @@ func (storeMailbox *Mailbox) GetDelimiter() string {
// deleteMailboxEvent deletes the mailbox bucket. // deleteMailboxEvent deletes the mailbox bucket.
// This is called from the event loop. // This is called from the event loop.
func (storeMailbox *Mailbox) deleteMailboxEvent() error { func (storeMailbox *Mailbox) deleteMailboxEvent() error {
if !storeMailbox.isDeleting.Load().(bool) {
// Deleting label removes bucket. Any ongoing connection selected
// in such mailbox then might panic because of non-existing bucket.
// Closing connetions prevents that panic but if the connection
// asked for deletion, it should not be closed so it can receive
// successful response.
storeMailbox.store.user.CloseAllConnections()
}
return storeMailbox.db().Update(func(tx *bolt.Tx) error { return storeMailbox.db().Update(func(tx *bolt.Tx) error {
return tx.Bucket(mailboxesBucket).DeleteBucket(storeMailbox.getBucketName()) return tx.Bucket(mailboxesBucket).DeleteBucket(storeMailbox.getBucketName())
}) })

View File

@ -5,9 +5,10 @@
package mocks package mocks
import ( import (
reflect "reflect"
pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi" pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
reflect "reflect"
) )
// MockPanicHandler is a mock of PanicHandler interface // MockPanicHandler is a mock of PanicHandler interface
@ -105,6 +106,18 @@ func (m *MockBridgeUser) EXPECT() *MockBridgeUserMockRecorder {
return m.recorder return m.recorder
} }
// CloseAllConnections mocks base method
func (m *MockBridgeUser) CloseAllConnections() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "CloseAllConnections")
}
// CloseAllConnections indicates an expected call of CloseAllConnections
func (mr *MockBridgeUserMockRecorder) CloseAllConnections() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CloseAllConnections", reflect.TypeOf((*MockBridgeUser)(nil).CloseAllConnections))
}
// CloseConnection mocks base method // CloseConnection mocks base method
func (m *MockBridgeUser) CloseConnection(arg0 string) { func (m *MockBridgeUser) CloseConnection(arg0 string) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -5,9 +5,10 @@
package mocks package mocks
import ( import (
gomock "github.com/golang/mock/gomock"
reflect "reflect" reflect "reflect"
time "time" time "time"
gomock "github.com/golang/mock/gomock"
) )
// MockListener is a mock of Listener interface // MockListener is a mock of Listener interface

View File

@ -36,6 +36,7 @@ type BridgeUser interface {
GetPrimaryAddress() string GetPrimaryAddress() string
GetStoreAddresses() []string GetStoreAddresses() []string
UpdateUser() error UpdateUser() error
CloseAllConnections()
CloseConnection(string) CloseConnection(string)
Logout() error Logout() error
} }

View File

@ -58,6 +58,7 @@ type MessageStatus struct {
targetID string // Message ID at the target (if any). targetID string // Message ID at the target (if any).
bodyHash string // Hash of the message body. bodyHash string // Hash of the message body.
skipped bool
exported bool exported bool
imported bool imported bool
exportErr error exportErr error
@ -96,7 +97,7 @@ func (status *MessageStatus) setDetailsFromHeader(header mail.Header) {
} }
func (status *MessageStatus) hasError(includeMissing bool) bool { func (status *MessageStatus) hasError(includeMissing bool) bool {
return status.exportErr != nil || status.importErr != nil || (includeMissing && !status.imported) return status.exportErr != nil || status.importErr != nil || (includeMissing && !status.skipped && !status.imported)
} }
// GetErrorMessage returns error message. // GetErrorMessage returns error message.
@ -105,6 +106,9 @@ func (status *MessageStatus) GetErrorMessage() string {
} }
func (status *MessageStatus) getErrorMessage(includeMissing bool) string { func (status *MessageStatus) getErrorMessage(includeMissing bool) string {
if status.skipped {
return ""
}
if status.exportErr != nil { if status.exportErr != nil {
return fmt.Sprintf("failed to export: %s", status.exportErr) return fmt.Sprintf("failed to export: %s", status.exportErr)
} }

View File

@ -5,9 +5,10 @@
package mocks package mocks
import ( import (
reflect "reflect"
pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi" pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
reflect "reflect"
) )
// MockPanicHandler is a mock of PanicHandler interface // MockPanicHandler is a mock of PanicHandler interface

View File

@ -140,6 +140,19 @@ func (p *Progress) addMessage(messageID string, sourceNames, targetNames []strin
} }
} }
// messageSkipped should be called once the message is skipped due to some
// filter such as time or folder and so on.
func (p *Progress) messageSkipped(messageID string) {
p.lock.Lock()
defer p.lock.Unlock()
defer p.update()
p.log.WithField("id", messageID).Debug("Message skipped")
p.messageStatuses[messageID].skipped = true
p.logMessage(messageID)
}
// messageExported should be called right before message is exported. // messageExported should be called right before message is exported.
func (p *Progress) messageExported(messageID string, body []byte, err error) { func (p *Progress) messageExported(messageID string, body []byte, err error) {
p.lock.Lock() p.lock.Lock()
@ -330,35 +343,40 @@ func (p *Progress) GetFailedMessages() []*MessageStatus {
} }
// GetCounts returns counts of exported and imported messages. // GetCounts returns counts of exported and imported messages.
func (p *Progress) GetCounts() (failed, imported, exported, added, total uint) { func (p *Progress) GetCounts() ProgressCounts {
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
counts := ProgressCounts{}
// Return counts only once total is estimated or the process already // Return counts only once total is estimated or the process already
// ended (for a case when it ended quickly to report it correctly). // ended (for a case when it ended quickly to report it correctly).
if p.updateCh != nil && !p.messageCounted { if p.updateCh != nil && !p.messageCounted {
return return counts
} }
// Include lost messages in the process only when transfer is done. // Include lost messages in the process only when transfer is done.
includeMissing := p.updateCh == nil includeMissing := p.updateCh == nil
for _, mailboxCount := range p.messageCounts { for _, mailboxCount := range p.messageCounts {
total += mailboxCount counts.Total += mailboxCount
} }
for _, status := range p.messageStatuses { for _, status := range p.messageStatuses {
added++ counts.Added++
if status.skipped {
counts.Skipped++
}
if status.exported { if status.exported {
exported++ counts.Exported++
} }
if status.imported { if status.imported {
imported++ counts.Imported++
} }
if status.hasError(includeMissing) { if status.hasError(includeMissing) {
failed++ counts.Failed++
} }
} }
return return counts
} }
// GenerateBugReport generates similar file to import log except private information. // GenerateBugReport generates similar file to import log except private information.

View File

@ -15,35 +15,21 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322 package transfer
import ( // ProgressCounts holds counts counted by Progress.
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser" type ProgressCounts struct {
"github.com/sirupsen/logrus" Failed,
) Skipped,
Imported,
type fws struct { Exported,
value string Added,
Total uint
} }
func (w *walker) EnterFws(ctx *parser.FwsContext) { // Progress returns ratio between processed messages (fully imported, skipped
logrus.WithField("text", ctx.GetText()).Trace("Entering fws") // and failed ones) and total number of messages as percentage (0 - 1).
func (c *ProgressCounts) Progress() float32 {
w.enter(&fws{ progressed := c.Imported + c.Skipped + c.Failed
value: ctx.GetText(), return float32(progressed) / float32(c.Total)
})
}
func (w *walker) ExitFws(ctx *parser.FwsContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting fws")
type withFws interface {
withFws(*fws)
}
res := w.exit().(*fws)
if parent, ok := w.parent().(withFws); ok {
parent.withFws(res)
}
} }

View File

@ -39,8 +39,8 @@ func TestProgressUpdateCount(t *testing.T) {
progress.finish() progress.finish()
_, _, _, _, total := progress.GetCounts() //nolint[dogsled] counts := progress.GetCounts()
r.Equal(t, uint(42), total) r.Equal(t, uint(42), counts.Total)
} }
func TestProgressAddingMessages(t *testing.T) { func TestProgressAddingMessages(t *testing.T) {
@ -66,13 +66,18 @@ func TestProgressAddingMessages(t *testing.T) {
progress.messageExported("msg4", []byte(""), errors.New("failed export")) progress.messageExported("msg4", []byte(""), errors.New("failed export"))
progress.messageImported("msg4", "", nil) progress.messageImported("msg4", "", nil)
// msg5 is skipped.
progress.addMessage("msg5", []string{}, []string{})
progress.messageSkipped("msg5")
progress.finish() progress.finish()
failed, imported, exported, added, _ := progress.GetCounts() counts := progress.GetCounts()
a.Equal(t, uint(4), added) a.Equal(t, uint(5), counts.Added)
a.Equal(t, uint(2), exported) a.Equal(t, uint(2), counts.Exported)
a.Equal(t, uint(2), imported) a.Equal(t, uint(2), counts.Imported)
a.Equal(t, uint(3), failed) a.Equal(t, uint(1), counts.Skipped)
a.Equal(t, uint(3), counts.Failed)
errorsMap := map[string]string{} errorsMap := map[string]string{}
for _, status := range progress.GetFailedMessages() { for _, status := range progress.GetFailedMessages() {

View File

@ -82,8 +82,6 @@ func (p *EMLProvider) getFilePathsPerFolder(rules transferRules) (map[string][]s
} }
func (p *EMLProvider) exportMessages(rule *Rule, filePaths []string, progress *Progress, ch chan<- Message) { func (p *EMLProvider) exportMessages(rule *Rule, filePaths []string, progress *Progress, ch chan<- Message) {
count := uint(len(filePaths))
for _, filePath := range filePaths { for _, filePath := range filePaths {
if progress.shouldStop() { if progress.shouldStop() {
break break
@ -91,6 +89,8 @@ func (p *EMLProvider) exportMessages(rule *Rule, filePaths []string, progress *P
msg, err := p.exportMessage(rule, filePath) msg, err := p.exportMessage(rule, filePath)
progress.addMessage(filePath, msg.sourceNames(), msg.targetNames())
// Read and check time in body only if the rule specifies it // Read and check time in body only if the rule specifies it
// to not waste energy. // to not waste energy.
if err == nil && rule.HasTimeLimit() { if err == nil && rule.HasTimeLimit() {
@ -99,17 +99,11 @@ func (p *EMLProvider) exportMessages(rule *Rule, filePaths []string, progress *P
err = msgTimeErr err = msgTimeErr
} else if !rule.isTimeInRange(msgTime) { } else if !rule.isTimeInRange(msgTime) {
log.WithField("msg", filePath).Debug("Message skipped due to time") log.WithField("msg", filePath).Debug("Message skipped due to time")
progress.messageSkipped(filePath)
count--
progress.updateCount(rule.SourceMailbox.Name, count)
continue continue
} }
} }
// addMessage is called after time check to not report message
// which should not be exported but any error from reading body
// or parsing time is reported as an error.
progress.addMessage(filePath, msg.sourceNames(), msg.targetNames())
progress.messageExported(filePath, msg.Body, err) progress.messageExported(filePath, msg.Body, err)
if err == nil { if err == nil {
ch <- msg ch <- msg

View File

@ -114,7 +114,6 @@ func (p *MBOXProvider) transferTo(rules transferRules, progress *Progress, ch ch
} }
index := 0 index := 0
count := 0
for { for {
if progress.shouldStop() { if progress.shouldStop() {
break break
@ -133,24 +132,18 @@ func (p *MBOXProvider) transferTo(rules transferRules, progress *Progress, ch ch
msg, err := p.exportMessage(rules, folderName, id, msgReader) msg, err := p.exportMessage(rules, folderName, id, msgReader)
progress.addMessage(id, msg.sourceNames(), msg.targetNames())
if err == nil && len(msg.Targets) == 0 { if err == nil && len(msg.Targets) == 0 {
// Here should be called progress.messageSkipped(id) once we have progress.messageSkipped(id)
// this feature, and following progress.updateCount can be removed.
continue continue
} }
count++
// addMessage is called after time check to not report message
// which should not be exported but any error from reading body
// or parsing time is reported as an error.
progress.addMessage(id, msg.sourceNames(), msg.targetNames())
progress.messageExported(id, msg.Body, err) progress.messageExported(id, msg.Body, err)
if err == nil { if err == nil {
ch <- msg ch <- msg
} }
} }
progress.updateCount(filePath, uint(count))
} }
func (p *MBOXProvider) exportMessage(rules transferRules, folderName, id string, msgReader io.Reader) (Message, error) { func (p *MBOXProvider) exportMessage(rules transferRules, folderName, id string, msgReader io.Reader) (Message, error) {
@ -177,7 +170,7 @@ func (p *MBOXProvider) getMessageRules(rules transferRules, folderName, id strin
folderRule, err := rules.getRuleBySourceMailboxName(folderName) folderRule, err := rules.getRuleBySourceMailboxName(folderName)
if err != nil { if err != nil {
log.WithField("msg", id).WithField("source", folderName).Debug("Message source doesn't have a rule") log.WithField("msg", id).WithField("source", folderName).Debug("Message source doesn't have a rule")
} else { } else if folderRule.Active {
msgRules = append(msgRules, folderRule) msgRules = append(msgRules, folderRule)
} }
@ -191,7 +184,9 @@ func (p *MBOXProvider) getMessageRules(rules transferRules, folderName, id strin
log.WithField("msg", id).WithField("source", label).Debug("Message source doesn't have a rule") log.WithField("msg", id).WithField("source", label).Debug("Message source doesn't have a rule")
continue continue
} }
msgRules = append(msgRules, rule) if rule.Active {
msgRules = append(msgRules, rule)
}
} }
} }

View File

@ -155,6 +155,29 @@ func TestMBOXProviderTransferFromTo(t *testing.T) {
}) })
} }
func TestMBOXProviderGetMessageRules(t *testing.T) {
provider := newTestMBOXProvider("")
body := []byte(`Subject: Test
X-Gmail-Labels: foo,bar
`)
rules := transferRules{
rules: map[string]*Rule{
"1": {Active: true, SourceMailbox: Mailbox{Name: "folder"}},
"2": {Active: false, SourceMailbox: Mailbox{Name: "foo"}},
"3": {Active: true, SourceMailbox: Mailbox{Name: "bar"}},
"4": {Active: false, SourceMailbox: Mailbox{Name: "baz"}},
"5": {Active: true, SourceMailbox: Mailbox{Name: "other"}},
},
}
gotRules := provider.getMessageRules(rules, "folder", "id", body)
r.Equal(t, 2, len(gotRules))
r.Equal(t, "folder", gotRules[0].SourceMailbox.Name)
r.Equal(t, "bar", gotRules[1].SourceMailbox.Name)
}
func TestMBOXProviderGetMessageTargetsReturnsOnlyOneFolder(t *testing.T) { func TestMBOXProviderGetMessageTargetsReturnsOnlyOneFolder(t *testing.T) {
provider := newTestMBOXProvider("") provider := newTestMBOXProvider("")

View File

@ -28,7 +28,7 @@ import (
"sort" "sort"
"strings" "strings"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322" "github.com/ProtonMail/go-rfc5322"
"github.com/pkg/errors" "github.com/pkg/errors"
) )

View File

@ -5,11 +5,12 @@
package mocks package mocks
import ( import (
reflect "reflect"
store "github.com/ProtonMail/proton-bridge/internal/store" store "github.com/ProtonMail/proton-bridge/internal/store"
credentials "github.com/ProtonMail/proton-bridge/internal/users/credentials" credentials "github.com/ProtonMail/proton-bridge/internal/users/credentials"
pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi" pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
reflect "reflect"
) )
// MockConfiger is a mock of Configer interface // MockConfiger is a mock of Configer interface

View File

@ -437,7 +437,7 @@ func (u *User) SwitchAddressMode() (err error) {
u.lock.Lock() u.lock.Lock()
defer u.lock.Unlock() defer u.lock.Unlock()
u.closeAllConnections() u.CloseAllConnections()
if u.store == nil { if u.store == nil {
err = errors.New("store is not initialised") err = errors.New("store is not initialised")
@ -509,7 +509,7 @@ func (u *User) Logout() (err error) {
// Do not close whole store, just event loop. Some information might be needed offline (e.g. addressID) // Do not close whole store, just event loop. Some information might be needed offline (e.g. addressID)
u.closeEventLoop() u.closeEventLoop()
u.closeAllConnections() u.CloseAllConnections()
runtime.GC() runtime.GC()
@ -532,8 +532,8 @@ func (u *User) closeEventLoop() {
u.store.CloseEventLoop() u.store.CloseEventLoop()
} }
// closeAllConnections calls CloseConnection for all users addresses. // CloseAllConnections calls CloseConnection for all users addresses.
func (u *User) closeAllConnections() { func (u *User) CloseAllConnections() {
for _, address := range u.creds.EmailList() { for _, address := range u.creds.EmailList() {
u.CloseConnection(address) u.CloseConnection(address)
} }

View File

@ -186,7 +186,7 @@ func (u *Users) watchAPIAuths() {
func (u *Users) closeAllConnections() { func (u *Users) closeAllConnections() {
for _, user := range u.users { for _, user := range u.users {
user.closeAllConnections() user.CloseAllConnections()
} }
} }

View File

@ -15,6 +15,13 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322 package message
//go:generate make antlr import (
"github.com/ProtonMail/go-rfc5322"
pmmime "github.com/ProtonMail/proton-bridge/pkg/mime"
)
func init() { // nolint[noinit]
rfc5322.CharsetReader = pmmime.CharsetReader
}

View File

@ -26,8 +26,8 @@ import (
"net/textproto" "net/textproto"
"strings" "strings"
"github.com/ProtonMail/go-rfc5322"
"github.com/ProtonMail/proton-bridge/pkg/message/parser" "github.com/ProtonMail/proton-bridge/pkg/message/parser"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322"
pmmime "github.com/ProtonMail/proton-bridge/pkg/mime" pmmime "github.com/ProtonMail/proton-bridge/pkg/mime"
"github.com/ProtonMail/proton-bridge/pkg/pmapi" "github.com/ProtonMail/proton-bridge/pkg/pmapi"
"github.com/emersion/go-message" "github.com/emersion/go-message"

View File

@ -1,2 +0,0 @@
antlr: RFC5322Parser.g4 RFC5322Lexer.g4
antlr4 -Dlanguage=Go -o parser $^

View File

@ -1,160 +0,0 @@
# Outline
The `rfc5322` package implements a parser for `address-list` and `date-time` strings, as defined in RFC5322.
It also supports encoded words (RFC2047) and has international tokens (RFC6532).
# `rfc5322/parser` directory
The lexer and parser are generated using ANTLR4.
The grammar is defined in the g4 files:
- RFC5322Parser.g4 defines the parser grammar,
- RFC5322Lexer.g4 defines the lexer grammar.
These grammars are derived from the ABNF grammar provided in the RFCs above,
albeit with some relaxations added to support "nonstandard" (bad) input.
Running `antlr4` on these g4 files generates a parser which recognises strings conforming to the grammar:
- rfc5322_lexer.go
- rfc5322parser_base_listener.go
- rfc5322_parser.go
- rfc5322parser_listener.go
The generated parser can then be used to convert a valid address/date into an abstract syntax tree.
# `rfc5322` directory
Once we have an abstract syntax tree, we must turn it into something usable, namely a `mail.Address` or `time.Time`.
The generated code in the `rfc5322/parser` directory implements a walker.
This walker walks over the abstract syntax tree,
calling a callback when entering and another when when exiting each node.
By default, the callbacks are no-ops, unless they are overridden.
## `walker.go`
The `walker` type extends the base walker, overriding the default no-op callbacks
to do something specific when entering and exiting certain nodes.
The goal of the walker is to traverse the syntax tree, picking out relevant information from each node's text.
For example, when parsing a `mailbox` node, the relevant information to pick out from the parse tree is the
name and address of the mailbox. This information can appear in a number of different ways, e.g. it might be
RFC2047 word-encoded, it might be a string with escaped chars that need to be handled, it might have comments
that should be ignored, and so on.
So while walking the syntax tree, each node needs to ask its children what their "value" is.
The `mailbox` needs to ask its child nodes (either a `nameAddr` node or an `addrSpec` node)
what the name and address are.
If the child node is a `nameAddr`, it needs to ask its `displayName` child what the name is
and the `angleAddr` what the address is; these in turn ask `word` nodes, `addrSpec` nodes, etc.
Each child node is responsible for telling its parent what its own value is.
The parent is responsible for assembling the children into something useful.
Ideally, this would be done with the visitor pattern. But unfortunately, the generated parser only
provides a walker interface. So we need to make use of a stack, pushing on nodes when we enter them
and popping off nodes when we exit them, to turn the walker into a kind of visitor.
## `parser.go`
This file implements two methods,
`ParseAddressList(string) ([]*mail.Address, error)`
and
`ParseDateTime(string) (time.Time, error)`.
These methods set up a parser from the raw input, start the walker, and convert the walker result
into an object of the correct type.
# Example: Parsing `dateTime`
Parsing a date-time is rather simple. The implementation begins in `date_time.go`. The abridged code is below:
```
type dateTime struct {
year int
...
}
func (dt *dateTime) withYear(year *year) {
dt.year = year.value
}
...
func (w *walker) EnterDateTime(ctx *parser.DateTimeContext) {
w.enter(&dateTime{
loc: time.UTC,
})
}
func (w *walker) ExitDateTime(ctx *parser.DateTimeContext) {
dt := w.exit().(*dateTime)
w.res = time.Date(dt.year, ...)
}
```
As you can see, when the walker reaches a `dateTime` node, it pushes a `dateTime` object onto the stack:
```
w.enter(&dateTime{
loc: time.UTC,
})
```
and when it leaves a `dateTime` node, it pops it off the stack,
converting it from `interface{}` to the concrete type,
and uses the parsed `dateTime` values like day, month, year etc
to construct a go `time.Time` object to set the walker result:
```
dt := w.exit().(*dateTime)
w.res = time.Date(dt.year, ...)
```
These parsed values were discovered while the walker continued to walk across the date-time node.
Let's see how the walker discovers the `year`.
Here is the abridged code of what happens when the walker enters a `year` node:
```
type year struct {
value int
}
func (w *walker) EnterYear(ctx *parser.YearContext) {
var text string
for _, digit := range ctx.AllDigit() {
text += digit.GetText()
}
val, err := strconv.Atoi(text)
if err != nil {
w.err = err
}
w.enter(&year{
value: val,
})
}
```
When entering the `year` node, it collects all the raw digits, which are strings, then
converts them to an integer, and sets that as the year's integer value while pushing it onto the stack.
When exiting, it pops the year off the stack and gives itself to the parent (now on the top of the stack).
It doesn't know what type of object the parent is, it just checks to see if anything above it on the stack
is expecting a `year` node:
```
func (w *walker) ExitYear(ctx *parser.YearContext) {
type withYear interface {
withYear(*year)
}
res := w.exit().(*year)
if parent, ok := w.parent().(withYear); ok {
parent.withYear(res)
}
}
```
In our case, the `date` is expecting a `year` node because it implements `withYear`,
```
func (dt *dateTime) withYear(year *year) {
dt.year = year.value
}
```
and that is how the `dateTime` data members are collected.

View File

@ -1,98 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
lexer grammar RFC5322Lexer;
U_00: '\u0000';
U_01_08: '\u0001'..'\u0008';
TAB: '\t'; // \u0009
LF: '\n'; // \u000A
U_0B: '\u000B';
U_0C: '\u000C';
CR: '\r'; // \u000D
U_0E_1F: '\u000E'..'\u001F';
// Printable (0x20-0x7E)
SP: ' '; // \u0020
Exclamation: '!'; // \u0021
DQuote: '"'; // \u0022
Hash: '#'; // \u0023
Dollar: '$'; // \u0024
Percent: '%'; // \u0025
Ampersand: '&'; // \u0026
SQuote: '\''; // \u0027
LParens: '('; // \u0028
RParens: ')'; // \u0029
Asterisk: '*'; // \u002A
Plus: '+'; // \u002B
Comma: ','; // \u002C
Minus: '-'; // \u002D
Period: '.'; // \u002E
Slash: '/'; // \u002F
Digit: [0-9]; // \u0030 -- \u0039
Colon: ':'; // \u003A
Semicolon: ';'; // \u003B
Less: '<'; // \u003C
Equal: '='; // \u003D
Greater: '>'; // \u003E
Question: '?'; // \u003F
At: '@'; // \u0040
// alphaUpper
LBracket: '['; // \u005B
Backslash: '\\'; // \u005C
RBracket: ']'; // \u005D
Caret: '^'; // \u005E
Underscore: '_'; // \u005F
Backtick: '`'; // \u0060
// alphaLower
LCurly: '{'; // \u007B
Pipe: '|'; // \u007C
RCurly: '}'; // \u007D
Tilde: '~'; // \u007E
// Other
Delete: '\u007F';
// RFC6532 Extension
UTF8NonAscii: '\u0080'..'\uFFFF';
A: 'A'|'a';
B: 'B'|'b';
C: 'C'|'c';
D: 'D'|'d';
E: 'E'|'e';
F: 'F'|'f';
G: 'G'|'g';
H: 'H'|'h';
I: 'I'|'i';
J: 'J'|'j';
K: 'K'|'k';
L: 'L'|'l';
M: 'M'|'m';
N: 'N'|'n';
O: 'O'|'o';
P: 'P'|'p';
Q: 'Q'|'q';
R: 'R'|'r';
S: 'S'|'s';
T: 'T'|'t';
U: 'U'|'u';
V: 'V'|'v';
W: 'W'|'w';
X: 'X'|'x';
Y: 'Y'|'y';
Z: 'Z'|'z';

View File

@ -1,530 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
parser grammar RFC5322Parser;
options { tokenVocab=RFC5322Lexer; }
// -------------------
// 3.2. Lexical tokens
// -------------------
quotedChar: vchar | wsp;
quotedPair
: Backslash quotedChar
| obsQP
;
fws
: (wsp* crlf)? wsp+
| obsFWS
;
ctext
: alpha
| Exclamation
| DQuote
| Hash
| Dollar
| Percent
| Ampersand
| SQuote
| Asterisk
| Plus
| Comma
| Minus
| Period
| Slash
| Digit
| Colon
| Semicolon
| Less
| Equal
| Greater
| Question
| At
| LBracket
| RBracket
| Caret
| Underscore
| Backtick
| LCurly
| Pipe
| RCurly
| Tilde
| obsCtext
| UTF8NonAscii
;
ccontent
: ctext
| quotedPair
| comment
;
comment: LParens (fws? ccontent)* fws? RParens;
cfws
: (fws? comment)+ fws?
| fws
;
atext
: alpha
| Digit
| Exclamation
| Hash
| Dollar
| Percent
| Ampersand
| SQuote
| Asterisk
| Plus
| Minus
| Slash
| Equal
| Question
| Caret
| Underscore
| Backtick
| LCurly
| Pipe
| RCurly
| Tilde
| UTF8NonAscii
;
atom: atext+;
// Allow dotAtom to have a trailing period; some messages in the wild look like this.
dotAtom: atext+ (Period atext+)* Period?;
qtext
: alpha
| Exclamation
| Hash
| Dollar
| Percent
| Ampersand
| SQuote
| LParens
| RParens
| Asterisk
| Plus
| Comma
| Minus
| Period
| Slash
| Digit
| Colon
| Semicolon
| Less
| Equal
| Greater
| Question
| At
| LBracket
| RBracket
| Caret
| Underscore
| Backtick
| LCurly
| Pipe
| RCurly
| Tilde
| obsQtext
| UTF8NonAscii
;
quotedContent
: qtext
| quotedPair
;
quotedValue: (fws? quotedContent)*;
quotedString: DQuote quotedValue fws? DQuote;
// Allow word to consist of the @ token.
word
: cfws? encodedWord cfws?
| cfws? atom cfws?
| cfws? quotedString cfws?
| At
;
// --------------------------------
// 3.3. Date and Time Specification
// --------------------------------
dateTime: (dayOfweek Comma)? day month year hour Colon minute (Colon second)? zone? cfws? EOF;
dayOfweek
: fws? dayName
| cfws? dayName cfws?
;
dayName
: M O N
| T U E
| W E D
| T H U
| F R I
| S A T
| S U N
;
day
: fws? Digit Digit? fws
| cfws? Digit Digit? cfws?
;
month
: J A N
| F E B
| M A R
| A P R
| M A Y
| J U N
| J U L
| A U G
| S E P
| O C T
| N O V
| D E C
;
year
: fws Digit Digit Digit Digit fws
| cfws? Digit Digit cfws?
;
// NOTE: RFC5322 requires two digits for the hour, but we
// relax that requirement a bit, allowing single digits.
hour
: Digit? Digit
| cfws? Digit? Digit cfws?
;
minute
: Digit Digit
| cfws? Digit Digit cfws?
;
second
: Digit Digit
| cfws? Digit Digit cfws?
;
offset: (Plus | Minus)? Digit Digit Digit Digit;
zone
: fws offset
| obsZone
;
// --------------------------
// 3.4. Address Specification
// --------------------------
address
: mailbox
| group
;
mailbox
: nameAddr
| addrSpec
;
nameAddr: displayName? angleAddr;
angleAddr
: cfws? Less addrSpec? Greater cfws?
| obsAngleAddr
;
group: displayName Colon groupList? Semicolon cfws?;
displayName
: word+
| word (word | Period | cfws)*
;
mailboxList
: mailbox (Comma mailbox)*
| obsMboxList
;
addressList
: address (Comma address)* EOF
| obsAddrList EOF
;
groupList
: mailboxList
| cfws
| obsGroupList
;
// Allow addrSpec contain a port.
addrSpec: localPart At domain (Colon port)?;
localPart
: cfws? dotAtom cfws?
| cfws? quotedString cfws?
| obsLocalPart
;
port: Digit+;
domain
: cfws? dotAtom cfws?
| cfws? domainLiteral cfws?
| cfws? obsDomain cfws?
;
domainLiteral: LBracket (fws? dtext)* fws? RBracket;
dtext
: alpha
| Exclamation
| DQuote
| Hash
| Dollar
| Percent
| Ampersand
| SQuote
| LParens
| RParens
| Asterisk
| Plus
| Comma
| Minus
| Period
| Slash
| Digit
| Colon
| Semicolon
| Less
| Equal
| Greater
| Question
| At
| Caret
| Underscore
| Backtick
| LCurly
| Pipe
| RCurly
| Tilde
//| obsDtext
| UTF8NonAscii
;
// ----------------------------------
// 4.1. Miscellaneous Obsolete Tokens
// ----------------------------------
obsNoWSCTL
: U_01_08
| U_0B
| U_0C
| U_0E_1F
| Delete
;
obsCtext: obsNoWSCTL;
obsQtext: obsNoWSCTL;
obsQP: Backslash (U_00 | obsNoWSCTL | LF | CR);
// ---------------------------------
// 4.2. Obsolete Folding White Space
// ---------------------------------
obsFWS: wsp+ (crlf wsp+);
// ---------------------------
// 4.3. Obsolete Date and Time
// ---------------------------
obsZone
: U T
| U T C
| G M T
| E S T
| E D T
| C S T
| C D T
| M S T
| M D T
| P S T
| P D T
//| obsZoneMilitary
;
// ------------------------
// 4.4. Obsolete Addressing
// ------------------------
obsAngleAddr: cfws? Less obsRoute addrSpec Greater cfws?;
obsRoute: obsDomainList Colon;
obsDomainList: (cfws | Comma)* At domain (Comma cfws? (At domain)?)*;
obsMboxList: (cfws? Comma)* mailbox (Comma (mailbox | cfws)?)*;
obsAddrList: (cfws? Comma)* address (Comma (address | cfws)?)*;
obsGroupList: (cfws? Comma)+ cfws?;
obsLocalPart: word (Period word)*;
obsDomain: atom (Period atom)*;
// ------------------------------------
// 2. Syntax of encoded-words (RFC2047)
// ------------------------------------
encodedWord: Equal Question charset Question encoding Question encodedText Question Equal;
charset: token;
encoding: token;
token: tokenChar+;
tokenChar
: alpha
| Exclamation
| Hash
| Dollar
| Percent
| Ampersand
| SQuote
| Asterisk
| Plus
| Minus
| Digit
| Backslash
| Caret
| Underscore
| Backtick
| LCurly
| Pipe
| RCurly
| Tilde
;
encodedText: encodedChar+;
encodedChar
: alpha
| Exclamation
| DQuote
| Hash
| Dollar
| Percent
| Ampersand
| SQuote
| LParens
| RParens
| Asterisk
| Plus
| Comma
| Minus
| Period
| Slash
| Digit
| Colon
| Semicolon
| Less
| Equal
| Greater
| At
| LBracket
| Backslash
| RBracket
| Caret
| Underscore
| Backtick
| LCurly
| Pipe
| RCurly
| Tilde
;
// -------------------------
// B.1. Core Rules (RFC5234)
// -------------------------
crlf: CR LF;
wsp: SP | TAB;
vchar
: alpha
| Exclamation
| DQuote
| Hash
| Dollar
| Percent
| Ampersand
| SQuote
| LParens
| RParens
| Asterisk
| Plus
| Comma
| Minus
| Period
| Slash
| Digit
| Colon
| Semicolon
| Less
| Equal
| Greater
| Question
| At
| LBracket
| Backslash
| RBracket
| Caret
| Underscore
| Backtick
| LCurly
| Pipe
| RCurly
| Tilde
| UTF8NonAscii
;
alpha: A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z ;

View File

@ -1,58 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type addrSpec struct {
localPart, domain string
}
func (a *addrSpec) withLocalPart(localPart *localPart) {
a.localPart = localPart.value
}
func (a *addrSpec) withDomain(domain *domain) {
a.domain = domain.value
}
func (a *addrSpec) withPort(port *port) {
a.domain += ":" + port.value
}
func (w *walker) EnterAddrSpec(ctx *parser.AddrSpecContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering addrSpec")
w.enter(&addrSpec{})
}
func (w *walker) ExitAddrSpec(ctx *parser.AddrSpecContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting addrSpec")
type withAddrSpec interface {
withAddrSpec(*addrSpec)
}
res := w.exit().(*addrSpec)
if parent, ok := w.parent().(withAddrSpec); ok {
parent.withAddrSpec(res)
}
}

View File

@ -1,59 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"net/mail"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type address struct {
addresses []*mail.Address
}
func (a *address) withMailbox(mailbox *mailbox) {
a.addresses = append(a.addresses, &mail.Address{
Name: mailbox.name,
Address: mailbox.address,
})
}
func (a *address) withGroup(group *group) {
a.addresses = append(a.addresses, group.addresses...)
}
func (w *walker) EnterAddress(ctx *parser.AddressContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering address")
w.enter(&address{})
}
func (w *walker) ExitAddress(ctx *parser.AddressContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting address")
type withAddress interface {
withAddress(*address)
}
res := w.exit().(*address)
if parent, ok := w.parent().(withAddress); ok {
parent.withAddress(res)
}
}

View File

@ -1,43 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"net/mail"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type addressList struct {
addresses []*mail.Address
}
func (a *addressList) withAddress(address *address) {
a.addresses = append(a.addresses, address.addresses...)
}
func (w *walker) EnterAddressList(ctx *parser.AddressListContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering addressList")
w.enter(&addressList{})
}
func (w *walker) ExitAddressList(ctx *parser.AddressListContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting addressList")
w.res = w.exit().(*addressList).addresses
}

View File

@ -1,56 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"fmt"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type angleAddr struct {
address string
}
func (a *angleAddr) withAddrSpec(addrSpec *addrSpec) {
a.address = fmt.Sprintf("%v@%v", addrSpec.localPart, addrSpec.domain)
}
func (a *angleAddr) withObsAngleAddr(obsAngleAddr *obsAngleAddr) {
a.address = obsAngleAddr.address
}
func (w *walker) EnterAngleAddr(ctx *parser.AngleAddrContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering angleAddr")
w.enter(&angleAddr{})
}
func (w *walker) ExitAngleAddr(ctx *parser.AngleAddrContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting angleAddr")
type withAngleAddr interface {
withAngleAddr(*angleAddr)
}
res := w.exit().(*angleAddr)
if parent, ok := w.parent().(withAngleAddr); ok {
parent.withAngleAddr(res)
}
}

View File

@ -1,49 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type atom struct {
value string
}
func (w *walker) EnterAtom(ctx *parser.AtomContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering atom")
w.enter(&atom{
value: ctx.GetText(),
})
}
func (w *walker) ExitAtom(ctx *parser.AtomContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting atom")
type withAtom interface {
withAtom(*atom)
}
res := w.exit().(*atom)
if parent, ok := w.parent().(withAtom); ok {
parent.withAtom(res)
}
}

View File

@ -1,79 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"time"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type dateTime struct {
day int
month time.Month
year int
hour, min, sec int
loc *time.Location
}
func (dt *dateTime) withDay(day *day) {
dt.day = day.value
}
func (dt *dateTime) withMonth(month *month) {
dt.month = month.value
}
func (dt *dateTime) withYear(year *year) {
dt.year = year.value
}
func (dt *dateTime) withHour(hour *hour) {
dt.hour = hour.value
}
func (dt *dateTime) withMinute(minute *minute) {
dt.min = minute.value
}
func (dt *dateTime) withSecond(second *second) {
dt.sec = second.value
}
func (dt *dateTime) withZone(zone *zone) {
dt.loc = zone.location
}
func (w *walker) EnterDateTime(ctx *parser.DateTimeContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering dateTime")
w.enter(&dateTime{
loc: time.UTC,
})
}
func (w *walker) ExitDateTime(ctx *parser.DateTimeContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting dateTime")
dt := w.exit().(*dateTime)
w.res = time.Date(dt.year, dt.month, dt.day, dt.hour, dt.min, dt.sec, 0, dt.loc)
}

View File

@ -1,62 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"strconv"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type day struct {
value int
}
func (w *walker) EnterDay(ctx *parser.DayContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering day")
var text string
for _, digit := range ctx.AllDigit() {
text += digit.GetText()
}
val, err := strconv.Atoi(text)
if err != nil {
w.err = err
}
w.enter(&day{
value: val,
})
}
func (w *walker) ExitDay(ctx *parser.DayContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting day")
type withDay interface {
withDay(*day)
}
res := w.exit().(*day)
if parent, ok := w.parent().(withDay); ok {
parent.withDay(res)
}
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type displayName struct {
words []string
}
func (n *displayName) withWord(word *word) {
n.words = append(n.words, word.value)
}
func (w *walker) EnterDisplayName(ctx *parser.DisplayNameContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering displayName")
w.enter(&displayName{})
}
func (w *walker) ExitDisplayName(ctx *parser.DisplayNameContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting displayName")
type withDisplayName interface {
withDisplayName(*displayName)
}
res := w.exit().(*displayName)
if parent, ok := w.parent().(withDisplayName); ok {
parent.withDisplayName(res)
}
}

View File

@ -1,60 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"strings"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type domain struct {
value string
}
func (d *domain) withDotAtom(dotAtom *dotAtom) {
d.value = dotAtom.value
}
func (d *domain) withDomainLiteral(domainLiteral *domainLiteral) {
d.value = domainLiteral.value
}
func (d *domain) withObsDomain(obsDomain *obsDomain) {
d.value = strings.Join(obsDomain.atoms, ".")
}
func (w *walker) EnterDomain(ctx *parser.DomainContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering domain")
w.enter(&domain{})
}
func (w *walker) ExitDomain(ctx *parser.DomainContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting domain")
type withDomain interface {
withDomain(*domain)
}
res := w.exit().(*domain)
if parent, ok := w.parent().(withDomain); ok {
parent.withDomain(res)
}
}

View File

@ -1,49 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type domainLiteral struct {
value string
}
func (w *walker) EnterDomainLiteral(ctx *parser.DomainLiteralContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering domainLiteral")
w.enter(&domainLiteral{
value: ctx.GetText(),
})
}
func (w *walker) ExitDomainLiteral(ctx *parser.DomainLiteralContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting domainLiteral")
type withDomainLiteral interface {
withDomainLiteral(*domainLiteral)
}
res := w.exit().(*domainLiteral)
if parent, ok := w.parent().(withDomainLiteral); ok {
parent.withDomainLiteral(res)
}
}

View File

@ -1,49 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type dotAtom struct {
value string
}
func (w *walker) EnterDotAtom(ctx *parser.DotAtomContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering dotAtom")
w.enter(&dotAtom{
value: ctx.GetText(),
})
}
func (w *walker) ExitDotAtom(ctx *parser.DotAtomContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting dotAtom")
type withDotAtom interface {
withDotAtom(*dotAtom)
}
res := w.exit().(*dotAtom)
if parent, ok := w.parent().(withDotAtom); ok {
parent.withDotAtom(res)
}
}

View File

@ -1,55 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
pmmime "github.com/ProtonMail/proton-bridge/pkg/mime"
"github.com/sirupsen/logrus"
)
type encodedWord struct {
value string
}
func (w *walker) EnterEncodedWord(ctx *parser.EncodedWordContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering encodedWord")
word, err := pmmime.WordDec.Decode(ctx.GetText())
if err != nil {
word = ctx.GetText()
}
w.enter(&encodedWord{
value: word,
})
}
func (w *walker) ExitEncodedWord(ctx *parser.EncodedWordContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting encodedWord")
type withEncodedWord interface {
withEncodedWord(*encodedWord)
}
res := w.exit().(*encodedWord)
if parent, ok := w.parent().(withEncodedWord); ok {
parent.withEncodedWord(res)
}
}

View File

@ -1,52 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"net/mail"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type group struct {
addresses []*mail.Address
}
func (g *group) withGroupList(groupList *groupList) {
g.addresses = append(g.addresses, groupList.addresses...)
}
func (w *walker) EnterGroup(ctx *parser.GroupContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering group")
w.enter(&group{})
}
func (w *walker) ExitGroup(ctx *parser.GroupContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting group")
type withGroup interface {
withGroup(*group)
}
res := w.exit().(*group)
if parent, ok := w.parent().(withGroup); ok {
parent.withGroup(res)
}
}

View File

@ -1,52 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"net/mail"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type groupList struct {
addresses []*mail.Address
}
func (gl *groupList) withMailboxList(mailboxList *mailboxList) {
gl.addresses = append(gl.addresses, mailboxList.addresses...)
}
func (w *walker) EnterGroupList(ctx *parser.GroupListContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering groupList")
w.enter(&groupList{})
}
func (w *walker) ExitGroupList(ctx *parser.GroupListContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting groupList")
type withGroupList interface {
withGroupList(*groupList)
}
res := w.exit().(*groupList)
if parent, ok := w.parent().(withGroupList); ok {
parent.withGroupList(res)
}
}

View File

@ -1,62 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"strconv"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type hour struct {
value int
}
func (w *walker) EnterHour(ctx *parser.HourContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering hour")
var text string
for _, digit := range ctx.AllDigit() {
text += digit.GetText()
}
val, err := strconv.Atoi(text)
if err != nil {
w.err = err
}
w.enter(&hour{
value: val,
})
}
func (w *walker) ExitHour(ctx *parser.HourContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting hour")
type withHour interface {
withHour(*hour)
}
res := w.exit().(*hour)
if parent, ok := w.parent().(withHour); ok {
parent.withHour(res)
}
}

View File

@ -1,60 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"strings"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type localPart struct {
value string
}
func (p *localPart) withDotAtom(dotAtom *dotAtom) {
p.value = dotAtom.value
}
func (p *localPart) withQuotedString(quotedString *quotedString) {
p.value = quotedString.value
}
func (p *localPart) withObsLocalPart(obsLocalPart *obsLocalPart) {
p.value = strings.Join(obsLocalPart.words, ".")
}
func (w *walker) EnterLocalPart(ctx *parser.LocalPartContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering localPart")
w.enter(&localPart{})
}
func (w *walker) ExitLocalPart(ctx *parser.LocalPartContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting localPart")
type withLocalPart interface {
withLocalPart(*localPart)
}
res := w.exit().(*localPart)
if parent, ok := w.parent().(withLocalPart); ok {
parent.withLocalPart(res)
}
}

View File

@ -1,57 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"fmt"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type mailbox struct {
name, address string
}
func (m *mailbox) withNameAddr(nameAddr *nameAddr) {
m.name = nameAddr.name
m.address = nameAddr.address
}
func (m *mailbox) withAddrSpec(addrSpec *addrSpec) {
m.address = fmt.Sprintf("%v@%v", addrSpec.localPart, addrSpec.domain)
}
func (w *walker) EnterMailbox(ctx *parser.MailboxContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering mailbox")
w.enter(&mailbox{})
}
func (w *walker) ExitMailbox(ctx *parser.MailboxContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting mailbox")
type withMailbox interface {
withMailbox(*mailbox)
}
res := w.exit().(*mailbox)
if parent, ok := w.parent().(withMailbox); ok {
parent.withMailbox(res)
}
}

View File

@ -1,59 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"net/mail"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type mailboxList struct {
addresses []*mail.Address
}
func (ml *mailboxList) withMailbox(mailbox *mailbox) {
ml.addresses = append(ml.addresses, &mail.Address{
Name: mailbox.name,
Address: mailbox.address,
})
}
func (ml *mailboxList) withObsMboxList(obsMboxList *obsMboxList) {
ml.addresses = append(ml.addresses, obsMboxList.addresses...)
}
func (w *walker) EnterMailboxList(ctx *parser.MailboxListContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering mailboxList")
w.enter(&mailboxList{})
}
func (w *walker) ExitMailboxList(ctx *parser.MailboxListContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting mailboxList")
type withMailboxList interface {
withMailboxList(*mailboxList)
}
res := w.exit().(*mailboxList)
if parent, ok := w.parent().(withMailboxList); ok {
parent.withMailboxList(res)
}
}

View File

@ -1,62 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"strconv"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type minute struct {
value int
}
func (w *walker) EnterMinute(ctx *parser.MinuteContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering minute")
var text string
for _, digit := range ctx.AllDigit() {
text += digit.GetText()
}
val, err := strconv.Atoi(text)
if err != nil {
w.err = err
}
w.enter(&minute{
value: val,
})
}
func (w *walker) ExitMinute(ctx *parser.MinuteContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting minute")
type withMinute interface {
withMinute(*minute)
}
res := w.exit().(*minute)
if parent, ok := w.parent().(withMinute); ok {
parent.withMinute(res)
}
}

View File

@ -1,84 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"errors"
"strings"
"time"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type month struct {
value time.Month
}
func (w *walker) EnterMonth(ctx *parser.MonthContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering month")
var m time.Month
switch strings.ToLower(ctx.GetText()) {
case "jan":
m = time.January
case "feb":
m = time.February
case "mar":
m = time.March
case "apr":
m = time.April
case "may":
m = time.May
case "jun":
m = time.June
case "jul":
m = time.July
case "aug":
m = time.August
case "sep":
m = time.September
case "oct":
m = time.October
case "nov":
m = time.November
case "dec":
m = time.December
default:
w.err = errors.New("no such month")
}
w.enter(&month{
value: m,
})
}
func (w *walker) ExitMonth(ctx *parser.MonthContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting month")
type withMonth interface {
withMonth(*month)
}
res := w.exit().(*month)
if parent, ok := w.parent().(withMonth); ok {
parent.withMonth(res)
}
}

View File

@ -1,56 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"strings"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type nameAddr struct {
name, address string
}
func (a *nameAddr) withDisplayName(displayName *displayName) {
a.name = strings.Join(displayName.words, " ")
}
func (a *nameAddr) withAngleAddr(angleAddr *angleAddr) {
a.address = angleAddr.address
}
func (w *walker) EnterNameAddr(ctx *parser.NameAddrContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering nameAddr")
w.enter(&nameAddr{})
}
func (w *walker) ExitNameAddr(ctx *parser.NameAddrContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting nameAddr")
type withNameAddr interface {
withNameAddr(*nameAddr)
}
res := w.exit().(*nameAddr)
if parent, ok := w.parent().(withNameAddr); ok {
parent.withNameAddr(res)
}
}

View File

@ -1,54 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"fmt"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
// When interpreting addresses, the route portion SHOULD be ignored.
type obsAngleAddr struct {
address string
}
func (a *obsAngleAddr) withAddrSpec(addrSpec *addrSpec) {
a.address = fmt.Sprintf("%v@%v", addrSpec.localPart, addrSpec.domain)
}
func (w *walker) EnterObsAngleAddr(ctx *parser.ObsAngleAddrContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering obsAngleAddr")
w.enter(&obsAngleAddr{})
}
func (w *walker) ExitObsAngleAddr(ctx *parser.ObsAngleAddrContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting obsAngleAddr")
type withObsAngleAddr interface {
withObsAngleAddr(*obsAngleAddr)
}
res := w.exit().(*obsAngleAddr)
if parent, ok := w.parent().(withObsAngleAddr); ok {
parent.withObsAngleAddr(res)
}
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type obsDomain struct {
atoms []string
}
func (p *obsDomain) withAtom(atom *atom) {
p.atoms = append(p.atoms, atom.value)
}
func (w *walker) EnterObsDomain(ctx *parser.ObsDomainContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering obsDomain")
w.enter(&obsDomain{})
}
func (w *walker) ExitObsDomain(ctx *parser.ObsDomainContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting obsDomain")
type withObsDomain interface {
withObsDomain(*obsDomain)
}
res := w.exit().(*obsDomain)
if parent, ok := w.parent().(withObsDomain); ok {
parent.withObsDomain(res)
}
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type obsLocalPart struct {
words []string
}
func (p *obsLocalPart) withWord(word *word) {
p.words = append(p.words, word.value)
}
func (w *walker) EnterObsLocalPart(ctx *parser.ObsLocalPartContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering obsLocalPart")
w.enter(&obsLocalPart{})
}
func (w *walker) ExitObsLocalPart(ctx *parser.ObsLocalPartContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting obsLocalPart")
type withObsLocalPart interface {
withObsLocalPart(*obsLocalPart)
}
res := w.exit().(*obsLocalPart)
if parent, ok := w.parent().(withObsLocalPart); ok {
parent.withObsLocalPart(res)
}
}

View File

@ -1,55 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"net/mail"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type obsMboxList struct {
addresses []*mail.Address
}
func (ml *obsMboxList) withMailbox(mailbox *mailbox) {
ml.addresses = append(ml.addresses, &mail.Address{
Name: mailbox.name,
Address: mailbox.address,
})
}
func (w *walker) EnterObsMboxList(ctx *parser.ObsMboxListContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering obsMboxList")
w.enter(&obsMboxList{})
}
func (w *walker) ExitObsMboxList(ctx *parser.ObsMboxListContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting obsMboxList")
type withObsMboxList interface {
withObsMboxList(*obsMboxList)
}
res := w.exit().(*obsMboxList)
if parent, ok := w.parent().(withObsMboxList); ok {
parent.withObsMboxList(res)
}
}

View File

@ -1,82 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"errors"
"strings"
"time"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type obsZone struct {
location *time.Location
}
func (w *walker) EnterObsZone(ctx *parser.ObsZoneContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering obsZone")
loc := time.UTC
switch strings.ToLower(ctx.GetText()) {
case "ut":
loc = time.FixedZone(ctx.GetText(), 0)
case "utc":
loc = time.FixedZone(ctx.GetText(), 0)
case "gmt":
loc = time.FixedZone(ctx.GetText(), 0)
case "est":
loc = time.FixedZone(ctx.GetText(), -5*60*60)
case "edt":
loc = time.FixedZone(ctx.GetText(), -4*60*60)
case "cst":
loc = time.FixedZone(ctx.GetText(), -6*60*60)
case "cdt":
loc = time.FixedZone(ctx.GetText(), -5*60*60)
case "mst":
loc = time.FixedZone(ctx.GetText(), -7*60*60)
case "mdt":
loc = time.FixedZone(ctx.GetText(), -6*60*60)
case "pst":
loc = time.FixedZone(ctx.GetText(), -8*60*60)
case "pdt":
loc = time.FixedZone(ctx.GetText(), -7*60*60)
default:
w.err = errors.New("bad timezone")
}
w.enter(&obsZone{
location: loc,
})
}
func (w *walker) ExitObsZone(ctx *parser.ObsZoneContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting obsZone")
type withObsZone interface {
withObsZone(*obsZone)
}
res := w.exit().(*obsZone)
if parent, ok := w.parent().(withObsZone); ok {
parent.withObsZone(res)
}
}

View File

@ -1,73 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"fmt"
"strings"
"time"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type offset struct {
rep string
value int
}
func (w *walker) EnterOffset(ctx *parser.OffsetContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering offset")
text := ctx.GetText()
// NOTE: RFC5322 date-time should always begin with + or -
// but we relax that requirement a bit due to many messages
// in the wild that skip the +; we add the "+" if missing.
if !strings.HasPrefix(text, "+") && !strings.HasPrefix(text, "-") {
text = "+" + text
}
sgn := text[0:1]
hrs := text[1:3]
min := text[3:5]
dur, err := time.ParseDuration(fmt.Sprintf("%v%vh%vm", sgn, hrs, min))
if err != nil {
w.err = err
}
w.enter(&offset{
rep: text,
value: int(dur.Seconds()),
})
}
func (w *walker) ExitOffset(ctx *parser.OffsetContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting offset")
type withOffset interface {
withOffset(*offset)
}
res := w.exit().(*offset)
if parent, ok := w.parent().(withOffset); ok {
parent.withOffset(res)
}
}

View File

@ -1,701 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"encoding/xml"
"io"
"net/mail"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestParseSingleAddress(t *testing.T) {
tests := []struct {
input string
addrs []*mail.Address
}{
{
input: `user@example.com`,
addrs: []*mail.Address{{
Address: `user@example.com`,
}},
},
{
input: `John Doe <jdoe@machine.example>`,
addrs: []*mail.Address{{
Name: `John Doe`,
Address: `jdoe@machine.example`,
}},
},
{
input: `Mary Smith <mary@example.net>`,
addrs: []*mail.Address{{
Name: `Mary Smith`,
Address: `mary@example.net`,
}},
},
{
input: `"Joe Q. Public" <john.q.public@example.com>`,
addrs: []*mail.Address{{
Name: `Joe Q. Public`,
Address: `john.q.public@example.com`,
}},
},
{
input: `Mary Smith <mary@x.test>`,
addrs: []*mail.Address{{
Name: `Mary Smith`,
Address: `mary@x.test`,
}},
},
{
input: `jdoe@example.org`,
addrs: []*mail.Address{{
Address: `jdoe@example.org`,
}},
},
{
input: `Who? <one@y.test>`,
addrs: []*mail.Address{{
Name: `Who?`,
Address: `one@y.test`,
}},
},
{
input: `<boss@nil.test>`,
addrs: []*mail.Address{{
Address: `boss@nil.test`,
}},
},
{
input: `"Giant; \"Big\" Box" <sysservices@example.net>`,
addrs: []*mail.Address{{
Name: `Giant; "Big" Box`,
Address: `sysservices@example.net`,
}},
},
{
input: `Pete <pete@silly.example>`,
addrs: []*mail.Address{{
Name: `Pete`,
Address: `pete@silly.example`,
}},
},
{
input: `"Mary Smith: Personal Account" <smith@home.example>`,
addrs: []*mail.Address{{
Name: `Mary Smith: Personal Account`,
Address: `smith@home.example`,
}},
},
{
input: `Pete(A nice \) chap) <pete(his account)@silly.test(his host)>`,
addrs: []*mail.Address{{
Name: `Pete`,
Address: `pete@silly.test`,
}},
},
{
input: `Gogh Fir <gf@example.com>`,
addrs: []*mail.Address{{
Name: `Gogh Fir`,
Address: `gf@example.com`,
}},
},
{
input: `normal name <username@server.com>`,
addrs: []*mail.Address{{
Name: `normal name`,
Address: `username@server.com`,
}},
},
{
input: `"comma, name" <username@server.com>`,
addrs: []*mail.Address{{
Name: `comma, name`,
Address: `username@server.com`,
}},
},
{
input: `name <username@server.com> (ignore comment)`,
addrs: []*mail.Address{{
Name: `name`,
Address: `username@server.com`,
}},
},
{
input: `"Mail Robot" <>`,
addrs: []*mail.Address{{
Name: `Mail Robot`,
}},
},
{
input: `Michal Hořejšek <hořejšek@mail.com>`,
addrs: []*mail.Address{{
Name: `Michal Hořejšek`,
Address: `hořejšek@mail.com`, // Not his real address.
}},
},
{
input: `First Last <user@domain.com >`,
addrs: []*mail.Address{{
Name: `First Last`,
Address: `user@domain.com`,
}},
},
{
input: `First Last <user@domain.com. >`,
addrs: []*mail.Address{{
Name: `First Last`,
Address: `user@domain.com.`,
}},
},
{
input: `First Last <user@domain.com.>`,
addrs: []*mail.Address{{
Name: `First Last`,
Address: `user@domain.com.`,
}},
},
{
input: `First Last <user@domain.com:25>`,
addrs: []*mail.Address{{
Name: `First Last`,
Address: `user@domain.com:25`,
}},
},
{
input: `First Last <user@[10.0.0.1]>`,
addrs: []*mail.Address{{
Name: `First Last`,
Address: `user@[10.0.0.1]`,
}},
},
{
input: `<postmaster@[10.10.10.10]>`,
addrs: []*mail.Address{
{
Address: `postmaster@[10.10.10.10]`,
},
},
},
{
input: `user@domain <user@domain.com>`,
addrs: []*mail.Address{{
// Name: `user@domain`,
Name: `user @ domain`,
Address: `user@domain.com`,
}},
},
{
input: `First Last < user@domain.com>`,
addrs: []*mail.Address{{
Name: `First Last`,
Address: `user@domain.com`,
}},
},
{
input: `First Middle @ Last <user@domain.com>`,
addrs: []*mail.Address{{
Name: `First Middle @ Last`,
Address: `user@domain.com`,
}},
},
{
input: `user@domain.com,`,
addrs: []*mail.Address{
{
Address: `user@domain.com`,
},
},
},
{
input: `First Middle "Last" <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First Middle Last <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First Middle"Last" <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First Middle "Last"<user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First "Middle" "Last" <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First "Middle""Last" <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
addrs, err := ParseAddressList(test.input)
assert.NoError(t, err)
assert.ElementsMatch(t, test.addrs, addrs)
})
}
}
func TestParseSingleAddressEncodedWord(t *testing.T) {
tests := []struct {
input string
addrs []*mail.Address
}{
{
input: `=?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>`,
addrs: []*mail.Address{{
Name: `Keith Moore`,
Address: `moore@cs.utk.edu`,
}},
},
{
input: `=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>`,
addrs: []*mail.Address{{
Name: `Keld Jørn Simonsen`,
Address: `keld@dkuug.dk`,
}},
},
{
input: `=?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>`,
addrs: []*mail.Address{{
Name: `André Pirard`,
Address: `PIRARD@vm1.ulg.ac.be`,
}},
},
{
input: `=?ISO-8859-1?Q?Olle_J=E4rnefors?= <ojarnef@admin.kth.se>`,
addrs: []*mail.Address{{
Name: `Olle Järnefors`,
Address: `ojarnef@admin.kth.se`,
}},
},
{
input: `=?ISO-8859-1?Q?Patrik_F=E4ltstr=F6m?= <paf@nada.kth.se>`,
addrs: []*mail.Address{{
Name: `Patrik Fältström`,
Address: `paf@nada.kth.se`,
}},
},
{
input: `Nathaniel Borenstein <nsb@thumper.bellcore.com> (=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?=)`,
addrs: []*mail.Address{{
Name: `Nathaniel Borenstein`,
Address: `nsb@thumper.bellcore.com`,
}},
},
{
input: `=?UTF-8?B?PEJlemUgam3DqW5hPg==?= <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `<Beze jména>`,
Address: `user@domain.com`,
},
},
},
{
input: `First Middle =?utf-8?Q?Last?= <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
/*
{
input: `First Middle=?utf-8?Q?Last?= <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
*/
{
input: `First Middle =?utf-8?Q?Last?=<user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First =?utf-8?Q?Middle?= =?utf-8?Q?Last?= <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First =?utf-8?Q?Middle?==?utf-8?Q?Last?= <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First "Middle"=?utf-8?Q?Last?= <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First "Middle" =?utf-8?Q?Last?= <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `First "Middle" =?utf-8?Q?Last?=<user@domain.com>`,
addrs: []*mail.Address{
{
Name: `First Middle Last`,
Address: `user@domain.com`,
},
},
},
{
input: `=?UTF-8?B?PEJlemUgam3DqW5hPg==?= <user@domain.com>`,
addrs: []*mail.Address{
{
Name: `<Beze jména>`,
Address: `user@domain.com`,
},
},
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
addrs, err := ParseAddressList(test.input)
assert.NoError(t, err)
assert.ElementsMatch(t, test.addrs, addrs)
})
}
}
func TestParseAddressList(t *testing.T) {
tests := []struct {
input string
addrs []*mail.Address
}{
{
input: `Alice <alice@example.com>, Bob <bob@example.com>, Eve <eve@example.com>`,
addrs: []*mail.Address{
{
Name: `Alice`,
Address: `alice@example.com`,
},
{
Name: `Bob`,
Address: `bob@example.com`,
},
{
Name: `Eve`,
Address: `eve@example.com`,
},
},
},
{
input: `Ed Jones <c@a.test>,joe@where.test,John <jdoe@one.test>`,
addrs: []*mail.Address{
{
Name: `Ed Jones`,
Address: `c@a.test`,
},
{
Address: `joe@where.test`,
},
{
Name: `John`,
Address: `jdoe@one.test`,
},
},
},
{
input: `name (ignore comment) <username@server.com>, (Comment as name) username2@server.com`,
addrs: []*mail.Address{
{
Name: `name`,
Address: `username@server.com`,
},
{
Address: `username2@server.com`,
},
},
},
{
input: `"normal name" <username@server.com>, "comma, name" <address@server.com>`,
addrs: []*mail.Address{
{
Name: `normal name`,
Address: `username@server.com`,
},
{
Name: `comma, name`,
Address: `address@server.com`,
},
},
},
{
input: `"comma, one" <username@server.com>, "comma, two" <address@server.com>`,
addrs: []*mail.Address{
{
Name: `comma, one`,
Address: `username@server.com`,
},
{
Name: `comma, two`,
Address: `address@server.com`,
},
},
},
{
input: `normal name <username@server.com>, (comment)All.(around)address@(the)server.com`,
addrs: []*mail.Address{
{
Name: `normal name`,
Address: `username@server.com`,
},
{
Address: `All.address@server.com`,
},
},
},
{
input: `normal name <username@server.com>, All.("comma, in comment")address@(the)server.com`,
addrs: []*mail.Address{
{
Name: `normal name`,
Address: `username@server.com`,
},
{
Address: `All.address@server.com`,
},
},
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
addrs, err := ParseAddressList(test.input)
assert.NoError(t, err)
assert.ElementsMatch(t, test.addrs, addrs)
})
}
}
func TestParseGroup(t *testing.T) {
tests := []struct {
input string
addrs []*mail.Address
}{
{
input: `A Group:Ed Jones <c@a.test>,joe@where.test,John <jdoe@one.test>;`,
addrs: []*mail.Address{
{
Name: `Ed Jones`,
Address: `c@a.test`,
},
{
Address: `joe@where.test`,
},
{
Name: `John`,
Address: `jdoe@one.test`,
},
},
},
{
input: `Undisclosed recipients:;`,
addrs: []*mail.Address{},
},
{
input: `(Empty list)(start)Hidden recipients :(nobody(that I know)) ;`,
addrs: []*mail.Address{},
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
addrs, err := ParseAddressList(test.input)
assert.NoError(t, err)
assert.ElementsMatch(t, test.addrs, addrs)
})
}
}
// TestParseRejectedAddresses tests that weird addresses that are rejected by
// serverside are also rejected by us. If for some reason we end up being able
// to parse these malformed addresses, great! For now let's collect them here.
func TestParseRejectedAddresses(t *testing.T) {
tests := []struct {
input string
addrs []*mail.Address
}{
{input: `"comma, name" <username@server.com>, another, name <address@server.com>`},
{input: `username`},
{input: `undisclosed-recipients:`},
{input: `=?ISO-8859-2?Q?First_Last?= <user@domain.com>, <user@domain.com,First/AAA/BBB/CCC,>`},
{input: `user@domain...com`},
{input: `=?windows-1250?Q?Spr=E1vce_syst=E9mu?=`},
{input: `"'user@domain.com.'"`},
{input: `<this is not an email address>`},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
_, err := ParseAddressList(test.input)
assert.Error(t, err)
})
}
}
// TestIsEmailValidCategory runs over the "IsEmail" standard tests,
// ensuring it can at least recognize all emails in the "valid" category.
// In future, we should expand these tests to run over more categories.
func TestIsEmailValidCategory(t *testing.T) {
f, err := os.Open("tests.xml")
require.NoError(t, err)
defer func() { require.NoError(t, err) }()
for test := range readTestCases(f) {
test := test
if test.category != "ISEMAIL_VALID_CATEGORY" {
continue
}
t.Run(test.id, func(t *testing.T) {
_, err := ParseAddressList(test.address)
assert.NoError(t, err)
})
}
}
type testCase struct {
id string
address string
category string
diagnosis string
}
func readTestCases(r io.Reader) chan testCase {
ch := make(chan testCase)
var (
test testCase
data string
)
go func() {
decoder := xml.NewDecoder(r)
for token, err := decoder.Token(); err == nil; token, err = decoder.Token() {
switch t := token.(type) {
case xml.StartElement:
if t.Name.Local == "test" {
test = testCase{
id: t.Attr[0].Value,
}
}
case xml.EndElement:
switch t.Name.Local {
case "test":
ch <- test
case "address":
test.address = data
case "category":
test.category = data
case "diagnosis":
test.diagnosis = data
}
case xml.CharData:
data = string(t)
}
}
close(ch)
}()
return ch
}

View File

@ -1,248 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestParseDateTime(t *testing.T) {
tests := []struct {
input string
want string
}{
{
input: `Fri, 21 Nov 1997 09:55:06`,
want: `1997-11-21T09:55:06Z`,
},
{
input: `Fri, 21 Nov 1997 09:55:06 -0600`,
want: `1997-11-21T09:55:06-06:00`,
},
{
input: `Tue, 1 Jul 2003 10:52:37 +0200`,
want: `2003-07-01T10:52:37+02:00`,
},
{
input: `Thu, 13 Feb 1969 23:32:54 -0330`,
want: `1969-02-13T23:32:54-03:30`,
},
{
input: "Thu, 13 Feb 1969 23:32 -0330 (Newfoundland Time)",
want: `1969-02-13T23:32:00-03:30`,
},
{
input: `2 Jan 2006 15:04:05 -0700`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `2 Jan 2006 15:04:05 MST`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `2 Jan 2006 15:04 -0700`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `2 Jan 2006 15:04 MST`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `2 Jan 06 15:04:05 -0700`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `2 Jan 06 15:04:05 MST`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `2 Jan 06 15:04 -0700`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `2 Jan 06 15:04 MST`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `02 Jan 2006 15:04:05 -0700`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `02 Jan 2006 15:04:05 MST`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `02 Jan 2006 15:04 -0700`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `02 Jan 2006 15:04 MST`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `02 Jan 06 15:04:05 -0700`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `02 Jan 06 15:04:05 MST`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `02 Jan 06 15:04 -0700`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `02 Jan 06 15:04 MST`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `Mon, 2 Jan 2006 15:04:05 -0700`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `Mon, 2 Jan 2006 15:04:05 MST`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `Mon, 2 Jan 2006 15:04 -0700`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `Mon, 2 Jan 2006 15:04 MST`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `Mon, 2 Jan 06 15:04:05 -0700`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `Mon, 2 Jan 06 15:04:05 MST`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `Mon, 2 Jan 06 15:04 -0700`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `Mon, 2 Jan 06 15:04 MST`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `Mon, 02 Jan 2006 15:04:05 -0700`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `Mon, 02 Jan 2006 15:04:05 MST`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `Mon, 02 Jan 2006 15:04 -0700`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `Mon, 02 Jan 2006 15:04 MST`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `Mon, 02 Jan 06 15:04:05 -0700`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `Mon, 02 Jan 06 15:04:05 MST`,
want: `2006-01-02T15:04:05-07:00`,
},
{
input: `Mon, 02 Jan 06 15:04 -0700`,
want: `2006-01-02T15:04:00-07:00`,
},
{
input: `Mon, 02 Jan 06 15:04 MST`,
want: `2006-01-02T15:04:00-07:00`,
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
got, err := ParseDateTime(test.input)
assert.NoError(t, err)
assert.Equal(t, test.want, got.Format(time.RFC3339))
})
}
}
func TestParseDateTimeObsolete(t *testing.T) {
tests := []struct {
input string
want string
}{
{
input: `21 Nov 97 09:55:06 GMT`,
want: `1997-11-21T09:55:06Z`,
},
{
input: `Wed, 01 Jan 2020 12:00:00 UTC`,
want: `2020-01-01T12:00:00Z`,
},
{
input: `Wed, 01 Jan 2020 13:00:00 UTC`,
want: `2020-01-01T13:00:00Z`,
},
{
input: `Wed, 01 Jan 2020 12:30:00 UTC`,
want: `2020-01-01T12:30:00Z`,
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
got, err := ParseDateTime(test.input)
assert.NoError(t, err)
assert.Equal(t, test.want, got.Format(time.RFC3339))
})
}
}
func TestParseDateTimeRelaxed(t *testing.T) {
tests := []struct {
input string
want string
}{
{
input: `Mon, 28 Jan 2019 20:59:01 0000`,
want: `2019-01-28T20:59:01Z`,
},
{
input: `Mon, 25 Sep 2017 5:25:40 +0200`,
want: `2017-09-25T05:25:40+02:00`,
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
got, err := ParseDateTime(test.input)
assert.NoError(t, err)
assert.Equal(t, test.want, got.Format(time.RFC3339))
})
}
}

View File

@ -1,83 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"net/mail"
"time"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/antlr/antlr4/runtime/Go/antlr"
"github.com/sirupsen/logrus"
)
// ParseAddressList parses one or more valid RFC5322 (with RFC2047) addresses.
func ParseAddressList(input string) ([]*mail.Address, error) {
if len(input) == 0 {
return []*mail.Address{}, nil
}
l := parser.NewRFC5322Lexer(antlr.NewInputStream(input))
p := parser.NewRFC5322Parser(antlr.NewCommonTokenStream(l, antlr.TokenDefaultChannel))
w := &walker{}
p.AddErrorListener(w)
p.AddParseListener(&parseListener{rules: p.GetRuleNames()})
antlr.ParseTreeWalkerDefault.Walk(w, p.AddressList())
return w.res.([]*mail.Address), w.err
}
// ParseDateTime parses a valid RFC5322 date-time.
func ParseDateTime(input string) (time.Time, error) {
if len(input) == 0 {
return time.Time{}, nil
}
l := parser.NewRFC5322Lexer(antlr.NewInputStream(input))
p := parser.NewRFC5322Parser(antlr.NewCommonTokenStream(l, antlr.TokenDefaultChannel))
w := &walker{}
p.AddErrorListener(w)
p.AddParseListener(&parseListener{rules: p.GetRuleNames()})
antlr.ParseTreeWalkerDefault.Walk(w, p.DateTime())
return w.res.(time.Time), w.err
}
type parseListener struct {
antlr.BaseParseTreeListener
rules []string
}
func (l *parseListener) EnterEveryRule(ctx antlr.ParserRuleContext) {
logrus.
WithField("rule", l.rules[ctx.GetRuleIndex()]).
WithField("text", ctx.GetText()).
Trace("Entering rule")
}
func (l *parseListener) ExitEveryRule(ctx antlr.ParserRuleContext) {
logrus.
WithField("rule", l.rules[ctx.GetRuleIndex()]).
WithField("text", ctx.GetText()).
Trace("Exiting rule")
}

File diff suppressed because one or more lines are too long

View File

@ -1,110 +0,0 @@
U_00=1
U_01_08=2
TAB=3
LF=4
U_0B=5
U_0C=6
CR=7
U_0E_1F=8
SP=9
Exclamation=10
DQuote=11
Hash=12
Dollar=13
Percent=14
Ampersand=15
SQuote=16
LParens=17
RParens=18
Asterisk=19
Plus=20
Comma=21
Minus=22
Period=23
Slash=24
Digit=25
Colon=26
Semicolon=27
Less=28
Equal=29
Greater=30
Question=31
At=32
LBracket=33
Backslash=34
RBracket=35
Caret=36
Underscore=37
Backtick=38
LCurly=39
Pipe=40
RCurly=41
Tilde=42
Delete=43
UTF8NonAscii=44
A=45
B=46
C=47
D=48
E=49
F=50
G=51
H=52
I=53
J=54
K=55
L=56
M=57
N=58
O=59
P=60
Q=61
R=62
S=63
T=64
U=65
V=66
W=67
X=68
Y=69
Z=70
'\u0000'=1
'\t'=3
'\n'=4
'\u000B'=5
'\u000C'=6
'\r'=7
' '=9
'!'=10
'"'=11
'#'=12
'$'=13
'%'=14
'&'=15
'\''=16
'('=17
')'=18
'*'=19
'+'=20
','=21
'-'=22
'.'=23
'/'=24
':'=26
';'=27
'<'=28
'='=29
'>'=30
'?'=31
'@'=32
'['=33
'\\'=34
']'=35
'^'=36
'_'=37
'`'=38
'{'=39
'|'=40
'}'=41
'~'=42
'\u007F'=43

File diff suppressed because one or more lines are too long

View File

@ -1,110 +0,0 @@
U_00=1
U_01_08=2
TAB=3
LF=4
U_0B=5
U_0C=6
CR=7
U_0E_1F=8
SP=9
Exclamation=10
DQuote=11
Hash=12
Dollar=13
Percent=14
Ampersand=15
SQuote=16
LParens=17
RParens=18
Asterisk=19
Plus=20
Comma=21
Minus=22
Period=23
Slash=24
Digit=25
Colon=26
Semicolon=27
Less=28
Equal=29
Greater=30
Question=31
At=32
LBracket=33
Backslash=34
RBracket=35
Caret=36
Underscore=37
Backtick=38
LCurly=39
Pipe=40
RCurly=41
Tilde=42
Delete=43
UTF8NonAscii=44
A=45
B=46
C=47
D=48
E=49
F=50
G=51
H=52
I=53
J=54
K=55
L=56
M=57
N=58
O=59
P=60
Q=61
R=62
S=63
T=64
U=65
V=66
W=67
X=68
Y=69
Z=70
'\u0000'=1
'\t'=3
'\n'=4
'\u000B'=5
'\u000C'=6
'\r'=7
' '=9
'!'=10
'"'=11
'#'=12
'$'=13
'%'=14
'&'=15
'\''=16
'('=17
')'=18
'*'=19
'+'=20
','=21
'-'=22
'.'=23
'/'=24
':'=26
';'=27
'<'=28
'='=29
'>'=30
'?'=31
'@'=32
'['=33
'\\'=34
']'=35
'^'=36
'_'=37
'`'=38
'{'=39
'|'=40
'}'=41
'~'=42
'\u007F'=43

View File

@ -1,309 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Code generated from RFC5322Lexer.g4 by ANTLR 4.8. DO NOT EDIT.
package parser
import (
"fmt"
"unicode"
"github.com/antlr/antlr4/runtime/Go/antlr"
)
// Suppress unused import error
var _ = fmt.Printf
var _ = unicode.IsLetter
var serializedLexerAtn = []uint16{
3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 72, 283,
8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7,
9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12,
4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4,
18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23,
9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9,
28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33,
4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4,
39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44,
9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9,
49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54,
4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4,
60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65,
9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9,
70, 4, 71, 9, 71, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6,
3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3,
12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17,
3, 17, 3, 18, 3, 18, 3, 19, 3, 19, 3, 20, 3, 20, 3, 21, 3, 21, 3, 22, 3,
22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 27, 3, 27,
3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 31, 3, 31, 3, 32, 3, 32, 3,
33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38,
3, 38, 3, 39, 3, 39, 3, 40, 3, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 43, 3,
43, 3, 44, 3, 44, 3, 45, 3, 45, 3, 46, 3, 46, 3, 47, 3, 47, 3, 48, 3, 48,
3, 49, 3, 49, 3, 50, 3, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3,
54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59,
3, 59, 3, 60, 3, 60, 3, 61, 3, 61, 3, 62, 3, 62, 3, 63, 3, 63, 3, 64, 3,
64, 3, 65, 3, 65, 3, 66, 3, 66, 3, 67, 3, 67, 3, 68, 3, 68, 3, 69, 3, 69,
3, 70, 3, 70, 3, 71, 3, 71, 2, 2, 72, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13,
8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17,
33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26,
51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35,
69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 44,
87, 45, 89, 46, 91, 47, 93, 48, 95, 49, 97, 50, 99, 51, 101, 52, 103, 53,
105, 54, 107, 55, 109, 56, 111, 57, 113, 58, 115, 59, 117, 60, 119, 61,
121, 62, 123, 63, 125, 64, 127, 65, 129, 66, 131, 67, 133, 68, 135, 69,
137, 70, 139, 71, 141, 72, 3, 2, 29, 3, 2, 50, 59, 4, 2, 67, 67, 99, 99,
4, 2, 68, 68, 100, 100, 4, 2, 69, 69, 101, 101, 4, 2, 70, 70, 102, 102,
4, 2, 71, 71, 103, 103, 4, 2, 72, 72, 104, 104, 4, 2, 73, 73, 105, 105,
4, 2, 74, 74, 106, 106, 4, 2, 75, 75, 107, 107, 4, 2, 76, 76, 108, 108,
4, 2, 77, 77, 109, 109, 4, 2, 78, 78, 110, 110, 4, 2, 79, 79, 111, 111,
4, 2, 80, 80, 112, 112, 4, 2, 81, 81, 113, 113, 4, 2, 82, 82, 114, 114,
4, 2, 83, 83, 115, 115, 4, 2, 84, 84, 116, 116, 4, 2, 85, 85, 117, 117,
4, 2, 86, 86, 118, 118, 4, 2, 87, 87, 119, 119, 4, 2, 88, 88, 120, 120,
4, 2, 89, 89, 121, 121, 4, 2, 90, 90, 122, 122, 4, 2, 91, 91, 123, 123,
4, 2, 92, 92, 124, 124, 2, 282, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2,
7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2,
2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2,
2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2,
2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3,
2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45,
3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2,
53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2,
2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2,
2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2,
2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3,
2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91,
3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 95, 3, 2, 2, 2, 2, 97, 3, 2, 2, 2, 2,
99, 3, 2, 2, 2, 2, 101, 3, 2, 2, 2, 2, 103, 3, 2, 2, 2, 2, 105, 3, 2, 2,
2, 2, 107, 3, 2, 2, 2, 2, 109, 3, 2, 2, 2, 2, 111, 3, 2, 2, 2, 2, 113,
3, 2, 2, 2, 2, 115, 3, 2, 2, 2, 2, 117, 3, 2, 2, 2, 2, 119, 3, 2, 2, 2,
2, 121, 3, 2, 2, 2, 2, 123, 3, 2, 2, 2, 2, 125, 3, 2, 2, 2, 2, 127, 3,
2, 2, 2, 2, 129, 3, 2, 2, 2, 2, 131, 3, 2, 2, 2, 2, 133, 3, 2, 2, 2, 2,
135, 3, 2, 2, 2, 2, 137, 3, 2, 2, 2, 2, 139, 3, 2, 2, 2, 2, 141, 3, 2,
2, 2, 3, 143, 3, 2, 2, 2, 5, 145, 3, 2, 2, 2, 7, 147, 3, 2, 2, 2, 9, 149,
3, 2, 2, 2, 11, 151, 3, 2, 2, 2, 13, 153, 3, 2, 2, 2, 15, 155, 3, 2, 2,
2, 17, 157, 3, 2, 2, 2, 19, 159, 3, 2, 2, 2, 21, 161, 3, 2, 2, 2, 23, 163,
3, 2, 2, 2, 25, 165, 3, 2, 2, 2, 27, 167, 3, 2, 2, 2, 29, 169, 3, 2, 2,
2, 31, 171, 3, 2, 2, 2, 33, 173, 3, 2, 2, 2, 35, 175, 3, 2, 2, 2, 37, 177,
3, 2, 2, 2, 39, 179, 3, 2, 2, 2, 41, 181, 3, 2, 2, 2, 43, 183, 3, 2, 2,
2, 45, 185, 3, 2, 2, 2, 47, 187, 3, 2, 2, 2, 49, 189, 3, 2, 2, 2, 51, 191,
3, 2, 2, 2, 53, 193, 3, 2, 2, 2, 55, 195, 3, 2, 2, 2, 57, 197, 3, 2, 2,
2, 59, 199, 3, 2, 2, 2, 61, 201, 3, 2, 2, 2, 63, 203, 3, 2, 2, 2, 65, 205,
3, 2, 2, 2, 67, 207, 3, 2, 2, 2, 69, 209, 3, 2, 2, 2, 71, 211, 3, 2, 2,
2, 73, 213, 3, 2, 2, 2, 75, 215, 3, 2, 2, 2, 77, 217, 3, 2, 2, 2, 79, 219,
3, 2, 2, 2, 81, 221, 3, 2, 2, 2, 83, 223, 3, 2, 2, 2, 85, 225, 3, 2, 2,
2, 87, 227, 3, 2, 2, 2, 89, 229, 3, 2, 2, 2, 91, 231, 3, 2, 2, 2, 93, 233,
3, 2, 2, 2, 95, 235, 3, 2, 2, 2, 97, 237, 3, 2, 2, 2, 99, 239, 3, 2, 2,
2, 101, 241, 3, 2, 2, 2, 103, 243, 3, 2, 2, 2, 105, 245, 3, 2, 2, 2, 107,
247, 3, 2, 2, 2, 109, 249, 3, 2, 2, 2, 111, 251, 3, 2, 2, 2, 113, 253,
3, 2, 2, 2, 115, 255, 3, 2, 2, 2, 117, 257, 3, 2, 2, 2, 119, 259, 3, 2,
2, 2, 121, 261, 3, 2, 2, 2, 123, 263, 3, 2, 2, 2, 125, 265, 3, 2, 2, 2,
127, 267, 3, 2, 2, 2, 129, 269, 3, 2, 2, 2, 131, 271, 3, 2, 2, 2, 133,
273, 3, 2, 2, 2, 135, 275, 3, 2, 2, 2, 137, 277, 3, 2, 2, 2, 139, 279,
3, 2, 2, 2, 141, 281, 3, 2, 2, 2, 143, 144, 7, 2, 2, 2, 144, 4, 3, 2, 2,
2, 145, 146, 4, 3, 10, 2, 146, 6, 3, 2, 2, 2, 147, 148, 7, 11, 2, 2, 148,
8, 3, 2, 2, 2, 149, 150, 7, 12, 2, 2, 150, 10, 3, 2, 2, 2, 151, 152, 7,
13, 2, 2, 152, 12, 3, 2, 2, 2, 153, 154, 7, 14, 2, 2, 154, 14, 3, 2, 2,
2, 155, 156, 7, 15, 2, 2, 156, 16, 3, 2, 2, 2, 157, 158, 4, 16, 33, 2,
158, 18, 3, 2, 2, 2, 159, 160, 7, 34, 2, 2, 160, 20, 3, 2, 2, 2, 161, 162,
7, 35, 2, 2, 162, 22, 3, 2, 2, 2, 163, 164, 7, 36, 2, 2, 164, 24, 3, 2,
2, 2, 165, 166, 7, 37, 2, 2, 166, 26, 3, 2, 2, 2, 167, 168, 7, 38, 2, 2,
168, 28, 3, 2, 2, 2, 169, 170, 7, 39, 2, 2, 170, 30, 3, 2, 2, 2, 171, 172,
7, 40, 2, 2, 172, 32, 3, 2, 2, 2, 173, 174, 7, 41, 2, 2, 174, 34, 3, 2,
2, 2, 175, 176, 7, 42, 2, 2, 176, 36, 3, 2, 2, 2, 177, 178, 7, 43, 2, 2,
178, 38, 3, 2, 2, 2, 179, 180, 7, 44, 2, 2, 180, 40, 3, 2, 2, 2, 181, 182,
7, 45, 2, 2, 182, 42, 3, 2, 2, 2, 183, 184, 7, 46, 2, 2, 184, 44, 3, 2,
2, 2, 185, 186, 7, 47, 2, 2, 186, 46, 3, 2, 2, 2, 187, 188, 7, 48, 2, 2,
188, 48, 3, 2, 2, 2, 189, 190, 7, 49, 2, 2, 190, 50, 3, 2, 2, 2, 191, 192,
9, 2, 2, 2, 192, 52, 3, 2, 2, 2, 193, 194, 7, 60, 2, 2, 194, 54, 3, 2,
2, 2, 195, 196, 7, 61, 2, 2, 196, 56, 3, 2, 2, 2, 197, 198, 7, 62, 2, 2,
198, 58, 3, 2, 2, 2, 199, 200, 7, 63, 2, 2, 200, 60, 3, 2, 2, 2, 201, 202,
7, 64, 2, 2, 202, 62, 3, 2, 2, 2, 203, 204, 7, 65, 2, 2, 204, 64, 3, 2,
2, 2, 205, 206, 7, 66, 2, 2, 206, 66, 3, 2, 2, 2, 207, 208, 7, 93, 2, 2,
208, 68, 3, 2, 2, 2, 209, 210, 7, 94, 2, 2, 210, 70, 3, 2, 2, 2, 211, 212,
7, 95, 2, 2, 212, 72, 3, 2, 2, 2, 213, 214, 7, 96, 2, 2, 214, 74, 3, 2,
2, 2, 215, 216, 7, 97, 2, 2, 216, 76, 3, 2, 2, 2, 217, 218, 7, 98, 2, 2,
218, 78, 3, 2, 2, 2, 219, 220, 7, 125, 2, 2, 220, 80, 3, 2, 2, 2, 221,
222, 7, 126, 2, 2, 222, 82, 3, 2, 2, 2, 223, 224, 7, 127, 2, 2, 224, 84,
3, 2, 2, 2, 225, 226, 7, 128, 2, 2, 226, 86, 3, 2, 2, 2, 227, 228, 7, 129,
2, 2, 228, 88, 3, 2, 2, 2, 229, 230, 4, 130, 1, 2, 230, 90, 3, 2, 2, 2,
231, 232, 9, 3, 2, 2, 232, 92, 3, 2, 2, 2, 233, 234, 9, 4, 2, 2, 234, 94,
3, 2, 2, 2, 235, 236, 9, 5, 2, 2, 236, 96, 3, 2, 2, 2, 237, 238, 9, 6,
2, 2, 238, 98, 3, 2, 2, 2, 239, 240, 9, 7, 2, 2, 240, 100, 3, 2, 2, 2,
241, 242, 9, 8, 2, 2, 242, 102, 3, 2, 2, 2, 243, 244, 9, 9, 2, 2, 244,
104, 3, 2, 2, 2, 245, 246, 9, 10, 2, 2, 246, 106, 3, 2, 2, 2, 247, 248,
9, 11, 2, 2, 248, 108, 3, 2, 2, 2, 249, 250, 9, 12, 2, 2, 250, 110, 3,
2, 2, 2, 251, 252, 9, 13, 2, 2, 252, 112, 3, 2, 2, 2, 253, 254, 9, 14,
2, 2, 254, 114, 3, 2, 2, 2, 255, 256, 9, 15, 2, 2, 256, 116, 3, 2, 2, 2,
257, 258, 9, 16, 2, 2, 258, 118, 3, 2, 2, 2, 259, 260, 9, 17, 2, 2, 260,
120, 3, 2, 2, 2, 261, 262, 9, 18, 2, 2, 262, 122, 3, 2, 2, 2, 263, 264,
9, 19, 2, 2, 264, 124, 3, 2, 2, 2, 265, 266, 9, 20, 2, 2, 266, 126, 3,
2, 2, 2, 267, 268, 9, 21, 2, 2, 268, 128, 3, 2, 2, 2, 269, 270, 9, 22,
2, 2, 270, 130, 3, 2, 2, 2, 271, 272, 9, 23, 2, 2, 272, 132, 3, 2, 2, 2,
273, 274, 9, 24, 2, 2, 274, 134, 3, 2, 2, 2, 275, 276, 9, 25, 2, 2, 276,
136, 3, 2, 2, 2, 277, 278, 9, 26, 2, 2, 278, 138, 3, 2, 2, 2, 279, 280,
9, 27, 2, 2, 280, 140, 3, 2, 2, 2, 281, 282, 9, 28, 2, 2, 282, 142, 3,
2, 2, 2, 3, 2, 2,
}
var lexerDeserializer = antlr.NewATNDeserializer(nil)
var lexerAtn = lexerDeserializer.DeserializeFromUInt16(serializedLexerAtn)
var lexerChannelNames = []string{
"DEFAULT_TOKEN_CHANNEL", "HIDDEN",
}
var lexerModeNames = []string{
"DEFAULT_MODE",
}
var lexerLiteralNames = []string{
"", "'\u0000'", "", "'\t'", "'\n'", "'\u000B'", "'\u000C'", "'\r'", "",
"' '", "'!'", "'\"'", "'#'", "'$'", "'%'", "'&'", "'''", "'('", "')'",
"'*'", "'+'", "','", "'-'", "'.'", "'/'", "", "':'", "';'", "'<'", "'='",
"'>'", "'?'", "'@'", "'['", "'\\'", "']'", "'^'", "'_'", "'`'", "'{'",
"'|'", "'}'", "'~'", "'\u007F'",
}
var lexerSymbolicNames = []string{
"", "U_00", "U_01_08", "TAB", "LF", "U_0B", "U_0C", "CR", "U_0E_1F", "SP",
"Exclamation", "DQuote", "Hash", "Dollar", "Percent", "Ampersand", "SQuote",
"LParens", "RParens", "Asterisk", "Plus", "Comma", "Minus", "Period", "Slash",
"Digit", "Colon", "Semicolon", "Less", "Equal", "Greater", "Question",
"At", "LBracket", "Backslash", "RBracket", "Caret", "Underscore", "Backtick",
"LCurly", "Pipe", "RCurly", "Tilde", "Delete", "UTF8NonAscii", "A", "B",
"C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
"R", "S", "T", "U", "V", "W", "X", "Y", "Z",
}
var lexerRuleNames = []string{
"U_00", "U_01_08", "TAB", "LF", "U_0B", "U_0C", "CR", "U_0E_1F", "SP",
"Exclamation", "DQuote", "Hash", "Dollar", "Percent", "Ampersand", "SQuote",
"LParens", "RParens", "Asterisk", "Plus", "Comma", "Minus", "Period", "Slash",
"Digit", "Colon", "Semicolon", "Less", "Equal", "Greater", "Question",
"At", "LBracket", "Backslash", "RBracket", "Caret", "Underscore", "Backtick",
"LCurly", "Pipe", "RCurly", "Tilde", "Delete", "UTF8NonAscii", "A", "B",
"C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
"R", "S", "T", "U", "V", "W", "X", "Y", "Z",
}
type RFC5322Lexer struct {
*antlr.BaseLexer
channelNames []string
modeNames []string
// TODO: EOF string
}
var lexerDecisionToDFA = make([]*antlr.DFA, len(lexerAtn.DecisionToState))
func init() {
for index, ds := range lexerAtn.DecisionToState {
lexerDecisionToDFA[index] = antlr.NewDFA(ds, index)
}
}
func NewRFC5322Lexer(input antlr.CharStream) *RFC5322Lexer {
l := new(RFC5322Lexer)
l.BaseLexer = antlr.NewBaseLexer(input)
l.Interpreter = antlr.NewLexerATNSimulator(l, lexerAtn, lexerDecisionToDFA, antlr.NewPredictionContextCache())
l.channelNames = lexerChannelNames
l.modeNames = lexerModeNames
l.RuleNames = lexerRuleNames
l.LiteralNames = lexerLiteralNames
l.SymbolicNames = lexerSymbolicNames
l.GrammarFileName = "RFC5322Lexer.g4"
// TODO: l.EOF = antlr.TokenEOF
return l
}
// RFC5322Lexer tokens.
const (
RFC5322LexerU_00 = 1
RFC5322LexerU_01_08 = 2
RFC5322LexerTAB = 3
RFC5322LexerLF = 4
RFC5322LexerU_0B = 5
RFC5322LexerU_0C = 6
RFC5322LexerCR = 7
RFC5322LexerU_0E_1F = 8
RFC5322LexerSP = 9
RFC5322LexerExclamation = 10
RFC5322LexerDQuote = 11
RFC5322LexerHash = 12
RFC5322LexerDollar = 13
RFC5322LexerPercent = 14
RFC5322LexerAmpersand = 15
RFC5322LexerSQuote = 16
RFC5322LexerLParens = 17
RFC5322LexerRParens = 18
RFC5322LexerAsterisk = 19
RFC5322LexerPlus = 20
RFC5322LexerComma = 21
RFC5322LexerMinus = 22
RFC5322LexerPeriod = 23
RFC5322LexerSlash = 24
RFC5322LexerDigit = 25
RFC5322LexerColon = 26
RFC5322LexerSemicolon = 27
RFC5322LexerLess = 28
RFC5322LexerEqual = 29
RFC5322LexerGreater = 30
RFC5322LexerQuestion = 31
RFC5322LexerAt = 32
RFC5322LexerLBracket = 33
RFC5322LexerBackslash = 34
RFC5322LexerRBracket = 35
RFC5322LexerCaret = 36
RFC5322LexerUnderscore = 37
RFC5322LexerBacktick = 38
RFC5322LexerLCurly = 39
RFC5322LexerPipe = 40
RFC5322LexerRCurly = 41
RFC5322LexerTilde = 42
RFC5322LexerDelete = 43
RFC5322LexerUTF8NonAscii = 44
RFC5322LexerA = 45
RFC5322LexerB = 46
RFC5322LexerC = 47
RFC5322LexerD = 48
RFC5322LexerE = 49
RFC5322LexerF = 50
RFC5322LexerG = 51
RFC5322LexerH = 52
RFC5322LexerI = 53
RFC5322LexerJ = 54
RFC5322LexerK = 55
RFC5322LexerL = 56
RFC5322LexerM = 57
RFC5322LexerN = 58
RFC5322LexerO = 59
RFC5322LexerP = 60
RFC5322LexerQ = 61
RFC5322LexerR = 62
RFC5322LexerS = 63
RFC5322LexerT = 64
RFC5322LexerU = 65
RFC5322LexerV = 66
RFC5322LexerW = 67
RFC5322LexerX = 68
RFC5322LexerY = 69
RFC5322LexerZ = 70
)

File diff suppressed because it is too large Load Diff

View File

@ -1,435 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Code generated from RFC5322Parser.g4 by ANTLR 4.8. DO NOT EDIT.
package parser // RFC5322Parser
import "github.com/antlr/antlr4/runtime/Go/antlr"
// BaseRFC5322ParserListener is a complete listener for a parse tree produced by RFC5322Parser.
type BaseRFC5322ParserListener struct{}
var _ RFC5322ParserListener = &BaseRFC5322ParserListener{}
// VisitTerminal is called when a terminal node is visited.
func (s *BaseRFC5322ParserListener) VisitTerminal(node antlr.TerminalNode) {}
// VisitErrorNode is called when an error node is visited.
func (s *BaseRFC5322ParserListener) VisitErrorNode(node antlr.ErrorNode) {}
// EnterEveryRule is called when any rule is entered.
func (s *BaseRFC5322ParserListener) EnterEveryRule(ctx antlr.ParserRuleContext) {}
// ExitEveryRule is called when any rule is exited.
func (s *BaseRFC5322ParserListener) ExitEveryRule(ctx antlr.ParserRuleContext) {}
// EnterQuotedChar is called when production quotedChar is entered.
func (s *BaseRFC5322ParserListener) EnterQuotedChar(ctx *QuotedCharContext) {}
// ExitQuotedChar is called when production quotedChar is exited.
func (s *BaseRFC5322ParserListener) ExitQuotedChar(ctx *QuotedCharContext) {}
// EnterQuotedPair is called when production quotedPair is entered.
func (s *BaseRFC5322ParserListener) EnterQuotedPair(ctx *QuotedPairContext) {}
// ExitQuotedPair is called when production quotedPair is exited.
func (s *BaseRFC5322ParserListener) ExitQuotedPair(ctx *QuotedPairContext) {}
// EnterFws is called when production fws is entered.
func (s *BaseRFC5322ParserListener) EnterFws(ctx *FwsContext) {}
// ExitFws is called when production fws is exited.
func (s *BaseRFC5322ParserListener) ExitFws(ctx *FwsContext) {}
// EnterCtext is called when production ctext is entered.
func (s *BaseRFC5322ParserListener) EnterCtext(ctx *CtextContext) {}
// ExitCtext is called when production ctext is exited.
func (s *BaseRFC5322ParserListener) ExitCtext(ctx *CtextContext) {}
// EnterCcontent is called when production ccontent is entered.
func (s *BaseRFC5322ParserListener) EnterCcontent(ctx *CcontentContext) {}
// ExitCcontent is called when production ccontent is exited.
func (s *BaseRFC5322ParserListener) ExitCcontent(ctx *CcontentContext) {}
// EnterComment is called when production comment is entered.
func (s *BaseRFC5322ParserListener) EnterComment(ctx *CommentContext) {}
// ExitComment is called when production comment is exited.
func (s *BaseRFC5322ParserListener) ExitComment(ctx *CommentContext) {}
// EnterCfws is called when production cfws is entered.
func (s *BaseRFC5322ParserListener) EnterCfws(ctx *CfwsContext) {}
// ExitCfws is called when production cfws is exited.
func (s *BaseRFC5322ParserListener) ExitCfws(ctx *CfwsContext) {}
// EnterAtext is called when production atext is entered.
func (s *BaseRFC5322ParserListener) EnterAtext(ctx *AtextContext) {}
// ExitAtext is called when production atext is exited.
func (s *BaseRFC5322ParserListener) ExitAtext(ctx *AtextContext) {}
// EnterAtom is called when production atom is entered.
func (s *BaseRFC5322ParserListener) EnterAtom(ctx *AtomContext) {}
// ExitAtom is called when production atom is exited.
func (s *BaseRFC5322ParserListener) ExitAtom(ctx *AtomContext) {}
// EnterDotAtom is called when production dotAtom is entered.
func (s *BaseRFC5322ParserListener) EnterDotAtom(ctx *DotAtomContext) {}
// ExitDotAtom is called when production dotAtom is exited.
func (s *BaseRFC5322ParserListener) ExitDotAtom(ctx *DotAtomContext) {}
// EnterQtext is called when production qtext is entered.
func (s *BaseRFC5322ParserListener) EnterQtext(ctx *QtextContext) {}
// ExitQtext is called when production qtext is exited.
func (s *BaseRFC5322ParserListener) ExitQtext(ctx *QtextContext) {}
// EnterQuotedContent is called when production quotedContent is entered.
func (s *BaseRFC5322ParserListener) EnterQuotedContent(ctx *QuotedContentContext) {}
// ExitQuotedContent is called when production quotedContent is exited.
func (s *BaseRFC5322ParserListener) ExitQuotedContent(ctx *QuotedContentContext) {}
// EnterQuotedValue is called when production quotedValue is entered.
func (s *BaseRFC5322ParserListener) EnterQuotedValue(ctx *QuotedValueContext) {}
// ExitQuotedValue is called when production quotedValue is exited.
func (s *BaseRFC5322ParserListener) ExitQuotedValue(ctx *QuotedValueContext) {}
// EnterQuotedString is called when production quotedString is entered.
func (s *BaseRFC5322ParserListener) EnterQuotedString(ctx *QuotedStringContext) {}
// ExitQuotedString is called when production quotedString is exited.
func (s *BaseRFC5322ParserListener) ExitQuotedString(ctx *QuotedStringContext) {}
// EnterWord is called when production word is entered.
func (s *BaseRFC5322ParserListener) EnterWord(ctx *WordContext) {}
// ExitWord is called when production word is exited.
func (s *BaseRFC5322ParserListener) ExitWord(ctx *WordContext) {}
// EnterDateTime is called when production dateTime is entered.
func (s *BaseRFC5322ParserListener) EnterDateTime(ctx *DateTimeContext) {}
// ExitDateTime is called when production dateTime is exited.
func (s *BaseRFC5322ParserListener) ExitDateTime(ctx *DateTimeContext) {}
// EnterDayOfweek is called when production dayOfweek is entered.
func (s *BaseRFC5322ParserListener) EnterDayOfweek(ctx *DayOfweekContext) {}
// ExitDayOfweek is called when production dayOfweek is exited.
func (s *BaseRFC5322ParserListener) ExitDayOfweek(ctx *DayOfweekContext) {}
// EnterDayName is called when production dayName is entered.
func (s *BaseRFC5322ParserListener) EnterDayName(ctx *DayNameContext) {}
// ExitDayName is called when production dayName is exited.
func (s *BaseRFC5322ParserListener) ExitDayName(ctx *DayNameContext) {}
// EnterDay is called when production day is entered.
func (s *BaseRFC5322ParserListener) EnterDay(ctx *DayContext) {}
// ExitDay is called when production day is exited.
func (s *BaseRFC5322ParserListener) ExitDay(ctx *DayContext) {}
// EnterMonth is called when production month is entered.
func (s *BaseRFC5322ParserListener) EnterMonth(ctx *MonthContext) {}
// ExitMonth is called when production month is exited.
func (s *BaseRFC5322ParserListener) ExitMonth(ctx *MonthContext) {}
// EnterYear is called when production year is entered.
func (s *BaseRFC5322ParserListener) EnterYear(ctx *YearContext) {}
// ExitYear is called when production year is exited.
func (s *BaseRFC5322ParserListener) ExitYear(ctx *YearContext) {}
// EnterHour is called when production hour is entered.
func (s *BaseRFC5322ParserListener) EnterHour(ctx *HourContext) {}
// ExitHour is called when production hour is exited.
func (s *BaseRFC5322ParserListener) ExitHour(ctx *HourContext) {}
// EnterMinute is called when production minute is entered.
func (s *BaseRFC5322ParserListener) EnterMinute(ctx *MinuteContext) {}
// ExitMinute is called when production minute is exited.
func (s *BaseRFC5322ParserListener) ExitMinute(ctx *MinuteContext) {}
// EnterSecond is called when production second is entered.
func (s *BaseRFC5322ParserListener) EnterSecond(ctx *SecondContext) {}
// ExitSecond is called when production second is exited.
func (s *BaseRFC5322ParserListener) ExitSecond(ctx *SecondContext) {}
// EnterOffset is called when production offset is entered.
func (s *BaseRFC5322ParserListener) EnterOffset(ctx *OffsetContext) {}
// ExitOffset is called when production offset is exited.
func (s *BaseRFC5322ParserListener) ExitOffset(ctx *OffsetContext) {}
// EnterZone is called when production zone is entered.
func (s *BaseRFC5322ParserListener) EnterZone(ctx *ZoneContext) {}
// ExitZone is called when production zone is exited.
func (s *BaseRFC5322ParserListener) ExitZone(ctx *ZoneContext) {}
// EnterAddress is called when production address is entered.
func (s *BaseRFC5322ParserListener) EnterAddress(ctx *AddressContext) {}
// ExitAddress is called when production address is exited.
func (s *BaseRFC5322ParserListener) ExitAddress(ctx *AddressContext) {}
// EnterMailbox is called when production mailbox is entered.
func (s *BaseRFC5322ParserListener) EnterMailbox(ctx *MailboxContext) {}
// ExitMailbox is called when production mailbox is exited.
func (s *BaseRFC5322ParserListener) ExitMailbox(ctx *MailboxContext) {}
// EnterNameAddr is called when production nameAddr is entered.
func (s *BaseRFC5322ParserListener) EnterNameAddr(ctx *NameAddrContext) {}
// ExitNameAddr is called when production nameAddr is exited.
func (s *BaseRFC5322ParserListener) ExitNameAddr(ctx *NameAddrContext) {}
// EnterAngleAddr is called when production angleAddr is entered.
func (s *BaseRFC5322ParserListener) EnterAngleAddr(ctx *AngleAddrContext) {}
// ExitAngleAddr is called when production angleAddr is exited.
func (s *BaseRFC5322ParserListener) ExitAngleAddr(ctx *AngleAddrContext) {}
// EnterGroup is called when production group is entered.
func (s *BaseRFC5322ParserListener) EnterGroup(ctx *GroupContext) {}
// ExitGroup is called when production group is exited.
func (s *BaseRFC5322ParserListener) ExitGroup(ctx *GroupContext) {}
// EnterDisplayName is called when production displayName is entered.
func (s *BaseRFC5322ParserListener) EnterDisplayName(ctx *DisplayNameContext) {}
// ExitDisplayName is called when production displayName is exited.
func (s *BaseRFC5322ParserListener) ExitDisplayName(ctx *DisplayNameContext) {}
// EnterMailboxList is called when production mailboxList is entered.
func (s *BaseRFC5322ParserListener) EnterMailboxList(ctx *MailboxListContext) {}
// ExitMailboxList is called when production mailboxList is exited.
func (s *BaseRFC5322ParserListener) ExitMailboxList(ctx *MailboxListContext) {}
// EnterAddressList is called when production addressList is entered.
func (s *BaseRFC5322ParserListener) EnterAddressList(ctx *AddressListContext) {}
// ExitAddressList is called when production addressList is exited.
func (s *BaseRFC5322ParserListener) ExitAddressList(ctx *AddressListContext) {}
// EnterGroupList is called when production groupList is entered.
func (s *BaseRFC5322ParserListener) EnterGroupList(ctx *GroupListContext) {}
// ExitGroupList is called when production groupList is exited.
func (s *BaseRFC5322ParserListener) ExitGroupList(ctx *GroupListContext) {}
// EnterAddrSpec is called when production addrSpec is entered.
func (s *BaseRFC5322ParserListener) EnterAddrSpec(ctx *AddrSpecContext) {}
// ExitAddrSpec is called when production addrSpec is exited.
func (s *BaseRFC5322ParserListener) ExitAddrSpec(ctx *AddrSpecContext) {}
// EnterLocalPart is called when production localPart is entered.
func (s *BaseRFC5322ParserListener) EnterLocalPart(ctx *LocalPartContext) {}
// ExitLocalPart is called when production localPart is exited.
func (s *BaseRFC5322ParserListener) ExitLocalPart(ctx *LocalPartContext) {}
// EnterPort is called when production port is entered.
func (s *BaseRFC5322ParserListener) EnterPort(ctx *PortContext) {}
// ExitPort is called when production port is exited.
func (s *BaseRFC5322ParserListener) ExitPort(ctx *PortContext) {}
// EnterDomain is called when production domain is entered.
func (s *BaseRFC5322ParserListener) EnterDomain(ctx *DomainContext) {}
// ExitDomain is called when production domain is exited.
func (s *BaseRFC5322ParserListener) ExitDomain(ctx *DomainContext) {}
// EnterDomainLiteral is called when production domainLiteral is entered.
func (s *BaseRFC5322ParserListener) EnterDomainLiteral(ctx *DomainLiteralContext) {}
// ExitDomainLiteral is called when production domainLiteral is exited.
func (s *BaseRFC5322ParserListener) ExitDomainLiteral(ctx *DomainLiteralContext) {}
// EnterDtext is called when production dtext is entered.
func (s *BaseRFC5322ParserListener) EnterDtext(ctx *DtextContext) {}
// ExitDtext is called when production dtext is exited.
func (s *BaseRFC5322ParserListener) ExitDtext(ctx *DtextContext) {}
// EnterObsNoWSCTL is called when production obsNoWSCTL is entered.
func (s *BaseRFC5322ParserListener) EnterObsNoWSCTL(ctx *ObsNoWSCTLContext) {}
// ExitObsNoWSCTL is called when production obsNoWSCTL is exited.
func (s *BaseRFC5322ParserListener) ExitObsNoWSCTL(ctx *ObsNoWSCTLContext) {}
// EnterObsCtext is called when production obsCtext is entered.
func (s *BaseRFC5322ParserListener) EnterObsCtext(ctx *ObsCtextContext) {}
// ExitObsCtext is called when production obsCtext is exited.
func (s *BaseRFC5322ParserListener) ExitObsCtext(ctx *ObsCtextContext) {}
// EnterObsQtext is called when production obsQtext is entered.
func (s *BaseRFC5322ParserListener) EnterObsQtext(ctx *ObsQtextContext) {}
// ExitObsQtext is called when production obsQtext is exited.
func (s *BaseRFC5322ParserListener) ExitObsQtext(ctx *ObsQtextContext) {}
// EnterObsQP is called when production obsQP is entered.
func (s *BaseRFC5322ParserListener) EnterObsQP(ctx *ObsQPContext) {}
// ExitObsQP is called when production obsQP is exited.
func (s *BaseRFC5322ParserListener) ExitObsQP(ctx *ObsQPContext) {}
// EnterObsFWS is called when production obsFWS is entered.
func (s *BaseRFC5322ParserListener) EnterObsFWS(ctx *ObsFWSContext) {}
// ExitObsFWS is called when production obsFWS is exited.
func (s *BaseRFC5322ParserListener) ExitObsFWS(ctx *ObsFWSContext) {}
// EnterObsZone is called when production obsZone is entered.
func (s *BaseRFC5322ParserListener) EnterObsZone(ctx *ObsZoneContext) {}
// ExitObsZone is called when production obsZone is exited.
func (s *BaseRFC5322ParserListener) ExitObsZone(ctx *ObsZoneContext) {}
// EnterObsAngleAddr is called when production obsAngleAddr is entered.
func (s *BaseRFC5322ParserListener) EnterObsAngleAddr(ctx *ObsAngleAddrContext) {}
// ExitObsAngleAddr is called when production obsAngleAddr is exited.
func (s *BaseRFC5322ParserListener) ExitObsAngleAddr(ctx *ObsAngleAddrContext) {}
// EnterObsRoute is called when production obsRoute is entered.
func (s *BaseRFC5322ParserListener) EnterObsRoute(ctx *ObsRouteContext) {}
// ExitObsRoute is called when production obsRoute is exited.
func (s *BaseRFC5322ParserListener) ExitObsRoute(ctx *ObsRouteContext) {}
// EnterObsDomainList is called when production obsDomainList is entered.
func (s *BaseRFC5322ParserListener) EnterObsDomainList(ctx *ObsDomainListContext) {}
// ExitObsDomainList is called when production obsDomainList is exited.
func (s *BaseRFC5322ParserListener) ExitObsDomainList(ctx *ObsDomainListContext) {}
// EnterObsMboxList is called when production obsMboxList is entered.
func (s *BaseRFC5322ParserListener) EnterObsMboxList(ctx *ObsMboxListContext) {}
// ExitObsMboxList is called when production obsMboxList is exited.
func (s *BaseRFC5322ParserListener) ExitObsMboxList(ctx *ObsMboxListContext) {}
// EnterObsAddrList is called when production obsAddrList is entered.
func (s *BaseRFC5322ParserListener) EnterObsAddrList(ctx *ObsAddrListContext) {}
// ExitObsAddrList is called when production obsAddrList is exited.
func (s *BaseRFC5322ParserListener) ExitObsAddrList(ctx *ObsAddrListContext) {}
// EnterObsGroupList is called when production obsGroupList is entered.
func (s *BaseRFC5322ParserListener) EnterObsGroupList(ctx *ObsGroupListContext) {}
// ExitObsGroupList is called when production obsGroupList is exited.
func (s *BaseRFC5322ParserListener) ExitObsGroupList(ctx *ObsGroupListContext) {}
// EnterObsLocalPart is called when production obsLocalPart is entered.
func (s *BaseRFC5322ParserListener) EnterObsLocalPart(ctx *ObsLocalPartContext) {}
// ExitObsLocalPart is called when production obsLocalPart is exited.
func (s *BaseRFC5322ParserListener) ExitObsLocalPart(ctx *ObsLocalPartContext) {}
// EnterObsDomain is called when production obsDomain is entered.
func (s *BaseRFC5322ParserListener) EnterObsDomain(ctx *ObsDomainContext) {}
// ExitObsDomain is called when production obsDomain is exited.
func (s *BaseRFC5322ParserListener) ExitObsDomain(ctx *ObsDomainContext) {}
// EnterEncodedWord is called when production encodedWord is entered.
func (s *BaseRFC5322ParserListener) EnterEncodedWord(ctx *EncodedWordContext) {}
// ExitEncodedWord is called when production encodedWord is exited.
func (s *BaseRFC5322ParserListener) ExitEncodedWord(ctx *EncodedWordContext) {}
// EnterCharset is called when production charset is entered.
func (s *BaseRFC5322ParserListener) EnterCharset(ctx *CharsetContext) {}
// ExitCharset is called when production charset is exited.
func (s *BaseRFC5322ParserListener) ExitCharset(ctx *CharsetContext) {}
// EnterEncoding is called when production encoding is entered.
func (s *BaseRFC5322ParserListener) EnterEncoding(ctx *EncodingContext) {}
// ExitEncoding is called when production encoding is exited.
func (s *BaseRFC5322ParserListener) ExitEncoding(ctx *EncodingContext) {}
// EnterToken is called when production token is entered.
func (s *BaseRFC5322ParserListener) EnterToken(ctx *TokenContext) {}
// ExitToken is called when production token is exited.
func (s *BaseRFC5322ParserListener) ExitToken(ctx *TokenContext) {}
// EnterTokenChar is called when production tokenChar is entered.
func (s *BaseRFC5322ParserListener) EnterTokenChar(ctx *TokenCharContext) {}
// ExitTokenChar is called when production tokenChar is exited.
func (s *BaseRFC5322ParserListener) ExitTokenChar(ctx *TokenCharContext) {}
// EnterEncodedText is called when production encodedText is entered.
func (s *BaseRFC5322ParserListener) EnterEncodedText(ctx *EncodedTextContext) {}
// ExitEncodedText is called when production encodedText is exited.
func (s *BaseRFC5322ParserListener) ExitEncodedText(ctx *EncodedTextContext) {}
// EnterEncodedChar is called when production encodedChar is entered.
func (s *BaseRFC5322ParserListener) EnterEncodedChar(ctx *EncodedCharContext) {}
// ExitEncodedChar is called when production encodedChar is exited.
func (s *BaseRFC5322ParserListener) ExitEncodedChar(ctx *EncodedCharContext) {}
// EnterCrlf is called when production crlf is entered.
func (s *BaseRFC5322ParserListener) EnterCrlf(ctx *CrlfContext) {}
// ExitCrlf is called when production crlf is exited.
func (s *BaseRFC5322ParserListener) ExitCrlf(ctx *CrlfContext) {}
// EnterWsp is called when production wsp is entered.
func (s *BaseRFC5322ParserListener) EnterWsp(ctx *WspContext) {}
// ExitWsp is called when production wsp is exited.
func (s *BaseRFC5322ParserListener) ExitWsp(ctx *WspContext) {}
// EnterVchar is called when production vchar is entered.
func (s *BaseRFC5322ParserListener) EnterVchar(ctx *VcharContext) {}
// ExitVchar is called when production vchar is exited.
func (s *BaseRFC5322ParserListener) ExitVchar(ctx *VcharContext) {}
// EnterAlpha is called when production alpha is entered.
func (s *BaseRFC5322ParserListener) EnterAlpha(ctx *AlphaContext) {}
// ExitAlpha is called when production alpha is exited.
func (s *BaseRFC5322ParserListener) ExitAlpha(ctx *AlphaContext) {}

View File

@ -1,423 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// Code generated from RFC5322Parser.g4 by ANTLR 4.8. DO NOT EDIT.
package parser // RFC5322Parser
import "github.com/antlr/antlr4/runtime/Go/antlr"
// RFC5322ParserListener is a complete listener for a parse tree produced by RFC5322Parser.
type RFC5322ParserListener interface {
antlr.ParseTreeListener
// EnterQuotedChar is called when entering the quotedChar production.
EnterQuotedChar(c *QuotedCharContext)
// EnterQuotedPair is called when entering the quotedPair production.
EnterQuotedPair(c *QuotedPairContext)
// EnterFws is called when entering the fws production.
EnterFws(c *FwsContext)
// EnterCtext is called when entering the ctext production.
EnterCtext(c *CtextContext)
// EnterCcontent is called when entering the ccontent production.
EnterCcontent(c *CcontentContext)
// EnterComment is called when entering the comment production.
EnterComment(c *CommentContext)
// EnterCfws is called when entering the cfws production.
EnterCfws(c *CfwsContext)
// EnterAtext is called when entering the atext production.
EnterAtext(c *AtextContext)
// EnterAtom is called when entering the atom production.
EnterAtom(c *AtomContext)
// EnterDotAtom is called when entering the dotAtom production.
EnterDotAtom(c *DotAtomContext)
// EnterQtext is called when entering the qtext production.
EnterQtext(c *QtextContext)
// EnterQuotedContent is called when entering the quotedContent production.
EnterQuotedContent(c *QuotedContentContext)
// EnterQuotedValue is called when entering the quotedValue production.
EnterQuotedValue(c *QuotedValueContext)
// EnterQuotedString is called when entering the quotedString production.
EnterQuotedString(c *QuotedStringContext)
// EnterWord is called when entering the word production.
EnterWord(c *WordContext)
// EnterDateTime is called when entering the dateTime production.
EnterDateTime(c *DateTimeContext)
// EnterDayOfweek is called when entering the dayOfweek production.
EnterDayOfweek(c *DayOfweekContext)
// EnterDayName is called when entering the dayName production.
EnterDayName(c *DayNameContext)
// EnterDay is called when entering the day production.
EnterDay(c *DayContext)
// EnterMonth is called when entering the month production.
EnterMonth(c *MonthContext)
// EnterYear is called when entering the year production.
EnterYear(c *YearContext)
// EnterHour is called when entering the hour production.
EnterHour(c *HourContext)
// EnterMinute is called when entering the minute production.
EnterMinute(c *MinuteContext)
// EnterSecond is called when entering the second production.
EnterSecond(c *SecondContext)
// EnterOffset is called when entering the offset production.
EnterOffset(c *OffsetContext)
// EnterZone is called when entering the zone production.
EnterZone(c *ZoneContext)
// EnterAddress is called when entering the address production.
EnterAddress(c *AddressContext)
// EnterMailbox is called when entering the mailbox production.
EnterMailbox(c *MailboxContext)
// EnterNameAddr is called when entering the nameAddr production.
EnterNameAddr(c *NameAddrContext)
// EnterAngleAddr is called when entering the angleAddr production.
EnterAngleAddr(c *AngleAddrContext)
// EnterGroup is called when entering the group production.
EnterGroup(c *GroupContext)
// EnterDisplayName is called when entering the displayName production.
EnterDisplayName(c *DisplayNameContext)
// EnterMailboxList is called when entering the mailboxList production.
EnterMailboxList(c *MailboxListContext)
// EnterAddressList is called when entering the addressList production.
EnterAddressList(c *AddressListContext)
// EnterGroupList is called when entering the groupList production.
EnterGroupList(c *GroupListContext)
// EnterAddrSpec is called when entering the addrSpec production.
EnterAddrSpec(c *AddrSpecContext)
// EnterLocalPart is called when entering the localPart production.
EnterLocalPart(c *LocalPartContext)
// EnterPort is called when entering the port production.
EnterPort(c *PortContext)
// EnterDomain is called when entering the domain production.
EnterDomain(c *DomainContext)
// EnterDomainLiteral is called when entering the domainLiteral production.
EnterDomainLiteral(c *DomainLiteralContext)
// EnterDtext is called when entering the dtext production.
EnterDtext(c *DtextContext)
// EnterObsNoWSCTL is called when entering the obsNoWSCTL production.
EnterObsNoWSCTL(c *ObsNoWSCTLContext)
// EnterObsCtext is called when entering the obsCtext production.
EnterObsCtext(c *ObsCtextContext)
// EnterObsQtext is called when entering the obsQtext production.
EnterObsQtext(c *ObsQtextContext)
// EnterObsQP is called when entering the obsQP production.
EnterObsQP(c *ObsQPContext)
// EnterObsFWS is called when entering the obsFWS production.
EnterObsFWS(c *ObsFWSContext)
// EnterObsZone is called when entering the obsZone production.
EnterObsZone(c *ObsZoneContext)
// EnterObsAngleAddr is called when entering the obsAngleAddr production.
EnterObsAngleAddr(c *ObsAngleAddrContext)
// EnterObsRoute is called when entering the obsRoute production.
EnterObsRoute(c *ObsRouteContext)
// EnterObsDomainList is called when entering the obsDomainList production.
EnterObsDomainList(c *ObsDomainListContext)
// EnterObsMboxList is called when entering the obsMboxList production.
EnterObsMboxList(c *ObsMboxListContext)
// EnterObsAddrList is called when entering the obsAddrList production.
EnterObsAddrList(c *ObsAddrListContext)
// EnterObsGroupList is called when entering the obsGroupList production.
EnterObsGroupList(c *ObsGroupListContext)
// EnterObsLocalPart is called when entering the obsLocalPart production.
EnterObsLocalPart(c *ObsLocalPartContext)
// EnterObsDomain is called when entering the obsDomain production.
EnterObsDomain(c *ObsDomainContext)
// EnterEncodedWord is called when entering the encodedWord production.
EnterEncodedWord(c *EncodedWordContext)
// EnterCharset is called when entering the charset production.
EnterCharset(c *CharsetContext)
// EnterEncoding is called when entering the encoding production.
EnterEncoding(c *EncodingContext)
// EnterToken is called when entering the token production.
EnterToken(c *TokenContext)
// EnterTokenChar is called when entering the tokenChar production.
EnterTokenChar(c *TokenCharContext)
// EnterEncodedText is called when entering the encodedText production.
EnterEncodedText(c *EncodedTextContext)
// EnterEncodedChar is called when entering the encodedChar production.
EnterEncodedChar(c *EncodedCharContext)
// EnterCrlf is called when entering the crlf production.
EnterCrlf(c *CrlfContext)
// EnterWsp is called when entering the wsp production.
EnterWsp(c *WspContext)
// EnterVchar is called when entering the vchar production.
EnterVchar(c *VcharContext)
// EnterAlpha is called when entering the alpha production.
EnterAlpha(c *AlphaContext)
// ExitQuotedChar is called when exiting the quotedChar production.
ExitQuotedChar(c *QuotedCharContext)
// ExitQuotedPair is called when exiting the quotedPair production.
ExitQuotedPair(c *QuotedPairContext)
// ExitFws is called when exiting the fws production.
ExitFws(c *FwsContext)
// ExitCtext is called when exiting the ctext production.
ExitCtext(c *CtextContext)
// ExitCcontent is called when exiting the ccontent production.
ExitCcontent(c *CcontentContext)
// ExitComment is called when exiting the comment production.
ExitComment(c *CommentContext)
// ExitCfws is called when exiting the cfws production.
ExitCfws(c *CfwsContext)
// ExitAtext is called when exiting the atext production.
ExitAtext(c *AtextContext)
// ExitAtom is called when exiting the atom production.
ExitAtom(c *AtomContext)
// ExitDotAtom is called when exiting the dotAtom production.
ExitDotAtom(c *DotAtomContext)
// ExitQtext is called when exiting the qtext production.
ExitQtext(c *QtextContext)
// ExitQuotedContent is called when exiting the quotedContent production.
ExitQuotedContent(c *QuotedContentContext)
// ExitQuotedValue is called when exiting the quotedValue production.
ExitQuotedValue(c *QuotedValueContext)
// ExitQuotedString is called when exiting the quotedString production.
ExitQuotedString(c *QuotedStringContext)
// ExitWord is called when exiting the word production.
ExitWord(c *WordContext)
// ExitDateTime is called when exiting the dateTime production.
ExitDateTime(c *DateTimeContext)
// ExitDayOfweek is called when exiting the dayOfweek production.
ExitDayOfweek(c *DayOfweekContext)
// ExitDayName is called when exiting the dayName production.
ExitDayName(c *DayNameContext)
// ExitDay is called when exiting the day production.
ExitDay(c *DayContext)
// ExitMonth is called when exiting the month production.
ExitMonth(c *MonthContext)
// ExitYear is called when exiting the year production.
ExitYear(c *YearContext)
// ExitHour is called when exiting the hour production.
ExitHour(c *HourContext)
// ExitMinute is called when exiting the minute production.
ExitMinute(c *MinuteContext)
// ExitSecond is called when exiting the second production.
ExitSecond(c *SecondContext)
// ExitOffset is called when exiting the offset production.
ExitOffset(c *OffsetContext)
// ExitZone is called when exiting the zone production.
ExitZone(c *ZoneContext)
// ExitAddress is called when exiting the address production.
ExitAddress(c *AddressContext)
// ExitMailbox is called when exiting the mailbox production.
ExitMailbox(c *MailboxContext)
// ExitNameAddr is called when exiting the nameAddr production.
ExitNameAddr(c *NameAddrContext)
// ExitAngleAddr is called when exiting the angleAddr production.
ExitAngleAddr(c *AngleAddrContext)
// ExitGroup is called when exiting the group production.
ExitGroup(c *GroupContext)
// ExitDisplayName is called when exiting the displayName production.
ExitDisplayName(c *DisplayNameContext)
// ExitMailboxList is called when exiting the mailboxList production.
ExitMailboxList(c *MailboxListContext)
// ExitAddressList is called when exiting the addressList production.
ExitAddressList(c *AddressListContext)
// ExitGroupList is called when exiting the groupList production.
ExitGroupList(c *GroupListContext)
// ExitAddrSpec is called when exiting the addrSpec production.
ExitAddrSpec(c *AddrSpecContext)
// ExitLocalPart is called when exiting the localPart production.
ExitLocalPart(c *LocalPartContext)
// ExitPort is called when exiting the port production.
ExitPort(c *PortContext)
// ExitDomain is called when exiting the domain production.
ExitDomain(c *DomainContext)
// ExitDomainLiteral is called when exiting the domainLiteral production.
ExitDomainLiteral(c *DomainLiteralContext)
// ExitDtext is called when exiting the dtext production.
ExitDtext(c *DtextContext)
// ExitObsNoWSCTL is called when exiting the obsNoWSCTL production.
ExitObsNoWSCTL(c *ObsNoWSCTLContext)
// ExitObsCtext is called when exiting the obsCtext production.
ExitObsCtext(c *ObsCtextContext)
// ExitObsQtext is called when exiting the obsQtext production.
ExitObsQtext(c *ObsQtextContext)
// ExitObsQP is called when exiting the obsQP production.
ExitObsQP(c *ObsQPContext)
// ExitObsFWS is called when exiting the obsFWS production.
ExitObsFWS(c *ObsFWSContext)
// ExitObsZone is called when exiting the obsZone production.
ExitObsZone(c *ObsZoneContext)
// ExitObsAngleAddr is called when exiting the obsAngleAddr production.
ExitObsAngleAddr(c *ObsAngleAddrContext)
// ExitObsRoute is called when exiting the obsRoute production.
ExitObsRoute(c *ObsRouteContext)
// ExitObsDomainList is called when exiting the obsDomainList production.
ExitObsDomainList(c *ObsDomainListContext)
// ExitObsMboxList is called when exiting the obsMboxList production.
ExitObsMboxList(c *ObsMboxListContext)
// ExitObsAddrList is called when exiting the obsAddrList production.
ExitObsAddrList(c *ObsAddrListContext)
// ExitObsGroupList is called when exiting the obsGroupList production.
ExitObsGroupList(c *ObsGroupListContext)
// ExitObsLocalPart is called when exiting the obsLocalPart production.
ExitObsLocalPart(c *ObsLocalPartContext)
// ExitObsDomain is called when exiting the obsDomain production.
ExitObsDomain(c *ObsDomainContext)
// ExitEncodedWord is called when exiting the encodedWord production.
ExitEncodedWord(c *EncodedWordContext)
// ExitCharset is called when exiting the charset production.
ExitCharset(c *CharsetContext)
// ExitEncoding is called when exiting the encoding production.
ExitEncoding(c *EncodingContext)
// ExitToken is called when exiting the token production.
ExitToken(c *TokenContext)
// ExitTokenChar is called when exiting the tokenChar production.
ExitTokenChar(c *TokenCharContext)
// ExitEncodedText is called when exiting the encodedText production.
ExitEncodedText(c *EncodedTextContext)
// ExitEncodedChar is called when exiting the encodedChar production.
ExitEncodedChar(c *EncodedCharContext)
// ExitCrlf is called when exiting the crlf production.
ExitCrlf(c *CrlfContext)
// ExitWsp is called when exiting the wsp production.
ExitWsp(c *WspContext)
// ExitVchar is called when exiting the vchar production.
ExitVchar(c *VcharContext)
// ExitAlpha is called when exiting the alpha production.
ExitAlpha(c *AlphaContext)
}

View File

@ -1,49 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type port struct {
value string
}
func (w *walker) EnterPort(ctx *parser.PortContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering port")
w.enter(&port{
value: ctx.GetText(),
})
}
func (w *walker) ExitPort(ctx *parser.PortContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting port")
type withPort interface {
withPort(*port)
}
res := w.exit().(*port)
if parent, ok := w.parent().(withPort); ok {
parent.withPort(res)
}
}

View File

@ -1,49 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type qtext struct {
value string
}
func (w *walker) EnterQtext(ctx *parser.QtextContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering qtext")
w.enter(&qtext{
value: ctx.GetText(),
})
}
func (w *walker) ExitQtext(ctx *parser.QtextContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting qtext")
type withQtext interface {
withQtext(*qtext)
}
res := w.exit().(*qtext)
if parent, ok := w.parent().(withQtext); ok {
parent.withQtext(res)
}
}

View File

@ -1,49 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type quotedChar struct {
value string
}
func (w *walker) EnterQuotedChar(ctx *parser.QuotedCharContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering quotedChar")
w.enter(&quotedChar{
value: ctx.GetText(),
})
}
func (w *walker) ExitQuotedChar(ctx *parser.QuotedCharContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting quotedChar")
type withQuotedChar interface {
withQuotedChar(*quotedChar)
}
res := w.exit().(*quotedChar)
if parent, ok := w.parent().(withQuotedChar); ok {
parent.withQuotedChar(res)
}
}

View File

@ -1,54 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type quotedContent struct {
value string
}
func (c *quotedContent) withQtext(qtext *qtext) {
c.value = qtext.value
}
func (c *quotedContent) withQuotedPair(quotedPair *quotedPair) {
c.value = quotedPair.value
}
func (w *walker) EnterQuotedContent(ctx *parser.QuotedContentContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering quotedContent")
w.enter(&quotedContent{})
}
func (w *walker) ExitQuotedContent(ctx *parser.QuotedContentContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting quotedContent")
type withQuotedContent interface {
withQuotedContent(*quotedContent)
}
res := w.exit().(*quotedContent)
if parent, ok := w.parent().(withQuotedContent); ok {
parent.withQuotedContent(res)
}
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type quotedPair struct {
value string
}
func (p *quotedPair) withQuotedChar(quotedChar *quotedChar) {
p.value = quotedChar.value
}
func (w *walker) EnterQuotedPair(ctx *parser.QuotedPairContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering quotedPair")
w.enter(&quotedPair{})
}
func (w *walker) ExitQuotedPair(ctx *parser.QuotedPairContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting quotedPair")
type withQuotedPair interface {
withQuotedPair(*quotedPair)
}
res := w.exit().(*quotedPair)
if parent, ok := w.parent().(withQuotedPair); ok {
parent.withQuotedPair(res)
}
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type quotedString struct {
value string
}
func (s *quotedString) withQuotedValue(quotedValue *quotedValue) {
s.value = quotedValue.value
}
func (w *walker) EnterQuotedString(ctx *parser.QuotedStringContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering quotedString")
w.enter(&quotedString{})
}
func (w *walker) ExitQuotedString(ctx *parser.QuotedStringContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting quotedString")
type withQuotedString interface {
withQuotedString(*quotedString)
}
res := w.exit().(*quotedString)
if parent, ok := w.parent().(withQuotedString); ok {
parent.withQuotedString(res)
}
}

View File

@ -1,54 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type quotedValue struct {
value string
}
func (v *quotedValue) withFws(fws *fws) {
v.value += fws.value
}
func (v *quotedValue) withQuotedContent(quotedContent *quotedContent) {
v.value += quotedContent.value
}
func (w *walker) EnterQuotedValue(ctx *parser.QuotedValueContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering quotedValue")
w.enter(&quotedValue{})
}
func (w *walker) ExitQuotedValue(ctx *parser.QuotedValueContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting quotedValue")
type withQuotedValue interface {
withQuotedValue(*quotedValue)
}
res := w.exit().(*quotedValue)
if parent, ok := w.parent().(withQuotedValue); ok {
parent.withQuotedValue(res)
}
}

View File

@ -1,62 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"strconv"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type second struct {
value int
}
func (w *walker) EnterSecond(ctx *parser.SecondContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering second")
var text string
for _, digit := range ctx.AllDigit() {
text += digit.GetText()
}
val, err := strconv.Atoi(text)
if err != nil {
w.err = err
}
w.enter(&second{
value: val,
})
}
func (w *walker) ExitSecond(ctx *parser.SecondContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting second")
type withSecond interface {
withSecond(*second)
}
res := w.exit().(*second)
if parent, ok := w.parent().(withSecond); ok {
parent.withSecond(res)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,62 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"fmt"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/antlr/antlr4/runtime/Go/antlr"
)
// walker implements parser.BaseRFC5322ParserListener, defining what to do at
// each node while traversing the syntax tree.
// It also implements antlr.DefaultErrorListener, allowing us to react to
// errors encountered while trying to determine the syntax tree of the input.
type walker struct {
parser.BaseRFC5322ParserListener
antlr.DefaultErrorListener
// nodes acts as a stack; when entering a node, it is pushed here, and when
// exiting a node, it is popped from here.
nodes []interface{}
// res holds the result of walking the parse tree.
res interface{}
// err holds the error encountered during parsing, if any.
err error
}
func (w *walker) enter(b interface{}) {
w.nodes = append(w.nodes, b)
}
func (w *walker) exit() interface{} {
b := w.nodes[len(w.nodes)-1]
w.nodes = w.nodes[:len(w.nodes)-1]
return b
}
func (w *walker) parent() (b interface{}) {
return w.nodes[len(w.nodes)-1]
}
func (w *walker) SyntaxError(_ antlr.Recognizer, _ interface{}, _, _ int, msg string, _ antlr.RecognitionException) {
w.err = fmt.Errorf("error parsing rfc5322 input: %v", msg)
}

View File

@ -1,61 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type word struct {
value string
}
func (w *word) withAtom(atom *atom) {
w.value = atom.value
}
func (w *word) withQuotedString(quotedString *quotedString) {
w.value = quotedString.value
}
func (w *word) withEncodedWord(encodedWord *encodedWord) {
w.value = encodedWord.value
}
func (w *walker) EnterWord(ctx *parser.WordContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering word")
w.enter(&word{
value: ctx.GetText(),
})
}
func (w *walker) ExitWord(ctx *parser.WordContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting word")
type withWord interface {
withWord(*word)
}
res := w.exit().(*word)
if parent, ok := w.parent().(withWord); ok {
parent.withWord(res)
}
}

View File

@ -1,72 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"strconv"
"time"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type year struct {
value int
}
func (w *walker) EnterYear(ctx *parser.YearContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering year")
var text string
for _, digit := range ctx.AllDigit() {
text += digit.GetText()
}
val, err := strconv.Atoi(text)
if err != nil {
w.err = err
}
// NOTE: 2-digit years are obsolete but let's just have some simple handling anyway.
if len(text) == 2 {
if val > time.Now().Year()%100 {
val += 1900
} else {
val += 2000
}
}
w.enter(&year{
value: val,
})
}
func (w *walker) ExitYear(ctx *parser.YearContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting year")
type withYear interface {
withYear(*year)
}
res := w.exit().(*year)
if parent, ok := w.parent().(withYear); ok {
parent.withYear(res)
}
}

View File

@ -1,59 +0,0 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rfc5322
import (
"time"
"github.com/ProtonMail/proton-bridge/pkg/message/rfc5322/parser"
"github.com/sirupsen/logrus"
)
type zone struct {
location *time.Location
}
func (z *zone) withOffset(offset *offset) {
z.location = time.FixedZone(offset.rep, offset.value)
}
func (z *zone) withObsZone(obsZone *obsZone) {
z.location = obsZone.location
}
func (w *walker) EnterZone(ctx *parser.ZoneContext) {
logrus.WithField("text", ctx.GetText()).Trace("Entering zone")
w.enter(&zone{
location: time.UTC,
})
}
func (w *walker) ExitZone(ctx *parser.ZoneContext) {
logrus.WithField("text", ctx.GetText()).Trace("Exiting zone")
type withZone interface {
withZone(*zone)
}
res := w.exit().(*zone)
if parent, ok := w.parent().(withZone); ok {
parent.withZone(res)
}
}

View File

@ -32,17 +32,19 @@ import (
"golang.org/x/text/encoding/htmlindex" "golang.org/x/text/encoding/htmlindex"
) )
func CharsetReader(charset string, input io.Reader) (io.Reader, error) {
dec, err := SelectDecoder(charset)
if err != nil {
return nil, err
}
if dec == nil { // utf-8
return input, nil
}
return dec.Reader(input), nil
}
var WordDec = &mime.WordDecoder{ var WordDec = &mime.WordDecoder{
CharsetReader: func(charset string, input io.Reader) (io.Reader, error) { CharsetReader: CharsetReader,
dec, err := SelectDecoder(charset)
if err != nil {
return nil, err
}
if dec == nil { // utf-8
return input, nil
}
return dec.Reader(input), nil
},
} }
// Expects trimmed lowercase. // Expects trimmed lowercase.

View File

@ -15,7 +15,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>. // along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build pmapi_env // +build pmapi_qa
package pmapi package pmapi

View File

@ -5,12 +5,11 @@
package mocks package mocks
import ( import (
io "io"
reflect "reflect"
crypto "github.com/ProtonMail/gopenpgp/v2/crypto" crypto "github.com/ProtonMail/gopenpgp/v2/crypto"
pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi" pmapi "github.com/ProtonMail/proton-bridge/pkg/pmapi"
gomock "github.com/golang/mock/gomock" gomock "github.com/golang/mock/gomock"
io "io"
reflect "reflect"
) )
// MockClient is a mock of Client interface // MockClient is a mock of Client interface

View File

@ -1,3 +0,0 @@
• Linux font issues - Fedora specific
• App response to the user pausing and canceling import or export
• Handling errors during update

View File

@ -1,5 +1,3 @@
Improvements to the import from large mbox files with multiple labels Further improvements to address and date parsing
Not allow to run multiple instances of the app or transfers at the same time Better handling and displaying of skipped messages
Various enhancements of the import process related to parsing Improved error reporting
• Cosmetic GUI changes
• Better error handling

Some files were not shown because too many files have changed in this diff Show More