#!/usr/bin/perl

# Copyright (C) Florian Weimer <fw@deneb.enyo.de>
# Released under the GPL (version 2 or later, at your choice)

# Converts a nnml folder to a maildir folder.  Messages which are
# already present in the maildir folder are skipped.

use strict;
use warnings;

use File::Copy;
use File::Path;
use Digest::MD5;

if (@ARGV != 2) {
    die "usage: $0 FROM-DIR TO-DIR\n";
}

my ($fromdir, $todir) = @ARGV;

my $hostname = `hostname`;
$hostname =~ tr/a-zA-Z._-//cd;

my $deliveries = 0;
my $start_time = time;

sub maildir_name () {
    $deliveries++;
    return "$start_time.${$}_$deliveries.$hostname";
}

unless (-d $fromdir && -x $fromdir && -r $fromdir) {
    die "$fromdir: not a readable directory\n";
}

sub hash_file ($) {
    my $name = shift;
    my $ctx = Digest::MD5->new;

    open FILE, "<$name"
	or die "$name: open failed: $!\n";
    $ctx->addfile(*FILE);
    close FILE;

    return $ctx->hexdigest;
}

my %existing;
if (-e $todir) {
    unless (-d "$todir/cur" && -d "$todir/new" && -d "$todir/tmp") {
	die "$todir: not a maildir directory\n";
    }
    for my $dir ("$todir/new", "$todir/cur") {
	opendir MAILDIR, $dir
	    or die "$todir: not a maildir directory\n";
	for my $nam (sort readdir MAILDIR) {
	    my $name = "$dir/$nam";
	    next if -d $name;
	    my $hash = hash_file ($name);
	    $existing{$hash}++;
	}
    }

} else {
    for my $dir ("$todir", "$todir/cur", "$todir/new", "$todir/tmp") {
	mkpath $dir or die "$dir: could not create directory: $!\n";
    }
}

opendir NNML, $fromdir 
    or die "opendir: $!\n";
my @message_names = sort readdir NNML;
closedir NNML;

print STDERR "$fromdir: converting to $todir\n";

my $count = 0;
my $total = @message_names;
my $copied = 0;
my $ignored = 0;
my $special = 0;
my $skipped = 0;
for my $message_name (@message_names) {
    $count++;
    print STDERR "$count/$total\r" if ($count % 10) == 0;

    # Silently ignore special files.
    if ($message_name =~ /^\.(|\.|marks|overview)$/) {
	$special++;
	next;
    }

    if ($message_name =~ /^[0-9]+$/) {
	my $new_name = maildir_name;
	my $old_hash = hash_file "$fromdir/$message_name";
	if ($existing{$old_hash}) {
	    $skipped++;
	    next;
	}
	copy "$fromdir/$message_name", "$todir/tmp/$new_name"
	    or die ("$fromdir/$message_name: cannot copy to "
		    . "$todir/tmp/$new_name: $!\n");
	rename "$todir/tmp/$new_name", "$todir/new/$new_name"
	    or die ("$todir/$new_name: cannot rename to "
		    . "$todir/tmp/$new_name: $!\n");
	$copied++;
    } else {
	print STDERR "$fromdir/$message_name: illegal file name, ignored\n";
	$ignored++;
    }
}
print STDERR "$todir: $total files processed, $copied converted, "
    . "$skipped skipped, $ignored ignored, $special special.\n";

