init III
This commit is contained in:
199
Perl OTRS/Kernel/cpan-lib/Sisimai/MDA.pm
Normal file
199
Perl OTRS/Kernel/cpan-lib/Sisimai/MDA.pm
Normal file
@@ -0,0 +1,199 @@
|
||||
package Sisimai::MDA;
|
||||
use feature ':5.10';
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $AgentNames = {
|
||||
# dovecot/src/deliver/deliver.c
|
||||
# 11: #define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
|
||||
# 12: "Your message to <%t> was automatically rejected:%n%r"
|
||||
'dovecot' => qr/\AYour message to .+ was automatically rejected:\z/,
|
||||
'mail.local' => qr/\Amail[.]local: /,
|
||||
'procmail' => qr/\Aprocmail: /,
|
||||
'maildrop' => qr/\Amaildrop: /,
|
||||
'vpopmail' => qr/\Avdelivermail: /,
|
||||
'vmailmgr' => qr/\Avdeliver: /,
|
||||
};
|
||||
my $MarkingsOf = {
|
||||
'message' => qr{\A(?>
|
||||
Your[ ]message[ ]to[ ].+[ ]was[ ]automatically[ ]rejected:\z
|
||||
|(?:mail[.]local|procmail|maildrop|vdelivermail|vdeliver):[ ]
|
||||
)
|
||||
}x,
|
||||
};
|
||||
|
||||
# dovecot/src/deliver/mail-send.c:94
|
||||
my $MessagesOf = {
|
||||
'dovecot' => {
|
||||
'userunknown' => ["mailbox doesn't exist: "],
|
||||
'mailboxfull' => [
|
||||
'quota exceeded', # Dovecot 1.2 dovecot/src/plugins/quota/quota.c
|
||||
'quota exceeded (mailbox for user is full)', # dovecot/src/plugins/quota/quota.c
|
||||
'not enough disk space',
|
||||
],
|
||||
},
|
||||
'mail.local' => {
|
||||
'userunknown' => [
|
||||
': unknown user:',
|
||||
': user unknown',
|
||||
': invalid mailbox path',
|
||||
': user missing home directory',
|
||||
],
|
||||
'mailboxfull' => [
|
||||
'disc quota exceeded',
|
||||
'mailbox full or quota exceeded',
|
||||
],
|
||||
'systemerror' => ['temporary file write error'],
|
||||
},
|
||||
'procmail' => {
|
||||
'mailboxfull' => ['quota exceeded while writing'],
|
||||
'systemfull' => ['no space left to finish writing'],
|
||||
},
|
||||
'maildrop' => {
|
||||
'userunknown' => [
|
||||
'invalid user specified.',
|
||||
'cannot find system user',
|
||||
],
|
||||
'mailboxfull' => ['maildir over quota.'],
|
||||
},
|
||||
'vpopmail' => {
|
||||
'userunknown' => ['sorry, no mailbox here by that name.'],
|
||||
'filtered' => [
|
||||
'account is locked email bounced',
|
||||
'user does not exist, but will deliver to '
|
||||
],
|
||||
'mailboxfull' => [
|
||||
'domain is over quota',
|
||||
'user is over quota',
|
||||
],
|
||||
},
|
||||
'vmailmgr' => {
|
||||
'userunknown' => [
|
||||
'invalid or unknown base user or domain',
|
||||
'invalid or unknown virtual user',
|
||||
'user name does not refer to a virtual user'
|
||||
],
|
||||
'mailboxfull' => ['delivery failed due to system quota violation'],
|
||||
},
|
||||
};
|
||||
|
||||
sub scan {
|
||||
# Parse message body and return reason and text
|
||||
# @param [Hash] mhead Message header of a bounce email
|
||||
# @options mhead [String] from From header
|
||||
# @options mhead [String] date Date header
|
||||
# @options mhead [String] subject Subject header
|
||||
# @options mhead [Array] received Received headers
|
||||
# @options mhead [String] others Other required headers
|
||||
# @param [String] mbody Message body of a bounce email
|
||||
# @return [Hash, Undef] Bounce data list and message/rfc822 part
|
||||
# or Undef if it failed to parse or the
|
||||
# arguments are missing
|
||||
my $class = shift;
|
||||
my $mhead = shift // return undef;
|
||||
my $mbody = shift // return undef;
|
||||
|
||||
return undef unless ref($mhead) eq 'HASH';
|
||||
return undef unless lc($mhead->{'from'}) =~ /\A(?:mail delivery subsystem|mailer-daemon|postmaster)/;
|
||||
return undef unless ref($mbody) eq 'SCALAR';
|
||||
return undef unless $$mbody;
|
||||
|
||||
my $agentname0 = ''; # [String] MDA name
|
||||
my $reasonname = ''; # [String] Error reason
|
||||
my $bouncemesg = ''; # [String] Error message
|
||||
my @hasdivided = split("\n", $$mbody);
|
||||
my @linebuffer = ();
|
||||
|
||||
for my $e ( @hasdivided ) {
|
||||
# Check each line with each MDA's symbol regular expression.
|
||||
if( $agentname0 eq '' ) {
|
||||
# Try to match with each regular expression
|
||||
next unless $e;
|
||||
next unless $e =~ $MarkingsOf->{'message'};
|
||||
|
||||
for my $f ( keys %$AgentNames ) {
|
||||
# Detect the agent name from the line
|
||||
next unless $e =~ $AgentNames->{ $f };
|
||||
$agentname0 = $f;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
# Append error message lines to @linebuffer
|
||||
push @linebuffer, $e;
|
||||
last unless length $e;
|
||||
}
|
||||
return undef unless $agentname0;
|
||||
return undef unless scalar @linebuffer;
|
||||
|
||||
for my $e ( keys %{ $MessagesOf->{ $agentname0 } } ) {
|
||||
# Detect an error reason from message patterns of the MDA.
|
||||
for my $f ( @linebuffer ) {
|
||||
# Whether the error message include each message defined in $MessagesOf
|
||||
my $g = lc $f;
|
||||
next unless grep { index($g, $_) > -1 } @{ $MessagesOf->{ $agentname0 }->{ $e } };
|
||||
$reasonname = $e;
|
||||
$bouncemesg = $f;
|
||||
last;
|
||||
}
|
||||
last if $bouncemesg && $reasonname;
|
||||
}
|
||||
|
||||
return {
|
||||
'mda' => $agentname0,
|
||||
'reason' => $reasonname // '',
|
||||
'message' => $bouncemesg // '',
|
||||
};
|
||||
}
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=encoding utf-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Sisimai::MDA - Error message parser for MDA
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Sisimai::MDA;
|
||||
my $header = { 'from' => 'mailer-daemon@example.jp' };
|
||||
my $string = 'mail.local: Disc quota exceeded';
|
||||
my $return = Sisimai::MDA->scan($header, \$string);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Sisimai::MDA parse bounced email which created by some MDA, such as C<dovecot>,
|
||||
C<mail.local>, C<procmail>, and so on.
|
||||
This class is called from Sisimai::Message only.
|
||||
|
||||
=head1 CLASS METHODS
|
||||
|
||||
=head2 C<B<scan(I<Header>, I<Reference to message body>)>>
|
||||
|
||||
C<scan()> is a parser for detecting an error from mail delivery agent.
|
||||
|
||||
my $header = { 'from' => 'mailer-daemon@example.jp' };
|
||||
my $string = 'mail.local: Disc quota exceeded';
|
||||
my $return = Sisimai::MDA->scan($header, \$string);
|
||||
warn Dumper $return;
|
||||
$VAR1 = {
|
||||
'mda' => 'mail.local',
|
||||
'reason' => 'mailboxfull',
|
||||
'message' => 'mail.local: Disc quota exceeded'
|
||||
}
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
azumakuniyuki
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (C) 2014-2016,2018 azumakuniyuki, All rights reserved.
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
This software is distributed under The BSD 2-Clause License.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user