In draft-daboo-imap-annotatemore-08 (the last draft which defined the GETANNOTATION command) all attribute names have a ".priv" and a ".shared" suffix.
Extend Cyrus::IMAP::Admin::getinfo and Cyrus::IMAP::Shell::info to request and print "value.priv" in addition to "value.shared" attributes (should be identical to requesting "value"). additionally: - GETANNOTATION responses changed slightly with 2.5: mailbox and value may be QTEXT instead of qstring. For the time being only accept the QTEXT value NIL. - Add GETANNOTATION response examples to Cyrus::IMAP::Admin::getinfo to make it a bit easier to dissect the non-trivial regular expressions used to process the imap server responses. - In the else-clause the wrong backreference was used to extract the length of the value. - Do not quote '"' inside regular expressions because that's not required. - "next" does not work in callbacks and confuses imclient and/or perl without visible feedback in cyradm. --- perl/imap/IMAP/Admin.pm | 69 +++++++++++++++++++++++++++++++++++++------------ perl/imap/IMAP/Shell.pm | 35 +++++++++++++++---------- 2 files changed, 74 insertions(+), 30 deletions(-) diff --git a/perl/imap/IMAP/Admin.pm b/perl/imap/IMAP/Admin.pm index 1a6c1eb..42cd660 100644 --- a/perl/imap/IMAP/Admin.pm +++ b/perl/imap/IMAP/Admin.pm @@ -721,37 +721,74 @@ sub getinfo { # but since we send only the latest form command, # this is the only possible response. + # Regex 1 (Shared-Folder, user folder looks similar): + # cyrus imapd 2.5.0 + # folder "/vendor/cmu/cyrus-imapd/expire" ("value.shared" "90") + # 1 2 3 4 + # folder "/vendor/cmu/cyrus-imapd/pop3showafter" ("value.shared" NIL) + # 1 2 3 4 + # folder "/specialuse" ("value.priv" NIL "value.shared" NIL) + # 1 2 3 4 5 6 + + # cyrus imapd 2.4.17 + # "folder" "/vendor/cmu/cyrus-imapd/partition" ("value.shared" "default") + # 1 2 3 4 + + # cyrus imapd 2.2.13 + # "folder" "/vendor/cmu/cyrus-imapd/expire" ("value.shared" "90") + # 1 2 3 4 + + # Regex 1: server info + # cyrus imapd 2.5.0 + # "" "/comment" ("value.shared" "test") + # 1 2 3 4 + # "" "/motd" ("value.shared" NIL) + # 1 2 3 4 + # "" "/vendor/cmu/cyrus-imapd/expire" ("value.priv" NIL "value.shared" NIL) + # 1 2 3 4 5 6 + + # cyrus imapd 2.4.17 + # "" "/vendor/cmu/cyrus-imapd/freespace" ("value.shared" "3122744") + # 1 2 3 4 + + # Regex 2 + # cyrus imapd 2.5.0 (user folder, authorized as user) + # Note: two lines + # INBOX.Sent "/specialuse" ("value.priv" {5}\r\n + # \Sent)> + # 1 2 3 4\r\n + # 5 + if ($text =~ - /^\s*\"([^\"]*)\"\s+\"([^\"]*)\"\s+\(\"([^\"]*)\"\s+\"([^\"]*)\"\)/) { - # note that we require mailbox and entry to be qstrings - # Single annotation, not literal, - # but possibly multiple values - # however, we are only asking for one value, so... + /^\s*(?|"([^"]*)"|([^\s]+))\s+"([^"]*)"\s+\("([^"]*)"\s+(?|"([^"]*)"|(NIL))(?:\s+"([^"]*)"\s+(?|"([^"]*)"|(NIL)))*\)/) { my $key; if($1 ne "") { $key = "/mailbox/{$1}$2"; } else { $key = "/server$2"; } - $d{-rock}{$key} = $4; + $d{-rock}{$3}->{$key} = $4; + $d{-rock}{$5}->{$key} = $6 if (defined ($5) && defined ($6)); } elsif ($text =~ - /^\s*\"([^\"]*)\"\s+\"([^\"]*)\"\s+\(\"([^\"]*)\"\s+\{(.*)\}\r\n/) { - my $len = $3; - $text =~ s/^\s*\"([^\"]*)\"\s+\"([^\"]*)\"\s+\(\"([^\"]*)\"\s+\{(.*)\}\r\n//s; + /^\s*"([^"]*)"\s+"([^"]*)"\s+\("([^"]*)"\s+\{(.*)\}\r\n/ || + $text =~ + /^\s*([^\s]+)\s+"([^"]*)"\s+\("([^"]*)"\s+\{(.*)\}\r\n/) { + my $len = $4; + $text =~ s/^\s*"*([^"\s]*)"*\s+"([^"]*)"\s+\("([^"]*)"\s+\{(.*)\}\r\n//s; $text = substr($text, 0, $len); - # note that we require mailbox and entry to be qstrings # Single annotation (literal style), - # possibly multiple values - # however, we are only asking for one value, so... + # possibly multiple values -- multiple + # values not tested. + my $key; if($1 ne "") { $key = "/mailbox/{$1}$2"; } else { $key = "/server$2"; } - $d{-rock}{$1} = $text; + $d{-rock}{$3}->{$key} = $text; } else { - next; + ; # XXX: unrecognized line, how to notify caller? } }, -rock => \%info}); @@ -760,12 +797,12 @@ sub getinfo { my($rc, $msg); if(scalar(@entries)) { foreach my $annot (@entries) { - ($rc, $msg) = $self->send('', '', "GETANNOTATION %s %q \"value.shared\"", + ($rc, $msg) = $self->send('', '', 'GETANNOTATION %s %q ("value.priv" "value.shared")', $box, $annot); last if($rc ne 'OK'); } } else { - ($rc, $msg) = $self->send('', '', "GETANNOTATION %s \"*\" \"value.shared\"", + ($rc, $msg) = $self->send('', '', 'GETANNOTATION %s "*" ("value.priv" "value.shared")', $box); } $self->addcallback({-trigger => 'ANNOTATION'}); diff --git a/perl/imap/IMAP/Shell.pm b/perl/imap/IMAP/Shell.pm index 0240d41..05a12d4 100644 --- a/perl/imap/IMAP/Shell.pm +++ b/perl/imap/IMAP/Shell.pm @@ -1386,23 +1386,30 @@ sub _sc_info { # keep track of what mailboxes we've printed a header for already my %section = (); - foreach my $attrib (sort keys %info) { - # server metadata does not contain '{}' - my $sect = undef; - $sect = $1 if $attrib =~ /(\{.*\})/; - if(!defined($sect)) { - $sect = "Server Wide"; - } + my %attribname = (); + foreach my $attribname (sort keys %info) { + foreach my $attrib (sort keys %{$info{$attribname}}) { + # server metadata does not contain '{}' + my $sect = undef; + $sect = $1 if $attrib =~ /(\{.*\})/; + if(!defined($sect)) { + $sect = "Server Wide"; + } - if(!exists $section{$sect}) { - $section{$sect} = 'x'; - print "$sect:\n"; - } + if(!exists $section{$sect}) { + $section{$sect} = 'x'; + print "$sect:\n"; + } - $attrib =~ /([^\/]*)$/; - my $attrname = $1; + if(!exists $attribname{$attribname}) { + $attribname{$attribname} = 'x'; + print " $attribname:\n"; + } + $attrib =~ /([^\/]*)$/; + my $attrname = $1; - $lfh->[1]->print(" ", $attrname, ": ", $info{$attrib}, "\n"); + $lfh->[1]->print(" ", $attrname, ": ", $info{$attribname}->{$attrib}, "\n"); + } } 0; } -- 2.1.4