Mail::Summary::Tools::CLI::Create - Create or update a summary file from mailboxes
Index
Code Index:
NAME

Mail::Summary::Tools::CLI::Create - Create or update a summary file from mailboxes
SYNOPSIS

DESCRIPTION

#!/usr/bin/perl
package Mail::Summary::Tools::CLI::Create;
use base qw/Mail::Summary::Tools::CLI::Command/;
use strict;
use warnings;
use DateTime::Format::DateManip;
use DateTime::Infinite;
use Class::Autouse (<<'#\'END_USE' =~ m!(\w+::[\w:]+)!g);
#\
use Mail::Box::Manager;
use Mail::Summary::Tools::Summary;
use Mail::Summary::Tools::Summary::List;
use Mail::Summary::Tools::Summary::Thread;
use Mail::Summary::Tools::ThreadFilter;
#'END_USE
use Mail::Summary::Tools::ThreadFilter::Util qw/
get_root_message guess_mailing_list
thread_root last_in_thread any_in_thread all_in_thread
negate
mailing_list_is in_date_range
/; # subject_matches
sub usage_desc {
"%c create %o summary.yaml mailbox [mailbox2]\n".
"%c create \%o -o summary.yaml -i mailbox -i mailbox2"
}
use constant options => (
[ 'input|i=s@' => "Mailboxes to read from (can be used several times)" ],
[ 'output|o=s' => "Summary file to write" ],
[ 'update|u!' => "Update an existing summary" ],
[ 'from|f=s' => "From date (any string Date::Manip can parse)" ],
[ 'to|t=s' => "To date (any string Date::Manip can parse)" ],
[ 'list|l=s@' => "Only posts in this list (can be used several times)" ],
#[ 'subject|s=s' => "subject" ], # TODO
[ 'posters|p!' => "Collect information about posters (defaults to true)", { default => 1 } ],
[ 'dates|d!' => "Collect information about dates (defaults to true)", { default => 1 } ],
#[ 'm|match=s' => "match" ], # TODO
[ 'clean|c!' => "Scrub the thread subjects" ],
[ 'rt|r!' => "Collect information about RT tickets (defaults to true)", { default => 1 } ],
);
sub construct_filters {
my $self = shift;
return (
$self->construct_date_filter,
$self->construct_list_filter,
$self->construct_subject_filter,
);
}
sub construct_date_filter {
my $self = shift;
my $opt = $self->{opt};
my $from = DateTime::Format::DateManip->parse_datetime( $opt->{from} || return );
my $to = DateTime::Format::DateManip->parse_datetime( $opt->{to} || return );
if ( defined($from) || defined($to) ) {
$from = DateTime::Infinite::Past->new unless defined($from);
$to = DateTime::Infinite::Future->new unless defined($to);
return $self->comb_filter( in_date_range( $from, $to ) );
} else {
die "From or to date specification is invalid\n";
}
}
sub construct_list_filter {
my $self = shift;
if ( my $list = $self->{opt}{list} ) {
return $self->comb_filter( mailing_list_is($list) );
} else {
return;
}
}
sub construct_subject_filter {
return;
}
sub comb_filter {
my ( $self, $filter ) = @_;
any_in_thread( $filter );
}
sub filter {
my ( $self, @params ) = @_;
my $f = Mail::Summary::Tools::ThreadFilter->new(
filters => [ $self->construct_filters ],
);
return $f->filter(@params);
}
sub clean_subject {
my ( $self, $subject ) = @_;
return $subject unless $self->{opt}{clean};
$subject =~ s/^\s*(?:Re|Fwd):\s*//i;
$subject =~ s/^\s*\[[\w-]+\]\s*//; # remove [Listname] munging
$subject =~ s/^\s*|\s*$//g; # strip whitespace
return $subject;
}
sub validate {
my ( $self, $opt, $args ) = @_;
$self->{opt} = $opt;
@$args and $opt->{$_} ||= shift @$args for qw/output/;
push @{ $opt->{input} ||= [] }, @$args; @$args = ();
unless ( $opt->{output} and @{ $opt->{input} } ) {
$self->usage_error("Please specify a summary output file and at least one mail box for input.");
}
}
sub run {
my ( $self, $opt, $args ) = @_;
my @folders = @{ $opt->{input} };
my $summary_out = $opt->{output};
if ( -f $summary_out and !$opt->{update} ) {
die "The output file '$summary_out' exists. Either remove it or specify the --update option\n";
}
my $summary = -f $summary_out
? Mail::Summary::Tools::Summary->load( $summary_out )
: Mail::Summary::Tools::Summary->new;
$self->diag("loading and threading mailboxes: @folders");
my $mgr = Mail::Box::Manager->new;
my $threads = $mgr->threads(
folders => [ map { $mgr->open( folder => $_ ) } @folders ],
timespan => 'EVER',
window => 'ALL',
( $self->app->global_options->{verbose} ? (trace => "PROGRESS") : ()),
);
my %lists = map { $_->name => $_ } $summary->lists;
my %seen;
$self->filter( threads => $threads, callback => sub {
my $thread = shift;
my $root = get_root_message($thread);
return if $seen{$root->messageId}++;
my $list_name = eval { guess_mailing_list($root)->listname };
my $list_key = $list_name || "unknown";
my $list = $lists{$list_key} ||= do {
my $list = Mail::Summary::Tools::Summary::List->new( $list_name ? (name => $list_name) : () );
$summary->add_lists( $list );
$list;
};
my $summarized_thread = Mail::Summary::Tools::Summary::Thread->from_mailbox_thread( $thread,
collect_posters => $opt->{posters},
collect_dates => $opt->{dates},
collect_rt => $opt->{dates},
process_subject => sub { $self->clean_subject(shift) },
);
#$summarized_thread->extra->{ .... } = { ... }
if ( my $existing = $summary->get_thread_by_id( $summarized_thread->message_id ) ) {
my $was_out_of_date = $existing->extra->{out_of_date};
$existing->merge( $summarized_thread );
$self->diag($summarized_thread->message_id . " is now out of date") if !$was_out_of_date and $existing->extra->{out_of_date};
} else {
$self->diag($summarized_thread->message_id . " has been added to the summary");
$list->add_threads( $summarized_thread );
}
});
$self->diag( "found threads in the mailing lists: @{[ map { $_->name || '<unknown>' } values %lists ]}" );
$summary->save( $summary_out );
}
__PACKAGE__;
__END__