#!/usr/bin/perl -w use strict; use FindBin; use lib "$FindBin::RealBin/../lib"; use Curses::UI; use Curses; use Net::POP3; use Mail::Header; use Mail::Address; my $cui = new Curses::UI ( -clear_on_exit => 1 ); my $pop3 = undef; my $connection = undef; # We do not want STDERR to clutter our screen. open STDERR, ">/dev/null"; # ---------------------------------------------------------------------- # setup(): Setup the connection # ---------------------------------------------------------------------- sub check_connection($;) { my $buttons = shift; my $conwin = $buttons->parent; my $cui = $conwin->root; foreach my $key ('username','password','host','port') { my $obj = $conwin->getobj($key); my $value = $obj->get; $connection->{$key} = $value; # TODO: focus back to entry does not seem to # move the cursor with it. if ($value =~ /^\s*$/) { $cui->error("Missing value for $key field"); $obj->focus; return; } } return 1; } sub setup_connection() { my $conwin = $cui->add( 'connection_window', 'Window', -border => 1, -ipad => 2, -height => 15, -width => 60, -centered => 1, -title => "POP3 connection", ); $conwin->add( 'host_label', 'Label', -x => 0, -y => 0, -width => 13, -textalignment => 'right', -text => 'POP3 host :', ); $conwin->add( 'host', 'TextEntry', -x => 14, -y => 0, -text => 'pop', ); $conwin->add( 'port_label', 'Label', -x => 0, -y => 2, -width => 13, -textalignment => 'right', -text => 'POP3 port :', ); $conwin->add( 'port', 'TextEntry', -x => 14, -y => 2, -regexp => '/^\d*$/', -text => '110', ); $conwin->add( 'username_label', 'Label', -x => 0, -y => 4, -width => 13, -textalignment => 'right', -text => 'Username :', ); $conwin->add( 'username', 'TextEntry', -x => 14, -y => 4, -text => getpwuid($>), ); $conwin->add( 'password_label', 'Label', -x => 0, -y => 6, -width => 13, -textalignment => 'right', -text => 'Password :', ); $conwin->add( 'password', 'TextEntry', -x => 14, -y => 6, -password => '*', -text => '', )->focus; my $buttons = $conwin->add( 'buttons', 'Buttonbox', -x => 14, -y => 8, -buttons => [ { -label => '< Connect >', -onpress => sub { my $this = shift; if (check_connection($this)) { if (pop3_connect()) { $this->parent->loose_focus; } } }, }, { -label => '< Quit >', -onpress => sub {exit} }, ], ); $conwin->modalfocus; $cui->delete('connection_window') } # ---------------------------------------------------------------------- # pop3_connect(): Connect to the POP3 server and exit if it fails # ---------------------------------------------------------------------- sub pop3_connect() { $cui->progress( -message => "Connecting to the POP3 server...", -max => 4, -pos => 1, ); my $error = 0; $pop3 = Net::POP3->new( $connection->{host}, Port => $connection->{port}, Timeout => 0, ); if (not $pop3) { $error++; $cui->error("Could not connect to " ."$connection->{host}:$connection->{port}"); } $cui->setprogress(2, "Sending username..."); if (not $error and not defined $pop3->user($connection->{username})) { $error++; my $err = $pop3->message(); chomp $err; $cui->error("Sending USER failed:\n$err"); } $cui->setprogress(3, "Sending password..."); if (not $error and not defined $pop3->pass($connection->{password})) { $error++; my $err = $pop3->message(); chomp $err; $cui->error("Sending PASS failed:\n$err"); } if (not $error) { $cui->setprogress(4, "Connection successful!"); sleep 1; } $cui->noprogress; return !$error; } # ---------------------------------------------------------------------- # The inbox screen # ---------------------------------------------------------------------- sub build_inbox() { my $list = $pop3->list(); my @ids = sort {$a<=>$b} keys %$list; my $msg = "Retrieving headers"; $cui->progress( -max => scalar(@ids), -message => $msg, ); my @values = (); my %labels = (); my $progress_pos = 0; foreach my $n (@ids) { my $lines = $pop3->top($n, 0); my $header = new Mail::Header($lines); # Add value push @values, $n; # Add label my $subject = $header->get('Subject'); my $from = $header->get('From'); my $addr = new Mail::Address($from); my $name = substr($addr->name, 0, 15); $labels{$n} = sprintf("%4d", $n) . " | " . sprintf("%15s", $name) . " | " . $header->get('Subject'); $cui->setprogress( ++$progress_pos, $msg . ": message $progress_pos of " . scalar(@ids) ); } $cui->noprogress; my $listwin = $cui->add('list_window', 'Window'); my $ml = $listwin->add( 'message_list', 'Listbox', -values => \@values, -labels => \%labels, -vscrollbar => 1, -border => 1, -ipad => 1, -title => ' view message Quit from program', ); $ml->set_binding(sub{exit(0)}, "\cC", "\cQ"); $ml->set_routine('option-select', \&view_message); } # ---------------------------------------------------------------------- # view_message(): callback routine for the inbox list # ---------------------------------------------------------------------- sub view_message() { my $this = shift; # Get the selected message id. $this->{-selected} = $this->{-ypos}; my $id = $this->get; $this->{-selected} = undef; # Retrieve the message from the POP3 server. $cui->status("Retrieving message $id from the POP3 server..."); my $lines = $pop3->get($id); unless (ref $lines) { # Maybe the connection went away. Reconnect and try again. $pop3->close; unless (pop3_connect()) { $cui->error("Fatal error: Could not reconnect\n" . "to the POP3 server."); exit(1); } $lines = $pop3->get($id); } unless (ref $lines) { $cui->error("Failed to retrieve message $id\n" ."from the POP3 server.\n" ."Even after reconnecting"); exit_program(); } $cui->nostatus; # Create the viewer window. my $viewwin = $cui->add('view_window', 'Window'); my $tv = $viewwin->add( 'textviewer', 'TextViewer', -text => join("", @$lines), -vscrollbar => 1, -wrapping => 1, -border => 1, -ipad => 1, -title => ' return to inbox : Quit from program', ); $viewwin->set_binding(sub{ shift()->loose_focus }, KEY_ENTER()); $viewwin->set_binding(sub{exit(0)}, "\cC", "\cQ"); $viewwin->modalfocus; $cui->delete('view_window'); $cui->draw; } # ---------------------------------------------------------------------- # Clean exit # ---------------------------------------------------------------------- END { $pop3->quit if defined $pop3 } # ---------------------------------------------------------------------- # The main program # ---------------------------------------------------------------------- setup_connection(); build_inbox(); $cui->mainloop;