]> git.g-eek.se Git - interimap.git/commitdiff
interimap: accept C-style escape sequences in 'list-mailbox'.
authorGuilhem Moulin <guilhem@fripost.org>
Wed, 15 May 2019 23:05:25 +0000 (01:05 +0200)
committerGuilhem Moulin <guilhem@fripost.org>
Sun, 26 May 2019 22:07:30 +0000 (00:07 +0200)
This is useful for defining names containing control characters (incl.
\0 for unspecified hierarchy delimiter).

Changelog
interimap
interimap.md

index f261a98316237100efbd9a7ce4ce485207c2c013..209bb25b91f83f29abf03323be598cd1897ca43d 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -1,5 +1,8 @@
 interimap (0.5) upstream;
 
+ * interimap: the space-speparated list of names and/or patterns in
+   'list-mailbox' can now contain C-style escape sequences (backslash
+   and hexadecimal escape).
  + interimap: write which --target to use in --delete command
    suggestions.
  - libinterimap: bugfix: hierarchy delimiters in LIST responses were
@@ -11,6 +14,9 @@ interimap (0.5) upstream;
  - libinterimap: quote() the empty string as "" instead of a 0-length
    literal.  (This saves 3 bytes + one round-trip on servers not
    supporting non-synchronizing literals, and 4 bytes otherwise.)
+ - interimap: unlike what the documentation said, spaces where not
+   allowed in the 'list-select-opts' configuration option, so at maximum
+   one selector could be used for the initial LIST command.
 
  -- Guilhem Moulin <guilhem@fripost.org>  Fri, 10 May 2019 00:58:14 +0200
 
index fa65241fb22e774dadfa7ec5868d068565a04e6a..8aeaba493f4349588e6ee9427df8da039bdbae6d 100755 (executable)
--- a/interimap
+++ b/interimap
@@ -2,7 +2,7 @@
 
 #----------------------------------------------------------------------
 # Fast bidirectional synchronization for QRESYNC-capable IMAP servers
-# Copyright © 2015-2018 Guilhem Moulin <guilhem@fripost.org>
+# Copyright © 2015-2019 Guilhem Moulin <guilhem@fripost.org>
 #
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -79,11 +79,11 @@ my $CONF = do {
                , database => qr/\A(\P{Control}+)\z/
                , logfile => qr/\A(\/\P{Control}+)\z/
                , 'list-mailbox' => qr/\A([\x01-\x09\x0B\x0C\x0E-\x7F]+)\z/
-               , 'list-select-opts' => qr/\A([\x21\x23\x24\x26\x27\x2B-\x5B\x5E-\x7A\x7C-\x7E]+)\z/
+               , 'list-select-opts' => qr/\A([\x20\x21\x23\x24\x26\x27\x2B-\x5B\x5E-\x7A\x7C-\x7E]*)\z/
                , 'ignore-mailbox' => qr/\A([\x01-\x09\x0B\x0C\x0E-\x7F]+)\z/
                );
 };
-my ($DBFILE, $LOGGER_FD);
+my ($DBFILE, $LOGGER_FD, %LIST);
 
 {
     $DBFILE = $CONF->{_}->{database} if defined $CONF->{_};
@@ -104,6 +104,31 @@ my ($DBFILE, $LOGGER_FD);
     elsif ($CONFIG{debug}) {
         $LOGGER_FD = \*STDERR;
     }
+
+    $LIST{mailbox} = [@ARGV];
+    if (!defined $COMMAND or $COMMAND eq 'repair') {
+        if (!@ARGV and defined (my $v = $CONF->{_}->{'list-mailbox'})) {
+            my @mailbox;
+            do {
+                if ($v =~ s/\A[\x21\x23-\x27\x2A-\x5B\x5D-\x7A\x7C-\x7E]+//p) {
+                    push @mailbox, ${^MATCH};
+                } elsif ($v =~ s/\A\"((?:
+                            [\x20\x21\x23-\x5B\x5D-\x7E] |              # the above plus \x20\x28\x29\x7B
+                            (?:\\(?:[\x22\x5C0abtnvfr] | x\p{AHex}{2})) # quoted char or hex-encoded pair
+                        )+)\"//x) {
+                    push @mailbox, $1 =~ s/\\(?:[\x22\x5C0abtnvfr]|x\p{AHex}{2})/"\"${^MATCH}\""/greep;
+                }
+            } while ($v =~ s/\A\s+//);
+            die "Invalid value for list-mailbox: ".$CONF->{_}->{'list-mailbox'}."\n" if $v ne "";
+            $LIST{mailbox} = \@mailbox;
+        }
+        $LIST{'select-opts'} = uc($CONF->{_}->{'list-select-opts'})
+            if defined $CONF->{_}->{'list-select-opts'} and $CONF->{_}->{'list-select-opts'} ne "";
+        $LIST{params} = [ "SUBSCRIBED" ]; # RFC 5258 - LIST Command Extensions
+        push @{$LIST{params}}, "STATUS (UIDVALIDITY UIDNEXT HIGHESTMODSEQ)"
+            # RFC 5819 - Returning STATUS Information in Extended LIST
+            unless $CONFIG{notify};
+    }
 }
 my $DBH;
 
@@ -227,20 +252,6 @@ logger(undef, ">>> $NAME $VERSION");
 #############################################################################
 # Connect to the local and remote IMAP servers
 
-my $LIST = '"" ';
-my @LIST_PARAMS;
-my %LIST_PARAMS_STATUS = (STATUS => [qw/UIDVALIDITY UIDNEXT HIGHESTMODSEQ/]);
-if (!defined $COMMAND or $COMMAND eq 'repair') {
-    $LIST  = '('.uc($CONF->{_}->{'list-select-opts'}).') '.$LIST if defined $CONF->{_}->{'list-select-opts'};
-    $LIST .= (defined $CONF->{_}->{'list-mailbox'} ? '('.$CONF->{_}->{'list-mailbox'}.')' : '*') unless @ARGV;
-    @LIST_PARAMS = ('SUBSCRIBED');
-    push @LIST_PARAMS, map { "$_ (".join(' ', @{$LIST_PARAMS_STATUS{$_}}).")" } keys %LIST_PARAMS_STATUS
-        unless $CONFIG{notify};
-}
-$LIST .= $#ARGV == 0 ? Net::IMAP::InterIMAP::quote($ARGV[0])
-       : ('('.join(' ',map {Net::IMAP::InterIMAP::quote($_)} @ARGV).')') if @ARGV;
-
-
 foreach my $name (qw/local remote/) {
     my %config = %{$CONF->{$name}};
     $config{$_} = $CONFIG{$_} foreach grep {defined $CONFIG{$_}} qw/quiet debug/;
@@ -257,7 +268,21 @@ foreach my $name (qw/local remote/) {
     die "Non LIST-STATUS-capable IMAP server.\n" if !$CONFIG{notify} and $client->incapable('LIST-STATUS');
 }
 
-@{$IMAP->{$_}}{qw/mailboxes delims/} = $IMAP->{$_}->{client}->list($LIST, @LIST_PARAMS) for qw/local remote/;
+# List mailboxes; don't return anything but update $IMAP->{$name}->{mailboxes} and
+# $IMAP->{$name}->{delims}
+sub list_mailboxes($) {
+    my $name = shift;
+    my $list = "";
+    $list .= "(" .$LIST{'select-opts'}. ") " if defined $LIST{'select-opts'};
+    $list .= "\"\" ";
+    my @mailboxes = @{$LIST{mailbox}} ? map {Net::IMAP::InterIMAP::quote($_)} @{$LIST{mailbox}} : "*";
+    $list .= $#mailboxes == 0 ? $mailboxes[0] : "(".join(" ", @mailboxes).")";
+    my ($mbx, $delims) = $IMAP->{$name}->{client}->list($list, @{$LIST{params} // []});
+    $IMAP->{$name}->{mailboxes} = $mbx;
+    $IMAP->{$name}->{delims}    = $delims;
+}
+
+list_mailboxes($_) for qw/local remote/;
 
 
 ##############################################################################
@@ -1239,7 +1264,7 @@ while (1) {
 
         sleep $CONFIG{watch};
         # refresh the mailbox list and status
-        @{$IMAP->{$_}}{qw/mailboxes delims/} = $IMAP->{$_}->{client}->list($LIST, @LIST_PARAMS) for qw/local remote/;
+        list_mailboxes($_) for qw/local remote/;
         @MAILBOXES = sync_mailbox_list();
     }
 }
index 4d85eafa1aa4fadde9ef92b4e1a0003cc6ebcc04..a230c092776a42ad942e05caa22a80cb67365284 100644 (file)
@@ -82,10 +82,10 @@ the *list-mailbox*, *list-select-opts* and *ignore-mailbox* options from
 the [configuration file](#configuration-file) can be used to shrink that
 list and save bandwidth.
 However if some extra argument are provided on the command line,
-`interimap` ignores said options and synchronizes the given
+`interimap` ignores these options and synchronizes the given
 *MAILBOX*es instead.  Note that each *MAILBOX* is taken “as is”; in
 particular, it must be [UTF-7 encoded][RFC 2152], unquoted, and the list
-wildcards ‘\*’ and ‘%’ are not expanded.
+wildcards ‘\*’ and ‘%’ are passed verbatim to the IMAP server.
 
 If the synchronization was interrupted during a previous run while some
 messages were being replicated (but before the `UIDNEXT` or
@@ -219,12 +219,16 @@ Valid options are:
 :   A space separated list of mailbox patterns to use when issuing the
     initial `LIST` command (overridden by the *MAILBOX*es given as
     command-line arguments).
-    Note that each pattern containing special characters such as spaces
-    or brackets (see [RFC 3501] for the exact syntax) must be quoted.
+    Names containing special characters such as spaces or brackets need
+    to be enclosed in double quotes.  Within double quotes C-style
+    backslash escape sequences can be used (‘\\t’ for an horizontal tab,
+    ‘\\n’ for a new line, ‘\\\\’ for a backslash, etc.), as well as
+    hexadecimal escape sequences ‘\\xHH’.
     Furthermore, non-ASCII names must be [UTF-7 encoded][RFC 2152].
-    Two wildcards are available: a ‘\*’ character matches zero or more
-    characters, while a ‘%’ character matches zero or more characters up
-    to the mailbox's hierarchy delimiter.
+    Two wildcards are available, and passed verbatim to the IMAP server:
+    a ‘\*’ character matches zero or more characters, while a ‘%’
+    character matches zero or more characters up to the hierarchy
+    delimiter.
     This option is only available in the default section.
     (The default pattern, `*`, matches all visible mailboxes on the
     server.)