]> Sergey Matveev's repositories - public-inbox.git/commitdiff
imap: case-insensitive mailbox name comparisons
authorEric Wong <e@yhbt.net>
Wed, 10 Jun 2020 07:04:37 +0000 (07:04 +0000)
committerEric Wong <e@yhbt.net>
Sat, 13 Jun 2020 07:55:45 +0000 (07:55 +0000)
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.

lib/PublicInbox/IMAPD.pm
t/imap.t
t/imapd.t

index a3a2598661bbf97d09b0c5ddb550f5c9faeca506..966879d8ea59f76e8401468e09db7953bbc269c2 100644 (file)
@@ -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//) {
index 451b6596bf9f8d08df021a385d597fcb8eebb807..aa262a196329f49d79808c7b4c951a6fb5ecc81f 100644 (file)
--- 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');
index 2c4315dec30fb19b003a790944ebb2c7e0227a0d..a5324f78da0044b3c82113c46a2057ed7f2844e5 100644 (file)
--- 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