Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1215 → Rev 1214

/hostadmiral/trunk/backend/backend.pl
6,7 → 6,6
#
 
# FIXME use transactions
# FIXME validate all information
 
use strict;
use vars;
60,20 → 59,17
my $code_db_connect_error = 501;
my $code_db_error = 502;
my $code_db_close_error = 503;
my $code_db_inconsistent = 504;
 
# == internal global variables =================
 
my %handlers;
my $database_connection;
my $database_in_use = 0;
 
sub connection_loop
{
# listen for connections
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or return $!;
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1) or return $!;
bind(SERVER, sockaddr_in($port, inet_aton($host))) or return $!;
socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die "$!\n";
setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1) or die "$!\n";
bind(SERVER, sockaddr_in($port, inet_aton($host))) or die "$!\n";
listen(SERVER, 1);
 
while(1) {
107,7 → 103,6
 
# close the port
close SERVER;
return undef;
}
 
sub handle_request
114,7 → 109,7
{
my $request = shift @_;
 
log_debug("Handle request [\n" . strip_request_password($request->{'body'}) . "]");
log_debug("Handle request [\n$request->{'body'}]");
 
my @lines = split /\n/, $request->{'body'}, -1;
my $cur = 0;
203,7 → 198,6
set_request_code($request, $code_ignored, "Not interesting in users");
}
 
# FIXME: merge with handle_domain_modify
sub handle_domain_create
{
my $request = shift @_;
233,8 → 227,6
my %params = parse_command_params($request, shift @_, ("oldName", "name"));
return unless(%params);
 
# FIXME: move maildirs, update users and aliases tables
 
my $res_action = save_to_db($request, "transport",
{ domain => $params{"oldName"} },
{ domain => $params{"name"}, comment => $params{"comment"},
256,8 → 248,6
my %params = parse_command_params($request, shift @_, ("name"));
return unless(%params);
 
# FIXME: delete maildirs, update users and aliases tables (or they are already deleted by frontend?)
 
my $res_action = delete_from_db($request, "transport",
{ domain => $params{"name"} } );
 
282,30 → 272,6
{
}
 
sub update_mailbox_mailid
{
my $request = shift @_;
my $id = shift @_;
my $login = shift @_;
my $domain = shift @_;
 
return 1 unless($id);
 
my $res_action2 = save_to_db($request, "users",
{ login => "$login\@$domain" },
{ mailid => "$id\@$domain" });
return 0 if($res_action2 eq "error");
 
my $res_action3 = save_to_db($request, "aliases",
{ alias => "$id\@$domain", rcpt => "$id\@$domain" },
{ alias => "$id\@$domain", rcpt => "$id\@$domain",
comment => "loop for $login\@$domain" } );
return 0 if($res_action3 eq "error");
 
return 1;
}
 
# FIXME: merge with handle_mailbox_modify
sub handle_mailbox_create
{
my $request = shift @_;
313,8 → 279,6
("login", "password", "domain"));
return unless(%params);
 
# insert or update main information
my $id;
my $res_action = save_to_db($request, "users",
{ login => "$params{'login'}\@$params{'domain'}" },
{ login => "$params{'login'}\@$params{'domain'}",
322,15 → 286,10
maildir => "$params{'domain'}/$params{'login'}/",
expired => ($params{"enabled"} eq "true" ? 0 : 1),
comment => $params{"comment"},
uid => ($params{"systemUser"} ? $params{"systemUser"} : undef) },
\$id);
uid => ($params{"systemUser"} ? $params{"systemUser"} : undef) } );
 
# set mailid for the new record
return unless(update_mailbox_mailid($request, $id, $params{'login'}, $params{'domain'}));
# FIXME mailid?
 
# FIXME create an empty maildir
 
# result
if($res_action eq 'update') {
set_request_code($request, $code_ok_but, "Mailbox exists, modified");
}
348,8 → 307,6
 
# FIXME move the old maildir
 
# insert or update main information
my $id;
my $res_action = save_to_db($request, "users",
{ login => "$params{'oldLogin'}\@$params{'oldDomain'}" },
{ login => "$params{'login'}\@$params{'domain'}",
357,13 → 314,8
maildir => "$params{'domain'}/$params{'login'}/",
expired => ($params{"enabled"} eq "true" ? "0" : "1"),
comment => $params{"comment"},
uid => ($params{"systemUser"} ? $params{"systemUser"} : undef) },
\$id);
uid => ($params{"systemUser"} ? $params{"systemUser"} : undef) } );
 
# set mailid for the new record
return unless(update_mailbox_mailid($request, $id, $params{'login'}, $params{'domain'}));
 
# result
if($res_action eq 'update') {
set_request_code($request, $code_ok, "Mailbox modified");
}
380,26 → 332,9
 
# FIXME remove the maildir
 
# get mailid
my $dbh = db_begin($request);
return unless($dbh);
 
my $select_sth = $dbh->prepare("select mailid from users where login=?");
$select_sth->execute("$params{'login'}\@$params{'domain'}");
my $mail_id = $select_sth->fetchrow_array();
db_end();
unless($mail_id) {
set_request_code($request, $code_db_inconsistent, "Cannot find mailid");
return;
}
 
# clear db
my $res_action = delete_from_db($request, "users",
{ login => "$params{'login'}\@$params{'domain'}" } );
 
my $res_action2 = delete_from_db($request, "aliases", { alias => $mail_id } );
return if($res_action2 eq "error");
 
if($res_action eq 'delete') {
set_request_code($request, $code_ok, "Mailbox deleted");
}
408,58 → 343,6
}
}
 
sub save_mail_alias_dest
{
my $request = shift @_;
my $address = shift @_;
my $domain = shift @_;
my $comment = shift @_;
my $rcpts = shift @_;
 
# try to find mailboxes with given names
my $select_sql = "select login, mailid from users where login in (";
my $param_count = 0;
foreach my $rcpt (@$rcpts) {
$select_sql .= "," unless($param_count++ == 0);
$select_sql .= "?";
}
$select_sql .= ")";
 
my $dbh = db_begin($request);
return unless($dbh);
 
my $select_sth = $dbh->prepare($select_sql);
$param_count = 0;
foreach my $rcpt (@$rcpts) {
$select_sth->bind_param(++$param_count, $rcpt);
}
 
$select_sth->execute || return 0;
my @row;
while(@row = $select_sth->fetchrow_array()) {
my $login = $row[0];
my $mailid = $row[1];
foreach my $rcpt (@$rcpts) {
if($rcpt eq $login) {
$rcpt = $mailid;
}
}
}
db_end();
 
# save
foreach my $rcpt (@$rcpts) {
log_debug("save $rcpt");
my $res_action = save_to_db($request, "aliases",
undef,
{ alias => "$address\@$domain",
rcpt => $rcpt, comment => $comment } );
return 0 if($res_action eq "error");
}
 
return 1;
}
 
sub handle_mail_alias_create
{
my $request = shift @_;
471,8 → 354,14
{ alias => "$params{'address'}\@$params{'domain'}" } );
return if($del_action eq "error");
 
return unless(save_mail_alias_dest($request, $params{'address'}, $params{'domain'},
$params{'comment'}, \@rcpts));
foreach my $rcpt (@rcpts) {
log_debug("save $rcpt");
my $res_action = save_to_db($request, "aliases",
undef,
{ alias => "$params{'address'}\@$params{'domain'}",
rcpt => $rcpt, comment => $params{"comment"} } );
return if($res_action eq "error");
}
 
if($del_action eq 'delete') {
set_request_code($request, $code_ok_but, "Mail alias exists, modified");
493,8 → 382,16
{ alias => "$params{'address'}\@$params{'domain'}" } );
return if($del_action eq "error");
 
return unless(save_mail_alias_dest($request, $params{'address'}, $params{'domain'},
$params{'comment'}, \@rcpts));
foreach my $rcpt (@rcpts) {
log_debug("save $rcpt");
my $res_action = save_to_db($request, "aliases",
undef,
{ alias => "$params{'address'}\@$params{'domain'}",
rcpt => $rcpt, comment => $params{"comment"} } );
return if($res_action eq "error");
}
# FIXME add the loopback destination? handle "a@domain.com => a@domain.com"
# as "a@domain.com => _something_@domain.com + _something_@domain.com => _something_@domain.com" ?
 
if($del_action eq 'delete') {
set_request_code($request, $code_ok, "Mail alias modified");
521,17 → 418,6
}
}
 
sub validate_domain
{
$_ = shift @_;
return /^(([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)\.)*([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)$/
? 1 : 0;
}
 
sub validate_name
{
}
 
sub decode_param
{
my $value = shift @_;
593,61 → 479,42
 
sub db_connect
{
eval {
$database_connection = DBI->connect($db_url, $db_user, $db_password);
};
my $request = shift @_;
my $dbh = undef;
 
eval { $dbh = DBI->connect($db_url, $db_user, $db_password); };
if($@) {
$database_connection = undef;
return $@;
set_request_code($request, $code_db_connect_error, $@);
$dbh = undef;
}
 
return undef;
return $dbh;
}
 
sub db_close
{
eval {
$database_connection->disconnect() if($database_connection);
};
}
my $request = shift @_;
my $dbh = shift @_;
my $error = shift @_;
my $no_error = 1;
 
sub db_begin
{
my $request = shift @_;
 
# connect if not yet connection
unless($database_connection) {
log_info("No DB connection, try to connect");
my $error = db_connect();
unless($database_connection) {
set_request_code($request, $code_db_connect_error, $error);
return undef;
}
if($error) {
set_request_code($request, $code_db_error, $error);
$no_error = 0;
}
 
# verify connection and reconnect if needed
eval {
$database_connection->selectrow_array("select 1");
$dbh->disconnect() if($dbh);
};
if($database_connection->state eq "S1000") {
log_info("Lost DB connection, try to reconnect");
my $error = db_connect();
unless($database_connection) {
set_request_code($request, $code_db_connect_error, $error);
return undef;
}
 
if($@ && $no_error) {
set_request_code($request, $code_db_close_error, $@);
$no_error = 0;
}
 
$database_in_use = 1;
return $database_connection;
return $no_error;
}
 
sub db_end
{
$database_in_use = 0;
}
 
sub delete_from_db
{
my $request = shift @_;
655,9 → 522,10
my $key_columns = shift @_;
 
my $res_action = 'none';
my $dbh = db_begin($request);
return unless($dbh);
my $dbh = db_connect($request);
 
return 'error' unless($dbh);
 
eval {
my $sql = "";
while(my ($key, $value) = each(%$key_columns)) {
684,8 → 552,12
}
};
 
db_end();
return $res_action;
if(db_close($request, $dbh, $@)) {
return $res_action;
}
else {
return 'error';
}
}
 
sub save_to_db
694,15 → 566,13
my $table = shift @_;
my $key_columns = shift @_;
my $value_columns = shift @_;
my $last_id_ref = shift @_;
 
$$last_id_ref = 0 if($last_id_ref);
 
my $error_set = 0;
my $res_action = 'none';
my $dbh = db_begin($request);
return unless($dbh);
my $dbh = db_connect($request);
 
return 'error' unless($dbh);
 
eval {
my $res = 0;
 
773,24 → 643,20
$insert_sth->bind_param(++$count, $value);
}
 
$res = $insert_sth->execute;
$res_action = 'insert';
$$last_id_ref = $dbh->selectrow_array("select LAST_INSERT_ID()") if($last_id_ref);
$res = $insert_sth->execute;
$res_action = 'insert';
}
};
# FIXME handle exceptions?
# FIXME handle exceptions?
 
db_end();
return $res_action;
if(db_close($request, $dbh, $@)) {
return $res_action;
}
else {
return 'error';
}
}
 
sub strip_request_password
{
$_ = shift @_;
s/^password=.*$/password=*****/gm;
return $_;
}
 
sub set_request_code
{
my $request = shift @_;
800,8 → 666,7
$request->{'code'} = $code;
$request->{'response'} = $message;
 
my $error = "Error $code '$message' in request [\n"
. strip_request_password($request->{'body'}) . "]";
my $error = "Error $code '$message' in request [\n$request->{'body'}]";
if($code >= 500 && $code < 600) {
log_error($error);
}
858,25 → 723,19
$handlers{"${mail_alias_header}_${create_action}"} = \&handle_mail_alias_create;
$handlers{"${mail_alias_header}_${modify_action}"} = \&handle_mail_alias_modify;
$handlers{"${mail_alias_header}_${delete_action}"} = \&handle_mail_alias_delete;
 
return undef;
}
 
sub main
{
my $error;
#my $sth = $dbh->prepare("SELECT * FROM transport");
#$sth->execute();
#while(my $ref = $sth->fetchrow_hashref()) {
# print "id = $ref->{'id'}\n";
#}
#$sth->finish();
 
$error = init();
die "Cannot init: $error\n" if($error);
 
# connect now to show any error to admin
$error = db_connect();
die "Cannot connect to DB: $error\n" if($error);
 
$error = connection_loop();
 
db_close();
die "Cannot listen for connections: $error\n" if($error);
init();
connection_loop();
}
 
main();