4 use List::MoreUtils qw(any);
 
  12   use lib "$FindBin::Bin/..";
 
  14   use SL::System::Process;
 
  15   $exe_dir = SL::System::Process::exe_dir;
 
  17   unshift @INC, "${exe_dir}/modules/override"; # Use our own versions of various modules (e.g. YAML).
 
  18   push    @INC, "${exe_dir}/modules/fallback"; # Only use our own versions of modules if there's no system version.
 
  19   unshift @INC, $exe_dir;
 
  21   chdir($exe_dir) || die "Cannot change directory to ${exe_dir}\n";
 
  24 use CGI qw( -no_xhtml);
 
  30 use English qw(-no_match_vars);
 
  32 use List::Util qw(first);
 
  33 use POSIX qw(setuid setgid);
 
  36 use SL::DB::AuthClient;
 
  37 use SL::DB::BackgroundJob;
 
  38 use SL::BackgroundJob::ALL;
 
  40 use SL::Helper::DateTime;
 
  41 use SL::InstanceConfiguration;
 
  46 use SL::System::TaskServer;
 
  52   return if !$lx_office_conf{task_server}->{debug};
 
  53   $::lxdebug->message(LXDebug::DEBUG1(), join(' ', "task server:", @_));
 
  57   return SL::DB::Manager::AuthClient->get_all(where => [ '!task_server_user_id' => undef ]);
 
  60 sub initialize_kivitendo {
 
  67   Form::disconnect_standard_dbh;
 
  68   $::lxdebug       = LXDebug->new;
 
  69   $::locale        = Locale->new($::lx_office_conf{system}->{language});
 
  71   $::auth          = SL::Auth->new;
 
  75   $::auth->set_client($client->id);
 
  77   $::form->{__ERROR_HANDLER} = sub { die @_ };
 
  79   $::instance_conf = SL::InstanceConfiguration->new;
 
  80   $::request       = SL::Request->new(
 
  82     layout         => SL::Layout::None->new,
 
  85   die 'cannot reach auth db'               unless $::auth->session_tables_present;
 
  87   $::auth->restore_session;
 
  88   $::auth->create_or_refresh_session;
 
  90   my $login = $client->task_server_user->login;
 
  92   die "cannot find user $login"            unless %::myconfig = $::auth->read_user(login => $login);
 
  93   die "cannot find locale for user $login" unless $::locale   = Locale->new($::myconfig{countrycode} || $::lx_office_conf{system}->{language});
 
  96 sub cleanup_kivitendo {
 
  97   eval { SL::DB->client->dbh->rollback; };
 
  99   $::auth->save_session;
 
 100   $::auth->expire_sessions;
 
 109 sub clean_before_sleeping {
 
 110   Form::disconnect_standard_dbh;
 
 111   SL::DBConnect::Cache->disconnect_all_and_clear;
 
 112   SL::DB->db_cache->clear;
 
 114   File::Temp::cleanup();
 
 117 sub drop_privileges {
 
 118   my $user = $lx_office_conf{task_server}->{run_as};
 
 122   while (my @details = getpwent()) {
 
 123     next unless $details[0] eq $user;
 
 124     ($uid, $gid) = @details[2, 3];
 
 130     print "Error: Cannot drop privileges to ${user}: user does not exist\n";
 
 135     print "Error: Cannot drop group privileges to ${user} (group ID $gid): $!\n";
 
 140     print "Error: Cannot drop user privileges to ${user} (user ID $uid): $!\n";
 
 145 sub notify_on_failure {
 
 148   my $cfg = $lx_office_conf{'task_server/notify_on_failure'} || {};
 
 150   return if any { !$cfg->{$_} } qw(send_email_to email_from email_subject email_template);
 
 154   return debug("Template " . $cfg->{email_template} . " missing!") unless -f $cfg->{email_template};
 
 156   my $email_to = $cfg->{send_email_to};
 
 157   if ($email_to !~ m{\@}) {
 
 158     my %user = $::auth->read_user(login => $email_to);
 
 159     return debug("cannot find user for notification $email_to") unless %user;
 
 161     $email_to = $user{email};
 
 162     return debug("user for notification " . $user{login} . " doesn't have a valid email address") unless $email_to =~ m{\@};
 
 165   my $template  = Template->new({
 
 172   return debug("Could not create Template instance") unless $template;
 
 174   $params{client} = $::auth->client;
 
 178     $template->process($cfg->{email_template}, \%params, \$body);
 
 181       from         => $cfg->{email_from},
 
 183       subject      => $cfg->{email_subject},
 
 184       content_type => 'text/plain',
 
 186       message      => Encode::decode('utf-8', $body),
 
 191     debug("Sending a failure notification failed with an exception: $@");
 
 198   SL::LxOfficeConf->read($self->{configfile});
 
 200   die "Missing section [task_server] in config file" unless $lx_office_conf{task_server};
 
 202   if ($lx_office_conf{task_server}->{login} || $lx_office_conf{task_server}->{client}) {
 
 204 ERROR: The keys 'login' and/or 'client' are still present in the
 
 205 section [task_server] in the configuration file. These keys are
 
 206 deprecated. You have to configure the clients for which to run the
 
 207 task server in the web admin interface.
 
 209 The task server will refuse to start until the keys have been removed from
 
 210 the configuration file.
 
 215   initialize_kivitendo();
 
 217   my $dbupdater_auth = SL::DBUpgrade2->new(form => $::form, auth => 1)->parse_dbupdate_controls;
 
 218   if ($dbupdater_auth->unapplied_upgrade_scripts($::auth->dbconnect)) {
 
 220 The authentication database requires an upgrade. Please login to
 
 221 kivitendo's administration interface in order to apply it. The task
 
 222 server cannot start until the upgrade has been applied.
 
 232 sub run_once_for_all_clients {
 
 233   initialize_kivitendo();
 
 235   my $clients = enabled_clients();
 
 237   foreach my $client (@{ $clients }) {
 
 238     debug("Running for client ID " . $client->id . " (" . $client->name . ")");
 
 241       initialize_kivitendo($client);
 
 243       my $jobs = SL::DB::Manager::BackgroundJob->get_all_need_to_run;
 
 246         debug(" Executing the following jobs: " . join(' ', map { $_->package_name } @{ $jobs }));
 
 248         debug(" No jobs to execute found");
 
 251       foreach my $job (@{ $jobs }) {
 
 252         # Provide fresh global variables in case legacy code modifies
 
 254         initialize_kivitendo($client);
 
 256         my $history = $job->run;
 
 258         notify_on_failure(history => $history) if $history && $history->has_failed;
 
 265       my $error = $EVAL_ERROR;
 
 266       debug("Exception during execution: ${error}");
 
 267       notify_on_failure(exception => $error);
 
 276     $SIG{'ALRM'} = 'IGNORE';
 
 278     run_once_for_all_clients();
 
 282     clean_before_sleeping();
 
 284     my $seconds = 60 - (localtime)[0];
 
 287         $SIG{'ALRM'} = 'IGNORE';
 
 288         debug("Got woken up by SIGALRM");
 
 291       sleep($seconds < 30 ? $seconds + 60 : $seconds);
 
 294       die $@ unless $@ eq "Alarm!\n";
 
 301 mkdir SL::System::TaskServer::PID_BASE() if !-d SL::System::TaskServer::PID_BASE();
 
 303 my $file = first { -f } ("${exe_dir}/config/kivitendo.conf", "${exe_dir}/config/lx_office.conf", "${exe_dir}/config/kivitendo.conf.default");
 
 305 die "No configuration file found." unless $file;
 
 307 $file = File::Spec->abs2rel(Cwd::abs_path($file), Cwd::abs_path($exe_dir));
 
 309 newdaemon(configfile => $file,
 
 310           progname   => 'kivitendo-background-jobs',
 
 311           pidbase    => SL::System::TaskServer::PID_BASE() . '/',