package MH; use Mail::Internet; our %profile; sub croak { require Carp; goto &Carp::croak; } # Return an object for the specifed message # If $folder is omitted, it defaults to the current folder # $class indicates the class in which the object is to be created; # it must support a 'new' method which expects a filehandle argument sub _msg_obj { my ($class, $n, $folder) = @_; my $file = mhpath($folder, $n); local *F; open F, "<", $file or croak "Couldn't read message $n in $folder: $!"; $class->new(\*F); } # Return a Mail::Internet object for the specifed message sub message { _msg_obj('Mail::Internet', @_); } # Return a Mail::Header object for the specifed message sub header { _msg_obj('Mail::Header', @_); } # Return list of message numbers in the specified folder sub message_list { my $folder = shift; my $dir = _mkabs($folder); local *D; opendir D, $dir or croak "Couldn't open folder '+$folder': $!"; my @r = grep /^\d+$/, readdir D } # Return list of all messages in the specified folder # (list of Mail::Internet objects) sub messages { my $folder = shift; my @r = map message($_, $folder), message_list($folder); } # Return list of all headers in the specified folder # (list of Mail::Header objects) sub messages { my $folder = shift; my @r = map header($_, $folder), message_list($folder); } # Return path to specified message, or # if message number argument omitted, to specified folder. # If folder is omitted, default to current folder sub mhpath { my ($folder, $n) = @_; $folder = current_folder() unless defined $folder; my $dir = _mkabs($folder); defined $n ? "$dir/$n" : $dir; } # Return name of current folder sub current_folder { my %c = context(); $c{'Current-Folder'} || croak("Couldn't find current folder"); } # Return contents of context file as hash sub context { my $cf = context_file(); local *CF; open CF, "<", $cf or croak "Couldn't open context file '$cf': $!; aborting"; my %c; while () { chomp; my ($k, $v) = split /:\s*/, $_, 2; $c{$k} = $v; } wantarray ? %c : \%c; } # Return name of context file sub context_file { return $ENV{MHCONTEXT} if defined $ENV{MHCONTEXT}; profile(); $context = $profile{context} || _mkabs('context'); } # Return contents of profile as hash sub profile { if (%profile) { return wantarray ? %profile : \%profile; } my $profile = profile_filename(); open P, "<", $profile or croak "Couldn't open profile file $profile: $!; aborting"; local $_; my $next_line =

; while (defined $next_line) { my $cur_line = $next_line; $next_line =

; next if $cur_line =~ /^#/; while ($next_line =~ /^[ \t]/) { $cur_line .= $next_line; $next_line =

; } my ($key, $value) = split /:\s*/, $cur_line, 2; chomp $value; $profile{$key} = $value; } return wantarray ? %profile : \%profile; } my $profile; # Return profile filename sub profile_filename { $profile ||= $ENV{MH} || home_dir() . "/.mh_profile"; } # Return MH directory path my $MH_DIR; sub mh_dir { return $MH_DIR if defined $MH_DIR; profile(); my $path = $profile{Path} || croak "Profile $profile does not define 'Path' component\n"; $MH_DIR = _mkabs($path, home_dir()); } my $HOME; # Return home directory path sub home_dir { $HOME ||= $ENV{HOME} || (getpwuid($<))[7] || croak "Couldn't determine home directory\n"; } # convert $path argument to absolute path # If not already absolute, $path is interpreted relative to # current user's MH directory, or relative to $dir if $dir is supplied. sub _mkabs { my $path = shift; my $dir = shift || mh_dir(); $path =~ m{^/} ? $path : "$dir/$path"; } 1;