#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Std;

my %Opts;
getopts('cdDu:', \%Opts);

my %flagmap = (
  0 => "\\Answered",
  1 => "\\Flagged",
  2 => "\\Deleted",
  3 => "\\Draft",
  4 => "\\Seen",
 30 => "[UNLINKED]",
 31 => "[EXPUNGED]",
);

my $file = shift || die "Usage: $0 <indexfile>\n";
my $cfile = $file;
my $hfile = $file;
$cfile =~ s/index$/cache/;
$hfile =~ s/index$/header/;
unless (-f $file) {
  require "ME/User.pm";
  require "ME/Machine.pm";
  my $User = ME::User->new_find($file, NoResolveUser => 1, AllowJustUserName => 1);
  my $Slot;
  foreach my $S (ME::Machine->ImapSlots()) {
    next unless $S->Store->Name() eq $User->ImapStore->Name();
    $Slot = $S;
    last;
  }
  my $folder = shift;
  my $Path = $Slot->ImapdConf->GetUserLocation('meta', $User->CyrusName(), 'default', $folder);
  my $DPath = $Slot->ImapdConf->GetUserLocation('spool', $User->CyrusName(), 'default', $folder);

  $file = "$Path/cyrus.index";
  $cfile = "$Path/cyrus.cache";
  $cfile = "$DPath/cyrus.cache" unless (-f $cfile);
  $hfile = "$Path/cyrus.header";
}
use Cyrus::IndexFile;
use Cyrus::CacheFile;
use Cyrus::HeaderFile;
my $index = Cyrus::IndexFile->new_file($file);
my $cache;
if ($Opts{c}) {
  $cache = Cyrus::CacheFile->new_file($cfile);
}
my $headerfile = Cyrus::HeaderFile->new_file($hfile);
my $header = $index->header();
unless ($Opts{u}) {
  if ($Opts{d}) {
    print $index->header_dump() . "\n";
  } elsif ($Opts{D}) {
    print $index->header_longdump() . "\n";
  } else {
    $header->{NumRecords} ||= $header->{Exists};
    print "V:$header->{MinorVersion} E:$header->{Exists} N:$header->{NumRecords} U:$header->{LastUid} M:$header->{HighestModseq}\n";
  }
}
while (my $r = $index->next_record) {
  next if ($Opts{u} and $Opts{u} != $r->{Uid});
  if ($Opts{d}) {
    print $index->record_dump() . "\n";
  }
  elsif ($Opts{D}) {
    print $index->record_longdump();
    if ($headerfile) {
      my $flags = $index->flags_arrayref($headerfile);
      print "FLAGS: @$flags\n";
    }
    print "\n";
  }
  elsif ($header->{MinorVersion} == 9) {
    print "$r->{Uid} $r->{MessageUuid} $r->{Size}\n";
  }
  elsif ($header->{MinorVersion} < 13) {
    my $flags = flags($r);
    print "$r->{Uid}\@$r->{Modseq} $r->{MessageGuid} $r->{Size} ($flags)\n";
  }
  else {
    my $flags = flags($r);
    printf "$r->{Uid}\@$r->{Modseq} $r->{MessageGuid} $r->{CID} $r->{Size} ($flags)\n";
  }
  if ($Opts{c}) {
    $cache->offset($r->{CacheOffset});
    my $r = $cache->next_record();
    print $cache->print_record($r);   
    print "------------------------------------------------\n";
  }
}

sub flags {
  my $r = shift;
  my @res;
  foreach my $key (sort { $a <=> $b } keys %flagmap) {
    if (substr($r->{SystemFlags}, 31 - $key, 1) eq '1') {
      push @res, $flagmap{$key};
    }
  }
  return join(' ', @res);
}
