Gmail IMAP implements a XLIST extension that allows a client to
determine which folders to use for functions such as Trash, Drafts,
Sent, etc. Attached is a patch that adds two methods, "xlist" to handle
the raw XLIST command, and "special_folders" as a user-friendly way to
determine a mapping of "standard" folder types to actual folder names.
Subject: | xlist.diff |
diff --git a/lib/Mail/IMAPClient.pm b/lib/Mail/IMAPClient.pm
index bda613d..2c6bc92 100644
--- a/lib/Mail/IMAPClient.pm
+++ b/lib/Mail/IMAPClient.pm
@@ -477,6 +477,12 @@ sub _list_or_lsub {
sub list { shift->_list_or_lsub( "LIST", @_ ) }
sub lsub { shift->_list_or_lsub( "LSUB", @_ ) }
+sub xlist {
+ my ( $self ) = @_;
+ return undef unless $self->has_capability("XLIST");
+ shift->_list_or_lsub( "XLIST", @_ );
+}
+
sub _folders_or_subscribed {
my ( $self, $method, $what ) = @_;
my @folders;
@@ -531,6 +537,28 @@ sub folders {
return wantarray ? @folders : \@folders;
}
+sub special_folders {
+ my ( $self ) = @_;
+ my $xlist = $self->xlist;
+ return undef unless defined $xlist;
+
+ my $special_re = qr/\A\\(Inbox|AllMail|Trash|Drafts|Sent|Spam|Starred)\Z/;
+
+ my %specials;
+
+ for my $resp (@$xlist) {
+ my $rec = $self->_list_or_lsub_response_parse($resp);
+ next unless defined $rec->{name};
+ for my $attr (@{$rec->{attrs}}) {
+ if ($attr =~ $special_re) {
+ $specials{$1} = $rec->{name};
+ }
+ }
+ }
+
+ return wantarray ? %specials : \%specials;
+}
+
sub subscribed {
my ( $self, $what ) = @_;
my @folders = $self->_folders_or_subscribed( "lsub", $what );
@@ -1771,7 +1799,7 @@ sub _disconnect {
$self;
}
-# LIST or LSUB Response
+# LIST/XLIST or LSUB Response
# Contents: name attributes, hierarchy delimiter, name
# Example: * LIST (\Noselect) "/" ~/Mail/foo
# NOTE: in _list_response_preprocess we append literal data so we need
@@ -1784,10 +1812,10 @@ sub _list_or_lsub_response_parse {
$resp =~ s/\015?\012$//;
if (
- $resp =~ / ^\* \s+ (?:LIST|LSUB) \s+ # * LIST or LSUB
- \( ([^\)]*) \) \s+ # (attrs)
- (?: \" ([^"]*) \" | NIL ) \s # "delimiter" or NIL
- (?:\s*\" (.*) \" | (.*) ) # "name" or name
+ $resp =~ / ^\* \s+ (?:LIST|XLIST|LSUB) \s+ # * LIST or XLIST or LSUB
+ \( ([^\)]*) \) \s+ # (attrs)
+ (?: \" ([^"]*) \" | NIL ) \s # "delimiter" or NIL
+ (?:\s*\" (.*) \" | (.*) ) # "name" or name
/ix
)
{
diff --git a/lib/Mail/IMAPClient.pod b/lib/Mail/IMAPClient.pod
index 1e44874..4868a9d 100644
--- a/lib/Mail/IMAPClient.pod
+++ b/lib/Mail/IMAPClient.pod
@@ -1269,6 +1269,75 @@ Notice that if you just want to list a folder's subfolders (and not
the folder itself), then you need to include the hierarchy separator
character (as returned by the L</separator> method).
+=head2 special_folders
+
+Example:
+
+ my $specials = $imap->special_folders
+ or die "Could not get special folders.\n";
+
+IMAP servers implementing the XLIST extension (such as Gmail) designate
+particular folders to be used for particular functions. This is useful
+in the case where you want to know which folder should be used for Trash
+when the actual folder name can't be predicted (eg in the case of Gmail,
+the folder names change depending on the user's locale settings).
+
+The B<special_folders> method returns a hash listing any "special"
+folder names, with the values listing the actual folders that should be
+used for those names. For example, using this method with a Gmail user
+using the English (US) locale might give this output from
+L<Data::Dumper>:
+
+ $VAR1 = {
+ 'Inbox' => 'Inbox',
+ 'AllMail' => '[Gmail]/All Mail',
+ 'Trash' => '[Gmail]/Trash',
+ 'Drafts' => '[Gmail]/Drafts',
+ 'Sent' => '[Gmail]/Sent Mail',
+ 'Spam' => '[Gmail]/Spam',
+ 'Starred' => '[Gmail]/Starred'
+ };
+
+The same list for a user using the French locale might look like this:
+
+ $VAR1 = {
+ 'Inbox' => 'Bo&AO4-te de r&AOk-ception',
+ 'AllMail' => '[Gmail]/Tous les messages',
+ 'Trash' => '[Gmail]/Corbeille',
+ 'Drafts' => '[Gmail]/Brouillons',
+ 'Sent' => '[Gmail]/Messages envoy&AOk-s',
+ 'Spam' => '[Gmail]/Spam',
+ 'Starred' => '[Gmail]/Suivis'
+ };
+
+Mail::IMAPClient recognises the following "special" folder names:
+
+=over 4
+
+=item Inbox
+
+=item AllMail
+
+=item Trash
+
+=item Drafts
+
+=item Sent
+
+=item Spam
+
+=item Starred
+
+=back
+
+These are currently the only ones supported by Gmail. The XLIST
+extension is not documented, and there are no other known
+implementations other than Gmail, so this list is based on what Gmail
+provides.
+
+If the server does not support the XLIST extension, this method returns
+undef.
+
=head2 has_capability
Example: