MAILBOX="INBOX" TIMEOUT=60 N=2048 step_start "\`pullimap --idle\` refuses to create the state file" ! pullimap --idle "remote" || error step_done step_start "\`pullimap\` creates statefile with mode 0600" pullimap "remote" || error if ! st="$(stat -c"%#a" -- "$XDG_DATA_HOME/pullimap/remote")" || [ "$st" != "0600" ]; then error "$XDG_DATA_HOME/pullimap/remote has mode $st != 0600" fi step_done step_start "\`pullimap\` locks its statefile" pullimap --idle "remote" & PID=$! trap "ptree_abort $PID" EXIT INT TERM # wait a short while so we have time to lock the database (ugly and racy...) sleep .5 ! pullimap "remote" || error grep -F "Can't lock $XDG_DATA_HOME/pullimap/remote: Resource temporarily unavailable at " <"$STDERR" || error ptree_abort $PID trap - EXIT INT TERM step_done # compare mailboxes (can't compare the RFC 3501 TEXT as the LMTPd inconditionally # adds a Return-Path: header -- and also Delivered-To: and Received: to by default) list_mails_sha256() { local u="$1" guid uid local fields="body date.sent imap.bodystructure imap.envelope" while read guid uid; do doveadm -u "$u" -f "flow" fetch "$fields" mailbox-guid "$guid" uid "$uid" | sha256sum done < <(doveadm -u "$u" search mailbox "$MAILBOX") | sort -f } check() { diff -u --label="local/mails" --label="remote/mails" \ <( list_mails_sha256 "local" ) \ <( list_mails_sha256 "remote" ) \ || error "mailboxes differ" } message_from() { local date="$(date +"%s.%N")" sender="$1" cat <<-EOF From: $sender To: Date: $(date -R -d@"$date") Message-ID: <$date@example.net> EOF xxd -ps -l8 /dev/urandom } step_start "Quote envelope sender address" declare -a senders=("sender" "first.last" "foo-bar" \"\" "\"x\\\" #&\\\\y\"") for s in "${senders[@]}"; do message_from "$s@example.net" | deliver -u "remote" -- -m "$MAILBOX" done pullimap "remote" || error check for s in "${senders[@]}"; do grep -F " from <$s@example.net> " <"$STDERR" || error "$s" done step_done step_start "Mail without data" deliver -u "remote" -- -m "$MAILBOX" foo . .bar ..baz EOF # we can't add a test for message data not ending with CRLF, because the # LMTP/SMTP client needs to add a CRLF so local and remote message # bodies would differ. that said, while such a message could be added # by IMAP and LDA, it's not valid for SMTP (RFC 5321 sec. 4.1.1.4) pullimap "remote" || error check step_done # make sure remote UIDs are 11-bytes long doveadm -u "remote" mailbox update --min-next-uid 1000000000 "$MAILBOX" # Add some messages and sync step_start "Fetching messages" for ((i = 0; i < 32; i++)); do sample_message | deliver -u "remote" -- -m "$MAILBOX" done pullimap "remote" || error check # same thing, but with some missing messages for ((i = 0; i < N; i+=2)); do sample_message | deliver -u "remote" -- -m "$MAILBOX" deliver -u "remote" -- -m "$MAILBOX" "$TMPDIR/unseen" [ ! -s "$TMPDIR/unseen" ] || error "\\Unseen messages left" step_done if [ $TIMEOUT -gt 0 ]; then step_start "--idle (${TIMEOUT}s)" pullimap --idle "remote" & PID=$! trap "ptree_abort $PID" EXIT INT TERM timer=$(( $(date +%s) + TIMEOUT )) while [ $(date +%s) -le $timer ]; do n="$(shuf -n1 -i1-5)" for (( i=0; i < n; i++)); do sample_message | deliver -u "remote" -- -m "$MAILBOX" done s=$(shuf -n1 -i1-1500) [ $s -ge 1000 ] && s="$(printf "1.%03d" $((s-1000)))" || s="$(printf "0.%03d" $s)" sleep "$s" done sleep 5 ptree_abort $PID trap - EXIT INT TERM check step_done fi step_start "Purging" echo "purge-after = 0" >>"$XDG_CONFIG_HOME/pullimap/config" for ((i = 0; i < 32; i++)); do sample_message | deliver -u "remote" -- -m "$MAILBOX" done pullimap "remote" doveadm -u "remote" search mailbox "$MAILBOX" all >"$TMPDIR/messages" [ ! -s "$TMPDIR/messages" ] || error "messages left" step_done # vim: set filetype=bash :