#!/usr/bin/perl
# This is used to let a guest register for an account on the moo.
#use Mooix::Thing;
#use Mooix::Root;
use Mooix::Conf;
use Text::Wrap;

sub expand {
	my $template=shift;
	%_=@_;

	$template=~s/\$\{?(\w+)\}?(?:->(\w+))?/_expand($1, $2, %_)/eg;
	return $template;
}

sub _expand {
	my $key=shift;
	my $field=shift;
	my %hash=@_;

	if (! exists $hash{$key}) {
		return "";
	}

	my $val;
	if (! $field) {
		$val = $hash{$key};
	}
	else {
		$val = $hash{$key}->safegetfield($field);
	}

	if (ref($val) eq 'Mooix::Thing') {
		return $val->prettyname;
	}
	else {
		return $val;
	}
}

sub emailbody {
	my $message=shift;
	my @body = split (/\n\n/, $message);
	my $body = '';
	foreach (@body) {
		s/\n/ /g;
		$body.=wrap('','', $_)."\n\n";
	}
	return $body;
}

run sub {
	my $this=shift;
	%_=@_;
	my $session=$_{session};
	
	# Make sure that this command is not spoofed, just in case.
        if ($_{avatar} != $this) {
		fail "No!"; 
	}
	
	if (! $this->register_ok) {
		fail "I'm sorry, but registration is currently not allowed for your user class.";
	}
	
	# I settled on Mail::Sendmail because eg, exim refuses to send mail from a
	# user account w/o an entry in the password file, and bin/mail is
	# historically insecure and buggy.
	eval "use Mail::Sendmail";
	if ($@) {
		fail "I'm sorry, but registration is currently not allowd, as Mail::SendMail is not installed.";
	}

	
	my %info;
	$info{mooinfo} = $Mooix::Root->system->mooinfo;
	$info{from} = 'Moo Admin <'.$Mooix::Conf::field{mooadmin}.'@'.
	              $info{mooinfo}->hostname.'>';

	# The first half of registration.
	if (! exists $_{quote}) {
		$session->write($this->regintro);
		
		my $ok=0;
		while (! $ok) {
			$info{name} = $session->prompt(prompt => $this->name_prompt." ", default => $info{name});
			my $uname = $info{name};
			if (! length $uname) {
				fail "Aborting on blank name.";
			}
			$uname =~ s/[^a-zA-Z0-9]//g;
			if (! length $uname) {
				$session->write("Invalid name, try again.");
				next;
			}
	
			$session->write($this->email_info);
			for (;;) {
				$info{email} = $session->prompt(prompt => $this->email_prompt." ", default => $info{email});
				if (! length $info{email}) {
					fail "Aborting on blank email.";
				}
				$info{email} =~ s/\s+//g;
				last if $info{email} =~ /^.+@.+\..+$/;
				$session->write("That doesn't look like a valid email address.")
			}

			$ok = $this->parser_parse_yesno(
					string => $session->prompt(
						prompt => $this->ok_prompt." ",
						completions => 'yes|no'));
		}

		# Come up with a password for them.
		my @letters=('a' .. 'z', 0 .. 9);
		for (1..8) {
			$info{password}.=$letters[rand $#letters];
		}
	
		# Add an item to the reglog.
		my $reglog=$Mooix::Root->system->reglog;
		$reglog->add(%info, regdate => time);
	
		# Generate and send mail.
		my %mail = (
			To => $info{email},
			From => $info{from},
			Subject => expand($this->email_subject, %info),
			Message => emailbody(expand(scalar $this->regemail, %info)),
		);
		sendmail(%mail) || fail("Failed to send mail: ".$Mail::Sendmail::error);
		$session->write(split("\n", expand(scalar $this->regwait, %info)));
	}
	else {
		$info{email}=$_{quote};
	}

	# The second half of registration.
	my $password = $session->password(prompt => $this->password_prompt." ");
	if (! length $password) {
		fail "Aborting on empty password. To try again: register \"$info{email}\"";
	}
	
	if (exists $info{password} && $password ne $info{password}) {
		fail "Sorry, that's not the password. To try again: register \"$info{email}\"";
	}
	$info{password}=$password;
	
	# So mooregister can be found.
	$ENV{PATH}=$Mooix::Conf::field{safepath};
	
	# This suid helper program takes care of making the account. It
	# outputs the username.
	$ENV{EMAIL}=$info{email};
	$ENV{PASSWORD}=$info{password};
	$info{username} = `mooregister`;
	chomp $info{username};
	if (($? >> 8) != 0 || ! length $info{username}) {
		fail "You entered the wrong password, or there was a problem adding the account.";
	}
	
	# Success!
	my $message = expand(scalar $this->regsuccess, %info);
	my %mail = (
		To => $info{email},
		From => $info{from},
		Subject => expand($this->email_subject, %info),
		Message => emailbody($message),
	);
	sendmail(%mail);
	$session->write(split("\n", $message));
}
