]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
config: avoid eidx_key and newsgroup conflicts
authorEric Wong <e@80x24.org>
Tue, 14 Nov 2023 00:32:20 +0000 (00:32 +0000)
committerEric Wong <e@80x24.org>
Tue, 14 Nov 2023 20:08:08 +0000 (20:08 +0000)
Start lowercasing newsgroup names automatically since uppercase
names are incompatible with IMAP and POP3 and also causes
problems with both -extindex and -cindex.

We'll also warn on eidx_key and newsgroup conflicts to avoid
sometimes subtle breakage when using -extindex and -cindex.

Documentation/RelNotes/v2.0.0.wip
Documentation/public-inbox-config.pod
lib/PublicInbox/Config.pm
lib/PublicInbox/IMAPD.pm
t/config.t
t/imap.t

index 859d858bd1e1ec33e2972f6100e54d1b24eb6728..5fc9ecd79759683350fff164c7c47764d21a5b9e 100644 (file)
@@ -18,6 +18,14 @@ Upgrading:
   backwards-incompatible data format changes so rolling back to
   older versions is harmless.
 
+Compatibility:
+
+  Uppercase newsgroup names were always broken with IMAP, POP3, and
+  -extindex.  Uppercase names will now be lowercased by default and
+  warnings will be emitted.  Conflicting newsgroup names (and `inboxdir'
+  entries if `newsgroup' isn't specified) will also generate warnings
+  since it breaks -extindex and the new -cindex (coderepo index)
+
 treewide
 
   * support raw UTF-8 headers from SMTPUTF8 hosts
index 1ef7f46f7ed2225f0fa55ceb106b1bc8db57ba68..d394d31f70dd616c762c37f3603eb7f3f4b27b7f 100644 (file)
@@ -74,6 +74,11 @@ Omitting this for a given inbox will prevent the inbox from
 being served by L<public-inbox-nntpd(1)>,
 L<public-inbox-imapd(1)>, and/or L<public-inbox-pop3d(1)>
 
+Newsgroup names should be all lowercase.  Uppercase characters are
+converted to lowercase for compatibility with IMAP, POP3, and our
+L<public-inbox-extindex(1)> and L<public-inbox-cindex(1)> tools
+starting with public-inbox 2.0+ (they were unusable before).
+
 Default: none, optional
 
 =item publicinbox.<name>.watch
index 01cb536d96026e3cb1c7070f0e959f4202e31d26..9bee94b84752b34a642d24c71bd7263c43e97392 100644 (file)
@@ -509,9 +509,16 @@ sub _fill_ibx {
                        delete $ibx->{newsgroup};
                        warn "newsgroup name invalid: `$ngname'\n";
                } else {
+                       my $lc = $ibx->{newsgroup} = lc $ngname;
+                       warn <<EOM if $lc ne $ngname;
+W: newsgroup=`$ngname' lowercased to `$lc'
+EOM
                        # PublicInbox::NNTPD does stricter ->nntp_usable
                        # checks, keep this lean for startup speed
-                       $self->{-by_newsgroup}->{$ngname} = $ibx;
+                       my $cur = $self->{-by_newsgroup}->{$lc} //= $ibx;
+                       warn <<EOM if $cur != $ibx;
+W: newsgroup=`$lc' is used by both `$cur->{name}' and `$ibx->{name}'
+EOM
                }
        }
        unless (defined $ibx->{newsgroup}) { # for ->eidx_key
@@ -531,7 +538,10 @@ sub _fill_ibx {
                require PublicInbox::Isearch;
                $ibx->{isrch} = PublicInbox::Isearch->new($ibx, $es);
        }
-       $self->{-by_eidx_key}->{$ibx->eidx_key} = $ibx;
+       my $cur = $self->{-by_eidx_key}->{my $ekey = $ibx->eidx_key} //= $ibx;
+       $cur == $ibx or warn
+               "W: `$ekey' used by both `$cur->{name}' and `$ibx->{name}'\n";
+       $ibx;
 }
 
 sub _fill_ei ($$) {
index bdadb7a35ef9275855842bc69e7ffce9194c081b..42dc2a9ff14bdf654ba1416c02b6f20420e80f00 100644 (file)
@@ -27,13 +27,8 @@ sub _refresh_ibx { # pi_cfg->each_inbox cb
        my ($ibx, $imapd, $cache, $dummies) = @_;
        my $ngname = $ibx->{newsgroup} // return;
 
-       # We require lower-case since IMAP mailbox names are
-       # case-insensitive (but -nntpd matches INN in being
-       # case-sensitive)
-       if ($ngname =~ m![^a-z0-9/_\.\-\~\@\+\=:]! ||
-                       # don't confuse with 50K slices
-                       $ngname =~ /\.[0-9]+\z/) {
-               warn "mailbox name invalid: newsgroup=`$ngname'\n";
+       if ($ngname =~ /\.[0-9]+\z/) { # don't confuse with 50K slices
+               warn "E: mailbox name invalid: newsgroup=`$ngname' (ignored)\n";
                return;
        }
        my $ce = $cache->{$ngname};
index 9b6684b74ef0a0ae9e60d7ffaf4880150ab4b9c6..975cf836e97c7ed82fffef726bd58fe1a6ec86ae 100644 (file)
@@ -299,4 +299,37 @@ my $re = $glob2re->('a/**/b');
 is_deeply($re, 'a/.*?b', 'double asterisk middle');
 like($_, qr!$re!, "a/**/b matches $_") for ('a/b', 'a/c/b', 'a/c/a/b');
 
-done_testing();
+{
+       my $w = '';
+       local $SIG{__WARN__} = sub { $w .= "@_"; };
+       my $cfg = cfg_new $tmpdir, <<EOF;
+[publicinbox "a"]
+       address = a\@example.com
+       inboxdir = $tmpdir/aa
+[publicinbox "b"]
+       address = b\@example.com
+       inboxdir = $tmpdir/aa
+EOF
+       $cfg->fill_all;
+       like $w, qr!`\Q$tmpdir/aa\E' used by both!, 'inboxdir conflict warned';
+}
+
+{
+       my $w = '';
+       local $SIG{__WARN__} = sub { $w .= "@_"; };
+       my $cfg = cfg_new $tmpdir, <<EOF;
+[publicinbox "a"]
+       address = a\@example.com
+       inboxdir = $tmpdir/a
+       newsgroup = inbox.test
+[publicinbox "b"]
+       address = b\@example.com
+       inboxdir = $tmpdir/b
+       newsgroup = inbox.tesT
+EOF
+       $cfg->fill_all;
+       like $w, qr!`inbox\.test' used by both!, 'newsgroup conflict warned';
+       like $w, qr!`inbox\.tesT' lowercased!, 'upcase warned';
+}
+
+done_testing;
index e6efe04f7702c0c6a2b92f23ec8da32fbd9e77c6..44b8ef2af11cb7898a9f5c69b0c491d9b358a813 100644 (file)
--- a/t/imap.t
+++ b/t/imap.t
@@ -1,5 +1,5 @@
 #!perl -w
-# Copyright (C) 2020-2021 all contributors <meta@public-inbox.org>
+# Copyright (C) all contributors <meta@public-inbox.org>
 # License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
 # unit tests (no network) for IMAP, see t/imapd.t for end-to-end tests
 use strict;
@@ -9,12 +9,12 @@ require_git 2.6;
 require_mods(qw(-imapd));
 require_ok 'PublicInbox::IMAP';
 require_ok 'PublicInbox::IMAPD';
+use PublicInbox::IO qw(write_file);
 
 my ($tmpdir, $for_destroy) = tmpdir();
 my $cfgfile = "$tmpdir/config";
 {
-       open my $fh, '>', $cfgfile or BAIL_OUT $!;
-       print $fh <<EOF or BAIL_OUT $!;
+       write_file '>', $cfgfile, <<EOF;
 [publicinbox "a"]
        inboxdir = $tmpdir/a
        newsgroup = x.y.z
@@ -23,9 +23,8 @@ my $cfgfile = "$tmpdir/config";
        newsgroup = x.z.y
 [publicinbox "c"]
        inboxdir = $tmpdir/c
-       newsgroup = IGNORE.THIS
+       newsgroup = ignore.this.9
 EOF
-       close $fh or BAIL_OUT $!;
        local $ENV{PI_CONFIG} = $cfgfile;
        for my $x (qw(a b c)) {
                ok(run_script(['-init', '-Lbasic', '-V2', $x, "$tmpdir/$x",
@@ -37,8 +36,8 @@ EOF
        local $SIG{__WARN__} = sub { push @w, @_ };
        $imapd->refresh_groups;
        my $self = { imapd => $imapd };
-       is(scalar(@w), 1, 'got a warning for upper-case');
-       like($w[0], qr/IGNORE\.THIS/, 'warned about upper-case');
+       is(scalar(@w), 1, 'got a warning for slice-like name');
+       like($w[0], qr/ignore\.this\.9/i, 'warned about slice-like name');
        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');