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   $::lxdebug       = LXDebug->new;
 
  68   $::locale        = Locale->new($::lx_office_conf{system}->{language});
 
  70   $::auth          = SL::Auth->new;
 
  74   $::auth->set_client($client->id);
 
  76   $::form->{__ERROR_HANDLER} = sub { die @_ };
 
  78   $::instance_conf = SL::InstanceConfiguration->new;
 
  79   $::request       = SL::Request->new(
 
  81     layout         => SL::Layout::None->new,
 
  84   die 'cannot reach auth db'               unless $::auth->session_tables_present;
 
  86   $::auth->restore_session;
 
  87   $::auth->create_or_refresh_session;
 
  89   my $login = $client->task_server_user->login;
 
  91   die "cannot find user $login"            unless %::myconfig = $::auth->read_user(login => $login);
 
  92   die "cannot find locale for user $login" unless $::locale   = Locale->new($::myconfig{countrycode} || $::lx_office_conf{system}->{language});
 
  95 sub cleanup_kivitendo {
 
  96   eval { SL::DB->client->dbh->rollback; };
 
  98   $::auth->save_session;
 
  99   $::auth->expire_sessions;
 
 108 sub clean_before_sleeping {
 
 109   SL::DBConnect::Cache->disconnect_all_and_clear;
 
 110   SL::DB->db_cache->clear;
 
 112   File::Temp::cleanup();
 
 115 sub drop_privileges {
 
 116   my $user = $lx_office_conf{task_server}->{run_as};
 
 120   while (my @details = getpwent()) {
 
 121     next unless $details[0] eq $user;
 
 122     ($uid, $gid) = @details[2, 3];
 
 128     print "Error: Cannot drop privileges to ${user}: user does not exist\n";
 
 133     print "Error: Cannot drop group privileges to ${user} (group ID $gid): $!\n";
 
 138     print "Error: Cannot drop user privileges to ${user} (user ID $uid): $!\n";
 
 143 sub notify_on_failure {
 
 146   my $cfg = $lx_office_conf{'task_server/notify_on_failure'} || {};
 
 148   return if any { !$cfg->{$_} } qw(send_email_to email_from email_subject email_template);
 
 152   return debug("Template " . $cfg->{email_template} . " missing!") unless -f $cfg->{email_template};
 
 154   my $email_to = $cfg->{send_email_to};
 
 155   if ($email_to !~ m{\@}) {
 
 156     my %user = $::auth->read_user(login => $email_to);
 
 157     return debug("cannot find user for notification $email_to") unless %user;
 
 159     $email_to = $user{email};
 
 160     return debug("user for notification " . $user{login} . " doesn't have a valid email address") unless $email_to =~ m{\@};
 
 163   my $template  = Template->new({
 
 170   return debug("Could not create Template instance") unless $template;
 
 172   $params{client} = $::auth->client;
 
 176     $template->process($cfg->{email_template}, \%params, \$body);
 
 179       from         => $cfg->{email_from},
 
 181       subject      => $cfg->{email_subject},
 
 182       content_type => 'text/plain',
 
 184       message      => Encode::decode('utf-8', $body),
 
 189     debug("Sending a failure notification failed with an exception: $@");
 
 196   SL::LxOfficeConf->read($self->{configfile});
 
 198   die "Missing section [task_server] in config file" unless $lx_office_conf{task_server};
 
 200   if ($lx_office_conf{task_server}->{login} || $lx_office_conf{task_server}->{client}) {
 
 202 ERROR: The keys 'login' and/or 'client' are still present in the
 
 203 section [task_server] in the configuration file. These keys are
 
 204 deprecated. You have to configure the clients for which to run the
 
 205 task server in the web admin interface.
 
 207 The task server will refuse to start until the keys have been removed from
 
 208 the configuration file.
 
 213   initialize_kivitendo();
 
 215   my $dbupdater_auth = SL::DBUpgrade2->new(form => $::form, auth => 1)->parse_dbupdate_controls;
 
 216   if ($dbupdater_auth->unapplied_upgrade_scripts($::auth->dbconnect)) {
 
 218 The authentication database requires an upgrade. Please login to
 
 219 kivitendo's administration interface in order to apply it. The task
 
 220 server cannot start until the upgrade has been applied.
 
 230 sub run_once_for_all_clients {
 
 231   initialize_kivitendo();
 
 233   my $clients = enabled_clients();
 
 235   foreach my $client (@{ $clients }) {
 
 236     debug("Running for client ID " . $client->id . " (" . $client->name . ")");
 
 239       initialize_kivitendo($client);
 
 241       my $jobs = SL::DB::Manager::BackgroundJob->get_all_need_to_run;
 
 244         debug(" Executing the following jobs: " . join(' ', map { $_->package_name } @{ $jobs }));
 
 246         debug(" No jobs to execute found");
 
 249       foreach my $job (@{ $jobs }) {
 
 250         # Provide fresh global variables in case legacy code modifies
 
 252         initialize_kivitendo($client);
 
 254         my $history = $job->run;
 
 256         notify_on_failure(history => $history) if $history && $history->has_failed;
 
 263       my $error = $EVAL_ERROR;
 
 264       debug("Exception during execution: ${error}");
 
 265       notify_on_failure(exception => $error);
 
 274     $SIG{'ALRM'} = 'IGNORE';
 
 276     run_once_for_all_clients();
 
 280     clean_before_sleeping();
 
 282     my $seconds = 60 - (localtime)[0];
 
 285         $SIG{'ALRM'} = 'IGNORE';
 
 286         debug("Got woken up by SIGALRM");
 
 289       sleep($seconds < 30 ? $seconds + 60 : $seconds);
 
 292       die $@ unless $@ eq "Alarm!\n";
 
 299 mkdir SL::System::TaskServer::PID_BASE() if !-d SL::System::TaskServer::PID_BASE();
 
 301 my $file = first { -f } ("${exe_dir}/config/kivitendo.conf", "${exe_dir}/config/lx_office.conf", "${exe_dir}/config/kivitendo.conf.default");
 
 303 die "No configuration file found." unless $file;
 
 305 $file = File::Spec->abs2rel(Cwd::abs_path($file), Cwd::abs_path($exe_dir));
 
 307 newdaemon(configfile => $file,
 
 308           progname   => 'kivitendo-background-jobs',
 
 309           pidbase    => SL::System::TaskServer::PID_BASE() . '/',