package Sisimai::Rhost::GoogleApps;
use feature ':5.10';
use strict;
use warnings;

my $StatusList = {
    # https://support.google.com/a/answer/3726730
    'X.1.1' => [{ 'reason' => 'userunknown', 'string' => ['The email account that you tried to reach does not exist.'] }],
    'X.1.2' => [{ 'reason' => 'hostunknown', 'string' => ["We weren't able to find the recipient domain."] }],
    'X.2.1' => [
        { 'reason' => 'suspend',   'string' => ['The email account that you tried to reach is disabled.'] },
        { 'reason' => 'undefined', 'string' => ['The user you are trying to contact is receiving mail ']  },
    ],
    'X.2.2' => [{ 'reason' => 'mailboxfull', 'string' => ['The email account that you tried to reach is over quota.'] }],
    'X.2.3' => [{ 'reason' => 'exceedlimit', 'string' => ["Your message exceeded Google's message size limits."] }],
    'X.3.0' => [
        { 'reason' => 'syntaxerror', 'string' => ['Multiple destination domains per transaction is unsupported.'] },
        { 'reason' => 'undefined',   'string' => ['Mail server temporarily rejected message.'] },
    ],
    'X.4.2' => [{ 'reason' => 'expired', 'string' => ['Timeout - closing connection.'] }],
    'X.4.5' => [
        { 'reason' => 'exceedlimit', 'string' => ['Daily sending quota exceeded.'] },
        { 'reason' => 'undefined',   'string' => ['Server busy, try again later.'] },
    ],
    'X.5.0' => [{ 'reason' => 'syntaxerror', 'string' => ['SMTP protocol violation'] }],
    'X.5.1' => [
        { 'reason' => 'securityerror',  'string' => ['Authentication Required.'] },
        { 'reason' => 'syntaxerror',    'string' => [
            'STARTTLS may not be repeated',
            'Too many unrecognized commands, goodbye.',
            'Unimplemented command.',
            'Unrecognized command.',
            'EHLO/HELO first.',
            'MAIL first.',
            'RCPT first.',
        ]},
    ],
    'X.5.2' => [
        { 'reason' => 'securityerror',  'string' => ['Cannot Decode response.'] },   # 2FA related error, maybe.
        { 'reason' => 'syntaxerror',    'string' => ['Syntax error.'] },
    ],
    'X.5.3' => [
        { 'reason' => 'mailboxfull',    'string' => ['Domain policy size per transaction exceeded,'] },
        { 'reason' => 'policyviolation','string' => ['Your message has too many recipients.'] },
    ],
    'X.5.4' => [{ 'reason' => 'syntaxerror', 'string' => ['Optional Argument not permitted for that AUTH mode.'] }],
    'X.6.0' => [
        { 'reason' => 'contenterror',   'string' => ['Mail message is malformed.'] },
        { 'reason' => 'networkerror',   'string' => ['Message exceeded 50 hops'] }
    ],
    'X.7.0' => [
        { 'reason' => 'blocked',        'string' => [
            'IP not in whitelist for RCPT domain, closing connection.',
            'unusual rate of unsolicited mail originating from your IP address.',
        ]},
        { 'reason' => 'expired',        'string' => [
            'Temporary System Problem. Try again later.',
            'Try again later, closing connection.',
        ]},
        { 'reason' => 'securityerror',  'string' => [
            'TLS required for RCPT domain, closing connection.',
            'No identity changes permitted.',
            'Must issue a STARTTLS command first.',
            'Too Many Unauthenticated commands.',
        ]},
        { 'reason' => 'policyviolation','string' => [
            'an illegal attachment on your message',
            'This message was blocked because its content presents a potential',
        ]},
        { 'reason' => 'systemerror',    'string' => ['Cannot authenticate due to temporary system problem.'] },
        { 'reason' => 'norelaying',     'string' => ['Mail relay denied.'] },
        { 'reason' => 'rejected',       'string' => ['Mail Sending denied.'] },
    ],
    'X.7.1' => [
        { 'reason' => 'mailboxfull',    'string' => ['Email quota exceeded.'] },
        { 'reason' => 'securityerror',  'string' => [
            'Application-specific password required.',
            'Please log in with your web browser and then try again.',
            'Username and Password not accepted.',
        ]},
        { 'reason' => 'blocked',        'string' => [
            'The IP address sending this message does not have a PTR record setup.',
            "The IP you're using to send mail is not authorized to send email directly to our servers.",
            'this message is likely suspicious due to the very low reputation of the sending IP address',
            'unusual rate of unsolicited mail originating from your IP address.',
        ]},
        { 'reason' => 'spamdetected',   'string' => ['this message is likely unsolicited mail.'] },
        { 'reason' => 'policyviolation','string' => [
            'Messages with multiple addresses in From: header are not accepted.',
            'The user or domain that you are sending to (or from) has a policy',
        ]},
        { 'reason' => 'rejected',       'string' => ['Unauthenticated email is not accepted from this domain.'] },
    ],
    'X.7.4' => [{ 'reason' => 'syntaxerror', 'string' => ['Unrecognized Authentication Type.'] }],
};

sub get {
    # Detect bounce reason from Google Apps
    # @param    [Sisimai::Data] argvs   Parsed email object
    # @return   [String]                The bounce reason for Google Apps
    # @see      https://support.google.com/a/answer/3726730?hl=en
    my $class = shift;
    my $argvs = shift // return undef;
    return $argvs->reason if $argvs->reason;

    substr(my $statuscode = $argvs->deliverystatus, 0, 1, 'X');
    return '' unless exists $StatusList->{ $statuscode };
    return '' unless scalar @{ $StatusList->{ $statuscode } };

    my $reasontext = '';
    for my $e ( @{ $StatusList->{ $statuscode } } ) {
        # Try to match
        next unless grep { rindex($argvs->diagnosticcode, $_) > -1 } @{ $e->{'string'} };
        $reasontext = $e->{'reason'};
        last;
    }
    return $reasontext;
}

1;
__END__

=encoding utf-8

=head1 NAME

Sisimai::Rhost::GoogleApps - Detect the bounce reason returned from Google Apps.

=head1 SYNOPSIS

    use Sisimai::Rhost;

=head1 DESCRIPTION

Sisimai::Rhost detects the bounce reason from the content of Sisimai::Data
object as an argument of get() method when the value of C<rhost> of the object
is "aspmx.l.google.com". This class is called only Sisimai::Data class.

=head1 CLASS METHODS

=head2 C<B<get(I<Sisimai::Data Object>)>>

C<get()> detects the bounce reason.

=head1 AUTHOR

azumakuniyuki

=head1 COPYRIGHT

Copyright (C) 2014-2016,2018-2019 azumakuniyuki, All rights reserved.

=head1 LICENSE

This software is distributed under The BSD 2-Clause License.

=cut
