├── .github ├── FUNDING.yml └── workflows │ ├── build.yml │ └── test.yml ├── .gitignore ├── CHANGELOG ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── fuzz ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── fuzz_targets │ └── imap_server.rs ├── install.sh ├── resources ├── config │ ├── config.yml │ └── config_win.yml ├── scripts-deb │ ├── postinst │ ├── postrm │ ├── preinst │ └── prerm └── systemd │ ├── stalwart-imap.service │ └── stalwart.imap.plist └── src ├── commands ├── acl.rs ├── append.rs ├── authenticate.rs ├── capability.rs ├── close.rs ├── copy_move.rs ├── create.rs ├── delete.rs ├── enable.rs ├── expunge.rs ├── fetch.rs ├── idle.rs ├── list.rs ├── login.rs ├── logout.rs ├── mod.rs ├── namespace.rs ├── noop.rs ├── rename.rs ├── search.rs ├── select.rs ├── starttls.rs ├── status.rs ├── store.rs ├── subscribe.rs ├── thread.rs └── unselect.rs ├── core ├── client.rs ├── config.rs ├── connection.rs ├── env_settings.rs ├── housekeeper.rs ├── listener.rs ├── mailbox.rs ├── message.rs ├── mod.rs ├── receiver.rs ├── utf7.rs └── writer.rs ├── lib.rs ├── main.rs ├── managesieve ├── client.rs ├── commands │ ├── authenticate.rs │ ├── capability.rs │ ├── checkscript.rs │ ├── deletescript.rs │ ├── getscript.rs │ ├── havespace.rs │ ├── listscripts.rs │ ├── logout.rs │ ├── mod.rs │ ├── noop.rs │ ├── putscript.rs │ ├── renamescript.rs │ ├── setactive.rs │ └── starttls.rs ├── connection.rs ├── listener.rs └── mod.rs ├── parser ├── acl.rs ├── append.rs ├── authenticate.rs ├── copy_move.rs ├── create.rs ├── delete.rs ├── enable.rs ├── fetch.rs ├── list.rs ├── login.rs ├── lsub.rs ├── mod.rs ├── rename.rs ├── search.rs ├── select.rs ├── sort.rs ├── status.rs ├── store.rs ├── subscribe.rs └── thread.rs ├── protocol ├── acl.rs ├── append.rs ├── authenticate.rs ├── capability.rs ├── copy_move.rs ├── create.rs ├── delete.rs ├── enable.rs ├── expunge.rs ├── fetch.rs ├── list.rs ├── login.rs ├── mod.rs ├── namespace.rs ├── rename.rs ├── search.rs ├── select.rs ├── status.rs ├── store.rs ├── subscribe.rs └── thread.rs └── tests ├── acl.rs ├── append.rs ├── basic.rs ├── condstore.rs ├── copy_move.rs ├── fetch.rs ├── idle.rs ├── mailbox.rs ├── managesieve.rs ├── mod.rs ├── resources ├── cert.pem ├── imap-test │ ├── append │ ├── append-binary │ ├── atoms │ ├── broken │ │ ├── search-intdate │ │ └── search-intdate.mbox │ ├── catenate │ ├── catenate-multiappend │ ├── close │ ├── copy │ ├── default.mbox │ ├── esearch │ ├── esearch-condstore │ ├── esearch.mbox │ ├── esort │ ├── expunge │ ├── expunge2 │ ├── fetch │ ├── fetch-binary-mime │ ├── fetch-binary-mime-base64 │ ├── fetch-binary-mime-base64.mbox │ ├── fetch-binary-mime-qp │ ├── fetch-binary-mime-qp.mbox │ ├── fetch-binary-mime.mbox │ ├── fetch-body │ ├── fetch-body-message-rfc822 │ ├── fetch-body-message-rfc822-mime │ ├── fetch-body-message-rfc822-mime.mbox │ ├── fetch-body-message-rfc822-x2 │ ├── fetch-body-message-rfc822-x2.mbox │ ├── fetch-body-message-rfc822.mbox │ ├── fetch-body-mime │ ├── fetch-body-mime.mbox │ ├── fetch-body.mbox │ ├── fetch-bodystructure │ ├── fetch-bodystructure.mbox │ ├── fetch-envelope │ ├── fetch-envelope.mbox │ ├── id │ ├── list │ ├── listext │ ├── logout │ ├── move │ ├── multiappend │ ├── mutf7 │ ├── nil │ ├── nil.mbox │ ├── notify │ ├── pipeline │ ├── search-addresses │ ├── search-addresses.mbox │ ├── search-body │ ├── search-body.mbox │ ├── search-context-update │ ├── search-context-update2 │ ├── search-context-update3 │ ├── search-date │ ├── search-date.mbox │ ├── search-flags │ ├── search-header │ ├── search-header.mbox │ ├── search-partial │ ├── search-partial.mbox │ ├── search-sets │ ├── search-size │ ├── search-size.mbox │ ├── select │ ├── select.mbox │ ├── sort-addresses │ ├── sort-addresses.mbox │ ├── sort-arrival │ ├── sort-arrival.mbox │ ├── sort-date │ ├── sort-date.mbox │ ├── sort-display-from │ ├── sort-display-from.mbox │ ├── sort-display-to │ ├── sort-display-to.mbox │ ├── sort-partial │ ├── sort-partial.mbox │ ├── sort-size │ ├── sort-size.mbox │ ├── sort-subject │ ├── sort-subject.mbox │ ├── store │ ├── subscribe │ ├── thread │ ├── thread-orderedsubject │ ├── thread-orderedsubject.mbox │ ├── thread-orderedsubject2 │ ├── thread-orderedsubject2.mbox │ ├── thread.mbox │ ├── thread2 │ ├── thread2.mbox │ ├── thread3 │ ├── thread3.mbox │ ├── thread4 │ ├── thread4.mbox │ ├── thread5 │ ├── thread5.mbox │ ├── thread6 │ ├── thread6.mbox │ ├── thread7 │ ├── thread7.mbox │ ├── thread8 │ ├── thread8.mbox │ ├── uidplus │ ├── uidvalidity │ ├── uidvalidity-rename │ ├── urlauth │ ├── urlauth-binary │ ├── urlauth-binary.mbox │ └── urlauth2 ├── key.pem └── messages │ ├── 000.imap │ ├── 000.txt │ ├── 001.imap │ ├── 001.txt │ ├── 002.imap │ ├── 002.txt │ ├── 003.imap │ ├── 003.txt │ ├── 004.imap │ ├── 004.txt │ ├── 005.imap │ ├── 005.txt │ ├── 006.imap │ ├── 006.txt │ ├── 007.imap │ ├── 007.txt │ ├── 008.imap │ ├── 008.txt │ ├── 009.imap │ ├── 009.txt │ ├── 010.imap │ ├── 010.txt │ ├── 011.imap │ ├── 011.txt │ ├── 012.imap │ ├── 012.txt │ ├── 013.imap │ └── 013.txt ├── search.rs ├── store.rs └── thread.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: stalwartlabs 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: 8 | - main 9 | 10 | jobs: 11 | style: 12 | name: Check Style 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v1 17 | 18 | - name: Install Rust 19 | uses: actions-rs/toolchain@v1 20 | with: 21 | toolchain: stable 22 | components: rustfmt 23 | profile: minimal 24 | override: true 25 | 26 | - name: cargo fmt -- --check 27 | uses: actions-rs/cargo@v1 28 | with: 29 | command: fmt 30 | args: --all -- --check 31 | 32 | test: 33 | name: Test 34 | needs: [style] 35 | runs-on: ubuntu-latest 36 | 37 | steps: 38 | - name: Checkout 39 | uses: actions/checkout@v1 40 | 41 | - name: Install Rust 42 | uses: actions-rs/toolchain@v1 43 | with: 44 | toolchain: stable 45 | profile: minimal 46 | override: true 47 | 48 | - name: Base Tests 49 | uses: actions-rs/cargo@v1 50 | with: 51 | command: test 52 | args: --all 53 | 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # These are backup files generated by rustfmt 6 | **/*.rs.bk 7 | 8 | _ignore 9 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | stalwart-imap 0.2.0 2 | ================================ 3 | - ManageSieve support. 4 | - Fixed BODY[1] bug. 5 | - Added UTF8=ACCEPT (RFC 6855) support. 6 | 7 | stalwart-imap 0.1.0 8 | ================================ 9 | - Initial release. 10 | 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stalwart-imap-proxy" 3 | description = "Stalwart IMAP to JMAP proxy serve" 4 | authors = [ "Stalwart Labs Ltd. "] 5 | repository = "https://github.com/stalwartlabs/imap-server" 6 | homepage = "https://stalw.art/imap" 7 | keywords = ["imap", "email", "mail", "server"] 8 | categories = ["email"] 9 | license = "AGPL-3.0-only" 10 | version = "0.2.0" 11 | edition = "2021" 12 | resolver = "2" 13 | 14 | [dependencies] 15 | jmap-client = { git = "https://github.com/stalwartlabs/jmap-client", features = ["websockets", "follow-trusted"] } 16 | mail-parser = { git = "https://github.com/stalwartlabs/mail-parser" } 17 | ahash = "0.8.0" 18 | chrono = { version = "0.4"} 19 | tracing-subscriber = "0.3.15" 20 | tracing = "0.1" 21 | rustls = "0.20" 22 | rustls-pemfile = "1.0" 23 | tokio = { version = "1.16.1", features = ["full"] } 24 | tokio-rustls = { version = "0.23.4"} 25 | rayon = "1.5.1" 26 | sled = "0.34.7" 27 | num_cpus = "1.13.1" 28 | futures = "0.3" 29 | parking_lot = "0.12.0" 30 | base64 = "0.13" 31 | md5 = "0.7.0" 32 | 33 | [dev-dependencies] 34 | 35 | 36 | [profile.dev] 37 | opt-level = 0 38 | debug = 1 39 | codegen-units = 4 40 | lto = false 41 | incremental = true 42 | panic = 'unwind' 43 | debug-assertions = true 44 | overflow-checks = false 45 | rpath = false 46 | 47 | [profile.release] 48 | opt-level = 3 49 | debug = false 50 | codegen-units = 1 51 | lto = true 52 | incremental = false 53 | panic = 'unwind' 54 | debug-assertions = false 55 | overflow-checks = false 56 | rpath = false 57 | #strip = true 58 | 59 | [profile.test] 60 | opt-level = 0 61 | debug = 1 62 | codegen-units = 16 63 | lto = false 64 | incremental = true 65 | debug-assertions = true 66 | overflow-checks = true 67 | rpath = false 68 | 69 | [profile.bench] 70 | opt-level = 3 71 | debug = false 72 | codegen-units = 1 73 | lto = true 74 | incremental = false 75 | debug-assertions = false 76 | overflow-checks = false 77 | rpath = false 78 | 79 | [package.metadata.deb] 80 | name = "stalwart-imap" 81 | maintainer = "Stalwart Labs Ltd. " 82 | copyright = "2022, Stalwart Labs Ltd. " 83 | depends = "$auto" 84 | section = "mail" 85 | license-file = ["LICENSE"] 86 | maintainer-scripts = "resources/scripts-deb" 87 | assets = [ 88 | ["target/release/imap-server", "usr/bin/stalwart-imap", "755"], 89 | ["resources/config/config.yml", "etc/stalwart-imap/", "600"], 90 | ["resources/systemd/stalwart-imap.service", "lib/systemd/system/", "644"], 91 | ] 92 | conf-files = [ 93 | "/etc/stalwart-imap/config.yml" 94 | ] 95 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "imap-server-fuzz" 3 | version = "0.0.0" 4 | authors = ["Automatically generated"] 5 | publish = false 6 | edition = "2018" 7 | 8 | [package.metadata] 9 | cargo-fuzz = true 10 | 11 | [dependencies] 12 | libfuzzer-sys = "0.4" 13 | 14 | [dependencies.imap-server] 15 | path = ".." 16 | 17 | # Prevent this from interfering with workspaces 18 | [workspace] 19 | members = ["."] 20 | 21 | [[bin]] 22 | name = "imap_server" 23 | path = "fuzz_targets/imap_server.rs" 24 | test = false 25 | doc = false 26 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/imap_server.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | #![no_main] 25 | use libfuzzer_sys::fuzz_target; 26 | use stalwart_imap::core::receiver::{Receiver, State}; 27 | 28 | static IMAP_ALPHABET: &[u8] = b"()[]<>{}+-.:=\"NIL012345ABCDEF "; 29 | 30 | fuzz_target!(|data: &[u8]| { 31 | let imap_data = data 32 | .iter() 33 | .map(|&byte| IMAP_ALPHABET[byte as usize % IMAP_ALPHABET.len()]) 34 | .collect::>(); 35 | 36 | for state in [ 37 | State::Start, 38 | State::Tag, 39 | State::Command { is_uid: false }, 40 | State::Argument { last_ch: 0 }, 41 | State::Argument { 42 | last_ch: data.get(0).copied().unwrap_or(u8::MAX), 43 | }, 44 | State::ArgumentQuoted { escaped: true }, 45 | State::ArgumentQuoted { escaped: false }, 46 | State::Literal { non_sync: true }, 47 | State::Literal { non_sync: false }, 48 | State::LiteralData { remaining: 8192 }, 49 | ] { 50 | let mut r = Receiver::new(); 51 | r.state = state; 52 | r.parse(&mut data.iter()).ok(); 53 | 54 | let mut r = Receiver::new(); 55 | r.state = state; 56 | r.parse(&mut imap_data.iter()).ok(); 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /resources/config/config.yml: -------------------------------------------------------------------------------- 1 | ###################################################### 2 | # # 3 | # Stalwart IMAP config # 4 | # # 5 | ###################################################### 6 | 7 | bind-addr: 0.0.0.0 8 | bind-port: 143 9 | bind-port-tls: 993 10 | log-level: info 11 | 12 | jmap-url: https://localhost:8080 13 | #jmap-trusted-hosts: jmap1.example.org;jmap2.example.org 14 | 15 | 16 | # ---------------------------------------- 17 | # IMAP-to-JMAP Id Cache configuration 18 | # ---------------------------------------- 19 | 20 | cache-dir: /usr/local/stalwart-imap/data 21 | cache-purge-every: 0 3 * 22 | cache-removed-id-ttl: 2592000 # secs 23 | 24 | # ---------------------------------------- 25 | # TLS certificates 26 | # ---------------------------------------- 27 | 28 | cert-path: /usr/local/stalwart-imap/etc/imap.crt 29 | key-path: /usr/local/stalwart-imap/etc/imap.key 30 | 31 | # ---------------------------------------- 32 | # Default folder names 33 | # ---------------------------------------- 34 | name-shared: Shared Folders 35 | name-all: All Mail 36 | 37 | # ---------------------------------------- 38 | # Limits 39 | # ---------------------------------------- 40 | 41 | max-request-size: 52428800 42 | #worker-pool-size: 8 43 | -------------------------------------------------------------------------------- /resources/config/config_win.yml: -------------------------------------------------------------------------------- 1 | ###################################################### 2 | # # 3 | # Stalwart IMAP config # 4 | # # 5 | ###################################################### 6 | 7 | bind-addr: 0.0.0.0 8 | bind-port: 143 9 | bind-port-tls: 993 10 | log-level: info 11 | 12 | jmap-url: https://localhost:8080 13 | #jmap-trusted-hosts: jmap1.example.org;jmap2.example.org 14 | 15 | 16 | # ---------------------------------------- 17 | # IMAP-to-JMAP Id Cache configuration 18 | # ---------------------------------------- 19 | 20 | cache-dir: C:\Program Files\Stalwart IMAP\data 21 | cache-purge-every: 0 3 * 22 | cache-removed-id-ttl: 2592000 # secs 23 | 24 | # ---------------------------------------- 25 | # TLS certificates 26 | # ---------------------------------------- 27 | 28 | cert-path: C:\Program Files\Stalwart IMAP\etc\imap.crt 29 | key-path: C:\Program Files\Stalwart IMAP\etc\imap.key 30 | 31 | # ---------------------------------------- 32 | # Default folder names 33 | # ---------------------------------------- 34 | name-shared: Shared Folders 35 | name-all: All Mail 36 | 37 | # ---------------------------------------- 38 | # Limits 39 | # ---------------------------------------- 40 | 41 | max-request-size: 52428800 42 | #worker-pool-size: 8 43 | -------------------------------------------------------------------------------- /resources/scripts-deb/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Generate self-signed certificates 4 | if [ ! -f /etc/stalwart-imap/certs/imap.crt ]; then 5 | openssl req -x509 -nodes -days 1825 -newkey rsa:4096 -subj '/CN=localhost' -keyout /etc/stalwart-imap/private/imap.key -out /etc/stalwart-imap/certs/imap.crt 6 | fi 7 | 8 | # Set permissions 9 | chown -R stalwart-imap:stalwart-imap /etc/stalwart-imap 10 | chmod -R 770 /etc/stalwart-imap 11 | 12 | # Install service 13 | /bin/systemctl enable stalwart-imap 14 | /bin/systemctl restart stalwart-imap 15 | 16 | echo 17 | echo "************************************************************" 18 | echo "*** ***" 19 | echo "*** Stalwart IMAP successfully installed ***" 20 | echo "*** ***" 21 | echo "*** Please configure ***" 22 | echo "*** '/etc/stalwart-imap/config.yml' ***" 23 | echo "*** ***" 24 | echo "************************************************************" 25 | echo 26 | -------------------------------------------------------------------------------- /resources/scripts-deb/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | -------------------------------------------------------------------------------- /resources/scripts-deb/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Add user 4 | useradd stalwart-imap -s /sbin/nologin -M 5 | 6 | # Create default data and config directories 7 | mkdir -p /var/lib/stalwart-imap 8 | mkdir -p /etc/stalwart-imap/certs 9 | mkdir -p /etc/stalwart-imap/private 10 | 11 | # Set permissions 12 | chown -R stalwart-imap:stalwart-imap /var/lib/stalwart-imap 13 | chmod -R 770 /var/lib/stalwart-imap 14 | -------------------------------------------------------------------------------- /resources/scripts-deb/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | /bin/systemctl stop stalwart-imap 3 | /bin/systemctl disable stalwart-imap 4 | deluser stalwart-imap 5 | -------------------------------------------------------------------------------- /resources/systemd/stalwart-imap.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Stalwart IMAP 3 | ConditionPathExists=/usr/local/stalwart-imap/bin/stalwart-imap 4 | After=network-online.target 5 | 6 | [Service] 7 | Type=simple 8 | #User=stalwart-imap 9 | #Group=stalwart-imap 10 | LimitNOFILE=65536 11 | KillMode=process 12 | KillSignal=SIGINT 13 | Restart=on-failure 14 | RestartSec=5 15 | ExecStart=/usr/local/stalwart-imap/bin/stalwart-imap --config=/usr/local/stalwart-imap/etc/config.yml 16 | PermissionsStartOnly=true 17 | StandardOutput=syslog 18 | StandardError=syslog 19 | SyslogIdentifier=stalwart-imap 20 | 21 | [Install] 22 | WantedBy=multi-user.target 23 | -------------------------------------------------------------------------------- /resources/systemd/stalwart.imap.plist: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Label 7 | stalwart.imap 8 | ServiceDescription 9 | Stalwart IMAP Server 10 | ProgramArguments 11 | 12 | /usr/local/stalwart-imap/bin/stalwart-imap 13 | --config=/usr/local/stalwart-imap/etc/config.yml 14 | 15 | UserName 16 | _stalwart-imap 17 | RunAtLoad 18 | 19 | KeepAlive 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/commands/capability.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::{client::Session, receiver::Request, Command, StatusResponse}, 26 | protocol::{ 27 | capability::{Capability, Response}, 28 | ImapResponse, 29 | }, 30 | }; 31 | 32 | impl Session { 33 | pub async fn handle_capability(&mut self, request: Request) -> Result<(), ()> { 34 | self.write_bytes( 35 | StatusResponse::completed(Command::Capability) 36 | .with_tag(request.tag) 37 | .serialize( 38 | Response { 39 | capabilities: Capability::all_capabilities( 40 | self.state.is_authenticated(), 41 | self.is_tls, 42 | ), 43 | } 44 | .serialize(), 45 | ), 46 | ) 47 | .await 48 | } 49 | 50 | pub async fn handle_id(&mut self, request: Request) -> Result<(), ()> { 51 | self.write_bytes( 52 | StatusResponse::completed(Command::Id) 53 | .with_tag(request.tag) 54 | .serialize( 55 | concat!( 56 | "* ID (\"name\" \"Stalwart IMAP\" \"version\" \"", 57 | env!("CARGO_PKG_VERSION"), 58 | "\" \"vendor\" \"Stalwart Labs Ltd.\" ", 59 | "\"support-url\" \"https://stalw.art/imap\")\r\n" 60 | ) 61 | .as_bytes() 62 | .to_vec(), 63 | ), 64 | ) 65 | .await 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/commands/close.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::core::{ 25 | client::{Session, State}, 26 | receiver::Request, 27 | Command, StatusResponse, 28 | }; 29 | 30 | impl Session { 31 | pub async fn handle_close(&mut self, request: Request) -> Result<(), ()> { 32 | let (data, mailbox) = self.state.select_data(); 33 | if mailbox.is_select { 34 | data.expunge(mailbox, None).await.ok(); 35 | } 36 | 37 | self.state = State::Authenticated { data }; 38 | self.write_bytes( 39 | StatusResponse::completed(Command::Close) 40 | .with_tag(request.tag) 41 | .into_bytes(), 42 | ) 43 | .await 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/commands/login.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use jmap_client::client::Credentials; 25 | 26 | use crate::core::{client::Session, receiver::Request, Command}; 27 | 28 | impl Session { 29 | pub async fn handle_login(&mut self, request: Request) -> Result<(), ()> { 30 | match request.parse_login() { 31 | Ok(args) => { 32 | self.authenticate(Credentials::basic(&args.username, &args.password), args.tag) 33 | .await 34 | } 35 | Err(response) => self.write_bytes(response.into_bytes()).await, 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/commands/logout.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::core::{client::Session, receiver::Request, Command, StatusResponse}; 25 | 26 | impl Session { 27 | pub async fn handle_logout(&mut self, request: Request) -> Result<(), ()> { 28 | let mut response = StatusResponse::bye( 29 | concat!( 30 | "Stalwart IMAP4rev2 v", 31 | env!("CARGO_PKG_VERSION"), 32 | " bids you farewell." 33 | ) 34 | .to_string(), 35 | ) 36 | .into_bytes(); 37 | response.extend( 38 | StatusResponse::completed(Command::Logout) 39 | .with_tag(request.tag) 40 | .into_bytes(), 41 | ); 42 | self.write_bytes(response).await?; 43 | Err(()) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/commands/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | pub mod acl; 25 | pub mod append; 26 | pub mod authenticate; 27 | pub mod capability; 28 | pub mod close; 29 | pub mod copy_move; 30 | pub mod create; 31 | pub mod delete; 32 | pub mod enable; 33 | pub mod expunge; 34 | pub mod fetch; 35 | pub mod idle; 36 | pub mod list; 37 | pub mod login; 38 | pub mod logout; 39 | pub mod namespace; 40 | pub mod noop; 41 | pub mod rename; 42 | pub mod search; 43 | pub mod select; 44 | pub mod starttls; 45 | pub mod status; 46 | pub mod store; 47 | pub mod subscribe; 48 | pub mod thread; 49 | pub mod unselect; 50 | -------------------------------------------------------------------------------- /src/commands/namespace.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::{client::Session, receiver::Request, Command, StatusResponse}, 26 | protocol::{namespace::Response, ImapResponse}, 27 | }; 28 | 29 | impl Session { 30 | pub async fn handle_namespace(&mut self, request: Request) -> Result<(), ()> { 31 | self.write_bytes( 32 | StatusResponse::completed(Command::Namespace) 33 | .with_tag(request.tag) 34 | .serialize( 35 | Response { 36 | shared_prefix: if self.state.session_data().mailboxes.lock().len() > 1 { 37 | self.core.folder_shared.clone().into() 38 | } else { 39 | None 40 | }, 41 | } 42 | .serialize(), 43 | ), 44 | ) 45 | .await 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/commands/noop.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::core::{ 25 | client::{Session, State}, 26 | receiver::Request, 27 | Command, StatusResponse, 28 | }; 29 | 30 | impl Session { 31 | pub async fn handle_noop( 32 | &mut self, 33 | request: Request, 34 | is_check: bool, 35 | ) -> Result<(), ()> { 36 | match &self.state { 37 | State::Authenticated { data } => { 38 | data.write_changes(None, true, true, self.is_qresync, self.version.is_rev2()) 39 | .await; 40 | } 41 | State::Selected { data, mailbox, .. } => { 42 | data.write_changes( 43 | mailbox.into(), 44 | true, 45 | true, 46 | self.is_qresync, 47 | self.version.is_rev2(), 48 | ) 49 | .await; 50 | } 51 | _ => (), 52 | } 53 | 54 | self.write_bytes( 55 | StatusResponse::completed(if !is_check { 56 | Command::Noop 57 | } else { 58 | Command::Check 59 | }) 60 | .with_tag(request.tag) 61 | .into_bytes(), 62 | ) 63 | .await 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/commands/starttls.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use tokio::{io::WriteHalf, net::TcpStream, sync::oneshot}; 25 | use tracing::debug; 26 | 27 | use crate::core::{client::Session, receiver::Request, writer, Command, StatusResponse}; 28 | 29 | impl Session { 30 | pub async fn handle_starttls( 31 | &mut self, 32 | request: Request, 33 | ) -> Result>, ()> { 34 | self.write_bytes( 35 | StatusResponse::ok("Begin TLS negotiation now") 36 | .with_tag(request.tag) 37 | .into_bytes(), 38 | ) 39 | .await?; 40 | 41 | // Recover WriteHalf from writer 42 | let (tx, rx) = oneshot::channel(); 43 | if let Err(err) = self.writer.send(writer::Event::Upgrade(tx)).await { 44 | debug!("Failed to write to channel: {}", err); 45 | return Err(()); 46 | } 47 | if let Ok(event) = rx.await { 48 | if let writer::Event::Stream(stream_tx) = event { 49 | Ok(Some(stream_tx)) 50 | } else { 51 | unreachable!() 52 | } 53 | } else { 54 | debug!("Failed to read from channel"); 55 | Err(()) 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/commands/unselect.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::core::{ 25 | client::{Session, State}, 26 | receiver::Request, 27 | Command, StatusResponse, 28 | }; 29 | 30 | impl Session { 31 | pub async fn handle_unselect(&mut self, request: Request) -> Result<(), ()> { 32 | self.state = State::Authenticated { 33 | data: self.state.session_data(), 34 | }; 35 | self.write_bytes( 36 | StatusResponse::completed(Command::Unselect) 37 | .with_tag(request.tag) 38 | .into_bytes(), 39 | ) 40 | .await 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use stalwart_imap_proxy::core::env_settings::EnvSettings; 25 | use stalwart_imap_proxy::start_imap_server; 26 | 27 | #[tokio::main] 28 | async fn main() -> std::io::Result<()> { 29 | // Start server 30 | start_imap_server(EnvSettings::new()).await 31 | } 32 | -------------------------------------------------------------------------------- /src/managesieve/commands/checkscript.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::receiver::Request, 26 | managesieve::{client::Session, Command, StatusResponse}, 27 | }; 28 | 29 | use super::IntoStatusResponse; 30 | 31 | impl Session { 32 | pub async fn handle_checkscript( 33 | &mut self, 34 | request: Request, 35 | ) -> Result { 36 | if request.tokens.is_empty() { 37 | return Err(StatusResponse::no("Expected script as a parameter.")); 38 | } 39 | 40 | self.client() 41 | .sieve_script_validate(request.tokens.into_iter().next().unwrap().unwrap_bytes()) 42 | .await 43 | .map_err(|err| err.into_status_response())?; 44 | 45 | Ok(self 46 | .write_bytes(StatusResponse::ok("Script is valid.").into_bytes()) 47 | .await 48 | .is_ok()) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/managesieve/commands/deletescript.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::receiver::Request, 26 | managesieve::{client::Session, Command, StatusResponse}, 27 | }; 28 | 29 | use super::IntoStatusResponse; 30 | 31 | impl Session { 32 | pub async fn handle_deletescript( 33 | &mut self, 34 | request: Request, 35 | ) -> Result { 36 | let name = request 37 | .tokens 38 | .into_iter() 39 | .next() 40 | .and_then(|s| s.unwrap_string().ok()) 41 | .ok_or_else(|| StatusResponse::no("Expected script name as a parameter."))?; 42 | 43 | self.client() 44 | .sieve_script_destroy(&self.get_script_id(name).await?) 45 | .await 46 | .map_err(|err| err.into_status_response())?; 47 | 48 | Ok(self 49 | .write_bytes(StatusResponse::ok("Deleted.").into_bytes()) 50 | .await 51 | .is_ok()) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/managesieve/commands/getscript.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use jmap_client::sieve::Property; 25 | 26 | use crate::{ 27 | core::receiver::Request, 28 | managesieve::{client::Session, Command, ResponseCode, StatusResponse}, 29 | }; 30 | 31 | use super::IntoStatusResponse; 32 | 33 | impl Session { 34 | pub async fn handle_getscript( 35 | &mut self, 36 | request: Request, 37 | ) -> Result { 38 | let name = request 39 | .tokens 40 | .into_iter() 41 | .next() 42 | .and_then(|s| s.unwrap_string().ok()) 43 | .ok_or_else(|| StatusResponse::no("Expected script name as a parameter."))?; 44 | 45 | let client = self.client(); 46 | let script = client 47 | .sieve_script_get(&self.get_script_id(name).await?, [Property::BlobId].into()) 48 | .await 49 | .map_err(|err| err.into_status_response())? 50 | .ok_or_else(|| { 51 | StatusResponse::no("Script not found").with_code(ResponseCode::NonExistent) 52 | })?; 53 | let script = client 54 | .download(script.blob_id().ok_or_else(|| { 55 | StatusResponse::no("BlobId not included in response") 56 | .with_code(ResponseCode::NonExistent) 57 | })?) 58 | .await 59 | .map_err(|err| err.into_status_response())?; 60 | 61 | let mut response = Vec::with_capacity(script.len() + 30); 62 | response.push(b'{'); 63 | response.extend_from_slice(script.len().to_string().as_bytes()); 64 | response.extend_from_slice(b"}\r\n"); 65 | response.extend(script); 66 | 67 | Ok(self 68 | .write_bytes(StatusResponse::ok("").serialize(response)) 69 | .await 70 | .is_ok()) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/managesieve/commands/havespace.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::receiver::Request, 26 | managesieve::{client::Session, Command, StatusResponse}, 27 | }; 28 | 29 | impl Session { 30 | pub async fn handle_havespace( 31 | &mut self, 32 | request: Request, 33 | ) -> Result { 34 | let mut tokens = request.tokens.into_iter(); 35 | let _name = tokens 36 | .next() 37 | .and_then(|s| s.unwrap_string().ok()) 38 | .ok_or_else(|| StatusResponse::no("Expected script name as a parameter."))?; 39 | let _size = tokens 40 | .next() 41 | .and_then(|s| s.unwrap_string().ok()) 42 | .ok_or_else(|| StatusResponse::no("Expected script size as a parameter."))? 43 | .parse::() 44 | .map_err(|_| StatusResponse::no("Invalid size parameter."))?; 45 | 46 | // Not yet implemented, requires QUOTA support. 47 | 48 | Ok(self 49 | .write_bytes(StatusResponse::ok("").into_bytes()) 50 | .await 51 | .is_ok()) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/managesieve/commands/listscripts.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use jmap_client::sieve::Property; 25 | 26 | use crate::managesieve::{client::Session, StatusResponse}; 27 | 28 | use super::IntoStatusResponse; 29 | 30 | impl Session { 31 | pub async fn handle_listscripts(&mut self) -> Result { 32 | let mut request = self.client().build(); 33 | request 34 | .get_sieve_script() 35 | .properties([Property::Name, Property::IsActive]); 36 | 37 | let mut response = Vec::with_capacity(128); 38 | 39 | for script in request 40 | .send_get_sieve_script() 41 | .await 42 | .map_err(|err| err.into_status_response())? 43 | .take_list() 44 | { 45 | response.push(b'\"'); 46 | if let Some(name) = script.name() { 47 | for ch in name.as_bytes() { 48 | if [b'\\', b'\"'].contains(ch) { 49 | response.push(b'\\'); 50 | } 51 | response.push(*ch); 52 | } 53 | } 54 | 55 | if script.is_active() { 56 | response.extend_from_slice(b"\" ACTIVE\r\n"); 57 | } else { 58 | response.extend_from_slice(b"\"\r\n"); 59 | } 60 | } 61 | 62 | Ok(self 63 | .write_bytes(StatusResponse::ok("").serialize(response)) 64 | .await 65 | .is_ok()) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/managesieve/commands/logout.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::managesieve::{client::Session, StatusResponse}; 25 | 26 | impl Session { 27 | pub async fn handle_logout(&mut self) -> Result { 28 | self.write_bytes( 29 | StatusResponse::bye(concat!( 30 | "Stalwart ManageSieve v", 31 | env!("CARGO_PKG_VERSION"), 32 | " bids you farewell." 33 | )) 34 | .into_bytes(), 35 | ) 36 | .await 37 | .ok(); 38 | 39 | Ok(false) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/managesieve/commands/noop.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::receiver::Request, 26 | managesieve::{client::Session, Command, ResponseCode, StatusResponse}, 27 | }; 28 | 29 | impl Session { 30 | pub async fn handle_noop(&mut self, request: Request) -> Result { 31 | Ok(self 32 | .write_bytes( 33 | (if let Some(tag) = request 34 | .tokens 35 | .into_iter() 36 | .next() 37 | .and_then(|t| t.unwrap_string().ok()) 38 | { 39 | StatusResponse::ok("Done").with_code(ResponseCode::Tag(tag)) 40 | } else { 41 | StatusResponse::ok("Done") 42 | }) 43 | .into_bytes(), 44 | ) 45 | .await 46 | .is_ok()) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/managesieve/commands/putscript.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::receiver::Request, 26 | managesieve::{client::Session, Command, StatusResponse}, 27 | }; 28 | 29 | use super::IntoStatusResponse; 30 | 31 | impl Session { 32 | pub async fn handle_putscript( 33 | &mut self, 34 | request: Request, 35 | ) -> Result { 36 | let mut tokens = request.tokens.into_iter(); 37 | let name = tokens 38 | .next() 39 | .and_then(|s| s.unwrap_string().ok()) 40 | .ok_or_else(|| StatusResponse::no("Expected script name as a parameter."))?; 41 | let script = tokens 42 | .next() 43 | .ok_or_else(|| StatusResponse::no("Expected script as a parameter."))? 44 | .unwrap_bytes(); 45 | 46 | self.client() 47 | .sieve_script_create(name, script, false) 48 | .await 49 | .map_err(|err| err.into_status_response())?; 50 | 51 | Ok(self 52 | .write_bytes(StatusResponse::ok("Success.").into_bytes()) 53 | .await 54 | .is_ok()) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/managesieve/commands/renamescript.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::receiver::Request, 26 | managesieve::{client::Session, Command, StatusResponse}, 27 | }; 28 | 29 | use super::IntoStatusResponse; 30 | 31 | impl Session { 32 | pub async fn handle_renamescript( 33 | &mut self, 34 | request: Request, 35 | ) -> Result { 36 | let mut tokens = request.tokens.into_iter(); 37 | let name = tokens 38 | .next() 39 | .and_then(|s| s.unwrap_string().ok()) 40 | .ok_or_else(|| StatusResponse::no("Expected old script name as a parameter."))?; 41 | let new_name = tokens 42 | .next() 43 | .and_then(|s| s.unwrap_string().ok()) 44 | .ok_or_else(|| StatusResponse::no("Expected new script name as a parameter."))?; 45 | 46 | self.client() 47 | .sieve_script_rename(&self.get_script_id(name).await?, new_name, false) 48 | .await 49 | .map_err(|err| err.into_status_response())?; 50 | 51 | Ok(self 52 | .write_bytes(StatusResponse::ok("Success.").into_bytes()) 53 | .await 54 | .is_ok()) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/managesieve/commands/setactive.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::receiver::Request, 26 | managesieve::{client::Session, Command, StatusResponse}, 27 | }; 28 | 29 | use super::IntoStatusResponse; 30 | 31 | impl Session { 32 | pub async fn handle_setactive( 33 | &mut self, 34 | request: Request, 35 | ) -> Result { 36 | let name = request 37 | .tokens 38 | .into_iter() 39 | .next() 40 | .and_then(|s| s.unwrap_string().ok()) 41 | .ok_or_else(|| StatusResponse::no("Expected script name as a parameter."))?; 42 | 43 | (if !name.is_empty() { 44 | self.client() 45 | .sieve_script_activate(&self.get_script_id(name).await?) 46 | .await 47 | } else { 48 | self.client().sieve_script_deactivate().await 49 | }) 50 | .map_err(|err| err.into_status_response())?; 51 | 52 | Ok(self 53 | .write_bytes(StatusResponse::ok("Success").into_bytes()) 54 | .await 55 | .is_ok()) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/managesieve/commands/starttls.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use tokio::{io::WriteHalf, net::TcpStream, sync::oneshot}; 25 | use tracing::debug; 26 | 27 | use crate::{ 28 | core::writer, 29 | managesieve::{client::Session, StatusResponse}, 30 | }; 31 | 32 | impl Session { 33 | pub async fn handle_starttls(&mut self) -> Result>, ()> { 34 | self.write_bytes(StatusResponse::ok("Begin TLS negotiation now").into_bytes()) 35 | .await?; 36 | 37 | // Recover WriteHalf from writer 38 | let (tx, rx) = oneshot::channel(); 39 | if let Err(err) = self.writer.send(writer::Event::Upgrade(tx)).await { 40 | debug!("Failed to write to channel: {}", err); 41 | return Err(()); 42 | } 43 | if let Ok(event) = rx.await { 44 | if let writer::Event::Stream(stream_tx) = event { 45 | Ok(Some(stream_tx)) 46 | } else { 47 | unreachable!() 48 | } 49 | } else { 50 | debug!("Failed to read from channel"); 51 | Err(()) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/managesieve/listener.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use std::{net::SocketAddr, sync::Arc}; 25 | 26 | use tokio::{net::TcpListener, sync::watch}; 27 | use tracing::{debug, error}; 28 | 29 | use crate::{ 30 | core::{config::failed_to, Core}, 31 | managesieve::{client::Session, connection::handle_conn}, 32 | }; 33 | 34 | pub async fn spawn_managesieve_listener( 35 | bind_addr: SocketAddr, 36 | core: Arc, 37 | mut shutdown_rx: watch::Receiver, 38 | ) { 39 | // Start listening for ManageSieve connections. 40 | let listener = TcpListener::bind(bind_addr).await.unwrap_or_else(|e| { 41 | failed_to(&format!("bind to {}: {}", bind_addr, e)); 42 | }); 43 | 44 | tokio::spawn(async move { 45 | loop { 46 | tokio::select! { 47 | stream = listener.accept() => { 48 | match stream { 49 | Ok((stream, _)) => { 50 | let shutdown_rx = shutdown_rx.clone(); 51 | let core = core.clone(); 52 | 53 | tokio::spawn(async move { 54 | let peer_addr = stream.peer_addr().unwrap(); 55 | 56 | handle_conn( 57 | stream, 58 | Session::new(core, peer_addr, false), 59 | shutdown_rx 60 | ).await; 61 | }); 62 | } 63 | Err(err) => { 64 | error!("Failed to accept TCP connection: {}", err); 65 | } 66 | } 67 | }, 68 | _ = shutdown_rx.changed() => { 69 | debug!("ManageSieve listener shutting down."); 70 | break; 71 | } 72 | }; 73 | } 74 | }); 75 | } 76 | -------------------------------------------------------------------------------- /src/parser/copy_move.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::{receiver::Request, Command}, 26 | protocol::copy_move, 27 | }; 28 | 29 | use super::parse_sequence_set; 30 | 31 | impl Request { 32 | pub fn parse_copy_move(self) -> crate::core::Result { 33 | if self.tokens.len() > 1 { 34 | let mut tokens = self.tokens.into_iter(); 35 | 36 | Ok(copy_move::Arguments { 37 | sequence_set: parse_sequence_set( 38 | &tokens 39 | .next() 40 | .ok_or((self.tag.as_str(), "Missing sequence set."))? 41 | .unwrap_bytes(), 42 | ) 43 | .map_err(|v| (self.tag.as_str(), v))?, 44 | mailbox_name: tokens 45 | .next() 46 | .ok_or((self.tag.as_str(), "Missing mailbox name."))? 47 | .unwrap_string() 48 | .map_err(|v| (self.tag.as_str(), v))?, 49 | tag: self.tag, 50 | }) 51 | } else { 52 | Err(self.into_error("Missing arguments.")) 53 | } 54 | } 55 | } 56 | 57 | #[cfg(test)] 58 | mod tests { 59 | use crate::{ 60 | core::receiver::Receiver, 61 | protocol::{copy_move, Sequence}, 62 | }; 63 | 64 | #[test] 65 | fn parse_copy() { 66 | let mut receiver = Receiver::new(); 67 | 68 | assert_eq!( 69 | receiver 70 | .parse(&mut "A003 COPY 2:4 MEETING\r\n".as_bytes().iter()) 71 | .unwrap() 72 | .parse_copy_move() 73 | .unwrap(), 74 | copy_move::Arguments { 75 | sequence_set: Sequence::Range { 76 | start: 2.into(), 77 | end: 4.into(), 78 | }, 79 | mailbox_name: "MEETING".to_string(), 80 | tag: "A003".to_string(), 81 | } 82 | ); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/parser/delete.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::{receiver::Request, utf7::utf7_maybe_decode, Command}, 26 | protocol::{delete, ProtocolVersion}, 27 | }; 28 | 29 | impl Request { 30 | pub fn parse_delete(self, version: ProtocolVersion) -> crate::core::Result { 31 | match self.tokens.len() { 32 | 1 => Ok(delete::Arguments { 33 | mailbox_name: utf7_maybe_decode( 34 | self.tokens 35 | .into_iter() 36 | .next() 37 | .unwrap() 38 | .unwrap_string() 39 | .map_err(|v| (self.tag.as_ref(), v))?, 40 | version, 41 | ), 42 | tag: self.tag, 43 | }), 44 | 0 => Err(self.into_error("Missing mailbox name.")), 45 | _ => Err(self.into_error("Too many arguments.")), 46 | } 47 | } 48 | } 49 | 50 | #[cfg(test)] 51 | mod tests { 52 | use crate::{ 53 | core::receiver::Receiver, 54 | protocol::{delete, ProtocolVersion}, 55 | }; 56 | 57 | #[test] 58 | fn parse_delete() { 59 | let mut receiver = Receiver::new(); 60 | 61 | for (command, arguments) in [ 62 | ( 63 | "A142 DELETE INBOX\r\n", 64 | delete::Arguments { 65 | mailbox_name: "INBOX".to_string(), 66 | tag: "A142".to_string(), 67 | }, 68 | ), 69 | ( 70 | "A142 DELETE \"my funky mailbox\"\r\n", 71 | delete::Arguments { 72 | mailbox_name: "my funky mailbox".to_string(), 73 | tag: "A142".to_string(), 74 | }, 75 | ), 76 | ] { 77 | assert_eq!( 78 | receiver 79 | .parse(&mut command.as_bytes().iter()) 80 | .unwrap() 81 | .parse_delete(ProtocolVersion::Rev2) 82 | .unwrap(), 83 | arguments 84 | ); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/parser/subscribe.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::{ 25 | core::{receiver::Request, utf7::utf7_maybe_decode, Command}, 26 | protocol::{subscribe, ProtocolVersion}, 27 | }; 28 | 29 | impl Request { 30 | pub fn parse_subscribe( 31 | self, 32 | version: ProtocolVersion, 33 | ) -> crate::core::Result { 34 | match self.tokens.len() { 35 | 1 => Ok(subscribe::Arguments { 36 | mailbox_name: utf7_maybe_decode( 37 | self.tokens 38 | .into_iter() 39 | .next() 40 | .unwrap() 41 | .unwrap_string() 42 | .map_err(|v| (self.tag.as_ref(), v))?, 43 | version, 44 | ), 45 | tag: self.tag, 46 | }), 47 | 0 => Err(self.into_error("Missing mailbox name.")), 48 | _ => Err(self.into_error("Too many arguments.")), 49 | } 50 | } 51 | } 52 | 53 | #[cfg(test)] 54 | mod tests { 55 | use crate::{ 56 | core::receiver::Receiver, 57 | protocol::{subscribe, ProtocolVersion}, 58 | }; 59 | 60 | #[test] 61 | fn parse_subscribe() { 62 | let mut receiver = Receiver::new(); 63 | 64 | for (command, arguments) in [ 65 | ( 66 | "A142 SUBSCRIBE #news.comp.mail.mime\r\n", 67 | subscribe::Arguments { 68 | mailbox_name: "#news.comp.mail.mime".to_string(), 69 | tag: "A142".to_string(), 70 | }, 71 | ), 72 | ( 73 | "A142 SUBSCRIBE \"#news.comp.mail.mime\"\r\n", 74 | subscribe::Arguments { 75 | mailbox_name: "#news.comp.mail.mime".to_string(), 76 | tag: "A142".to_string(), 77 | }, 78 | ), 79 | ] { 80 | assert_eq!( 81 | receiver 82 | .parse(&mut command.as_bytes().iter()) 83 | .unwrap() 84 | .parse_subscribe(ProtocolVersion::Rev2) 85 | .unwrap(), 86 | arguments 87 | ); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/protocol/append.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::core::Flag; 25 | 26 | #[derive(Debug, Clone, PartialEq, Eq)] 27 | pub struct Arguments { 28 | pub tag: String, 29 | pub mailbox_name: String, 30 | pub messages: Vec, 31 | } 32 | 33 | #[derive(Debug, Clone, PartialEq, Eq)] 34 | pub struct Message { 35 | pub message: Vec, 36 | pub flags: Vec, 37 | pub received_at: Option, 38 | } 39 | -------------------------------------------------------------------------------- /src/protocol/authenticate.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct Arguments { 26 | pub tag: String, 27 | pub mechanism: Mechanism, 28 | pub params: Vec, 29 | } 30 | 31 | #[derive(Debug, Clone, PartialEq, Eq)] 32 | pub enum Mechanism { 33 | Plain, 34 | CramMd5, 35 | DigestMd5, 36 | ScramSha1, 37 | ScramSha256, 38 | Apop, 39 | Ntlm, 40 | Gssapi, 41 | Anonymous, 42 | External, 43 | OAuthBearer, 44 | XOauth2, 45 | } 46 | 47 | impl Mechanism { 48 | pub fn serialize(&self, buf: &mut Vec) { 49 | buf.extend_from_slice(match self { 50 | Mechanism::Plain => b"PLAIN", 51 | Mechanism::CramMd5 => b"CRAM-MD5", 52 | Mechanism::DigestMd5 => b"DIGEST-MD5", 53 | Mechanism::ScramSha1 => b"SCRAM-SHA-1", 54 | Mechanism::ScramSha256 => b"SCRAM-SHA-256", 55 | Mechanism::Apop => b"APOP", 56 | Mechanism::Ntlm => b"NTLM", 57 | Mechanism::Gssapi => b"GSSAPI", 58 | Mechanism::Anonymous => b"ANONYMOUS", 59 | Mechanism::External => b"EXTERNAL", 60 | Mechanism::OAuthBearer => b"OAUTHBEARER", 61 | Mechanism::XOauth2 => b"XOAUTH2", 62 | }); 63 | } 64 | 65 | pub fn into_bytes(self) -> Vec { 66 | let mut buf = Vec::with_capacity(10); 67 | self.serialize(&mut buf); 68 | buf 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/protocol/copy_move.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use super::Sequence; 25 | 26 | #[derive(Debug, Clone, PartialEq, Eq)] 27 | pub struct Arguments { 28 | pub tag: String, 29 | pub sequence_set: Sequence, 30 | pub mailbox_name: String, 31 | } 32 | -------------------------------------------------------------------------------- /src/protocol/create.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use jmap_client::mailbox::Role; 25 | 26 | #[derive(Debug, Clone, PartialEq, Eq)] 27 | pub struct Arguments { 28 | pub tag: String, 29 | pub mailbox_name: String, 30 | pub mailbox_role: Role, 31 | } 32 | -------------------------------------------------------------------------------- /src/protocol/delete.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct Arguments { 26 | pub tag: String, 27 | pub mailbox_name: String, 28 | } 29 | -------------------------------------------------------------------------------- /src/protocol/enable.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use super::capability::Capability; 25 | 26 | #[derive(Debug, Clone, PartialEq, Eq)] 27 | pub struct Arguments { 28 | pub tag: String, 29 | pub capabilities: Vec, 30 | } 31 | -------------------------------------------------------------------------------- /src/protocol/login.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct Arguments { 26 | pub tag: String, 27 | pub username: String, 28 | pub password: String, 29 | } 30 | -------------------------------------------------------------------------------- /src/protocol/namespace.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use super::{quoted_string, ImapResponse}; 25 | 26 | pub struct Response { 27 | pub shared_prefix: Option, 28 | } 29 | 30 | impl ImapResponse for Response { 31 | fn serialize(self) -> Vec { 32 | let mut buf = Vec::with_capacity(64); 33 | if let Some(shared_prefix) = &self.shared_prefix { 34 | buf.extend_from_slice(b"* NAMESPACE ((\"\" \"/\")) (("); 35 | quoted_string(&mut buf, shared_prefix); 36 | buf.extend_from_slice(b" \"/\")) NIL\r\n"); 37 | } else { 38 | buf.extend_from_slice(b"* NAMESPACE ((\"\" \"/\")) NIL NIL\r\n"); 39 | } 40 | buf 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/protocol/rename.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct Arguments { 26 | pub tag: String, 27 | pub mailbox_name: String, 28 | pub new_mailbox_name: String, 29 | } 30 | -------------------------------------------------------------------------------- /src/protocol/store.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::core::Flag; 25 | 26 | use super::{fetch::FetchItem, ImapResponse, Sequence}; 27 | 28 | #[derive(Debug, Clone, PartialEq, Eq)] 29 | pub struct Arguments { 30 | pub tag: String, 31 | pub sequence_set: Sequence, 32 | pub operation: Operation, 33 | pub is_silent: bool, 34 | pub keywords: Vec, 35 | pub unchanged_since: Option, 36 | } 37 | 38 | #[derive(Debug, Clone, PartialEq, Eq)] 39 | pub enum Operation { 40 | Set, 41 | Add, 42 | Clear, 43 | } 44 | 45 | #[derive(Debug, Clone, PartialEq, Eq)] 46 | pub struct Response<'x> { 47 | pub items: Vec>, 48 | } 49 | 50 | impl<'x> ImapResponse for Response<'x> { 51 | fn serialize(self) -> Vec { 52 | let mut buf = Vec::with_capacity(64); 53 | for item in &self.items { 54 | item.serialize(&mut buf); 55 | } 56 | buf 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/protocol/subscribe.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | #[derive(Debug, Clone, PartialEq, Eq)] 25 | pub struct Arguments { 26 | pub tag: String, 27 | pub mailbox_name: String, 28 | } 29 | -------------------------------------------------------------------------------- /src/protocol/thread.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use super::{search::Filter, ImapResponse}; 25 | 26 | #[derive(Debug, Clone, PartialEq, Eq)] 27 | pub struct Arguments { 28 | pub tag: String, 29 | pub filter: Filter, 30 | pub algorithm: Algorithm, 31 | } 32 | 33 | #[derive(Debug, Clone, PartialEq, Eq)] 34 | pub enum Algorithm { 35 | OrderedSubject, 36 | References, 37 | } 38 | 39 | #[derive(Debug, Clone, PartialEq, Eq)] 40 | pub struct Response { 41 | pub is_uid: bool, 42 | pub threads: Vec>, 43 | } 44 | 45 | impl ImapResponse for Response { 46 | fn serialize(self) -> Vec { 47 | let mut buf = Vec::with_capacity(64); 48 | buf.extend_from_slice(b"* THREAD "); 49 | for thread in &self.threads { 50 | buf.push(b'('); 51 | for (pos, id) in thread.iter().enumerate() { 52 | if pos > 0 { 53 | buf.push(b' '); 54 | } 55 | buf.extend_from_slice(id.to_string().as_bytes()); 56 | } 57 | buf.push(b')'); 58 | } 59 | buf.extend_from_slice(b"\r\n"); 60 | buf 61 | } 62 | } 63 | 64 | #[cfg(test)] 65 | mod tests { 66 | use crate::protocol::ImapResponse; 67 | 68 | #[test] 69 | fn serialize_thread() { 70 | assert_eq!( 71 | String::from_utf8( 72 | super::Response { 73 | is_uid: true, 74 | threads: vec![vec![2, 10, 11], vec![49], vec![1, 3]], 75 | } 76 | .serialize() 77 | ) 78 | .unwrap(), 79 | concat!("* THREAD (2 10 11)(49)(1 3)\r\n",) 80 | ); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/tests/basic.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::core::ResponseType; 25 | 26 | use super::{AssertResult, ImapConnection, Type}; 27 | 28 | pub async fn test(imap: &mut ImapConnection, _imap_check: &mut ImapConnection) { 29 | // Test CAPABILITY 30 | imap.send("CAPABILITY").await; 31 | imap.assert_read(Type::Tagged, ResponseType::Ok).await; 32 | 33 | // Test NOOP 34 | imap.send("NOOP").await; 35 | imap.assert_read(Type::Tagged, ResponseType::Ok).await; 36 | 37 | // Test ID 38 | imap.send("ID").await; 39 | imap.assert_read(Type::Tagged, ResponseType::Ok) 40 | .await 41 | .assert_contains("* ID (\"name\" \"Stalwart IMAP\" \"version\" "); 42 | 43 | // Login should be disabled 44 | imap.send("LOGIN jdoe@example.com secret").await; 45 | imap.assert_read(Type::Tagged, ResponseType::No).await; 46 | 47 | // Try logging in with wrong password 48 | imap.send("AUTHENTICATE PLAIN {24}").await; 49 | imap.assert_read(Type::Continuation, ResponseType::Ok).await; 50 | imap.send_untagged("AGJvYXR5AG1jYm9hdGZhY2U=").await; 51 | imap.assert_read(Type::Tagged, ResponseType::No).await; 52 | } 53 | -------------------------------------------------------------------------------- /src/tests/resources/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFCTCCAvGgAwIBAgIUCgHGQYUqtelbHGVSzCVwBL3fyEUwDQYJKoZIhvcNAQEL 3 | BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIyMDUxNjExNDAzNFoXDTIzMDUx 4 | NjExNDAzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF 5 | AAOCAg8AMIICCgKCAgEAtwS0Fzl3SjaCuKEXgZ/fdWbDoj/qDphyNCAKNevQ0+D0 6 | STNkWCO04aFSH0zcL8zoD9gokNos0i7OU9//ZhZQmex4V6EFdZn8bFwUWN/scUvW 7 | HEFXVjtHldO2isZgIxH9LuwRv7KAgkISuWahqerOVDhe7SeQUV0AJGNEh3cT9PZr 8 | gSY931BxB7n+5k8eoSk8Z1gtBzQzL62kVGpHDKfw8yX8m65owF9eLUBrNzgxmXfC 9 | xpuHwj7hmVhS09PPKeN/RsFS8PsYO7bo0u8jEKalteumjRT7RyUEbioqfo6ZFOGj 10 | FHPIq/uKXS9zN1fpoyNh3ur5hMznQhrqlwBM9KlM7GdBJ0pZ3ad0YjT8IL/GnGKR 11 | 85J2WZdLqaQdUZo7nV67FhqdDlNE4MdwiykTMjfmLRXGAVhAzJHKyRKNwmkI2aqe 12 | S7aqeNgvuDBwY80Q9a2rb5py1Aw+L8yCkUBuHboToDpxSVRDNN8DrWNmmsXnxsOG 13 | wRDODy4GICKyxlP+RFSM8xWSQ6y9ktS2OfDBm+Eqcw+3pZKhdz2wgxLkUBJ8X1eh 14 | kJrCA/6LTuhy6m6mMjAfoSOFU7fu88jxaWPgvP7GKyH+LM/t9eucobz2ks5rtSjz 15 | V4Dc5DCS94/OpVRHwHdaFSPbJKBN9Ev8gnNrAyx/aBPGoHBPG/QUiU7dcUNIPt0C 16 | AwEAAaNTMFEwHQYDVR0OBBYEFI167IxBmErB11EqiPPqFLa31ZaMMB8GA1UdIwQY 17 | MBaAFI167IxBmErB11EqiPPqFLa31ZaMMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI 18 | hvcNAQELBQADggIBALU00IOiH5ubEauVCmakms5ermNTZfculnhnDfWTLMeh2+a7 19 | G4cqADErfMhm/mmLbrw33t9s6tCAhQltvewKR40ST9uMPSyiQbYaCXd5DXnuI6Ox 20 | JtNW+UOWIaMf8abnkdLvREOvb8dVQS1i3xq14tAjY5XgpGwCPP8m54b7N3Q7soLn 21 | e5PDhPNTnhRIn2RLuYoZmQmMA5fcqEUDYff4epUww7PhrM1QckZligI3566NlGOf 22 | j1G9JrivBtY0eaJtamIFnGMBT0ThDudxVja2Nv0C2Elry0p4T/o4nc4M67BJ/y1R 23 | vjNLAgFhbxssemU3lZqSd+pykpJBwDBjFSPrZZmQcbk7H6Uz8V1xr/xuzfw6fA13 24 | NWZ5vLgP/DQ13sM+XFlxThKfbPMPVe/UCTvfGtNW+3XyBgPntEkR+fNEawQmzbYl 25 | R+X1ymT9MZnEZqRMf7/UD/SYek1aUJefoew3upjMgxYVvh4F8dqJ+39F+xoFzIA2 26 | 1dDAEMzXtjA3zKhZ2cycZbEzpJvYA3eGLuR16Suqfi4kPvfwK0mOhCxQmpayt7/X 27 | vuEzW6dPCH8Hgbb0WvsSppGOvhdbDaZFNfFc5eNSxhyKzu3H3ACNImZRtZE+yixx 28 | 0fR8+xz9kDLf8xupV+X9heyFGHSyYU2Lveaevtr2Ij3weLRgJ6LbNALoeKXk 29 | -----END CERTIFICATE----- 30 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/append: -------------------------------------------------------------------------------- 1 | connections: 3 2 | state: created 3 | 4 | 1 ok select $mailbox 5 | 2 ok select $mailbox 6 | 7 | # Two connections have mailbox SELECTed, one doesn't. 8 | # The \recent flags can be given to either one of the SELECTed connections, 9 | # but never for the 3rd. We rely on mailbox state tracking to catch duplicate 10 | # \recent flags (which is why there are two FETCH FLAGS commands). 11 | 12 | 1 ok append $mailbox (\seen \flagged) 13 | * 1 exists 14 | 2 ok noop 15 | * 1 exists 16 | 3 ok status $mailbox (messages unseen recent) 17 | * status $mailbox (messages 1 unseen 0 recent 0) 18 | 1 ok fetch 1 (uid flags) 19 | * 1 fetch (uid $uid1 flags (\seen \flagged)) 20 | 2 ok fetch 1 (uid flags) 21 | * 1 fetch (uid $uid1 flags (\seen \flagged)) 22 | 23 | 2 ok append 24 | * 2 exists 25 | 1 ok noop 26 | * 2 exists 27 | 3 ok status $mailbox (messages unseen recent) 28 | * status $mailbox (messages 2 unseen 1 recent 0) 29 | 1 ok fetch 2 (uid flags) 30 | 2 ok fetch 2 (uid flags) 31 | 32 | 3 ok append 33 | 3 ok status $mailbox (messages unseen) 34 | * status $mailbox (messages 3 unseen 2) 35 | 2 ok noop 36 | * 3 exists 37 | 1 ok noop 38 | * 3 exists 39 | 1 ok fetch 3 (uid flags) 40 | 2 ok fetch 3 (uid flags) 41 | 42 | 1 append ${mailbox}nonexistent 43 | no [trycreate] 44 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/append-binary: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stalwartlabs/imap-to-jmap/6c4f5b78e6e2a5ff7287f59fd60112d8f0c2cbc7/src/tests/resources/imap-test/append-binary -------------------------------------------------------------------------------- /src/tests/resources/imap-test/atoms: -------------------------------------------------------------------------------- 1 | state: auth 2 | 3 | # Don't confuse with ~{literal8} 4 | ok list "" ~foo 5 | no select ~foo 6 | 7 | # atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / 8 | # quoted-specials / resp-specials 9 | # quoted-specials = DQUOTE / "\" 10 | # resp-specials = "]" 11 | # list-wildcards = "%" / "*" 12 | no select !#$$&'+,-.0123456789:;<=>?@^_`|[} 13 | ok list "" !#$$&'+,-.0123456789:;<=>?@^_`|[}%* 14 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/broken/search-intdate: -------------------------------------------------------------------------------- 1 | # this test assumes that server stores INTERNALDATE timestamps in 2 | # EET/EEST timezones (or stores/fetches them using the same timezones as 3 | # they were APPENDed with) 4 | 5 | # 1) Timezone changes from EET +0200 -> EEST +0300 6 | # 1a) BEFORE 7 | ok search before 24-mar-2007 8 | * search 9 | ok search before 25-mar-2007 10 | * search 1 11 | ok search before 26-mar-2007 12 | * search 1 2 3 4 5 6 13 | ok search before 27-mar-2007 14 | * search 1 2 3 4 5 6 7 15 | 16 | # 1b) ON 17 | ok search on 23-mar-2007 18 | * search 19 | ok search on 24-mar-2007 20 | * search 1 21 | ok search on 25-mar-2007 22 | * search 2 3 4 5 6 23 | ok search on 26-mar-2007 24 | * search 7 25 | 26 | # 1c) SINCE 27 | ok search 1:7 since 24-mar-2007 28 | * search 1 2 3 4 5 6 7 29 | ok search 1:7 since 25-mar-2007 30 | * search 2 3 4 5 6 7 31 | ok search 1:7 since 26-mar-2007 32 | * search 7 33 | ok search 1:7 since 27-mar-2007 34 | * search 35 | 36 | # 2) Timezone changes from EEST +0300 -> EET +0200 37 | # 2a) BEFORE 38 | ok search 8:* before 27-oct-2007 39 | * search 40 | ok search 8:* before 28-oct-2007 41 | * search 8 42 | ok search 8:* before 29-oct-2007 43 | * search 8 9 10 11 12 13 14 15 44 | ok search 8:* before 30-oct-2007 45 | * search 8 9 10 11 12 13 14 15 16 46 | 47 | # 2b) ON 48 | ok search 8:* on 26-oct-2007 49 | * search 50 | ok search 8:* on 27-oct-2007 51 | * search 8 52 | ok search 8:* on 28-oct-2007 53 | * search 9 10 11 12 13 14 15 54 | ok search 8:* on 29-oct-2007 55 | * search 16 56 | 57 | # 2c) SINCE 58 | ok search 8:* since 27-oct-2007 59 | * search 8 9 10 11 12 13 14 15 16 60 | ok search 8:* since 28-oct-2007 61 | * search 9 10 11 12 13 14 15 16 62 | ok search 8:* since 29-oct-2007 63 | * search 16 64 | ok search 8:* since 30-oct-2007 65 | * search 66 | 67 | # 3) Try a couple of NOTs 68 | ok search 1:7 not before 26-mar-2007 69 | * search 7 70 | ok search 1:7 not on 25-mar-2007 71 | * search 1 7 72 | ok search 8:* not since 28-oct-2007 73 | * search 8 74 | ok search 8:* not on 28-oct-2007 75 | * search 8 16 76 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/broken/search-intdate.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Sat Mar 24 23:00:00 2007 +0200 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | 4 | body 5 | 6 | From user@domain Sun Mar 25 00:00:00 2007 +0200 7 | Date: Sat, 24 Mar 2007 23:00:00 +0200 8 | 9 | body 10 | 11 | From user@domain Sun Mar 25 01:00:00 2007 +0200 12 | Date: Sat, 24 Mar 2007 23:00:00 +0200 13 | 14 | body 15 | 16 | From user@domain Sun Mar 25 02:00:00 2007 +0200 17 | Date: Sat, 24 Mar 2007 23:00:00 +0200 18 | 19 | body 20 | 21 | From user@domain Sun Mar 25 04:00:00 2007 +0300 22 | Date: Sat, 24 Mar 2007 23:00:00 +0200 23 | 24 | body 25 | 26 | From user@domain Sun Mar 25 23:00:00 2007 +0300 27 | Date: Sat, 24 Mar 2007 23:00:00 +0200 28 | 29 | body 30 | 31 | From user@domain Mon Mar 26 00:00:00 2007 +0300 32 | Date: Sat, 24 Mar 2007 23:00:00 +0200 33 | 34 | body 35 | 36 | From user@domain Sat Oct 27 23:00:00 2007 +0300 37 | Date: Sat, 24 Mar 2007 23:00:00 +0200 38 | 39 | body 40 | 41 | From user@domain Sun Oct 28 00:00:00 2007 +0300 42 | Date: Sat, 24 Mar 2007 23:00:00 +0200 43 | 44 | body 45 | 46 | From user@domain Sun Oct 28 01:00:00 2007 +0300 47 | Date: Sat, 24 Mar 2007 23:00:00 +0200 48 | 49 | body 50 | 51 | From user@domain Sun Oct 28 02:00:00 2007 +0300 52 | Date: Sat, 24 Mar 2007 23:00:00 +0200 53 | 54 | body 55 | 56 | From user@domain Sun Oct 28 03:00:00 2007 +0300 57 | Date: Sat, 24 Mar 2007 23:00:00 +0200 58 | 59 | body 60 | 61 | From user@domain Sun Oct 28 03:00:00 2007 +0200 62 | Date: Sat, 24 Mar 2007 23:00:00 +0200 63 | 64 | body 65 | 66 | From user@domain Sun Oct 28 04:00:00 2007 +0200 67 | Date: Sat, 24 Mar 2007 23:00:00 +0200 68 | 69 | body 70 | 71 | From user@domain Sun Oct 28 23:00:00 2007 +0200 72 | Date: Sat, 24 Mar 2007 23:00:00 +0200 73 | 74 | body 75 | 76 | From user@domain Mon Oct 29 00:00:00 2007 +0200 77 | Date: Sat, 24 Mar 2007 23:00:00 +0200 78 | 79 | body 80 | 81 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/catenate-multiappend: -------------------------------------------------------------------------------- 1 | state: created 2 | capabilities: CATENATE MULTIAPPEND 3 | 4 | ok append $mailbox catenate (text {{{ 5 | From: foo@example.com 6 | 7 | Hello world body 8 | 9 | }}}) catenate (text {{{ 10 | From: bar@example.com 11 | 12 | Second body 13 | 14 | }}}) 15 | 16 | ok select $mailbox 17 | * ok [uidvalidity $uidv] 18 | 19 | ok fetch 1:2 (uid body.peek[]) 20 | * 1 fetch (uid $uid body[] {{{ 21 | From: foo@example.com 22 | 23 | Hello world body 24 | 25 | }}}) 26 | * 2 fetch (uid $uid2 body[] {{{ 27 | From: bar@example.com 28 | 29 | Second body 30 | 31 | }}}) 32 | 33 | ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid/;section=header" text {{{ 34 | body1 35 | 36 | }}}) catenate (url "/$mailbox_url/;uid=$uid2/;section=header" text {{{ 37 | body2 38 | 39 | }}}) 40 | 41 | ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid") catenate (url "/$mailbox_url/;uid=$uid2/;section=header" text {{{ 42 | body3 43 | 44 | }}}) 45 | 46 | ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid") {{{ 47 | New: Message 48 | 49 | body4 50 | 51 | }}} 52 | 53 | ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid") (\answered) {{{ 54 | New: Message 55 | 56 | body5 57 | 58 | }}} 59 | 60 | ok noop 61 | 62 | ok fetch 3:* body.peek[] 63 | * 3 fetch (body[] {{{ 64 | From: foo@example.com 65 | 66 | body1 67 | 68 | }}}) 69 | * 4 fetch (body[] {{{ 70 | From: bar@example.com 71 | 72 | body2 73 | 74 | }}}) 75 | * 5 fetch (body[] {{{ 76 | From: foo@example.com 77 | 78 | Hello world body 79 | 80 | }}}) 81 | * 6 fetch (body[] {{{ 82 | From: bar@example.com 83 | 84 | body3 85 | 86 | }}}) 87 | * 7 fetch (body[] {{{ 88 | From: foo@example.com 89 | 90 | Hello world body 91 | 92 | }}}) 93 | * 8 fetch (body[] {{{ 94 | New: Message 95 | 96 | body4 97 | 98 | }}}) 99 | * 9 fetch (body[] {{{ 100 | From: foo@example.com 101 | 102 | Hello world body 103 | 104 | }}}) 105 | * 10 fetch (body[] {{{ 106 | New: Message 107 | 108 | body5 109 | 110 | }}}) 111 | 112 | # 113 | # Try invalid URLs 114 | # 115 | 116 | no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") catenate (url "/$mailbox_url/;uid=$uid") 117 | 118 | no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") catenate (url "/$mailbox_url/;uid=$uid" text {{{ 119 | hello 120 | }}}) 121 | 122 | no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") catenate (text {{{ 123 | hello 124 | }}}) 125 | 126 | no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") {{{ 127 | hello 128 | }}} 129 | 130 | ok noop 131 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/close: -------------------------------------------------------------------------------- 1 | connections: 2 2 | messages: 3 3 | 4 | 1 ok store 1,3 +flags \deleted 5 | 1 ok close 6 | 7 | 2 ok noop 8 | * $1 expunge 9 | * $3 expunge 10 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/copy: -------------------------------------------------------------------------------- 1 | connections: 2 2 | state: created 3 | 4 | 1 ok select ${mailbox} 5 | 1 ok append 6 | 1 ok append 7 | 1 ok append 8 | 1 ok append 9 | 1 ok append 10 | # make sure the server sees the appended messages 11 | 1 ok check 12 | 13 | 2 "" delete ${mailbox}2 14 | 2 ok create ${mailbox}2 15 | 2 ok select ${mailbox}2 16 | 17 | 1 ok store 1 flags (\seen) 18 | 1 ok store 2 flags (\answered \flagged) 19 | 1 ok store 5 flags (\flagged $$keyword1 $$keyword2) 20 | 21 | 1 ok fetch 1:5 (internaldate) 22 | * 1 fetch (internaldate $date1) 23 | * 2 fetch (internaldate $date2) 24 | * 4 fetch (internaldate $date4) 25 | * 5 fetch (internaldate $date5) 26 | 1 ok copy 1:2,4 ${mailbox}2 27 | 28 | 2 ok noop 29 | * 3 exists 30 | #* 3 recent 31 | 32 | 2 ok fetch 1:3 (flags internaldate) 33 | * 3 fetch (flags (\seen) internaldate $date1) 34 | * 2 fetch (flags (\answered \flagged) internaldate $date2) 35 | * 1 fetch (flags () internaldate $date4) 36 | 37 | # keywords aren't required to be created on COPY, so help the server here 38 | 2 ok store 3 +flags ($$keyword1 $$keyword2) 39 | 40 | 1 ok copy 5 ${mailbox}2 41 | 2 ok noop 42 | * 4 exists 43 | 44 | 2 ok fetch 4 (flags internaldate) 45 | * 4 fetch (flags (\flagged $$keyword1 $$keyword2) internaldate $date5) 46 | 47 | 2 ok close 48 | 2 "" delete ${mailbox}2 49 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/default.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user1@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Subject: s1 5 | 6 | body1 7 | 8 | From user@domain Fri Feb 22 17:06:23 2008 9 | From: user2@domain.org 10 | Date: Sat, 24 Mar 2007 23:00:00 +0200 11 | Subject: s22 12 | 13 | body22 14 | 15 | From user@domain Fri Feb 22 17:06:23 2008 16 | From: user3@domain.org 17 | Date: Sat, 24 Mar 2007 23:00:00 +0200 18 | Subject: s333 19 | 20 | body33 21 | 22 | From user@domain Fri Feb 22 17:06:23 2008 23 | From: user4@domain.org 24 | Date: Sat, 24 Mar 2007 23:00:00 +0200 25 | Subject: s4444 26 | 27 | body4444 28 | 29 | From user@domain Fri Feb 22 17:06:23 2008 30 | From: user5@domain.org 31 | Date: Sat, 24 Mar 2007 23:00:00 +0200 32 | Subject: s55555 33 | 34 | body55555 35 | 36 | From user@domain Fri Feb 22 17:06:23 2008 37 | From: user6@domain.org 38 | Date: Sat, 24 Mar 2007 23:00:00 +0200 39 | Subject: s666666 40 | 41 | body666666 42 | 43 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/esearch: -------------------------------------------------------------------------------- 1 | capabilities: ESEARCH 2 | messages: all 3 | 4 | ok store 4 +flags \deleted 5 | ok expunge 6 | 7 | # SEARCH ALL 8 | 9 | ok search return (all) all 10 | * esearch (tag $tag) all 1:6 11 | ok search return () all 12 | * esearch (tag $tag) all 1:6 13 | ok search return (min) all 14 | * esearch (tag $tag) min 1 15 | ok search return (max) all 16 | * esearch (tag $tag) max 6 17 | ok search return (count) all 18 | * esearch (tag $tag) count 6 19 | 20 | # UID SEARCH ALL 21 | 22 | ok fetch 1:* UID 23 | * 1 fetch (uid $uid1) 24 | * 2 fetch (uid $uid2) 25 | * 3 fetch (uid $uid3) 26 | * 4 fetch (uid $uid4) 27 | * 5 fetch (uid $uid5) 28 | * 6 fetch (uid $uid6) 29 | 30 | ok uid search return (all) all 31 | * esearch (tag $tag) uid all $uid1:$uid3,$uid4:$uid6 32 | ok uid search return () all 33 | * esearch (tag $tag) uid all $uid1:$uid3,$uid4:$uid6 34 | ok uid search return (min) all 35 | * esearch (tag $tag) uid min $uid1 36 | ok uid search return (max) all 37 | * esearch (tag $tag) uid max $uid6 38 | ok uid search return (count) all 39 | * esearch (tag $tag) uid count 6 40 | 41 | # \Seen flag test 42 | 43 | ok store 2,4 +flags \seen 44 | 45 | ok uid search return (all) seen 46 | * esearch (tag $tag) uid all $uid2,$uid4 47 | ok uid search return () seen 48 | * esearch (tag $tag) uid all $uid2,$uid4 49 | ok uid search return (min) seen 50 | * esearch (tag $tag) uid min $uid2 51 | ok uid search return (max) seen 52 | * esearch (tag $tag) uid max $uid4 53 | ok uid search return (count) seen 54 | * esearch (tag $tag) uid count 2 55 | 56 | # nonexistent 57 | 58 | ok search return () 1000 59 | * esearch (tag $tag) 60 | ok search return (min) 1000 61 | * esearch (tag $tag) 62 | ok search return (max) 1000 63 | * esearch (tag $tag) 64 | ok search return (count) 1000 65 | * esearch (tag $tag) count 0 66 | 67 | # UID nonexistent 68 | 69 | ok uid search return () 1000 70 | * esearch (tag $tag) uid 71 | ok uid search return (min) 1000 72 | * esearch (tag $tag) uid 73 | ok uid search return (max) 1000 74 | * esearch (tag $tag) uid 75 | ok uid search return (count) 1000 76 | * esearch (tag $tag) uid count 0 77 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/esearch-condstore: -------------------------------------------------------------------------------- 1 | capabilities: ESEARCH CONDSTORE 2 | messages: 4 3 | 4 | # ENABLE is valid only in authenticated state. we could do enable+select 5 | # manually here also, but lets just make sure that switching it on via 6 | # condstore-enabling command works as well (since that is valid) 7 | ok fetch 1 modseq 8 | * ok [highestmodseq $highestmodseq] 9 | 10 | ok store 1 +flags \seen 11 | * 1 fetch (modseq ($modseq1)) 12 | ok store 3 +flags \seen 13 | * 3 fetch (modseq ($modseq3)) 14 | ok store 2 +flags \seen 15 | * 2 fetch (modseq ($modseq2)) 16 | ok store 4 +flags \seen 17 | * 4 fetch (modseq ($modseq4)) 18 | 19 | ok search return (min) 1:3 modseq "/flags/\\seen" all $highestmodseq 20 | * esearch (tag $tag) min 1 modseq $modseq4 21 | 22 | ok search return (max) 1:3 modseq "/flags/\\seen" all $highestmodseq 23 | * esearch (tag $tag) max 3 modseq $modseq4 24 | 25 | ok search return () 1:3 modseq "/flags/\\seen" all $highestmodseq 26 | * esearch (tag $tag) all 1:3 modseq $modseq4 27 | 28 | ok search return (min max) 2:3 modseq "/flags/\\seen" all $highestmodseq 29 | * esearch (tag $tag) min 2 max 3 modseq $modseq4 30 | 31 | ok search return (all) 2:4 modseq "/flags/\\seen" all $modseq3 32 | * esearch (tag $tag) all 2,4 modseq $modseq4 33 | 34 | ok search return (all) 2:4 modseq "/flags/\\seen" all $modseq2 35 | * esearch (tag $tag) all 4 modseq $modseq4 36 | 37 | ok search return (all) 2:4 modseq "/flags/\\seen" all $modseq4 38 | * esearch (tag $tag) modseq $modseq4 39 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/esearch.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:21 2008 2 | 3 | 1 4 | 5 | From user@domain Fri Feb 22 17:06:22 2008 6 | 7 | 2 8 | 9 | From user@domain Fri Feb 22 17:06:23 2008 10 | 11 | 3 12 | 13 | From user@domain Fri Feb 22 17:06:23 2008 14 | 15 | 4 16 | 17 | From user@domain Fri Feb 22 17:06:25 2008 18 | 19 | 5 20 | 21 | From user@domain Fri Feb 22 17:06:25 2008 22 | 23 | 6 24 | 25 | From user@domain Fri Feb 22 17:06:25 2008 26 | 27 | 7 28 | 29 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/esort: -------------------------------------------------------------------------------- 1 | capabilities: ESORT 2 | messages: 5 3 | 4 | ok sort return (min) (arrival) us-ascii 1:5 5 | * esearch (tag $tag) min 1 6 | ok sort return (max) (arrival) us-ascii 1:5 7 | * esearch (tag $tag) max 5 8 | ok sort return (all) (arrival) us-ascii 1:5 9 | * esearch (tag $tag) all 1:5 10 | ok sort return (count) (arrival) us-ascii 1:5 11 | * esearch (tag $tag) count 5 12 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/expunge: -------------------------------------------------------------------------------- 1 | connections: 2 2 | messages: 8 3 | 4 | # get UIDs 5 | 1 ok fetch 1:4 uid 6 | * 1 fetch (uid $uid1) 7 | * 2 fetch (uid $uid2) 8 | * 3 fetch (uid $uid3) 9 | * 4 fetch (uid $uid4) 10 | 11 | # 1) test that expunges work ok and session 2 fetch sees 1's flag changes. 12 | 1 ok store 1,3 flags \deleted 13 | * 1 fetch (flags (\deleted)) 14 | * 3 fetch (flags (\deleted)) 15 | 1 ok store 2,4 flags \seen 16 | * 2 fetch (flags (\seen)) 17 | * 4 fetch (flags (\seen)) 18 | 1 ok expunge 19 | * $1 expunge 20 | * $3 expunge 21 | 22 | 2 ok fetch 2,4 (uid) 23 | * 2 fetch (uid $uid2) 24 | * 4 fetch (uid $uid4) 25 | 2 ok fetch 2,4 (uid) 26 | * 2 fetch (uid $uid2) 27 | * 4 fetch (uid $uid4) 28 | 2 ok check 29 | * $1 expunge 30 | * $3 expunge 31 | 2 ok fetch 1:2 (uid flags) 32 | * 1 fetch (uid $uid2 flags (\seen)) 33 | * 2 fetch (uid $uid4 flags (\seen)) 34 | 35 | # 2) test that session 2 can update flags while some messages are expunged 36 | 1 ok store 2 +flags \deleted 37 | 1 ok expunge 38 | 39 | 2 ok store 1 flags \answered 40 | * 1 fetch (flags (\answered)) 41 | 1 ok check 42 | * 1 fetch (flags (\answered)) 43 | 2 ok noop 44 | * 2 expunge 45 | 46 | # 3) check notices flag changes correctly with expunges 47 | 1 ok store 1,3 +flags \deleted 48 | 1 ok store 2,4 flags \flagged 49 | 1 ok expunge 50 | 2 ok check 51 | * $1 expunge 52 | * $2 fetch (flags (\flagged)) 53 | * $3 expunge 54 | * $4 fetch (flags (\flagged)) 55 | 56 | # 4) expunging while message is already expunged 57 | 1 ok store 1 +flags \deleted 58 | 2 ok store 1 +flags \deleted 59 | 1 ok expunge 60 | * 1 expunge 61 | 2 ok expunge 62 | * 1 expunge 63 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/expunge2: -------------------------------------------------------------------------------- 1 | connections: 2 2 | messages: 6 3 | 4 | 1 ok fetch 2,4 uid 5 | * 2 fetch (uid $uid2) 6 | * 4 fetch (uid $uid4) 7 | 8 | # UID FETCH 9 | 1 ok store 1,3 +flags \deleted 10 | 1 ok expunge 11 | * $1 expunge 12 | * $3 expunge 13 | 14 | 2 ok uid fetch $uid2,$uid4 uid 15 | * $2 fetch (uid $uid2) 16 | * $4 fetch (uid $uid4) 17 | 2 ok noop 18 | 19 | # UID STORE 20 | 1 ok store 1 +flags \deleted 21 | 1 ok expunge 22 | * 1 expunge 23 | 24 | 2 ok uid store $uid4 flags \seen 25 | * $2 fetch (uid $uid4 flags (\seen)) 26 | 2 ok noop 27 | 28 | # Make sure CHECK works just as well as NOOP 29 | 1 ok store 1 +flags \deleted 30 | 1 ok expunge 31 | * 1 expunge 32 | 2 ok check 33 | * 1 expunge 34 | 35 | # Make sure FETCH, STORE and SEARCH don't trigger EXPUNGE 36 | 1 ok store 1 +flags \deleted 37 | 1 ok expunge 38 | 39 | 2 ok fetch 2 flags 40 | ! $1 expunge 41 | 2 ok store 2 flags (\seen) 42 | ! $1 expunge 43 | 2 ok search all 44 | ! $1 expunge 45 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch: -------------------------------------------------------------------------------- 1 | messages: 3 2 | 3 | ok status $mailbox (uidnext) 4 | * status $mailbox (uidnext $uidnext) 5 | 6 | ok fetch 1:3 uid 7 | * 1 fetch (uid $uid1) 8 | * 2 fetch (uid $uid2) 9 | * 3 fetch (uid $uid3) 10 | 11 | ok fetch 3:1 uid 12 | * 1 fetch (uid $uid1) 13 | * 2 fetch (uid $uid2) 14 | * 3 fetch (uid $uid3) 15 | 16 | ok fetch 1,* uid 17 | * 1 fetch (uid $uid1) 18 | * 3 fetch (uid $uid3) 19 | 20 | ok fetch * uid 21 | * 3 fetch (uid $uid3) 22 | 23 | ok fetch *:1 uid 24 | * 1 fetch (uid $uid1) 25 | * 2 fetch (uid $uid2) 26 | * 3 fetch (uid $uid3) 27 | 28 | ok uid fetch $uidnext:* uid 29 | * 3 fetch (uid $uid3) 30 | 31 | # break seq=uid map 32 | ok store 2 flags \deleted 33 | ok expunge 34 | * 2 expunge 35 | 36 | ok uid fetch $uidnext:* uid 37 | * 2 fetch (uid $uid3) 38 | ok uid fetch 1:* uid 39 | * 1 fetch (uid $uid1) 40 | * 2 fetch (uid $uid3) 41 | ok uid fetch $uid2 uid 42 | ! 1 fetch (uid $uid1) 43 | ! 2 fetch (uid $uid3) 44 | ok uid fetch $uid1,* uid 45 | * 1 fetch (uid $uid1) 46 | * 2 fetch (uid $uid3) 47 | 48 | # test macros 49 | ok fetch 1 full 50 | * 1 fetch (flags () internaldate $intdate1 rfc822.size $size1 envelope ($!unordered) body ($!unordered)) 51 | ok fetch 1 all 52 | * 1 fetch (flags () internaldate $intdate1 rfc822.size $size1 envelope ($!unordered)) 53 | ok fetch 1 fast 54 | * 1 fetch (flags () internaldate $intdate1 rfc822.size $size1) 55 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-binary-mime: -------------------------------------------------------------------------------- 1 | capabilities: BINARY 2 | messages: all 3 | 4 | # This is the fetch-body-mime test, except with body[] changed to binary[]. 5 | # The idea is to verify that binary[] works correctly when it doesn't actually 6 | # have to convert anything. 7 | 8 | ok fetch 1 (binary.peek[]) 9 | * 1 fetch (binary[] {{{ 10 | From: user@domain.org 11 | Date: Sat, 24 Mar 2007 23:00:00 +0200 12 | Mime-Version: 1.0 13 | Content-Type: multipart/mixed; boundary="foo 14 | bar" 15 | 16 | Root MIME prologue 17 | 18 | --foo bar 19 | Content-Type: text/x-myown; charset=us-ascii 20 | 21 | hello 22 | 23 | --foo bar 24 | Content-Type: message/rfc822 25 | 26 | From: sub@domain.org 27 | Date: Sun, 12 Aug 2012 12:34:56 +0300 28 | Subject: submsg 29 | Content-Type: multipart/alternative; boundary="sub1" 30 | 31 | Sub MIME prologue 32 | --sub1 33 | Content-Type: text/html 34 | 35 |

Hello world

36 | 37 | --sub1 38 | Content-Type: text/plain 39 | 40 | Hello another world 41 | 42 | --sub1-- 43 | Sub MIME epilogue 44 | 45 | --foo bar-- 46 | Root MIME epilogue 47 | 48 | }}}) 49 | 50 | ok fetch 1 (binary.size[]) 51 | * 1 fetch (binary.size[] 602) 52 | 53 | ok fetch 1 (binary.size[1]) 54 | * 1 fetch (binary.size[1] 7) 55 | 56 | ok fetch 1 (binary.peek[1]) 57 | * 1 fetch (binary[1] {{{ 58 | hello 59 | 60 | }}}) 61 | 62 | ok fetch 1 (binary.peek[2]) 63 | * 1 fetch (binary[2] {{{ 64 | From: sub@domain.org 65 | Date: Sun, 12 Aug 2012 12:34:56 +0300 66 | Subject: submsg 67 | Content-Type: multipart/alternative; boundary="sub1" 68 | 69 | Sub MIME prologue 70 | --sub1 71 | Content-Type: text/html 72 | 73 |

Hello world

74 | 75 | --sub1 76 | Content-Type: text/plain 77 | 78 | Hello another world 79 | 80 | --sub1-- 81 | Sub MIME epilogue 82 | 83 | }}}) 84 | 85 | ok fetch 1 (binary.size[2]) 86 | * 1 fetch (binary.size[2] 298) 87 | 88 | ok fetch 1 (binary.size[2.1]) 89 | * 1 fetch (binary.size[2.1] 20) 90 | 91 | ok fetch 1 (binary.peek[2.1]) 92 | * 1 fetch (binary[2.1] {{{ 93 |

Hello world

94 | 95 | }}}) 96 | 97 | ok fetch 1 (binary.peek[2.2]) 98 | * 1 fetch (binary[2.2] {{{ 99 | Hello another world 100 | 101 | }}}) 102 | 103 | ok fetch 1 (binary.size[2.2]) 104 | * 1 fetch (binary.size[2.2] 21) 105 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-binary-mime-base64: -------------------------------------------------------------------------------- 1 | capabilities: BINARY 2 | messages: all 3 | 4 | ok fetch 1 (binary.size[1] binary.size[5]) 5 | * 1 fetch (binary.size[1] 11 binary.size[5] 30) 6 | 7 | ok fetch 1 (binary.peek[1] binary.peek[2] binary.peek[3] binary.peek[4] binary.peek[5]) 8 | * 1 fetch (binary[1] {{{ 9 | hello world 10 | }}} binary[2] {{{ 11 | hello world 12 | }}} binary[3] {{{ 13 | hello to you too 14 | }}} binary[4] {{{ 15 | hello to everyone! 16 | }}} binary[5] ~{{{ 17 | abcdefg hijkl 18 | mno 19 | pqrstuvqxyz 20 | }}}) 21 | 22 | ok fetch 1 (binary.size[1] binary.peek[1]) 23 | * 1 fetch (binary.size[1] 11 binary[1] {{{ 24 | hello world 25 | }}}) 26 | 27 | ok fetch 1 (binary.size[3] binary.peek[2]) 28 | * 1 fetch (binary.size[3] 16 binary[2] {{{ 29 | hello world 30 | }}}) 31 | 32 | ok fetch 1 (binary.size[2] binary.size[3] binary.size[4]) 33 | * 1 fetch (binary.size[2] 11 binary.size[3] 16 binary.size[4] 18) 34 | 35 | ok fetch 1 (binary.peek[5]<0.7>) 36 | * 1 fetch (binary[5]<0> ~{{{ 37 | abcdefg 38 | }}}) 39 | 40 | ok fetch 1 (binary.peek[5]<0.8>) 41 | * 1 fetch (binary[5]<0> ~{{{ 42 | abcdefg 43 | }}}) 44 | 45 | ok fetch 1 (binary.peek[5]<0.10>) 46 | * 1 fetch (binary[5]<0> ~{{{ 47 | abcdefg hi 48 | }}}) 49 | 50 | ok fetch 1 (binary.peek[5]<10.10>) 51 | * 1 fetch (binary[5]<10> ~{{{ 52 | jkl 53 | mno 54 | p 55 | }}}) 56 | 57 | ok fetch 1 (binary.peek[5]<5.10>) 58 | * 1 fetch (binary[5]<5> ~{{{ 59 | fg hijkl 60 | 61 | }}}) 62 | 63 | ok fetch 1 (binary.peek[5]<15.100>) 64 | * 1 fetch (binary[5]<15> ~{{{ 65 | mno 66 | pqrstuvqxyz 67 | }}}) 68 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-binary-mime-base64.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Mime-Version: 1.0 5 | Content-Type: multipart/mixed; boundary="foo 6 | bar" 7 | 8 | Root MIME prologue 9 | 10 | --foo bar 11 | Content-Type: text/x-myown; charset=us-ascii 12 | Content-Transfer-Encoding: base64 13 | 14 | 15 | aGVs 16 | bG8gd29y 17 | bGQ= 18 | 19 | --foo bar 20 | Content-Type: text/x-myown; charset=us-ascii 21 | Content-Transfer-Encoding: base64 22 | 23 | aGVs 24 | bG8g 25 | d29y 26 | bGQ= 27 | 28 | 29 | --foo bar 30 | Content-Type: text/x-myown; charset=us-ascii 31 | Content-Transfer-Encoding: base64 32 | 33 | aGVsbG8g 34 | dG8geW91IHRv 35 | bw== 36 | 37 | --foo bar 38 | Content-Type: text/x-myown; charset=us-ascii 39 | Content-Transfer-Encoding: base64 40 | 41 | aGVsbG8gdG8gZXZlcnlvbmUh 42 | --foo bar 43 | Content-Type: text/x-myown; charset=us-ascii 44 | Content-Transfer-Encoding: base64 45 | 46 | YWJjZGVmZw1oaWprbA0KbW5vCnBxcnN0dXZxeHl6 47 | 48 | --foo bar-- 49 | Root MIME epilogue 50 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-binary-mime-qp: -------------------------------------------------------------------------------- 1 | capabilities: BINARY 2 | messages: all 3 | 4 | ok fetch 1 (binary.size[1]) 5 | * 1 fetch (binary.size[1] 65) 6 | 7 | ok fetch 1 (binary.peek[1]) 8 | * 1 fetch (binary[1] {{{ 9 | hello 10 | bar 11 | foo bar 12 | foo b 13 | foo bar 14 | foo b 15 | foo 16 | bar 17 | foo_bar 18 | 19 | }}}) 20 | 21 | ok fetch 1 (binary.peek[1]<0.10>) 22 | * 1 fetch (binary[1]<0> {{{ 23 | hello 24 | bar 25 | }}}) 26 | 27 | ok fetch 1 (binary.peek[1]<10.10>) 28 | * 1 fetch (binary[1]<10> ~{{{ 29 | 30 | foo bar 31 | }}}) 32 | 33 | ok fetch 1 (binary.peek[1]<20.10>) 34 | * 1 fetch (binary[1]<20> ~{{{ 35 | 36 | foo b 37 | 38 | }}}) 39 | 40 | ok fetch 1 (binary.peek[1]<15.10>) 41 | * 1 fetch (binary[1]<15> ~{{{ 42 | bar 43 | foo 44 | }}}) 45 | 46 | ok fetch 1 (binary.peek[1]<40.100>) 47 | * 1 fetch (binary[1]<40> {{{ 48 | oo b 49 | foo 50 | bar 51 | foo_bar 52 | 53 | }}}) 54 | 55 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-binary-mime-qp.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Mime-Version: 1.0 5 | Content-Type: multipart/mixed; boundary="foo 6 | bar" 7 | 8 | Root MIME prologue 9 | 10 | --foo bar 11 | Content-Type: text/x-myown; charset=us-ascii 12 | Content-Transfer-Encoding: quoted-printable 13 | 14 | hello 15 | bar= 16 | 17 | foo = 18 | bar 19 | foo = 20 | =62 21 | foo = 22 | bar 23 | foo = 24 | =62 25 | foo 26 | bar= 27 | 28 | foo_bar 29 | 30 | --foo bar-- 31 | Root MIME epilogue 32 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-binary-mime.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Mime-Version: 1.0 5 | Content-Type: multipart/mixed; boundary="foo 6 | bar" 7 | 8 | Root MIME prologue 9 | 10 | --foo bar 11 | Content-Type: text/x-myown; charset=us-ascii 12 | 13 | hello 14 | 15 | --foo bar 16 | Content-Type: message/rfc822 17 | 18 | From: sub@domain.org 19 | Date: Sun, 12 Aug 2012 12:34:56 +0300 20 | Subject: submsg 21 | Content-Type: multipart/alternative; boundary="sub1" 22 | 23 | Sub MIME prologue 24 | --sub1 25 | Content-Type: text/html 26 | 27 |

Hello world

28 | 29 | --sub1 30 | Content-Type: text/plain 31 | 32 | Hello another world 33 | 34 | --sub1-- 35 | Sub MIME epilogue 36 | 37 | --foo bar-- 38 | Root MIME epilogue 39 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-body: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | # header and body fetches 4 | ok fetch 1 rfc822.header 5 | * 1 fetch (rfc822.header $hdr1) 6 | ok fetch 1 body.peek[header] 7 | * 1 fetch (body[header] $hdr1) 8 | 9 | ok fetch 1 (flags body.peek[text]) 10 | * 1 fetch (flags () body[text] {{{ 11 | body1 12 | 13 | 14 | }}}) 15 | ok fetch 1 rfc822.text 16 | * 1 fetch (rfc822.text {{{ 17 | body1 18 | 19 | 20 | }}}) 21 | * 1 fetch (flags (\seen)) 22 | 23 | ok fetch 2 (flags body.peek[]) 24 | * 2 fetch (flags () body[] $full2) 25 | ok fetch 2 rfc822 26 | * 2 fetch (rfc822 $full2) 27 | * 2 fetch (flags (\seen)) 28 | 29 | ok fetch 3 (body[]) 30 | * 3 fetch (body[] $full3) 31 | * 3 fetch (flags (\seen)) 32 | ok fetch 4 (body[header]) 33 | * 4 fetch (body[header] $hdr4) 34 | * 4 fetch (flags (\seen)) 35 | 36 | # partial fetches 37 | ok fetch 2 body.peek[text]<0.3> 38 | * 2 fetch (body[text]<0> "bod") 39 | ok fetch 2 body.peek[text]<3.3> 40 | * 2 fetch (body[text]<3> "y22") 41 | 42 | ok fetch 3 body.peek[text]<0.1> 43 | * 3 fetch (body[text]<0> "b") 44 | ok fetch 3 body.peek[text]<5.1> 45 | * 3 fetch (body[text]<5> "3") 46 | ok fetch 3 body.peek[text]<5.2> 47 | * 3 fetch (body[text]<5> ~{{{ 48 | 3 49 | }}}) 50 | ok fetch 3 body.peek[text]<5.3> 51 | * 3 fetch (body[text]<5> ~{{{ 52 | 3 53 | 54 | }}}) 55 | ok fetch 3 body.peek[text]<6.1> 56 | * 3 fetch (body[text]<6> ~{{{ 57 | 58 | }}}) 59 | ok fetch 3 body.peek[text]<6.2> 60 | * 3 fetch (body[text]<6> ~{{{ 61 | 62 | 63 | }}}) 64 | ok fetch 3 body.peek[text]<7.1> 65 | * 3 fetch (body[text]<7> ~{{{ 66 | 67 | 68 | }}}) 69 | 70 | # header fields 71 | ok fetch 1 body.peek[header.fields (from)] 72 | * 1 fetch (body[header.fields (from)] {{{ 73 | From: User1 74 | 75 | 76 | }}}) 77 | 78 | ok fetch 1 (body.peek[header.fields (from)]) 79 | * 1 fetch (body[header.fields (from)] {{{ 80 | From: User1 81 | 82 | 83 | }}}) 84 | 85 | ok fetch 1 (body.peek[header.fields (from from)]) 86 | * 1 fetch (body[header.fields (from from)] {{{ 87 | From: User1 88 | 89 | 90 | }}}) 91 | 92 | ok fetch 1 body.peek[header.fields (from subject)] 93 | * 1 fetch (body[header.fields (from subject)] {{{ 94 | From: User1 95 | Subject: s1 96 | 97 | 98 | }}}) 99 | 100 | ok fetch 1 body.peek[header.fields.not (date)] 101 | ! 1 fetch (body[header.fields.not (date)] {{{ 102 | From: User1 103 | Date: Sat, 24 Mar 2007 23:00:00 +0200 104 | Subject: s1 105 | 106 | 107 | }}}) 108 | 109 | ok fetch 1 body.peek[header.fields.not (date date)] 110 | ! 1 fetch (body[header.fields.not (date date)] {{{ 111 | From: User1 112 | Date: Sat, 24 Mar 2007 23:00:00 +0200 113 | Subject: s1 114 | 115 | 116 | }}}) 117 | 118 | ok fetch 1 body.peek[header.fields (xyz)] 119 | * 1 fetch (body[header.fields (xyz)] {{{ 120 | 121 | 122 | }}}) 123 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-body-message-rfc822: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | ok fetch 1 (body.peek[]) 4 | * 1 fetch (body[] {{{ 5 | From: user@domain.org 6 | Date: Sat, 24 Mar 2007 23:00:00 +0200 7 | Mime-Version: 1.0 8 | Content-Type: message/rfc822 9 | 10 | From: sub@domain.org 11 | Date: Sun, 12 Aug 2012 12:34:56 +0300 12 | Subject: submsg 13 | 14 | Hello world 15 | 16 | }}}) 17 | 18 | ok fetch 1 (body.peek[text]) 19 | * 1 fetch (body[text] {{{ 20 | From: sub@domain.org 21 | Date: Sun, 12 Aug 2012 12:34:56 +0300 22 | Subject: submsg 23 | 24 | Hello world 25 | 26 | }}}) 27 | 28 | ok fetch 1 (body.peek[1]) 29 | * 1 fetch (body[1] {{{ 30 | From: sub@domain.org 31 | Date: Sun, 12 Aug 2012 12:34:56 +0300 32 | Subject: submsg 33 | 34 | Hello world 35 | 36 | }}}) 37 | 38 | ok fetch 1 (body.peek[1.1]) 39 | * 1 fetch (body[1.1] {{{ 40 | Hello world 41 | 42 | }}}) 43 | 44 | ok fetch 1 (body.peek[1.header]) 45 | * 1 fetch (body[1.header] {{{ 46 | From: sub@domain.org 47 | Date: Sun, 12 Aug 2012 12:34:56 +0300 48 | Subject: submsg 49 | 50 | 51 | }}}) 52 | 53 | ok fetch 1 (body.peek[1.header.fields (from subject X-foo)]) 54 | * 1 fetch (body[1.header.fields (from subject X-foo)] {{{ 55 | From: sub@domain.org 56 | Subject: submsg 57 | 58 | 59 | }}}) 60 | 61 | ok fetch 1 (body.peek[1.header.fields.not (from subject X-foo)]) 62 | * 1 fetch (body[1.header.fields.not (from subject X-foo)] {{{ 63 | Date: Sun, 12 Aug 2012 12:34:56 +0300 64 | 65 | 66 | }}}) 67 | 68 | ok fetch 1 (body.peek[1.text]) 69 | * 1 fetch (body[1.text] {{{ 70 | Hello world 71 | 72 | }}}) 73 | 74 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-body-message-rfc822-mime: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | ok fetch 1 (body.peek[]) 4 | * 1 fetch (body[] {{{ 5 | From: user@domain.org 6 | Date: Sat, 24 Mar 2007 23:00:00 +0200 7 | Mime-Version: 1.0 8 | Content-Type: message/rfc822 9 | 10 | From: sub@domain.org 11 | Date: Sun, 12 Aug 2012 12:34:56 +0300 12 | Subject: submsg 13 | Content-Type: multipart/digest; boundary="foo" 14 | 15 | prologue 16 | 17 | --foo 18 | 19 | From: m1@example.com 20 | Subject: m1 21 | 22 | m1 body 23 | 24 | --foo 25 | X-Mime: m2 header 26 | 27 | From: m2@example.com 28 | Subject: m2 29 | 30 | m2 body 31 | 32 | --foo-- 33 | 34 | epilogue 35 | 36 | }}}) 37 | 38 | ok fetch 1 (body.peek[text]) 39 | * 1 fetch (body[text] {{{ 40 | From: sub@domain.org 41 | Date: Sun, 12 Aug 2012 12:34:56 +0300 42 | Subject: submsg 43 | Content-Type: multipart/digest; boundary="foo" 44 | 45 | prologue 46 | 47 | --foo 48 | 49 | From: m1@example.com 50 | Subject: m1 51 | 52 | m1 body 53 | 54 | --foo 55 | X-Mime: m2 header 56 | 57 | From: m2@example.com 58 | Subject: m2 59 | 60 | m2 body 61 | 62 | --foo-- 63 | 64 | epilogue 65 | 66 | }}}) 67 | 68 | ok fetch 1 (body.peek[1]) 69 | * 1 fetch (body[1] {{{ 70 | From: sub@domain.org 71 | Date: Sun, 12 Aug 2012 12:34:56 +0300 72 | Subject: submsg 73 | Content-Type: multipart/digest; boundary="foo" 74 | 75 | prologue 76 | 77 | --foo 78 | 79 | From: m1@example.com 80 | Subject: m1 81 | 82 | m1 body 83 | 84 | --foo 85 | X-Mime: m2 header 86 | 87 | From: m2@example.com 88 | Subject: m2 89 | 90 | m2 body 91 | 92 | --foo-- 93 | 94 | epilogue 95 | 96 | }}}) 97 | 98 | ok fetch 1 (body.peek[1.header]) 99 | * 1 fetch (body[1.header] {{{ 100 | From: sub@domain.org 101 | Date: Sun, 12 Aug 2012 12:34:56 +0300 102 | Subject: submsg 103 | Content-Type: multipart/digest; boundary="foo" 104 | 105 | 106 | }}}) 107 | 108 | ok fetch 1 (body.peek[1.text]) 109 | * 1 fetch (body[1.text] {{{ 110 | prologue 111 | 112 | --foo 113 | 114 | From: m1@example.com 115 | Subject: m1 116 | 117 | m1 body 118 | 119 | --foo 120 | X-Mime: m2 header 121 | 122 | From: m2@example.com 123 | Subject: m2 124 | 125 | m2 body 126 | 127 | --foo-- 128 | 129 | epilogue 130 | 131 | }}}) 132 | 133 | ok fetch 1 (body.peek[1.1]) 134 | * 1 fetch (body[1.1] {{{ 135 | From: m1@example.com 136 | Subject: m1 137 | 138 | m1 body 139 | 140 | }}}) 141 | 142 | ok fetch 1 (body.peek[1.1.MIME]) 143 | * 1 fetch (body[1.1.MIME] {{{ 144 | 145 | 146 | }}}) 147 | 148 | ok fetch 1 (body.peek[1.1.HEADER]) 149 | * 1 fetch (body[1.1.HEADER] {{{ 150 | From: m1@example.com 151 | Subject: m1 152 | 153 | 154 | }}}) 155 | 156 | ok fetch 1 (body.peek[1.1.TEXT]) 157 | * 1 fetch (body[1.1.TEXT] {{{ 158 | m1 body 159 | 160 | }}}) 161 | 162 | ok fetch 1 (body.peek[1.2]) 163 | * 1 fetch (body[1.2] {{{ 164 | From: m2@example.com 165 | Subject: m2 166 | 167 | m2 body 168 | 169 | }}}) 170 | 171 | ok fetch 1 (body.peek[1.2.MIME]) 172 | * 1 fetch (body[1.2.MIME] {{{ 173 | X-Mime: m2 header 174 | 175 | 176 | }}}) 177 | 178 | ok fetch 1 (body.peek[1.2.HEADER]) 179 | * 1 fetch (body[1.2.HEADER] {{{ 180 | From: m2@example.com 181 | Subject: m2 182 | 183 | 184 | }}}) 185 | 186 | ok fetch 1 (body.peek[1.2.TEXT]) 187 | * 1 fetch (body[1.2.TEXT] {{{ 188 | m2 body 189 | 190 | }}}) 191 | 192 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-body-message-rfc822-mime.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Mime-Version: 1.0 5 | Content-Type: message/rfc822 6 | 7 | From: sub@domain.org 8 | Date: Sun, 12 Aug 2012 12:34:56 +0300 9 | Subject: submsg 10 | Content-Type: multipart/digest; boundary="foo" 11 | 12 | prologue 13 | 14 | --foo 15 | 16 | From: m1@example.com 17 | Subject: m1 18 | 19 | m1 body 20 | 21 | --foo 22 | X-Mime: m2 header 23 | 24 | From: m2@example.com 25 | Subject: m2 26 | 27 | m2 body 28 | 29 | --foo-- 30 | 31 | epilogue 32 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-body-message-rfc822-x2: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | ok fetch 1 (body.peek[]) 4 | * 1 fetch (body[] {{{ 5 | From: user@domain.org 6 | Date: Sat, 24 Mar 2007 23:00:00 +0200 7 | Mime-Version: 1.0 8 | Content-Type: message/rfc822 9 | 10 | From: user2@domain.org 11 | Date: Fri, 23 Mar 2007 11:22:33 +0200 12 | Mime-Version: 1.0 13 | Content-Type: message/rfc822 14 | 15 | From: sub@domain.org 16 | Date: Sun, 12 Aug 2012 12:34:56 +0300 17 | Subject: submsg 18 | 19 | Hello world 20 | 21 | }}}) 22 | 23 | ok fetch 1 (body.peek[text]) 24 | * 1 fetch (body[text] {{{ 25 | From: user2@domain.org 26 | Date: Fri, 23 Mar 2007 11:22:33 +0200 27 | Mime-Version: 1.0 28 | Content-Type: message/rfc822 29 | 30 | From: sub@domain.org 31 | Date: Sun, 12 Aug 2012 12:34:56 +0300 32 | Subject: submsg 33 | 34 | Hello world 35 | 36 | }}}) 37 | 38 | ok fetch 1 (body.peek[1]) 39 | * 1 fetch (body[1] {{{ 40 | From: user2@domain.org 41 | Date: Fri, 23 Mar 2007 11:22:33 +0200 42 | Mime-Version: 1.0 43 | Content-Type: message/rfc822 44 | 45 | From: sub@domain.org 46 | Date: Sun, 12 Aug 2012 12:34:56 +0300 47 | Subject: submsg 48 | 49 | Hello world 50 | 51 | }}}) 52 | 53 | ok fetch 1 (body.peek[1.1]) 54 | * 1 fetch (body[1.1] {{{ 55 | From: sub@domain.org 56 | Date: Sun, 12 Aug 2012 12:34:56 +0300 57 | Subject: submsg 58 | 59 | Hello world 60 | 61 | }}}) 62 | 63 | ok fetch 1 (body.peek[1.header]) 64 | * 1 fetch (body[1.header] {{{ 65 | From: user2@domain.org 66 | Date: Fri, 23 Mar 2007 11:22:33 +0200 67 | Mime-Version: 1.0 68 | Content-Type: message/rfc822 69 | 70 | 71 | }}}) 72 | 73 | ok fetch 1 (body.peek[1.text]) 74 | * 1 fetch (body[1.text] {{{ 75 | From: sub@domain.org 76 | Date: Sun, 12 Aug 2012 12:34:56 +0300 77 | Subject: submsg 78 | 79 | Hello world 80 | 81 | }}}) 82 | 83 | ok fetch 1 (body.peek[1.1.1]) 84 | * 1 fetch (body[1.1.1] {{{ 85 | Hello world 86 | 87 | }}}) 88 | 89 | ok fetch 1 (body.peek[1.1.header]) 90 | * 1 fetch (body[1.1.header] {{{ 91 | From: sub@domain.org 92 | Date: Sun, 12 Aug 2012 12:34:56 +0300 93 | Subject: submsg 94 | 95 | 96 | }}}) 97 | 98 | ok fetch 1 (body.peek[1.1.text]) 99 | * 1 fetch (body[1.1.text] {{{ 100 | Hello world 101 | 102 | }}}) 103 | 104 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-body-message-rfc822-x2.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Mime-Version: 1.0 5 | Content-Type: message/rfc822 6 | 7 | From: user2@domain.org 8 | Date: Fri, 23 Mar 2007 11:22:33 +0200 9 | Mime-Version: 1.0 10 | Content-Type: message/rfc822 11 | 12 | From: sub@domain.org 13 | Date: Sun, 12 Aug 2012 12:34:56 +0300 14 | Subject: submsg 15 | 16 | Hello world 17 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-body-message-rfc822.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Mime-Version: 1.0 5 | Content-Type: message/rfc822 6 | 7 | From: sub@domain.org 8 | Date: Sun, 12 Aug 2012 12:34:56 +0300 9 | Subject: submsg 10 | 11 | Hello world 12 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-body-mime.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Mime-Version: 1.0 5 | Content-Type: multipart/mixed; boundary="foo 6 | bar" 7 | 8 | Root MIME prologue 9 | 10 | --foo bar 11 | Content-Type: text/x-myown; charset=us-ascii 12 | 13 | hello 14 | 15 | --foo bar 16 | Content-Type: message/rfc822 17 | 18 | From: sub@domain.org 19 | Date: Sun, 12 Aug 2012 12:34:56 +0300 20 | Subject: submsg 21 | Content-Type: multipart/alternative; boundary="sub1" 22 | 23 | Sub MIME prologue 24 | --sub1 25 | Content-Type: text/html 26 | 27 |

Hello world

28 | 29 | --sub1 30 | Content-Type: text/plain 31 | 32 | Hello another world 33 | 34 | --sub1-- 35 | Sub MIME epilogue 36 | 37 | --foo bar-- 38 | Root MIME epilogue 39 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-body.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: User1 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Subject: s1 5 | 6 | body1 7 | 8 | From user@domain Fri Feb 22 17:06:23 2008 9 | From: User2 10 | Date: Sat, 24 Mar 2007 23:00:00 +0200 11 | Subject: s22 12 | 13 | body22 14 | 15 | From user@domain Fri Feb 22 17:06:23 2008 16 | From: User3 17 | Date: Sat, 24 Mar 2007 23:00:00 +0200 18 | Subject: s333 19 | 20 | body33 21 | 22 | From user@domain Fri Feb 22 17:06:23 2008 23 | From: User4 24 | Date: Sat, 24 Mar 2007 23:00:00 +0200 25 | Subject: s4444 26 | 27 | body4444 28 | 29 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-bodystructure: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | ok fetch 1:* body 4 | * 1 FETCH (BODY (("TEXT" "x-MYOWN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 7 1) "MIXED")) 5 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-bodystructure.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Mime-Version: 1.0 5 | Content-Type: multipart/mixed; boundary="foo 6 | bar" 7 | 8 | --foo bar 9 | Content-Type: text/x-myown; charset=us-ascii 10 | 11 | hello 12 | 13 | --foo bar-- 14 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-envelope: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | # date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, message-id 4 | ok fetch 1:* envelope 5 | * 1 FETCH (ENVELOPE ("Thu, 15 Feb 2007 01:02:03 +0200" "subject header" (("From Real" NIL "fromuser" "fromdomain.org")) (("Sender Real" NIL "senderuser" "senderdomain.org")) (("ReplyTo Real" NIL "replytouser" "replytodomain.org")) (("To Real" NIL "touser" "todomain.org")) (("Cc Real" NIL "ccuser" "ccdomain.org")) (("Bcc Real" NIL "bccuser" "bccdomain.org")) "" "")) 6 | * 2 FETCH (ENVELOPE ("Thu, 15 Feb 2007 01:02:03 +0200" NIL ((NIL NIL "user" "domain")) ((NIL NIL "user" "domain")) ((NIL NIL "user" "domain")) NIL NIL NIL NIL NIL)) 7 | * 3 FETCH (ENVELOPE ("Thu, 15 Feb 2007 01:02:03 +0200" NIL ((NIL NIL "user" "domain")) ((NIL NIL "user" "domain")) ((NIL NIL "user" "domain")) NIL NIL NIL NIL NIL)) 8 | * 4 FETCH (ENVELOPE ("Thu, 15 Feb 2007 01:02:03 +0200" NIL (("Real Name" NIL "user" "domain")) (("Real Name" NIL "user" "domain")) (("Real Name" NIL "user" "domain")) ((NIL NIL "group" NIL)(NIL NIL "g1" "d1.org")(NIL NIL "g2" "d2.org")(NIL NIL NIL NIL)(NIL NIL "group2" NIL)(NIL NIL "g3" "d3.org")(NIL NIL NIL NIL)) ((NIL NIL "group" NIL)(NIL NIL NIL NIL)(NIL NIL "group2" NIL)(NIL NIL NIL NIL)) NIL NIL NIL)) 9 | * 5 FETCH (ENVELOPE ("Thu, 15 Feb 2007 01:02:03 +0200" NIL (("Real Name" NIL "user" "domain")) (("Real Name" NIL "user" "domain")) (("Real Name" NIL "user" "domain")) NIL NIL NIL NIL NIL)) 10 | * 6 FETCH (ENVELOPE ("Thu, 15 Feb 2007 01:02:03 +0200" NIL ((NIL "@route" "user" "domain")) ((NIL "@route" "user" "domain")) ((NIL "@route" "user" "domain")) NIL NIL NIL NIL NIL)) 11 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/fetch-envelope.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | Message-ID: 3 | In-Reply-To: 4 | Date: Thu, 15 Feb 2007 01:02:03 +0200 5 | Subject: subject header 6 | From: From Real 7 | To: To Real 8 | Cc: Cc Real 9 | Bcc: Bcc Real 10 | Sender: Sender Real 11 | Reply-To: ReplyTo Real 12 | 13 | body 14 | 15 | From user@domain Fri Feb 22 17:06:23 2008 16 | Date: Thu, 15 Feb 2007 01:02:03 +0200 17 | From: user@domain 18 | 19 | body 20 | 21 | From user@domain Fri Feb 22 17:06:23 2008 22 | Date: Thu, 15 Feb 2007 01:02:03 +0200 23 | From: user@domain 24 | 25 | body 26 | 27 | From user@domain Fri Feb 22 17:06:23 2008 28 | Date: Thu, 15 Feb 2007 01:02:03 +0200 29 | From: user@domain (Real Name) 30 | To: group: g1@d1.org, g2@d2.org;, group2: g3@d3.org; 31 | Cc: group:;, group2: (foo) ; 32 | 33 | body 34 | 35 | From user@domain Fri Feb 22 17:06:23 2008 36 | Date: Thu, 15 Feb 2007 01:02:03 +0200 37 | From: user@domain (Real Name) 38 | Sender: 39 | Reply-To: 40 | 41 | body 42 | 43 | From user@domain Fri Feb 22 17:06:23 2008 44 | Date: Thu, 15 Feb 2007 01:02:03 +0200 45 | From: <@route:user@domain> 46 | 47 | body 48 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/list: -------------------------------------------------------------------------------- 1 | connections: 3 2 | state: auth 3 | 4 | # get the separator 5 | 1 ok list "" "" 6 | * list () $sep $root 7 | # it should be \noselect, but don't fail everything if it doesn't exist 8 | * list (\noselect) $sep $root 9 | 10 | 1 ok create $mailbox${sep} 11 | 1 ok create $mailbox${sep}test 12 | 2 ok list "" $mailbox${sep}% 13 | * list () $sep $mailbox${sep}test 14 | 15 | 2 ok create $mailbox${sep}test2 16 | 1 ok list "" $mailbox${sep}% 17 | * list () $sep $mailbox${sep}test 18 | * list () $sep $mailbox${sep}test2 19 | 20 | 3 ok create $mailbox${sep}test3${sep} 21 | 2 ok create $mailbox${sep}test3${sep}test4${sep} 22 | 2 ok create $mailbox${sep}test3${sep}test4${sep}test5 23 | 2 ok list "" $mailbox${sep}% 24 | * list () $sep $mailbox${sep}test 25 | * list () $sep $mailbox${sep}test2 26 | * list () $sep $mailbox${sep}test3 27 | ! list () $sep $mailbox${sep}test3${sep}test4 28 | ! list () $sep $mailbox${sep}test3${sep}test4${sep}test5 29 | 30 | 3 ok list "" $mailbox${sep}% 31 | * list () $sep $mailbox${sep}test 32 | * list () $sep $mailbox${sep}test2 33 | * list () $sep $mailbox${sep}test3 34 | 35 | 2 ok list "" $mailbox${sep}%${sep}% 36 | ! list () $sep $mailbox${sep}test 37 | ! list () $sep $mailbox${sep}test2 38 | ! list () $sep $mailbox${sep}test3 39 | * list () $sep $mailbox${sep}test3${sep}test4 40 | ! list () $sep $mailbox${sep}test3${sep}test4${sep}test5 41 | 42 | 3 ok list "" $mailbox${sep}* 43 | * list () $sep $mailbox${sep}test 44 | * list () $sep $mailbox${sep}test2 45 | * list () $sep $mailbox${sep}test3 46 | * list () $sep $mailbox${sep}test3${sep}test4${sep}test5 47 | 48 | 3 ok list $mailbox${sep} * 49 | * list () $sep $mailbox${sep}test 50 | * list () $sep $mailbox${sep}test2 51 | * list () $sep $mailbox${sep}test3 52 | * list () $sep $mailbox${sep}test3${sep}test4${sep}test5 53 | 54 | 2 ok list "" $mailbox${sep}*test4 55 | ! list () $sep $mailbox${sep}test 56 | ! list () $sep $mailbox${sep}test2 57 | ! list () $sep $mailbox${sep}test3 58 | * list () $sep $mailbox${sep}test3${sep}test4 59 | ! list () $sep $mailbox${sep}test3${sep}test4${sep}test5 60 | 61 | 2 ok list "" $mailbox${sep}*test* 62 | * list () $sep $mailbox${sep}test 63 | * list () $sep $mailbox${sep}test2 64 | * list () $sep $mailbox${sep}test3 65 | * list () $sep $mailbox${sep}test3${sep}test4${sep}test5 66 | 67 | 2 ok list "" $mailbox${sep}%3${sep}% 68 | * list () $sep $mailbox${sep}test3${sep}test4 69 | 2 ok list "" $mailbox${sep}%3${sep}%4 70 | * list () $sep $mailbox${sep}test3${sep}test4 71 | 2 ok list "" $mailbox${sep}%t*4 72 | * list () $sep $mailbox${sep}test3${sep}test4 73 | 74 | 2 ok delete $mailbox${sep}test2 75 | 1 ok list "" $mailbox${sep}* 76 | ! list () $sep $mailbox${sep}test2 77 | 78 | 1 ok list "" INBOX 79 | * list () $inboxsep INBOX 80 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/logout: -------------------------------------------------------------------------------- 1 | state: nonauth 2 | connections: 2 3 | 4 | 1 ok noop 5 | ! bye 6 | 2 ok noop 7 | ! bye 8 | 9 | 1 ok logout 10 | * bye 11 | 12 | 2 ok noop 13 | 2 ok logout 14 | * bye 15 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/move: -------------------------------------------------------------------------------- 1 | capabilities: MOVE 2 | state: created 3 | 4 | # - assumes COPYUID is sent untagged before expunges. 5 | # - assumes MOVE to mailbox itself changes message UID 6 | 7 | ok append 8 | ok append 9 | ok append 10 | ok create ${mailbox}2 11 | 12 | ok select ${mailbox}2 13 | * 0 exists 14 | * ok [uidvalidity $uidvalidity_dest] 15 | * ok [uidnext $uidnext_dest1] 16 | 17 | # MOVE: 18 | ok select $mailbox 19 | 20 | ok fetch 1:* uid 21 | * 1 fetch (uid $uid1) 22 | * 2 fetch (uid $uid2) 23 | * 3 fetch (uid $uid3) 24 | 25 | ok move 1 ${mailbox}2 26 | * ok [copyuid $uidvalidity_dest $uid1 $uidnext_dest1] 27 | * 1 expunge 28 | 29 | # UID MOVE: 30 | ok select ${mailbox}2 31 | * 1 exists 32 | * ok [uidvalidity $uidvalidity_dest] 33 | * ok [uidnext $uidnext_dest2] 34 | 35 | ok select $mailbox 36 | * ok [uidvalidity $uidvalidity] 37 | * ok [uidnext $uidnext1] 38 | 39 | ok uid move $uid2 ${mailbox}2 40 | * ok [copyuid $uidvalidity_dest $uid2 $uidnext_dest2] 41 | * 1 expunge 42 | 43 | # MOVE to same mailbox: 44 | #ok move 1 $mailbox 45 | #* ok [copyuid $uidvalidity $uid3 $uidnext1] 46 | #* 1 expunge 47 | #* 1 exists 48 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/multiappend: -------------------------------------------------------------------------------- 1 | capabilities: MULTIAPPEND 2 | state: created 3 | 4 | ok append $mailbox {{{ 5 | From: user@domain.org 6 | Date: Sat, 24 Mar 2007 23:00:00 +0200 7 | Subject: mail1 8 | 9 | body1 10 | }}} {{{ 11 | From: user@domain.org 12 | Date: Sat, 24 Mar 2007 23:00:00 +0200 13 | Subject: mail2 14 | 15 | body2 16 | }}} 17 | 18 | ok select $mailbox 19 | 20 | ok fetch 1:* body.peek[header.fields (subject)] 21 | * 1 fetch (body[header.fields (subject)] {{{ 22 | Subject: mail1 23 | 24 | 25 | }}}) 26 | * 2 fetch (body[header.fields (subject)] {{{ 27 | Subject: mail2 28 | 29 | 30 | }}}) 31 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/mutf7: -------------------------------------------------------------------------------- 1 | state: auth 2 | 3 | # get the separator 4 | ok list "" "" 5 | * list () $sep $root 6 | 7 | ok create "$mailbox${sep}p&AOQA5A-" 8 | ok list "" "$mailbox${sep}p&AOQA5A-" 9 | * list () $sep "$mailbox${sep}p&AOQA5A-" 10 | 11 | ok status "$mailbox${sep}p&AOQA5A-" (messages) 12 | * status "$mailbox${sep}p&AOQA5A-" (messages 0) 13 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/nil: -------------------------------------------------------------------------------- 1 | messages: 1 2 | 3 | ok search subject NIL 4 | * search 1 5 | 6 | ok search body nil 7 | * search 1 8 | 9 | ok list "" NIL 10 | 11 | ok store 1 +flags NIL 12 | ok fetch 1 flags 13 | * 1 fetch (flags (NIL)) 14 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/nil.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | Subject: NiL 4 | 5 | nil 6 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/notify: -------------------------------------------------------------------------------- 1 | capabilities: notify qresync 2 | 3 | ok create ${mailbox}2 4 | ok append ${mailbox}2 5 | 6 | # 7 | # Check that initial STATUS notifications are sent when needed 8 | # 9 | 10 | ok notify set status (mailboxes ${mailbox}2 (MessageExpunge)) 11 | * status ${mailbox}2 (messages 1) 12 | 13 | ok notify set status (mailboxes ${mailbox}2 (MessageNew)) 14 | * status ${mailbox}2 (messages 1 uidnext $uidnext uidvalidity $uidvalidity) 15 | 16 | ok notify set status (mailboxes ${mailbox}2 (FlagChange)) 17 | * status ${mailbox}2 (uidvalidity $uidvalidity highestmodseq $hmodseq) 18 | 19 | ok notify set (mailboxes ${mailbox}2 (MessageNew MessageExpunge FlagChange)) 20 | ! status ${mailbox}2 () 21 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/pipeline: -------------------------------------------------------------------------------- 1 | state: auth 2 | 3 | tag1 create ${mailbox} 4 | tag2 create ${mailbox}2 5 | tag3 create ${mailbox}3 6 | tag4 create ${mailbox}4 7 | tag1 ok 8 | tag2 ok 9 | tag3 ok 10 | tag4 ok 11 | 12 | tag1 status ${mailbox} (messages) 13 | tag2 status ${mailbox}2 (messages) 14 | tag3 status ${mailbox}3 (messages) 15 | tag4 status ${mailbox}4 (messages) 16 | * status ${mailbox} (messages 0) 17 | * status ${mailbox}2 (messages 0) 18 | * status ${mailbox}3 (messages 0) 19 | * status ${mailbox}4 (messages 0) 20 | tag1 ok 21 | tag2 ok 22 | tag3 ok 23 | tag4 ok 24 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-addresses: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | # full address searching 4 | ok search from user-from@domain.org 5 | * search 1 2 3 4 6 7 6 | ok search to user-to@domain.org 7 | * search 1 2 3 4 8 | ok search cc user-cc@domain.org 9 | * search 1 2 3 4 5 10 | ok search bcc user-bcc@domain.org 11 | * search 1 2 3 4 12 | 13 | # realname searching 14 | ok search from realfrom 15 | * search 2 4 6 7 16 | ok search to realto 17 | * search 2 4 18 | ok search cc realcc 19 | * search 2 4 20 | ok search bcc realbcc 21 | * search 2 4 22 | 23 | # existence searches 24 | ok search header from "" 25 | * search 1 2 3 4 5 6 7 26 | ok search header to "" 27 | * search 1 2 3 4 6 7 28 | ok search header cc "" 29 | * search 1 2 3 4 5 30 | ok search header bcc "" 31 | * search 1 2 3 4 32 | 33 | # substring address searches 34 | #ok search from ser-fro 35 | #* search 1 2 3 4 5 6 7 36 | #ok search to ser-t 37 | #* search 1 2 3 4 38 | #ok search cc ser-c 39 | #* search 1 2 3 4 5 40 | #ok search bcc ser-bc 41 | #* search 1 2 3 4 42 | 43 | # substring realname searches 44 | #ok search from ealfro 45 | #* search 2 4 6 7 46 | #ok search to ealt 47 | #* search 2 4 48 | #ok search cc ealc 49 | #* search 2 4 50 | #ok search bcc ealbc 51 | #* search 2 4 52 | 53 | # multiple addresses 54 | ok search from user-from1 55 | * search 5 56 | ok search from user-from2 57 | * search 5 58 | 59 | # groups 60 | ok search to groupname 61 | * search 6 7 62 | ok search to groupname2 63 | * search 6 64 | ok search to groupuser1 65 | * search 6 66 | ok search to groupuser2 67 | * search 6 68 | ok search to groupuser3 69 | * search 6 70 | ok search to groupuser4 71 | * search 72 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-addresses.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user-from@domain.org 3 | To: user-to@domain.org 4 | Cc: user-cc@domain.org 5 | Bcc: user-bcc@domain.org 6 | 7 | body 8 | 9 | From user@domain Fri Feb 22 17:06:23 2008 10 | From: RealFrom 11 | To: RealTo 12 | Cc: RealCc 13 | Bcc: RealBcc 14 | 15 | body2 16 | 17 | From user@domain Fri Feb 22 17:06:23 2008 18 | From: 19 | To: 20 | Cc: 21 | Bcc: 22 | 23 | body3 24 | 25 | From user@domain Fri Feb 22 17:06:23 2008 26 | From: user-from@domain.org (RealFrom) 27 | To: user-to@domain.org (RealTo) 28 | Cc: user-cc@domain.org (RealCc) 29 | Bcc: user-bcc@domain.org (RealBcc) 30 | 31 | body4 32 | 33 | From user@domain Fri Feb 22 17:06:23 2008 34 | From: user-from1@domain.org, user-from2@domain.org 35 | Cc: user-cc@domain.org 36 | 37 | body5 38 | 39 | From user@domain Fri Feb 22 17:06:23 2008 40 | From: RealFrom 41 | To: groupname: groupuser1@domain.org, groupuser2@domain.org;, 42 | groupname2: groupuser3@domain.org; 43 | 44 | body6 45 | 46 | From user@domain Fri Feb 22 17:06:23 2008 47 | From: RealFrom 48 | To: groupname:; 49 | 50 | body7 51 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-body: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | # search full words first 4 | ok search text asdfghjkl 5 | * search 1 2 6 | ok search text zxcvbnm 7 | * search 1 3 4 8 | ok search text qwertyuiop 9 | * search 2 4 10 | 11 | ok search body asdfghjkl 12 | * search 1 2 13 | ok search body zxcvbnm 14 | * search 1 3 4 15 | ok search body qwertyuiop 16 | * search 4 17 | 18 | # search substrings 19 | #ok search text sdfghjk 20 | #* search 1 2 21 | #ok search text xcvbn 22 | #* search 1 3 4 23 | #ok search text wertyuio 24 | #* search 2 3 4 25 | 26 | #ok search body sdfghjk 27 | #* search 1 2 28 | #ok search body xcvbn 29 | #* search 1 3 4 30 | #ok search body wertyuio 31 | #* search 4 32 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-body.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | 4 | asdfghjkl zxcvbnm 5 | 6 | From user@domain Fri Feb 22 17:06:23 2008 7 | Date: Sat, 24 Mar 2007 23:00:00 +0200 8 | Subject: qwertyuiop 9 | 10 | asdfghjkl 11 | 12 | From user@domain Fri Feb 22 17:06:23 2008 13 | Date: Sat, 24 Mar 2007 23:00:00 +0200 14 | X-Header: qwertyuiop 15 | 16 | zxcvbnm 17 | 18 | From user@domain Fri Feb 22 17:06:23 2008 19 | Date: Sat, 24 Mar 2007 23:00:00 +0200 20 | 21 | zxcvbnm qwertyuiop 22 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-context-update: -------------------------------------------------------------------------------- 1 | capabilities: CONTEXT=SEARCH 2 | state: created 3 | 4 | ok append 5 | ok append 6 | ok append 7 | ok append 8 | ok append 9 | 10 | ok select $mailbox 11 | 12 | ok search return (update) body body seen 13 | * esearch (tag $searchtag) 14 | 15 | ok store 1,2,4 +flags \seen 16 | * esearch (tag $searchtag) addto ($pos 1:2,4) 17 | 18 | ok store 1,2 -flags \seen 19 | * esearch (tag $searchtag) removefrom ($pos2 1:2) 20 | 21 | ok store 3:5 +flags \deleted 22 | ok expunge 23 | * esearch (tag $searchtag) removefrom ($pos3 $4) 24 | * $3 expunge 25 | * $4 expunge 26 | * $5 expunge 27 | 28 | ok append $mailbox (\seen) 29 | * 3 exists 30 | * esearch (tag $searchtag) addto ($pos4 3) 31 | 32 | ok cancelupdate "$searchtag" 33 | 34 | ok store 1 +flags \seen 35 | ! esearch (tag $searchtag) addto ($pos5 1) 36 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-context-update2: -------------------------------------------------------------------------------- 1 | capabilities: CONTEXT=SEARCH 2 | messages: 5 3 | 4 | ok store 1,2 +flags \seen 5 | 6 | ok search return (update all) or seen subject s22 7 | * esearch (tag $searchtag) all 1:2 8 | 9 | ok store 3:5 +flags \seen 10 | * esearch (tag $searchtag) addto ($pos 3:5) 11 | 12 | ok store 1:5 -flags \seen 13 | * esearch (tag $searchtag) removefrom ($pos2 1,3:5) 14 | 15 | ok store 3,4 +flags \seen 16 | * esearch (tag $searchtag) addto ($pos3 3:4) 17 | 18 | ok store 3 +flags \deleted 19 | ok expunge 20 | * 3 expunge 21 | * esearch (tag $searchtag) removefrom ($pos4 3) 22 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-context-update3: -------------------------------------------------------------------------------- 1 | capabilities: CONTEXT=SEARCH 2 | messages: 6 3 | 4 | ok store 1 +flags \deleted 5 | ok expunge 6 | 7 | ok fetch 1:5 uid 8 | * 1 fetch (uid $uid1) 9 | * 2 fetch (uid $uid2) 10 | * 3 fetch (uid $uid3) 11 | * 4 fetch (uid $uid4) 12 | * 5 fetch (uid $uid5) 13 | 14 | ok store 1,2 +flags \seen 15 | 16 | ok uid search return (update all) or seen subject s33 17 | * esearch (tag $searchtag) uid all $uid1:$uid2 18 | 19 | ok store 3:5 +flags \seen 20 | * esearch (tag $searchtag) uid addto ($pos $uid3:$uid5) 21 | 22 | ok store 1:5 -flags \seen 23 | * esearch (tag $searchtag) uid removefrom ($pos2 $uid1,$uid3:$uid5) 24 | 25 | ok uid store $uid3,$uid4 +flags \seen 26 | * esearch (tag $searchtag) uid addto ($pos3 $uid3:$uid4) 27 | 28 | ok store 3 +flags \deleted 29 | ok expunge 30 | * 3 expunge 31 | * esearch (tag $searchtag) uid removefrom ($pos4 $uid3) 32 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-date: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | # 1) Timezone changes from EET +0200 -> EEST +0300 4 | # 1a) SENTBEFORE 5 | ok search sentbefore 24-mar-2007 6 | * search 7 | ok search sentbefore 25-mar-2007 8 | * search 1 9 | ok search sentbefore 26-mar-2007 10 | * search 1 2 3 4 5 6 11 | ok search sentbefore 27-mar-2007 12 | * search 1 2 3 4 5 6 7 13 | 14 | # 1b) SENTON 15 | ok search senton 23-mar-2007 16 | * search 17 | ok search senton 24-mar-2007 18 | * search 1 19 | ok search senton 25-mar-2007 20 | * search 2 3 4 5 6 21 | ok search senton 26-mar-2007 22 | * search 7 23 | 24 | # 1c) SENTSINCE 25 | ok search 1:7 sentsince 24-mar-2007 26 | * search 1 2 3 4 5 6 7 27 | ok search 1:7 sentsince 25-mar-2007 28 | * search 2 3 4 5 6 7 29 | ok search 1:7 sentsince 26-mar-2007 30 | * search 7 31 | ok search 1:7 sentsince 27-mar-2007 32 | * search 33 | 34 | # 2) Timezone changes from EEST +0300 -> EET +0200 35 | # 2a) SENTBEFORE 36 | ok search 8:* sentbefore 27-oct-2007 37 | * search 38 | ok search 8:* sentbefore 28-oct-2007 39 | * search 8 40 | ok search 8:* sentbefore 29-oct-2007 41 | * search 8 9 10 11 12 13 14 15 42 | ok search 8:* sentbefore 30-oct-2007 43 | * search 8 9 10 11 12 13 14 15 16 44 | 45 | # 2b) SENTON 46 | ok search 8:* senton 26-oct-2007 47 | * search 48 | ok search 8:* senton 27-oct-2007 49 | * search 8 50 | ok search 8:* senton 28-oct-2007 51 | * search 9 10 11 12 13 14 15 52 | ok search 8:* senton 29-oct-2007 53 | * search 16 54 | 55 | # 2c) SENTSINCE 56 | ok search 8:* sentsince 27-oct-2007 57 | * search 8 9 10 11 12 13 14 15 16 58 | ok search 8:* sentsince 28-oct-2007 59 | * search 9 10 11 12 13 14 15 16 60 | ok search 8:* sentsince 29-oct-2007 61 | * search 16 62 | ok search 8:* sentsince 30-oct-2007 63 | * search 64 | 65 | # 3) Try a couple of NOTs 66 | ok search 1:7 not sentbefore 26-mar-2007 67 | * search 7 68 | ok search 1:7 not senton 25-mar-2007 69 | * search 1 7 70 | ok search 8:* not sentsince 28-oct-2007 71 | * search 8 72 | ok search 8:* not senton 28-oct-2007 73 | * search 8 16 74 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-date.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Sat Mar 24 23:00:00 2007 +0200 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | 4 | body 5 | 6 | From user@domain Sat Mar 24 23:00:00 2007 +0200 7 | Date: Sun, 25 Mar 2007 00:00:00 +0200 8 | 9 | body 10 | 11 | From user@domain Sat Mar 24 23:00:00 2007 +0200 12 | Date: Sun, 25 Mar 2007 01:00:00 +0200 13 | 14 | body 15 | 16 | From user@domain Sat Mar 24 23:00:00 2007 +0200 17 | Date: Sun, 25 Mar 2007 02:00:00 +0200 18 | 19 | body 20 | 21 | From user@domain Sat Mar 24 23:00:00 2007 +0200 22 | Date: Sun, 25 Mar 2007 04:00:00 +0300 23 | 24 | body 25 | 26 | From user@domain Sat Mar 24 23:00:00 2007 +0200 27 | Date: Sun, 25 Mar 2007 23:00:00 +0300 28 | 29 | body 30 | 31 | From user@domain Sat Mar 24 23:00:00 2007 +0200 32 | Date: Mon, 26 Mar 2007 00:00:00 +0300 33 | 34 | body 35 | 36 | From user@domain Sat Mar 24 23:00:00 2007 +0200 37 | Date: Sat, 27 Oct 2007 03:00:00 +0300 38 | 39 | body 40 | 41 | From user@domain Sat Mar 24 23:00:00 2007 +0200 42 | Date: Sun, 28 Oct 2007 00:00:00 +0300 43 | 44 | body 45 | 46 | From user@domain Sat Mar 24 23:00:00 2007 +0200 47 | Date: Sun, 28 Oct 2007 01:00:00 +0300 48 | 49 | body 50 | 51 | From user@domain Sat Mar 24 23:00:00 2007 +0200 52 | Date: Sun, 28 Oct 2007 02:00:00 +0300 53 | 54 | body 55 | 56 | From user@domain Sat Mar 24 23:00:00 2007 +0200 57 | Date: Sun, 28 Oct 2007 03:00:00 +0300 58 | 59 | body 60 | 61 | From user@domain Sat Mar 24 23:00:00 2007 +0200 62 | Date: Sun, 28 Oct 2007 03:00:00 +0200 63 | 64 | body 65 | 66 | From user@domain Sat Mar 24 23:00:00 2007 +0200 67 | Date: Sun, 28 Oct 2007 04:00:00 +0200 68 | 69 | body 70 | 71 | From user@domain Sat Mar 24 23:00:00 2007 +0200 72 | Date: Sun, 28 Oct 2007 23:00:00 +0200 73 | 74 | body 75 | 76 | From user@domain Sat Mar 24 23:00:00 2007 +0200 77 | Date: Mon, 29 Oct 2007 00:00:00 +0200 78 | 79 | body 80 | 81 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-flags: -------------------------------------------------------------------------------- 1 | messages: 5 2 | 3 | ok store 1 flags ($$hello) 4 | ok store 2 flags (\seen \flagged) 5 | ok store 3 flags (\answered $$hello) 6 | ok store 4 flags (\flagged \draft) 7 | ok store 5 flags (\deleted \answered) 8 | 9 | ok search answered 10 | * search 3 5 11 | ok search unanswered 12 | * search 1 2 4 13 | 14 | ok search deleted 15 | * search 5 16 | ok search undeleted 17 | * search 1 2 3 4 18 | 19 | ok search draft 20 | * search 4 21 | ok search undraft 22 | * search 1 2 3 5 23 | 24 | ok search flagged 25 | * search 2 4 26 | ok search unflagged 27 | * search 1 3 5 28 | 29 | ok search seen 30 | * search 2 31 | ok search unseen 32 | * search 1 3 4 5 33 | 34 | ok search keyword $$hello 35 | * search 1 3 36 | ok search unkeyword $$hello 37 | * search 2 4 5 38 | 39 | #ok search new 40 | #* search 1 3 4 5 41 | 42 | #ok search old 43 | #* search 44 | 45 | #ok search recent 46 | #* search 1 2 3 4 5 47 | 48 | ok store 1:* flags (\seen) 49 | ok store 2 +flags (\flagged) 50 | ok search seen flagged 51 | * search 2 52 | ok search seen not flagged 53 | * search 1 3 4 5 54 | ok search not seen flagged 55 | * search 56 | ok search not seen not flagged 57 | * search 58 | 59 | ok store 1:* flags (\deleted) 60 | ok store 2 +flags (\flagged) 61 | ok search deleted flagged 62 | * search 2 63 | ok search deleted not flagged 64 | * search 1 3 4 5 65 | ok search not deleted flagged 66 | * search 67 | ok search not deleted not flagged 68 | * search 69 | 70 | ok store 1:* flags (\seen \deleted) 71 | ok store 2 +flags (\flagged) 72 | ok search seen flagged 73 | * search 2 74 | ok search seen not flagged 75 | * search 1 3 4 5 76 | ok search not seen flagged 77 | * search 78 | ok search not seen not flagged 79 | * search 80 | ok search seen deleted flagged 81 | * search 2 82 | ok search seen deleted not flagged 83 | * search 1 3 4 5 84 | ok search not seen deleted flagged 85 | * search 86 | ok search not seen deleted not flagged 87 | * search 88 | ok search seen not deleted flagged 89 | * search 90 | ok search seen not deleted not flagged 91 | * search 92 | ok search not seen not deleted flagged 93 | * search 94 | ok search not seen not deleted not flagged 95 | * search 96 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-header: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | # just check that this returns ok. it's not really specified in RFC, so 4 | # don't verify the result. 5 | ok search subject "" 6 | 7 | # subject 8 | ok search subject hello 9 | * search 1 10 | ok search subject beautiful 11 | * search 1 12 | ok search subject world 13 | * search 1 14 | ok search subject "hello beautiful" 15 | * search 1 16 | ok search subject "hello beautiful world" 17 | * search 1 18 | #ok search subject "eautiful worl" 19 | #* search 1 20 | 21 | # header 22 | ok search header subject "" 23 | * search 1 24 | ok search not header subject "" 25 | * search 2 26 | #ok search header x-extra "" 27 | #* search 2 28 | #ok search not header x-extra "" 29 | #* search 1 30 | #ok search header x-extra hello 31 | #* search 2 32 | #ok search header x-extra "hello beautiful" 33 | #* search 2 34 | #ok search header x-extra "eautiful head" 35 | #* search 2 36 | #ok search header x-extra "another" 37 | #* search 2 38 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-header.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | Subject: hello beautiful world 3 | 4 | body 5 | 6 | From user@domain Fri Feb 22 17:06:23 2008 7 | X-Extra: hello beautiful header 8 | X-Extra: another one 9 | 10 | body 11 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-partial: -------------------------------------------------------------------------------- 1 | capabilities: CONTEXT=SEARCH 2 | messages: all 3 | 4 | ok search return (partial 1:1) all 5 | * esearch (tag $tag) partial (1:1 1) 6 | ok search return (partial 2:4) all 7 | * esearch (tag $tag) partial (2:4 2:4) 8 | ok search return (partial 4:2) all 9 | * esearch (tag $tag) partial (2:4 2:4) 10 | ok search return (partial 1:6) all 11 | * esearch (tag $tag) partial (1:6 1:5) 12 | ok search return (partial 6:6) all 13 | * esearch (tag $tag) partial (6:6 nil) 14 | 15 | ok search return (partial 1:3) 1:2,4:5 16 | * esearch (tag $tag) partial (1:3 1:2,4) 17 | ok search return (partial 2:3) 1:2,4:5 18 | * esearch (tag $tag) partial (2:3 2,4) 19 | ok search return (partial 2:4) 1:2,4:5 20 | * esearch (tag $tag) partial (2:4 2,4:5) 21 | ok search return (partial 2:10) 1:2,4:5 22 | * esearch (tag $tag) partial (2:10 2,4:5) 23 | 24 | # UID partials 25 | 26 | ok fetch 1 uid 27 | * 1 fetch (uid $uid1) 28 | ok fetch 2 uid 29 | * 2 fetch (uid $uid2) 30 | ok fetch 3 uid 31 | * 3 fetch (uid $uid3) 32 | ok fetch 5 uid 33 | * 5 fetch (uid $uid5) 34 | 35 | ok uid search return (partial 1:1) all 36 | * esearch (tag $tag) uid partial (1:1 $uid1) 37 | 38 | ok uid search return (partial 2:2) all 39 | * esearch (tag $tag) uid partial (2:2 $uid2) 40 | 41 | ok store 2 +flags \deleted 42 | ok expunge 43 | 44 | ok uid search return (partial 2:2) all 45 | * esearch (tag $tag) uid partial (2:2 $uid3) 46 | 47 | ok uid search return (partial 5:10) all 48 | * esearch (tag $tag) uid partial (5:10 nil) 49 | 50 | # broken results 51 | 52 | bad search return (partial 1) all 53 | bad search return (partial 1:*) all 54 | bad search return (partial *:1) all 55 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-partial.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:21 2008 2 | 3 | 1 4 | 5 | From user@domain Fri Feb 22 17:06:22 2008 6 | 7 | 2 8 | 9 | From user@domain Fri Feb 22 17:06:23 2008 10 | 11 | 3 12 | 13 | From user@domain Fri Feb 22 17:06:23 2008 14 | 15 | 4 16 | 17 | From user@domain Fri Feb 22 17:06:25 2008 18 | 19 | 5 20 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-sets: -------------------------------------------------------------------------------- 1 | messages: 6 2 | 3 | ok uid search all 4 | * search $uid1 $uid2 $uid3 $uid4 $uid5 $uid6 5 | ok status $mailbox (uidnext) 6 | * status $mailbox (uidnext $uidnext) 7 | 8 | # break seq=uid mapping 9 | ok store 2 +flags \deleted 10 | ok expunge 11 | * 2 expunge 12 | 13 | ok search all 14 | * search 1 2 3 4 5 15 | ok uid search all 16 | * search $uid1 $uid3 $uid4 $uid5 $uid6 17 | 18 | ok search 1:3,5 19 | * search 1 2 3 5 20 | ok search 4:2 21 | * search 2 3 4 22 | ok search uid $uid1:$uid3,$uid5 23 | * search 1 2 4 24 | ok search uid $uid4:$uid2 25 | * search 2 3 26 | 27 | ok search 1:3 not uid $uid3 28 | * search 1 3 29 | ok search not 2,4 30 | * search 1 3 5 31 | ok search or 1 uid $uid3 32 | * search 1 2 33 | 34 | ok search * 35 | * search 5 36 | ok search uid * 37 | * search 5 38 | ok search uid $uidnext:* 39 | * search 5 40 | ok search *:3 41 | * search 3 4 5 42 | ok search 1,4,* 43 | * search 1 4 5 44 | 45 | # These are in a bit of a grey area. Most servers allow them, but it's not 46 | # explicitly defined in the RFC that they're legal: 47 | #ok search 6:* 48 | #* search 5 49 | #ok search *:6 50 | #* search 5 51 | 52 | ok search (3) uid $uid4 53 | * search 3 54 | ok search (uid $uid4) 3 55 | * search 3 56 | ok search 3 (uid $uid4) 57 | * search 3 58 | 59 | ok uid search uid 1:4294967295 60 | * search $uid1 $uid3 $uid4 $uid5 $uid6 61 | ok uid search uid $uidnext:4294967295 62 | * search 63 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-size: -------------------------------------------------------------------------------- 1 | messages: all 2 | 3 | # get the middle size. don't trust precalculated values in case server 4 | # modifies the message while APPENDing it. Messages 3 and 4 have different 5 | # RFC822.SIZE, but with servers that store linefeeds as LFs they have the 6 | # same file size. This test catches if they search using file size. 7 | ok fetch 1:4 rfc822.size 8 | * 3 fetch (rfc822.size $size) 9 | 10 | ok search smaller $size 11 | * search 1 2 12 | ok search larger $size 13 | * search 4 14 | ok search not smaller $size 15 | * search 3 4 16 | ok search not larger $size 17 | * search 1 2 3 18 | 19 | ok search not smaller $size not larger $size 20 | * search 3 21 | ok search or smaller $size larger $size 22 | * search 1 2 4 23 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/search-size.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | 4 | 1 5 | 6 | From user@domain Fri Feb 22 17:06:23 2008 7 | Date: Sat, 24 Mar 2007 23:00:00 +0200 8 | 9 | 22 10 | 11 | From user@domain Fri Feb 22 17:06:23 2008 12 | Date: Sat, 24 Mar 2007 23:00:00 +0200 13 | 14 | 333 15 | 16 | From user@domain Fri Feb 22 17:06:23 2008 17 | Date: Sat, 24 Mar 2007 23:00:00 +0200 18 | 19 | 4 20 | 4 21 | 22 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/select: -------------------------------------------------------------------------------- 1 | state: created 2 | 3 | ok append 4 | ok append 5 | 6 | # first open read-only so recent flags don't get lost 7 | examine $mailbox 8 | * 2 exists 9 | #* 2 recent 10 | #* ok [unseen 1] 11 | * ok [uidvalidity $uidvalidity] 12 | * ok [uidnext $uidnext] 13 | ok [read-only] 14 | 15 | ok close 16 | 17 | # check that STATUS replies with the same values 18 | ok status $mailbox (messages uidnext uidvalidity unseen) 19 | * status $mailbox (messages 2 uidnext $uidnext uidvalidity $uidvalidity unseen 2) 20 | 21 | # then try read-write 22 | select $mailbox 23 | * 2 exists 24 | #* 2 recent 25 | #* ok [unseen 1] 26 | * ok [uidvalidity $uidvalidity] 27 | * ok [uidnext $uidnext] 28 | ok [read-write] 29 | 30 | ok close 31 | 32 | #ok status $mailbox (recent) 33 | #* status $mailbox (recent 0) 34 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/select.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | 4 | body 5 | 6 | From user@domain Fri Feb 22 17:06:23 2008 7 | Date: Sat, 24 Mar 2007 23:00:00 +0200 8 | 9 | body2 10 | 11 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-addresses: -------------------------------------------------------------------------------- 1 | capabilities: SORT 2 | messages: all 3 | 4 | ok sort (from) us-ascii all 5 | * sort 3 2 1 6 | ok sort (to) us-ascii all 7 | * sort 3 1 2 8 | ok sort (cc) us-ascii all 9 | * sort 3 1 2 10 | 11 | ok sort (reverse from) us-ascii all 12 | * sort 1 2 3 13 | ok sort (reverse to) us-ascii all 14 | * sort 1 2 3 15 | ok sort (reverse cc) us-ascii all 16 | * sort 1 2 3 17 | 18 | ok sort (from reverse arrival) us-ascii all 19 | * sort 3 2 1 20 | ok sort (to reverse arrival) us-ascii all 21 | * sort 3 2 1 22 | ok sort (cc reverse arrival) us-ascii all 23 | * sort 3 2 1 24 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-addresses.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 00:06:23 2008 2 | From: user2@domain2.org 3 | To: foo bar 4 | Cc: user2@domain2.org (foo bar) 5 | 6 | 1 7 | 8 | From user@domain Fri Feb 22 01:06:23 2008 9 | From: user2@domain1.org 10 | To: user2@domain1.org 11 | Cc: user2: blah@domain1.org; 12 | 13 | 2 14 | 15 | From user@domain Fri Feb 22 02:06:23 2008 16 | From: user1@domain1.org 17 | To: user1@domain1.org 18 | Cc: user1@domain1.org 19 | 20 | 3 21 | 22 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-arrival: -------------------------------------------------------------------------------- 1 | capabilities: SORT 2 | messages: all 3 | 4 | ok sort (arrival) us-ascii all 5 | * sort 1 3 2 4 5 6 | 7 | ok sort (reverse arrival) us-ascii all 8 | * sort 5 4 2 3 1 9 | 10 | ok sort (arrival reverse size) us-ascii all 11 | * sort 1 3 5 4 2 12 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-arrival.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 00:00:00 2008 2 | 3 | 1 4 | 5 | From user@domain Fri Feb 22 02:00:00 2008 6 | 7 | 2 8 | 9 | From user@domain Fri Feb 22 01:00:00 2008 10 | 11 | 33 12 | 13 | From user@domain Fri Feb 22 02:00:00 2008 14 | 15 | 44 16 | 17 | From user@domain Fri Feb 22 02:00:00 2008 18 | 19 | 5555 20 | 21 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-date: -------------------------------------------------------------------------------- 1 | capabilities: SORT 2 | messages: all 3 | 4 | ok sort (date) us-ascii all 5 | * sort 1 3 7 5 2 4 6 6 | 7 | ok sort (reverse date) us-ascii all 8 | * sort 2 4 6 5 3 7 1 9 | 10 | ok sort (date reverse size) us-ascii all 11 | * sort 1 7 3 5 6 4 2 12 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-date.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 23:00:00 2008 +0200 2 | Date: Fri, 22 Feb 2008 00:00:00 +0200 3 | 4 | 1 5 | 6 | From user@domain Fri Feb 22 22:00:00 2008 +0200 7 | Date: Fri, 22 Feb 2008 02:00:00 +0200 8 | 9 | 2 10 | 11 | From user@domain Fri Feb 22 21:00:00 2008 +0200 12 | Date: Fri, 22 Feb 2008 01:00:00 +0200 13 | 14 | 33 15 | 16 | From user@domain Fri Feb 22 20:00:00 2008 +0200 17 | Date: Fri, 22 Feb 2008 02:00:00 +0200 18 | 19 | 44 20 | 21 | From user@domain Fri Feb 22 01:30:23 2008 +0200 22 | Subject: foo 23 | 24 | 55555 25 | 26 | From user@domain Fri Feb 22 18:00:00 2008 +0200 27 | Date: Fri, 22 Feb 2008 02:00:00 +0200 28 | 29 | 6666 30 | 31 | From user@domain Fri Feb 22 01:00:00 2008 +0200 32 | Subject: foo bar foo bar foo bar fooo 33 | 34 | 777 35 | 36 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-display-from: -------------------------------------------------------------------------------- 1 | capabilities: SORT=DISPLAY 2 | messages: all 3 | 4 | ok sort (displayfrom) us-ascii all 5 | * sort 2 3 4 1 5 6 | 7 | ok sort (reverse displayfrom) us-ascii all 8 | * sort 5 1 4 3 2 9 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-display-from.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 23:00:00 2008 +0200 2 | From: foo bar 3 | 4 | 1 5 | 6 | From user@domain Fri Feb 22 23:00:00 2008 +0200 7 | From: b@c.d 8 | 9 | 2 10 | 11 | From user@domain Fri Feb 22 23:00:00 2008 +0200 12 | From: d 13 | 14 | 3 15 | 16 | From user@domain Fri Feb 22 23:00:00 2008 +0200 17 | From: =?iso-8859-1?q?foo_aar?= 18 | 19 | 4 20 | 21 | From user@domain Fri Feb 22 23:00:00 2008 +0200 22 | From: =?iso-8859-1?q?foo_car?= 23 | 24 | 5 25 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-display-to: -------------------------------------------------------------------------------- 1 | capabilities: SORT=DISPLAY 2 | messages: all 3 | 4 | ok sort (displayto) us-ascii all 5 | * sort 6 2 3 8 4 1 5 7 6 | 7 | ok sort (reverse displayto) us-ascii all 8 | * sort 7 5 1 4 8 3 2 6 9 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-display-to.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 23:00:00 2008 +0200 2 | To: foo bar 3 | 4 | 1 5 | 6 | From user@domain Fri Feb 22 23:00:00 2008 +0200 7 | To: b@c.d 8 | 9 | 2 10 | 11 | From user@domain Fri Feb 22 23:00:00 2008 +0200 12 | To: d 13 | 14 | 3 15 | 16 | From user@domain Fri Feb 22 23:00:00 2008 +0200 17 | To: =?iso-8859-1?q?foo_aar?= 18 | 19 | 4 20 | 21 | From user@domain Fri Feb 22 23:00:00 2008 +0200 22 | To: =?iso-8859-1?q?foo_car?= 23 | 24 | 5 25 | 26 | From user@domain Fri Feb 22 23:00:00 2008 +0200 27 | To: a: xx@xx.org, yy@yy.org; 28 | 29 | 6 30 | 31 | From user@domain Fri Feb 22 23:00:00 2008 +0200 32 | To: z: aa@aa.org, bb@bb.org; 33 | 34 | 7 35 | 36 | From user@domain Fri Feb 22 23:00:00 2008 +0200 37 | To: empty:; 38 | 39 | 8 40 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-partial: -------------------------------------------------------------------------------- 1 | capabilities: CONTEXT=SORT 2 | messages: all 3 | 4 | ok sort return (partial 1:1) (arrival) us-ascii all 5 | * esearch (tag $tag) partial (1:1 1) 6 | ok sort return (partial 2:4) (arrival) us-ascii all 7 | * esearch (tag $tag) partial (2:4 2:4) 8 | ok sort return (partial 4:2) (arrival) us-ascii all 9 | * esearch (tag $tag) partial (2:4 2:4) 10 | ok sort return (partial 2:4) (reverse arrival) us-ascii all 11 | * esearch (tag $tag) partial (2:4 3:4,2) 12 | ok sort return (partial 1:6) (arrival) us-ascii all 13 | * esearch (tag $tag) partial (1:6 1:5) 14 | ok sort return (partial 1:6) (reverse arrival) us-ascii all 15 | * esearch (tag $tag) partial (1:6 5,3:4,2,1) 16 | 17 | bad sort return (partial 1) (arrival) us-ascii all 18 | bad sort return (partial 1:*) (arrival) us-ascii all 19 | bad sort return (partial *:1) (arrival) us-ascii all 20 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-partial.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:21 2008 2 | 3 | 1 4 | 5 | From user@domain Fri Feb 22 17:06:22 2008 6 | 7 | 2 8 | 9 | From user@domain Fri Feb 22 17:06:23 2008 10 | 11 | 3 12 | 13 | From user@domain Fri Feb 22 17:06:23 2008 14 | 15 | 4 16 | 17 | From user@domain Fri Feb 22 17:06:25 2008 18 | 19 | 5 20 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-size: -------------------------------------------------------------------------------- 1 | capabilities: SORT 2 | messages: all 3 | 4 | ok sort (size) us-ascii all 5 | * sort 1 8 2 6 3 5 4 7 6 | 7 | ok sort (reverse size) us-ascii all 8 | * sort 7 4 5 3 6 2 8 1 9 | 10 | ok sort (size reverse arrival) us-ascii all 11 | * sort 8 1 6 2 5 3 7 4 12 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-size.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 00:06:23 2008 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | 4 | 1 5 | 6 | From user@domain Fri Feb 22 01:06:23 2008 7 | Date: Sat, 24 Mar 2007 23:00:00 +0200 8 | 9 | 22 10 | 11 | From user@domain Fri Feb 22 02:06:23 2008 12 | Date: Sat, 24 Mar 2007 23:00:00 +0200 13 | 14 | 333 15 | 16 | From user@domain Fri Feb 22 03:06:23 2008 17 | Date: Sat, 24 Mar 2007 23:00:00 +0200 18 | 19 | 4 20 | 4 21 | 22 | From user@domain Fri Feb 22 04:06:23 2008 23 | Date: Sat, 24 Mar 2007 23:00:00 +0200 24 | 25 | 555 26 | 27 | From user@domain Fri Feb 22 05:06:23 2008 28 | Date: Sat, 24 Mar 2007 23:00:00 +0200 29 | 30 | 66 31 | 32 | From user@domain Fri Feb 22 06:06:23 2008 33 | Date: Sat, 24 Mar 2007 23:00:00 +0200 34 | 35 | 7777 36 | 37 | From user@domain Fri Feb 22 07:06:23 2008 38 | Date: Sat, 24 Mar 2007 23:00:00 +0200 39 | 40 | 8 41 | 42 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-subject: -------------------------------------------------------------------------------- 1 | capabilities: SORT 2 | messages: all 3 | 4 | ok sort (subject) us-ascii all 5 | * sort 9 10 1 14 3 5 11 6 15 2 7 12 13 8 4 6 | 7 | ok sort (reverse subject) us-ascii all 8 | * sort 4 8 2 7 12 13 15 6 3 5 11 14 1 9 10 9 | 10 | ok sort (subject reverse size) us-ascii all 11 | * sort 10 9 1 14 11 5 3 6 15 13 12 7 2 8 4 12 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/sort-subject.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 23:00:00 2008 +0200 2 | Subject: a 3 | 4 | 1 5 | 6 | From user@domain Fri Feb 22 23:00:00 2008 +0200 7 | Subject: C 8 | 9 | 2 10 | 11 | From user@domain Fri Feb 22 23:00:00 2008 +0200 12 | Subject: b 13 | 14 | 3 15 | 16 | From user@domain Fri Feb 22 23:00:00 2008 +0200 17 | Subject: _ 18 | 19 | 4 20 | 21 | From user@domain Fri Feb 22 23:00:00 2008 +0200 22 | Subject: [foo] Fwd: [bar] Re: fw: b (fWd) (fwd) 23 | 24 | 55 25 | 26 | From user@domain Fri Feb 22 23:00:00 2008 +0200 27 | Subject: b (a) 28 | 29 | 66 30 | 31 | From user@domain Fri Feb 22 23:00:00 2008 +0200 32 | Subject: Re: [FWD: c] 33 | 34 | 77 35 | 36 | From user@domain Fri Feb 22 23:00:00 2008 +0200 37 | Subject: [xyz] 38 | 39 | 88 40 | 41 | From user@domain Fri Feb 22 23:00:00 2008 +0200 42 | 43 | 9 44 | 45 | From user@domain Fri Feb 22 23:00:00 2008 +0200 46 | Subject: =?iso-8859-1?q?_?= 47 | 48 | 10 49 | 50 | From user@domain Fri Feb 22 23:00:00 2008 +0200 51 | Subject: Re: =?utf-8?q?b?= 52 | 53 | 11 54 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 55 | 56 | From user@domain Fri Feb 22 23:00:00 2008 +0200 57 | Subject: =?iso-8859-1?q?RE:_C?= 58 | 59 | 12 60 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 61 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 62 | 63 | From user@domain Fri Feb 22 23:00:00 2008 +0200 64 | Subject: =?us-ascii?b?UmU6IGM=?= 65 | 66 | 13 67 | 68 | The subject is 'Re: c'. 69 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 70 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 71 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 72 | 73 | From user@domain Fri Feb 22 23:00:00 2008 +0200 74 | Subject: Ad: Re: Ad: Re: Ad: x 75 | 76 | 14 77 | 78 | From user@domain Fri Feb 22 23:00:00 2008 +0200 79 | Subject: re: [fwd: [fwd: re: [fwd: babylon]]] 80 | 81 | 15 82 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/store: -------------------------------------------------------------------------------- 1 | connections: 2 2 | messages: 4 3 | 4 | # simple tests 5 | 1 ok store 1:3 flags (\seen) 6 | * 1 fetch (flags (\seen)) 7 | * 2 fetch (flags (\seen)) 8 | * 3 fetch (flags (\seen)) 9 | 10 | 2 ok check 11 | * 1 fetch (flags (\seen)) 12 | * 2 fetch (flags (\seen)) 13 | * 3 fetch (flags (\seen)) 14 | 15 | 1 ok store 4 -flags \seen 16 | 1 ok store 3 flags (\draft) 17 | * 3 fetch (flags (\draft)) 18 | 19 | # keywords 20 | 1 ok store 2,4 +flags ($$hello $$world) 21 | * 2 fetch (flags (\seen $$hello $$world)) 22 | * 4 fetch (flags ($$hello $$world)) 23 | 24 | # check that two sessions don't overwrite each others' changes 25 | 1 ok store 1 +flags (\answered) 26 | 2 ok store 1 -flags (\seen) 27 | 1 ok check 28 | 2 ok check 29 | 30 | 1 ok fetch 1 flags 31 | * 1 fetch (flags (\answered)) 32 | 2 ok fetch 1 flags 33 | * 1 fetch (flags (\answered)) 34 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/subscribe: -------------------------------------------------------------------------------- 1 | connections: 2 2 | state: auth 3 | 4 | # get the separator 5 | 1 ok list "" "" 6 | * list () $sep $root 7 | 8 | 1 "" unsubscribe $mailbox${sep}test 9 | 1 "" unsubscribe $mailbox${sep}test2 10 | 1 "" unsubscribe $mailbox${sep}test2${sep}test 11 | 1 "" unsubscribe $mailbox${sep}test3${sep}test3 12 | 13 | 1 ok create $mailbox${sep} 14 | 1 ok create $mailbox${sep}test 15 | 1 ok create $mailbox${sep}test2${sep} 16 | 1 ok create $mailbox${sep}test3${sep} 17 | 1 ok create $mailbox${sep}test2${sep}test 18 | 1 ok create $mailbox${sep}test3${sep}test3 19 | # create the test2 mailbox only if server supports inferior mailboxes 20 | 1 "" create $mailbox${sep}test2 21 | 22 | 1 ok subscribe $mailbox${sep}test 23 | 1 ok subscribe $mailbox${sep}test2${sep}test 24 | 1 ok subscribe $mailbox${sep}test3${sep}test3 25 | 26 | 2 ok lsub "" $mailbox${sep}% 27 | * lsub () $sep $mailbox${sep}test 28 | #* lsub (\noselect) $sep $mailbox${sep}test2 29 | #* lsub (\noselect) $sep $mailbox${sep}test3 30 | ! lsub (\noselect) $sep $mailbox${sep}test2${sep}test 31 | ! lsub (\noselect) $sep $mailbox${sep}test3${sep}test3 32 | 33 | 2 ok lsub "" *test 34 | * lsub () $sep $mailbox${sep}test 35 | * lsub () $sep $mailbox${sep}test2${sep}test 36 | ! lsub () $sep $mailbox${sep}test3${sep}test3 37 | 38 | 1 ok unsubscribe $mailbox${sep}test 39 | 2 ok lsub "" $mailbox${sep}% 40 | ! lsub () $sep $mailbox${sep}test 41 | 42 | 1 ok unsubscribe $mailbox${sep}test2${sep}test 43 | 2 ok lsub "" $mailbox${sep}* 44 | ! lsub () $sep $mailbox${sep}test 45 | * lsub () $sep $mailbox${sep}test3${sep}test3 46 | 47 | 1 ok unsubscribe $mailbox${sep}test3${sep}test3 48 | 2 ok lsub "" $mailbox${sep}% 49 | ! lsub () $sep $mailbox${sep}test3 50 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=REFERENCES 2 | messages: all 3 | 4 | ok thread references us-ascii all 5 | * thread (3 2)(1) 6 | 7 | ok store 1 +flags \deleted 8 | ok expunge 9 | 10 | ok thread references us-ascii all 11 | * thread (2 1) 12 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread-orderedsubject: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=ORDEREDSUBJECT 2 | messages: all 3 | 4 | ok thread orderedsubject us-ascii all 5 | * THREAD (1)(2 (7)(12)(13))(3 (5)(11))(4)(6)(8)(9 10)(14)(15) 6 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread-orderedsubject.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 23:00:00 2008 +0200 2 | Subject: a 3 | 4 | 1 5 | 6 | From user@domain Fri Feb 22 23:00:00 2008 +0200 7 | Subject: C 8 | 9 | 2 10 | 11 | From user@domain Fri Feb 22 23:00:00 2008 +0200 12 | Subject: b 13 | 14 | 3 15 | 16 | From user@domain Fri Feb 22 23:00:00 2008 +0200 17 | Subject: _ 18 | 19 | 4 20 | 21 | From user@domain Fri Feb 22 23:00:00 2008 +0200 22 | Subject: [foo] Fwd: [bar] Re: fw: b (fWd) (fwd) 23 | 24 | 55 25 | 26 | From user@domain Fri Feb 22 23:00:00 2008 +0200 27 | Subject: b (a) 28 | 29 | 66 30 | 31 | From user@domain Fri Feb 22 23:00:00 2008 +0200 32 | Subject: Re: [FWD: c] 33 | 34 | 77 35 | 36 | From user@domain Fri Feb 22 23:00:00 2008 +0200 37 | Subject: [xyz] 38 | 39 | 88 40 | 41 | From user@domain Fri Feb 22 23:00:00 2008 +0200 42 | 43 | 9 44 | 45 | From user@domain Fri Feb 22 23:00:00 2008 +0200 46 | Subject: =?iso-8859-1?q?_?= 47 | 48 | 10 49 | 50 | From user@domain Fri Feb 22 23:00:00 2008 +0200 51 | Subject: Re: =?utf-8?q?b?= 52 | 53 | 11 54 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 55 | 56 | From user@domain Fri Feb 22 23:00:00 2008 +0200 57 | Subject: =?iso-8859-1?q?RE:_C?= 58 | 59 | 12 60 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 61 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 62 | 63 | From user@domain Fri Feb 22 23:00:00 2008 +0200 64 | Subject: =?us-ascii?b?UmU6IGM=?= 65 | 66 | 13 67 | 68 | The subject is 'Re: c'. 69 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 70 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 71 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 72 | 73 | From user@domain Fri Feb 22 23:00:00 2008 +0200 74 | Subject: Ad: Re: Ad: Re: Ad: x 75 | 76 | 14 77 | 78 | From user@domain Fri Feb 22 23:00:00 2008 +0200 79 | Subject: re: [fwd: [fwd: re: [fwd: babylon]]] 80 | 81 | 15 82 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread-orderedsubject2: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=ORDEREDSUBJECT 2 | messages: all 3 | 4 | ok thread orderedsubject us-ascii all 5 | * THREAD (4 (2)(8)(6))(3 (1)(7)(5)) 6 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread-orderedsubject2.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 23:00:01 2008 +0200 2 | Subject: a 3 | Date: Fri, 22 Feb 2008 22:00:10 +0200 4 | 5 | 1 6 | 7 | From user@domain Fri Feb 22 23:00:02 2008 +0200 8 | Date: Fri, 22 Feb 2008 22:00:09 +0200 9 | Subject: b 10 | 11 | 2 12 | 13 | From user@domain Fri Feb 22 23:00:03 2008 +0200 14 | Date: Fri, 22 Feb 2008 22:00:08 +0200 15 | Subject: a 16 | 17 | 3 18 | 19 | From user@domain Fri Feb 22 23:00:04 2008 +0200 20 | Date: Fri, 22 Feb 2008 22:00:07 +0200 21 | Subject: b 22 | 23 | 4 24 | 25 | From user@domain Fri Feb 22 22:00:30 2008 +0200 26 | Subject: a 27 | 28 | 5 29 | 30 | From user@domain Fri Feb 22 22:00:29 2008 +0200 31 | Subject: b 32 | 33 | 6 34 | 35 | From user@domain Fri Feb 22 22:00:28 2008 +0200 36 | Subject: a 37 | 38 | 7 39 | 40 | From user@domain Fri Feb 22 22:00:27 2008 +0200 41 | Subject: b 42 | 43 | 8 44 | 45 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | Message-ID: 3 | 4 | body 5 | 6 | From user@domain Fri Feb 22 15:06:23 2008 7 | Message-Id: 8 | References: 9 | 10 | body 11 | 12 | From user@domain Fri Feb 22 16:06:25 2008 13 | Message-Id: 14 | References: 15 | 16 | body 17 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread2: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=REFERENCES 2 | messages: all 3 | 4 | ok thread references us-ascii all 5 | * thread (1)(2) 6 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread2.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 15:06:23 2008 2 | Message-Id: 3 | 4 | body 5 | 6 | From user@domain Fri Feb 22 15:06:23 2008 7 | Message-Id: 8 | 9 | body 10 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread3: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=REFERENCES 2 | messages: all 3 | 4 | ok thread references us-ascii all 5 | * THREAD (1 2) 6 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread3.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 15:06:23 2008 2 | Message-Id: 3 | Subject: foo 4 | 5 | body 6 | 7 | From user@domain Fri Feb 22 15:06:24 2008 8 | Message-Id: 9 | Subject: Re: foo 10 | 11 | body 12 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread4: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=REFERENCES 2 | messages: all 3 | 4 | ok thread references us-ascii all 5 | * THREAD (1 2) 6 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread4.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 15:06:23 2008 2 | Message-Id: 3 | Subject: foo 4 | 5 | body 6 | 7 | From user@domain Fri Feb 22 15:06:24 2008 8 | Message-Id: 9 | References: 10 | Subject: Re: foo 11 | 12 | body 13 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread5: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=REFERENCES 2 | state: created 3 | 4 | ok append 5 | ok append 6 | ok append 7 | ok append 8 | 9 | ok select $mailbox 10 | ok thread references us-ascii all 11 | * THREAD (1 (2 4)(3)) 12 | 13 | ok store 1,2 +flags \deleted 14 | ok expunge 15 | ok thread references us-ascii all 16 | * THREAD (1)(2) 17 | 18 | ok append 19 | ok thread references us-ascii all 20 | * THREAD (1)((2)(3)) 21 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread5.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | Message-ID: <1@b> 3 | 4 | body 5 | 6 | From user@domain Fri Feb 22 15:06:23 2008 7 | Message-Id: <2@b> 8 | In-Reply-To: <1@b> 9 | 10 | body 11 | 12 | From user@domain Fri Feb 22 15:06:23 2008 13 | Message-Id: <3@b> 14 | In-Reply-To: <1@b> 15 | 16 | body 17 | 18 | From user@domain Fri Feb 22 15:06:23 2008 19 | Message-Id: <4@b> 20 | In-Reply-To: <2@b> 21 | 22 | body 23 | 24 | From user@domain Fri Feb 22 15:06:23 2008 25 | Message-Id: <5@b> 26 | In-Reply-To: <2@b> 27 | 28 | body 29 | 30 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread6: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=REFERENCES 2 | messages: all 3 | 4 | ok thread references us-ascii all 5 | * THREAD ((1)(2)) 6 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread6.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 15:06:23 2008 2 | References: 3 | 4 | body 5 | 6 | From user@domain Fri Feb 22 15:06:24 2008 7 | References: 8 | 9 | body 10 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread7: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=REFERENCES 2 | messages: all 3 | 4 | ok thread references us-ascii all 5 | * thread (1 (2 3)(4)) 6 | 7 | ok store 2 +flags \deleted 8 | ok expunge 9 | 10 | ok thread references us-ascii all 11 | * thread (1 3 2) 12 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread7.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 15:06:23 2008 2 | Message-Id: 3 | 4 | body1 5 | 6 | From user@domain Fri Feb 22 15:06:23 2008 7 | Message-Id: 8 | References: 9 | 10 | body2 11 | 12 | From user@domain Fri Feb 22 15:06:23 2008 13 | Message-Id: 14 | References: 15 | 16 | body3 17 | 18 | From user@domain Fri Feb 22 15:06:23 2008 19 | Message-Id: 20 | References: 21 | 22 | body4 (2 duplicate) 23 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread8: -------------------------------------------------------------------------------- 1 | capabilities: THREAD=REFERENCES 2 | state: created 3 | 4 | ok append 5 | ok append 6 | ok select $mailbox 7 | 8 | ok thread references us-ascii all 9 | * thread (1 2) 10 | 11 | ok store 2 +flags \deleted 12 | ok expunge 13 | 14 | ok thread references us-ascii all 15 | * thread (1) 16 | 17 | ok append 18 | 19 | ok thread references us-ascii all 20 | * thread (1 2) 21 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/thread8.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 15:06:23 2008 2 | Message-Id: 3 | 4 | body1 5 | 6 | From user@domain Fri Feb 22 15:06:23 2008 7 | Message-Id: 8 | References: 9 | 10 | body2 11 | 12 | From user@domain Fri Feb 22 15:06:23 2008 13 | Message-Id: 14 | References: 15 | 16 | body3 17 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/uidplus: -------------------------------------------------------------------------------- 1 | capabilities: UIDPLUS 2 | state: created 3 | 4 | ok select ${mailbox} 5 | ok append 6 | 7 | "" delete ${mailbox}2 8 | ok create ${mailbox}2 9 | 10 | append ${mailbox}2 11 | ok [appenduid $uidvalidity $uid] 12 | 13 | copy 1 ${mailbox}2 14 | ok [copyuid $uidvalidity $srcuid $uid2] 15 | 16 | ok select ${mailbox}2 17 | * ok [uidvalidity $uidvalidity] 18 | ok fetch 1:2 uid 19 | * 1 fetch (uid $uid) 20 | * 2 fetch (uid $uid2) 21 | 22 | ok close 23 | "" delete ${mailbox}2 24 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/uidvalidity: -------------------------------------------------------------------------------- 1 | connections: 2 2 | state: created 3 | 4 | 1 ok append 5 | 1 ok status $mailbox (uidvalidity uidnext) 6 | * status $mailbox (uidvalidity $uidvalidity uidnext $uidnext) 7 | 1 ok delete $mailbox 8 | 9 | 2 ok create $mailbox 10 | 2 ok append $mailbox 11 | 12 | #1 ok status $mailbox (uidvalidity uidnext) 13 | #! status $mailbox (uidvalidity $uidvalidity uidnext $uidnext) 14 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/uidvalidity-rename: -------------------------------------------------------------------------------- 1 | connections: 2 2 | state: auth 3 | 4 | 1 ok create ${mailbox} 5 | 2 ok create ${mailbox}2 6 | 7 | 1 ok append 8 | 2 ok append 9 | 10 | 1 ok status $mailbox (uidvalidity uidnext) 11 | * status $mailbox (uidvalidity $uidvalidity uidnext $uidnext) 12 | 13 | 1 ok rename ${mailbox} ${mailbox}3 14 | 2 ok rename ${mailbox}2 ${mailbox} 15 | 16 | #1 ok status $mailbox (uidvalidity uidnext) 17 | #! status $mailbox (uidvalidity $uidvalidity uidnext $uidnext) 18 | 19 | 1 "" delete ${mailbox}3 20 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/urlauth: -------------------------------------------------------------------------------- 1 | capabilities: urlauth 2 | messages: 2 3 | 4 | ok fetch 1:2 (uid body[]) 5 | * 1 fetch (uid $uid1 body[] $body1) 6 | * 2 fetch (uid $uid2 body[] $body2) 7 | 8 | ok GENURLAUTH "imap://$username@$domain/$mailbox_url/;uid=$uid1;urlauth=user+$user" INTERNAL 9 | * GENURLAUTH $mail_url1 10 | 11 | ok GENURLAUTH "imap://$username@$domain/$mailbox_url/;uid=$uid2;urlauth=user+$user" INTERNAL 12 | * GENURLAUTH $mail_url2 13 | 14 | ok URLFETCH $mail_url1 15 | * URLFETCH $mail_url1 $body1 16 | 17 | ok URLFETCH $mail_url2 18 | * URLFETCH $mail_url2 $body2 19 | 20 | ok resetkey $mailbox 21 | 22 | ok URLFETCH $mail_url1 23 | * URLFETCH $mail_url1 NIL 24 | 25 | ok URLFETCH $mail_url2 26 | * URLFETCH $mail_url2 NIL 27 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/urlauth-binary.mbox: -------------------------------------------------------------------------------- 1 | From user@domain Fri Feb 22 17:06:23 2008 2 | From: user@domain.org 3 | Date: Sat, 24 Mar 2007 23:00:00 +0200 4 | Mime-Version: 1.0 5 | Content-Type: multipart/mixed; boundary="foo 6 | bar" 7 | 8 | Root MIME prologue 9 | 10 | --foo bar 11 | Content-Type: message/rfc822 12 | 13 | From: sub@domain.org 14 | Date: Sun, 12 Aug 2012 12:34:56 +0300 15 | Subject: submsg 16 | Content-Type: multipart/alternative; boundary="sub1" 17 | 18 | Sub MIME prologue 19 | --sub1 20 | Content-Type: text/x-myown; charset=us-ascii 21 | Content-Transfer-Encoding: base64 22 | 23 | aGVs 24 | bG8gd29y 25 | bGQ= 26 | 27 | --sub1 28 | Content-Type: text/x-myown; charset=us-ascii 29 | Content-Transfer-Encoding: base64 30 | 31 | aGVs 32 | bG8g 33 | d29y 34 | bGQ= 35 | 36 | 37 | --sub1-- 38 | Sub MIME epilogue 39 | 40 | --foo bar-- 41 | Root MIME epilogue 42 | -------------------------------------------------------------------------------- /src/tests/resources/imap-test/urlauth2: -------------------------------------------------------------------------------- 1 | capabilities: urlauth 2 | connections: 2 3 | user 2: $user2 4 | 5 | 1 ok fetch 1:2 (uid body[]) 6 | * 1 fetch (uid $uid1 body[] $body1) 7 | * 2 fetch (uid $uid2 body[] $body2) 8 | 9 | 1 ok GENURLAUTH "imap://$username@$domain/$mailbox_url/;uid=$uid1;urlauth=authuser" INTERNAL 10 | * GENURLAUTH $mail_url1 11 | 12 | 1 ok GENURLAUTH "imap://$username@$domain/$mailbox_url/;uid=$uid2;urlauth=authuser" INTERNAL 13 | * GENURLAUTH $mail_url2 14 | 15 | 2 ok URLFETCH $mail_url1 16 | * URLFETCH $mail_url1 $body1 17 | 18 | 2 ok URLFETCH $mail_url2 19 | * URLFETCH $mail_url2 $body2 20 | 21 | 1 ok resetkey $mailbox 22 | 23 | 2 ok URLFETCH $mail_url1 24 | * URLFETCH $mail_url1 NIL 25 | 26 | 2 ok URLFETCH $mail_url2 27 | * URLFETCH $mail_url2 NIL 28 | -------------------------------------------------------------------------------- /src/tests/resources/messages/000.txt: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 2 | From: Nathaniel Borenstein 3 | To: Ned Freed 4 | Date: Fri, 07 Oct 1994 16:15:05 -0700 (PDT) 5 | Subject: A multipart example 6 | Content-Type: multipart/mixed; 7 | boundary=unique-boundary-1 8 | 9 | This is the preamble area of a multipart message. 10 | Mail readers that understand multipart format 11 | should ignore this preamble. 12 | 13 | If you are reading this text, you might want to 14 | consider changing to a mail reader that understands 15 | how to properly display multipart messages. 16 | 17 | --unique-boundary-1 18 | 19 | ... Some text appears here ... 20 | 21 | [Note that the blank between the boundary and the start 22 | of the text in this part means no header fields were 23 | given and this is text in the US-ASCII character set. 24 | It could have been done with explicit typing as in the 25 | next part.] 26 | 27 | --unique-boundary-1 28 | Content-type: text/plain; charset=US-ASCII 29 | 30 | This could have been part of the previous part, but 31 | illustrates explicit versus implicit typing of body 32 | parts. 33 | 34 | --unique-boundary-1 35 | Content-Type: multipart/parallel; boundary=unique-boundary-2 36 | 37 | --unique-boundary-2 38 | Content-Type: audio/basic 39 | Content-Transfer-Encoding: base64 40 | 41 | ... base64-encoded 8000 Hz single-channel 42 | mu-law-format audio data goes here ... 43 | 44 | --unique-boundary-2 45 | Content-Type: image/jpeg 46 | Content-Transfer-Encoding: base64 47 | 48 | ... base64-encoded image data goes here ... 49 | 50 | --unique-boundary-2-- 51 | 52 | --unique-boundary-1 53 | Content-type: text/enriched 54 | 55 | This is enriched. 56 | as defined in RFC 1896 57 | 58 | Isn't it 59 | cool? 60 | 61 | --unique-boundary-1 62 | Content-Type: message/rfc822 63 | 64 | From: (mailbox in US-ASCII) 65 | To: (address in US-ASCII) 66 | Subject: (subject in US-ASCII) 67 | Content-Type: Text/plain; charset=ISO-8859-1 68 | Content-Transfer-Encoding: Quoted-printable 69 | 70 | ... Additional text in ISO-8859-1 goes here ... 71 | 72 | --unique-boundary-1-- 73 | 74 | -------------------------------------------------------------------------------- /src/tests/resources/messages/001.txt: -------------------------------------------------------------------------------- 1 | From: Whomever 2 | To: Someone 3 | Date: Whenever 4 | Subject: whatever 5 | MIME-Version: 1.0 6 | Message-ID: 7 | Content-Type: multipart/alternative; boundary=42 8 | Content-ID: 9 | 10 | --42 11 | Content-Type: message/external-body; name="BodyFormats.ps"; 12 | site="thumper.bellcore.com"; mode="image"; 13 | access-type=ANON-FTP; directory="pub"; 14 | expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" 15 | 16 | Content-type: application/postscript 17 | Content-ID: 18 | 19 | --42 20 | Content-Type: message/external-body; access-type=local-file; 21 | name="/u/nsb/writing/rfcs/RFC-MIME.ps"; 22 | site="thumper.bellcore.com"; 23 | expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" 24 | 25 | Content-type: application/postscript 26 | Content-ID: 27 | 28 | --42 29 | Content-Type: message/external-body; 30 | access-type=mail-server 31 | server="listserv@bogus.bitnet"; 32 | expiration="Fri, 14 Jun 1991 19:13:14 -0400 (EDT)" 33 | 34 | Content-type: application/postscript 35 | Content-ID: 36 | 37 | get RFC-MIME.DOC 38 | 39 | --42-- 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/tests/resources/messages/002.txt: -------------------------------------------------------------------------------- 1 | From: Al Gore 2 | To: White House Transportation Coordinator 3 | 4 | Subject: [Fwd: Map of Argentina with Description] 5 | Content-Type: multipart/mixed; 6 | boundary="D7F------------D7FD5A0B8AB9C65CCDBFA872" 7 | 8 | This is a multi-part message in MIME format. 9 | --D7F------------D7FD5A0B8AB9C65CCDBFA872 10 | Content-Type: text/plain; charset=us-ascii 11 | Content-Transfer-Encoding: 7bit 12 | 13 | Fred, 14 | 15 | Fire up Air Force One! We're going South! 16 | 17 | Thanks, 18 | Al 19 | --D7F------------D7FD5A0B8AB9C65CCDBFA872 20 | Content-Type: message/rfc822 21 | Content-Transfer-Encoding: 7bit 22 | Content-Disposition: inline 23 | 24 | Return-Path: 25 | Received: from mailhost.whitehouse.gov ([192.168.51.200]) 26 | by heartbeat.whitehouse.gov (8.8.8/8.8.8) with ESMTP id SAA22453 27 | for ; 28 | Mon, 13 Aug 1998 l8:14:23 +1000 29 | Received: from the_big_box.whitehouse.gov ([192.168.51.50]) 30 | by mailhost.whitehouse.gov (8.8.8/8.8.7) with ESMTP id RAA20366 31 | for vice-president@whitehouse.gov; Mon, 13 Aug 1998 17:42:41 +1000 32 | Date: Mon, 13 Aug 1998 17:42:41 +1000 33 | Message-Id: <199804130742.RAA20366@mai1host.whitehouse.gov> 34 | From: Bill Clinton 35 | To: A1 (The Enforcer) Gore 36 | Subject: Map of Argentina with Description 37 | MIME-Version: 1.0 38 | Content-Type: multipart/mixed; 39 | boundary="DC8------------DC8638F443D87A7F0726DEF7" 40 | 41 | This is a multi-part message in MIME format. 42 | --DC8------------DC8638F443D87A7F0726DEF7 43 | Content-Type: text/plain; charset=us-ascii 44 | Content-Transfer-Encoding: 7bit 45 | 46 | Hi A1, 47 | 48 | I finally figured out this MIME thing. Pretty cool. I'll send you 49 | some sax music in .au files next week! 50 | 51 | Anyway, the attached image is really too small to get a good look at 52 | Argentina. Try this for a much better map: 53 | 54 | http://www.1one1yp1anet.com/dest/sam/graphics/map-arg.htm 55 | 56 | Then again, shouldn't the CIA have something like that? 57 | 58 | Bill 59 | --DC8------------DC8638F443D87A7F0726DEF7 60 | Content-Type: image/gif; name="map_of_Argentina.gif" 61 | Content-Transfer-Encoding: base64 62 | Content-Disposition: inline; fi1ename="map_of_Argentina.gif" 63 | 64 | R01GOD1hJQA1AKIAAP/////78P/omn19fQAAAAAAAAAAAAAAACwAAAAAJQA1AAAD7Qi63P5w 65 | wEmjBCLrnQnhYCgM1wh+pkgqqeC9XrutmBm7hAK3tP31gFcAiFKVQrGFR6kscnonTe7FAAad 66 | GugmRu3CmiBt57fsVq3Y0VFKnpYdxPC6M7Ze4crnnHum4oN6LFJ1bn5NXTN7OF5fQkN5WYow 67 | BEN2dkGQGWJtSzqGTICJgnQuTJN/WJsojad9qXMuhIWdjXKjY4tenjo6tjVssk2gaWq3uGNX 68 | U6ZGxseyk8SasGw3J9GRzdTQky1iHNvcPNNI4TLeKdfMvy0vMqLrItvuxfDW8ubjueDtJufz 69 | 7itICBxISKDBgwgTKjyYAAA7 70 | --DC8------------DC8638F443D87A7F0726DEF7-- 71 | 72 | --D7F------------D7FD5A0B8AB9C65CCDBFA872-- 73 | 74 | -------------------------------------------------------------------------------- /src/tests/resources/messages/003.txt: -------------------------------------------------------------------------------- 1 | From: Nathaniel Borenstein 2 | To: Ned Freed 3 | Date: Mon, 22 Mar 1993 09:41:09 -0800 (PST) 4 | Subject: Formatted text mail 5 | MIME-Version: 1.0 6 | Content-Type: multipart/alternative; boundary=boundary42 7 | 8 | --boundary42 9 | Content-Type: text/plain; charset=us-ascii 10 | 11 | ... plain text version of message goes here ... 12 | 13 | --boundary42 14 | Content-Type: text/enriched 15 | 16 | ... RFC 1896 text/enriched version of same message 17 | goes here ... 18 | 19 | --boundary42 20 | Content-Type: application/x-whatever 21 | 22 | ... fanciest version of same message goes here ... 23 | 24 | --boundary42-- 25 | 26 | -------------------------------------------------------------------------------- /src/tests/resources/messages/004.txt: -------------------------------------------------------------------------------- 1 | From: Moderator-Address 2 | To: Recipient-List 3 | Date: Mon, 22 Mar 1994 13:34:51 +0000 4 | Subject: Internet Digest, volume 42 5 | MIME-Version: 1.0 6 | Content-Type: multipart/mixed; 7 | boundary="---- main boundary ----" 8 | 9 | ------ main boundary ---- 10 | 11 | ...Introductory text or table of contents... 12 | 13 | ------ main boundary ---- 14 | Content-Type: multipart/digest; 15 | boundary="---- next message ----" 16 | 17 | ------ next message ---- 18 | 19 | From: someone-else 20 | Date: Fri, 26 Mar 1993 11:13:32 +0200 21 | Subject: my opinion 22 | 23 | ...body goes here ... 24 | 25 | ------ next message ---- 26 | 27 | From: someone-else-again 28 | Date: Fri, 26 Mar 1993 10:07:13 -0500 29 | Subject: my different opinion 30 | 31 | ... another body goes here ... 32 | 33 | ------ next message ------ 34 | 35 | ------ main boundary ------ 36 | 37 | -------------------------------------------------------------------------------- /src/tests/resources/messages/005.txt: -------------------------------------------------------------------------------- 1 | From: Nathaniel Borenstein 2 | To: Ned Freed 3 | Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST) 4 | Subject: Sample message 5 | MIME-Version: 1.0 6 | Content-type: multipart/mixed; boundary="simple boundary" 7 | 8 | This is the preamble. It is to be ignored, though it 9 | is a handy place for composition agents to include an 10 | explanatory note to non-MIME conformant readers. 11 | 12 | --simple boundary 13 | 14 | This is implicitly typed plain US-ASCII text. 15 | It does NOT end with a linebreak. 16 | --simple boundary 17 | Content-type: text/plain; charset=us-ascii 18 | 19 | This is explicitly typed plain US-ASCII text. 20 | It DOES end with a linebreak. 21 | 22 | --simple boundary-- 23 | 24 | This is the epilogue. It is also to be ignored. 25 | 26 | -------------------------------------------------------------------------------- /src/tests/resources/messages/006.txt: -------------------------------------------------------------------------------- 1 | From: sender@example.com 2 | To: recipient@example.com 3 | Subject: Multipart Email Example 4 | Content-Type: multipart/alternative; boundary="boundary-string" 5 | 6 | --boundary-string 7 | Content-Type: text/plain; charset="utf-8" 8 | Content-Transfer-Encoding: quoted-printable 9 | Content-Disposition: inline 10 | 11 | Plain text email goes here! 12 | This is the fallback if email client does not support HTML 13 | 14 | --boundary-string 15 | Content-Type: text/html; charset="utf-8" 16 | Content-Transfer-Encoding: quoted-printable 17 | Content-Disposition: inline 18 | 19 |

This is the HTML Section!

20 |

This is what displays in most modern email clients

21 | 22 | --boundary-string-- 23 | 24 | -------------------------------------------------------------------------------- /src/tests/resources/messages/007.txt: -------------------------------------------------------------------------------- 1 | Subject: RFC 8621 Section 4.1.4 test 2 | Content-Type: multipart/mixed; boundary="1" 3 | 4 | --1 5 | Content-Type: text/plain 6 | Content-Disposition: inline 7 | 8 | A 9 | --1 10 | Content-Type: multipart/mixed; boundary="2" 11 | 12 | --2 13 | Content-Type: multipart/alternative; boundary="3" 14 | 15 | --3 16 | Content-Type: multipart/mixed; boundary="4" 17 | 18 | --4 19 | Content-Type: text/plain 20 | Content-Disposition: inline 21 | 22 | B 23 | --4 24 | Content-Type: image/jpeg 25 | Content-Disposition: inline 26 | 27 | C 28 | --4 29 | Content-Type: text/plain 30 | Content-Disposition: inline 31 | 32 | D 33 | --4-- 34 | 35 | --3 36 | Content-Type: multipart/related; boundary="5" 37 | 38 | --5 39 | Content-Type: text/html 40 | 41 | E 42 | --5 43 | Content-Type: image/jpeg 44 | 45 | F 46 | --5-- 47 | 48 | --3-- 49 | 50 | --2 51 | Content-Type: image/jpeg 52 | Content-Disposition: attachment 53 | 54 | G 55 | --2 56 | Content-Type: application/x-excel 57 | 58 | H 59 | --2 60 | Content-Type: message/rfc822 61 | 62 | Subject: J 63 | 64 | J 65 | --2-- 66 | 67 | --1 68 | Content-Type: text/plain 69 | Content-Disposition: inline 70 | 71 | K 72 | --1-- 73 | 74 | -------------------------------------------------------------------------------- /src/tests/resources/messages/008.txt: -------------------------------------------------------------------------------- 1 | Content-Type: multipart/mixed; 2 | boundary=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 3 | 4 | --bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 5 | Content-Type: text/plain; charset=utf-8 6 | Content-Transfer-Encoding: 7bit 7 | 8 | This is a message with a base64 encoded attached email 9 | --bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 10 | Content-Disposition: attachment; filename="attached_email.eml" 11 | Content-Type: message/rfc822 12 | Content-Transfer-Encoding: base64 13 | 14 | VG86ICJlbWFpbEBleGFtcGxlLmNvbSIgPGVtYWlsQGV4YW1wbGUuY29tPg0KRnJvbTogTmFtZSA8 15 | ZW1haWxAZXhhbXBsZS5jb20+DQpTdWJqZWN0OiBIVE1MIHRlc3QNCk1lc3NhZ2UtSUQ6IDxyYW5k 16 | b20tbWVzc2FnZS1pZEBleGFtcGxlLmNvbT4NCkRhdGU6IFR1ZSwgMTQgRGVjIDIwMjEgMTE6NDg6 17 | MjUgKzAxMDANCk1JTUUtVmVyc2lvbjogMS4wDQpDb250ZW50LVR5cGU6IG11bHRpcGFydC9hbHRl 18 | cm5hdGl2ZTsNCiBib3VuZGFyeT0iYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh 19 | YWFhYSINCkNvbnRlbnQtTGFuZ3VhZ2U6IGVuLVVTDQoNClRoaXMgaXMgYSBtdWx0aS1wYXJ0IG1l 20 | c3NhZ2UgaW4gTUlNRSBmb3JtYXQuDQotLWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh 21 | YWFhYWFhYWENCkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD11dGYtODsgZm9ybWF0 22 | PWZsb3dlZA0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogN2JpdA0KDQpUaGlzIGlzIGFuICpI 23 | VE1MKiB0ZXN0IG1lc3NhZ2UNCi0tYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh 24 | YWFhYQ0KQ29udGVudC1UeXBlOiB0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLTgNCkNvbnRlbnQtVHJh 25 | bnNmZXItRW5jb2Rpbmc6IDdiaXQNCg0KPGh0bWw+DQogIDxoZWFkPg0KICAgIDxtZXRhIGh0dHAt 26 | ZXF1aXY9ImNvbnRlbnQtdHlwZSIgY29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PVVURi04Ij4N 27 | CiAgPC9oZWFkPg0KICA8Ym9keT4NCiAgICBUaGlzIGlzIGFuIDxiPkhUTUw8L2I+IHRlc3QgbWVz 28 | c2FnZQ0KICA8L2JvZHk+DQo8L2h0bWw+DQoNCi0tYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh 29 | YWFhYWFhYWFhYWFhYS0tDQo= 30 | --bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb-- 31 | -------------------------------------------------------------------------------- /src/tests/resources/messages/009.txt: -------------------------------------------------------------------------------- 1 | From: Art Vandelay (Vandelay Industries) 2 | To: "Colleagues": "James Smythe" ; Friends: 3 | jane@example.com, =?UTF-8?Q?John_Sm=C3=AEth?= ; 4 | Date: Sat, 20 Nov 2021 14:22:01 -0800 5 | Subject: Why not both importing AND exporting? =?utf-8?b?4pi6?= 6 | Content-Type: multipart/mixed; boundary="festivus"; 7 | 8 | --festivus 9 | Content-Type: text/html; charset="us-ascii" 10 | Content-Transfer-Encoding: base64 11 | 12 | PGh0bWw+PHA+SSB3YXMgdGhpbmtpbmcgYWJvdXQgcXVpdHRpbmcgdGhlICZsZHF1bztle 13 | HBvcnRpbmcmcmRxdW87IHRvIGZvY3VzIGp1c3Qgb24gdGhlICZsZHF1bztpbXBvcnRpbm 14 | cmcmRxdW87LDwvcD48cD5idXQgdGhlbiBJIHRob3VnaHQsIHdoeSBub3QgZG8gYm90aD8 15 | gJiN4MjYzQTs8L3A+PC9odG1sPg== 16 | --festivus 17 | Content-Type: message/rfc822 18 | 19 | From: "Cosmo Kramer" 20 | Subject: Exporting my book about coffee tables 21 | Content-Type: multipart/mixed; boundary="giddyup"; 22 | 23 | --giddyup 24 | Content-Type: text/plain; charset="utf-16" 25 | Content-Transfer-Encoding: quoted-printable 26 | 27 | =FF=FE=0C!5=D8"=DD5=D8)=DD5=D8-=DD =005=D8*=DD5=D8"=DD =005=D8"= 28 | =DD5=D85=DD5=D8-=DD5=D8,=DD5=D8/=DD5=D81=DD =005=D8*=DD5=D86=DD = 29 | =005=D8=1F=DD5=D8,=DD5=D8,=DD5=D8(=DD =005=D8-=DD5=D8)=DD5=D8"= 30 | =DD5=D8=1E=DD5=D80=DD5=D8"=DD!=00 31 | --giddyup 32 | Content-Type: image/gif; name*1="about "; name*0="Book "; 33 | name*2*=utf-8''%e2%98%95 tables.gif 34 | Content-Transfer-Encoding: Base64 35 | Content-Disposition: attachment 36 | 37 | R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7 38 | --giddyup-- 39 | --festivus-- 40 | -------------------------------------------------------------------------------- /src/tests/resources/messages/010.imap: -------------------------------------------------------------------------------- 1 | BODY ( 2 | "message" "rfc822" NIL NIL NIL NIL 88 ( 3 | "Sun, 12 Aug 2012 09:34:56 +0000" "submsg" ( 4 | ( 5 | NIL NIL "sub" "domain.org" 6 | ) 7 | ) ( 8 | ( 9 | NIL NIL "sub" "domain.org" 10 | ) 11 | ) ( 12 | ( 13 | NIL NIL "sub" "domain.org" 14 | ) 15 | ) NIL NIL NIL NIL NIL 16 | ) ( 17 | "text" "plain" ( 18 | "charset" "us-ascii" 19 | ) NIL NIL "7bit" 12 1 20 | ) 0 21 | ) 22 | 23 | BODYSTRUCTURE ( 24 | "message" "rfc822" NIL NIL NIL NIL 88 ( 25 | "Sun, 12 Aug 2012 09:34:56 +0000" "submsg" ( 26 | ( 27 | NIL NIL "sub" "domain.org" 28 | ) 29 | ) ( 30 | ( 31 | NIL NIL "sub" "domain.org" 32 | ) 33 | ) ( 34 | ( 35 | NIL NIL "sub" "domain.org" 36 | ) 37 | ) NIL NIL NIL NIL NIL 38 | ) ( 39 | "text" "plain" ( 40 | "charset" "us-ascii" 41 | ) NIL NIL "7bit" 12 1 "f0ef7081e1539ac00ef5b761b4fb01b3" NIL NIL NIL 42 | ) 0 "dfea5a78f321b331e6d7983a1f9cc6b7" NIL NIL NIL 43 | ) 44 | 45 | BODY[] {196} 46 | From: user@domain.org 47 | Date: Sat, 24 Mar 2007 23:00:00 +0200 48 | Mime-Version: 1.0 49 | Content-Type: message/rfc822 50 | 51 | From: sub@domain.org 52 | Date: Sun, 12 Aug 2012 12:34:56 +0300 53 | Subject: submsg 54 | 55 | Hello world 56 | 57 | BINARY[] {16} 58 | [binary content] 59 | BINARY.SIZE[] 88 60 | ---------------------------------- 61 | BODY[HEADER] {108} 62 | From: user@domain.org 63 | Date: Sat, 24 Mar 2007 23:00:00 +0200 64 | Mime-Version: 1.0 65 | Content-Type: message/rfc822 66 | 67 | 68 | ---------------------------------- 69 | BODY[TEXT] {88} 70 | From: sub@domain.org 71 | Date: Sun, 12 Aug 2012 12:34:56 +0300 72 | Subject: submsg 73 | 74 | Hello world 75 | 76 | ---------------------------------- 77 | BODY[MIME] {31} 78 | Content-Type: message/rfc822 79 | 80 | 81 | ---------------------------------- 82 | BODY[1] {88} 83 | From: sub@domain.org 84 | Date: Sun, 12 Aug 2012 12:34:56 +0300 85 | Subject: submsg 86 | 87 | Hello world 88 | 89 | ---------------------------------- 90 | BODY[1.HEADER] {76} 91 | From: sub@domain.org 92 | Date: Sun, 12 Aug 2012 12:34:56 +0300 93 | Subject: submsg 94 | 95 | 96 | ---------------------------------- 97 | BODY[1.TEXT] {12} 98 | Hello world 99 | 100 | ---------------------------------- 101 | BODY[1.MIME] {2} 102 | 103 | 104 | ---------------------------------- 105 | BODY[HEADER.FIELDS (FROM TO)] {24} 106 | From: user@domain.org 107 | 108 | 109 | ---------------------------------- 110 | BODY[HEADER.FIELDS (FROM TO)]<10> {14} 111 | @domain.org 112 | 113 | 114 | ---------------------------------- 115 | BODY[HEADER.FIELDS.NOT (SUBJECT CC)] {109} 116 | From: user@domain.org 117 | Date: Sat, 24 Mar 2007 23:00:00 +0200 118 | MIME-Version: 1.0 119 | Content-Type: message/rfc822 120 | 121 | 122 | ---------------------------------- 123 | BODY[HEADER.FIELDS.NOT (SUBJECT CC)]<10> {25} 124 | @domain.org 125 | Date: Sat, 24 126 | ---------------------------------- 127 | -------------------------------------------------------------------------------- /src/tests/resources/messages/010.txt: -------------------------------------------------------------------------------- 1 | From: user@domain.org 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | Mime-Version: 1.0 4 | Content-Type: message/rfc822 5 | 6 | From: sub@domain.org 7 | Date: Sun, 12 Aug 2012 12:34:56 +0300 8 | Subject: submsg 9 | 10 | Hello world 11 | -------------------------------------------------------------------------------- /src/tests/resources/messages/011.txt: -------------------------------------------------------------------------------- 1 | From: user@domain.org 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | Mime-Version: 1.0 4 | Content-Type: message/rfc822 5 | 6 | From: sub@domain.org 7 | Date: Sun, 12 Aug 2012 12:34:56 +0300 8 | Subject: submsg 9 | Content-Type: multipart/digest; boundary="foo" 10 | 11 | prologue 12 | 13 | --foo 14 | 15 | From: m1@example.com 16 | Subject: m1 17 | 18 | m1 body 19 | 20 | --foo 21 | X-Mime: m2 header 22 | 23 | From: m2@example.com 24 | Subject: m2 25 | 26 | m2 body 27 | 28 | --foo-- 29 | 30 | epilogue 31 | -------------------------------------------------------------------------------- /src/tests/resources/messages/012.txt: -------------------------------------------------------------------------------- 1 | From: user@domain.org 2 | Date: Sat, 24 Mar 2007 23:00:00 +0200 3 | Mime-Version: 1.0 4 | Content-Type: multipart/mixed; boundary="foo 5 | bar" 6 | 7 | Root MIME prologue 8 | 9 | --foo bar 10 | Content-Type: text/x-myown; charset=us-ascii 11 | 12 | hello 13 | 14 | --foo bar 15 | Content-Type: message/rfc822 16 | 17 | From: sub@domain.org 18 | Date: Sun, 12 Aug 2012 12:34:56 +0300 19 | Subject: submsg 20 | Content-Type: multipart/alternative; boundary="sub1" 21 | 22 | Sub MIME prologue 23 | --sub1 24 | Content-Type: text/html 25 | 26 |

Hello world

27 | 28 | --sub1 29 | Content-Type: text/plain 30 | 31 | Hello another world 32 | 33 | --sub1-- 34 | Sub MIME epilogue 35 | 36 | --foo bar-- 37 | Root MIME epilogue 38 | -------------------------------------------------------------------------------- /src/tests/resources/messages/013.txt: -------------------------------------------------------------------------------- 1 | Date: Mon, 13 Aug 1998 17:42:41 +1000 2 | Message-Id: <199804130742.RAA20366@mai1host.whitehouse.gov> 3 | From: Bill Clinton 4 | To: A1 (The Enforcer) Gore 5 | Subject: Map of Argentina with Description 6 | MIME-Version: 1.0 7 | Content-Type: text/plain; charset=us-ascii 8 | Content-Transfer-Encoding: 7bit 9 | 10 | Hi A1, 11 | 12 | I finally figured out this MIME thing. Pretty cool. I'll send you 13 | some sax music in .au files next week! 14 | 15 | Anyway, the attached image is really too small to get a good look at 16 | Argentina. Try this for a much better map: 17 | 18 | http://www.1one1yp1anet.com/dest/sam/graphics/map-arg.htm 19 | 20 | Then again, shouldn't the CIA have something like that? 21 | 22 | Bill 23 | -------------------------------------------------------------------------------- /src/tests/store.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Stalwart Labs Ltd. 3 | * 4 | * This file is part of the Stalwart IMAP Server. 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Affero General Public License as 8 | * published by the Free Software Foundation, either version 3 of 9 | * the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Affero General Public License for more details. 15 | * in the LICENSE file at the top-level directory of this distribution. 16 | * You should have received a copy of the GNU Affero General Public License 17 | * along with this program. If not, see . 18 | * 19 | * You can be released from the requirements of the AGPLv3 license by 20 | * purchasing a commercial license. Please contact licensing@stalw.art 21 | * for more details. 22 | */ 23 | 24 | use crate::core::ResponseType; 25 | 26 | use super::{AssertResult, ImapConnection, Type}; 27 | 28 | pub async fn test(imap: &mut ImapConnection, _imap_check: &mut ImapConnection) { 29 | // Select INBOX 30 | imap.send("SELECT INBOX").await; 31 | imap.assert_read(Type::Tagged, ResponseType::Ok) 32 | .await 33 | .assert_contains("10 EXISTS") 34 | .assert_contains("[UIDNEXT 11]"); 35 | 36 | // Set all messages to flag "Seen" 37 | imap.send("UID STORE 1:10 +FLAGS.SILENT (\\Seen)").await; 38 | imap.assert_read(Type::Tagged, ResponseType::Ok) 39 | .await 40 | .assert_count("FLAGS", 0); 41 | 42 | // Check that the flags were set 43 | imap.send("UID FETCH 1:* (Flags)").await; 44 | imap.assert_read(Type::Tagged, ResponseType::Ok) 45 | .await 46 | .assert_count("\\Seen", 10); 47 | 48 | // Check status 49 | imap.send("STATUS INBOX (UIDNEXT MESSAGES UNSEEN)").await; 50 | imap.assert_read(Type::Tagged, ResponseType::Ok) 51 | .await 52 | .assert_contains("MESSAGES 10") 53 | .assert_contains("UNSEEN 0") 54 | .assert_contains("UIDNEXT 11"); 55 | 56 | // Remove Seen flag from all messages 57 | imap.send("UID STORE 1:10 -FLAGS (\\Seen)").await; 58 | imap.assert_read(Type::Tagged, ResponseType::Ok) 59 | .await 60 | .assert_count("FLAGS", 10) 61 | .assert_count("Seen", 0); 62 | 63 | // Store using saved searches 64 | imap.send("SEARCH RETURN (SAVE) FROM nathaniel").await; 65 | imap.assert_read(Type::Tagged, ResponseType::Ok).await; 66 | imap.send("UID STORE $ +FLAGS (\\Answered)").await; 67 | imap.assert_read(Type::Tagged, ResponseType::Ok) 68 | .await 69 | .assert_count("FLAGS", 3); 70 | 71 | // Remove Answered flag 72 | imap.send("UID STORE 1:* -FLAGS (\\Answered)").await; 73 | imap.assert_read(Type::Tagged, ResponseType::Ok) 74 | .await 75 | .assert_count("FLAGS", 10) 76 | .assert_count("Answered", 0); 77 | } 78 | --------------------------------------------------------------------------------