#!/usr/bin/perl

use v5.10;
use warnings;
use strict;

use Socket qw/PF_INET SOCK_STREAM pack_sockaddr_in INADDR_LOOPBACK/;
use Compress::Raw::Zlib qw/Z_OK Z_STREAM_END Z_SYNC_FLUSH MAX_WBITS/;

socket(my $S, PF_INET, SOCK_STREAM, 0) or die "socket: $!";
connect($S, pack_sockaddr_in(10143, INADDR_LOOPBACK)) or die "connect: $!";

my $MAX_LINE_LENGTH = $ARGV[0] // 8192;
my $COMPRESS = $ENV{COMPRESS} // "y";

my ($DEFLATE, $INFLATE);
sub getline() {
    state $BUFFER = "";
    my $idx;
    until (($idx = 1 + index($BUFFER, "\n")) > 0) {
        sysread($S, my $buf, 4096) or die "read: $!";
        if (defined $INFLATE) {
            my $r = $INFLATE->inflate($buf, my $data);
            die $INFLATE->msg() unless $r == Z_OK or $r == Z_STREAM_END;
            $buf = $data;
        }
        $BUFFER .= $buf;
    }
    my $resp = substr($BUFFER, 0, $idx, "");
    print "S: ", $resp;
    return $resp;
}

sub command($) {
    my $command = "x $_[0]\r\n";
    print "C: x ", substr($_[0], 0, 64), " [", length($command), " bytes]\n";
    if (defined $DEFLATE) {
        die $DEFLATE->msg() unless $DEFLATE->deflate($command, my $data) == Z_OK; 
        die $DEFLATE->msg() unless $DEFLATE->flush($data, Z_SYNC_FLUSH) == Z_OK; 
        $command = $data;
    }
    $S->printflush($command);
    while (defined (my $resp = getline())) {
        last if substr($resp, 0, 2) eq "x "; 
    }

}

getline();
command("AUTHENTICATE ANONYMOUS \"\"");

if ($COMPRESS eq "y") {
    command("COMPRESS DEFLATE");
    my %RFC1951 = (-WindowBits => 0 - MAX_WBITS);
    $DEFLATE = Compress::Raw::Zlib::Deflate::->new(%RFC1951) // die;
    $INFLATE = Compress::Raw::Zlib::Inflate::->new(%RFC1951) // die;
}

command("EXAMINE INBOX");

my ($fetch, $attrs) = ("UID FETCH", "(UID)");
my $length = 2 + length($fetch) + 3 + length($attrs) + 2;
my $n = int(($MAX_LINE_LENGTH - $length) / 2);

command($fetch. " " . "1," x $n ."1 (UID)");
command($fetch. " " . "1," x $n ."12 (UID)");
command($fetch. " " . "1," x $n ."123 (UID)");
