aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2019-05-16 01:05:25 +0200
committerGuilhem Moulin <guilhem@fripost.org>2019-05-27 00:07:30 +0200
commit7d50d83ab52148285c642158bd57bdd18a1ee6d4 (patch)
tree59ea2f247292d59ce8e5a2341165a5d6be440092
parentb59e3b1416c54a2ce8be7f4aaa9c04ff52ff65a9 (diff)
interimap: accept C-style escape sequences in 'list-mailbox'.
This is useful for defining names containing control characters (incl. \0 for unspecified hierarchy delimiter).
-rw-r--r--Changelog6
-rwxr-xr-xinterimap63
-rw-r--r--interimap.md18
3 files changed, 61 insertions, 26 deletions
diff --git a/Changelog b/Changelog
index f261a98..209bb25 100644
--- 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
diff --git a/interimap b/interimap
index fa65241..8aeaba4 100755
--- 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();
}
}
diff --git a/interimap.md b/interimap.md
index 4d85eaf..a230c09 100644
--- a/interimap.md
+++ b/interimap.md
@@ -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.)