From: Eric Wong Date: Wed, 10 Jun 2020 07:04:37 +0000 (+0000) Subject: imap: case-insensitive mailbox name comparisons X-Git-Tag: v1.6.0~427 X-Git-Url: http://www.git.stargrave.org/?p=public-inbox.git;a=commitdiff_plain;h=49175649b3e49cdd5f2ac857cb91e69a5b91a739 imap: case-insensitive mailbox name comparisons IMAP RFC 3501 stipulates case-insensitive comparisons, and so does RFC 977 (NNTP). However, INN (nnrpd) uses case-sensitive comparisons, so we've always used case-sensitive comparisons for NNTP to match nnrpd behavior. Unfortunately, some IMAP clients insist on sending "INBOX" with caps, which causes problems for us. Since NNTP group names are typically all lowercase anyways, just force all comparisons to lowercase for IMAP and warn admins if uppercase-containing newsgroups won't be accessible over IMAP. This ensures our existing -nntpd behavior remains unchanged while being compatible with the expectations of real-world IMAP clients. --- diff --git a/lib/PublicInbox/IMAPD.pm b/lib/PublicInbox/IMAPD.pm index a3a25986..966879d8 100644 --- a/lib/PublicInbox/IMAPD.pm +++ b/lib/PublicInbox/IMAPD.pm @@ -25,6 +25,13 @@ sub refresh_inboxlist ($) { my ($self) = @_; my @names = map { $_->{newsgroup} } @{delete $self->{grouplist}}; my %ns; # "\Noselect \HasChildren" + + if (my @uc = grep(/[A-Z]/, @names)) { + warn "Uppercase not allowed for IMAP newsgroup(s):\n", + map { "\t$_\n" } @uc; + my %uc = map { $_ => 1 } @uc; + @names = grep { !$uc{$_} } @names; + } for (@names) { my $up = $_; while ($up =~ s/\.[^\.]+\z//) { diff --git a/t/imap.t b/t/imap.t index 451b6596..aa262a19 100644 --- a/t/imap.t +++ b/t/imap.t @@ -8,9 +8,14 @@ use PublicInbox::IMAP; use PublicInbox::IMAPD; { # make sure we get '%' globbing right - my @n = map { { newsgroup => $_ } } (qw(x.y.z x.z.y)); + my @w; + local $SIG{__WARN__} = sub { push @w, @_ }; + my @n = map { { newsgroup => $_ } } (qw(x.y.z x.z.y IGNORE.THIS)); my $self = { imapd => { grouplist => \@n } }; PublicInbox::IMAPD::refresh_inboxlist($self->{imapd}); + is(scalar(@w), 1, 'got a warning for upper-case'); + like($w[0], qr/IGNORE\.THIS/, 'warned about upper-case'); + my $res = PublicInbox::IMAP::cmd_list($self, 'tag', 'x', '%'); is(scalar($$res =~ tr/\n/\n/), 2, 'only one result'); like($$res, qr/ x\r\ntag OK/, 'saw expected'); diff --git a/t/imapd.t b/t/imapd.t index 2c4315de..a5324f78 100644 --- a/t/imapd.t +++ b/t/imapd.t @@ -88,7 +88,7 @@ like($e, qr/\bNO\b/, 'got a NO on EXAMINE for non-existent'); ok(!$mic->select('foo') && ($e = $@), 'EXAMINE non-existent'); like($e, qr/\bNO\b/, 'got a NO on EXAMINE for non-existent'); ok($mic->select('inbox.i1'), 'SELECT succeeds'); -ok($mic->examine('inbox.i1'), 'EXAMINE succeeds'); +ok($mic->examine('INBOX.i1'), 'EXAMINE succeeds'); my @raw = $mic->status('inbox.i1', qw(Messages uidnext uidvalidity)); is(scalar(@raw), 2, 'got status response'); like($raw[0], qr/\A\*\x20STATUS\x20inbox\.i1\x20