diff options
author | Guilhem Moulin <guilhem@fripost.org> | 2018-05-09 01:14:35 +0200 |
---|---|---|
committer | Guilhem Moulin <guilhem@fripost.org> | 2018-05-09 01:14:35 +0200 |
commit | 98aa4bf1b7e58a92f069dafc8a58fe4fa8fc738a (patch) | |
tree | 897172c72352b013dec3f4594dd089292a258511 | |
parent | 4f55cb8d1f8f1ba7fe52e1d0035d13638ff25a00 (diff) | |
parent | c41c280d3a1243ae445311e1ededd1dedc1484c3 (diff) |
Merge branch 'master' into debian
-rw-r--r-- | Changelog | 3 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | lib/Net/IMAP/InterIMAP.pm | 56 |
3 files changed, 51 insertions, 12 deletions
@@ -3,7 +3,10 @@ interimap (0.4) UNRELEASED * pullimap: replace non RFC 5321-compliant envelope sender addresses (received by the IMAP FETCH ENVELOPE command) by the null sender address <>. + + Library: new API idle_start() and idle_stop(). + + Add support for untagged ESEARCH responses from RFC 4731. - Ensure the lower bound of UID ranges is at least 1. + - Fix manpage generation with pandoc >=2.1. -- Guilhem Moulin <guilhem@guilhem.org> Tue, 06 Dec 2016 17:37:01 +0100 @@ -2,7 +2,7 @@ all: pullimap.1 interimap.1 # upper case the headers and remove the links %.1: %.md - @pandoc -S -f markdown -t json "$<" | \ + @pandoc -f markdown -t json "$<" | \ jq " \ def fixheaders: \ if .t == \"Header\" then \ @@ -27,7 +27,7 @@ all: pullimap.1 interimap.1 , meta \ , blocks: .blocks | map(fixheaders) | map(fixlinks) \ }" | \ - pandoc -sS -f json -t man -o "$@" + pandoc -s -f json -t man+smart -o "$@" install: diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index 6f148b7..4a9ffd9 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -594,12 +594,15 @@ sub incapable($@) { # $self->search($criterion) -# Issue an UID SEARCH command with the given $criterion. Return the -# list of matching UIDs. +# Issue an UID SEARCH command with the given $criterion. For the "normal" +# UID SEARCH command from RFC 3501, return the list of matching UIDs; +# for the extended UID SEARCH command from RFC 4731 (ensuring ESEARCH +# capability is the caller's responsibility), return an "UID" +# indicator followed by a hash containing search data pairs. sub search($$) { my ($self, $crit) = @_; my @res; - $self->_send('UID SEARCH '.$crit, sub(@) {push @res, @_}); + $self->_send('UID SEARCH '.$crit, sub(@) {@res = @_}); return @res } @@ -959,14 +962,15 @@ sub slurp($$$) { foreach my $imap (@ready) { my $x = $imap->_getline(); - $imap->_resp($x, sub($) { - if ($stopwhen->($imap, shift)) { + $imap->_resp($x, sub($;$$) { + if ($stopwhen->(@_)) { $aborted = 1; $timeout = 0; # keep reading the handles while there is pending data } }, 'slurp'); } } + return $aborted; } @@ -977,20 +981,39 @@ sub slurp($$$) { # after the $timeout) and false otherwise. sub idle($$$) { my ($self, $timeout, $stopwhen) = @_; + my $tag = $self->idle_start($timeout); + my $r = slurp([$self], $timeout // 1740, $stopwhen); # 29 mins + $r += $self->idle_stop($tag, $stopwhen); + return $r; +} +# $self->idle_start() +# Enter IDLE (RFC 2177). +# Return the command tag. +sub idle_start($) { + my $self = shift; $self->fail("Server did not advertise IDLE (RFC 2177) capability.") unless $self->_capable('IDLE'); my $tag = $self->_cmd_init('IDLE'); $self->_cmd_flush(); - my $r = slurp([$self], $timeout // 1740, $stopwhen); # 29 mins + return $tag; +} + +# $self->idle_stop($tag, $callback) +# Stop a running IDLE (RFC 2177) command $tag. +# Returns the number of untagged responses received between the DONE +# the tagged response that are satisfying $callback. +sub idle_stop($$$) { + my ($self, $tag, $callback) = @_; + my $r = 0; # done idling $self->_cmd_extend('DONE'); $self->_cmd_flush(); # run the callback again to update the return value if we received # untagged responses between the DONE and the tagged response - $self->_recv($tag, sub($) { $r = 1 if $stopwhen->($self, shift) }, 'slurp'); + $self->_recv($tag, sub($;$$) { $r++ if $callback->($self, @_) }, 'slurp'); return $r; } @@ -1922,7 +1945,9 @@ sub _send($$;&) { $self->_recv($tag, undef, $cmd); } else { - my $set = $$command =~ /\AUID (?:FETCH|STORE) ([0-9:,*]+)/ ? $1 : undef; + my $set = $$command =~ /\AUID (?:FETCH|STORE) ([0-9:,*]+)/ ? $1 + : $$command =~ /\AUID SEARCH / ? "\"$tag\"" # RFC 4466's tag-string + : undef; $self->_recv($tag, $callback, $cmd, $set); } } @@ -2247,7 +2272,7 @@ sub _resp($$;&$$) { $self->{_NEW} += $1 - $cache->{EXISTS} if $1 > $cache->{EXISTS}; # new mails } $cache->{EXISTS} = $1; - $callback->($self->{_SELECTED} // $self->panic()) if defined $callback and $cmd eq 'slurp'; + $callback->($self->{_SELECTED} // $self->panic(), EXISTS => $1) if defined $callback and $cmd eq 'slurp'; } elsif (/\A([0-9]+) EXPUNGE\z/) { $self->panic() unless defined $cache->{EXISTS}; # sanity check @@ -2263,6 +2288,17 @@ sub _resp($$;&$$) { elsif (/\ASEARCH((?: [0-9]+)*)\z/) { $callback->(split(/ /, ($1 =~ s/^ //r))) if defined $callback and $cmd eq 'SEARCH'; } + elsif (s/\AESEARCH \(TAG \Q$set\E\)( UID)?//) { + my $uid = $1; + my %ret; # RFC 4731 + while ($_ ne '') { + $self->fail("RFC 4731 violation in ESEARCH response") + # XXX RFC 4466's tagged-ext-comp unsupported + unless s/\A ($RE_ATOM_CHAR+) ([0-9,:]+)//; + $ret{uc $1} = $2; + } + $callback->($uid, %ret) if defined $callback and $cmd eq 'SEARCH'; + } elsif (s/\ALIST \((\\?$RE_ATOM_CHAR+(?: \\?$RE_ATOM_CHAR+)*)?\) ("(?:\\[\x22\x5C]|[\x01-\x09\x0B\x0C\x0E-\x21\x23-\x5B\x5D-\x7F])"|NIL) //) { my ($delim, $attrs) = ($2, $1); my @attrs = defined $attrs ? split(/ /, $attrs) : (); @@ -2340,7 +2376,7 @@ sub _resp($$;&$$) { if ($cmd eq 'FETCH' or $cmd eq 'STORE') { $callback->(\%mail) if defined $uid and in_set($uid, $set); } elsif ($cmd eq 'slurp') { - $callback->($self->{_SELECTED} // $self->panic()) + $callback->($self->{_SELECTED} // $self->panic(), FETCH => $seq) } } } |