1# --
2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
3# --
4# This software comes with ABSOLUTELY NO WARRANTY. For details, see
5# the enclosed file COPYING for license information (GPL). If you
6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
7# --
8
9package Kernel::System::PostMaster::Filter::FollowUpArticleVisibilityCheck;
10
11use strict;
12use warnings;
13
14our @ObjectDependencies = (
15    'Kernel::System::Log',
16    'Kernel::System::CustomerUser',
17    'Kernel::System::Ticket',
18    'Kernel::System::Ticket::Article',
19);
20
21sub new {
22    my ( $Type, %Param ) = @_;
23
24    # allocate new hash for object
25    my $Self = {};
26    bless( $Self, $Type );
27
28    # get parser object
29    $Self->{ParserObject} = $Param{ParserObject} || die "Got no ParserObject!";
30
31    # Get communication log object.
32    $Self->{CommunicationLogObject} = $Param{CommunicationLogObject} || die "Got no CommunicationLogObject!";
33
34    return $Self;
35}
36
37sub Run {
38    my ( $Self, %Param ) = @_;
39
40    # This filter is not needed if there is no TicketID.
41    return 1 if !$Param{TicketID};
42
43    # check needed stuff
44    for (qw(JobConfig GetParam UserID)) {
45        if ( !$Param{$_} ) {
46            $Self->{CommunicationLogObject}->ObjectLog(
47                ObjectLogType => 'Message',
48                Priority      => 'Error',
49                Key           => 'Kernel::System::PostMaster::Filter::FollowUpArticleVisibilityCheck',
50                Value         => "Need $_!",
51            );
52            return;
53        }
54    }
55
56    # Only run if we have a follow-up article with SenderType 'customer'.
57    #   It could be that follow-ups have a different SenderType like 'system' for
58    #   automatic notifications. In these cases there is no need to hide them.
59    #   See also bug#10182 for details.
60    if (
61        !$Param{GetParam}->{'X-OTRS-FollowUp-SenderType'}
62        || $Param{GetParam}->{'X-OTRS-FollowUp-SenderType'} ne 'customer'
63        )
64    {
65        return 1;
66    }
67
68    my %Ticket = $Kernel::OM->Get('Kernel::System::Ticket')->TicketGet(
69        TicketID => $Param{TicketID},
70        UserID   => $Param{UserID},
71    );
72
73    # Check if it is a known customer, otherwise use email address from CustomerUserID field of the ticket.
74    my %CustomerData = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerUserDataGet(
75        User => $Ticket{CustomerUserID},
76    );
77    my $CustomerEmailAddress = $CustomerData{UserEmail} || $Ticket{CustomerUserID};
78
79    # Email sender address
80    my $SenderAddress = $Param{GetParam}->{'X-Sender'};
81
82    # Email Reply-To address for forwarded emails
83    my $ReplyToAddress;
84    if ( $Param{GetParam}->{ReplyTo} ) {
85        $ReplyToAddress = $Self->{ParserObject}->GetEmailAddress(
86            Email => $Param{GetParam}->{ReplyTo},
87        );
88    }
89
90    # check if current sender is customer (do nothing)
91    if ( $CustomerEmailAddress && $SenderAddress ) {
92        return 1 if lc $CustomerEmailAddress eq lc $SenderAddress;
93    }
94
95    my @References = $Self->{ParserObject}->GetReferences();
96
97    my $ArticleObject = $Kernel::OM->Get('Kernel::System::Ticket::Article');
98
99    # Get all internal email articles sent by agents.
100    my @MetaArticleIndex = $ArticleObject->ArticleList(
101        TicketID             => $Param{TicketID},
102        CommunicationChannel => 'Email',
103        SenderType           => 'agent',
104        IsVisibleForCustomer => 0,
105    );
106    return 1 if !@MetaArticleIndex;
107
108    my $ArticleBackendObject = $ArticleObject->BackendForChannel( ChannelName => 'Email' );
109
110    # check if current sender got an internal forward
111    my $IsInternalForward;
112    ARTICLE:
113    for my $MetaArticle ( reverse @MetaArticleIndex ) {
114
115        my $Article = {
116            $ArticleBackendObject->ArticleGet( %{$MetaArticle} )
117        };
118
119        # check recipients
120        next ARTICLE if !$Article->{To};
121
122        # check based on recipient addresses of the article
123        my @ToEmailAddresses = $Self->{ParserObject}->SplitAddressLine(
124            Line => $Article->{To},
125        );
126        my @CcEmailAddresses = $Self->{ParserObject}->SplitAddressLine(
127            Line => $Article->{Cc},
128        );
129        my @EmailAdresses = ( @ToEmailAddresses, @CcEmailAddresses );
130
131        EMAIL:
132        for my $Email (@EmailAdresses) {
133            my $Recipient = $Self->{ParserObject}->GetEmailAddress(
134                Email => $Email,
135            );
136            if ( lc $Recipient eq lc $SenderAddress ) {
137                $IsInternalForward = 1;
138                last ARTICLE;
139            }
140            if ( $ReplyToAddress && lc $Recipient eq lc $ReplyToAddress ) {
141                $IsInternalForward = 1;
142                last ARTICLE;
143            }
144        }
145
146        # check based on Message-ID of the article
147        for my $Reference (@References) {
148            if ( $Article->{MessageID} && $Article->{MessageID} eq $Reference ) {
149                $IsInternalForward = 1;
150                last ARTICLE;
151            }
152        }
153    }
154
155    return 1 if !$IsInternalForward;
156
157    $Param{GetParam}->{'X-OTRS-FollowUp-IsVisibleForCustomer'} = $Param{JobConfig}->{IsVisibleForCustomer} // 0;
158    $Param{GetParam}->{'X-OTRS-FollowUp-SenderType'}           = $Param{JobConfig}->{SenderType} || 'customer';
159
160    return 1;
161}
162
1631;
164