Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
[package]
|
||||
name = "tests"
|
||||
version = "0.16.22"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
#default = ["sqlite", "postgres", "mysql", "rocks", "s3", "redis", "nats", "azure", "foundationdb"]
|
||||
#default = ["sqlite", "postgres", "mysql", "rocks", "s3", "redis", "foundationdb"]
|
||||
default = ["rocks", "sqlite"]
|
||||
sqlite = ["store/sqlite", "directory/sqlite"]
|
||||
foundationdb = ["store/foundation", "common/foundation"]
|
||||
postgres = ["store/postgres", "directory/postgres"]
|
||||
mysql = ["store/mysql", "directory/mysql"]
|
||||
rocks = ["store/rocks"]
|
||||
s3 = ["store/s3"]
|
||||
redis = ["store/redis", "coordinator/redis"]
|
||||
nats = ["coordinator/nats"]
|
||||
kafka = ["coordinator/kafka"]
|
||||
azure = ["store/azure"]
|
||||
|
||||
[dev-dependencies]
|
||||
store = { path = "../crates/store", features = ["test_mode"] }
|
||||
nlp = { path = "../crates/nlp" }
|
||||
directory = { path = "../crates/directory", features = ["test_mode"] }
|
||||
coordinator = { path = "../crates/coordinator", features = ["test_mode"] }
|
||||
jmap = { path = "../crates/jmap", features = ["test_mode"] }
|
||||
jmap_proto = { path = "../crates/jmap-proto" }
|
||||
imap = { path = "../crates/imap", features = ["test_mode"] }
|
||||
imap_proto = { path = "../crates/imap-proto" }
|
||||
types = { path = "../crates/types" }
|
||||
dav = { path = "../crates/dav", features = ["test_mode"] }
|
||||
dav-proto = { path = "../crates/dav-proto", features = ["test_mode"] }
|
||||
calcard = { version = "0.3", features = ["rkyv"] }
|
||||
groupware = { path = "../crates/groupware", features = ["test_mode"] }
|
||||
http = { path = "../crates/http", features = ["test_mode"] }
|
||||
http_proto = { path = "../crates/http-proto", features = ["test_mode"] }
|
||||
scim = { path = "../crates/scim", features = ["test_mode"] }
|
||||
scim-proto = { path = "../crates/scim-proto" }
|
||||
services = { path = "../crates/services", features = ["test_mode"] }
|
||||
pop3 = { path = "../crates/pop3", features = ["test_mode"] }
|
||||
smtp = { path = "../crates/smtp", features = ["test_mode"] }
|
||||
common = { path = "../crates/common", features = ["test_mode"] }
|
||||
registry = { path = "../crates/registry" }
|
||||
email = { path = "../crates/email", features = ["test_mode"] }
|
||||
spam-filter = { path = "../crates/spam-filter", features = ["test_mode"] }
|
||||
trc = { path = "../crates/trc", features = [] }
|
||||
managesieve = { path = "../crates/managesieve", features = ["test_mode"] }
|
||||
smtp-proto = { version = "0.2" }
|
||||
mail-auth = { version = "0.13", features = ["test"] }
|
||||
mail-parser = { version = "0.11", features = ["full_encoding", "rkyv"] }
|
||||
mail-builder = "1.0"
|
||||
sieve-rs = { version = "0.7", features = ["rkyv"] }
|
||||
utils = { path = "../crates/utils", features = ["test_mode"] }
|
||||
jmap-client = { version = "0.4", features = ["websockets", "debug", "async"] }
|
||||
tokio = { version = "1.53", features = ["full"] }
|
||||
tokio-rustls = { version = "0.26", default-features = false, features = ["aws_lc_rs", "tls12"] }
|
||||
rustls = { version = "0.23.43", default-features = false, features = ["std", "aws_lc_rs", "tls12"] }
|
||||
rustls-pki-types = { version = "1" }
|
||||
csv = "1.4"
|
||||
rayon = { version = "1.12.0" }
|
||||
flate2 = { version = "1.1.10", features = ["zlib"], default-features = false }
|
||||
serde = { version = "1.0", features = ["derive"]}
|
||||
serde_json = "1.0"
|
||||
reqwest = { version = "0.13", default-features = false, features = ["rustls", "multipart", "http2", "form"]}
|
||||
bytes = "1.12.1"
|
||||
futures = "0.3"
|
||||
ece = "2.3"
|
||||
hyper = { version = "1.11.1", features = ["server", "http1", "http2"] }
|
||||
hyper-util = { version = "0.1.20", features = ["tokio"] }
|
||||
base64 = "0.23"
|
||||
ahash = { version = "0.8" }
|
||||
serial_test = "4.0.1"
|
||||
chrono = "0.4"
|
||||
aws-lc-rs = { version = "1" }
|
||||
biscuit = "0.8.0"
|
||||
form_urlencoded = "1.2.2"
|
||||
rkyv = { version = "0.8.18", features = ["little_endian"] }
|
||||
quick-xml = "0.41"
|
||||
jmap-tools = { version = "0.1" }
|
||||
dns-update = { version = "0.5", features = ["test_provider"] }
|
||||
x509-parser = "0.18"
|
||||
rcgen = "0.14"
|
||||
sha2 = "0.11"
|
||||
time = "0.3"
|
||||
testcontainers = { version = "0.28", features = ["reusable-containers"] }
|
||||
rust-s3 = { version = "0.37", default-features = false, features = ["tokio-rustls-tls"] }
|
||||
|
||||
[target.'cfg(not(any(target_env = "msvc", target_os = "freebsd")))'.dependencies]
|
||||
tikv-jemallocator = "0.7"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,220 @@
|
||||
# Stalwart – Test Infrastructure
|
||||
|
||||
Ephemeral Docker Compose stack for testing Stalwart against external services.
|
||||
All data is lost on `docker compose down` – every restart is a clean slate.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
cd stalwart-test
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Wait ~30 seconds for all services to initialize (Keycloak takes the longest).
|
||||
|
||||
## Connection Reference
|
||||
|
||||
| Service | Host | Port(s) | Credentials / Notes |
|
||||
|----------------|-------------------|-----------------|--------------------------------------------|
|
||||
| PostgreSQL | localhost | 5432 | `stalwart` / `stalwart`, db: `stalwart` |
|
||||
| MySQL | localhost | 3306 | `stalwart` / `stalwart`, db: `stalwart` |
|
||||
| FoundationDB | localhost | 4500 | Cluster file from container |
|
||||
| Redis | localhost | 6379 | No auth |
|
||||
| OpenSearch | localhost | 9200 | No auth, security plugin disabled |
|
||||
| Meilisearch | localhost | 7700 | Master key: `stalwart-master-key` |
|
||||
| MinIO (S3) | localhost | 9000 / 9001 | `minioadmin` / `minioadmin`, bucket: `stalwart` |
|
||||
| Keycloak (OIDC)| localhost | 9080 | Admin: `admin` / `admin` |
|
||||
| OpenLDAP | localhost | 389 / 636 (TLS) | Admin DN: `cn=admin,dc=stalwart,dc=test`, pw: `admin` |
|
||||
| Pebble (ACME) | localhost | 14000 / 15000 | Self-signed TLS, uses challtestsrv |
|
||||
| Challtestsrv | localhost | 8055 | ACME challenge test server (management API)|
|
||||
| PowerDNS | localhost | 5300 / 8081 | API key: `stalwart-api-key` |
|
||||
| NATS | localhost | 4222 / 8222 | No auth |
|
||||
|
||||
## OIDC (Keycloak) Details
|
||||
|
||||
- **OIDC Discovery**: `http://localhost:9080/realms/stalwart/.well-known/openid-configuration`
|
||||
- **Token Endpoint**: `http://localhost:9080/realms/stalwart/protocol/openid-connect/token`
|
||||
- **Client ID**: `stalwart`
|
||||
- **Client Secret**: `stalwart-secret`
|
||||
- **Realm**: `stalwart`
|
||||
|
||||
### Test Users
|
||||
|
||||
| Username | Password | Groups |
|
||||
|---------------------------|--------------------------|----------------------------------------|
|
||||
| john.doe@example.org | this is an OIDC password | sales@example.org |
|
||||
| jane.smith@example.org | this is an OIDC password | sales@example.org, corporate@example.org |
|
||||
| bill.foobar@example.org | this is an OIDC password | corporate@example.org |
|
||||
|
||||
### Example: Get a Token
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:9080/realms/stalwart/protocol/openid-connect/token \
|
||||
-d "grant_type=password" \
|
||||
-d "client_id=stalwart" \
|
||||
-d "client_secret=stalwart-secret" \
|
||||
-d "[email protected]" \
|
||||
-d "password=this is an OIDC password"
|
||||
```
|
||||
|
||||
## LDAP Details
|
||||
|
||||
- **Base DN**: `dc=stalwart,dc=test`
|
||||
- **Admin DN**: `cn=admin,dc=stalwart,dc=test`
|
||||
- **Admin Password**: `admin`
|
||||
- **Read-only DN**: `cn=readonly,dc=stalwart,dc=test`
|
||||
- **Read-only Password**: `readonly`
|
||||
- **User DN pattern**: `uid={username},ou=users,dc=stalwart,dc=test`
|
||||
|
||||
### Test Users
|
||||
|
||||
| DN | Mail | Password |
|
||||
|------------------------------------------------|--------------------------|--------------------------|
|
||||
| uid=john.doe,ou=users,dc=stalwart,dc=test | john.doe@example.org | this is an LDAP password |
|
||||
| uid=jane.smith,ou=users,dc=stalwart,dc=test | jane.smith@example.org | this is an LDAP password |
|
||||
| uid=bill.foobar,ou=users,dc=stalwart,dc=test | bill.foobar@example.org | this is an LDAP password |
|
||||
|
||||
### Groups
|
||||
|
||||
| DN | Mail | Members |
|
||||
|---------------------------------------------|-------------------------|------------------|
|
||||
| cn=sales,ou=groups,dc=stalwart,dc=test | sales@example.org | john.doe, jane.smith |
|
||||
| cn=corporate,ou=groups,dc=stalwart,dc=test | corporate@example.org | bill.foobar, jane.smith |
|
||||
|
||||
### Example: Search by Email
|
||||
|
||||
```bash
|
||||
ldapsearch -x -H ldap://localhost:389 \
|
||||
-D "cn=admin,dc=stalwart,dc=test" -w admin \
|
||||
-b "dc=stalwart,dc=test" "([email protected])"
|
||||
```
|
||||
|
||||
## S3 (MinIO) Details
|
||||
|
||||
- **Endpoint**: `http://localhost:9000`
|
||||
- **Access Key**: `minioadmin`
|
||||
- **Secret Key**: `minioadmin`
|
||||
- **Bucket**: `stalwart`
|
||||
- **Console**: `http://localhost:9001`
|
||||
- **Region**: `us-east-1` (MinIO default)
|
||||
|
||||
## DNS (PowerDNS) Details
|
||||
|
||||
- **DNS port**: 5300 (TCP+UDP)
|
||||
- **API**: `http://localhost:8081` (API key: `stalwart-api-key`)
|
||||
- **Zone**: `stalwart.test`
|
||||
- **TSIG key name**: `stalwart-update-key`
|
||||
- **TSIG algorithm**: `hmac-sha256`
|
||||
- **TSIG secret (base64)**: `c3RhbHdhcnQtdGVzdC10c2lnLXNlY3JldC1rZXkxMjM0NTY3ODkw`
|
||||
|
||||
> **Note on SIG(0):** PowerDNS does not support SIG(0) authentication for RFC2136
|
||||
> updates. Only BIND has (limited) SIG(0) support. If you need to test SIG(0),
|
||||
> a separate BIND instance would be required.
|
||||
|
||||
### Example: Query TLSA Record
|
||||
|
||||
```bash
|
||||
dig @localhost -p 5300 _25._tcp.mail.stalwart.test TLSA
|
||||
```
|
||||
|
||||
### Example: RFC2136 Dynamic Update
|
||||
|
||||
```bash
|
||||
nsupdate -y hmac-sha256:stalwart-update-key:c3RhbHdhcnQtdGVzdC10c2lnLXNlY3JldC1rZXkxMjM0NTY3ODkw <<EOF
|
||||
server 127.0.0.1 5300
|
||||
zone stalwart.test
|
||||
update add test.stalwart.test 300 A 192.168.1.100
|
||||
send
|
||||
EOF
|
||||
```
|
||||
|
||||
## ACME (Pebble + Challenge Test Server) Details
|
||||
|
||||
- **Directory URL**: `https://localhost:14000/dir`
|
||||
- **Pebble Management URL**: `https://localhost:15000`
|
||||
- **Challenge Test Server API**: `http://localhost:8055`
|
||||
- **TLS**: Self-signed — Stalwart must trust the Pebble CA or skip TLS verification
|
||||
- Pebble uses the challenge test server (`pebble-challtestsrv`) as its DNS resolver,
|
||||
so challenge validation goes through controllable DNS/HTTP/TLS-ALPN responders.
|
||||
|
||||
### Challenge Test Server (challtestsrv)
|
||||
|
||||
The challenge test server provides a management API on port 8055 to programmatically
|
||||
control DNS records and challenge responses used during ACME validation.
|
||||
|
||||
**Default behavior**: All A/AAAA queries resolve to `host.docker.internal` (the Docker
|
||||
host), so Pebble can reach your test server on localhost automatically. Tests only need
|
||||
to add challenge-specific records (TXT for DNS-01, HTTP tokens, etc.).
|
||||
|
||||
### How Pebble Reaches Your Test Server
|
||||
|
||||
When Pebble validates an HTTP-01 or TLS-ALPN-01 challenge, it:
|
||||
|
||||
1. Resolves the domain via challtestsrv — by default all domains resolve to the Docker host
|
||||
2. Connects to the resolved IP on port **5002** (HTTP-01) or **5001** (TLS-ALPN-01)
|
||||
|
||||
These ports are configured in `pebble/pebble-config.json` (`httpPort` / `tlsPort`).
|
||||
Change them to match whatever port your test Stalwart instance listens on.
|
||||
|
||||
#### Management API Examples
|
||||
|
||||
```bash
|
||||
# Add a DNS-01 TXT challenge response
|
||||
curl -s -X POST http://localhost:8055/add-dns \
|
||||
-d '{"host": "_acme-challenge.mail.stalwart.test.", "value": "dns-challenge-token"}'
|
||||
|
||||
# Remove a DNS-01 TXT challenge response
|
||||
curl -s -X POST http://localhost:8055/del-dns \
|
||||
-d '{"host": "_acme-challenge.mail.stalwart.test."}'
|
||||
|
||||
# Add an HTTP-01 challenge response (served by challtestsrv itself)
|
||||
curl -s -X POST http://localhost:8055/add-http \
|
||||
-d '{"token": "challenge-token", "content": "challenge-key-authorization"}'
|
||||
|
||||
# Remove an HTTP-01 challenge response
|
||||
curl -s -X POST http://localhost:8055/del-http \
|
||||
-d '{"token": "challenge-token"}'
|
||||
|
||||
# Add a TLS-ALPN-01 challenge response (served by challtestsrv itself)
|
||||
curl -s -X POST http://localhost:8055/add-tlsalpn \
|
||||
-d '{"host": "mail.stalwart.test", "content": "base64-encoded-key-authz"}'
|
||||
|
||||
# Remove a TLS-ALPN-01 challenge response
|
||||
curl -s -X POST http://localhost:8055/del-tlsalpn \
|
||||
-d '{"host": "mail.stalwart.test"}'
|
||||
|
||||
# Clear all mock DNS/challenge data
|
||||
curl -s -X POST http://localhost:8055/clear-request-count
|
||||
```
|
||||
|
||||
## Self-Signed TLS Certificate
|
||||
|
||||
A shared self-signed certificate is generated at startup and mounted into services
|
||||
that need it. The cert is valid for:
|
||||
- `localhost`, `keycloak`, `openldap`, `pebble`, `*.stalwart.test`, `127.0.0.1`
|
||||
|
||||
To extract the cert for use with Stalwart:
|
||||
|
||||
```bash
|
||||
docker compose cp cert-init:/certs/cert.pem ./test-cert.pem
|
||||
docker compose cp cert-init:/certs/key.pem ./test-key.pem
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
```bash
|
||||
# Check all services are running
|
||||
docker compose ps
|
||||
|
||||
# View logs for a specific service
|
||||
docker compose logs -f keycloak
|
||||
|
||||
# Restart everything fresh
|
||||
docker compose down && docker compose up -d
|
||||
|
||||
# Check FoundationDB status
|
||||
docker compose exec foundationdb fdbcli --exec "status"
|
||||
|
||||
# Verify TSIG key is loaded
|
||||
docker compose exec powerdns pdnsutil list-tsig-keys
|
||||
```
|
||||
@@ -0,0 +1,276 @@
|
||||
###############################################################################
|
||||
# Stalwart – Test Infrastructure
|
||||
# All services are ephemeral (no volumes = fresh on every restart)
|
||||
# Ports exposed on localhost; 80/443/8080 are remapped
|
||||
###############################################################################
|
||||
|
||||
services:
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Init: generate shared self-signed TLS certificates
|
||||
# ---------------------------------------------------------------------------
|
||||
cert-init:
|
||||
image: alpine/openssl:latest
|
||||
volumes:
|
||||
- certs:/certs
|
||||
- ./scripts/gen-certs.sh:/gen-certs.sh:ro
|
||||
entrypoint: [ "sh", "/gen-certs.sh" ]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PostgreSQL
|
||||
# ---------------------------------------------------------------------------
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_USER: stalwart
|
||||
POSTGRES_PASSWORD: stalwart
|
||||
POSTGRES_DB: stalwart
|
||||
ports:
|
||||
- "127.0.0.1:5432:5432"
|
||||
tmpfs:
|
||||
- /var/lib/postgresql/data
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# MySQL
|
||||
# ---------------------------------------------------------------------------
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: stalwart
|
||||
MYSQL_DATABASE: stalwart
|
||||
MYSQL_USER: stalwart
|
||||
MYSQL_PASSWORD: stalwart
|
||||
ports:
|
||||
- "127.0.0.1:3306:3306"
|
||||
tmpfs:
|
||||
- /var/lib/mysql
|
||||
command: --default-authentication-plugin=mysql_native_password
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# FoundationDB
|
||||
# ---------------------------------------------------------------------------
|
||||
foundationdb:
|
||||
image: foundationdb/foundationdb:7.4.6
|
||||
ports:
|
||||
- "127.0.0.1:4500:4500"
|
||||
environment:
|
||||
FDB_NETWORKING_MODE: container
|
||||
volumes:
|
||||
- fdb-config:/var/fdb
|
||||
tmpfs:
|
||||
- /var/fdb/data
|
||||
- /var/fdb/logs
|
||||
healthcheck:
|
||||
test: [ "CMD-SHELL", "fdbcli --exec 'status' --timeout 3 >/dev/null 2>&1" ]
|
||||
interval: 2s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
start_period: 5s
|
||||
|
||||
fdb-init:
|
||||
image: foundationdb/foundationdb:7.4.6
|
||||
depends_on:
|
||||
foundationdb:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- fdb-config:/var/fdb
|
||||
- ./scripts/init-fdb.sh:/init-fdb.sh:ro
|
||||
entrypoint: [ "bash", "/init-fdb.sh" ]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Redis
|
||||
# ---------------------------------------------------------------------------
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- "127.0.0.1:6379:6379"
|
||||
command: redis-server --save "" --appendonly no
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# OpenSearch (ElasticSearch-compatible)
|
||||
# ---------------------------------------------------------------------------
|
||||
opensearch:
|
||||
image: opensearchproject/opensearch:2
|
||||
environment:
|
||||
discovery.type: single-node
|
||||
DISABLE_SECURITY_PLUGIN: "true"
|
||||
OPENSEARCH_JAVA_OPTS: "-Xms256m -Xmx256m"
|
||||
DISABLE_INSTALL_DEMO_CONFIG: "true"
|
||||
ports:
|
||||
- "127.0.0.1:9200:9200"
|
||||
tmpfs:
|
||||
- /usr/share/opensearch/data:uid=1000,gid=1000
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Meilisearch
|
||||
# ---------------------------------------------------------------------------
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:latest
|
||||
environment:
|
||||
MEILI_ENV: development
|
||||
MEILI_NO_ANALYTICS: "true"
|
||||
MEILI_MASTER_KEY: stalwart-master-key
|
||||
ports:
|
||||
- "127.0.0.1:7700:7700"
|
||||
tmpfs:
|
||||
- /meili_data
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# MinIO (S3-compatible)
|
||||
# ---------------------------------------------------------------------------
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
environment:
|
||||
MINIO_ROOT_USER: minioadmin
|
||||
MINIO_ROOT_PASSWORD: minioadmin
|
||||
ports:
|
||||
- "127.0.0.1:9000:9000"
|
||||
- "127.0.0.1:9001:9001"
|
||||
command: server /data --console-address ":9001"
|
||||
tmpfs:
|
||||
- /data
|
||||
|
||||
minio-init:
|
||||
image: minio/mc:latest
|
||||
depends_on:
|
||||
- minio
|
||||
volumes:
|
||||
- ./scripts/init-minio.sh:/init-minio.sh:ro
|
||||
entrypoint: [ "bash", "/init-minio.sh" ]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Keycloak (OIDC Provider) – port 9080 (moved from 8080)
|
||||
# ---------------------------------------------------------------------------
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:latest
|
||||
depends_on:
|
||||
cert-init:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
KC_BOOTSTRAP_ADMIN_USERNAME: admin
|
||||
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
|
||||
KC_HTTP_PORT: 9080
|
||||
KC_HEALTH_ENABLED: "true"
|
||||
ports:
|
||||
- "127.0.0.1:9080:9080"
|
||||
volumes:
|
||||
- ./keycloak/stalwart-realm.json:/opt/keycloak/data/import/stalwart-realm.json:ro
|
||||
- certs:/certs:ro
|
||||
command: >
|
||||
start-dev --import-realm
|
||||
tmpfs:
|
||||
- /opt/keycloak/data:uid=1000,gid=1000
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# OpenLDAP
|
||||
# ---------------------------------------------------------------------------
|
||||
openldap:
|
||||
image: osixia/openldap:1.5.0
|
||||
depends_on:
|
||||
cert-init:
|
||||
condition: service_completed_successfully
|
||||
environment:
|
||||
LDAP_ORGANISATION: "Stalwart Test"
|
||||
LDAP_DOMAIN: "stalwart.test"
|
||||
LDAP_BASE_DN: "dc=stalwart,dc=test"
|
||||
LDAP_ADMIN_PASSWORD: "admin"
|
||||
LDAP_READONLY_USER: "true"
|
||||
LDAP_READONLY_USER_USERNAME: "readonly"
|
||||
LDAP_READONLY_USER_PASSWORD: "readonly"
|
||||
LDAP_TLS: "true"
|
||||
LDAP_TLS_CRT_FILENAME: "cert.pem"
|
||||
LDAP_TLS_KEY_FILENAME: "key.pem"
|
||||
LDAP_TLS_CA_CRT_FILENAME: "cert.pem"
|
||||
LDAP_TLS_VERIFY_CLIENT: "never"
|
||||
ports:
|
||||
- "127.0.0.1:389:389"
|
||||
- "127.0.0.1:636:636"
|
||||
volumes:
|
||||
- ./ldap/50-users.ldif:/seed/50-users.ldif:ro
|
||||
- ./ldap/60-groups.ldif:/seed/60-groups.ldif:ro
|
||||
- certs:/certs-shared:ro
|
||||
entrypoint: [ "/bin/bash", "-c", "mkdir -p /container/service/slapd/assets/config/bootstrap/ldif/custom && cp /seed/*.ldif /container/service/slapd/assets/config/bootstrap/ldif/custom/ && cp /certs-shared/* /container/service/slapd/assets/certs/ 2>/dev/null; exec /container/tool/run" ]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pebble Challenge Test Server – port 8055 (management API)
|
||||
# Provides controllable DNS, HTTP, and TLS-ALPN challenge responders.
|
||||
# Use the management API to add/remove challenge responses before requesting
|
||||
# certificates from Pebble.
|
||||
# ---------------------------------------------------------------------------
|
||||
pebble-challtestsrv:
|
||||
build:
|
||||
context: ./pebble
|
||||
dockerfile: Dockerfile.challtestsrv
|
||||
image: stalwart-pebble-challtestsrv:local
|
||||
ports:
|
||||
- "127.0.0.1:8055:8055"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
restart: unless-stopped
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pebble (ACME server) – ports 14000 (directory) + 15000 (management)
|
||||
# ---------------------------------------------------------------------------
|
||||
pebble:
|
||||
image: ghcr.io/letsencrypt/pebble:latest
|
||||
depends_on:
|
||||
- pebble-challtestsrv
|
||||
environment:
|
||||
PEBBLE_VA_NOSLEEP: "1"
|
||||
PEBBLE_WFE_NONCEREJECT: "0"
|
||||
ports:
|
||||
- "127.0.0.1:14000:14000"
|
||||
- "127.0.0.1:15000:15000"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- ./pebble/pebble-config.json:/test/config/pebble-config.json:ro
|
||||
command: -config /test/config/pebble-config.json -dnsserver pebble-challtestsrv:8053
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PowerDNS (DNS with TLSA + RFC2136) – port 5300 (moved from 53)
|
||||
# ---------------------------------------------------------------------------
|
||||
powerdns:
|
||||
image: powerdns/pdns-auth-49:latest
|
||||
environment:
|
||||
PDNS_AUTH_API_KEY: stalwart-api-key
|
||||
ports:
|
||||
- "127.0.0.1:5300:53/tcp"
|
||||
- "127.0.0.1:5300:53/udp"
|
||||
- "127.0.0.1:8081:8081"
|
||||
volumes:
|
||||
- ./powerdns/pdns.conf:/etc/powerdns/pdns.d/stalwart.conf:ro
|
||||
- ./powerdns/init-zone.sh:/etc/powerdns/init-zone.sh:ro
|
||||
- pdns-data:/var/lib/powerdns
|
||||
|
||||
powerdns-init:
|
||||
image: powerdns/pdns-auth-49:latest
|
||||
depends_on:
|
||||
- powerdns
|
||||
volumes:
|
||||
- ./powerdns/entrypoint.sh:/init.sh:ro
|
||||
- ./powerdns/init-zone.sh:/etc/powerdns/init-zone.sh:ro
|
||||
- pdns-data:/var/lib/powerdns
|
||||
entrypoint: [ "bash", "/init.sh" ]
|
||||
network_mode: "service:powerdns"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# NATS (message queue, core mode)
|
||||
# ---------------------------------------------------------------------------
|
||||
nats:
|
||||
image: nats:latest
|
||||
ports:
|
||||
- "127.0.0.1:4222:4222"
|
||||
- "127.0.0.1:8222:8222"
|
||||
command: "--addr 0.0.0.0 --port 4222 --http_port 8222"
|
||||
|
||||
# =============================================================================
|
||||
# Shared volumes (ephemeral – docker compose down removes them)
|
||||
# =============================================================================
|
||||
volumes:
|
||||
certs:
|
||||
driver: local
|
||||
fdb-config:
|
||||
driver: local
|
||||
pdns-data:
|
||||
driver: local
|
||||
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"realm": "stalwart",
|
||||
"enabled": true,
|
||||
"registrationAllowed": false,
|
||||
"loginWithEmailAllowed": true,
|
||||
"duplicateEmailsAllowed": false,
|
||||
"sslRequired": "none",
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "stalwart",
|
||||
"enabled": true,
|
||||
"clientAuthenticatorType": "client-secret",
|
||||
"secret": "stalwart-secret",
|
||||
"redirectUris": [
|
||||
"*"
|
||||
],
|
||||
"webOrigins": [
|
||||
"*"
|
||||
],
|
||||
"publicClient": false,
|
||||
"protocol": "openid-connect",
|
||||
"directAccessGrantsEnabled": true,
|
||||
"standardFlowEnabled": true,
|
||||
"serviceAccountsEnabled": true,
|
||||
"defaultClientScopes": [
|
||||
"openid",
|
||||
"email",
|
||||
"profile",
|
||||
"roles"
|
||||
],
|
||||
"protocolMappers": [
|
||||
{
|
||||
"name": "groups",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-group-membership-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"full.path": "false",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "groups",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "email-claim",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-attribute-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.attribute": "email",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"claim.name": "email",
|
||||
"userinfo.token.claim": "true",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "audience",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-audience-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"included.client.audience": "stalwart",
|
||||
"id.token.claim": "false",
|
||||
"access.token.claim": "true"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"clientId": "stalwart-fallback",
|
||||
"enabled": true,
|
||||
"clientAuthenticatorType": "client-secret",
|
||||
"secret": "stalwart-fallback-secret",
|
||||
"redirectUris": [
|
||||
"*"
|
||||
],
|
||||
"webOrigins": [
|
||||
"*"
|
||||
],
|
||||
"publicClient": false,
|
||||
"protocol": "openid-connect",
|
||||
"directAccessGrantsEnabled": true,
|
||||
"standardFlowEnabled": true,
|
||||
"serviceAccountsEnabled": true,
|
||||
"defaultClientScopes": [
|
||||
"openid"
|
||||
],
|
||||
"optionalClientScopes": [
|
||||
"email",
|
||||
"profile",
|
||||
"roles"
|
||||
],
|
||||
"protocolMappers": [
|
||||
{
|
||||
"name": "email-claim-userinfo-only",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-attribute-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"user.attribute": "email",
|
||||
"id.token.claim": "false",
|
||||
"access.token.claim": "false",
|
||||
"claim.name": "email",
|
||||
"userinfo.token.claim": "true",
|
||||
"jsonType.label": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "groups-userinfo-only",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-group-membership-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"full.path": "false",
|
||||
"id.token.claim": "false",
|
||||
"access.token.claim": "false",
|
||||
"claim.name": "groups",
|
||||
"userinfo.token.claim": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "audience",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-audience-mapper",
|
||||
"consentRequired": false,
|
||||
"config": {
|
||||
"included.client.audience": "stalwart",
|
||||
"id.token.claim": "false",
|
||||
"access.token.claim": "true"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"username": "[email protected]",
|
||||
"enabled": true,
|
||||
"email": "[email protected]",
|
||||
"emailVerified": true,
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "this is an OIDC password",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
"/[email protected]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"username": "[email protected]",
|
||||
"enabled": true,
|
||||
"email": "[email protected]",
|
||||
"emailVerified": true,
|
||||
"firstName": "Jane",
|
||||
"lastName": "Smith",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "this is an OIDC password",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
"/[email protected]",
|
||||
"/[email protected]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"username": "[email protected]",
|
||||
"enabled": true,
|
||||
"email": "[email protected]",
|
||||
"emailVerified": true,
|
||||
"firstName": "Bill",
|
||||
"lastName": "Foobar",
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "this is an OIDC password",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
"/[email protected]"
|
||||
]
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"name": "[email protected]",
|
||||
"path": "/[email protected]"
|
||||
},
|
||||
{
|
||||
"name": "[email protected]",
|
||||
"path": "/[email protected]"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
dn: ou=users,dc=stalwart,dc=test
|
||||
objectClass: organizationalUnit
|
||||
ou: users
|
||||
|
||||
dn: uid=john.doe,ou=users,dc=stalwart,dc=test
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
objectClass: extensibleObject
|
||||
uid: john.doe
|
||||
cn: John Doe
|
||||
sn: Doe
|
||||
givenName: John
|
||||
mail: [email protected]
|
||||
mailAlias: [email protected]
|
||||
userPassword: this is John's LDAP password
|
||||
shadowLastChange: 19723
|
||||
uidNumber: 10001
|
||||
gidNumber: 10001
|
||||
homeDirectory: /home/john.doe
|
||||
loginShell: /bin/bash
|
||||
|
||||
dn: uid=jane.smith,ou=users,dc=stalwart,dc=test
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
uid: jane.smith
|
||||
cn: Jane Smith
|
||||
sn: Smith
|
||||
givenName: Jane
|
||||
mail: [email protected]
|
||||
userPassword: this is Jane's LDAP password
|
||||
shadowLastChange: 19724
|
||||
uidNumber: 10002
|
||||
gidNumber: 10002
|
||||
homeDirectory: /home/jane.smith
|
||||
loginShell: /bin/bash
|
||||
|
||||
dn: uid=multi.mail,ou=users,dc=stalwart,dc=test
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
uid: multi.mail
|
||||
cn: Multi Mail
|
||||
sn: Mail
|
||||
givenName: Multi
|
||||
mail: [email protected]
|
||||
mail: [email protected]
|
||||
mail: [email protected]
|
||||
userPassword: this is Multi's LDAP password
|
||||
uidNumber: 10004
|
||||
gidNumber: 10004
|
||||
homeDirectory: /home/multi.mail
|
||||
loginShell: /bin/bash
|
||||
|
||||
dn: uid=bill.foobar,ou=users,dc=stalwart,dc=test
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: posixAccount
|
||||
objectClass: shadowAccount
|
||||
objectClass: extensibleObject
|
||||
uid: bill.foobar
|
||||
cn: Bill Foobar
|
||||
sn: Foobar
|
||||
givenName: Bill
|
||||
mail: [email protected]
|
||||
mailAlias: [email protected]
|
||||
userPassword: this is Bill's LDAP password
|
||||
uidNumber: 10003
|
||||
gidNumber: 10003
|
||||
homeDirectory: /home/bill.foobar
|
||||
loginShell: /bin/bash
|
||||
@@ -0,0 +1,20 @@
|
||||
dn: ou=groups,dc=stalwart,dc=test
|
||||
objectClass: organizationalUnit
|
||||
ou: groups
|
||||
|
||||
dn: cn=sales,ou=groups,dc=stalwart,dc=test
|
||||
objectClass: groupOfNames
|
||||
objectClass: extensibleObject
|
||||
cn: sales
|
||||
mail: [email protected]
|
||||
member: uid=john.doe,ou=users,dc=stalwart,dc=test
|
||||
member: uid=jane.smith,ou=users,dc=stalwart,dc=test
|
||||
|
||||
dn: cn=corporate,ou=groups,dc=stalwart,dc=test
|
||||
objectClass: groupOfNames
|
||||
objectClass: extensibleObject
|
||||
cn: corporate
|
||||
mail: [email protected]
|
||||
mailAlias: [email protected]
|
||||
member: uid=bill.foobar,ou=users,dc=stalwart,dc=test
|
||||
member: uid=jane.smith,ou=users,dc=stalwart,dc=test
|
||||
@@ -0,0 +1,5 @@
|
||||
FROM ghcr.io/letsencrypt/pebble-challtestsrv:latest AS upstream
|
||||
|
||||
FROM alpine:latest
|
||||
COPY --from=upstream /app /app
|
||||
ENTRYPOINT ["/bin/sh", "-c", "HOSTIP=$(getent hosts host.docker.internal 2>/dev/null | awk '{print $1}' | head -n1); exec /app -defaultIPv6 \"\" -defaultIPv4 \"${HOSTIP:-127.0.0.1}\""]
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"pebble": {
|
||||
"listenAddress": "0.0.0.0:14000",
|
||||
"managementListenAddress": "0.0.0.0:15000",
|
||||
"certificate": "/test/certs/localhost/cert.pem",
|
||||
"privateKey": "/test/certs/localhost/key.pem",
|
||||
"httpPort": 8898,
|
||||
"tlsPort": 8899,
|
||||
"ocspResponderURL": "",
|
||||
"externalAccountBindingRequired": false,
|
||||
"domainBlocklist": [],
|
||||
"retryAfter": {
|
||||
"authz": 3,
|
||||
"order": 5
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Wait for PowerDNS to be ready (started by default entrypoint)
|
||||
echo "Waiting for PowerDNS to start..."
|
||||
for i in $(seq 1 30); do
|
||||
if pdnsutil list-all-zones 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Run zone initialization
|
||||
bash /etc/powerdns/init-zone.sh
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Wait for the SQLite database to be ready
|
||||
sleep 2
|
||||
|
||||
# Skip if already initialized
|
||||
if pdnsutil list-zone stalwart.test >/dev/null 2>&1; then
|
||||
echo "Zone stalwart.test already exists; skipping init."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create the zone with default SOA + NS
|
||||
pdnsutil create-zone stalwart.test ns1.stalwart.test
|
||||
pdnsutil set-kind stalwart.test native
|
||||
|
||||
# Replace the default SOA with our own
|
||||
pdnsutil replace-rrset stalwart.test '' SOA 'ns1.stalwart.test. admin.stalwart.test. 2024010101 3600 900 604800 86400'
|
||||
|
||||
# Add basic records
|
||||
pdnsutil add-record stalwart.test 'ns1' A '127.0.0.1'
|
||||
pdnsutil add-record stalwart.test '' A '127.0.0.1'
|
||||
pdnsutil add-record stalwart.test '' MX '10 mail.stalwart.test.'
|
||||
pdnsutil add-record stalwart.test 'mail' A '127.0.0.1'
|
||||
|
||||
# Add a sample TLSA record
|
||||
# Usage=3 (DANE-EE), Selector=1 (SubjectPublicKeyInfo), Matching=1 (SHA-256)
|
||||
pdnsutil add-record stalwart.test '_25._tcp.mail' TLSA '3 1 1 0000000000000000000000000000000000000000000000000000000000000000'
|
||||
|
||||
# Import static TSIG key for RFC2136 dynamic updates
|
||||
# Key: stalwart-update-key / HMAC-SHA256
|
||||
# Base64 secret: c3RhbHdhcnQtdGVzdC10c2lnLXNlY3JldC1rZXkxMjM0NTY3ODkw
|
||||
pdnsutil import-tsig-key stalwart-update-key hmac-sha256 'c3RhbHdhcnQtdGVzdC10c2lnLXNlY3JldC1rZXkxMjM0NTY3ODkw'
|
||||
pdnsutil activate-tsig-key stalwart.test stalwart-update-key primary
|
||||
pdnsutil set-meta stalwart.test TSIG-ALLOW-DNSUPDATE stalwart-update-key
|
||||
pdnsutil set-meta stalwart.test ALLOW-DNSUPDATE-FROM '0.0.0.0/0'
|
||||
|
||||
|
||||
echo "PowerDNS zone setup complete."
|
||||
echo "TSIG key name: stalwart-update-key"
|
||||
echo "TSIG algorithm: hmac-sha256"
|
||||
echo "TSIG secret (b64): c3RhbHdhcnQtdGVzdC10c2lnLXNlY3JldC1rZXkxMjM0NTY3ODkw"
|
||||
@@ -0,0 +1,3 @@
|
||||
dnsupdate=yes
|
||||
allow-dnsupdate-from=0.0.0.0/0
|
||||
zone-cache-refresh-interval=0
|
||||
@@ -0,0 +1,9 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
RUN pip install --no-cache-dir \
|
||||
"scim2-tester==0.2.8" \
|
||||
"scim2-client==0.7.5" \
|
||||
"scim2-models==0.6.12" \
|
||||
"httpx==0.28.1"
|
||||
|
||||
CMD ["sleep", "infinity"]
|
||||
@@ -0,0 +1,457 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Drives the third party SCIM client libraries against a Stalwart service provider."""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
import traceback
|
||||
import uuid
|
||||
|
||||
import httpx
|
||||
from scim2_client.engines.httpx import SyncSCIMClient
|
||||
from scim2_models import (
|
||||
Context,
|
||||
Error,
|
||||
ListResponse,
|
||||
PatchOp,
|
||||
PatchOperation,
|
||||
SearchRequest,
|
||||
ServiceProviderConfig,
|
||||
)
|
||||
from scim2_tester import check_server
|
||||
|
||||
|
||||
def allow_post_rfc7643_service_provider_config_attributes():
|
||||
"""RFC 9865 adds a top level `pagination` attribute to ServiceProviderConfig and
|
||||
draft-zollner-scim-interop-profile adds `interopProfileConformant`. scim2-models
|
||||
validates against RFC 7643 alone and forbids both."""
|
||||
ServiceProviderConfig.model_config["extra"] = "ignore"
|
||||
ServiceProviderConfig.model_rebuild(force=True)
|
||||
|
||||
|
||||
def build_client(url, token):
|
||||
return SyncSCIMClient(
|
||||
httpx.Client(
|
||||
base_url=url,
|
||||
headers={"Authorization": "Bearer " + token},
|
||||
verify=False,
|
||||
timeout=120.0,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def conformance(client, _domain):
|
||||
results = check_server(client, raise_exceptions=False)
|
||||
return {
|
||||
"checks": [
|
||||
{
|
||||
"status": result.status.name,
|
||||
"title": result.title,
|
||||
"reason": result.reason,
|
||||
"tags": sorted(result.tags) if result.tags else [],
|
||||
"resource_type": result.resource_type,
|
||||
}
|
||||
for result in results
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def lifecycle(client, domain):
|
||||
steps = []
|
||||
|
||||
def record(name, detail=None):
|
||||
steps.append({"step": name, "ok": True, "detail": detail})
|
||||
|
||||
user_model = client.get_resource_model("User")
|
||||
group_model = client.get_resource_model("Group")
|
||||
tag = uuid.uuid4().hex[:8]
|
||||
user_name = "lifecycle-{}@{}".format(tag, domain)
|
||||
renamed = "lifecycle-{}-renamed@{}".format(tag, domain)
|
||||
alias = "lifecycle-{}-alias@{}".format(tag, domain)
|
||||
display_name = "Lifecycle Person {}".format(tag)
|
||||
group_name = "Lifecycle Team {}".format(tag)
|
||||
user_id = None
|
||||
group_id = None
|
||||
|
||||
try:
|
||||
config = client.service_provider_config
|
||||
assert config.patch.supported is True
|
||||
assert config.etag.supported is True
|
||||
assert config.sort.supported is True
|
||||
assert config.change_password.supported is False
|
||||
assert config.bulk.max_operations == 1000, config.bulk
|
||||
assert config.filter.max_results == 200, config.filter
|
||||
record("discover", {
|
||||
"resource_types": sorted(
|
||||
resource_type.id for resource_type in client.resource_types
|
||||
),
|
||||
"resource_models": sorted(
|
||||
model.__name__ for model in client.resource_models
|
||||
),
|
||||
})
|
||||
|
||||
created = client.create(
|
||||
user_model(
|
||||
user_name=user_name,
|
||||
display_name=display_name,
|
||||
external_id="lifecycle-" + tag,
|
||||
emails=[{"value": alias}],
|
||||
),
|
||||
expected_status_codes=[201],
|
||||
raise_scim_errors=True,
|
||||
)
|
||||
user_id = created.id
|
||||
assert created.user_name == user_name, created.user_name
|
||||
assert created.display_name == display_name, created.display_name
|
||||
assert created.meta.location.endswith("/Users/" + user_id), created.meta.location
|
||||
assert created.meta.version, "the create response carried no version"
|
||||
assert "last_modified" not in type(created.meta).model_fields, "meta.lastModified was published"
|
||||
record("create_user", {"id": user_id, "version": created.meta.version})
|
||||
|
||||
fetched = client.query(
|
||||
user_model, user_id, expected_status_codes=[200], raise_scim_errors=True
|
||||
)
|
||||
assert fetched.id == user_id
|
||||
assert fetched.meta.version == created.meta.version
|
||||
assert [email.value for email in fetched.emails] == [user_name, alias], fetched.emails
|
||||
record("query_user_by_id")
|
||||
|
||||
response = client.client.get(
|
||||
"/Users", params={"filter": 'userName eq "{}"'.format(user_name)}
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
listed = ListResponse[user_model].model_validate(
|
||||
response.json(), scim_ctx=Context.RESOURCE_QUERY_RESPONSE
|
||||
)
|
||||
assert listed.total_results == 1, listed.total_results
|
||||
assert listed.resources[0].id == user_id
|
||||
record("query_user_by_filter")
|
||||
|
||||
searched = client.search(
|
||||
search_request=SearchRequest(filter='userName eq "{}"'.format(user_name)),
|
||||
expected_status_codes=[200],
|
||||
raise_scim_errors=True,
|
||||
)
|
||||
assert searched.total_results == 1, searched.total_results
|
||||
record("search_endpoint")
|
||||
|
||||
patched = client.modify(
|
||||
user_model,
|
||||
user_id,
|
||||
PatchOp[user_model](
|
||||
operations=[
|
||||
PatchOperation(op="replace", path="displayName", value="Patched " + tag),
|
||||
PatchOperation(op="replace", path="active", value=False),
|
||||
]
|
||||
),
|
||||
expected_status_codes=[200],
|
||||
raise_scim_errors=True,
|
||||
)
|
||||
assert patched.display_name == "Patched " + tag, patched.display_name
|
||||
assert patched.active is False, patched.active
|
||||
assert patched.meta.version != created.meta.version, "the version did not change"
|
||||
record("patch_user")
|
||||
|
||||
replaced = client.replace(
|
||||
user_model(id=user_id, user_name=renamed),
|
||||
expected_status_codes=[200],
|
||||
raise_scim_errors=True,
|
||||
)
|
||||
assert replaced.user_name == renamed, replaced.user_name
|
||||
assert replaced.active is True, "a replace must reset active to its default"
|
||||
assert replaced.display_name is None, replaced.display_name
|
||||
record("replace_user")
|
||||
|
||||
group = client.create(
|
||||
group_model(display_name=group_name, members=[{"value": user_id}]),
|
||||
expected_status_codes=[201],
|
||||
raise_scim_errors=True,
|
||||
)
|
||||
group_id = group.id
|
||||
assert group.display_name == group_name
|
||||
assert [member.value for member in group.members] == [user_id], group.members
|
||||
record("create_group_with_member", {"id": group_id})
|
||||
|
||||
member_view = client.query(
|
||||
user_model, user_id, expected_status_codes=[200], raise_scim_errors=True
|
||||
)
|
||||
assert [entry.value for entry in member_view.groups] == [group_id], member_view.groups
|
||||
record("membership_visible_on_user")
|
||||
|
||||
emptied = client.modify(
|
||||
group_model,
|
||||
group_id,
|
||||
PatchOp[group_model](
|
||||
operations=[PatchOperation(op="remove", path="members")]
|
||||
),
|
||||
expected_status_codes=[200],
|
||||
raise_scim_errors=True,
|
||||
)
|
||||
assert not emptied.members, emptied.members
|
||||
record("patch_group_members")
|
||||
|
||||
client.delete(group_model, group_id, expected_status_codes=[204], raise_scim_errors=True)
|
||||
group_id = None
|
||||
record("delete_group")
|
||||
|
||||
client.delete(user_model, user_id, expected_status_codes=[204], raise_scim_errors=True)
|
||||
gone = client.query(
|
||||
user_model,
|
||||
user_id,
|
||||
expected_status_codes=[404],
|
||||
raise_scim_errors=False,
|
||||
)
|
||||
assert isinstance(gone, Error), gone
|
||||
assert gone.status == 404, gone
|
||||
user_id = None
|
||||
record("delete_user")
|
||||
except Exception as err:
|
||||
steps.append(
|
||||
{
|
||||
"step": "aborted",
|
||||
"ok": False,
|
||||
"detail": "".join(
|
||||
traceback.format_exception(type(err), err, err.__traceback__)
|
||||
),
|
||||
}
|
||||
)
|
||||
finally:
|
||||
for model, resource_id in ((group_model, group_id), (user_model, user_id)):
|
||||
if resource_id:
|
||||
try:
|
||||
client.delete(model, resource_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {"steps": steps}
|
||||
|
||||
|
||||
def clients(client, domain):
|
||||
"""Replays the payload shapes that Okta and the Keycloak community extensions send."""
|
||||
steps = []
|
||||
user_model = client.get_resource_model("User")
|
||||
tag = uuid.uuid4().hex[:8]
|
||||
created = []
|
||||
|
||||
def check(name, fn):
|
||||
try:
|
||||
fn()
|
||||
steps.append({"step": name, "ok": True, "detail": None})
|
||||
except Exception as err:
|
||||
steps.append(
|
||||
{
|
||||
"step": name,
|
||||
"ok": False,
|
||||
"detail": "".join(
|
||||
traceback.format_exception(type(err), err, err.__traceback__)
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
def post(name, payload):
|
||||
def run():
|
||||
response = client.client.post("/Users", json=payload)
|
||||
assert response.status_code == 201, "{} {}".format(
|
||||
response.status_code, response.text
|
||||
)
|
||||
body = response.json()
|
||||
created.append(body["id"])
|
||||
assert body["userName"] == payload["userName"], body
|
||||
assert "password" not in response.text, body
|
||||
if payload.get("displayName"):
|
||||
assert body["displayName"] == payload["displayName"], body
|
||||
elif payload.get("name", {}).get("givenName"):
|
||||
expected = " ".join(
|
||||
part
|
||||
for part in (
|
||||
payload["name"].get("givenName"),
|
||||
payload["name"].get("familyName"),
|
||||
)
|
||||
if part
|
||||
)
|
||||
assert body["displayName"] == expected, body
|
||||
user_model.model_validate(body, scim_ctx=Context.RESOURCE_QUERY_RESPONSE)
|
||||
|
||||
check(name, run)
|
||||
|
||||
okta_name = "okta-{}@{}".format(tag, domain)
|
||||
post(
|
||||
"okta_create_user",
|
||||
{
|
||||
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
|
||||
"userName": okta_name,
|
||||
"name": {"givenName": "Barbara", "familyName": "Jensen"},
|
||||
"emails": [{"primary": True, "value": okta_name, "type": "work"}],
|
||||
"displayName": "Barbara Jensen",
|
||||
"locale": "en-US",
|
||||
"externalId": "00u" + tag,
|
||||
"groups": [],
|
||||
"password": "correct horse battery staple",
|
||||
"active": True,
|
||||
"title": "Vice President",
|
||||
"userType": "Employee",
|
||||
"phoneNumbers": [{"value": "555-0100", "type": "work"}],
|
||||
},
|
||||
)
|
||||
|
||||
keycloak_name = "keycloak-{}@{}".format(tag, domain)
|
||||
post(
|
||||
"keycloak_create_user",
|
||||
{
|
||||
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
|
||||
"userName": keycloak_name,
|
||||
"name": {"givenName": "Wile", "familyName": "Coyote"},
|
||||
"emails": [{"value": keycloak_name, "primary": True}],
|
||||
"active": True,
|
||||
"externalId": "kc-" + tag,
|
||||
},
|
||||
)
|
||||
|
||||
entra_name = "entra-{}@{}".format(tag, domain)
|
||||
post(
|
||||
"entra_create_user",
|
||||
{
|
||||
"schemas": [
|
||||
"urn:ietf:params:scim:schemas:core:2.0:User",
|
||||
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
|
||||
],
|
||||
"userName": entra_name,
|
||||
"name": {"givenName": "Road", "familyName": "Runner"},
|
||||
"displayName": "Road Runner",
|
||||
"emails": [{"value": entra_name, "type": "work", "primary": True}],
|
||||
"active": True,
|
||||
"externalId": "entra-" + tag,
|
||||
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
|
||||
"department": "Sales",
|
||||
"employeeNumber": "42",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
if created:
|
||||
okta_id = created[0]
|
||||
|
||||
def okta_put():
|
||||
response = client.client.put(
|
||||
"/Users/" + okta_id,
|
||||
json={
|
||||
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
|
||||
"id": okta_id,
|
||||
"userName": okta_name,
|
||||
"name": {"givenName": "Babs", "familyName": "Jensen"},
|
||||
"emails": [{"primary": True, "value": okta_name, "type": "work"}],
|
||||
"displayName": "Babs Jensen",
|
||||
"active": False,
|
||||
"password": "correct horse battery staple",
|
||||
"title": "President",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
body = response.json()
|
||||
assert body["displayName"] == "Babs Jensen", body
|
||||
assert body["active"] is False, body
|
||||
|
||||
check("okta_replace_user", okta_put)
|
||||
|
||||
def keycloak_patch():
|
||||
response = client.client.patch(
|
||||
"/Users/" + created[1],
|
||||
json={
|
||||
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
"Operations": [{"op": "replace", "value": {"active": "false"}}],
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json()["active"] is False, response.text
|
||||
|
||||
check("keycloak_deactivate_user", keycloak_patch)
|
||||
|
||||
def entra_patch():
|
||||
response = client.client.patch(
|
||||
"/Users/" + created[2],
|
||||
json={
|
||||
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
|
||||
"Operations": [
|
||||
{"op": "replace", "path": "name.givenName", "value": "Wile"},
|
||||
{"op": "replace", "path": "displayName", "value": "Wile Runner"},
|
||||
{
|
||||
"op": "add",
|
||||
"path": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department",
|
||||
"value": "Marketing",
|
||||
},
|
||||
],
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert response.json()["displayName"] == "Wile Runner", response.text
|
||||
|
||||
check("entra_patch_user", entra_patch)
|
||||
|
||||
def okta_lookup():
|
||||
response = client.client.get(
|
||||
"/Users", params={"filter": 'userName eq "{}"'.format(okta_name)}
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
listed = ListResponse[user_model].model_validate(
|
||||
response.json(), scim_ctx=Context.RESOURCE_QUERY_RESPONSE
|
||||
)
|
||||
assert listed.total_results == 1, listed.total_results
|
||||
|
||||
check("okta_lookup_by_username", okta_lookup)
|
||||
|
||||
def rejects_typos():
|
||||
response = client.client.post(
|
||||
"/Users",
|
||||
json={
|
||||
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
|
||||
"userName": "typo-{}@{}".format(tag, domain),
|
||||
"dispalyName": "Typo",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 400, response.text
|
||||
assert response.json()["scimType"] == "invalidSyntax", response.text
|
||||
|
||||
check("misspelled_attributes_are_still_rejected", rejects_typos)
|
||||
|
||||
for resource_id in created:
|
||||
try:
|
||||
client.client.delete("/Users/" + resource_id)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return {"steps": steps}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--url", required=True)
|
||||
parser.add_argument("--token", required=True)
|
||||
parser.add_argument("--domain", required=True)
|
||||
parser.add_argument(
|
||||
"--mode", required=True, choices=["conformance", "lifecycle", "clients"]
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
allow_post_rfc7643_service_provider_config_attributes()
|
||||
client = build_client(args.url, args.token)
|
||||
try:
|
||||
client.discover()
|
||||
except Exception as err:
|
||||
json.dump(
|
||||
{"error": "discovery failed: " + "".join(
|
||||
traceback.format_exception(type(err), err, err.__traceback__)
|
||||
)},
|
||||
sys.stdout,
|
||||
)
|
||||
sys.stdout.write("\n")
|
||||
return
|
||||
|
||||
runner = {"conformance": conformance, "lifecycle": lifecycle, "clients": clients}[
|
||||
args.mode
|
||||
]
|
||||
json.dump(runner(client, args.domain), sys.stdout)
|
||||
sys.stdout.write("\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
CERT_DIR=/certs
|
||||
|
||||
if [ ! -f "$CERT_DIR/cert.pem" ]; then
|
||||
echo "Generating self-signed certificate..."
|
||||
openssl req -x509 -newkey rsa:2048 -nodes \
|
||||
-keyout "$CERT_DIR/key.pem" \
|
||||
-out "$CERT_DIR/cert.pem" \
|
||||
-days 365 \
|
||||
-subj "/CN=localhost/O=Stalwart Test/C=US" \
|
||||
-addext "subjectAltName=DNS:localhost,DNS:keycloak,DNS:openldap,DNS:pebble,DNS:*.stalwart.test,IP:127.0.0.1"
|
||||
|
||||
# Create combined PEM for services that need it
|
||||
cat "$CERT_DIR/cert.pem" "$CERT_DIR/key.pem" > "$CERT_DIR/combined.pem"
|
||||
|
||||
# Create PKCS12 for Keycloak
|
||||
openssl pkcs12 -export -in "$CERT_DIR/cert.pem" -inkey "$CERT_DIR/key.pem" \
|
||||
-out "$CERT_DIR/keystore.p12" -name localhost -password pass:changeit
|
||||
|
||||
chmod 644 "$CERT_DIR"/*
|
||||
echo "Certificates generated."
|
||||
else
|
||||
echo "Certificates already exist."
|
||||
fi
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
for i in $(seq 1 30); do
|
||||
if fdbcli --exec 'status minimal' --timeout 5 2>&1 | grep -q "The database is available"; then
|
||||
echo "FoundationDB already configured."
|
||||
exit 0
|
||||
fi
|
||||
if fdbcli --exec 'configure new single memory' --timeout 5 2>&1 | grep -q "Database created"; then
|
||||
echo "FoundationDB configured."
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting for FoundationDB to be ready (attempt $i)..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "ERROR: Failed to configure FoundationDB after retries" >&2
|
||||
exit 1
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Wait for MinIO to be ready
|
||||
echo "Waiting for MinIO..."
|
||||
until mc alias set local http://minio:9000 minioadmin minioadmin 2>/dev/null; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Create the stalwart bucket
|
||||
mc mb local/stalwart --ignore-existing
|
||||
echo "MinIO bucket 'stalwart' created."
|
||||
Binary file not shown.
@@ -0,0 +1,35 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
xjMEZMYfNhYJKwYBBAHaRw8BAQdAYyTN1HzqapLw8xwkCGwa0OjsgT/JqhcB/+Dy
|
||||
Ga1fsBrNG0pvaG4gRG9lIDxqb2huQGV4YW1wbGUub3JnPsKJBBMWCAAxFiEEg836
|
||||
pwbXpuQ/THMtpJwd4oBfIrUFAmTGHzYCGwMECwkIBwUVCAkKCwUWAgMBAAAKCRCk
|
||||
nB3igF8itYhyAQD2jEdeYa3gyQ47X9YWZTK1wEJkN8W9//V1fYl2XQwqlQEA0qBv
|
||||
Ai6nUh99oDw+/zQ8DFIKdeb5Ti4tu/X58PdpiQ7OOARkxh82EgorBgEEAZdVAQUB
|
||||
AQdAvXz2FbFN0DovQF/ACnZyczTsSIQp0mvmF1PE+aijbC8DAQgHwngEGBYIACAW
|
||||
IQSDzfqnBtem5D9Mcy2knB3igF8itQUCZMYfNgIbDAAKCRCknB3igF8itRnoAQC3
|
||||
GzPmgx7TnB+SexPuJV/DoKSMJ0/X+hbEFcZkulxaDQEAh+xiJCvf+ZNAKw6kFhsL
|
||||
UuZhEDktxnY6Ehz3aB7FawA=
|
||||
=KGrr
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDbjCCAlagAwIBAgIUZ4K0WXNSS8H0cUcZavD9EYqqTAswDQYJKoZIhvcNAQEN
|
||||
BQAwLTErMCkGA1UEAxMiU2FtcGxlIExBTVBTIENlcnRpZmljYXRlIEF1dGhvcml0
|
||||
eTAgFw0xOTExMjAwNjU0MThaGA8yMDUyMDkyNzA2NTQxOFowGTEXMBUGA1UEAxMO
|
||||
QWxpY2UgTG92ZWxhY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD
|
||||
7q35ZdG2JAzzJGNZDZ9sV7AKh0hlRfoFjTZN5m4RegQAYSyag43ouWi1xRN0avf0
|
||||
UTYrwjK04qRdV7GzCACoEKq/xiNUOsjfJXzbCublN3fZMOXDshKKBqThlK75SjA9
|
||||
Czxg7ejGoiY/iidk0e91neK30SCCaBTJlfR2ZDrPk73IPMeksxoTatfF9hw9dDA+
|
||||
/Hi1yptN/aG0Q/s9icFrxr6y2zQXsjuQPmjMZgj10aD9cazWVgRYCgflhmA0V1uQ
|
||||
l1wobYU8DAVxVn+GgabqyjGQMoythIK0Gn5+ofwxXXUM/zbU+g6+1ISdoXxRRFtq
|
||||
2GzbIqkAHZZQm+BbnFrhAgMBAAGjgZcwgZQwDAYDVR0TAQH/BAIwADAeBgNVHREE
|
||||
FzAVgRNhbGljZUBzbWltZS5leGFtcGxlMBMGA1UdJQQMMAoGCCsGAQUFBwMEMA8G
|
||||
A1UdDwEB/wQFAwMHoAAwHQYDVR0OBBYEFKwuVFqk/VUYry7oZkQ40SXR1wB5MB8G
|
||||
A1UdIwQYMBaAFLdSTXPAiD2yw3paDPOU9/eAonfbMA0GCSqGSIb3DQEBDQUAA4IB
|
||||
AQB76o4Yz7yrVSFcpXqLrcGtdI4q93aKCXECCCzNQLp4yesh6brqaZHNJtwYcJ5T
|
||||
qbUym9hJ70iJE4jGNN+yAZR1ltte0HFKYIBKM4EJumG++2hqbUaLz4tl06BHaQPC
|
||||
v/9NiNY7q9R9c/B6s1YzHhwqkWht2a+AtgJ4BkpG+g+MmZMQV/Ao7RwLFKJ9OlMW
|
||||
LBmEXFcpIJN0HpPasT0nEl/MmotSu+8RnClAi3yFfyTKb+8rD7VxuyXetqDZ6dU/
|
||||
9/iqD/SZS7OQIjywtd343mACz3B1RlFxMHSA6dQAf2btGumqR0KiAp3KkYRAePoa
|
||||
JqYkB7Zad06ngFl0G0FHON+7
|
||||
-----END CERTIFICATE-----
|
||||
Binary file not shown.
@@ -0,0 +1,53 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=0TDv
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,98 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIHbTCCBVWgAwIBAgIQFxA+3j2KHLXKBlGT58pDazANBgkqhkiG9w0BAQsFADBr
|
||||
MQswCQYDVQQGEwJJVDEOMAwGA1UEBwwFTWlsYW4xIzAhBgNVBAoMGkFjdGFsaXMg
|
||||
Uy5wLkEuLzAzMzU4NTIwOTY3MScwJQYDVQQDDB5BY3RhbGlzIEF1dGhlbnRpY2F0
|
||||
aW9uIFJvb3QgQ0EwHhcNMjAwNzA2MDg0NTQ3WhcNMzAwOTIyMTEyMjAyWjCBgTEL
|
||||
MAkGA1UEBhMCSVQxEDAOBgNVBAgMB0JlcmdhbW8xGTAXBgNVBAcMEFBvbnRlIFNh
|
||||
biBQaWV0cm8xFzAVBgNVBAoMDkFjdGFsaXMgUy5wLkEuMSwwKgYDVQQDDCNBY3Rh
|
||||
bGlzIENsaWVudCBBdXRoZW50aWNhdGlvbiBDQSBHMzCCAiIwDQYJKoZIhvcNAQEB
|
||||
BQADggIPADCCAgoCggIBAO3mh5ahwaS27cJCVfc/Dw8iYF8T4KZDiIZJkXkcGy8a
|
||||
UA/cRgHu9ro6hsxRYe/ED4AIcSlarRh82HqtFSVQs4ZwikQW1V/icCIS91C2IVAG
|
||||
a1YlKfedqgweqky+bBniUvRevVT0keZOqRTcO5hw007dL6FhYNmlZBt5IaJs1V6I
|
||||
niRjokOHR++qWgrUGy5LefY6ACs9gZ8Bi0OMK9PZ37pibeQCsdmMRytl4Ej7JVWe
|
||||
M/BtNIIprHwO1LY0/8InpGOmdG+5LC6xHLzg53B0HvVUqzUQNePUhNwJZFmmTP46
|
||||
FXovxmH4/SuY5IkXop0eJqjN+dxRHHizngYUk1EaTHUOcLFy4vQ0kxgbjb+GsNg6
|
||||
M2/6gZZIRk78JPdpotIwHnBNtkp9wPVH61NqdcP7kbPkyLXkNMTtAfydpmNnGqqH
|
||||
LEvUrK4iBpUPG9C09KOjm9OyhrT2uf5SLzJsee9g79r/rw4hAgcsZtR3YI6fCbRO
|
||||
JncmD+hgbHCck+9TWcNc1x5xZMgm8UXmoPamkkfceAlVV49QQ5jUTgqneTQHyF1F
|
||||
2ExXmf47pEIoJMVxloRIXywQuB2uqcIs8/X6tfsMDynFmhfT/0mTrgQ6xt9DIsgm
|
||||
WuuhvZhLReWS7oeKxnyqscuGeTMXnLs7fjGZq0inyhnlznhA/4rl+WdNjNaO4jEv
|
||||
AgMBAAGjggH0MIIB8DAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFFLYiDrI
|
||||
n3hm7YnzezhwlMkCAjbQMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAYYlaHR0
|
||||
cDovL29jc3AwNS5hY3RhbGlzLml0L1ZBL0FVVEgtUk9PVDBFBgNVHSAEPjA8MDoG
|
||||
BFUdIAAwMjAwBggrBgEFBQcCARYkaHR0cHM6Ly93d3cuYWN0YWxpcy5pdC9hcmVh
|
||||
LWRvd25sb2FkMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDCB4wYDVR0f
|
||||
BIHbMIHYMIGWoIGToIGQhoGNbGRhcDovL2xkYXAwNS5hY3RhbGlzLml0L2NuJTNk
|
||||
QWN0YWxpcyUyMEF1dGhlbnRpY2F0aW9uJTIwUm9vdCUyMENBLG8lM2RBY3RhbGlz
|
||||
JTIwUy5wLkEuJTJmMDMzNTg1MjA5NjcsYyUzZElUP2NlcnRpZmljYXRlUmV2b2Nh
|
||||
dGlvbkxpc3Q7YmluYXJ5MD2gO6A5hjdodHRwOi8vY3JsMDUuYWN0YWxpcy5pdC9S
|
||||
ZXBvc2l0b3J5L0FVVEgtUk9PVC9nZXRMYXN0Q1JMMB0GA1UdDgQWBBS+l6mqhL+A
|
||||
vxBTfQky+eEuMhvPdzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIB
|
||||
ACab5xtZDXSzEgPp51X3hICFzULDO2EcV8em5hLfSCKxZR9amCnjcODVfMbaKfdU
|
||||
ZXtevMIIZmHgkz9dBan7ijGbJXjZCPP29zwZGSyCjpfadg5s9hnNCN1r3DGwIHfy
|
||||
LgbcfffDyV/2wW+XTGbhldnazZsX892q+srRmC8XnX4ygg+eWL/AkHDenvbFuTlJ
|
||||
vUyd5I7e1nb3dYXMObPu24ZTQ9/K1hSQbs7pqecaptTUjoIDpBUpSp4Us+h1I4MA
|
||||
WonemKYoPS9f0y65JrRCKcfsKSI+1kwPSanDDMiydKzeo46XrS0hlA5NzQjqUJ7U
|
||||
suGvPtDvknqc0v03nNXBnUjejYtvwO3sEDXdUW5m9kjNqlQZXzdHumZJVqPUGKTW
|
||||
cn9Hf3d7qbCmmxPXjQoNUuHg56fLCanZWkEO4SP1GAgIA7SyJu/yffv0ts7sBFrS
|
||||
TD3L2mCAXM3Y8BfblvvDSf2bvySm/fPe9brmuzrCXsTxUQc1+/z5ydvzV3E3cLnU
|
||||
oSXP6XfXNyEVO6sPkcUSnISHM798xLkCTB5EkjPCjPE2zs4v9L9JVOkkskvW6RnW
|
||||
WccdfR3fELNHL/kep8re6IbbYs8Hn5GM0Ohs8CMDPYEox+QX/6/SnOfyaqqSilBo
|
||||
nMQBstsymBBgdEKO+tTHHCMnJQVvZn7jRQ20wXgxMrvN
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
|
||||
BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
|
||||
MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
|
||||
IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC
|
||||
SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1
|
||||
ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv
|
||||
UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX
|
||||
4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9
|
||||
KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/
|
||||
gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb
|
||||
rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ
|
||||
51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F
|
||||
be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe
|
||||
KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F
|
||||
v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn
|
||||
fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7
|
||||
jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz
|
||||
ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
|
||||
ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL
|
||||
e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70
|
||||
jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz
|
||||
WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V
|
||||
SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j
|
||||
pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX
|
||||
X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok
|
||||
fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R
|
||||
K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU
|
||||
ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
|
||||
LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
|
||||
LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDbjCCAlagAwIBAgIUZ4K0WXNSS8H0cUcZavD9EYqqTAswDQYJKoZIhvcNAQEN
|
||||
BQAwLTErMCkGA1UEAxMiU2FtcGxlIExBTVBTIENlcnRpZmljYXRlIEF1dGhvcml0
|
||||
eTAgFw0xOTExMjAwNjU0MThaGA8yMDUyMDkyNzA2NTQxOFowGTEXMBUGA1UEAxMO
|
||||
QWxpY2UgTG92ZWxhY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD
|
||||
7q35ZdG2JAzzJGNZDZ9sV7AKh0hlRfoFjTZN5m4RegQAYSyag43ouWi1xRN0avf0
|
||||
UTYrwjK04qRdV7GzCACoEKq/xiNUOsjfJXzbCublN3fZMOXDshKKBqThlK75SjA9
|
||||
Czxg7ejGoiY/iidk0e91neK30SCCaBTJlfR2ZDrPk73IPMeksxoTatfF9hw9dDA+
|
||||
/Hi1yptN/aG0Q/s9icFrxr6y2zQXsjuQPmjMZgj10aD9cazWVgRYCgflhmA0V1uQ
|
||||
l1wobYU8DAVxVn+GgabqyjGQMoythIK0Gn5+ofwxXXUM/zbU+g6+1ISdoXxRRFtq
|
||||
2GzbIqkAHZZQm+BbnFrhAgMBAAGjgZcwgZQwDAYDVR0TAQH/BAIwADAeBgNVHREE
|
||||
FzAVgRNhbGljZUBzbWltZS5leGFtcGxlMBMGA1UdJQQMMAoGCCsGAQUFBwMEMA8G
|
||||
A1UdDwEB/wQFAwMHoAAwHQYDVR0OBBYEFKwuVFqk/VUYry7oZkQ40SXR1wB5MB8G
|
||||
A1UdIwQYMBaAFLdSTXPAiD2yw3paDPOU9/eAonfbMA0GCSqGSIb3DQEBDQUAA4IB
|
||||
AQB76o4Yz7yrVSFcpXqLrcGtdI4q93aKCXECCCzNQLp4yesh6brqaZHNJtwYcJ5T
|
||||
qbUym9hJ70iJE4jGNN+yAZR1ltte0HFKYIBKM4EJumG++2hqbUaLz4tl06BHaQPC
|
||||
v/9NiNY7q9R9c/B6s1YzHhwqkWht2a+AtgJ4BkpG+g+MmZMQV/Ao7RwLFKJ9OlMW
|
||||
LBmEXFcpIJN0HpPasT0nEl/MmotSu+8RnClAi3yFfyTKb+8rD7VxuyXetqDZ6dU/
|
||||
9/iqD/SZS7OQIjywtd343mACz3B1RlFxMHSA6dQAf2btGumqR0KiAp3KkYRAePoa
|
||||
JqYkB7Zad06ngFl0G0FHON+7
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,211 @@
|
||||
Subject: TRUE
|
||||
Content-Type: multipart/encrypted;
|
||||
protocol="application/pgp-encrypted";
|
||||
boundary="17778885806d6b28_46555a54adda6fa5_d83705f326a6b951"
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: FALSE
|
||||
Content-Type: multipart/signed;
|
||||
protocol="application/pkcs7-signature";
|
||||
boundary="17778885806d6b28_46555a54adda6fa5_d83705f326a6b951"
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: application/pkcs7-mime;
|
||||
name="smime.p7m";
|
||||
smime-type=enveloped-data
|
||||
Content-Disposition: attachment;
|
||||
filename="smime.p7m"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: application/pkcs7-signature;
|
||||
name="smime.p7s"; smime-type="signed-data"
|
||||
Content-Disposition: attachment;
|
||||
filename="smime.p7s"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: application/octet-stream;
|
||||
name="smime.p7m"
|
||||
Content-Disposition: attachment;
|
||||
filename="smime.p7m"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: application/octet-stream;
|
||||
name="smime.p7m"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: attachment;
|
||||
filename="smime.p7m"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: attachment;
|
||||
filename="smime.p7s"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: attachment;
|
||||
filename="smime.p7c"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: attachment;
|
||||
filename="smime.p7z"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: FALSE
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: attachment;
|
||||
filename="file.gz"
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: FALSE
|
||||
Content-Type: application/octet-stream
|
||||
Content-Disposition: attachment
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: FALSE
|
||||
Content-Type: multipart/mixed;
|
||||
boundary="17778885806d6b28_46555a54adda6fa5_d83705f326a6b951"
|
||||
|
||||
body
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: multipart/mixed; boundary="----sinikael-?=_1-17364333937490.28304631087789"
|
||||
|
||||
------sinikael-?=_1-17364333937490.28304631087789
|
||||
Content-Type: text/plain
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
Version: Mailvelope v6.0.1
|
||||
Comment: https://mailvelope.com
|
||||
|
||||
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
|
||||
5fkw+PwLe2vPtuObvuY+ezbJGb1jV0tWZFXF
|
||||
=3DaQyM
|
||||
-----END PGP MESSAGE-----
|
||||
|
||||
------sinikael-?=_1-17364333937490.28304631087789--
|
||||
!!!
|
||||
Subject: TRUE
|
||||
Content-Type: text/plain
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
|
||||
|
||||
-----BEGIN PGP MESSAGE-----
|
||||
Version: Mailvelope v6.0.1
|
||||
Comment: https://mailvelope.com
|
||||
|
||||
wcFMAy3n9oegk2NSARAApgl4nuztm5uxuCe+7ISW9Ox+315/pCHZmOUibORX
|
||||
xGEbUs+ZgTqKIdYMet3+zSS70ykgjZDvh+cLm1oGmD5ZzLxSMjhgLpqrA0tG
|
||||
3GB3gus844irLGBjVwgTuwAKhRz/CYaqlKGOloQkvcwRwy3N8UY8KG/WqD63
|
||||
g9WQKYc+8+cR4wfQ0PSzZL6HexdT2LE2mWgKxStwDbbkwZumR0qZy4OvyI6O
|
||||
zFCZSaz3F3VnDGbQgo5hK8Iynf25sC54P/E0ykdG6QpJZPo/ASoWePv0XyT6
|
||||
wRiqq2cx366P6lxB3CJyjn+qRCfcXz0XXYejHmuI++S6ucNS4JcIhpuoi+tv
|
||||
8b7pSy/6yQEKLyUhPfUmvFLxBm10bu8E9uhsmZnpiSnBsEGkLm/l9TFbOOSd
|
||||
9nK0NeEVfqfIi25bxVJtRcYryf7BpjmgEdKlmF8Efeb1RpaI8IwVc6E7AhYB
|
||||
c1vz1gN6BQ5ePtlHDFKxFV3jIqBKck8h2GSFGEYOXyTT+3tgFkqv/SuAUed9
|
||||
X0bCjy7v578nsNieoyy/133X1+mu7L8rdADEAHhU/WLQ9VY/xu6GhNA0vzU8
|
||||
yVQfSEJ1DJ4awU9Cn1mrbVg3vD/jpQzs67Sd33gC8xMqA9ZFOmXrnR4V1wkz
|
||||
Y8XobC+UY6o9qn/Oz5mEtZG8rItYJ/bPOSSlFP6kXVrBwUwD8GquMWN8AUEB
|
||||
D/9IVPN/qCtuhF+9jIjrxiw+agmeqUPWBEmLLZYL6xivP7Bn5bOJb6wwgU4e
|
||||
IRIoh3Q5AKLvqN26BPePM16yZ6Z6qxTP/CFT5mOQQbj+3TH6fYD1ui74FoyR
|
||||
+szTfntIdUOShKqogSKoRytMXheR+4TW7/D525ohRUsz71pfdCxqYC+k/vXr
|
||||
ffl7lkv/V7GkPJ5fT+CantgLqXVevCIKOMVDVBT6G92t8Zn0klqv+MfVsZ3V
|
||||
6FbwcqS+GxsCNezSdT1+K2yPja0fZffQOHD6nLDyIZmcr8KrCmP1MPY5LKJw
|
||||
bMVCbYz0CrRl9d6JJGZOq+yapVOc0CDxWmxhGJP3M9OiCvGoPz3l+fDdNJ0f
|
||||
dmxEv8c/I5t+AELxLMBa4aPuGE3pZQj4zyzhC3gnK5n9bqFecHl2+Kz+aVsi
|
||||
4B1xZXIPT+XmlXM4rgCtuMlKZ6YkGRWiAnC8jok/k4iPaN7mfKbos0xwa187
|
||||
haMjKKFVP8YvXlYpGeuvP3C2/oBxwsw9WihqL2tLTEE60ZgDEKWcZ3zwVKjl
|
||||
bSNeDsWXlj+vIletdDyH/AMhyDOnUDc4bTkRW7W8ntq3fi8XmpQjHzW02BEd
|
||||
Wq1Y/bV7nlh97Y7d3z5zlLhQnKrrP5IyQdOkd2WGpU39cDZe6XE6arQZKGVT
|
||||
upnuX3Q48Hm6oSga+cydngjShtLCFQF/MFCZVYydjhe+KtzZCYBZ8nCMRxcV
|
||||
PTuACJtUqOR/z5aPgRjM14accCYDwJ0Dm51h5LuEzYFDJjcdFbVSVfvnCy5a
|
||||
b9h6VBCpWieI6ubAzYKKJxGwp/OcoaQyYPjwlNQyTSb7omZPsAtFpTALNXbU
|
||||
CIM2cFnD/MMvgEHCuqPZoKh0YdQxYV50p36Wa/rMvTfW+S1T2neWGD6kMDWZ
|
||||
I651K+HBCQV6INrJk5ugvCt26/l8+Y75cnGEKbkyJgt+NGjULX3jjPawhvwN
|
||||
0EKx8hYwASuJ3E71iAXga7oSMRemDk4ZXoz+PDngoWtcoXcdQNMiVymOt6iZ
|
||||
P5ImSQXkId1XZYjS3+1t+Sk8WgUi5kvu4WP3hm1Ovjd1kXTy3lqXpfci23si
|
||||
eZofjs9DLldkV5xtOwWVx/B1UkqvtD2BuwcDWgvGEm2LEn4/eXkHUTzHLs4j
|
||||
T9s454HasmVfd+4/koBdD6ASDqFf5Ue14OonsXvIvLop2CgUHxDVffr1onSk
|
||||
K9r0kKxe9iAFZ8KYpf2Do/FPTL8BIXjHC2vfJ05wl262xs7uNMdgWm4+NP/q
|
||||
uVNOoXByZIDEPixx7jimKhlEIZx36AbsI+OB5cV1Pr5SSbO3w205ALol+xKN
|
||||
TPJiaQDH8qNXX+9j4JfO8uWvDmhPUe83bm/mHg4wf/39+PNQptwmhLH9iXtC
|
||||
Czqgmr1vUNd/8dLgQuqVn/R3uUbGeWmKD9cqURWcvumbq+rFWPl1N7T7VRfc
|
||||
XGDnMBNBmLke2YO8XUY561lqKekfS/2fekSdz005sI2cnGmy5LLh+kPN6opz
|
||||
0pA2kSskbfSQqJmEdjKQU3oGEzEgwvOXjFwT7cChevgLEmDBkQXTDuEeo3Kb
|
||||
KnwaNPnodzaNXAfZh/NylEgcUFjEx6crZMN3ztl8zsvAvP4P0BPmixZ89G80
|
||||
5fkw+PwLe2vPtuObvuY+ezbJGb1jV0tWZFXF
|
||||
=3DaQyM
|
||||
-----END PGP MESSAGE-----
|
||||
@@ -0,0 +1,43 @@
|
||||
connections: 3
|
||||
state: created
|
||||
|
||||
1 ok select $mailbox
|
||||
2 ok select $mailbox
|
||||
|
||||
# Two connections have mailbox SELECTed, one doesn't.
|
||||
# The \recent flags can be given to either one of the SELECTed connections,
|
||||
# but never for the 3rd. We rely on mailbox state tracking to catch duplicate
|
||||
# \recent flags (which is why there are two FETCH FLAGS commands).
|
||||
|
||||
1 ok append $mailbox (\seen \flagged)
|
||||
* 1 exists
|
||||
2 ok noop
|
||||
* 1 exists
|
||||
3 ok status $mailbox (messages unseen recent)
|
||||
* status $mailbox (messages 1 unseen 0 recent 0)
|
||||
1 ok fetch 1 (uid flags)
|
||||
* 1 fetch (uid $uid1 flags (\seen \flagged))
|
||||
2 ok fetch 1 (uid flags)
|
||||
* 1 fetch (uid $uid1 flags (\seen \flagged))
|
||||
|
||||
2 ok append
|
||||
* 2 exists
|
||||
1 ok noop
|
||||
* 2 exists
|
||||
3 ok status $mailbox (messages unseen recent)
|
||||
* status $mailbox (messages 2 unseen 1 recent 0)
|
||||
1 ok fetch 2 (uid flags)
|
||||
2 ok fetch 2 (uid flags)
|
||||
|
||||
3 ok append
|
||||
3 ok status $mailbox (messages unseen)
|
||||
* status $mailbox (messages 3 unseen 2)
|
||||
2 ok noop
|
||||
* 3 exists
|
||||
1 ok noop
|
||||
* 3 exists
|
||||
1 ok fetch 3 (uid flags)
|
||||
2 ok fetch 3 (uid flags)
|
||||
|
||||
1 append ${mailbox}nonexistent
|
||||
no [trycreate]
|
||||
@@ -0,0 +1,39 @@
|
||||
capabilities: BINARY
|
||||
state: created
|
||||
|
||||
ok append $mailbox ~{{{
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: application/octet-stream
|
||||
Content-Transfer-Encoding: binary
|
||||
|
||||
nil
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
ok select $mailbox
|
||||
|
||||
# should have been converted to base64, or something
|
||||
ok fetch 1 (body.peek[1])
|
||||
! 1 fetch (body[1] {{{
|
||||
nil
|
||||
|
||||
}}})
|
||||
! 1 fetch (body[1] {{{
|
||||
nil
|
||||
|
||||
}}})
|
||||
! 1 fetch (body[1] ~{{{
|
||||
nil
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.size[1] binary.peek[1])
|
||||
! 1 fetch (binary.size[1] 6 binary[1] ~{{{
|
||||
nil
|
||||
|
||||
}}})
|
||||
@@ -0,0 +1,13 @@
|
||||
state: auth
|
||||
|
||||
# Don't confuse with ~{literal8}
|
||||
ok list "" ~foo
|
||||
no select ~foo
|
||||
|
||||
# atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards /
|
||||
# quoted-specials / resp-specials
|
||||
# quoted-specials = DQUOTE / "\"
|
||||
# resp-specials = "]"
|
||||
# list-wildcards = "%" / "*"
|
||||
no select !#$$&'+,-.0123456789:;<=>?@^_`|[}
|
||||
ok list "" !#$$&'+,-.0123456789:;<=>?@^_`|[}%*
|
||||
@@ -0,0 +1,75 @@
|
||||
# this test assumes that server stores INTERNALDATE timestamps in
|
||||
# EET/EEST timezones (or stores/fetches them using the same timezones as
|
||||
# they were APPENDed with)
|
||||
|
||||
# 1) Timezone changes from EET +0200 -> EEST +0300
|
||||
# 1a) BEFORE
|
||||
ok search before 24-mar-2007
|
||||
* search
|
||||
ok search before 25-mar-2007
|
||||
* search 1
|
||||
ok search before 26-mar-2007
|
||||
* search 1 2 3 4 5 6
|
||||
ok search before 27-mar-2007
|
||||
* search 1 2 3 4 5 6 7
|
||||
|
||||
# 1b) ON
|
||||
ok search on 23-mar-2007
|
||||
* search
|
||||
ok search on 24-mar-2007
|
||||
* search 1
|
||||
ok search on 25-mar-2007
|
||||
* search 2 3 4 5 6
|
||||
ok search on 26-mar-2007
|
||||
* search 7
|
||||
|
||||
# 1c) SINCE
|
||||
ok search 1:7 since 24-mar-2007
|
||||
* search 1 2 3 4 5 6 7
|
||||
ok search 1:7 since 25-mar-2007
|
||||
* search 2 3 4 5 6 7
|
||||
ok search 1:7 since 26-mar-2007
|
||||
* search 7
|
||||
ok search 1:7 since 27-mar-2007
|
||||
* search
|
||||
|
||||
# 2) Timezone changes from EEST +0300 -> EET +0200
|
||||
# 2a) BEFORE
|
||||
ok search 8:* before 27-oct-2007
|
||||
* search
|
||||
ok search 8:* before 28-oct-2007
|
||||
* search 8
|
||||
ok search 8:* before 29-oct-2007
|
||||
* search 8 9 10 11 12 13 14 15
|
||||
ok search 8:* before 30-oct-2007
|
||||
* search 8 9 10 11 12 13 14 15 16
|
||||
|
||||
# 2b) ON
|
||||
ok search 8:* on 26-oct-2007
|
||||
* search
|
||||
ok search 8:* on 27-oct-2007
|
||||
* search 8
|
||||
ok search 8:* on 28-oct-2007
|
||||
* search 9 10 11 12 13 14 15
|
||||
ok search 8:* on 29-oct-2007
|
||||
* search 16
|
||||
|
||||
# 2c) SINCE
|
||||
ok search 8:* since 27-oct-2007
|
||||
* search 8 9 10 11 12 13 14 15 16
|
||||
ok search 8:* since 28-oct-2007
|
||||
* search 9 10 11 12 13 14 15 16
|
||||
ok search 8:* since 29-oct-2007
|
||||
* search 16
|
||||
ok search 8:* since 30-oct-2007
|
||||
* search
|
||||
|
||||
# 3) Try a couple of NOTs
|
||||
ok search 1:7 not before 26-mar-2007
|
||||
* search 7
|
||||
ok search 1:7 not on 25-mar-2007
|
||||
* search 1 7
|
||||
ok search 8:* not since 28-oct-2007
|
||||
* search 8
|
||||
ok search 8:* not on 28-oct-2007
|
||||
* search 8 16
|
||||
@@ -0,0 +1,80 @@
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0200
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Mar 25 00:00:00 2007 +0200
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Mar 25 01:00:00 2007 +0200
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Mar 25 02:00:00 2007 +0200
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Mar 25 04:00:00 2007 +0300
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Mar 25 23:00:00 2007 +0300
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Mon Mar 26 00:00:00 2007 +0300
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Oct 27 23:00:00 2007 +0300
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Oct 28 00:00:00 2007 +0300
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Oct 28 01:00:00 2007 +0300
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Oct 28 02:00:00 2007 +0300
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Oct 28 03:00:00 2007 +0300
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Oct 28 03:00:00 2007 +0200
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Oct 28 04:00:00 2007 +0200
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sun Oct 28 23:00:00 2007 +0200
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Mon Oct 29 00:00:00 2007 +0200
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
state: created
|
||||
capabilities: CATENATE
|
||||
|
||||
"" delete ${mailbox}2
|
||||
|
||||
ok append $mailbox (\seen \flagged) catenate (text {{{
|
||||
From: [email protected]
|
||||
|
||||
Hello world body
|
||||
|
||||
}}})
|
||||
|
||||
ok append $mailbox (\seen \flagged) catenate (text {{{
|
||||
From: [email protected]
|
||||
|
||||
Lookslike: header
|
||||
|
||||
Another body
|
||||
|
||||
}}})
|
||||
|
||||
ok select $mailbox
|
||||
* ok [uidvalidity $uidv]
|
||||
|
||||
ok fetch 1:2 (uid body.peek[])
|
||||
* 1 fetch (uid $uid body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
Hello world body
|
||||
|
||||
}}})
|
||||
* 2 fetch (uid $uid2 body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
Lookslike: header
|
||||
|
||||
Another body
|
||||
|
||||
}}})
|
||||
|
||||
ok create ${mailbox}2
|
||||
|
||||
ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid/;section=header" text {{{
|
||||
body1
|
||||
|
||||
}}})
|
||||
|
||||
ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=$uidv/;uid=$uid/;section=header" text {{{
|
||||
body2
|
||||
|
||||
}}})
|
||||
|
||||
ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid2/;section=text" text {{{
|
||||
body3
|
||||
|
||||
}}})
|
||||
|
||||
ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid2/;section=1" text {{{
|
||||
body4
|
||||
|
||||
}}})
|
||||
|
||||
ok append ${mailbox}2 (\seen \flagged) catenate (text {{{
|
||||
From: [email protected]
|
||||
Subject: test header
|
||||
|
||||
|
||||
}}} url "/$mailbox_url/;uid=$uid/;section=1" text {{{
|
||||
|
||||
suffix
|
||||
|
||||
}}})
|
||||
|
||||
ok append ${mailbox}2 (\seen \flagged) catenate (text {{{
|
||||
From: [email protected]
|
||||
|
||||
}}} text {{{
|
||||
Subject: hdr2
|
||||
|
||||
}}} text {{{
|
||||
|
||||
body6
|
||||
|
||||
}}})
|
||||
|
||||
ok append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid2/;partial=100000.1" text {{{
|
||||
Hdr: foo
|
||||
|
||||
body7
|
||||
|
||||
}}})
|
||||
|
||||
#
|
||||
# Try invalid URLs
|
||||
#
|
||||
|
||||
no append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
|
||||
body
|
||||
|
||||
}}})
|
||||
|
||||
no append ${mailbox}2 (\seen \flagged) catenate (text {{{
|
||||
hdr: 1
|
||||
|
||||
}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header")
|
||||
|
||||
no append ${mailbox}2 (\seen \flagged) catenate (text {{{
|
||||
hdr: 1
|
||||
|
||||
}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
|
||||
hdr: 2
|
||||
|
||||
}}})
|
||||
|
||||
no append ${mailbox}2 (\seen \flagged) catenate (text {{{
|
||||
hdr: 1
|
||||
|
||||
}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
|
||||
hdr: 2
|
||||
|
||||
}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
|
||||
hdr: 3
|
||||
|
||||
}}})
|
||||
|
||||
no append ${mailbox}2 (\seen \flagged) catenate (text {{{
|
||||
hdr: 1
|
||||
|
||||
}}} url "/$mailbox_url/;uid=$uid/;section=header" text {{{
|
||||
hdr: 2
|
||||
|
||||
}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
|
||||
hdr: 3
|
||||
|
||||
}}})
|
||||
|
||||
no append ${mailbox}2 (\seen \flagged) catenate (text {{{
|
||||
hdr: 1
|
||||
|
||||
}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
|
||||
hdr: 2
|
||||
|
||||
}}} url "/$mailbox_url/;uid=$uid/;section=header" text {{{
|
||||
hdr: 3
|
||||
|
||||
}}})
|
||||
|
||||
no append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" url "/$mailbox_url/;uid=$uid/;section=header")
|
||||
no append ${mailbox}2 (\seen \flagged) catenate (url "/$mailbox_url/;uid=$uid/;section=header" url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header")
|
||||
|
||||
#
|
||||
# verify previous appends
|
||||
#
|
||||
ok select ${mailbox}2
|
||||
ok fetch 1:* body.peek[]
|
||||
* 1 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
body1
|
||||
|
||||
}}})
|
||||
* 2 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
body2
|
||||
|
||||
}}})
|
||||
* 3 fetch (body[] {{{
|
||||
Lookslike: header
|
||||
|
||||
Another body
|
||||
body3
|
||||
|
||||
}}})
|
||||
* 4 fetch (body[] {{{
|
||||
Lookslike: header
|
||||
|
||||
Another body
|
||||
body4
|
||||
|
||||
}}})
|
||||
* 5 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
Subject: test header
|
||||
|
||||
Hello world body
|
||||
|
||||
suffix
|
||||
|
||||
}}})
|
||||
* 6 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
Subject: hdr2
|
||||
|
||||
body6
|
||||
|
||||
}}})
|
||||
* 7 fetch (body[] {{{
|
||||
Hdr: foo
|
||||
|
||||
body7
|
||||
|
||||
}}})
|
||||
|
||||
|
||||
#
|
||||
# Try appending to nonexistent mailbox
|
||||
#
|
||||
|
||||
append ${mailbox}nonexistent catenate (url "/$mailbox_url/;uid=$uid/;section=1")
|
||||
no [trycreate]
|
||||
|
||||
append ${mailbox}nonexistent catenate (url "/$mailbox_url/;uid=$uid/;section=1" text {{{
|
||||
hello
|
||||
}}})
|
||||
no [trycreate]
|
||||
|
||||
append ${mailbox}nonexistent catenate (text {{{
|
||||
hello
|
||||
}}} url "/$mailbox_url/;uid=$uid/;section=1")
|
||||
no [trycreate]
|
||||
|
||||
append ${mailbox}nonexistent (\seen \flagged) catenate (text {{{
|
||||
hdr1: 1
|
||||
|
||||
}}} url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header" text {{{
|
||||
hdr2: 2
|
||||
|
||||
}}} url "/$mailbox_url/;uid=$uid/;section=header" text {{{
|
||||
hdr3: 3
|
||||
|
||||
}}})
|
||||
no [trycreate]
|
||||
|
||||
ok noop
|
||||
@@ -0,0 +1,130 @@
|
||||
state: created
|
||||
capabilities: CATENATE MULTIAPPEND
|
||||
|
||||
ok append $mailbox catenate (text {{{
|
||||
From: [email protected]
|
||||
|
||||
Hello world body
|
||||
|
||||
}}}) catenate (text {{{
|
||||
From: [email protected]
|
||||
|
||||
Second body
|
||||
|
||||
}}})
|
||||
|
||||
ok select $mailbox
|
||||
* ok [uidvalidity $uidv]
|
||||
|
||||
ok fetch 1:2 (uid body.peek[])
|
||||
* 1 fetch (uid $uid body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
Hello world body
|
||||
|
||||
}}})
|
||||
* 2 fetch (uid $uid2 body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
Second body
|
||||
|
||||
}}})
|
||||
|
||||
ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid/;section=header" text {{{
|
||||
body1
|
||||
|
||||
}}}) catenate (url "/$mailbox_url/;uid=$uid2/;section=header" text {{{
|
||||
body2
|
||||
|
||||
}}})
|
||||
|
||||
ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid") catenate (url "/$mailbox_url/;uid=$uid2/;section=header" text {{{
|
||||
body3
|
||||
|
||||
}}})
|
||||
|
||||
ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid") {{{
|
||||
New: Message
|
||||
|
||||
body4
|
||||
|
||||
}}}
|
||||
|
||||
ok append ${mailbox} catenate (url "/$mailbox_url/;uid=$uid") (\answered) {{{
|
||||
New: Message
|
||||
|
||||
body5
|
||||
|
||||
}}}
|
||||
|
||||
ok noop
|
||||
|
||||
ok fetch 3:* body.peek[]
|
||||
* 3 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
body1
|
||||
|
||||
}}})
|
||||
* 4 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
body2
|
||||
|
||||
}}})
|
||||
* 5 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
Hello world body
|
||||
|
||||
}}})
|
||||
* 6 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
body3
|
||||
|
||||
}}})
|
||||
* 7 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
Hello world body
|
||||
|
||||
}}})
|
||||
* 8 fetch (body[] {{{
|
||||
New: Message
|
||||
|
||||
body4
|
||||
|
||||
}}})
|
||||
* 9 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
|
||||
Hello world body
|
||||
|
||||
}}})
|
||||
* 10 fetch (body[] {{{
|
||||
New: Message
|
||||
|
||||
body5
|
||||
|
||||
}}})
|
||||
|
||||
#
|
||||
# Try invalid URLs
|
||||
#
|
||||
|
||||
no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") catenate (url "/$mailbox_url/;uid=$uid")
|
||||
|
||||
no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") catenate (url "/$mailbox_url/;uid=$uid" text {{{
|
||||
hello
|
||||
}}})
|
||||
|
||||
no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") catenate (text {{{
|
||||
hello
|
||||
}}})
|
||||
|
||||
no append ${mailbox} (\seen \flagged) catenate (url "/$mailbox_url;uidvalidity=12345/;uid=$uid/;section=header") {{{
|
||||
hello
|
||||
}}}
|
||||
|
||||
ok noop
|
||||
@@ -0,0 +1,9 @@
|
||||
connections: 2
|
||||
messages: 3
|
||||
|
||||
1 ok store 1,3 +flags \deleted
|
||||
1 ok close
|
||||
|
||||
2 ok noop
|
||||
* $1 expunge
|
||||
* $3 expunge
|
||||
@@ -0,0 +1,48 @@
|
||||
connections: 2
|
||||
state: created
|
||||
|
||||
1 ok select ${mailbox}
|
||||
1 ok append
|
||||
1 ok append
|
||||
1 ok append
|
||||
1 ok append
|
||||
1 ok append
|
||||
# make sure the server sees the appended messages
|
||||
1 ok check
|
||||
|
||||
2 "" delete ${mailbox}2
|
||||
2 ok create ${mailbox}2
|
||||
2 ok select ${mailbox}2
|
||||
|
||||
1 ok store 1 flags (\seen)
|
||||
1 ok store 2 flags (\answered \flagged)
|
||||
1 ok store 5 flags (\flagged $$keyword1 $$keyword2)
|
||||
|
||||
1 ok fetch 1:5 (internaldate)
|
||||
* 1 fetch (internaldate $date1)
|
||||
* 2 fetch (internaldate $date2)
|
||||
* 4 fetch (internaldate $date4)
|
||||
* 5 fetch (internaldate $date5)
|
||||
1 ok copy 1:2,4 ${mailbox}2
|
||||
|
||||
2 ok noop
|
||||
* 3 exists
|
||||
#* 3 recent
|
||||
|
||||
2 ok fetch 1:3 (flags internaldate)
|
||||
? 1 fetch (flags (\seen) internaldate $date1)
|
||||
? 2 fetch (flags (\answered \flagged) internaldate $date2)
|
||||
? 3 fetch (flags () internaldate $date4)
|
||||
|
||||
# keywords aren't required to be created on COPY, so help the server here
|
||||
2 ok store 3 +flags ($$keyword1 $$keyword2)
|
||||
|
||||
1 ok copy 5 ${mailbox}2
|
||||
2 ok noop
|
||||
* 4 exists
|
||||
|
||||
2 ok fetch 4 (flags internaldate)
|
||||
* 4 fetch (flags (\flagged $$keyword1 $$keyword2) internaldate $date5)
|
||||
|
||||
2 ok close
|
||||
2 "" delete ${mailbox}2
|
||||
@@ -0,0 +1,42 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s1
|
||||
|
||||
body1
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s22
|
||||
|
||||
body22
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s333
|
||||
|
||||
body33
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s4444
|
||||
|
||||
body4444
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s55555
|
||||
|
||||
body55555
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s666666
|
||||
|
||||
body666666
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
capabilities: ESEARCH
|
||||
messages: all
|
||||
|
||||
ok store 4 +flags \deleted
|
||||
ok expunge
|
||||
|
||||
# SEARCH ALL
|
||||
|
||||
ok search return (all) all
|
||||
* esearch (tag $tag) all 1:6
|
||||
ok search return () all
|
||||
* esearch (tag $tag) all 1:6
|
||||
ok search return (min) all
|
||||
* esearch (tag $tag) min 1
|
||||
ok search return (max) all
|
||||
* esearch (tag $tag) max 6
|
||||
ok search return (count) all
|
||||
* esearch (tag $tag) count 6
|
||||
|
||||
# UID SEARCH ALL
|
||||
|
||||
ok fetch 1:* UID
|
||||
* 1 fetch (uid $uid1)
|
||||
* 2 fetch (uid $uid2)
|
||||
* 3 fetch (uid $uid3)
|
||||
* 4 fetch (uid $uid4)
|
||||
* 5 fetch (uid $uid5)
|
||||
* 6 fetch (uid $uid6)
|
||||
|
||||
ok uid search return (all) all
|
||||
* esearch (tag $tag) uid all $uid1:$uid3,$uid4:$uid6
|
||||
ok uid search return () all
|
||||
* esearch (tag $tag) uid all $uid1:$uid3,$uid4:$uid6
|
||||
ok uid search return (min) all
|
||||
* esearch (tag $tag) uid min $uid1
|
||||
ok uid search return (max) all
|
||||
* esearch (tag $tag) uid max $uid6
|
||||
ok uid search return (count) all
|
||||
* esearch (tag $tag) uid count 6
|
||||
|
||||
# \Seen flag test
|
||||
|
||||
ok store 2,4 +flags \seen
|
||||
|
||||
ok uid search return (all) seen
|
||||
* esearch (tag $tag) uid all $uid2,$uid4
|
||||
ok uid search return () seen
|
||||
* esearch (tag $tag) uid all $uid2,$uid4
|
||||
ok uid search return (min) seen
|
||||
* esearch (tag $tag) uid min $uid2
|
||||
ok uid search return (max) seen
|
||||
* esearch (tag $tag) uid max $uid4
|
||||
ok uid search return (count) seen
|
||||
* esearch (tag $tag) uid count 2
|
||||
|
||||
# nonexistent
|
||||
|
||||
ok search return () 1000
|
||||
* esearch (tag $tag)
|
||||
ok search return (min) 1000
|
||||
* esearch (tag $tag)
|
||||
ok search return (max) 1000
|
||||
* esearch (tag $tag)
|
||||
ok search return (count) 1000
|
||||
* esearch (tag $tag) count 0
|
||||
|
||||
# UID nonexistent
|
||||
|
||||
ok uid search return () 1000
|
||||
* esearch (tag $tag) uid
|
||||
ok uid search return (min) 1000
|
||||
* esearch (tag $tag) uid
|
||||
ok uid search return (max) 1000
|
||||
* esearch (tag $tag) uid
|
||||
ok uid search return (count) 1000
|
||||
* esearch (tag $tag) uid count 0
|
||||
@@ -0,0 +1,38 @@
|
||||
capabilities: ESEARCH CONDSTORE
|
||||
messages: 4
|
||||
|
||||
# ENABLE is valid only in authenticated state. we could do enable+select
|
||||
# manually here also, but lets just make sure that switching it on via
|
||||
# condstore-enabling command works as well (since that is valid)
|
||||
ok fetch 1 modseq
|
||||
* ok [highestmodseq $highestmodseq]
|
||||
|
||||
ok store 1 +flags \seen
|
||||
* 1 fetch (modseq ($modseq1))
|
||||
ok store 3 +flags \seen
|
||||
* 3 fetch (modseq ($modseq3))
|
||||
ok store 2 +flags \seen
|
||||
* 2 fetch (modseq ($modseq2))
|
||||
ok store 4 +flags \seen
|
||||
* 4 fetch (modseq ($modseq4))
|
||||
|
||||
ok search return (min) 1:3 modseq "/flags/\\seen" all $highestmodseq
|
||||
* esearch (tag $tag) min 1 modseq $modseq4
|
||||
|
||||
ok search return (max) 1:3 modseq "/flags/\\seen" all $highestmodseq
|
||||
* esearch (tag $tag) max 3 modseq $modseq4
|
||||
|
||||
ok search return () 1:3 modseq "/flags/\\seen" all $highestmodseq
|
||||
* esearch (tag $tag) all 1:3 modseq $modseq4
|
||||
|
||||
ok search return (min max) 2:3 modseq "/flags/\\seen" all $highestmodseq
|
||||
* esearch (tag $tag) min 2 max 3 modseq $modseq4
|
||||
|
||||
ok search return (all) 2:4 modseq "/flags/\\seen" all $modseq3
|
||||
* esearch (tag $tag) all 2,4 modseq $modseq4
|
||||
|
||||
ok search return (all) 2:4 modseq "/flags/\\seen" all $modseq2
|
||||
* esearch (tag $tag) all 4 modseq $modseq4
|
||||
|
||||
ok search return (all) 2:4 modseq "/flags/\\seen" all $modseq4
|
||||
* esearch (tag $tag) modseq $modseq4
|
||||
@@ -0,0 +1,28 @@
|
||||
From user@domain Fri Feb 22 17:06:21 2008
|
||||
|
||||
1
|
||||
|
||||
From user@domain Fri Feb 22 17:06:22 2008
|
||||
|
||||
2
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
|
||||
3
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
|
||||
4
|
||||
|
||||
From user@domain Fri Feb 22 17:06:25 2008
|
||||
|
||||
5
|
||||
|
||||
From user@domain Fri Feb 22 17:06:25 2008
|
||||
|
||||
6
|
||||
|
||||
From user@domain Fri Feb 22 17:06:25 2008
|
||||
|
||||
7
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
capabilities: ESORT
|
||||
messages: 5
|
||||
|
||||
ok sort return (min) (arrival) us-ascii 1:5
|
||||
* esearch (tag $tag) min 1
|
||||
ok sort return (max) (arrival) us-ascii 1:5
|
||||
* esearch (tag $tag) max 5
|
||||
ok sort return (all) (arrival) us-ascii 1:5
|
||||
* esearch (tag $tag) all 1:5
|
||||
ok sort return (count) (arrival) us-ascii 1:5
|
||||
* esearch (tag $tag) count 5
|
||||
@@ -0,0 +1,62 @@
|
||||
connections: 2
|
||||
messages: 8
|
||||
|
||||
# get UIDs
|
||||
1 ok fetch 1:4 uid
|
||||
* 1 fetch (uid $uid1)
|
||||
* 2 fetch (uid $uid2)
|
||||
* 3 fetch (uid $uid3)
|
||||
* 4 fetch (uid $uid4)
|
||||
|
||||
# 1) test that expunges work ok and session 2 fetch sees 1's flag changes.
|
||||
1 ok store 1,3 flags \deleted
|
||||
* 1 fetch (flags (\deleted))
|
||||
* 3 fetch (flags (\deleted))
|
||||
1 ok store 2,4 flags \seen
|
||||
* 2 fetch (flags (\seen))
|
||||
* 4 fetch (flags (\seen))
|
||||
1 ok expunge
|
||||
* $1 expunge
|
||||
* $3 expunge
|
||||
|
||||
2 ok fetch 2,4 (uid)
|
||||
* 2 fetch (uid $uid2)
|
||||
* 4 fetch (uid $uid4)
|
||||
2 ok fetch 2,4 (uid)
|
||||
* 2 fetch (uid $uid2)
|
||||
* 4 fetch (uid $uid4)
|
||||
2 ok check
|
||||
* $1 expunge
|
||||
* $3 expunge
|
||||
2 ok fetch 1:2 (uid flags)
|
||||
* 1 fetch (uid $uid2 flags (\seen))
|
||||
* 2 fetch (uid $uid4 flags (\seen))
|
||||
|
||||
# 2) test that session 2 can update flags while some messages are expunged
|
||||
1 ok store 2 +flags \deleted
|
||||
1 ok expunge
|
||||
|
||||
2 ok store 1 flags \answered
|
||||
* 1 fetch (flags (\answered))
|
||||
1 ok check
|
||||
* 1 fetch (flags (\answered))
|
||||
2 ok noop
|
||||
* 2 expunge
|
||||
|
||||
# 3) check notices flag changes correctly with expunges
|
||||
1 ok store 1,3 +flags \deleted
|
||||
1 ok store 2,4 flags \flagged
|
||||
1 ok expunge
|
||||
2 ok check
|
||||
* $1 expunge
|
||||
* $2 fetch (flags (\flagged))
|
||||
* $3 expunge
|
||||
* $4 fetch (flags (\flagged))
|
||||
|
||||
# 4) expunging while message is already expunged
|
||||
1 ok store 1 +flags \deleted
|
||||
2 ok store 1 +flags \deleted
|
||||
1 ok expunge
|
||||
* 1 expunge
|
||||
2 ok expunge
|
||||
* 1 expunge
|
||||
@@ -0,0 +1,44 @@
|
||||
connections: 2
|
||||
messages: 6
|
||||
|
||||
1 ok fetch 2,4 uid
|
||||
* 2 fetch (uid $uid2)
|
||||
* 4 fetch (uid $uid4)
|
||||
|
||||
# UID FETCH
|
||||
1 ok store 1,3 +flags \deleted
|
||||
1 ok expunge
|
||||
* $1 expunge
|
||||
* $3 expunge
|
||||
|
||||
2 ok uid fetch $uid2,$uid4 uid
|
||||
* $2 fetch (uid $uid2)
|
||||
* $4 fetch (uid $uid4)
|
||||
2 ok noop
|
||||
|
||||
# UID STORE
|
||||
1 ok store 1 +flags \deleted
|
||||
1 ok expunge
|
||||
* 1 expunge
|
||||
|
||||
2 ok uid store $uid4 flags \seen
|
||||
* $2 fetch (uid $uid4 flags (\seen))
|
||||
2 ok noop
|
||||
|
||||
# Make sure CHECK works just as well as NOOP
|
||||
1 ok store 1 +flags \deleted
|
||||
1 ok expunge
|
||||
* 1 expunge
|
||||
2 ok check
|
||||
* 1 expunge
|
||||
|
||||
# Make sure FETCH, STORE and SEARCH don't trigger EXPUNGE
|
||||
1 ok store 1 +flags \deleted
|
||||
1 ok expunge
|
||||
|
||||
2 ok fetch 2 flags
|
||||
! $1 expunge
|
||||
2 ok store 2 flags (\seen)
|
||||
! $1 expunge
|
||||
2 ok search all
|
||||
! $1 expunge
|
||||
@@ -0,0 +1,54 @@
|
||||
messages: 3
|
||||
|
||||
ok status $mailbox (uidnext)
|
||||
* status $mailbox (uidnext $uidnext)
|
||||
|
||||
ok fetch 1:3 uid
|
||||
* 1 fetch (uid $uid1)
|
||||
* 2 fetch (uid $uid2)
|
||||
* 3 fetch (uid $uid3)
|
||||
|
||||
ok fetch 3:1 uid
|
||||
* 1 fetch (uid $uid1)
|
||||
* 2 fetch (uid $uid2)
|
||||
* 3 fetch (uid $uid3)
|
||||
|
||||
ok fetch 1,* uid
|
||||
* 1 fetch (uid $uid1)
|
||||
* 3 fetch (uid $uid3)
|
||||
|
||||
ok fetch * uid
|
||||
* 3 fetch (uid $uid3)
|
||||
|
||||
ok fetch *:1 uid
|
||||
* 1 fetch (uid $uid1)
|
||||
* 2 fetch (uid $uid2)
|
||||
* 3 fetch (uid $uid3)
|
||||
|
||||
ok uid fetch $uidnext:* uid
|
||||
* 3 fetch (uid $uid3)
|
||||
|
||||
# break seq=uid map
|
||||
ok store 2 flags \deleted
|
||||
ok expunge
|
||||
* 2 expunge
|
||||
|
||||
ok uid fetch $uidnext:* uid
|
||||
* 2 fetch (uid $uid3)
|
||||
ok uid fetch 1:* uid
|
||||
* 1 fetch (uid $uid1)
|
||||
* 2 fetch (uid $uid3)
|
||||
ok uid fetch $uid2 uid
|
||||
! 1 fetch (uid $uid1)
|
||||
! 2 fetch (uid $uid3)
|
||||
ok uid fetch $uid1,* uid
|
||||
* 1 fetch (uid $uid1)
|
||||
* 2 fetch (uid $uid3)
|
||||
|
||||
# test macros
|
||||
ok fetch 1 full
|
||||
* 1 fetch (flags () internaldate $intdate1 rfc822.size $size1 envelope ($!unordered) body ($!unordered))
|
||||
ok fetch 1 all
|
||||
* 1 fetch (flags () internaldate $intdate1 rfc822.size $size1 envelope ($!unordered))
|
||||
ok fetch 1 fast
|
||||
* 1 fetch (flags () internaldate $intdate1 rfc822.size $size1)
|
||||
@@ -0,0 +1,104 @@
|
||||
capabilities: BINARY
|
||||
messages: all
|
||||
|
||||
# This is the fetch-body-mime test, except with body[] changed to binary[].
|
||||
# The idea is to verify that binary[] works correctly when it doesn't actually
|
||||
# have to convert anything.
|
||||
|
||||
ok fetch 1 (binary.peek[])
|
||||
* 1 fetch (binary[] {{{
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="foo
|
||||
bar"
|
||||
|
||||
Root MIME prologue
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
|
||||
hello
|
||||
|
||||
--foo bar
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/alternative; boundary="sub1"
|
||||
|
||||
Sub MIME prologue
|
||||
--sub1
|
||||
Content-Type: text/html
|
||||
|
||||
<p>Hello world</p>
|
||||
|
||||
--sub1
|
||||
Content-Type: text/plain
|
||||
|
||||
Hello another world
|
||||
|
||||
--sub1--
|
||||
Sub MIME epilogue
|
||||
|
||||
--foo bar--
|
||||
Root MIME epilogue
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.size[])
|
||||
* 1 fetch (binary.size[] 602)
|
||||
|
||||
ok fetch 1 (binary.size[1])
|
||||
* 1 fetch (binary.size[1] 7)
|
||||
|
||||
ok fetch 1 (binary.peek[1])
|
||||
* 1 fetch (binary[1] {{{
|
||||
hello
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[2])
|
||||
* 1 fetch (binary[2] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/alternative; boundary="sub1"
|
||||
|
||||
Sub MIME prologue
|
||||
--sub1
|
||||
Content-Type: text/html
|
||||
|
||||
<p>Hello world</p>
|
||||
|
||||
--sub1
|
||||
Content-Type: text/plain
|
||||
|
||||
Hello another world
|
||||
|
||||
--sub1--
|
||||
Sub MIME epilogue
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.size[2])
|
||||
* 1 fetch (binary.size[2] 298)
|
||||
|
||||
ok fetch 1 (binary.size[2.1])
|
||||
* 1 fetch (binary.size[2.1] 20)
|
||||
|
||||
ok fetch 1 (binary.peek[2.1])
|
||||
* 1 fetch (binary[2.1] {{{
|
||||
<p>Hello world</p>
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[2.2])
|
||||
* 1 fetch (binary[2.2] {{{
|
||||
Hello another world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.size[2.2])
|
||||
* 1 fetch (binary.size[2.2] 21)
|
||||
@@ -0,0 +1,67 @@
|
||||
capabilities: BINARY
|
||||
messages: all
|
||||
|
||||
ok fetch 1 (binary.size[1] binary.size[5])
|
||||
* 1 fetch (binary.size[1] 11 binary.size[5] 30)
|
||||
|
||||
ok fetch 1 (binary.peek[1] binary.peek[2] binary.peek[3] binary.peek[4] binary.peek[5])
|
||||
* 1 fetch (binary[1] {{{
|
||||
hello world
|
||||
}}} binary[2] {{{
|
||||
hello world
|
||||
}}} binary[3] {{{
|
||||
hello to you too
|
||||
}}} binary[4] {{{
|
||||
hello to everyone!
|
||||
}}} binary[5] ~{{{
|
||||
abcdefg␍hijkl
|
||||
mno
|
||||
pqrstuvqxyz
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.size[1] binary.peek[1])
|
||||
* 1 fetch (binary.size[1] 11 binary[1] {{{
|
||||
hello world
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.size[3] binary.peek[2])
|
||||
* 1 fetch (binary.size[3] 16 binary[2] {{{
|
||||
hello world
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.size[2] binary.size[3] binary.size[4])
|
||||
* 1 fetch (binary.size[2] 11 binary.size[3] 16 binary.size[4] 18)
|
||||
|
||||
ok fetch 1 (binary.peek[5]<0.7>)
|
||||
* 1 fetch (binary[5]<0> ~{{{
|
||||
abcdefg
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[5]<0.8>)
|
||||
* 1 fetch (binary[5]<0> ~{{{
|
||||
abcdefg
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[5]<0.10>)
|
||||
* 1 fetch (binary[5]<0> ~{{{
|
||||
abcdefg␍hi
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[5]<10.10>)
|
||||
* 1 fetch (binary[5]<10> ~{{{
|
||||
jkl
|
||||
mno
|
||||
p
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[5]<5.10>)
|
||||
* 1 fetch (binary[5]<5> ~{{{
|
||||
fg␍hijkl
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[5]<15.100>)
|
||||
* 1 fetch (binary[5]<15> ~{{{
|
||||
mno
|
||||
pqrstuvqxyz
|
||||
}}})
|
||||
@@ -0,0 +1,49 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="foo
|
||||
bar"
|
||||
|
||||
Root MIME prologue
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
|
||||
aGVs
|
||||
bG8gd29y
|
||||
bGQ=
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
aGVs
|
||||
bG8g
|
||||
d29y
|
||||
bGQ=
|
||||
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
aGVsbG8g
|
||||
dG8geW91IHRv
|
||||
bw==
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
aGVsbG8gdG8gZXZlcnlvbmUh
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
YWJjZGVmZw1oaWprbA0KbW5vCnBxcnN0dXZxeHl6
|
||||
|
||||
--foo bar--
|
||||
Root MIME epilogue
|
||||
@@ -0,0 +1,54 @@
|
||||
capabilities: BINARY
|
||||
messages: all
|
||||
|
||||
ok fetch 1 (binary.size[1])
|
||||
* 1 fetch (binary.size[1] 65)
|
||||
|
||||
ok fetch 1 (binary.peek[1])
|
||||
* 1 fetch (binary[1] {{{
|
||||
hello
|
||||
bar
|
||||
foo bar
|
||||
foo b
|
||||
foo bar
|
||||
foo b
|
||||
foo
|
||||
bar
|
||||
foo_bar
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[1]<0.10>)
|
||||
* 1 fetch (binary[1]<0> {{{
|
||||
hello
|
||||
bar
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[1]<10.10>)
|
||||
* 1 fetch (binary[1]<10> ~{{{
|
||||
|
||||
foo bar
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[1]<20.10>)
|
||||
* 1 fetch (binary[1]<20> ~{{{
|
||||
|
||||
foo b
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[1]<15.10>)
|
||||
* 1 fetch (binary[1]<15> ~{{{
|
||||
bar
|
||||
foo
|
||||
}}})
|
||||
|
||||
ok fetch 1 (binary.peek[1]<40.100>)
|
||||
* 1 fetch (binary[1]<40> {{{
|
||||
oo b
|
||||
foo
|
||||
bar
|
||||
foo_bar
|
||||
|
||||
}}})
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="foo
|
||||
bar"
|
||||
|
||||
Root MIME prologue
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
hello
|
||||
bar=
|
||||
|
||||
foo =
|
||||
bar
|
||||
foo =
|
||||
=62
|
||||
foo =
|
||||
bar
|
||||
foo =
|
||||
=62
|
||||
foo
|
||||
bar=
|
||||
|
||||
foo_bar
|
||||
|
||||
--foo bar--
|
||||
Root MIME epilogue
|
||||
@@ -0,0 +1,38 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="foo
|
||||
bar"
|
||||
|
||||
Root MIME prologue
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
|
||||
hello
|
||||
|
||||
--foo bar
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/alternative; boundary="sub1"
|
||||
|
||||
Sub MIME prologue
|
||||
--sub1
|
||||
Content-Type: text/html
|
||||
|
||||
<p>Hello world</p>
|
||||
|
||||
--sub1
|
||||
Content-Type: text/plain
|
||||
|
||||
Hello another world
|
||||
|
||||
--sub1--
|
||||
Sub MIME epilogue
|
||||
|
||||
--foo bar--
|
||||
Root MIME epilogue
|
||||
@@ -0,0 +1,122 @@
|
||||
messages: all
|
||||
|
||||
# header and body fetches
|
||||
ok fetch 1 rfc822.header
|
||||
* 1 fetch (rfc822.header $hdr1)
|
||||
ok fetch 1 body.peek[header]
|
||||
* 1 fetch (body[header] $hdr1)
|
||||
|
||||
ok fetch 1 (flags body.peek[text])
|
||||
* 1 fetch (flags () body[text] {{{
|
||||
body1
|
||||
|
||||
|
||||
}}})
|
||||
ok fetch 1 rfc822.text
|
||||
* 1 fetch (rfc822.text {{{
|
||||
body1
|
||||
|
||||
|
||||
}}})
|
||||
* 1 fetch (flags (\seen))
|
||||
|
||||
ok fetch 2 (flags body.peek[])
|
||||
* 2 fetch (flags () body[] $full2)
|
||||
ok fetch 2 rfc822
|
||||
* 2 fetch (rfc822 $full2)
|
||||
* 2 fetch (flags (\seen))
|
||||
|
||||
ok fetch 3 (body[])
|
||||
* 3 fetch (body[] $full3)
|
||||
* 3 fetch (flags (\seen))
|
||||
ok fetch 4 (body[header])
|
||||
* 4 fetch (body[header] $hdr4)
|
||||
* 4 fetch (flags (\seen))
|
||||
|
||||
# partial fetches
|
||||
ok fetch 2 body.peek[text]<0.3>
|
||||
* 2 fetch (body[text]<0> "bod")
|
||||
ok fetch 2 body.peek[text]<3.3>
|
||||
* 2 fetch (body[text]<3> "y22")
|
||||
|
||||
ok fetch 3 body.peek[text]<0.1>
|
||||
* 3 fetch (body[text]<0> "b")
|
||||
ok fetch 3 body.peek[text]<5.1>
|
||||
* 3 fetch (body[text]<5> "3")
|
||||
ok fetch 3 body.peek[text]<5.2>
|
||||
* 3 fetch (body[text]<5> ~{{{
|
||||
3
|
||||
}}})
|
||||
ok fetch 3 body.peek[text]<5.3>
|
||||
* 3 fetch (body[text]<5> ~{{{
|
||||
3
|
||||
|
||||
}}})
|
||||
ok fetch 3 body.peek[text]<6.1>
|
||||
* 3 fetch (body[text]<6> ~{{{
|
||||
|
||||
}}})
|
||||
ok fetch 3 body.peek[text]<6.2>
|
||||
* 3 fetch (body[text]<6> ~{{{
|
||||
|
||||
|
||||
}}})
|
||||
ok fetch 3 body.peek[text]<7.1>
|
||||
* 3 fetch (body[text]<7> ~{{{
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
# header fields
|
||||
ok fetch 1 body.peek[header.fields (from)]
|
||||
* 1 fetch (body[header.fields (from)] {{{
|
||||
From: User1 <[email protected]>
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[header.fields (from)])
|
||||
* 1 fetch (body[header.fields (from)] {{{
|
||||
From: User1 <[email protected]>
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[header.fields (from from)])
|
||||
* 1 fetch (body[header.fields (from from)] {{{
|
||||
From: User1 <[email protected]>
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 body.peek[header.fields (from subject)]
|
||||
* 1 fetch (body[header.fields (from subject)] {{{
|
||||
From: User1 <[email protected]>
|
||||
Subject: s1
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 body.peek[header.fields.not (date)]
|
||||
! 1 fetch (body[header.fields.not (date)] {{{
|
||||
From: User1 <[email protected]>
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s1
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 body.peek[header.fields.not (date date)]
|
||||
! 1 fetch (body[header.fields.not (date date)] {{{
|
||||
From: User1 <[email protected]>
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s1
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 body.peek[header.fields (xyz)]
|
||||
* 1 fetch (body[header.fields (xyz)] {{{
|
||||
|
||||
|
||||
}}})
|
||||
@@ -0,0 +1,73 @@
|
||||
messages: all
|
||||
|
||||
ok fetch 1 (body.peek[])
|
||||
* 1 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[text])
|
||||
* 1 fetch (body[text] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1])
|
||||
* 1 fetch (body[1] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.1])
|
||||
* 1 fetch (body[1.1] {{{
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.header])
|
||||
* 1 fetch (body[1.header] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.header.fields (from subject X-foo)])
|
||||
* 1 fetch (body[1.header.fields (from subject X-foo)] {{{
|
||||
From: [email protected]
|
||||
Subject: submsg
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.header.fields.not (from subject X-foo)])
|
||||
* 1 fetch (body[1.header.fields.not (from subject X-foo)] {{{
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.text])
|
||||
* 1 fetch (body[1.text] {{{
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
messages: all
|
||||
|
||||
ok fetch 1 (body.peek[])
|
||||
* 1 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/digest; boundary="foo"
|
||||
|
||||
prologue
|
||||
|
||||
--foo
|
||||
|
||||
From: [email protected]
|
||||
Subject: m1
|
||||
|
||||
m1 body
|
||||
|
||||
--foo
|
||||
Content-Custom: m2 header
|
||||
|
||||
From: [email protected]
|
||||
Subject: m2
|
||||
|
||||
m2 body
|
||||
|
||||
--foo--
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[text])
|
||||
* 1 fetch (body[text] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/digest; boundary="foo"
|
||||
|
||||
prologue
|
||||
|
||||
--foo
|
||||
|
||||
From: [email protected]
|
||||
Subject: m1
|
||||
|
||||
m1 body
|
||||
|
||||
--foo
|
||||
Content-Custom: m2 header
|
||||
|
||||
From: [email protected]
|
||||
Subject: m2
|
||||
|
||||
m2 body
|
||||
|
||||
--foo--
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1])
|
||||
* 1 fetch (body[1] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/digest; boundary="foo"
|
||||
|
||||
prologue
|
||||
|
||||
--foo
|
||||
|
||||
From: [email protected]
|
||||
Subject: m1
|
||||
|
||||
m1 body
|
||||
|
||||
--foo
|
||||
Content-Custom: m2 header
|
||||
|
||||
From: [email protected]
|
||||
Subject: m2
|
||||
|
||||
m2 body
|
||||
|
||||
--foo--
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.header])
|
||||
* 1 fetch (body[1.header] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/digest; boundary="foo"
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.text])
|
||||
* 1 fetch (body[1.text] {{{
|
||||
prologue
|
||||
|
||||
--foo
|
||||
|
||||
From: [email protected]
|
||||
Subject: m1
|
||||
|
||||
m1 body
|
||||
|
||||
--foo
|
||||
Content-Custom: m2 header
|
||||
|
||||
From: [email protected]
|
||||
Subject: m2
|
||||
|
||||
m2 body
|
||||
|
||||
--foo--
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.1])
|
||||
* 1 fetch (body[1.1] {{{
|
||||
From: [email protected]
|
||||
Subject: m1
|
||||
|
||||
m1 body
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.1.MIME])
|
||||
* 1 fetch (body[1.1.MIME] {{{
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.1.HEADER])
|
||||
* 1 fetch (body[1.1.HEADER] {{{
|
||||
From: [email protected]
|
||||
Subject: m1
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.1.TEXT])
|
||||
* 1 fetch (body[1.1.TEXT] {{{
|
||||
m1 body
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.2])
|
||||
* 1 fetch (body[1.2] {{{
|
||||
From: [email protected]
|
||||
Subject: m2
|
||||
|
||||
m2 body
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.2.MIME])
|
||||
* 1 fetch (body[1.2.MIME] {{{
|
||||
Content-Custom: m2 header
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.2.HEADER])
|
||||
* 1 fetch (body[1.2.HEADER] {{{
|
||||
From: [email protected]
|
||||
Subject: m2
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.2.TEXT])
|
||||
* 1 fetch (body[1.2.TEXT] {{{
|
||||
m2 body
|
||||
|
||||
}}})
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/digest; boundary="foo"
|
||||
|
||||
prologue
|
||||
|
||||
--foo
|
||||
|
||||
From: [email protected]
|
||||
Subject: m1
|
||||
|
||||
m1 body
|
||||
|
||||
--foo
|
||||
Content-Custom: m2 header
|
||||
|
||||
From: [email protected]
|
||||
Subject: m2
|
||||
|
||||
m2 body
|
||||
|
||||
--foo--
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
messages: all
|
||||
|
||||
ok fetch 1 (body.peek[])
|
||||
* 1 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Fri, 23 Mar 2007 11:22:33 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[text])
|
||||
* 1 fetch (body[text] {{{
|
||||
From: [email protected]
|
||||
Date: Fri, 23 Mar 2007 11:22:33 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1])
|
||||
* 1 fetch (body[1] {{{
|
||||
From: [email protected]
|
||||
Date: Fri, 23 Mar 2007 11:22:33 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.1])
|
||||
* 1 fetch (body[1.1] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.header])
|
||||
* 1 fetch (body[1.header] {{{
|
||||
From: [email protected]
|
||||
Date: Fri, 23 Mar 2007 11:22:33 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.text])
|
||||
* 1 fetch (body[1.text] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.1.1])
|
||||
* 1 fetch (body[1.1.1] {{{
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.1.header])
|
||||
* 1 fetch (body[1.1.header] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.1.text])
|
||||
* 1 fetch (body[1.1.text] {{{
|
||||
Hello world
|
||||
|
||||
}}})
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Fri, 23 Mar 2007 11:22:33 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
@@ -0,0 +1,11 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
|
||||
Hello world
|
||||
@@ -0,0 +1,193 @@
|
||||
messages: all
|
||||
|
||||
ok fetch 1 (body.peek[])
|
||||
* 1 fetch (body[] {{{
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="foo
|
||||
bar"
|
||||
|
||||
Root MIME prologue
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
|
||||
hello
|
||||
|
||||
--foo bar
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/alternative; boundary="sub1"
|
||||
|
||||
Sub MIME prologue
|
||||
--sub1
|
||||
Content-Type: text/html
|
||||
|
||||
<p>Hello world</p>
|
||||
|
||||
--sub1
|
||||
Content-Type: text/plain
|
||||
|
||||
Hello another world
|
||||
|
||||
--sub1--
|
||||
Sub MIME epilogue
|
||||
|
||||
--foo bar--
|
||||
Root MIME epilogue
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[text])
|
||||
* 1 fetch (body[text] {{{
|
||||
Root MIME prologue
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
|
||||
hello
|
||||
|
||||
--foo bar
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/alternative; boundary="sub1"
|
||||
|
||||
Sub MIME prologue
|
||||
--sub1
|
||||
Content-Type: text/html
|
||||
|
||||
<p>Hello world</p>
|
||||
|
||||
--sub1
|
||||
Content-Type: text/plain
|
||||
|
||||
Hello another world
|
||||
|
||||
--sub1--
|
||||
Sub MIME epilogue
|
||||
|
||||
--foo bar--
|
||||
Root MIME epilogue
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1])
|
||||
* 1 fetch (body[1] {{{
|
||||
hello
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[1.mime])
|
||||
* 1 fetch (body[1.mime] {{{
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2])
|
||||
* 1 fetch (body[2] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/alternative; boundary="sub1"
|
||||
|
||||
Sub MIME prologue
|
||||
--sub1
|
||||
Content-Type: text/html
|
||||
|
||||
<p>Hello world</p>
|
||||
|
||||
--sub1
|
||||
Content-Type: text/plain
|
||||
|
||||
Hello another world
|
||||
|
||||
--sub1--
|
||||
Sub MIME epilogue
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2.mime])
|
||||
* 1 fetch (body[2.mime] {{{
|
||||
Content-Type: message/rfc822
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2.header])
|
||||
* 1 fetch (body[2.header] {{{
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/alternative; boundary="sub1"
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2.header.fields (from subject X-foo)])
|
||||
* 1 fetch (body[2.header.fields (from subject X-foo)] {{{
|
||||
From: [email protected]
|
||||
Subject: submsg
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2.header.fields.not (from subject X-foo)])
|
||||
* 1 fetch (body[2.header.fields.not (from subject X-foo)] {{{
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Content-Type: multipart/alternative; boundary="sub1"
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2.text])
|
||||
* 1 fetch (body[2.text] {{{
|
||||
Sub MIME prologue
|
||||
--sub1
|
||||
Content-Type: text/html
|
||||
|
||||
<p>Hello world</p>
|
||||
|
||||
--sub1
|
||||
Content-Type: text/plain
|
||||
|
||||
Hello another world
|
||||
|
||||
--sub1--
|
||||
Sub MIME epilogue
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2.1.mime])
|
||||
* 1 fetch (body[2.1.mime] {{{
|
||||
Content-Type: text/html
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2.1])
|
||||
* 1 fetch (body[2.1] {{{
|
||||
<p>Hello world</p>
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2.2.mime])
|
||||
* 1 fetch (body[2.2.mime] {{{
|
||||
Content-Type: text/plain
|
||||
|
||||
|
||||
}}})
|
||||
|
||||
ok fetch 1 (body.peek[2.2])
|
||||
* 1 fetch (body[2.2] {{{
|
||||
Hello another world
|
||||
|
||||
}}})
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="foo
|
||||
bar"
|
||||
|
||||
Root MIME prologue
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
|
||||
hello
|
||||
|
||||
--foo bar
|
||||
Content-Type: message/rfc822
|
||||
|
||||
From: [email protected]
|
||||
Date: Sun, 12 Aug 2012 12:34:56 +0300
|
||||
Subject: submsg
|
||||
Content-Type: multipart/alternative; boundary="sub1"
|
||||
|
||||
Sub MIME prologue
|
||||
--sub1
|
||||
Content-Type: text/html
|
||||
|
||||
<p>Hello world</p>
|
||||
|
||||
--sub1
|
||||
Content-Type: text/plain
|
||||
|
||||
Hello another world
|
||||
|
||||
--sub1--
|
||||
Sub MIME epilogue
|
||||
|
||||
--foo bar--
|
||||
Root MIME epilogue
|
||||
@@ -0,0 +1,28 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: User1 <[email protected]>
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s1
|
||||
|
||||
body1
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: User2 <[email protected]>
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s22
|
||||
|
||||
body22
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: User3 <[email protected]>
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s333
|
||||
|
||||
body33
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: User4 <[email protected]>
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: s4444
|
||||
|
||||
body4444
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
messages: all
|
||||
|
||||
ok fetch 1:* body
|
||||
* 1 FETCH (BODY (("TEXT" "x-MYOWN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 7 1) "MIXED"))
|
||||
@@ -0,0 +1,13 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Mime-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="foo
|
||||
bar"
|
||||
|
||||
--foo bar
|
||||
Content-Type: text/x-myown; charset=us-ascii
|
||||
|
||||
hello
|
||||
|
||||
--foo bar--
|
||||
@@ -0,0 +1,10 @@
|
||||
messages: all
|
||||
|
||||
# date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, message-id
|
||||
ok fetch 1:* envelope
|
||||
* 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")) "<[email protected]>" "<msg@id>"))
|
||||
* 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))
|
||||
* 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))
|
||||
* 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))
|
||||
* 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))
|
||||
* 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))
|
||||
@@ -0,0 +1,47 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Message-ID: <msg@id>
|
||||
In-Reply-To: <[email protected]>
|
||||
Date: Thu, 15 Feb 2007 01:02:03 +0200
|
||||
Subject: subject header
|
||||
From: From Real <[email protected]>
|
||||
To: To Real <[email protected]>
|
||||
Cc: Cc Real <[email protected]>
|
||||
Bcc: Bcc Real <[email protected]>
|
||||
Sender: Sender Real <[email protected]>
|
||||
Reply-To: ReplyTo Real <[email protected]>
|
||||
|
||||
body
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Thu, 15 Feb 2007 01:02:03 +0200
|
||||
From: user@domain
|
||||
|
||||
body
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Thu, 15 Feb 2007 01:02:03 +0200
|
||||
From: user@domain
|
||||
|
||||
body
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Thu, 15 Feb 2007 01:02:03 +0200
|
||||
From: user@domain (Real Name)
|
||||
To: group: [email protected], [email protected];, group2: [email protected];
|
||||
Cc: group:;, group2: (foo) ;
|
||||
|
||||
body
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Thu, 15 Feb 2007 01:02:03 +0200
|
||||
From: user@domain (Real Name)
|
||||
Sender:
|
||||
Reply-To:
|
||||
|
||||
body
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Thu, 15 Feb 2007 01:02:03 +0200
|
||||
From: <@route:user@domain>
|
||||
|
||||
body
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,79 @@
|
||||
connections: 3
|
||||
state: auth
|
||||
|
||||
# get the separator
|
||||
1 ok list "" ""
|
||||
* list () $sep $root
|
||||
# it should be \noselect, but don't fail everything if it doesn't exist
|
||||
* list (\noselect) $sep $root
|
||||
|
||||
1 ok create $mailbox${sep}
|
||||
1 ok create $mailbox${sep}test
|
||||
2 ok list "" $mailbox${sep}%
|
||||
* list () $sep $mailbox${sep}test
|
||||
|
||||
2 ok create $mailbox${sep}test2
|
||||
1 ok list "" $mailbox${sep}%
|
||||
* list () $sep $mailbox${sep}test
|
||||
* list () $sep $mailbox${sep}test2
|
||||
|
||||
3 ok create $mailbox${sep}test3${sep}
|
||||
2 ok create $mailbox${sep}test3${sep}test4${sep}
|
||||
2 ok create $mailbox${sep}test3${sep}test4${sep}test5
|
||||
2 ok list "" $mailbox${sep}%
|
||||
* list () $sep $mailbox${sep}test
|
||||
* list () $sep $mailbox${sep}test2
|
||||
* list () $sep $mailbox${sep}test3
|
||||
! list () $sep $mailbox${sep}test3${sep}test4
|
||||
! list () $sep $mailbox${sep}test3${sep}test4${sep}test5
|
||||
|
||||
3 ok list "" $mailbox${sep}%
|
||||
* list () $sep $mailbox${sep}test
|
||||
* list () $sep $mailbox${sep}test2
|
||||
* list () $sep $mailbox${sep}test3
|
||||
|
||||
2 ok list "" $mailbox${sep}%${sep}%
|
||||
! list () $sep $mailbox${sep}test
|
||||
! list () $sep $mailbox${sep}test2
|
||||
! list () $sep $mailbox${sep}test3
|
||||
* list () $sep $mailbox${sep}test3${sep}test4
|
||||
! list () $sep $mailbox${sep}test3${sep}test4${sep}test5
|
||||
|
||||
3 ok list "" $mailbox${sep}*
|
||||
* list () $sep $mailbox${sep}test
|
||||
* list () $sep $mailbox${sep}test2
|
||||
* list () $sep $mailbox${sep}test3
|
||||
* list () $sep $mailbox${sep}test3${sep}test4${sep}test5
|
||||
|
||||
3 ok list $mailbox${sep} *
|
||||
* list () $sep $mailbox${sep}test
|
||||
* list () $sep $mailbox${sep}test2
|
||||
* list () $sep $mailbox${sep}test3
|
||||
* list () $sep $mailbox${sep}test3${sep}test4${sep}test5
|
||||
|
||||
2 ok list "" $mailbox${sep}*test4
|
||||
! list () $sep $mailbox${sep}test
|
||||
! list () $sep $mailbox${sep}test2
|
||||
! list () $sep $mailbox${sep}test3
|
||||
* list () $sep $mailbox${sep}test3${sep}test4
|
||||
! list () $sep $mailbox${sep}test3${sep}test4${sep}test5
|
||||
|
||||
2 ok list "" $mailbox${sep}*test*
|
||||
* list () $sep $mailbox${sep}test
|
||||
* list () $sep $mailbox${sep}test2
|
||||
* list () $sep $mailbox${sep}test3
|
||||
* list () $sep $mailbox${sep}test3${sep}test4${sep}test5
|
||||
|
||||
2 ok list "" $mailbox${sep}%3${sep}%
|
||||
* list () $sep $mailbox${sep}test3${sep}test4
|
||||
2 ok list "" $mailbox${sep}%3${sep}%4
|
||||
* list () $sep $mailbox${sep}test3${sep}test4
|
||||
2 ok list "" $mailbox${sep}%t*4
|
||||
* list () $sep $mailbox${sep}test3${sep}test4
|
||||
|
||||
2 ok delete $mailbox${sep}test2
|
||||
1 ok list "" $mailbox${sep}*
|
||||
! list () $sep $mailbox${sep}test2
|
||||
|
||||
1 ok list "" INBOX
|
||||
* list () $inboxsep INBOX
|
||||
@@ -0,0 +1,95 @@
|
||||
state: auth
|
||||
capabilities: LIST-EXTENDED
|
||||
|
||||
# get the separator
|
||||
ok list "" ""
|
||||
* list () $sep ""
|
||||
|
||||
ok create $mailbox${sep}
|
||||
ok create $mailbox${sep}test1
|
||||
ok create $mailbox${sep}test2${sep}
|
||||
ok create $mailbox${sep}test2${sep}test1
|
||||
ok create $mailbox${sep}test3
|
||||
ok create $mailbox${sep}test4${sep}test5
|
||||
ok create $mailbox${sep}test4${sep}test52
|
||||
ok create $mailbox${sep}test6
|
||||
ok create $mailbox${sep}test7${sep}test7
|
||||
ok create $mailbox${sep}test8${sep}test8
|
||||
ok create $mailbox${sep}test8${sep}test9
|
||||
|
||||
ok subscribe $mailbox${sep}test1
|
||||
ok subscribe $mailbox${sep}test2${sep}test1
|
||||
ok subscribe $mailbox${sep}test6
|
||||
ok subscribe $mailbox${sep}test7${sep}test7
|
||||
ok subscribe $mailbox${sep}test8${sep}test8
|
||||
ok subscribe $mailbox${sep}test8${sep}test9
|
||||
|
||||
ok delete $mailbox${sep}test6
|
||||
|
||||
# "" isn't a special case with LIST-EXTENDED
|
||||
#ok list () "" ""
|
||||
#! list () $sep ""
|
||||
#ok list "" ("")
|
||||
#! list () $sep ""
|
||||
#ok list "" "" return ()
|
||||
#! list () $sep ""
|
||||
|
||||
# test multiple patterns
|
||||
ok list "" ($mailbox${sep}*2 $mailbox${sep}test3)
|
||||
! list () $sep $mailbox${sep}test1
|
||||
* list () $sep $mailbox${sep}test2
|
||||
! list () $sep $mailbox${sep}test2${sep}test1
|
||||
* list () $sep $mailbox${sep}test3
|
||||
! list () $sep $mailbox${sep}test4
|
||||
! list () $sep $mailbox${sep}test4${sep}test5
|
||||
* list () $sep $mailbox${sep}test4${sep}test52
|
||||
! list () $sep $mailbox${sep}test6
|
||||
|
||||
# test errors
|
||||
bad list (imaptest) "" ""
|
||||
bad list (recursivematch) "" ""
|
||||
bad list (recursivematch remote) "" ""
|
||||
bad list "" "" return (imaptest)
|
||||
|
||||
ok list (remote) "" %
|
||||
|
||||
ok list (subscribed) "" $mailbox${sep}*
|
||||
* list (\subscribed) $sep $mailbox${sep}test1
|
||||
* list (\subscribed) $sep $mailbox${sep}test2${sep}test1
|
||||
#* list ($!unordered $!ban=\noselect \subscribed \nonexistent) $sep $mailbox${sep}test6
|
||||
* list (\subscribed) $sep $mailbox${sep}test7${sep}test7
|
||||
* list (\subscribed) $sep $mailbox${sep}test8${sep}test9
|
||||
|
||||
ok list (subscribed recursivematch) "" $mailbox${sep}test2% return (children)
|
||||
* list (\haschildren) $sep $mailbox${sep}test2 (childinfo (subscribed))
|
||||
! list (\subscribed) $sep $mailbox${sep}test2
|
||||
! list (\subscribed) $sep $mailbox${sep}test2${sep}test1
|
||||
|
||||
# don't test for \hasnochildren, because it may be \noinferiors instead
|
||||
ok list "" $mailbox${sep}% return (children subscribed)
|
||||
* list ($!unordered $!ban=\haschildren \subscribed) $sep $mailbox${sep}test1
|
||||
* list ($!unordered $!ban=\subscribed \haschildren) $sep $mailbox${sep}test2
|
||||
* list ($!unordered $!ban=\subscribed $!ban=\haschildren) $sep $mailbox${sep}test3
|
||||
* list ($!unordered $!ban=\subscribed \haschildren) $sep $mailbox${sep}test4
|
||||
* list ($!unordered $!ban=\subscribed \haschildren) $sep $mailbox${sep}test7
|
||||
* list ($!unordered $!ban=\subscribed \haschildren) $sep $mailbox${sep}test8
|
||||
|
||||
ok list (subscribed recursivematch) "" $mailbox*test7
|
||||
! list () $sep $mailbox${sep}test7
|
||||
* list (\subscribed) $sep $mailbox${sep}test7${sep}test7
|
||||
|
||||
ok list (subscribed recursivematch) "" $mailbox*test8
|
||||
* list ($!unordered $!ban=\subscribed) $sep $mailbox${sep}test8 (childinfo ("subscribed"))
|
||||
* list (\subscribed) $sep $mailbox${sep}test8${sep}test8
|
||||
|
||||
ok list (subscribed recursivematch) "" ($mailbox${sep}test2)
|
||||
* list () $sep $mailbox${sep}test2 (childinfo ("subscribed"))
|
||||
! list () $sep $mailbox${sep}test2${sep}test1
|
||||
|
||||
ok list (subscribed recursivematch) "" ($mailbox${sep}test2 $mailbox${sep}test2${sep}test1)
|
||||
* list () $sep $mailbox${sep}test2 (childinfo ("subscribed"))
|
||||
* list (\subscribed) $sep $mailbox${sep}test2${sep}test1
|
||||
|
||||
ok list "" ($mailbox${sep}test7 $mailbox${sep}test7${sep}test7)
|
||||
#This isn't really an error, although it's non-optimal: ! list (\nonexistent) $sep $mailbox${sep}test7
|
||||
* list () $sep $mailbox${sep}test7${sep}test7
|
||||
@@ -0,0 +1,14 @@
|
||||
state: nonauth
|
||||
connections: 2
|
||||
|
||||
1 ok noop
|
||||
! bye
|
||||
2 ok noop
|
||||
! bye
|
||||
|
||||
1 ok logout
|
||||
* bye
|
||||
|
||||
2 ok noop
|
||||
2 ok logout
|
||||
* bye
|
||||
@@ -0,0 +1,47 @@
|
||||
capabilities: MOVE
|
||||
state: created
|
||||
|
||||
# - assumes COPYUID is sent untagged before expunges.
|
||||
# - assumes MOVE to mailbox itself changes message UID
|
||||
|
||||
ok append
|
||||
ok append
|
||||
ok append
|
||||
ok create ${mailbox}2
|
||||
|
||||
ok select ${mailbox}2
|
||||
* 0 exists
|
||||
* ok [uidvalidity $uidvalidity_dest]
|
||||
* ok [uidnext $uidnext_dest1]
|
||||
|
||||
# MOVE:
|
||||
ok select $mailbox
|
||||
|
||||
ok fetch 1:* uid
|
||||
* 1 fetch (uid $uid1)
|
||||
* 2 fetch (uid $uid2)
|
||||
* 3 fetch (uid $uid3)
|
||||
|
||||
ok move 1 ${mailbox}2
|
||||
* ok [copyuid $uidvalidity_dest $uid1 $uidnext_dest1]
|
||||
* 1 expunge
|
||||
|
||||
# UID MOVE:
|
||||
ok select ${mailbox}2
|
||||
* 1 exists
|
||||
* ok [uidvalidity $uidvalidity_dest]
|
||||
* ok [uidnext $uidnext_dest2]
|
||||
|
||||
ok select $mailbox
|
||||
* ok [uidvalidity $uidvalidity]
|
||||
* ok [uidnext $uidnext1]
|
||||
|
||||
ok uid move $uid2 ${mailbox}2
|
||||
* ok [copyuid $uidvalidity_dest $uid2 $uidnext_dest2]
|
||||
* 1 expunge
|
||||
|
||||
# MOVE to same mailbox:
|
||||
#ok move 1 $mailbox
|
||||
#* ok [copyuid $uidvalidity $uid3 $uidnext1]
|
||||
#* 1 expunge
|
||||
#* 1 exists
|
||||
@@ -0,0 +1,30 @@
|
||||
capabilities: MULTIAPPEND
|
||||
state: created
|
||||
|
||||
ok append $mailbox {{{
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: mail1
|
||||
|
||||
body1
|
||||
}}} {{{
|
||||
From: [email protected]
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: mail2
|
||||
|
||||
body2
|
||||
}}}
|
||||
|
||||
ok select $mailbox
|
||||
|
||||
ok fetch 1:* body.peek[header.fields (subject)]
|
||||
* 1 fetch (body[header.fields (subject)] {{{
|
||||
Subject: mail1
|
||||
|
||||
|
||||
}}})
|
||||
* 2 fetch (body[header.fields (subject)] {{{
|
||||
Subject: mail2
|
||||
|
||||
|
||||
}}})
|
||||
@@ -0,0 +1,12 @@
|
||||
state: auth
|
||||
|
||||
# get the separator
|
||||
ok list "" ""
|
||||
* list () $sep $root
|
||||
|
||||
ok create "$mailbox${sep}p&AOQA5A-"
|
||||
ok list "" "$mailbox${sep}p&AOQA5A-"
|
||||
* list () $sep "$mailbox${sep}p&AOQA5A-"
|
||||
|
||||
ok status "$mailbox${sep}p&AOQA5A-" (messages)
|
||||
* status "$mailbox${sep}p&AOQA5A-" (messages 0)
|
||||
@@ -0,0 +1,13 @@
|
||||
messages: 1
|
||||
|
||||
ok search subject NIL
|
||||
* search 1
|
||||
|
||||
ok search body nil
|
||||
* search 1
|
||||
|
||||
ok list "" NIL
|
||||
|
||||
ok store 1 +flags NIL
|
||||
ok fetch 1 flags
|
||||
* 1 fetch (flags (NIL))
|
||||
@@ -0,0 +1,5 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: NiL
|
||||
|
||||
nil
|
||||
@@ -0,0 +1,20 @@
|
||||
capabilities: notify qresync
|
||||
|
||||
ok create ${mailbox}2
|
||||
ok append ${mailbox}2
|
||||
|
||||
#
|
||||
# Check that initial STATUS notifications are sent when needed
|
||||
#
|
||||
|
||||
ok notify set status (mailboxes ${mailbox}2 (MessageExpunge))
|
||||
* status ${mailbox}2 (messages 1)
|
||||
|
||||
ok notify set status (mailboxes ${mailbox}2 (MessageNew))
|
||||
* status ${mailbox}2 (messages 1 uidnext $uidnext uidvalidity $uidvalidity)
|
||||
|
||||
ok notify set status (mailboxes ${mailbox}2 (FlagChange))
|
||||
* status ${mailbox}2 (uidvalidity $uidvalidity highestmodseq $hmodseq)
|
||||
|
||||
ok notify set (mailboxes ${mailbox}2 (MessageNew MessageExpunge FlagChange))
|
||||
! status ${mailbox}2 ()
|
||||
@@ -0,0 +1,23 @@
|
||||
state: auth
|
||||
|
||||
tag1 create ${mailbox}
|
||||
tag2 create ${mailbox}2
|
||||
tag3 create ${mailbox}3
|
||||
tag4 create ${mailbox}4
|
||||
tag1 ok
|
||||
tag2 ok
|
||||
tag3 ok
|
||||
tag4 ok
|
||||
|
||||
tag1 status ${mailbox} (messages)
|
||||
tag2 status ${mailbox}2 (messages)
|
||||
tag3 status ${mailbox}3 (messages)
|
||||
tag4 status ${mailbox}4 (messages)
|
||||
* status ${mailbox} (messages 0)
|
||||
* status ${mailbox}2 (messages 0)
|
||||
* status ${mailbox}3 (messages 0)
|
||||
* status ${mailbox}4 (messages 0)
|
||||
tag1 ok
|
||||
tag2 ok
|
||||
tag3 ok
|
||||
tag4 ok
|
||||
@@ -0,0 +1,71 @@
|
||||
messages: all
|
||||
|
||||
# full address searching
|
||||
ok search from [email protected]
|
||||
* search 1 2 3 4 6 7
|
||||
ok search to [email protected]
|
||||
* search 1 2 3 4
|
||||
ok search cc [email protected]
|
||||
* search 1 2 3 4 5
|
||||
ok search bcc [email protected]
|
||||
* search 1 2 3 4
|
||||
|
||||
# realname searching
|
||||
ok search from realfrom
|
||||
* search 2 4 6 7
|
||||
ok search to realto
|
||||
* search 2 4
|
||||
ok search cc realcc
|
||||
* search 2 4
|
||||
ok search bcc realbcc
|
||||
* search 2 4
|
||||
|
||||
# existence searches
|
||||
ok search header from ""
|
||||
* search 1 2 3 4 5 6 7
|
||||
ok search header to ""
|
||||
* search 1 2 3 4 6 7
|
||||
ok search header cc ""
|
||||
* search 1 2 3 4 5
|
||||
ok search header bcc ""
|
||||
* search 1 2 3 4
|
||||
|
||||
# substring address searches
|
||||
#ok search from ser-fro
|
||||
#* search 1 2 3 4 5 6 7
|
||||
#ok search to ser-t
|
||||
#* search 1 2 3 4
|
||||
#ok search cc ser-c
|
||||
#* search 1 2 3 4 5
|
||||
#ok search bcc ser-bc
|
||||
#* search 1 2 3 4
|
||||
|
||||
# substring realname searches
|
||||
#ok search from ealfro
|
||||
#* search 2 4 6 7
|
||||
#ok search to ealt
|
||||
#* search 2 4
|
||||
#ok search cc ealc
|
||||
#* search 2 4
|
||||
#ok search bcc ealbc
|
||||
#* search 2 4
|
||||
|
||||
# multiple addresses
|
||||
ok search from user-from1
|
||||
* search 5
|
||||
ok search from user-from2
|
||||
* search 5
|
||||
|
||||
# groups
|
||||
ok search to groupname
|
||||
* search 6 7
|
||||
ok search to groupname2
|
||||
* search 6
|
||||
ok search to groupuser1
|
||||
* search 6
|
||||
ok search to groupuser2
|
||||
* search 6
|
||||
ok search to groupuser3
|
||||
* search 6
|
||||
ok search to groupuser4
|
||||
* search
|
||||
@@ -0,0 +1,50 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected]
|
||||
To: [email protected]
|
||||
Cc: [email protected]
|
||||
Bcc: [email protected]
|
||||
|
||||
body
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: RealFrom <[email protected]>
|
||||
To: RealTo <[email protected]>
|
||||
Cc: RealCc <[email protected]>
|
||||
Bcc: RealBcc <[email protected]>
|
||||
|
||||
body2
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: <user-from (comment)@ (comment) domain.org>
|
||||
To: <[email protected]>
|
||||
Cc: <[email protected]>
|
||||
Bcc: <[email protected]>
|
||||
|
||||
body3
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected] (RealFrom)
|
||||
To: [email protected] (RealTo)
|
||||
Cc: [email protected] (RealCc)
|
||||
Bcc: [email protected] (RealBcc)
|
||||
|
||||
body4
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: [email protected], [email protected]
|
||||
Cc: [email protected]
|
||||
|
||||
body5
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: RealFrom <[email protected]>
|
||||
To: groupname: [email protected], [email protected];,
|
||||
groupname2: [email protected];
|
||||
|
||||
body6
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
From: RealFrom <[email protected]>
|
||||
To: groupname:;
|
||||
|
||||
body7
|
||||
@@ -0,0 +1,31 @@
|
||||
messages: all
|
||||
|
||||
# search full words first
|
||||
ok search text asdfghjkl
|
||||
* search 1 2
|
||||
ok search text zxcvbnm
|
||||
* search 1 3 4
|
||||
ok search text qwertyuiop
|
||||
* search 2 4
|
||||
|
||||
ok search body asdfghjkl
|
||||
* search 1 2
|
||||
ok search body zxcvbnm
|
||||
* search 1 3 4
|
||||
ok search body qwertyuiop
|
||||
* search 4
|
||||
|
||||
# search substrings
|
||||
#ok search text sdfghjk
|
||||
#* search 1 2
|
||||
#ok search text xcvbn
|
||||
#* search 1 3 4
|
||||
#ok search text wertyuio
|
||||
#* search 2 3 4
|
||||
|
||||
#ok search body sdfghjk
|
||||
#* search 1 2
|
||||
#ok search body xcvbn
|
||||
#* search 1 3 4
|
||||
#ok search body wertyuio
|
||||
#* search 4
|
||||
@@ -0,0 +1,21 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
asdfghjkl zxcvbnm
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
Subject: qwertyuiop
|
||||
|
||||
asdfghjkl
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
X-Header: qwertyuiop
|
||||
|
||||
zxcvbnm
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
zxcvbnm qwertyuiop
|
||||
@@ -0,0 +1,35 @@
|
||||
capabilities: CONTEXT=SEARCH
|
||||
state: created
|
||||
|
||||
ok append
|
||||
ok append
|
||||
ok append
|
||||
ok append
|
||||
ok append
|
||||
|
||||
ok select $mailbox
|
||||
|
||||
ok search return (update) body body seen
|
||||
* esearch (tag $searchtag)
|
||||
|
||||
ok store 1,2,4 +flags \seen
|
||||
* esearch (tag $searchtag) addto ($pos 1:2,4)
|
||||
|
||||
ok store 1,2 -flags \seen
|
||||
* esearch (tag $searchtag) removefrom ($pos2 1:2)
|
||||
|
||||
ok store 3:5 +flags \deleted
|
||||
ok expunge
|
||||
* esearch (tag $searchtag) removefrom ($pos3 $4)
|
||||
* $3 expunge
|
||||
* $4 expunge
|
||||
* $5 expunge
|
||||
|
||||
ok append $mailbox (\seen)
|
||||
* 3 exists
|
||||
* esearch (tag $searchtag) addto ($pos4 3)
|
||||
|
||||
ok cancelupdate "$searchtag"
|
||||
|
||||
ok store 1 +flags \seen
|
||||
! esearch (tag $searchtag) addto ($pos5 1)
|
||||
@@ -0,0 +1,21 @@
|
||||
capabilities: CONTEXT=SEARCH
|
||||
messages: 5
|
||||
|
||||
ok store 1,2 +flags \seen
|
||||
|
||||
ok search return (update all) or seen subject s22
|
||||
* esearch (tag $searchtag) all 1:2
|
||||
|
||||
ok store 3:5 +flags \seen
|
||||
* esearch (tag $searchtag) addto ($pos 3:5)
|
||||
|
||||
ok store 1:5 -flags \seen
|
||||
* esearch (tag $searchtag) removefrom ($pos2 1,3:5)
|
||||
|
||||
ok store 3,4 +flags \seen
|
||||
* esearch (tag $searchtag) addto ($pos3 3:4)
|
||||
|
||||
ok store 3 +flags \deleted
|
||||
ok expunge
|
||||
* 3 expunge
|
||||
* esearch (tag $searchtag) removefrom ($pos4 3)
|
||||
@@ -0,0 +1,31 @@
|
||||
capabilities: CONTEXT=SEARCH
|
||||
messages: 6
|
||||
|
||||
ok store 1 +flags \deleted
|
||||
ok expunge
|
||||
|
||||
ok fetch 1:5 uid
|
||||
* 1 fetch (uid $uid1)
|
||||
* 2 fetch (uid $uid2)
|
||||
* 3 fetch (uid $uid3)
|
||||
* 4 fetch (uid $uid4)
|
||||
* 5 fetch (uid $uid5)
|
||||
|
||||
ok store 1,2 +flags \seen
|
||||
|
||||
ok uid search return (update all) or seen subject s33
|
||||
* esearch (tag $searchtag) uid all $uid1:$uid2
|
||||
|
||||
ok store 3:5 +flags \seen
|
||||
* esearch (tag $searchtag) uid addto ($pos $uid3:$uid5)
|
||||
|
||||
ok store 1:5 -flags \seen
|
||||
* esearch (tag $searchtag) uid removefrom ($pos2 $uid1,$uid3:$uid5)
|
||||
|
||||
ok uid store $uid3,$uid4 +flags \seen
|
||||
* esearch (tag $searchtag) uid addto ($pos3 $uid3:$uid4)
|
||||
|
||||
ok store 3 +flags \deleted
|
||||
ok expunge
|
||||
* 3 expunge
|
||||
* esearch (tag $searchtag) uid removefrom ($pos4 $uid3)
|
||||
@@ -0,0 +1,71 @@
|
||||
messages: all
|
||||
|
||||
# 1) Timezone changes from EET +0200 -> EEST +0300
|
||||
# 1a) SENTBEFORE
|
||||
ok search sentbefore 24-mar-2007
|
||||
* search
|
||||
ok search sentbefore 25-mar-2007
|
||||
* search 1
|
||||
ok search sentbefore 27-mar-2007
|
||||
* search 1 2 3 4 5 6 7
|
||||
|
||||
# 1b) SENTON
|
||||
ok search senton 23-mar-2007
|
||||
* search
|
||||
ok search senton 24-mar-2007
|
||||
* search 1
|
||||
ok search senton 25-mar-2007
|
||||
* search 2 3 4 5 6
|
||||
ok search senton 26-mar-2007
|
||||
* search 7
|
||||
|
||||
# 1c) SENTSINCE
|
||||
ok search 1:7 sentsince 24-mar-2007
|
||||
* search 1 2 3 4 5 6 7
|
||||
ok search 1:7 sentsince 25-mar-2007
|
||||
* search 2 3 4 5 6 7
|
||||
ok search 1:7 sentsince 26-mar-2007
|
||||
* search 7
|
||||
ok search 1:7 sentsince 27-mar-2007
|
||||
* search
|
||||
|
||||
# 2) Timezone changes from EEST +0300 -> EET +0200
|
||||
# 2a) SENTBEFORE
|
||||
ok search 8:* sentbefore 27-oct-2007
|
||||
* search
|
||||
ok search 8:* sentbefore 28-oct-2007
|
||||
* search 8
|
||||
ok search 8:* sentbefore 29-oct-2007
|
||||
* search 8 9 10 11 12 13 14 15
|
||||
ok search 8:* sentbefore 30-oct-2007
|
||||
* search 8 9 10 11 12 13 14 15 16
|
||||
|
||||
# 2b) SENTON
|
||||
ok search 8:* senton 26-oct-2007
|
||||
* search
|
||||
ok search 8:* senton 27-oct-2007
|
||||
* search 8
|
||||
ok search 8:* senton 28-oct-2007
|
||||
* search 9 10 11 12 13 14 15
|
||||
ok search 8:* senton 29-oct-2007
|
||||
* search 16
|
||||
|
||||
# 2c) SENTSINCE
|
||||
ok search 8:* sentsince 27-oct-2007
|
||||
* search 8 9 10 11 12 13 14 15 16
|
||||
ok search 8:* sentsince 28-oct-2007
|
||||
* search 9 10 11 12 13 14 15 16
|
||||
ok search 8:* sentsince 29-oct-2007
|
||||
* search 16
|
||||
ok search 8:* sentsince 30-oct-2007
|
||||
* search
|
||||
|
||||
# 3) Try a couple of NOTs
|
||||
ok search 1:7 not sentbefore 26-mar-2007
|
||||
* search 7
|
||||
ok search 1:7 not senton 25-mar-2007
|
||||
* search 1 7
|
||||
ok search 8:* not sentsince 28-oct-2007
|
||||
* search 8
|
||||
ok search 8:* not senton 28-oct-2007
|
||||
* search 8 16
|
||||
@@ -0,0 +1,80 @@
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 25 Mar 2007 00:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 25 Mar 2007 01:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 25 Mar 2007 02:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 25 Mar 2007 04:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 25 Mar 2007 23:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Mon, 26 Mar 2007 00:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sat, 27 Oct 2007 03:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 28 Oct 2007 00:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 28 Oct 2007 01:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 28 Oct 2007 02:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 28 Oct 2007 03:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 28 Oct 2007 03:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 28 Oct 2007 04:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Sun, 28 Oct 2007 23:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
From user@domain Sat Mar 24 23:00:00 2007 +0000
|
||||
Date: Mon, 29 Oct 2007 00:00:00 +0000
|
||||
|
||||
body
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
messages: 5
|
||||
|
||||
ok store 1 flags ($$hello)
|
||||
ok store 2 flags (\seen \flagged)
|
||||
ok store 3 flags (\answered $$hello)
|
||||
ok store 4 flags (\flagged \draft)
|
||||
ok store 5 flags (\deleted \answered)
|
||||
|
||||
ok search answered
|
||||
* search 3 5
|
||||
ok search unanswered
|
||||
* search 1 2 4
|
||||
|
||||
ok search deleted
|
||||
* search 5
|
||||
ok search undeleted
|
||||
* search 1 2 3 4
|
||||
|
||||
ok search draft
|
||||
* search 4
|
||||
ok search undraft
|
||||
* search 1 2 3 5
|
||||
|
||||
ok search flagged
|
||||
* search 2 4
|
||||
ok search unflagged
|
||||
* search 1 3 5
|
||||
|
||||
ok search seen
|
||||
* search 2
|
||||
ok search unseen
|
||||
* search 1 3 4 5
|
||||
|
||||
ok search keyword $$hello
|
||||
* search 1 3
|
||||
ok search unkeyword $$hello
|
||||
* search 2 4 5
|
||||
|
||||
#ok search new
|
||||
#* search 1 3 4 5
|
||||
|
||||
#ok search old
|
||||
#* search
|
||||
|
||||
#ok search recent
|
||||
#* search 1 2 3 4 5
|
||||
|
||||
ok store 1:* flags (\seen)
|
||||
ok store 2 +flags (\flagged)
|
||||
ok search seen flagged
|
||||
* search 2
|
||||
ok search seen not flagged
|
||||
* search 1 3 4 5
|
||||
ok search not seen flagged
|
||||
* search
|
||||
ok search not seen not flagged
|
||||
* search
|
||||
|
||||
ok store 1:* flags (\deleted)
|
||||
ok store 2 +flags (\flagged)
|
||||
ok search deleted flagged
|
||||
* search 2
|
||||
ok search deleted not flagged
|
||||
* search 1 3 4 5
|
||||
ok search not deleted flagged
|
||||
* search
|
||||
ok search not deleted not flagged
|
||||
* search
|
||||
|
||||
ok store 1:* flags (\seen \deleted)
|
||||
ok store 2 +flags (\flagged)
|
||||
ok search seen flagged
|
||||
* search 2
|
||||
ok search seen not flagged
|
||||
* search 1 3 4 5
|
||||
ok search not seen flagged
|
||||
* search
|
||||
ok search not seen not flagged
|
||||
* search
|
||||
ok search seen deleted flagged
|
||||
* search 2
|
||||
ok search seen deleted not flagged
|
||||
* search 1 3 4 5
|
||||
ok search not seen deleted flagged
|
||||
* search
|
||||
ok search not seen deleted not flagged
|
||||
* search
|
||||
ok search seen not deleted flagged
|
||||
* search
|
||||
ok search seen not deleted not flagged
|
||||
* search
|
||||
ok search not seen not deleted flagged
|
||||
* search
|
||||
ok search not seen not deleted not flagged
|
||||
* search
|
||||
@@ -0,0 +1,37 @@
|
||||
messages: all
|
||||
|
||||
# just check that this returns ok. it's not really specified in RFC, so
|
||||
# don't verify the result.
|
||||
ok search subject ""
|
||||
|
||||
# subject
|
||||
ok search subject hello
|
||||
* search 1
|
||||
ok search subject beautiful
|
||||
* search 1
|
||||
ok search subject world
|
||||
* search 1
|
||||
ok search subject "hello beautiful"
|
||||
* search 1
|
||||
ok search subject "hello beautiful world"
|
||||
* search 1
|
||||
#ok search subject "eautiful worl"
|
||||
#* search 1
|
||||
|
||||
# header
|
||||
ok search header subject ""
|
||||
* search 1
|
||||
ok search not header subject ""
|
||||
* search 2
|
||||
#ok search header x-extra ""
|
||||
#* search 2
|
||||
#ok search not header x-extra ""
|
||||
#* search 1
|
||||
#ok search header x-extra hello
|
||||
#* search 2
|
||||
#ok search header x-extra "hello beautiful"
|
||||
#* search 2
|
||||
#ok search header x-extra "eautiful head"
|
||||
#* search 2
|
||||
#ok search header x-extra "another"
|
||||
#* search 2
|
||||
@@ -0,0 +1,10 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Subject: hello beautiful world
|
||||
|
||||
body
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
X-Extra: hello beautiful header
|
||||
X-Extra: another one
|
||||
|
||||
body
|
||||
@@ -0,0 +1,54 @@
|
||||
capabilities: CONTEXT=SEARCH
|
||||
messages: all
|
||||
|
||||
ok search return (partial 1:1) all
|
||||
* esearch (tag $tag) partial (1:1 1)
|
||||
ok search return (partial 2:4) all
|
||||
* esearch (tag $tag) partial (2:4 2:4)
|
||||
ok search return (partial 4:2) all
|
||||
* esearch (tag $tag) partial (2:4 2:4)
|
||||
ok search return (partial 1:6) all
|
||||
* esearch (tag $tag) partial (1:6 1:5)
|
||||
ok search return (partial 6:6) all
|
||||
* esearch (tag $tag) partial (6:6 nil)
|
||||
|
||||
ok search return (partial 1:3) 1:2,4:5
|
||||
* esearch (tag $tag) partial (1:3 1:2,4)
|
||||
ok search return (partial 2:3) 1:2,4:5
|
||||
* esearch (tag $tag) partial (2:3 2,4)
|
||||
ok search return (partial 2:4) 1:2,4:5
|
||||
* esearch (tag $tag) partial (2:4 2,4:5)
|
||||
ok search return (partial 2:10) 1:2,4:5
|
||||
* esearch (tag $tag) partial (2:10 2,4:5)
|
||||
|
||||
# UID partials
|
||||
|
||||
ok fetch 1 uid
|
||||
* 1 fetch (uid $uid1)
|
||||
ok fetch 2 uid
|
||||
* 2 fetch (uid $uid2)
|
||||
ok fetch 3 uid
|
||||
* 3 fetch (uid $uid3)
|
||||
ok fetch 5 uid
|
||||
* 5 fetch (uid $uid5)
|
||||
|
||||
ok uid search return (partial 1:1) all
|
||||
* esearch (tag $tag) uid partial (1:1 $uid1)
|
||||
|
||||
ok uid search return (partial 2:2) all
|
||||
* esearch (tag $tag) uid partial (2:2 $uid2)
|
||||
|
||||
ok store 2 +flags \deleted
|
||||
ok expunge
|
||||
|
||||
ok uid search return (partial 2:2) all
|
||||
* esearch (tag $tag) uid partial (2:2 $uid3)
|
||||
|
||||
ok uid search return (partial 5:10) all
|
||||
* esearch (tag $tag) uid partial (5:10 nil)
|
||||
|
||||
# broken results
|
||||
|
||||
bad search return (partial 1) all
|
||||
bad search return (partial 1:*) all
|
||||
bad search return (partial *:1) all
|
||||
@@ -0,0 +1,19 @@
|
||||
From user@domain Fri Feb 22 17:06:21 2008
|
||||
|
||||
1
|
||||
|
||||
From user@domain Fri Feb 22 17:06:22 2008
|
||||
|
||||
2
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
|
||||
3
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
|
||||
4
|
||||
|
||||
From user@domain Fri Feb 22 17:06:25 2008
|
||||
|
||||
5
|
||||
@@ -0,0 +1,62 @@
|
||||
messages: 6
|
||||
|
||||
ok uid search all
|
||||
* search $uid1 $uid2 $uid3 $uid4 $uid5 $uid6
|
||||
ok status $mailbox (uidnext)
|
||||
* status $mailbox (uidnext $uidnext)
|
||||
|
||||
# break seq=uid mapping
|
||||
ok store 2 +flags \deleted
|
||||
ok expunge
|
||||
* 2 expunge
|
||||
|
||||
ok search all
|
||||
* search 1 2 3 4 5
|
||||
ok uid search all
|
||||
* search $uid1 $uid3 $uid4 $uid5 $uid6
|
||||
|
||||
ok search 1:3,5
|
||||
* search 1 2 3 5
|
||||
ok search 4:2
|
||||
* search 2 3 4
|
||||
ok search uid $uid1:$uid3,$uid5
|
||||
* search 1 2 4
|
||||
ok search uid $uid4:$uid2
|
||||
* search 2 3
|
||||
|
||||
ok search 1:3 not uid $uid3
|
||||
* search 1 3
|
||||
ok search not 2,4
|
||||
* search 1 3 5
|
||||
ok search or 1 uid $uid3
|
||||
* search 1 2
|
||||
|
||||
ok search *
|
||||
* search 5
|
||||
ok search uid *
|
||||
* search 5
|
||||
ok search uid $uidnext:*
|
||||
* search 5
|
||||
ok search *:3
|
||||
* search 3 4 5
|
||||
ok search 1,4,*
|
||||
* search 1 4 5
|
||||
|
||||
# These are in a bit of a grey area. Most servers allow them, but it's not
|
||||
# explicitly defined in the RFC that they're legal:
|
||||
#ok search 6:*
|
||||
#* search 5
|
||||
#ok search *:6
|
||||
#* search 5
|
||||
|
||||
ok search (3) uid $uid4
|
||||
* search 3
|
||||
ok search (uid $uid4) 3
|
||||
* search 3
|
||||
ok search 3 (uid $uid4)
|
||||
* search 3
|
||||
|
||||
ok uid search uid 1:4294967295
|
||||
* search $uid1 $uid3 $uid4 $uid5 $uid6
|
||||
ok uid search uid $uidnext:4294967295
|
||||
* search
|
||||
@@ -0,0 +1,22 @@
|
||||
messages: all
|
||||
|
||||
# get the middle size. don't trust precalculated values in case server
|
||||
# modifies the message while APPENDing it. Messages 3 and 4 have different
|
||||
# RFC822.SIZE, but with servers that store linefeeds as LFs they have the
|
||||
# same file size. This test catches if they search using file size.
|
||||
ok fetch 1:4 rfc822.size
|
||||
* 3 fetch (rfc822.size $size)
|
||||
|
||||
ok search smaller $size
|
||||
* search 1 2
|
||||
ok search larger $size
|
||||
* search 4
|
||||
ok search not smaller $size
|
||||
* search 3 4
|
||||
ok search not larger $size
|
||||
* search 1 2 3
|
||||
|
||||
ok search not smaller $size not larger $size
|
||||
* search 3
|
||||
ok search or smaller $size larger $size
|
||||
* search 1 2 4
|
||||
@@ -0,0 +1,21 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
1
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
22
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
333
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
4
|
||||
4
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
state: created
|
||||
|
||||
ok append
|
||||
ok append
|
||||
|
||||
# first open read-only so recent flags don't get lost
|
||||
examine $mailbox
|
||||
* 2 exists
|
||||
#* 2 recent
|
||||
#* ok [unseen 1]
|
||||
* ok [uidvalidity $uidvalidity]
|
||||
* ok [uidnext $uidnext]
|
||||
ok [read-only]
|
||||
|
||||
ok close
|
||||
|
||||
# check that STATUS replies with the same values
|
||||
ok status $mailbox (messages uidnext uidvalidity unseen)
|
||||
* status $mailbox (messages 2 uidnext $uidnext uidvalidity $uidvalidity unseen 2)
|
||||
|
||||
# then try read-write
|
||||
select $mailbox
|
||||
* 2 exists
|
||||
#* 2 recent
|
||||
#* ok [unseen 1]
|
||||
* ok [uidvalidity $uidvalidity]
|
||||
* ok [uidnext $uidnext]
|
||||
ok [read-write]
|
||||
|
||||
ok close
|
||||
|
||||
#ok status $mailbox (recent)
|
||||
#* status $mailbox (recent 0)
|
||||
@@ -0,0 +1,10 @@
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body
|
||||
|
||||
From user@domain Fri Feb 22 17:06:23 2008
|
||||
Date: Sat, 24 Mar 2007 23:00:00 +0200
|
||||
|
||||
body2
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
capabilities: SORT
|
||||
messages: all
|
||||
|
||||
ok sort (from) us-ascii all
|
||||
* sort 3 2 1
|
||||
ok sort (to) us-ascii all
|
||||
* sort 3 2 1
|
||||
ok sort (cc) us-ascii all
|
||||
* sort 2 1 3
|
||||
|
||||
ok sort (reverse from) us-ascii all
|
||||
* sort 1 2 3
|
||||
ok sort (reverse to) us-ascii all
|
||||
* sort 1 2 3
|
||||
ok sort (reverse cc) us-ascii all
|
||||
* sort 3 1 2
|
||||
|
||||
ok sort (from reverse arrival) us-ascii all
|
||||
* sort 3 2 1
|
||||
ok sort (to reverse arrival) us-ascii all
|
||||
* sort 3 2 1
|
||||
ok sort (cc reverse arrival) us-ascii all
|
||||
* sort 2 1 3
|
||||
@@ -0,0 +1,21 @@
|
||||
From user@domain Fri Feb 22 00:06:23 2008
|
||||
From: [email protected]
|
||||
To: [email protected]
|
||||
Cc: [email protected] (foo bar)
|
||||
|
||||
1
|
||||
|
||||
From user@domain Fri Feb 22 01:06:23 2008
|
||||
From: [email protected]
|
||||
To: [email protected]
|
||||
Cc: [email protected]
|
||||
|
||||
2
|
||||
|
||||
From user@domain Fri Feb 22 02:06:23 2008
|
||||
From: [email protected]
|
||||
To: [email protected]
|
||||
Cc: [email protected]
|
||||
|
||||
3
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
capabilities: SORT
|
||||
messages: all
|
||||
|
||||
ok sort (arrival) us-ascii all
|
||||
* sort 1 3 2 4 5
|
||||
|
||||
ok sort (reverse arrival) us-ascii all
|
||||
* sort 5 4 2 3 1
|
||||
|
||||
ok sort (arrival reverse size) us-ascii all
|
||||
* sort 1 3 5 4 2
|
||||
@@ -0,0 +1,20 @@
|
||||
From user@domain Fri Feb 22 00:00:00 2008
|
||||
|
||||
1
|
||||
|
||||
From user@domain Fri Feb 22 02:00:00 2008
|
||||
|
||||
2
|
||||
|
||||
From user@domain Fri Feb 22 01:00:00 2008
|
||||
|
||||
33
|
||||
|
||||
From user@domain Fri Feb 22 02:00:00 2008
|
||||
|
||||
44
|
||||
|
||||
From user@domain Fri Feb 22 02:00:00 2008
|
||||
|
||||
5555
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
capabilities: SORT
|
||||
messages: all
|
||||
|
||||
ok sort (date) us-ascii all
|
||||
* sort 1 3 7 5 2 4 6
|
||||
|
||||
ok sort (reverse date) us-ascii all
|
||||
* sort 6 4 2 5 7 3 1
|
||||
|
||||
ok sort (date reverse size) us-ascii all
|
||||
* sort 1 7 3 5 6 4 2
|
||||
@@ -0,0 +1,37 @@
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
Date: Fri, 22 Feb 2008 00:00:00 +0200
|
||||
|
||||
1
|
||||
|
||||
From user@domain Fri Feb 22 22:00:00 2008 +0200
|
||||
Date: Fri, 22 Feb 2008 02:00:00 +0200
|
||||
|
||||
2
|
||||
|
||||
From user@domain Fri Feb 22 21:00:00 2008 +0200
|
||||
Date: Fri, 22 Feb 2008 01:00:00 +0200
|
||||
|
||||
33
|
||||
|
||||
From user@domain Fri Feb 22 20:00:00 2008 +0200
|
||||
Date: Fri, 22 Feb 2008 02:00:00 +0200
|
||||
|
||||
44
|
||||
|
||||
From user@domain Fri Feb 22 01:30:23 2008 +0200
|
||||
Date: Fri, 22 Feb 2008 01:30:23 +0200
|
||||
Subject: foo
|
||||
|
||||
55555
|
||||
|
||||
From user@domain Fri Feb 22 18:00:00 2008 +0200
|
||||
Date: Fri, 22 Feb 2008 02:00:00 +0200
|
||||
|
||||
6666
|
||||
|
||||
From user@domain Fri Feb 22 01:00:00 2008 +0200
|
||||
Date: Fri, 22 Feb 2008 01:00:00 +0200
|
||||
Subject: foo bar foo bar foo bar fooo
|
||||
|
||||
777
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
capabilities: SORT=DISPLAY
|
||||
messages: all
|
||||
|
||||
ok sort (displayfrom) us-ascii all
|
||||
* sort 2 3 4 1 5
|
||||
|
||||
ok sort (reverse displayfrom) us-ascii all
|
||||
* sort 5 1 4 3 2
|
||||
@@ -0,0 +1,24 @@
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
From: foo bar <[email protected]>
|
||||
|
||||
1
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
From: [email protected]
|
||||
|
||||
2
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
From: d
|
||||
|
||||
3
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
From: =?iso-8859-1?q?foo_aar?= <[email protected]>
|
||||
|
||||
4
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
From: =?iso-8859-1?q?foo_car?= <[email protected]>
|
||||
|
||||
5
|
||||
@@ -0,0 +1,8 @@
|
||||
capabilities: SORT=DISPLAY
|
||||
messages: all
|
||||
|
||||
ok sort (displayto) us-ascii all
|
||||
* sort 8 7 2 3 4 1 5 6
|
||||
|
||||
ok sort (reverse displayto) us-ascii all
|
||||
* sort 6 5 1 4 3 2 7 8
|
||||
@@ -0,0 +1,39 @@
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
To: foo bar <[email protected]>
|
||||
|
||||
1
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
To: [email protected]
|
||||
|
||||
2
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
To: d
|
||||
|
||||
3
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
To: =?iso-8859-1?q?foo_aar?= <[email protected]>
|
||||
|
||||
4
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
To: =?iso-8859-1?q?foo_car?= <[email protected]>
|
||||
|
||||
5
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
To: a: [email protected], [email protected];
|
||||
|
||||
6
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
To: z: [email protected], [email protected];
|
||||
|
||||
7
|
||||
|
||||
From user@domain Fri Feb 22 23:00:00 2008 +0200
|
||||
To: empty:;
|
||||
|
||||
8
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user