#!/usr/bin/env perl

## v0.06

use strict;

### Configuration variables

# Password file
my($passwd_file) = "/etc/passwd.imap";
my($passwd_file_bak) = "/etc/passwd.imap.bak";
# Base virtual domain
my($default_realm) = "domain.tld";
# ---
my($debug) = 1;
my($debug) = 0;

my($user);
print('user@domain: ');
if ($ARGV[0]) {
	$user = $ARGV[0];
} else {
	chomp($user = <STDIN>);
}
$user = lc($user);
$user .= "\@$default_realm" unless ($user =~ /\@/);
print("$user\n") if ($ARGV[0]);

my($word1, $word2);
if ($ARGV[1]) {
	$word1 = $ARGV[1];
} else {
	while (! $word1) {
		print "Password: ";
		system "stty -echo";
		chomp($word1 = <STDIN>);
		system "stty echo";
		print("\n");

		print "Retype password: ";
		system "stty -echo";
		chomp($word2 = <STDIN>);
		system "stty echo";
		print("\n");

		if ($word1 ne $word2) {
			print("Sorry, passwords do not match\n");
			$word1 = '';
		}
	}
}
my($salt) = join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
my($new_password) = crypt($word1, "\$1\$${salt}\$");

unless (open(PASSWD, "$passwd_file")) {
	print(STDERR "Couldn't open $passwd_file: $!\n");
} else {
	my(@passwd);
	unless (open(PASSWD_BAK, ">$passwd_file_bak")) {
		print(STDERR "Couldn't create $passwd_file_bak: $!\n");
	} else {
		my($exist, $line);
		while ($line = <PASSWD>) {
print("line read: $line") if ($debug);
			print(PASSWD_BAK $line);
			unless ($line =~ /^([^:]+):([^:]+):::([^:]*):[^:]+::/) {
				print("Unknown format: $line");
				push(@passwd, $line);
			} else {
				my($addr) = $1;
				my($pass) = $2;
				my($fullname) = $3;
				if ($addr eq $user) {
					# change password
					push(@passwd, sprintf("%s:{MD5}%s:::%s:/nonexistent::\n", $addr, $new_password, $fullname));
print("change password: ".$passwd[$#passwd]) if ($debug);
					$exist++;
				} else {
					push(@passwd, $line);
				}
			}
		}
		unless (close(PASSWD_BAK)) {
			print(STDERR "Couldn't save $passwd_file_bak: $!\n");
			close(PASSWD);
			exit(1);
		}
		unless ($exist) {
			my($fullname);
			if ($ARGV[2]) {
				$fullname = $ARGV[2];
			} else {
				print("Full name: ");
				chomp($fullname = <STDIN>);
			}
			push(@passwd, sprintf("%s:{MD5}%s:::%s:/nonexistent::\n", $user, $new_password, $fullname));
print("add user: ".$passwd[$#passwd]) if ($debug);
		}
	}
	close(PASSWD);
	unless (open(PASSWD, ">$passwd_file")) {
		print(STDERR "Couldn't truncate $passwd_file: $!\n");
	} else {
		print(PASSWD @passwd);
		print(STDERR "Couldn't save $passwd_file: $!
You may restore data from $passwd_file_bak") unless(close(PASSWD));
	}
}
