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::Auth->new->db->dbh->rollback; };
 
  98   eval { SL::DB::BackgroundJob->new->db->dbh->rollback; };
 
 100   $::auth->save_session;
 
 101   $::auth->expire_sessions;
 
 110 sub clean_before_sleeping {
 
 111   Form::disconnect_standard_dbh;
 
 112   SL::DBConnect::Cache->disconnect_all_and_clear;
 
 113   SL::DB->db_cache->clear;
 
 115   File::Temp::cleanup();
 
 118 sub drop_privileges {
 
 119   my $user = $lx_office_conf{task_server}->{run_as};
 
 123   while (my @details = getpwent()) {
 
 124     next unless $details[0] eq $user;
 
 125     ($uid, $gid) = @details[2, 3];
 
 131     print "Error: Cannot drop privileges to ${user}: user does not exist\n";
 
 136     print "Error: Cannot drop group privileges to ${user} (group ID $gid): $!\n";
 
 141     print "Error: Cannot drop user privileges to ${user} (user ID $uid): $!\n";
 
 146 sub notify_on_failure {
 
 149   my $cfg = $lx_office_conf{'task_server/notify_on_failure'} || {};
 
 151   return if any { !$cfg->{$_} } qw(send_email_to email_from email_subject email_template);
 
 155   return debug("Template " . $cfg->{email_template} . " missing!") unless -f $cfg->{email_template};
 
 157   my $email_to = $cfg->{send_email_to};
 
 158   if ($email_to !~ m{\@}) {
 
 159     my %user = $::auth->read_user(login => $email_to);
 
 160     return debug("cannot find user for notification $email_to") unless %user;
 
 162     $email_to = $user{email};
 
 163     return debug("user for notification " . $user{login} . " doesn't have a valid email address") unless $email_to =~ m{\@};
 
 166   my $template  = Template->new({
 
 173   return debug("Could not create Template instance") unless $template;
 
 175   $params{client} = $::auth->client;
 
 179     $template->process($cfg->{email_template}, \%params, \$body);
 
 182       from         => $cfg->{email_from},
 
 184       subject      => $cfg->{email_subject},
 
 185       content_type => 'text/plain',
 
 187       message      => Encode::decode('utf-8', $body),
 
 192     debug("Sending a failure notification failed with an exception: $@");
 
 199   SL::LxOfficeConf->read($self->{configfile});
 
 201   die "Missing section [task_server] in config file" unless $lx_office_conf{task_server};
 
 203   if ($lx_office_conf{task_server}->{login} || $lx_office_conf{task_server}->{client}) {
 
 205 ERROR: The keys 'login' and/or 'client' are still present in the
 
 206 section [task_server] in the configuration file. These keys are
 
 207 deprecated. You have to configure the clients for which to run the
 
 208 task server in the web admin interface.
 
 210 The task server will refuse to start until the keys have been removed from
 
 211 the configuration file.
 
 216   initialize_kivitendo();
 
 218   my $dbupdater_auth = SL::DBUpgrade2->new(form => $::form, auth => 1)->parse_dbupdate_controls;
 
 219   if ($dbupdater_auth->unapplied_upgrade_scripts($::auth->dbconnect)) {
 
 221 The authentication database requires an upgrade. Please login to
 
 222 kivitendo's administration interface in order to apply it. The task
 
 223 server cannot start until the upgrade has been applied.
 
 233 sub run_once_for_all_clients {
 
 234   initialize_kivitendo();
 
 236   my $clients = enabled_clients();
 
 238   foreach my $client (@{ $clients }) {
 
 239     debug("Running for client ID " . $client->id . " (" . $client->name . ")");
 
 242       initialize_kivitendo($client);
 
 244       my $jobs = SL::DB::Manager::BackgroundJob->get_all_need_to_run;
 
 247         debug(" Executing the following jobs: " . join(' ', map { $_->package_name } @{ $jobs }));
 
 249         debug(" No jobs to execute found");
 
 252       foreach my $job (@{ $jobs }) {
 
 253         # Provide fresh global variables in case legacy code modifies
 
 255         initialize_kivitendo($client);
 
 257         my $history = $job->run;
 
 259         notify_on_failure(history => $history) if $history && $history->has_failed;
 
 266       my $error = $EVAL_ERROR;
 
 267       debug("Exception during execution: ${error}");
 
 268       notify_on_failure(exception => $error);
 
 277     $SIG{'ALRM'} = 'IGNORE';
 
 279     run_once_for_all_clients();
 
 283     clean_before_sleeping();
 
 285     my $seconds = 60 - (localtime)[0];
 
 288         $SIG{'ALRM'} = 'IGNORE';
 
 289         debug("Got woken up by SIGALRM");
 
 292       sleep($seconds < 30 ? $seconds + 60 : $seconds);
 
 295       die $@ unless $@ eq "Alarm!\n";
 
 301   $main::lxdebug->show_backtrace();
 
 303 Job called ::end_of_request()!
 
 305 This usually indicates success but should not be used by background jobs. A
 
 306 backtrace has been logged. Please tell the job author to have a look at it.
 
 313 mkdir SL::System::TaskServer::PID_BASE() if !-d SL::System::TaskServer::PID_BASE();
 
 315 my $file = first { -f } ("${exe_dir}/config/kivitendo.conf", "${exe_dir}/config/lx_office.conf", "${exe_dir}/config/kivitendo.conf.default");
 
 317 die "No configuration file found." unless $file;
 
 319 $file = File::Spec->abs2rel(Cwd::abs_path($file), Cwd::abs_path($exe_dir));
 
 321 newdaemon(configfile => $file,
 
 322           progname   => 'kivitendo-background-jobs',
 
 323           pidbase    => SL::System::TaskServer::PID_BASE() . '/',