init III
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
## nofilter(TidyAll::Plugin::OTRS::Perl::NoExitInConsoleCommands)
|
||||
|
||||
package Kernel::System::Console::Command::Maint::PostMaster::MailAccountFetch;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use parent qw(Kernel::System::Console::BaseCommand);
|
||||
|
||||
use POSIX ":sys_wait_h";
|
||||
use Time::HiRes qw(sleep);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::System::Log',
|
||||
'Kernel::System::MailAccount',
|
||||
'Kernel::System::PID',
|
||||
);
|
||||
|
||||
sub Configure {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
$Self->Description('Fetch incoming emails from configured mail accounts.');
|
||||
$Self->AddOption(
|
||||
Name => 'mail-account-id',
|
||||
Description => "Fetch mail only from this account (default: fetch from all).",
|
||||
Required => 0,
|
||||
HasValue => 1,
|
||||
ValueRegex => qr{^\d+$}smx,
|
||||
);
|
||||
$Self->AddOption(
|
||||
Name => 'force-pid',
|
||||
Description => "Start even if another process is still registered in the database.",
|
||||
Required => 0,
|
||||
HasValue => 0,
|
||||
);
|
||||
$Self->AddOption(
|
||||
Name => 'debug',
|
||||
Description => "Print debug info to the OTRS log.",
|
||||
Required => 0,
|
||||
HasValue => 0,
|
||||
);
|
||||
$Self->AddOption(
|
||||
Name => 'timeout',
|
||||
Description =>
|
||||
"Timeout in seconds to kill the child process, that does the mail fetching (default: 600).",
|
||||
Required => 0,
|
||||
HasValue => 1,
|
||||
ValueRegex => qr{^\d+$}smx,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub PreRun {
|
||||
my ($Self) = @_;
|
||||
|
||||
my $PIDObject = $Kernel::OM->Get('Kernel::System::PID');
|
||||
|
||||
my $PIDCreated = $PIDObject->PIDCreate(
|
||||
Name => 'MailAccountFetch',
|
||||
Force => $Self->GetOption('force-pid'),
|
||||
TTL => 600, # 10 minutes
|
||||
);
|
||||
if ( !$PIDCreated ) {
|
||||
my $Error = "Unable to register the process in the database. Is another instance still running?\n";
|
||||
$Error .= "You can use --force-pid to override this check.\n";
|
||||
die $Error;
|
||||
}
|
||||
|
||||
my $Debug = $Self->GetOption('debug');
|
||||
my $Name = $Self->Name();
|
||||
|
||||
if ($Debug) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'debug',
|
||||
Message => "OTRS email handle ($Name) started.",
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub Run {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $MailAccountObject = $Kernel::OM->Get('Kernel::System::MailAccount');
|
||||
my %List = $MailAccountObject->MailAccountList( Valid => 1 );
|
||||
|
||||
my $Debug = $Self->GetOption('debug');
|
||||
my $Timeout = $Self->GetOption('timeout') || 600;
|
||||
my $MailAccountID = $Self->GetOption('mail-account-id');
|
||||
|
||||
if ( !%List ) {
|
||||
if ($MailAccountID) {
|
||||
$Self->PrintError("Could not find mail account $MailAccountID.");
|
||||
return $Self->ExitCodeError();
|
||||
}
|
||||
|
||||
$Self->Print("\n<yellow>No configured mail accounts found!</yellow>\n\n");
|
||||
return $Self->ExitCodeOk();
|
||||
}
|
||||
|
||||
# Setup alarm signal handler to kill the running child process if we reach the given timeout.
|
||||
local $SIG{ALRM} = sub {
|
||||
$Self->PrintError("Timeout of $Timeout seconds reached, killing child process!\n");
|
||||
kill 9, $Self->{ChildPID};
|
||||
};
|
||||
|
||||
# Set the timeout to kill the child.
|
||||
alarm $Timeout;
|
||||
|
||||
# Destroy objects for the child processes.
|
||||
$Kernel::OM->ObjectsDiscard(
|
||||
Objects => [
|
||||
'Kernel::System::DB',
|
||||
],
|
||||
ForcePackageReload => 0,
|
||||
);
|
||||
|
||||
$Self->Print("\n<yellow>Spawning child process to fetch incoming messages from mail accounts...</yellow>\n\n");
|
||||
|
||||
# Create a child process.
|
||||
my $PID = fork;
|
||||
|
||||
# Could not create child.
|
||||
if ( $PID < 0 ) {
|
||||
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Unable to fork to a child process for mail account fetching!"
|
||||
);
|
||||
$Self->PrintError("Unable to fork to a child process for mail account fetching!");
|
||||
|
||||
return $Self->ExitCodeError();
|
||||
}
|
||||
|
||||
# We're in the child process.
|
||||
if ( !$PID ) {
|
||||
|
||||
my $ErrorCount;
|
||||
my $FetchedCount;
|
||||
|
||||
KEY:
|
||||
for my $Key ( sort keys %List ) {
|
||||
|
||||
next KEY if ( $MailAccountID && $Key != $MailAccountID );
|
||||
|
||||
my %Data = $MailAccountObject->MailAccountGet( ID => $Key );
|
||||
|
||||
$Self->Print("<yellow>$Data{Host} ($Data{Type})...</yellow>\n");
|
||||
|
||||
# It is needed for capture the standard error.
|
||||
my $Status;
|
||||
my $ErrorMessage;
|
||||
|
||||
eval {
|
||||
|
||||
# Localize the standard error, everything will be restored after the eval block.
|
||||
local *STDERR;
|
||||
|
||||
# Redirect the standard error to a variable.
|
||||
open STDERR, ">>", \$ErrorMessage;
|
||||
|
||||
$Status = $MailAccountObject->MailAccountFetch(
|
||||
%Data,
|
||||
Debug => $Self->GetOption('debug'),
|
||||
CMD => 1,
|
||||
UserID => 1,
|
||||
);
|
||||
};
|
||||
|
||||
# Hide password contained in error message and print message back to standard error.
|
||||
# Please see bug#12829 for more information.
|
||||
if ($ErrorMessage) {
|
||||
$ErrorMessage =~ s/\Q$Data{Password}\E/********/g;
|
||||
print STDERR $ErrorMessage;
|
||||
}
|
||||
|
||||
if ($Status) {
|
||||
$FetchedCount++;
|
||||
}
|
||||
else {
|
||||
$ErrorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
my $ExitCode = $Self->ExitCodeOk();
|
||||
|
||||
if ($ErrorCount) {
|
||||
|
||||
# Error messages printed by backend.
|
||||
$ExitCode = $Self->ExitCodeError();
|
||||
}
|
||||
|
||||
if ( !$FetchedCount && $MailAccountID ) {
|
||||
$Self->PrintError("Could not find mail account $MailAccountID.");
|
||||
$ExitCode = $Self->ExitCodeError();
|
||||
}
|
||||
|
||||
# Close child process at the end.
|
||||
exit $ExitCode;
|
||||
}
|
||||
|
||||
# Remember the child process ID.
|
||||
$Self->{ChildPID} = $PID;
|
||||
|
||||
# Check the status of the child process every 0.1 seconds.
|
||||
# Wait for the child process to be finished.
|
||||
WAIT:
|
||||
while (1) {
|
||||
|
||||
last WAIT if !$Self->{ChildPID};
|
||||
|
||||
sleep 0.1;
|
||||
|
||||
my $WaitResult = waitpid( $PID, WNOHANG );
|
||||
|
||||
if ( $WaitResult == -1 ) {
|
||||
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Child process exited with errors: $?",
|
||||
);
|
||||
|
||||
$Self->{ChildPID} = undef;
|
||||
}
|
||||
|
||||
$Self->{ChildPID} = undef if $WaitResult;
|
||||
}
|
||||
|
||||
alarm 0;
|
||||
|
||||
$Self->Print("<green>Done.</green>\n\n");
|
||||
return $Self->ExitCodeOk();
|
||||
}
|
||||
|
||||
sub PostRun {
|
||||
my ($Self) = @_;
|
||||
|
||||
# Destroy objects for the child processes.
|
||||
$Kernel::OM->ObjectsDiscard(
|
||||
Objects => [
|
||||
'Kernel::System::DB',
|
||||
],
|
||||
ForcePackageReload => 0,
|
||||
);
|
||||
|
||||
my $Debug = $Self->GetOption('debug');
|
||||
my $Name = $Self->Name();
|
||||
|
||||
if ($Debug) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'debug',
|
||||
Message => "OTRS email handle ($Name) stopped.",
|
||||
);
|
||||
}
|
||||
|
||||
return $Kernel::OM->Get('Kernel::System::PID')->PIDDelete( Name => 'MailAccountFetch' );
|
||||
}
|
||||
|
||||
1;
|
||||
211
Perl OTRS/Kernel/System/Console/Command/Maint/PostMaster/Read.pm
Normal file
211
Perl OTRS/Kernel/System/Console/Command/Maint/PostMaster/Read.pm
Normal file
@@ -0,0 +1,211 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Console::Command::Maint::PostMaster::Read;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use parent qw(Kernel::System::Console::BaseCommand);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::System::CommunicationLog',
|
||||
'Kernel::System::Main',
|
||||
);
|
||||
|
||||
sub Configure {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
$Self->Description('Read incoming email from STDIN.');
|
||||
$Self->AddOption(
|
||||
Name => 'target-queue',
|
||||
Description => "Preselect a target queue by name.",
|
||||
Required => 0,
|
||||
HasValue => 1,
|
||||
ValueRegex => qr/.*/smx,
|
||||
);
|
||||
$Self->AddOption(
|
||||
Name => 'untrusted',
|
||||
Description => "This will cause X-OTRS email headers to be ignored.",
|
||||
Required => 0,
|
||||
HasValue => 0,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub Run {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# start a new incoming communication
|
||||
my $CommunicationLogObject = $Kernel::OM->Create(
|
||||
'Kernel::System::CommunicationLog',
|
||||
ObjectParams => {
|
||||
Transport => 'Email',
|
||||
Direction => 'Incoming',
|
||||
AccountType => 'STDIN',
|
||||
},
|
||||
);
|
||||
|
||||
# start object log for the incoming connection
|
||||
$CommunicationLogObject->ObjectLogStart( ObjectLogType => 'Connection' );
|
||||
|
||||
$CommunicationLogObject->ObjectLog(
|
||||
ObjectLogType => 'Connection',
|
||||
Priority => 'Debug',
|
||||
Key => 'Kernel::System::Console::Command::Maint::PostMaster::Read',
|
||||
Value => 'Read email from STDIN.',
|
||||
);
|
||||
|
||||
# get email from SDTIN
|
||||
my @Email = <STDIN>; ## no critic
|
||||
|
||||
if ( !@Email ) {
|
||||
|
||||
$CommunicationLogObject->ObjectLog(
|
||||
ObjectLogType => 'Connection',
|
||||
Priority => 'Error',
|
||||
Key => 'Kernel::System::Console::Command::Maint::PostMaster::Read',
|
||||
Value => 'Got no email on STDIN!',
|
||||
);
|
||||
|
||||
$CommunicationLogObject->ObjectLogStop(
|
||||
ObjectLogType => 'Connection',
|
||||
Status => 'Failed',
|
||||
);
|
||||
$CommunicationLogObject->CommunicationStop( Status => 'Failed' );
|
||||
|
||||
return $Self->ExitCodeError(1);
|
||||
}
|
||||
|
||||
$CommunicationLogObject->ObjectLog(
|
||||
ObjectLogType => 'Connection',
|
||||
Priority => 'Debug',
|
||||
Key => 'Kernel::System::Console::Command::Maint::PostMaster::Read',
|
||||
Value => 'Email with ' . ( scalar @Email ) . ' lines successfully read from STDIN.',
|
||||
);
|
||||
|
||||
# start object log for the email processing
|
||||
$CommunicationLogObject->ObjectLogStart( ObjectLogType => 'Message' );
|
||||
|
||||
# remember the return code to stop the communictaion later with a proper status
|
||||
my $PostMasterReturnCode = 0;
|
||||
|
||||
# Wrap the main part of the script in an "eval" block so that any
|
||||
# unexpected (but probably transient) fatal errors (such as the
|
||||
# database being unavailable) can be trapped without causing a
|
||||
# bounce
|
||||
eval {
|
||||
|
||||
$CommunicationLogObject->ObjectLog(
|
||||
ObjectLogType => 'Message',
|
||||
Priority => 'Debug',
|
||||
Key => 'Kernel::System::Console::Command::Maint::PostMaster::Read',
|
||||
Value => 'Processing email with PostMaster module.',
|
||||
);
|
||||
|
||||
my $PostMasterObject = $Kernel::OM->Create(
|
||||
'Kernel::System::PostMaster',
|
||||
ObjectParams => {
|
||||
CommunicationLogObject => $CommunicationLogObject,
|
||||
Email => \@Email,
|
||||
Trusted => $Self->GetOption('untrusted') ? 0 : 1,
|
||||
},
|
||||
);
|
||||
|
||||
my @Return = $PostMasterObject->Run(
|
||||
Queue => $Self->GetOption('target-queue'),
|
||||
);
|
||||
|
||||
if ( !$Return[0] ) {
|
||||
|
||||
$CommunicationLogObject->ObjectLog(
|
||||
ObjectLogType => 'Message',
|
||||
Priority => 'Error',
|
||||
Key => 'Kernel::System::Console::Command::Maint::PostMaster::Read',
|
||||
Value => 'PostMaster module exited with errors, could not process email. Please refer to the log!',
|
||||
);
|
||||
$CommunicationLogObject->CommunicationStop( Status => 'Failed' );
|
||||
|
||||
die "Could not process email. Please refer to the log!\n";
|
||||
}
|
||||
|
||||
my $Dump = $Kernel::OM->Get('Kernel::System::Main')->Dump( \@Return );
|
||||
$CommunicationLogObject->ObjectLog(
|
||||
ObjectLogType => 'Message',
|
||||
Priority => 'Debug',
|
||||
Key => 'Kernel::System::Console::Command::Maint::PostMaster::Read',
|
||||
Value => "Email processing with PostMaster module completed, return data: $Dump",
|
||||
);
|
||||
|
||||
$PostMasterReturnCode = $Return[0];
|
||||
};
|
||||
|
||||
if ($@) {
|
||||
|
||||
# An unexpected problem occurred (for example, the database was
|
||||
# unavailable). Return an EX_TEMPFAIL error to cause the mail
|
||||
# program to requeue the message instead of immediately bouncing
|
||||
# it; see sysexits.h. Most mail programs will retry an
|
||||
# EX_TEMPFAIL delivery for about four days, then bounce the
|
||||
# message.)
|
||||
my $Message = $@;
|
||||
|
||||
$CommunicationLogObject->ObjectLog(
|
||||
ObjectLogType => 'Message',
|
||||
Priority => 'Error',
|
||||
Key => 'Kernel::System::Console::Command::Maint::PostMaster::Read',
|
||||
Value => "An unexpected error occurred, message: $Message",
|
||||
);
|
||||
|
||||
$CommunicationLogObject->ObjectLogStop(
|
||||
ObjectLogType => 'Message',
|
||||
Status => 'Failed',
|
||||
);
|
||||
$CommunicationLogObject->ObjectLogStop(
|
||||
ObjectLogType => 'Connection',
|
||||
Status => 'Failed',
|
||||
);
|
||||
$CommunicationLogObject->CommunicationStop( Status => 'Failed' );
|
||||
|
||||
return $Self->ExitCodeError(75);
|
||||
}
|
||||
|
||||
$CommunicationLogObject->ObjectLog(
|
||||
ObjectLogType => 'Connection',
|
||||
Priority => 'Debug',
|
||||
Key => 'Kernel::System::Console::Command::Maint::PostMaster::Read',
|
||||
Value => 'Closing connection from STDIN.',
|
||||
);
|
||||
|
||||
$CommunicationLogObject->ObjectLogStop(
|
||||
ObjectLogType => 'Message',
|
||||
Status => 'Successful',
|
||||
);
|
||||
$CommunicationLogObject->ObjectLogStop(
|
||||
ObjectLogType => 'Connection',
|
||||
Status => 'Successful',
|
||||
);
|
||||
|
||||
my %ReturnCodeMap = (
|
||||
0 => 'Failed', # error (also false)
|
||||
1 => 'Successful', # new ticket created
|
||||
2 => 'Successful', # follow up / open/reopen
|
||||
3 => 'Successful', # follow up / close -> new ticket
|
||||
4 => 'Failed', # follow up / close -> reject
|
||||
5 => 'Successful', # ignored (because of X-OTRS-Ignore header)
|
||||
);
|
||||
|
||||
$CommunicationLogObject->CommunicationStop(
|
||||
Status => $ReturnCodeMap{$PostMasterReturnCode} // 'Failed',
|
||||
);
|
||||
|
||||
return $Self->ExitCodeOk();
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,91 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
||||
# --
|
||||
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
||||
# the enclosed file COPYING for license information (GPL). If you
|
||||
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
||||
# --
|
||||
|
||||
package Kernel::System::Console::Command::Maint::PostMaster::SpoolMailsReprocess;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use parent qw(Kernel::System::Console::BaseCommand);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::Log',
|
||||
'Kernel::System::Main',
|
||||
);
|
||||
|
||||
sub Configure {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
$Self->Description('Reprocess mails from spool directory that could not be imported in the first place.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub PreRun {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $SpoolDir = $Kernel::OM->Get('Kernel::Config')->Get('Home') . '/var/spool';
|
||||
if ( !-d $SpoolDir ) {
|
||||
die "Spool directory $SpoolDir does not exist!\n";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub Run {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $Home = $Kernel::OM->Get('Kernel::Config')->Get('Home');
|
||||
my $SpoolDir = "$Home/var/spool";
|
||||
|
||||
$Self->Print("<yellow>Processing mails in $SpoolDir...</yellow>\n");
|
||||
|
||||
my @Files = $Kernel::OM->Get('Kernel::System::Main')->DirectoryRead(
|
||||
Directory => $SpoolDir,
|
||||
Filter => '*',
|
||||
);
|
||||
|
||||
my $Success = 1;
|
||||
|
||||
for my $File (@Files) {
|
||||
$Self->Print(" Processing <yellow>$File</yellow>... ");
|
||||
|
||||
# Here we use a system call because Maint::PostMaster::Read has special exception handling
|
||||
# and will die if certain problems occur.
|
||||
my $Result = system("$^X $Home/bin/otrs.Console.pl Maint::PostMaster::Read < $File ");
|
||||
|
||||
# Exit code 0 == success
|
||||
if ( !$Result ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'info',
|
||||
Message => "Successfully reprocessed email $File.",
|
||||
);
|
||||
unlink $File;
|
||||
$Self->Print("<green>Ok.</green>\n");
|
||||
}
|
||||
else {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Could not re-process email $File.",
|
||||
);
|
||||
$Self->Print("<red>Failed.</red>\n");
|
||||
$Success = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !$Success ) {
|
||||
$Self->PrintError("There were problems importing the spool mails.");
|
||||
return $Self->ExitCodeError();
|
||||
}
|
||||
|
||||
$Self->Print("<green>Done.</green>\n");
|
||||
return $Self->ExitCodeOk();
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user