# vim: set cindent expandtab ts=4 sw=4:
#
# Copyright (c) 1998-2005 Chi-Keung Ho. All rights reserved.
#
# This programe is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# ExtMan - web interface to manage virtual accounts
# $Id$
package Ext::MgrApp::Signup;
use strict;
use Exporter;
use vars qw(@ISA @EXPORT);
@ISA = qw(Exporter Ext::MgrApp);
use POSIX qw(strftime);
use Ext::Utils; # import url2str
use Ext::MgrApp;
use Ext::CaptCha;
use vars qw($lang_charset %lang_signup);
use Ext::Lang;
use Fcntl qw(:flock);
sub init {
my $self = shift;
$self->register;
$self->SUPER::init(@_);
return unless($self->valid||$self->permit);
$self->add_methods(step1 => \&step1);
$self->add_methods(step2 => \&step2);
$self->add_methods(do_signup => \&do_signup);
$self->{default_mode} = 'step1';
$self->_initme;
$self->{tpl}->assign( DOMAIN => $self->{query}->cgi('domain') );
$self;
}
sub _initme {
initlang($_[0]->{sysconfig}->{'SYS_LANG'}, __PACKAGE__);
$_[0]->{tpl}->assign( lang_charset => $lang_charset );
$_[0]->{tpl}->assign( \%lang_signup );
}
sub check {
my $self = shift;
my $q = $self->{query};
my $tpl = $self->{tpl};
my $mgr = $self->{backend};
my $domain = $q->cgi('domain');
if (!$domain) {
$tpl->assign( ERROR => $lang_signup{'err_domain'} );
return;
}
my $info = $mgr->get_domain_info($domain);
if (!$info) {
$tpl->assign( ERROR => sprintf($lang_signup{'err_nosuch_domain'}, $domain) );
return;
}
if (!$info->{can_signup}) {
$tpl->assign( ERROR => sprintf($lang_signup{'err_nosignup'}, $domain) );
return;
}
$self->{_curinfo} = $info;
}
sub user_cfm_info {
my $self = shift;
my $sys = $self->{sysconfig};
my ($account, $tname, $idcard) = @_;
my $file = $sys->{SYS_VALIDATION_FILE} || "$sys->{SYS_CONFIG}/reg_validation.txt";
my $buf;
open (FD, "< $file") or die $!;
flock (FD, LOCK_EX);
while (<FD>) {
chomp;
my @m = split(/\s+/, $_);
next unless $m[1] eq $account && $m[2] eq $tname && $m[3] eq $idcard;
$buf = \@m;
last;
}
flock (FD, LOCK_UN);
return $buf;
}
sub toggle_user_status {
my $self = shift;
my $sys = $self->{sysconfig};
my ($account, $tname, $idcard) = @_;
my $file = $sys->{SYS_VALIDATION_FILE} || "$sys->{SYS_CONFIG}/reg_validation.txt";
my @lines;
open (FD, " < $file") or die $!;
flock (FD, LOCK_EX);
while (<FD>) {
chomp;
my @m = split(/\s+/, $_);
$m[0] = 1 if ($m[1] eq $account && $m[2] eq $tname && $m[3] eq $idcard);
push @lines, \@m;
}
flock (FD, LOCK_UN);
close FD;
open (FD, "> $file.tmp") or die $!;
flock (FD, LOCK_EX);
for my $line (@lines) {
print FD join("\t", @$line) . "\n";
}
close FD;
flock (FD, LOCK_UN);
rename ("$file.tmp", $file);
}
sub step1 {
my $self = shift;
my $mgr = $self->{backend};
my $q = $self->{query};
my $tpl = $self->{tpl};
$self->check;
$tpl->assign( STEP1 => 1);
}
sub step2 {
my $self = shift;
my $mgr = $self->{backend};
my $q = $self->{query};
my $tpl = $self->{tpl};
my ($user, $domain) = (lc $q->cgi('username'), lc $q->cgi('domain'));
my $account = $q->cgi('id1');
my $tname = $q->cgi('tname');
my $idcard = $q->cgi('idcard');
$tpl->assign(
ID1 => $account,
IDCARD => $idcard,
TNAME => $tname,
NAME => $tname,
);
if (!$self->check) {
$tpl->assign(STEP1 => 1);
return 0;
}
if (!$self->sanity_username($user)) {
$tpl->assign(ERROR => $lang_signup{'bad_username'});
$tpl->assign(DOMAIN => $domain);
$tpl->assign(STEP1 => 1);
return 0;
}
if ($mgr->get_user_info("$user\@$domain")) {
$tpl->assign(ERROR => sprintf($lang_signup{'user_exist'}, $user));
$self->step1;
return 0;
}
if (!$account or !$tname or !$idcard) {
$tpl->assign( ERROR => '个人资料输入不齐全');
$self->step1;
return;
}
if (my $buf = $self->user_cfm_info($account, $tname, $idcard)) {
if ($buf->[0] == 1) {
$tpl->assign( ERROR => '您已经注册过邮箱了!');
$self->step1;
return;
}
} else {
$tpl->assign( ERROR => '您输入的个人资料不正确!' );
$self->step1;
return;
}
$tpl->assign(
STEP2 => 1,
USERNAME => $user,
SUCCESS => sprintf($lang_signup{hint_can_signup}, "$user"),
);
}
sub do_signup {
my $self = shift;
my $tpl = $self->{tpl};
my $mgr = $self->{backend};
my $q = $self->{query};
my $multiplier = $self->{sysconfig}->{SYS_QUOTA_MULTIPLIER} || '1048576';
my ($user, $domain) = (lc $q->cgi('username'), lc $q->cgi('domain'));
my $sys = $self->{sysconfig};
my $account = $q->cgi('id1');
my $tname = $q->cgi('tname');
my $idcard = $q->cgi('idcard');
$tpl->assign(
ID1 => $account,
IDCARD => $idcard,
TNAME => $tname,
);
# recall step 1 again
$self->check;
if (!$self->sanity_username($user)) {
$tpl->assign(ERROR => $lang_signup{'bad_username'});
$tpl->assign(STEP1 => 1); # goto step1
$tpl->assign(DOMAIN => $domain);
return 0;
}
if (!$account or !$tname or !$idcard) {
$tpl->assign( ERROR => '个人资料输入不齐全');
$self->step1;
return;
}
my $cfm_info = $self->user_cfm_info($account, $tname, $idcard);
if ($cfm_info) {
if ($cfm_info->[0] == 1) {
$tpl->assign( ERROR => '您已经注册过邮箱了!');
return;
}
} else {
$tpl->assign( ERROR => '提交表单的用户信息有错!' );
return;
}
if ($mgr->get_user_info("$user\@$domain")) {
$tpl->assign(ERROR => sprintf($lang_signup{'user_exist'}, $user));
$self->step1;
return 0;
} else {
# new add user
my $info = $self->{_curinfo}; # XXX current domain info structure
my $pwd1 = $q->cgi('passwd1');
my $pwd2 = $q->cgi('passwd2');
$tpl->assign(
NAME => $q->cgi('cn') || $tname,
DOMAIN => $domain,
USERNAME => $user,
);
# include all possible state:
# 1) pwd1 null, pwd2 not null
# 2) pwd2 null, pwd1 not null
# 3) pwd2 and pwd1 not null, but not eq
# 4) pwd1 null, pwd2 null
if ( (!$pwd1 and !$pwd2) or ($pwd1 ne $pwd2) ) {
$tpl->assign(ERROR => $lang_signup{'errinput_passwd'});
$tpl->assign(STEP2 => 1);
return 0;
}
if (!$q->cgi('cn')) {
$tpl->assign(ERROR => $lang_signup{'errinput_cn'});
$tpl->assign(STEP2 => 1);
return 0;
}
if ($sys->{SYS_CAPTCHA_ON}) {
my $data = $q->get_cookie('scode');
my $raw = $q->cgi('vcode'); # verify code
my $key = $sys->{SYS_CAPTCHA_KEY} || 'extmail';
my $cap = Ext::CaptCha->new(key => $key);
if (!$cap->verify($raw, $data)) {
$tpl->assign(ERROR => $lang_signup{'err_vcode'}||'Bad verify Code');
$tpl->assign(STEP2 => 1);
return 0;
}
}
my $rc = $self->domain_overusage(
domain => $domain,
quota => $info->{default_quota} || $self->num2quota(5*$multiplier),
user => 1, # new add, must exists
ndquota => $info->{default_ndquota} || $self->num2quota(5*$multiplier),
);
my $d_hashdir = $self->get_domain_hashdir($domain);
my $u_hashdir = $self->gen_user_hashdir;
my $path;
if ($sys->{SYS_ISP_MODE} eq 'yes') {
$path = ($d_hashdir ? "$d_hashdir/" : "").
"$domain/" .($u_hashdir? "$u_hashdir/" : "").
$user;
} else {
$path = "$domain/$user";
}
my $uid = $sys->{SYS_DEFAULT_UID};
my $gid = $sys->{SYS_DEFAULT_GID};
my $expire = $self->cvt2expire(
strftime("%Y-%m-%d %H:%M:%S", localtime),
$info->{default_expire},
);
$rc = $mgr->add_user(
mail => "$user\@$domain",
domain => $domain,
uid => $user,
cn => $q->cgi('cn'),
uidnumber => $uid,
gidnumber => $gid,
# new user attributes here
create => strftime("%Y-%m-%d %H:%M:%S", localtime),
expire => $expire,
passwd => $pwd1,
quota => $info->{default_quota} || $self->num2quota(5*$multiplier),
maildir => "$path/Maildir/",
homedir => $path,
netdiskquota => $info->{default_ndquota} || $self->num2quota(5*$multiplier),
active => 1,
disablepwdchange => 0,
disablesmtpd => $info->{disablesmtpd} ? 1 : 0,
disablesmtp => $info->{disablesmtp} ? 1 : 0,
disablewebmail => $info->{disablewebmail} ? 1 : 0,
disablenetdisk => $info->{disablenetdisk} ? 1 : 0,
disablepop3 => $info->{disablepop3} ? 1 : 0,
disableimap => $info->{disableimap} ? 1 : 0,
) unless ($rc);
if ($rc) {
$tpl->assign(ERROR => sprintf($lang_signup{'add_fail'}, "$user\@$domain").$rc);
} else {
$tpl->assign(SUCCESS => sprintf($lang_signup{'add_ok'}, "$user\@$domain"));
my $dir = $sys->{SYS_CONFIG};
my $base = $sys->{SYS_MAILDIR_BASE};
system("$dir/tools/maildirmake.pl $base/$path/Maildir/");
$tpl->assign(STEP3 => 1);
$self->toggle_user_status($cfm_info->[1], $cfm_info->[2], $cfm_info->[3]);
}
}
}
sub pre_run { 1 }
sub post_run {
my $template = $_[0]->{query}->cgi('screen') || 'signup.html';
$_[0]->{tpl}->process($template);
$_[0]->{tpl}->print;
}
1;
syntax highlighted by Code2HTML, v. 0.9.1