no warnings;
################################################################################
sub peer_get {
$_[1] -> {xls} = 0;
my $item = peer_query (@_);
$_REQUEST {__read_only} = $item -> {__read_only};
return $item;
}
################################################################################
sub peer_execute {
my $data = peer_query (@_);
return $_REQUEST {error} if $_REQUEST {error};
redirect ({action => '', id => $data -> {id}}, {kind => 'js'});
return undef;
}
################################################################################
sub peer_name {
$preconf -> {peer_name} or die "Peer name not defined\n";
return $preconf -> {peer_name};
}
################################################################################
sub peer_reconnect {
unless ($UA) {
our $UA = LWP::UserAgent -> new (
agent => "Eludia/$Eludia_VERSION (" . peer_name () . ")",
requests_redirectable => ['GET', 'HEAD', 'POST'],
);
# $HTTP::Request::Common::DYNAMIC_FILE_UPLOAD = 1;
}
}
################################################################################
sub peer_proxy {
my ($peer_server, $params) = @_;
my $url = $preconf -> {peer_servers} -> {$peer_server} or die "Peer server '$peer_server' not defined\n";
$_REQUEST {__peer_server} = $peer_server;
peer_reconnect ();
$url .= '?sid=';
$url .= $_REQUEST {sid};
my @keys = keys %$params;
foreach my $k (@keys) {
$url .= '&';
$url .= $k;
$url .= '=';
$url .= uri_escape ($params -> {$k});
}
my $request = HTTP::Request -> new ('GET', $url);
my $virgin = 1;
my $response = $UA -> request ($request,
sub {
if ($virgin) {
$r -> print ($r -> protocol);
$r -> print (" 200OK\015\012");
$r -> print ($_[1] -> headers_as_string);
$r -> print ("\015\012");
$virgin = 0;
}
$r -> print ($_[0]);
},
);
$_REQUEST {__response_sent} = 1;
}
################################################################################
sub peer_query {
my ($peer_server, $params, $options) = @_;
my $url = $preconf -> {peer_servers} -> {$peer_server} or die "Peer server '$peer_server' not defined\n";
peer_reconnect ();
foreach my $k (keys %_REQUEST) {
next if $k =~ /^__/ && $k ne '__edit';
next if exists $params -> {$k};
$params -> {$k} = ref $_REQUEST {$k} eq 'Math::FixedPrecision' ? $_REQUEST {$k} -> bstr () : $_REQUEST {$k};
}
$params -> {__d} = 1;
delete $params -> {select};
delete $params -> {xls};
my @headers = (Accept_Encoding => 'gzip');
$options -> {files} = [$options -> {file}] if $options -> {file};
if (ref $options -> {files} eq ARRAY) {
foreach my $name (@{$options -> {files}}) {
my $file = upload_file ({ name => $name, dir => 'upload/images'});
$params -> {'_' . $name} = [$file -> {real_path}, $params -> {'_' . $name}];
}
push @headers, (Content_Type => 'form-data');
}
my @args = ($url,
@headers,
Content => [ %$params ],
);
my $request = POST (@args);
my $response = $UA -> request ($request);
foreach my $k (keys %$params) {
my $v = $params -> {$k};
ref $v eq ARRAY or next;
unlink $v -> [0];
}
while (1) {
$response -> is_success or die ("Invalid response from $peer_server: " . $response -> status_line . "\n");
my $dump = $response -> content;
if ($response -> headers -> header ('Content-Encoding') eq 'gzip') {
$dump = Compress::Zlib::memGunzip ($dump);
}
eval $dump;
my ($root, $data) = (%$VAR1);
undef $VAR1;
$_REQUEST {__peer_server} = $peer_server;
if ($root eq 'data') {
return $data;
}
if ($root eq 'redirect') {
$response = $UA -> request (GET $url . $data -> {url} . '&__d=1',
Accept_Encoding => 'gzip',
);
}
elsif ($root eq 'error') {
$_REQUEST {error} = $data -> {message};
$_REQUEST {error} = '#' . $data -> {field} . '#:' . $_REQUEST {error} if $data -> {field};
return $_REQUEST {error};
}
else {
die ("Invalid response from $peer_server: '$dump'\n");
}
}
}
#############################################################################
sub fake_select {
return {
type => 'input_select',
name => 'fake',
values => [
{id => '0,-1', label => 'Все'},
{id => '-1', label => 'Удалённые'},
],
empty => 'Активные',
}
}
#############################################################################
sub ids {
my ($ar, $options) = @_;
$options -> {field} ||= 'id';
$options -> {empty} ||= '-1';
$options -> {idx} ||= {};
my $ids = $options -> {empty};
my $idx = $options -> {idx};
foreach my $i (@$ar) {
my $id = $i -> {$options -> {field}};
$id > 0 or next;
$ids .= ',';
$ids .= $id;
if (ref $idx eq HASH) {
$idx -> {$id} = $i;
}
elsif (ref $idx eq ARRAY) {
$idx -> [$id] = $i;
}
}
return wantarray ? ($ids, $idx) : $ids;
}
#############################################################################
sub is_off {
my ($options, $value) = @_;
return 0 unless $options -> {off};
if ($options -> {off} eq 'if zero') {
return ($value == 0);
}
elsif ($options -> {off} eq 'if not') {
return !$value;
}
else {
return $options -> {off};
}
}
################################################################################
sub async ($@) {
my ($sub, @args) = @_;
eval { &$sub (@args); };
print STDERR $@ if $@;
# sql_disconnect ();
# defined (my $child_pid = fork) or die "Cannot fork: $!\n";
# sql_reconnect ();
# return $child_pid if $child_pid;
# chdir '/' or die "Can't chdir to /: $!";
# close STDIN;
# close STDOUT;
# close STDERR;
# eval { &$sub (@args); };
# sql_disconnect ();
# CORE::exit ();
}
################################################################################
sub send_mail {
my ($options) = @_;
warn "send_mail: " . Dumper ($options);
my $to = $options -> {to};
##### Multiple recipients
if (ref $to eq ARRAY) {
foreach (@$to) {
$options -> {to} = $_;
send_mail ($options);
delete $options -> {href};
}
return;
}
##### To address
if (!ref $to && $to > 0) {
$to = sql_select_hash ("SELECT label, mail FROM $conf->{systables}->{users} WHERE id = ?", $to);
}
my $original_to;
if ($preconf -> {mail} -> {to}) {
$original_to = '' . Dumper ($to);
$to = $preconf -> {mail} -> {to};
}
my $real_to = $to;
if (ref $to eq HASH) {
$real_to = $to -> {mail};
$to = encode_mail_header ($to -> {label}, $options -> {header_charset}) . "<$real_to>";
}
unless ($real_to =~ /\@/) {
warn "send_mail: INVALID MAIL ADDRESS '$real_to'\n";
return;
}
##### From address
$options -> {from} ||= $preconf -> {mail} -> {from};
my $from = $options -> {from};
if (ref $from eq HASH) {
$from -> {mail} ||= $from -> {address};
$from = encode_mail_header ($from -> {label}, $options -> {header_charset}) . "<" . $from -> {mail} . ">";
}
##### Message subject
my $subject = encode_mail_header ($options -> {subject}, $options -> {header_charset});
##### Message body
$options -> {body_charset} ||= 'windows-1251';
$options -> {content_type} ||= 'text/plain';
if ($options -> {href}) {
my $server_name = $preconf -> {mail} -> {server_name} || $ENV{HTTP_HOST};
$options -> {href} =~ /^http/ or $options -> {href} = "http://$server_name" . $options -> {href};
}
if ($options -> {template}) {
our $DATA = $options -> {data} if $options -> {data};
$DATA -> {href} = $options -> {href};
$options -> {text} = fill_in_template ($options -> {template}, '', {no_print => 1});
undef $DATA if $options -> {data};
}
elsif ($options -> {href}) {
$options -> {href} = "
$$options{href}" if $options -> {content_type} eq 'text/html';
$options -> {text} .= "\n\n" . $options -> {href};
}
my $text = encode_base64 ($options -> {text} . "\n" . $original_to);
unless ($^O eq 'MSWin32') {
defined (my $child_pid = fork) or die "Cannot fork: $!\n";
return $child_pid if $child_pid;
}
##### connecting...
my $repeat = 10;
my $smtp = undef;
while ($repeat) {
$repeat--;
$smtp = Net::SMTP -> new ($preconf -> {mail} -> {host}, %{$preconf -> {mail} -> {options}});
$smtp or next;
if ($preconf -> {mail} -> {user}) {
$smtp -> auth ($preconf -> {mail} -> {user}, $preconf -> {mail} -> {password}) or die "SMTP AUTH error: " . $smtp -> code . ' ' . $smtp -> message;
}
last if $smtp;
}
unless (defined $smtp) {
warn "Can't connect to $preconf->{mail}->{host}\n";
return;
}
# $smtp -> mail ($ENV{USER});
$smtp -> mail ($options -> {from} -> {address});
$smtp -> to ($real_to);
$smtp -> data ();
##### sending main message
$smtp -> datasend (< {attach} = [$options -> {attach}] if ($options -> {attach} && ref $options -> {attach} ne ARRAY);
foreach my $attach (@{$options -> {attach}}) {
if (-f $attach -> {real_path}) {
my $type = $attach -> {type};
$type ||= 'application/octet-stream';
my $fn = $attach -> {file_name};
$fn ||= $attach -> {real_path};
$fn =~ s{.*[\\\/]}{};
$smtp -> datasend (< {real_path}) or die "Can't open $attach->{real_path}: $!";
while (read (FILE, $buf, 60*57)) {
$smtp -> datasend (encode_base64 ($buf));
}
close (FILE);
}
}
$smtp -> datasend (< dataend ();
$smtp -> quit;
unless ($^O eq 'MSWin32') {
CORE::exit (0);
}
}
################################################################################
sub encode_mail_header {
my ($s, $charset) = @_;
$charset ||= 'windows-1251';
if ($charset eq 'windows-1251') {
$s =~ y{АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя}{бвчздеіцъйклмнопртуфхжигюыэящшьасБВЧЗДЕЈЦЪЙКЛМНОПРТУФХЖИГЮЫЭЯЩШЬАС};
$charset = 'koi8-r';
}
$s = '=?' . $charset . '?B?' . encode_base64 ($s) . '?=';
$s =~ s{[\n\r]}{}g;
return $s;
}
################################################################################
sub b64u_freeze {
b64u_encode (
$Storable::VERSION ?
Storable::freeze ($_[0]) :
Dumper ($_[0])
);
}
################################################################################
sub b64u_thaw {
my $serialized = b64u_decode ($_[0]);
if ($Storable::VERSION) {
return Storable::thaw ($serialized);
}
else {
my $VAR1;
eval $serialized;
return $VAR1;
}
}
################################################################################
sub b64u_encode {
my $s = MIME::Base64::encode ($_[0]);
$s =~ y{+/=}{-_.};
$s =~ s{[\n\r]}{}gsm;
return $s;
}
################################################################################
sub b64u_decode {
my $s = $_ [0];
$s =~ y{-_.}{+/=};
return MIME::Base64::decode ($s);
}
################################################################################
sub require_fresh {
my ($module_name, $fatal) = @_;
check_systables ();
my $file_name = $module_name;
$file_name =~ s{(::)+}{\/}g;
my $inc_key = $file_name . '.pm';
$file_name =~ s{^(.+?)\/}{\/};
my $found = 0;
my $the_path = '';
foreach my $path (reverse (@$PACKAGE_ROOT)) {
my $local_file_name = $path . $file_name . '.pm';
-f $local_file_name or next;
$file_name = $local_file_name;
$found = 1;
$the_path = $path;
$the_path =~ s{[\\\/]*(Content|Presentation)}{};
last;
}
my $is_config = $file_name =~ /Config\.pm$/ ? 1 : 0;
$found or return "File not found: $file_name\n";
my $need_refresh = $preconf -> {core_spy_modules} || !$INC {$inc_key};
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $last_modified, $ctime, $blksize, $blocks);
if ($need_refresh && (!$is_config || !$CONFIG_IS_LOADED)) {
($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $last_modified, $ctime, $blksize, $blocks) = stat ($file_name);
my $last_load = $INC_FRESH {$module_name} + 0;
$need_refresh = $last_load < $last_modified;
}
if ($need_refresh) {
if ($_OLD_PACKAGE) {
open (S, $file_name);
my $src = join '', ();
close (S);
$src =~ s{package\s+$_OLD_PACKAGE}{package $_NEW_PACKAGE}g;
$src =~ s{$_OLD_PACKAGE\:\:}{$_NEW_PACKAGE\:\:}g;
eval $src;
}
else {
do $file_name;
}
die $@ if $@;
if ($is_config) {
check_systables ();
sql_assert_core_tables ();
}
if (
$is_config
&& $DB_MODEL
&& !exists $DB_MODEL -> {tables}
) {
my %tables = ();
tie %tables, Eludia::FileDumpHash, {path => $PACKAGE_ROOT -> [0] . '/Model'};
$DB_MODEL -> {tables} = \%tables;
$DB_MODEL -> {splitted} = 1;
}
if (
$db && (
!$CONFIG_IS_LOADED || (
$last_modified > 0 + sql_select_scalar (
"SELECT unix_ts FROM $conf->{systables}->{__required_files} WHERE file_name = ?",
$module_name
)
)
)
) {
my $__last_update = sql_select_scalar ("SELECT unix_ts FROM $conf->{systables}->{__last_update}");
my $__time = int(time ());
if ($DB_MODEL && !$DB_MODEL -> {splitted}) {
open (CONFIG, $file_name) || die "can't open $file_name: $!";
flock (CONFIG, LOCK_EX);
eval {
$model_update -> assert (%$DB_MODEL,core_voc_replacement_use => $conf -> {core_voc_replacement_use});
};
flock (CONFIG, LOCK_UN);
close (CONFIG);
die $@ if $@;
}
elsif (-d "$the_path/Model") {
eval {
opendir (DIR, "$the_path/Model") || die "can't opendir $the_path/Model: $!";
my @scripts = readdir (DIR);
closedir DIR;
foreach my $script (@scripts) {
$script =~ /\.p[lm]$/ or next;
my $name = $`;
my $script_path = "$the_path/Model/$script";
($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $last_modified, $ctime, $blksize, $blocks) = stat ($script_path);
if ($last_modified <= $__last_update) {
next;
}
$__time = $last_modified if $__time < $last_modified;
open (SCRIPT, $script_path) || die "can't lock $script_path: $!";
flock (SCRIPT, LOCK_EX);
my ($__new_last_update, $pid) = sql_select_array ("SELECT unix_ts, pid FROM $conf->{systables}->{__last_update}");
if ($__new_last_update > $__last_update) {
print STDERR "[$$] Oops, [$pid] bypassed us. Unlocking $name...\n";
flock (SCRIPT, LOCK_UN);
close (SCRIPT);
print STDERR "[$$] $name unlocked.\n";
$__last_update = -1;
last;
}
print STDERR "[$$] Altering $name...\n";
my %db_model = %$DB_MODEL;
$db_model {no_checksums} = 1;
my $src = "\$db_model {tables} = {$name => {";
while (