File Coverage

lib/Sisimai/Lhost/DeutscheTelekom.pm
Criterion Covered Total %
statement 47 49 95.9
branch 17 20 85.0
condition 11 16 68.7
subroutine 6 6 100.0
pod 2 2 100.0
total 83 93 89.2


line stmt bran cond sub pod time code
1             package Sisimai::Lhost::DeutscheTelekom;
2 42     42   3284 use parent 'Sisimai::Lhost';
  42         73  
  42         293  
3 42     42   2747 use v5.26;
  42         120  
4 42     42   153 use strict;
  42         58  
  42         989  
5 42     42   140 use warnings;
  42         54  
  42         22405  
6              
7 1     1 1 2 sub description { 'Deutsche Telekom: https://www.telekom.com/' }
8             sub inquire {
9             # Detect an error from T-Online, Deutsche Telekom.
10             # @param [Hash] mhead Message headers of a bounce email
11             # @param [String] mbody Message body of a bounce email
12             # @return [Hash] Bounce data list and message/rfc822 part
13             # @return [undef] failed to decode or the arguments are missing
14             # @since v5.7.0
15 927     927 1 2747 my $class = shift;
16 927   100     1983 my $mhead = shift // return undef;
17 926   100     1926 my $mbody = shift // return undef;
18              
19             # - T-Online: https://www.t-online.de/, @t-online.de, @magenta.de
20             # - DeutscheTelekom: https://www.telekom.com/
21             # - Based on the bounce format of Smail 3, the original design model for Exim
22             # - Tailored for Deutsche Telekom's internal Smail 3 fork with custom banners
23             # - Module name follows the infrastructure owner for cross-language compatibility
24             # - Smail 3: http://www.weird.com/~woods/projects/smail.html
25              
26             # smail-3.2.0.108/src/
27             # notify.c:1052|(void) fprintf(f, "Subject: mail failed, %s\nReference: <%s@%s>\n\n",
28             # notify.c:1053| subject_to, message_id, primary_name);
29             #
30             # T-Online specific headers
31             # Received: from mailin42.aul.t-online.de (mailin42.aul.t-online.de [192.51.100.1])
32             # by mailout11.t-online.de (Postfix) with SMTP id 05E5A1CAC0
33             # From: Mail Delivery System
34             # X-TOI-MSGID: c9412855-531f-497b-b007-5ffc033877a0
35 925 100       1166 state $bannerDTAG = __PACKAGE__->BannerDTAG; return undef unless grep { index($$mbody, $_) > -1 } $bannerDTAG->@*;
  925         1973  
  3700         6914  
36 15         25 state $indicators = __PACKAGE__->INDICATORS;
37 15         22 state $startingof = { 'message' => [$bannerDTAG->[1]] };
38              
39 15         49 my $dscontents = [__PACKAGE__->DELIVERYSTATUS]; my $v = undef;
  15         26  
40 15         67 my $emailparts = Sisimai::RFC5322->part($mbody, [$bannerDTAG->[3], $bannerDTAG->[2]]);
41 15         29 my $messagelog = '';
42 15         16 my $readcursor = 0; # (Integer) Points the current cursor position
43 15         14 my $recipients = 0; # (Integer) The number of 'Final-Recipient' header
44              
45 15         55 for my $e ( split("\n", $emailparts->[0]) ) {
46             # Read error messages and delivery status lines from the head of the email to the previous
47             # line of the beginning of the original message.
48 60 100       74 unless( $readcursor ) {
49             # Beginning of the bounce message or message/delivery-status part
50 25 100       57 if( index($e, $startingof->{'message'}->[0]) == 0 ) {
51             # |------------------------- Failed addresses follow: ---------------------|
52 15         26 $readcursor |= $indicators->{'deliverystatus'};
53              
54             } else {
55             # |------------------------- Message log follows: -------------------------|
56             # The line above may appears only in Smail 3.
57             #
58             # smail-3.2.0.108/src/
59             # models.c:787| if (deliver == NULL && defer == NULL) {
60             # models.c:788| write_log(WRITE_LOG_MLOG, "no valid recipients were found for this message");
61             # models.c:789| return_to_sender = TRUE;
62             # models.c:879| }
63 10 100 66     63 $messagelog .= " ".$e if $e ne "" && index($e, $bannerDTAG->[0]) < 0;
64             }
65 25         33 next;
66             }
67 35 50 33     109 next if ($readcursor & $indicators->{'deliverystatus'}) == 0 || $e eq "";
68              
69             # |------------------------- Failed addresses follow: ---------------------|
70             #
71             # 552 5.2.2 Quota exceeded (mailbox for user is full)
72             #
73             # |------------------------- Message header follows: ----------------------|
74             # Received: from mail.fragdenstaat.de ([94.130.55.89]) by mailin41.mgt.mul.t-online.de.example.com
75             # with (TLSv1.3:TLS_AES_256_GCM_SHA384 encrypted)
76             # ...
77 35         42 $v = $dscontents->[-1];
78              
79 35 100 66     186 if( index($e, ' <') == 0 && substr($e, -1, 1) eq '>' && index($e, ' ', 1) < 0 ) {
    100 66        
80             # Deutsche Telekom: The recipient address is enclosed in angle brackets.
81             # |------------------------- Failed addresses follow: ---------------------|
82 15 100       55 if( $v->{'recipient'} ) {
83             # There are multiple recipient addresses in the message body.
84 5         14 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
85 5         9 $v = $dscontents->[-1];
86             }
87 15         34 $v->{'recipient'} = substr($e, 2, index($e, '>'));
88 15         17 $recipients++;
89              
90             } elsif( Sisimai::String->aligned(\$e, [' ', '@', '.', ' ... ']) ) {
91             # Smail 3:
92             # - The recipient address is not enclosed in angle brackets.
93             # - Error message begins with " ... failed:"
94             # smail-3.2.0.108/src/
95             # notify.c:845| if (cur->error) {
96             # notify.c:846| (void) fprintf(f, " %s ... failed: %s\n",
97             # notify.c:847| cur->in_addr ? cur->in_addr : "(unknown)",
98             # notify.c:848| cur->error->message);
99             # notify.c:849| }
100             # |------------------------- Failed addresses follow: ---------------------|
101             # kijitora@neko.nyaan.example.com ... unknown host
102 5 50       19 if( $v->{'recipient'} ) {
103             # There are multiple recipient addresses in the message body.
104 0         0 push @$dscontents, __PACKAGE__->DELIVERYSTATUS;
105 0         0 $v = $dscontents->[-1];
106             }
107 5         18 $v->{'recipient'} = substr($e, 1, index($e, ' ', 1) - 1);
108 5         10 $v->{'diagnosis'} = $messagelog.' '.$e;
109 5         13 $recipients++;
110              
111             } else {
112             # 552 5.2.2 Quota exceeded (mailbox for user is full)
113 15         33 $v->{'diagnosis'} = $e;
114             }
115             }
116 15 50       29 return undef unless $recipients;
117 15         55 return {"ds" => $dscontents, "rfc822" => $emailparts->[1]};
118             }
119              
120             1;
121             __END__