The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Net::IMAP::Server::Command::List;

use warnings;
use strict;

use base qw/Net::IMAP::Server::Command/;

use Encode;
use Encode::IMAPUTF7;

sub validate {
    my $self = shift;

    return $self->bad_command("Log in first") if $self->connection->is_unauth;

    my @options = $self->parsed_options;
    return $self->bad_command("Not enough options") if @options < 2;
    return $self->bad_command("Too many options") if @options > 2;

    return 1;
}

sub run {
    my $self = shift;

    my ( $root, $search ) = $self->parsed_options;

    # In the special case of a query for the delimiter, give them our delimiter
    if ( $search eq "" ) {
        my $sep = (defined $self->connection->model->root->separator)
            ? q{"}.$self->connection->model->root->separator.q{"} : "NIL";
        $self->tagged_response( qq|(\\Noselect) $sep ""| );
    } else {
        my $sep = $self->connection->model->root->separator;
        $search = quotemeta($search);
        $search =~ s/\\\*/.*/g;
        if (defined $sep) {
            $search =~ s/\\%/[^$sep]*/g;
        } else {
            $search =~ s/\\%/.*/g;
        }
        my $regex = qr{^\Q$root\E$search$};
        $self->connection->model->root->update_tree;
        $self->traverse( $self->connection->model->root, $regex );
    }

    $self->ok_completed;
}

sub list_out {
    my $self = shift;
    my $node = shift;
    my @props = @_;

    my $str = $self->data_out([map {\$_} @props]) . " "
        . $self->data_out($self->connection->model->root->separator) . " "
        . $self->data_out(Encode::encode('IMAP-UTF-7',$node->full_path));
    $self->tagged_response($str);
}

sub traverse {
    my $self  = shift;
    my $node  = shift;
    my $regex = shift;

    my @props;
    push @props, @{$node->children} ? '\HasChildren' : '\HasNoChildren';
    push @props, '\Noinferiors' unless defined $self->connection->model->root->separator;
    push @props, '\Noselect' unless $node->is_selectable;

    $self->list_out($node, @props) if $node->parent and 
        Encode::encode('IMAP-UTF-7',$node->full_path) =~ $regex;
    $self->traverse( $_, $regex ) for @{ $node->children };
}

1;