
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 (<CF>) {
    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 = <P>;
  while (defined $next_line) {
    my $cur_line = $next_line;
    $next_line = <P>;
    next if $cur_line =~ /^#/;
    while ($next_line =~ /^[ \t]/) {
      $cur_line .= $next_line;
      $next_line = <P>;
    }
    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;
