|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Haineko::Sendmail;  | 
| 
2
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
854
 | 
 use strict;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
    | 
| 
3
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
5
 | 
 use warnings;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
4
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
1062
 | 
 use Encode;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12578
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
101
 | 
    | 
| 
5
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
10
 | 
 use Try::Tiny;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
55
 | 
    | 
| 
6
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
15469
 | 
 use Time::Piece;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36787
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
7
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
104
 | 
 use Scalar::Util;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68
 | 
    | 
| 
8
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
1105
 | 
 use Haineko::Log;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37
 | 
    | 
| 
9
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
7
 | 
 use Haineko::JSON;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
    | 
| 
10
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
7
 | 
 use Haineko::Default;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
11
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
7
 | 
 use Haineko::SMTPD::Milter;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
    | 
| 
12
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
1186
 | 
 use Haineko::SMTPD::Session;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
13
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
8
 | 
 use Haineko::SMTPD::Response;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8589
 | 
    | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub submit {  | 
| 
16
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
  
0
  
 | 
26
 | 
     my $class = shift;  | 
| 
17
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
     my $httpd = shift;  # (Haineko::HTTPD)  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
19
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
     my $serverconf = $httpd->{'conf'}->{'smtpd'};  | 
| 
20
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52
 | 
     my $defaultset = Haineko::Default->conf;  | 
| 
21
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
     my $responsecn = 'Haineko::SMTPD::Response';  | 
| 
22
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
     my $responsejk = 'response';    # (String) Response json key name  | 
| 
23
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
     my $exceptions = 0;             # (Integer) Flag, be set in try {...} catch { ... }  | 
| 
24
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
     my $tmpsession = undef;         # (Haineko::SMTPD::Session) Temporary session object  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Create a queue id (session id)  | 
| 
27
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
111
 | 
     my $queueident = Haineko::SMTPD::Session->make_queueid;  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Variables related user information such as hostname or port number.  | 
| 
30
 | 
12
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
55
 | 
     my $xforwarded = [ split( ',', $httpd->req->header('X-Forwarded-For') || q() ) ];  | 
| 
31
 | 
12
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
2868
 | 
     my $remoteaddr = pop @$xforwarded || $httpd->req->address // undef;  | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
32
 | 
12
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
217
 | 
     my $remoteport = $httpd->req->env->{'REMOTE_PORT'} // undef;  | 
| 
33
 | 
12
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
125
 | 
     my $remotehost = $httpd->req->env->{'REMOTE_HOST'} // undef;  | 
| 
34
 | 
12
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
119
 | 
     my $remoteuser = $httpd->req->env->{'REMOTE_USER'} // undef;  | 
| 
35
 | 
12
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
131
 | 
     my $useragent1 = $httpd->req->user_agent // undef;  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Syslog object  | 
| 
38
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
523
 | 
     my $syslogargv = {  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'queueid'    => $queueident,  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'facility'   => $serverconf->{'syslog'}->{'facility'},  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'disabled'   => $serverconf->{'syslog'}->{'disabled'},  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'useragent'  => $useragent1,  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'remoteaddr' => $remoteaddr,  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'remoteport' => $remoteport,  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
46
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31
 | 
     for my $e ( 'facility', 'disabled' ) {  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Fallback to the default value when these values are not defined in  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # etc/haineko.cf  | 
| 
49
 | 
24
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
87
 | 
         $syslogargv->{ $e } //= $defaultset->{'smtpd'}->{'syslog'}->{ $e };  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
51
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
136
 | 
     my $nekosyslog = Haineko::Log->new( %$syslogargv );  | 
| 
52
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
     my $esresponse = undef;  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Create a new SMTP Session  | 
| 
55
 | 
12
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
48
 | 
     $tmpsession = Haineko::SMTPD::Session->new(   | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     'queueid'    => $queueident,  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     'referer'    => $httpd->req->referer // q(),  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     'useragent'  => $useragent1,  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     'remoteaddr' => $remoteaddr,  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     'remoteport' => $remoteport );  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
63
 | 
12
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
64
 | 
     if( $httpd->debug == 0 && $httpd->req->method eq 'GET' ) {  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # GET method is not permitted in production mode.  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Use ``POST'' method instead.  | 
| 
66
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
         $esresponse = $responsecn->r( 'http', 'method-not-supported' );  | 
| 
67
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         $tmpsession->add_response( $esresponse );  | 
| 
68
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
         $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
70
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
         return $httpd->res->json( 405, $tmpsession->damn );  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     CONN: {  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #   ____ ___  _   _ _   _   | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  / ___/ _ \| \ | | \ | |  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |  | | | |  \| |  \| |  | 
| 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |__| |_| | |\  | |\  |  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  \____\___/|_| \_|_| \_|  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #                           | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Check the remote address  | 
| 
81
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
181
 | 
         my $relayhosts = undef;  | 
| 
 
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
    | 
| 
82
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
         my $ip4network = undef;  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         try {   | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Check etc/relayhosts file.  The remote host or the network should  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # be listed in the file.  | 
| 
87
 | 
11
 | 
 
 | 
 
 | 
  
11
  
 | 
 
 | 
350
 | 
             $exceptions = 0;  | 
| 
88
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3602
 | 
             require Net::CIDR::Lite;  | 
| 
89
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7604
 | 
             $relayhosts = Haineko::JSON->loadfile( $serverconf->{'access'}->{'conn'} );  | 
| 
90
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
             $ip4network = Net::CIDR::Lite->new( @{ $relayhosts->{'relayhosts'} } );  | 
| 
 
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1507
 | 
    | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } catch {  | 
| 
93
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
             $exceptions = 1;  | 
| 
94
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
126
 | 
         };  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # If etc/relayhosts file does not exist or failed to load,   | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # only 127.0.0.1 is permitted to relay.  | 
| 
98
 | 
11
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
311
 | 
         $ip4network //= Net::CIDR::Lite->new( '127.0.0.1/32' );  | 
| 
99
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
50
 | 
         $ip4network->add( '127.0.0.1/32' ) unless $ip4network->list;  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Haineko relays an email from any to any when the remote user successfully  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # authenticated by Haineko with etc/password file.  | 
| 
103
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1525
 | 
         $relayhosts->{'open-relay'} = 1 if $remoteuser;  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
105
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
41
 | 
         if( not $relayhosts->{'open-relay'} ) {  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # When the value of ``openrelay'' is defined as ``0'' in etc/relayhosts,  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Only permitted host can send an email.  | 
| 
108
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
53
 | 
             if( not $ip4network->find( $remoteaddr ) ) {  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # The remote address or the remote network is not listed in   | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # etc/relayhosts.  | 
| 
111
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $esresponse = $responsecn->r( 'auth', 'access-denied' );  | 
| 
112
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $tmpsession->add_response( $esresponse );  | 
| 
113
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
115
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 return $httpd->res->json( 403, $tmpsession->damn );  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         XXFI_CONNECT: {  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Act like xxfi_connect() function  | 
| 
121
 | 
11
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
960
 | 
             my $milterlibs = $serverconf->{'milter'}->{'conn'} || [];  | 
| 
 
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
76
 | 
    | 
| 
122
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
             my $mfresponse = undef;  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
124
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
             for my $e ( @{ Haineko::SMTPD::Milter->import( $milterlibs ) } ) {  | 
| 
 
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
    | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Check the remote address with conn() method of each milter  | 
| 
126
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $mfresponse = $responsecn->new( 'code' => 421, 'command' => 'CONN' );  | 
| 
127
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 last if not $e->conn( $mfresponse, $remotehost, $remoteaddr );  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
129
 | 
11
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
126
 | 
             last XXFI_CONNECT unless defined $mfresponse;  | 
| 
130
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             last XXFI_CONNECT unless $mfresponse->error;  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Reject connection  | 
| 
133
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $esresponse = $mfresponse;  | 
| 
134
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
135
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
137
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } # End of ``XXFI_CONNECT''  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # End of ``CONN''  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
142
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
     my $headerlist = [ 'from', 'replyto', 'subject' ];  | 
| 
143
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
     my $emencoding = q();   # Character set such as iSO-2022-JP, UTF-8, or ISO-8859-1.  | 
| 
144
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     my $recipients = [];    # Recipient addresses specified in JSON  | 
| 
145
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
     my $cannotsend = [];    # Invalid recipient addresses checked by the following codes  | 
| 
146
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     my ( $ehlo, $mail, $rcpt, $head, $body, $json ) = undef;  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     try {   | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Load email data as a JSON  | 
| 
150
 | 
11
 | 
 
 | 
 
 | 
  
11
  
 | 
 
 | 
301
 | 
         $exceptions = 0;  | 
| 
151
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
         $json = Haineko::JSON->loadjson( $httpd->req->content );  | 
| 
152
 | 
10
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
64
 | 
         $ehlo = $json->{'ehlo'} // $json->{'helo'} // q();  | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
153
 | 
10
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
77
 | 
         $mail = $json->{'mail'} // $json->{'send'} // $json->{'from'} // q();  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
154
 | 
10
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
87
 | 
         $rcpt = $json->{'rcpt'} // $json->{'recv'} // $json->{'to'}   // [];  | 
| 
 
 | 
 
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
155
 | 
10
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
67
 | 
         $body = $json->{'body'} // q();  | 
| 
156
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
         $head = {};  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
158
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
         for my $e ( @$headerlist ) {  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Load each email header  | 
| 
160
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
52
 | 
             last unless ref $json->{'header'} eq 'HASH';  | 
| 
161
 | 
6
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
21
 | 
             next unless defined $json->{'header'}->{ $e };  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
163
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             $head->{ $e } = $json->{'header'}->{ $e };  | 
| 
164
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
             utf8::decode $head->{ $e } unless utf8::is_utf8 $head->{ $e };  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
167
 | 
10
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
144
 | 
         $emencoding = $head->{'charset'} // $head->{'Charset'} // 'UTF-8';  | 
| 
 
 | 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
168
 | 
10
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
70
 | 
         $head->{'subject'} //= q();  | 
| 
169
 | 
10
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
53
 | 
         utf8::decode $body unless utf8::is_utf8 $body;  | 
| 
170
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
         $recipients = $rcpt;  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } catch {  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Failed to load the email body or email headers  | 
| 
174
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
12
 | 
         $exceptions = 1;  | 
| 
175
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
         $esresponse = $responsecn->r( 'http', 'malformed-json' );  | 
| 
176
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
         $esresponse = $esresponse->mesg( $_ ) if $httpd->debug;  | 
| 
177
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
         $tmpsession->add_response( $esresponse );  | 
| 
178
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
         $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
179
 | 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
148
 | 
     };  | 
| 
180
 | 
11
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
301
 | 
     return $httpd->res->json( 400, $tmpsession->damn ) if $exceptions;  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
182
 | 
10
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
68
 | 
     DETECT_LOOP_DURING_HAINEKO_SERVERS: {  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  _                        ___   | 
| 
184
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |    ___   ___  _ __   |__ \  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |   / _ \ / _ \| '_ \    / /  | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |__| (_) | (_) | |_) |  |_|   | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |_____\___/ \___/| .__/   (_)   | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #                  |_|            | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Check ``X-Haineko-Loop'' header  | 
| 
190
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
         my $v = $head->{'x-haineko-loop'} || [];  | 
| 
191
 | 
10
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
35
 | 
         if( ref $v eq 'ARRAY' ) {  | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # The value of X-Haineko-Loop is an array reference  | 
| 
193
 | 
10
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
27
 | 
             if( scalar @$v ) {  | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # ``X-Haineko-Loop'' exists in received JSON   | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # "header": { ..., "x-haineko-loop": [] },   | 
| 
196
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 if( grep { $serverconf->{'servername'} eq $_ } @$v ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # DETECTED LOOP:  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # THE MESSAGE HAS ALREADY PASSED THIS Haineko  | 
| 
199
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     $esresponse = $responsecn->r( 'conn', 'detect-loop' );  | 
| 
200
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     $tmpsession->add_response( $esresponse );  | 
| 
201
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
203
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
204
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # The header is empty or other data structure.  | 
| 
207
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
                 push @{ $head->{'x-haineko-loop'} }, $serverconf->{'servername'};  | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
53
 | 
    | 
| 
208
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # The value of the header is not an array reference, set this hostname  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # into X-Haineko-Loop header.  | 
| 
212
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $head->{'x-haineko-loop'} = [ $serverconf->{'servername'} ];  | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     EHLO: {  | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  _____ _   _ _     ___    | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | ____| | | | |   / _ \   | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |  _| | |_| | |  | | | |  | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |___|  _  | |__| |_| |  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |_____|_| |_|_____\___/   | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #                           | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Check the value of ``ehlo'' field  | 
| 
224
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
         require Haineko::SMTPD::RFC5321;  | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2980
 | 
    | 
| 
225
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
         require Haineko::SMTPD::RFC5322;  | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
227
 | 
10
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
105
 | 
         if( not length $ehlo ) {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # The value is empty: { "ehlo": '', ... }  | 
| 
229
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
             $esresponse = $responsecn->r( 'ehlo', 'require-domain' );  | 
| 
230
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
231
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
233
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
             return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } elsif( not Haineko::SMTPD::RFC5321->check_ehlo( $ehlo ) ) {  | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # The value is invalid: { "ehlo": 1, ... }  | 
| 
237
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
             $esresponse = $responsecn->r( 'ehlo', 'invalid-domain' );  | 
| 
238
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
239
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
241
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         XXFI_HELO: {  | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Act like xxfi_helo() function  | 
| 
246
 | 
8
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
14
 | 
             my $milterlibs = $serverconf->{'milter'}->{'ehlo'} || [];  | 
| 
 
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
    | 
| 
247
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
             my $mfresponse = undef;  | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
249
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
             for my $e ( @{ Haineko::SMTPD::Milter->import( $milterlibs ) } ) {  | 
| 
 
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52
 | 
    | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Check the EHLO value with ehlo() method of each milter  | 
| 
251
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $mfresponse = $responsecn->new( 'code' => 521, 'command' => 'EHLO' );  | 
| 
252
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 last if not $e->ehlo( $mfresponse, $remotehost, $remoteaddr );  | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
254
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
255
 | 
8
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
34
 | 
             if( defined $mfresponse && $mfresponse->error ){  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # The value of EHLO is rejected  | 
| 
257
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $esresponse = $mfresponse->damn;  | 
| 
258
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $tmpsession->add_response( $mfresponse );  | 
| 
259
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $nekosyslog->w( 'err', $esresponse );  | 
| 
260
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
261
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
262
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } # End of ``XXFI_HELO''  | 
| 
264
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
52
 | 
         $tmpsession->ehlo(1);  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # End of ``EHLO''  | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     MAIL_FROM: {  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  __  __    _    ___ _       _____ ____   ___  __  __   | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |  \/  |  / \  |_ _| |     |  ___|  _ \ / _ \|  \/  |  | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |\/| | / _ \  | || |     | |_  | |_) | | | | |\/| |  | 
| 
272
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |  | |/ ___ \ | || |___  |  _| |  _ <| |_| | |  | |  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |_|  |_/_/   \_\___|_____| |_|   |_| \_\\___/|_|  |_|  | 
| 
274
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #                                                        | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Check the envelope sender address  | 
| 
276
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
         if( not length $mail ) {  | 
| 
 
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
44
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # The envelope sender address is empty: { "mail": '', ... }  | 
| 
278
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
             $esresponse = $responsecn->r( 'mail', 'syntax-error' );  | 
| 
279
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
280
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
282
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
             return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } elsif( not Haineko::SMTPD::RFC5322->is_emailaddress( $mail ) ) {  | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # The envelope sender address is not valid: { "mail": 'neko', ... }  | 
| 
286
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
             $esresponse = $responsecn->r( 'mail', 'domain-required' );  | 
| 
287
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
288
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
290
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
             return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } elsif( Haineko::SMTPD::RFC5321->is8bit( \$mail ) ) {  | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # The envelope sender address includes multi-byte character  | 
| 
294
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $esresponse = $responsecn->r( 'mail', 'non-ascii' );  | 
| 
295
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
296
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
298
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         XXFI_ENVFROM: {  | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Act like xxfi_envfrom() function  | 
| 
303
 | 
6
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
10
 | 
             my $milterlibs = $serverconf->{'milter'}->{'mail'} || [];  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
    | 
| 
304
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
             my $mfresponse = undef;  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
306
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
             for my $e ( @{ Haineko::SMTPD::Milter->import( $milterlibs ) } ) {  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
    | 
| 
307
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Check the envelope sender address with mail() method of each milter  | 
| 
308
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $mfresponse = $responsecn->new( 'code' => 501, 'dsn' => '5.1.8', 'command' => 'MAIL' );  | 
| 
309
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 last if not $e->mail( $mfresponse, $mail );  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
312
 | 
6
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
24
 | 
             if( defined $mfresponse && $mfresponse->error ){  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # The envelope sender address rejected  | 
| 
314
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $esresponse = $mfresponse->damn;  | 
| 
315
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $tmpsession->add_response( $mfresponse );  | 
| 
316
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $nekosyslog->w( 'err', $esresponse );  | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
318
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } # End of ``XXFI_ENVFROM''  | 
| 
321
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
         $tmpsession->mail(1);  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # End of ``MAIL_FROM''  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     RCPT_TO: {  | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  ____   ____ ____ _____   _____ ___    | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |  _ \ / ___|  _ \_   _| |_   _/ _ \   | 
| 
328
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |_) | |   | |_) || |     | || | | |  | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |  _ <| |___|  __/ | |     | || |_| |  | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |_| \_\\____|_|    |_|     |_| \___/   | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #                                        | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Check envelope recipient addresses  | 
| 
333
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
         my $accessconf = undef;  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
334
 | 
6
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
20
 | 
         my $xrecipient = $serverconf->{'max_rcpts_per_message'} // $defaultset->{'smtpd'}->{'max_rcpts_per_message'};  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
336
 | 
6
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
20
 | 
         if( not scalar @$recipients ) {  | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # No envelope recipient address: { "rcpt": [], ... }  | 
| 
338
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
             $esresponse = $responsecn->r( 'rcpt', 'address-required' );  | 
| 
339
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
340
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
342
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
             return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
345
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
27
 | 
         if( Scalar::Util::looks_like_number $xrecipient ) {  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
347
 | 
5
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
29
 | 
             if( $xrecipient && $xrecipient > 0 ) {  | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
349
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
                 if( scalar @$recipients > $xrecipient ) {  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # The number of recipients exceeded the value of ``max_rcpts_per_message''   | 
| 
351
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # defined in etc/haineko.cf  | 
| 
352
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
                     $esresponse = $responsecn->r( 'rcpt', 'too-many-recipients' );  | 
| 
353
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
                     $tmpsession->add_response( $esresponse );  | 
| 
354
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
                     $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
356
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
                     return $httpd->res->json( 403, $tmpsession->damn );  | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # The value of max_rcpts_per_message does not look like number, such  | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # as "max_rcpts_per_message": "neko"  | 
| 
362
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $esresponse = $responsecn->r( 'conf', 'not-looks-like-number' );  | 
| 
363
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $esresponse->mesg( sprintf( "Wrong value of max_rcpts_per_message: '%s'", $xrecipient ) );  | 
| 
364
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
365
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
366
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
367
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             return $httpd->res->json( 500, $tmpsession->damn );  | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
369
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
370
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         VALID_EMAIL_ADDRESS_OR_NOT: {  | 
| 
371
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # When there is any invalid email address in the value of "rcpt",  | 
| 
372
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Haineko rejects current session and returns an error message as  | 
| 
373
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # a JSON with HTTP status code 400.  | 
| 
374
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             for my $e ( @$recipients ) {   | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Check the all envelope recipient addresses  | 
| 
376
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
15
 | 
                 if( Haineko::SMTPD::RFC5322->is_emailaddress( $e ) ) {  | 
| 
377
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # Check the envelope recipient address includes multi-byte   | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # character or not.  | 
| 
379
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
                     next unless Haineko::SMTPD::RFC5321->is8bit( \$e );  | 
| 
380
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # The envelope recipient address includes multi-byte character  | 
| 
382
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     $esresponse = $responsecn->r( 'mail', 'non-ascii' );  | 
| 
383
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
384
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 } else {  | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # The envelope recipient address is not valid email address  | 
| 
386
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
                     $esresponse = $responsecn->r( 'rcpt', 'is-not-emailaddress' );  | 
| 
387
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
389
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
                 $esresponse->rcpt( $e );  | 
| 
390
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
                 $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
391
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
                 $tmpsession->add_response( $esresponse );  | 
| 
392
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
                 push @$cannotsend, $e;  | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         ALLOWED_RECIPIENT: {  | 
| 
397
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Check etc/recipients file. The envelope recipient address or the   | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # domain part of the recipient address should be listed in the file.  | 
| 
399
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
             try {   | 
| 
400
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
1232
 | 
                 $exceptions = 0;  | 
| 
401
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
                 $accessconf = Haineko::JSON->loadfile( $serverconf->{'access'}->{'rcpt'} );  | 
| 
402
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } catch {  | 
| 
404
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
                 $exceptions = 1;  | 
| 
405
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
             };  | 
| 
406
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
407
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
63
 | 
             if( not defined $accessconf ) {  | 
| 
408
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # If the file does not exist or failed to load the file, only  | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # $serverconf->{'hostname'} or $ENV{'HOSTNAME'} or $ENV{'SERVER_NAME'}   | 
| 
410
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # or `hostname` allowed as a domain part of the recipient address.  | 
| 
411
 | 
4
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
55
 | 
                 $accessconf //= {   | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     'open-relay' => 0,  | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     'domainpart' => [ $serverconf->{'hostname'} ],  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     'recipients' => [],  | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 };  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
418
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
15
 | 
             if( ref $accessconf eq 'HASH' ) {  | 
| 
419
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # etc/recipients file has loaded successfully  | 
| 
420
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
                 if( 0 ) {  | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # DISABLED FOR DUE TO SECURITY REASON.  | 
| 
422
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     if( $remoteaddr eq '127.0.0.1' && $remoteaddr eq $httpd->host ) {  | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # Allow relaying when the value of REMOTE_ADDR is equal to   | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # the value value SERVER_NAME and the value is 127.0.0.1  | 
| 
425
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $accessconf->{'open-relay'} = 1;  | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     } elsif( $remoteuser ) {  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # Turn on open-relay if REMOTE_USER environment variable exists.  | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $accessconf->{'open-relay'} = 1;  | 
| 
430
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
433
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
12
 | 
                 if( not $accessconf->{'open-relay'} ) {  | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # When the value of ``open-relay'' is 0, check the all recipient  | 
| 
435
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # addresses with entries defined in etc/recipients.  | 
| 
436
 | 
4
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
13
 | 
                     my $r = $accessconf->{'recipients'} || [];  | 
| 
437
 | 
4
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
10
 | 
                     my $d = $accessconf->{'domainpart'} || [];  | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
439
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
                     for my $e ( @$recipients ) {  | 
| 
440
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # The envelope recipient address is defined in etc/recipients  | 
| 
441
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
                         next if grep { $e eq $_ } @$r;  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
442
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
443
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # The domain part of the envelope recipient address is  | 
| 
444
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # defined in etc/recipients  | 
| 
445
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
                         my $x = [ split( '@', $e ) ]->[-1];  | 
| 
446
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
                         next if grep { $x eq $_ } @$d;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
    | 
| 
447
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
448
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # Neither the envelope recipient address nor the domain  | 
| 
449
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # part of the address are not allowed at etc/recipients  | 
| 
450
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # file.  | 
| 
451
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
                         $esresponse = $responsecn->r( 'rcpt', 'rejected' );  | 
| 
452
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
                         $esresponse->rcpt( $e );  | 
| 
453
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
                         $tmpsession->add_response( $esresponse );  | 
| 
454
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
                         $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
455
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
456
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
                         push @$cannotsend, $e;  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
458
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
459
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
460
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } # End of ``ALLOWED_RECIPIENT'' block  | 
| 
461
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
462
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         XXFI_ENVRCPT: {  | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Act like xxfi_envrcpt() function  | 
| 
464
 | 
4
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
9
 | 
             my $milterlibs = $serverconf->{'milter'}->{'rcpt'} || [];  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
    | 
| 
465
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
             my $mfresponse = undef;  | 
| 
466
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
467
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
             for my $e ( @{ Haineko::SMTPD::Milter->import( $milterlibs ) } ) {  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Check the envelope recipient address with rcpt() method of each milter  | 
| 
469
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 for my $r ( @$recipients ) {  | 
| 
470
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     my $v = { 'code' => 553, 'dsn' => '5.7.1', 'command' => 'RCPT' };  | 
| 
471
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     $mfresponse = $responsecn->new( %$v );  | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
473
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     next if $e->rcpt( $mfresponse, $r );  | 
| 
474
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
                     if( defined $mfresponse && $mfresponse->error ) {  | 
| 
475
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # One or more envelope recipient address will be rejected  | 
| 
476
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                         $esresponse = $mfresponse->damn;  | 
| 
477
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                         $mfresponse->rcpt( $r );  | 
| 
478
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                         $tmpsession->add_response( $mfresponse );  | 
| 
479
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                         $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
480
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
481
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                         push @$cannotsend, $r;  | 
| 
482
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
483
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
484
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
485
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } # End of ``XXFI_ENVRCPT''  | 
| 
486
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
487
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         CHECK_RCPT: {  | 
| 
488
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Check recipient addresses. If there is no envelope recipient address  | 
| 
489
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Haineko can send. The following code returns error.  | 
| 
490
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
9
 | 
             if( scalar @$cannotsend ) {  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
    | 
| 
491
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Cannot send to one or more envelope recipient address  | 
| 
492
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
                 my $v = [];  | 
| 
493
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
494
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
                 for my $e ( @$recipients ) {  | 
| 
495
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # Verify each envelope recipient address with addresses in  | 
| 
496
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # variable ``@$cannotsend''  | 
| 
497
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
                     next if grep { $e eq $_ } @$cannotsend;  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
498
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     push @$v, $e;  | 
| 
499
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
500
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
501
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
6
 | 
                 if( scalar @$v ) {  | 
| 
502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # Update the variable for holding recipient addresses without  | 
| 
503
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # invalid addresses checked above.  | 
| 
504
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     $recipients = $v;  | 
| 
505
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
506
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 } else {  | 
| 
507
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # There is no valid envelope recipient address.  | 
| 
508
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
                     return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
509
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
510
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
511
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
512
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
         $tmpsession->rcpt(1);  | 
| 
513
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
514
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # End of ``RCPT_TO''  | 
| 
515
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
516
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     DATA: {  | 
| 
517
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  ____    _  _____  _      | 
| 
518
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |  _ \  / \|_   _|/ \     | 
| 
519
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | | | |/ _ \ | | / _ \    | 
| 
520
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |_| / ___ \| |/ ___ \   | 
| 
521
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |____/_/   \_\_/_/   \_\  | 
| 
522
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #                           | 
| 
523
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Check email body and subject header  | 
| 
524
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
         if( not length $body ) {  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
    | 
| 
525
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Empty message is not allowed on Haineko  | 
| 
526
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
             $esresponse = $responsecn->r( 'data', 'empty-body' );  | 
| 
527
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
528
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
529
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
530
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
531
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
532
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
533
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Check message body size  | 
| 
534
 | 
1
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
5
 | 
             my $xmesgsize = $serverconf->{'max_message_size'} // $defaultset->{'smtpd'}->{'max_message_size'};  | 
| 
535
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
536
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
4
 | 
             if( Scalar::Util::looks_like_number $xmesgsize ) {  | 
| 
537
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
538
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
12
 | 
                 if( $xmesgsize > 0 && length( $body ) > $xmesgsize ) {  | 
| 
539
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # Message body size exceeds the limit defined in etc/haineko.cf  | 
| 
540
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # or Haineko::Default module.  | 
| 
541
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     $esresponse = $responsecn->r( 'data', 'mesg-too-big' );  | 
| 
542
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     $tmpsession->add_response( $esresponse );  | 
| 
543
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
544
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
545
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                     return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
546
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
547
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
548
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
549
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # The value of max_message_size does not look like number, such  | 
| 
550
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # as "max_message_size": "neko"  | 
| 
551
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $esresponse = $responsecn->r( 'conf', 'not-looks-like-number' );  | 
| 
552
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $esresponse->mesg( sprintf( "Wrong value of max_message_size: '%s'", $xmesgsize ) );  | 
| 
553
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $tmpsession->add_response( $esresponse );  | 
| 
554
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
555
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
556
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                 return $httpd->res->json( 500, $tmpsession->damn );  | 
| 
557
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
558
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
560
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
         if( not length $head->{'subject'} ) {  | 
| 
561
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Empty subject is not allowed on Haineko  | 
| 
562
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
             $esresponse = $responsecn->r( 'data', 'empty-subject' );  | 
| 
563
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
             $tmpsession->add_response( $esresponse );  | 
| 
564
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
565
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
566
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             return $httpd->res->json( 400, $tmpsession->damn );  | 
| 
567
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
568
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $tmpsession->data(1);  | 
| 
569
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
570
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # End of ``DATA''  | 
| 
571
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
572
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
573
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Create new Haineko::SMTPD::Session object from temporary session object  | 
| 
574
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $submission = Haineko::SMTPD::Session->new(  | 
| 
575
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'addresser' => $mail,  | 
| 
576
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'recipient' => $recipients,  | 
| 
577
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         %{ $tmpsession->damn },  | 
| 
578
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                      );  | 
| 
579
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
580
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $timestamp1 = localtime Time::Piece->new;  | 
| 
581
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $attributes = { 'content_type' => 'text/plain' };  | 
| 
582
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $mailheader = {  | 
| 
583
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'Date'       => $timestamp1->strftime,  | 
| 
584
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'Received'   => $head->{'received'} || [],  | 
| 
585
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'Message-Id' => sprintf( "%s.%d.%d.%03d@%s",   | 
| 
586
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             $submission->queueid, $$, $submission->started->epoch,  | 
| 
587
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             int(rand(100)), $serverconf->{'hostname'}  | 
| 
588
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         ),  | 
| 
589
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'MIME-Version'     => '1.0',  | 
| 
590
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'X-Mailer'         => $submission->useragent // q(),  | 
| 
591
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'X-SMTP-Engine'    => sprintf( "%s %s", $serverconf->{'system'}, $serverconf->{'version'} ),  | 
| 
592
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'X-HTTP-Referer'   => $submission->referer // q(),  | 
| 
593
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
         'X-Haineko-Loop'   => join( ',', @{ $head->{'x-haineko-loop'} } ),  | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
594
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         'X-Originating-IP' => $remoteaddr,  | 
| 
595
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
596
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     push @{ $mailheader->{'Received'} }, sprintf( "from %s ([%s]) by %s with HTTP id %s; %s",   | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
597
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                             $ehlo, $remoteaddr, $serverconf->{'hostname'},   | 
| 
598
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                             $submission->queueid, $timestamp1->strftime );  | 
| 
599
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
600
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     MIME_ENCODING: {  | 
| 
601
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  __  __ ___ __  __ _____   | 
| 
602
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |  \/  |_ _|  \/  | ____|  | 
| 
603
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |\/| || || |\/| |  _|    | 
| 
604
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # | |  | || || |  | | |___   | 
| 
605
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |_|  |_|___|_|  |_|_____|  | 
| 
606
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #                            | 
| 
607
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # detect encodings  | 
| 
608
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $encodelist = [ 'US-ASCII', 'ISO-2022-JP', 'ISO-8859-1' ];  | 
| 
609
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $ctencindex = {  | 
| 
610
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             'US-ASCII'    => '7bit',  | 
| 
611
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             'ISO-8859-1'  => 'quoted-printable',  | 
| 
612
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             'ISO-2022-JP' => '7bit',  | 
| 
613
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         };  | 
| 
614
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
615
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $ctencoding = Haineko::SMTPD::RFC5321->is8bit( \$body ) ? '8bit' : '7bit';  | 
| 
616
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $headencode = 'MIME-Header';  | 
| 
617
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $thisencode = uc $emencoding;    # The value of ``charset'' in received JSON  | 
| 
618
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
619
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if( grep { $thisencode eq $_ } @$encodelist ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
620
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Received supported encodings except UTF-8  | 
| 
621
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if( $ctencoding eq '8bit' ) {  | 
| 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # The message body includes multi-byte character  | 
| 
623
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $ctencoding = $ctencindex->{ $thisencode };  | 
| 
624
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
625
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 if( $thisencode eq 'ISO-2022-JP' ) {  | 
| 
626
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # ISO-2022-JP is 7bit encoding  | 
| 
627
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $thisencode =~ y/-/_/;  | 
| 
628
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $headencode =  sprintf( "MIME-Header-%s", $thisencode );  | 
| 
629
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
630
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
631
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
632
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
633
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Force UTF-8 except available encodings  | 
| 
634
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $emencoding = 'UTF-8';  | 
| 
635
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
636
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $attributes->{'charset'}  = $emencoding;  | 
| 
637
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $attributes->{'encoding'} = $ctencoding;  | 
| 
638
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
639
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         for my $e ( keys %$head ) {  | 
| 
640
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Prepare email headers. Email headers in received JSON except supported  | 
| 
641
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # headers in Haineko are not converted (will be ignored).  | 
| 
642
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             next unless grep { $e eq $_ } @$headerlist;  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
643
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             next unless defined $head->{ $e };  | 
| 
644
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
645
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $fieldvalue = $head->{ $e };  | 
| 
646
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             my $headername = ucfirst $e;  | 
| 
647
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $headername = 'Reply-To' if $headername eq 'Replyto';  | 
| 
648
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
649
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if( Haineko::SMTPD::RFC5321->is8bit( \$fieldvalue ) ) {  | 
| 
650
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # MIME encode if the value of the header contains any multi-byte  | 
| 
651
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # character.  | 
| 
652
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $fieldvalue = Encode::encode( $headencode, $fieldvalue );  | 
| 
653
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
654
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
655
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if( exists $mailheader->{ $headername } ) {  | 
| 
656
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # There is the header which has the same header name, such as  | 
| 
657
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # ``Received:'' header in generic email message.  | 
| 
658
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 if( ref $mailheader->{ $headername } eq 'ARRAY' ) {  | 
| 
659
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # The header already exists, Add the header into array.  | 
| 
660
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     push @{ $mailheader->{ $headername } }, $fieldvalue;  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
661
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
662
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 } else {  | 
| 
663
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # The first header, Add the header as the first element  | 
| 
664
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $mailheader->{ $headername } = [ $mailheader->{ $headername }, $fieldvalue ];  | 
| 
665
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
666
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
667
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
668
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $mailheader->{ $headername } = $fieldvalue;  | 
| 
669
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
670
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } # End of for()  | 
| 
671
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
672
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # End of MIME_ENCODING  | 
| 
673
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
674
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     SENDER_HEADER: {  | 
| 
675
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Add the envelope sender address into ``Sender:'' header.  | 
| 
676
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $fromheader = Haineko::SMTPD::Address->canonify( $head->{'from'} );  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
677
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $envelopemf = $submission->addresser->address;  | 
| 
678
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $mailheader->{'Sender'} = $envelopemf if $fromheader eq $envelopemf;  | 
| 
679
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
680
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
681
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     XXFI_HEADER: {  | 
| 
682
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Act like xxfi_header() function  | 
| 
683
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
         my $milterlibs = $serverconf->{'milter'}->{'head'} || [];  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
684
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $mfresponse = undef;  | 
| 
685
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
686
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         for my $e ( @{ Haineko::SMTPD::Milter->import( $milterlibs ) } ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
687
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Check email headers with head() method of each milter  | 
| 
688
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $mfresponse = $responsecn->new( 'code' => 554, 'dsn' => '5.7.1', 'command' => 'DATA' );  | 
| 
689
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             last if not $e->head( $mfresponse, $mailheader );  | 
| 
690
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
691
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
692
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
         if( defined $mfresponse && $mfresponse->error ){  | 
| 
693
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # One or more email header will be rejected  | 
| 
694
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $esresponse = $mfresponse->damn;  | 
| 
695
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $nekosyslog->w( 'err', $esresponse );  | 
| 
696
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $submission->add_response( $mfresponse );  | 
| 
697
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
698
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $httpd->res->json( 400, $submission->damn );  | 
| 
699
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
700
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # End of ``XXFI_HEADER''  | 
| 
701
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
702
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     XXFI_BODY: {  | 
| 
703
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Act like xxfi_body() function  | 
| 
704
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
         my $milterlibs = $serverconf->{'milter'}->{'body'} || [];  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
705
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $mfresponse = undef;  | 
| 
706
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
707
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         for my $e ( @{ Haineko::SMTPD::Milter->import( $milterlibs ) } ) {  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
708
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Check the email body with body() method of each milter  | 
| 
709
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $mfresponse = $responsecn->new( 'code' => 554, 'dsn' => '5.6.0', 'command' => 'DATA' );  | 
| 
710
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             last if not $e->body( $mfresponse, \$body );  | 
| 
711
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
712
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
713
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
         if( defined $mfresponse && $mfresponse->error ){  | 
| 
714
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # The email body will be rejected  | 
| 
715
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $esresponse = $mfresponse->damn;  | 
| 
716
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $submission->add_response( $mfresponse );  | 
| 
717
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $nekosyslog->w( 'err', $esresponse );  | 
| 
718
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
719
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return $httpd->res->json( 400, $submission->damn );  | 
| 
720
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
721
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
722
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # End of ``XXFI_BODY''  | 
| 
723
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
724
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
725
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # mailertable  | 
| 
726
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $mailerconf = { 'mail' => {}, 'rcpt' => {} };  | 
| 
727
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $defaulthub = undef; # Relays based on the domain part of the recipient address  | 
| 
728
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $sendershub = undef; # Relays based on the domain part of the sender address  | 
| 
729
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
730
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     MAILERTABLE: {  | 
| 
731
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Load etc/mailertable, etc/sendermt  | 
| 
732
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         require Haineko::SMTPD::Relay;  | 
| 
733
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
734
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         for my $e ( 'mail', 'rcpt' ) {  | 
| 
735
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Check the contents of the following mailer table files:  | 
| 
736
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             #   - etc/mailertable   | 
| 
737
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             #   - etc/sendermt  | 
| 
738
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             try {   | 
| 
739
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
                 $exceptions = 0;  | 
| 
740
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $mailerconf->{ $e } = Haineko::JSON->loadfile( $serverconf->{'mailer'}->{ $e } );  | 
| 
741
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
742
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } catch {  | 
| 
743
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Failed to load etc/mailertable or etc/sendermt. Maybe the file  | 
| 
744
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # format is wrong or is not JSON or YAML.  | 
| 
745
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
                 $exceptions = 1;  | 
| 
746
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             };  | 
| 
747
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
748
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Load ``default:'' section in etc/mailertable  | 
| 
749
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
             $defaulthub //= $mailerconf->{'rcpt'}->{'default'};  | 
| 
750
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
751
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             last if $e eq 'rcpt';  | 
| 
752
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
753
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # If the value of ``disabled'' is 1, the mailer table based on the   | 
| 
754
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # domain part of the envelope sender address will not be used.  | 
| 
755
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             next unless exists $mailerconf->{'mail'}->{ $submission->addresser->host };  | 
| 
756
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             next if $mailerconf->{'mail'}->{ $submission->addresser->host }->{'disabled'};  | 
| 
757
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
758
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $sendershub = $mailerconf->{'mail'}->{ $submission->addresser->host };  | 
| 
759
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
760
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
761
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # ``default:'' section was not defined in etc/mailertable. Use system  | 
| 
762
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # configuration as a default hub for relaying.  | 
| 
763
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
         $defaulthub //= Haineko::SMTPD::Relay->defaulthub;  | 
| 
764
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
765
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
766
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $autheninfo = undef;  | 
| 
767
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     AUTHINFO: {  | 
| 
768
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Load etc/authinfo file. Entries defined in etc/authinfo are used at  | 
| 
769
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # relaying to an external SMTP server or sending message to an email  | 
| 
770
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # clouds.  | 
| 
771
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         try {  | 
| 
772
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
             $exceptions = 0;  | 
| 
773
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $mailerconf->{'auth'} = Haineko::JSON->loadfile( $serverconf->{'mailer'}->{'auth'} );  | 
| 
774
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } catch {  | 
| 
775
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Failed to load etc/authinfo file.  | 
| 
776
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
             $exceptions = 1;  | 
| 
777
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         };  | 
| 
778
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
         $autheninfo = $mailerconf->{'auth'} // {};  | 
| 
779
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
780
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
781
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     SENDMIAL: {  | 
| 
782
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  ____  _____ _   _ ____  __  __    _    ___ _       | 
| 
783
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # / ___|| ____| \ | |  _ \|  \/  |  / \  |_ _| |      | 
| 
784
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # \___ \|  _| |  \| | | | | |\/| | / _ \  | || |      | 
| 
785
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #  ___) | |___| |\  | |_| | |  | |/ ___ \ | || |___   | 
| 
786
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # |____/|_____|_| \_|____/|_|  |_/_/   \_\___|_____|  | 
| 
787
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #                                                     | 
| 
788
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         require Module::Load;  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
789
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
790
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $maxworkers = scalar @$recipients;  | 
| 
791
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $preforkset = undef;     # (Parallel::Prefork) object  | 
| 
792
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $preforkarg = undef;     # (Ref->Hash) arguments for Parallel::Prefork  | 
| 
793
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $preforkipc = [];        # (Ref->Array) IO::Pipe objects  | 
| 
794
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $useprefork = 0;         # (Integer) use fork() or not  | 
| 
795
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $procnumber = 0;         # (Integer) Job ID of each child process  | 
| 
796
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $trappedsig = 0;         # (Integer) The number of received USR2 signal  | 
| 
797
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
798
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if( $maxworkers > 1 ) {  | 
| 
799
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Adjust the number of max worker processes.  | 
| 
800
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
             my $xprocesses = $serverconf->{'max_workers'} // $defaultset->{'smtpd'}->{'max_workers'};  | 
| 
801
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
802
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if( Scalar::Util::looks_like_number $xprocesses ) {  | 
| 
803
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Limit the value of max_workers to the value defined in   | 
| 
804
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # etc/haineko.cf or Haineko::Default.  | 
| 
805
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $maxworkers = $xprocesses if $maxworkers > $xprocesses;  | 
| 
806
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
807
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
808
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # The value of max_workers does not look like number, such as  | 
| 
809
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # "max_workers": "neko"  | 
| 
810
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $esresponse = $responsecn->r( 'conf', 'not-looks-like-number' );  | 
| 
811
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $esresponse->mesg( sprintf( "Wrong value of max_workers: '%s'", $xprocesses ) );  | 
| 
812
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $tmpsession->add_response( $esresponse );  | 
| 
813
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $nekosyslog->w( 'err', $esresponse->damn );  | 
| 
814
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
815
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 return $httpd->res->json( 500, $tmpsession->damn );  | 
| 
816
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
817
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $useprefork = 1 if $maxworkers > 1;;  | 
| 
818
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
819
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
820
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if( $useprefork ) {  | 
| 
821
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # If the number of recipients or the value of `maxworkers` is greater  | 
| 
822
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # than 1, fork and send emails by each child process.  | 
| 
823
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             require IO::Pipe;  | 
| 
824
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             require Parallel::Prefork;  | 
| 
825
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
826
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $preforkarg = {  | 
| 
827
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 'max_workers' => $maxworkers,  | 
| 
828
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 'err_respawn_interval' => 2,  | 
| 
829
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 'spawn_interval' => 0,  | 
| 
830
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 'trap_signals' => { 'HUP' => 'TERM', 'TERM' => 'TERM' },  | 
| 
831
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 'before_fork' => sub {  | 
| 
832
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
                     my $k = shift;  | 
| 
833
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $k->{'procnumber'} = $procnumber;  | 
| 
834
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
835
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     if( $procnumber < $maxworkers ) {  | 
| 
836
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $preforkipc->[ $procnumber ] = IO::Pipe->new;;  | 
| 
837
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $procnumber++;  | 
| 
838
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
839
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
840
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             };  | 
| 
841
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $preforkset = Parallel::Prefork->new( $preforkarg );  | 
| 
842
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
843
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $SIG{'USR2'} = sub {  | 
| 
844
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Trap signal from each child process  | 
| 
845
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
                 $trappedsig++;  | 
| 
846
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 kill( 'TERM', $$ ) if $trappedsig >= $maxworkers;  | 
| 
847
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             };  | 
| 
848
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
849
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
850
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $sendmailto = sub {  | 
| 
851
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Code reference for sending an email to each recipient which called  | 
| 
852
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # from Parallel::Prefork->start().  | 
| 
853
 | 
0
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
             my $thisworker = undef;  | 
| 
854
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
855
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             local $SIG{'TERM'} = 'IGNORE';  | 
| 
856
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
857
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if( $useprefork ) {  | 
| 
858
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # fork and send each email  | 
| 
859
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 kill( 'USR2', $preforkset->manager_pid );  | 
| 
860
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $thisworker = $preforkset->{'procnumber'};  | 
| 
861
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
862
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # The number of worker processes has exceeded the limit  | 
| 
863
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 return -1 if $thisworker >= $maxworkers;  | 
| 
864
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
865
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {  | 
| 
866
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # send each email in order  | 
| 
867
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $thisworker = 0;  | 
| 
868
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
869
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
870
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             ONE_TO_ONE: for( my $i = $thisworker; $i < $maxworkers; $i += $maxworkers ) {  | 
| 
871
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Skip if the recipient address is in @$cannotsend  | 
| 
872
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $e = $recipients->[ $i ];  | 
| 
873
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 next if grep { $e eq $_ } @$cannotsend;  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
874
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
875
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Create email address objects from each envelope recipient address  | 
| 
876
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $r = Haineko::SMTPD::Address->new( 'address' => $e );  | 
| 
877
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
878
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $relayclass = q();       # (String) Class name of $smtpmailer  | 
| 
879
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $smtpmailer = undef;     # (Haineko::SMTPD::Relay::*) Mailer object  | 
| 
880
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $relayingto = undef;     # (Ref->Hash) Mailertable  | 
| 
881
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $credential = undef;     # (Ref->Hash) Username and password for SMTP-AUTH or API  | 
| 
882
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
883
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                 $relayingto = $mailerconf->{'rcpt'}->{ $r->host } // $sendershub;  | 
| 
884
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $relayingto = $sendershub if $relayingto->{'disabled'};  | 
| 
885
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
886
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $relayingto = $defaulthub unless keys %$relayingto;  | 
| 
887
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $relayingto = $defaulthub if $relayingto->{'disabled'};  | 
| 
888
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
889
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                 $relayingto->{'port'}   //= 25;  | 
| 
890
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                 $relayingto->{'host'}   //= '127.0.0.1';  | 
| 
891
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                 $relayingto->{'mailer'} //= 'ESMTP';  | 
| 
892
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
893
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 if( $relayingto->{'auth'} ) {  | 
| 
894
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                     $credential = $autheninfo->{ $relayingto->{'auth'} } // {};  | 
| 
895
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }   | 
| 
896
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $relayingto->{'auth'} = q() unless keys %$credential;  | 
| 
897
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
898
 | 
0
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                 if( $relayingto->{'mailer'} =~ m/\A(?:ESMTP|Haineko|MX)\z/ ) {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
899
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # Use Haineko::SMTPD::Relay::ESMTP or Haineko::SMTPD::Relay::Haineko  | 
| 
900
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     #   ::MX      = Directly connect to the host listed in MX Resource record  | 
| 
901
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     #   ::ESMTP   = Generic SMTP connection to an external server  | 
| 
902
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     #   ::Haineko = Relay an message to Haineko running on other host  | 
| 
903
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                     my $methodargv = {  | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
904
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'ehlo'      => $serverconf->{'hostname'},  | 
| 
905
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'mail'      => $submission->addresser->address,  | 
| 
906
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'rcpt'      => $r->address,  | 
| 
907
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'head'      => $mailheader,  | 
| 
908
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'body'      => \$body,  | 
| 
909
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'attr'      => $attributes,  | 
| 
910
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'host'      => $relayingto->{'host'} // '127.0.0.1',  | 
| 
911
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'retry'     => $relayingto->{'retry'} // 0,  | 
| 
912
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'sleep'     => $relayingto->{'sleep'} // 5,  | 
| 
913
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'timeout'   => $relayingto->{'timeout'} // 59,  | 
| 
914
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'starttls'  => $relayingto->{'starttls'},  | 
| 
915
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     };  | 
| 
916
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
917
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     if( $relayingto->{'mailer'} eq 'ESMTP' ) {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
918
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # use well-known port for SMTP  | 
| 
919
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                         $methodargv->{'port'} = $relayingto->{'port'} // 25;  | 
| 
920
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                         $methodargv->{'debug'} = $relayingto->{'debug'} // 0;  | 
| 
921
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
922
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     } elsif( $relayingto->{'mailer'} eq 'Haineko' ) {  | 
| 
923
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # Haineko uses 2794 by default  | 
| 
924
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                         $methodargv->{'port'} = $relayingto->{'port'} // 2794;  | 
| 
925
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
926
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     } elsif( $relayingto->{'mailer'} eq 'MX' ) {  | 
| 
927
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # Mail Exchanger is waiting on *:25  | 
| 
928
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $methodargv->{'port'} = 25;  | 
| 
929
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                         $methodargv->{'debug'} = $relayingto->{'debug'} // 0;  | 
| 
930
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
931
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
932
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $relayclass = sprintf( "Haineko::SMTPD::Relay::%s", $relayingto->{'mailer'} );  | 
| 
933
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     Module::Load::load( $relayclass );  | 
| 
934
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $smtpmailer = $relayclass->new( %$methodargv );  | 
| 
935
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
936
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     if( $relayingto->{'auth'} ) {  | 
| 
937
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # Load credentials for SMTP-AUTH  | 
| 
938
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $smtpmailer->auth( 1 );  | 
| 
939
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $smtpmailer->username( $credential->{'username'} );  | 
| 
940
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $smtpmailer->password( $credential->{'password'} );  | 
| 
941
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
942
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
943
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $smtpmailer->sendmail();  | 
| 
944
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
945
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 } elsif( $relayingto->{'mailer'} =~ m/(?:Discard|Screen)/ ) {  | 
| 
946
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # These mailer does not open new connection to any host.  | 
| 
947
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # Haineko::SMTPD::Relay::  | 
| 
948
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     #   - Discard: email blackhole. It will discard all messages  | 
| 
949
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     #   - Screen: print the email message to STDERR  | 
| 
950
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $relayclass = sprintf( "Haineko::SMTPD::Relay::%s", $relayingto->{'mailer'} );  | 
| 
951
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     Module::Load::load( $relayclass );  | 
| 
952
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
953
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     my $methodargv = {  | 
| 
954
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'ehlo'      => $serverconf->{'hostname'},  | 
| 
955
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'mail'      => $submission->addresser->address,  | 
| 
956
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'rcpt'      => $r->address,  | 
| 
957
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'head'      => $mailheader,  | 
| 
958
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'body'      => \$body,  | 
| 
959
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'attr'      => $attributes,  | 
| 
960
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     };  | 
| 
961
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $smtpmailer = $relayclass->new( %$methodargv );  | 
| 
962
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $smtpmailer->sendmail();  | 
| 
963
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
964
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 } elsif( $relayingto->{'mailer'} =~ m|\A/| or $relayingto->{'mailer'} eq 'File' ) {  | 
| 
965
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # Haineko::SMTPD::Relay::File mailer  | 
| 
966
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     require Haineko::SMTPD::Relay::File;  | 
| 
967
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     my $mailfolder = $relayingto->{'mailer'} eq 'File' ? '/tmp' : $relayingto->{'mailer'};  | 
| 
968
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     my $methodargv = {  | 
| 
969
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'ehlo'      => $serverconf->{'hostname'},  | 
| 
970
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'host'      => $mailfolder,  | 
| 
971
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'mail'      => $submission->addresser->address,  | 
| 
972
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'rcpt'      => $r->address,  | 
| 
973
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'head'      => $mailheader,  | 
| 
974
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'body'      => \$body,  | 
| 
975
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'attr'      => $attributes,  | 
| 
976
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     };  | 
| 
977
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $smtpmailer = Haineko::SMTPD::Relay::File->new( %$methodargv );  | 
| 
978
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $smtpmailer->sendmail();  | 
| 
979
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
980
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 } else {  | 
| 
981
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $mailheader->{'To'} = $r->address;  | 
| 
982
 | 
0
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
                     my $methodargv = {  | 
| 
 
 | 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
983
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'ehlo'    => $serverconf->{'hostname'},  | 
| 
984
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'mail'    => $submission->addresser->address,  | 
| 
985
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'rcpt'    => $r->address,  | 
| 
986
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'head'    => $mailheader,  | 
| 
987
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'body'    => \$body,  | 
| 
988
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'attr'    => $attributes,  | 
| 
989
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'retry'   => $relayingto->{'retry'} // 0,  | 
| 
990
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         'timeout' => $relayingto->{'timeout'} // 60,  | 
| 
991
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     };  | 
| 
992
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
993
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     if( length $relayingto->{'mailer'} ) {  | 
| 
994
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # Use Haineko::SMTPD::Relay::* except H::S::R::ESMTP,   | 
| 
995
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # H::S::R::Haineko and H::S::R::Discard.  | 
| 
996
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         try {  | 
| 
997
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             $relayclass = sprintf( "Haineko::SMTPD::Relay::%s", $relayingto->{'mailer'} );  | 
| 
998
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             Module::Load::load( $relayclass );  | 
| 
999
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             $smtpmailer = $relayclass->new( %$methodargv );  | 
| 
1000
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1001
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             if( $relayingto->{'auth'} ) {  | 
| 
1002
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 # Load credentials for SMTP-AUTH  | 
| 
1003
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 $smtpmailer->auth( 1 );  | 
| 
1004
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 $smtpmailer->username( $credential->{'username'} );  | 
| 
1005
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 $smtpmailer->password( $credential->{'password'} );  | 
| 
1006
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             }  | 
| 
1007
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1008
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             $smtpmailer->sendmail();  | 
| 
1009
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1010
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             if( not $smtpmailer->response->dsn ) {  | 
| 
1011
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 # D.S.N. is empty or undefined.  | 
| 
1012
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 if( $smtpmailer->response->error ) {  | 
| 
1013
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                     # Error but no D.S.N.  | 
| 
1014
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                     $smtpmailer->response->dsn( '5.0.0' );  | 
| 
1015
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 } else {  | 
| 
1016
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                     # Successfully sent but no D.S.N.  | 
| 
1017
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                     $smtpmailer->response->dsn( '2.0.0' );  | 
| 
1018
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 }  | 
| 
1019
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             }  | 
| 
1020
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1021
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         } catch {  | 
| 
1022
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             require Haineko::E;  | 
| 
1023
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             my $v = [ split( "\n", $_ ) ]->[0];  | 
| 
1024
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             my $E = Haineko::E->new( $v );  | 
| 
1025
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             my $R = {   | 
| 
1026
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 'code' => 500,   | 
| 
1027
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 'error' => 1,   | 
| 
1028
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                 'message' => [ $E->mesg->[0] ],  | 
| 
1029
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             };  | 
| 
1030
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1031
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             $smtpmailer = Haineko::SMTPD::Relay->new( %$methodargv );  | 
| 
1032
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             $smtpmailer->response( Haineko::SMTPD::Response->new( %$R ) );  | 
| 
1033
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         };  | 
| 
1034
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1035
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     } else {  | 
| 
1036
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         # The value of "mailer" is empty  | 
| 
1037
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $smtpmailer = Haineko::SMTPD::Relay->new( %$methodargv );  | 
| 
1038
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         my $R = {   | 
| 
1039
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             'code' => 500,   | 
| 
1040
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             'error' => 1,   | 
| 
1041
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                             'message' => [ 'The value of "mailer" is empty' ],  | 
| 
1042
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         };  | 
| 
1043
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                         $smtpmailer->response( Haineko::SMTPD::Response->new( %$R ) );  | 
| 
1044
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     }  | 
| 
1045
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
1046
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1047
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 if( $maxworkers > 1 ) {  | 
| 
1048
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # Send the received response as a JSON from child process  | 
| 
1049
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # to parent process via pipe.  | 
| 
1050
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     my $p = $preforkipc->[ $thisworker ];  | 
| 
1051
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $p->writer;  | 
| 
1052
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     print( { $p } Haineko::JSON->dumpjson( $smtpmailer->response->damn ) );  | 
| 
 
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1053
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     close $p;  | 
| 
1054
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1055
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 } else {  | 
| 
1056
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # Add the received response as a Haineko::SMTPD::Response object  | 
| 
1057
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     # into Haineko::SMTPD::Session object.  | 
| 
1058
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $submission->add_response( $smtpmailer->response );  | 
| 
1059
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
1060
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1061
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } # End of for(ONE_TO_ONE)  | 
| 
1062
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1063
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             return 0;  | 
| 
1064
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1065
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }; # End of `sub sendmailto`  | 
| 
1066
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1067
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if( $useprefork ) {  | 
| 
1068
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Call sendmailto->() and wait all children  | 
| 
1069
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             while(1) {  | 
| 
1070
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 last if $preforkset->signal_received eq 'TERM';  | 
| 
1071
 | 
0
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 last if $preforkset->signal_received eq 'INT';  | 
| 
1072
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $preforkset->start( $sendmailto );  | 
| 
1073
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
1074
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $preforkset->wait_all_children;  | 
| 
1075
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1076
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             for my $v ( @$preforkipc ) {  | 
| 
1077
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 # Receive the response as a JSON from each child  | 
| 
1078
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $j = q();  | 
| 
1079
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $p = undef;  | 
| 
1080
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1081
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $v->reader;  | 
| 
1082
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 while( <$v> ) {  | 
| 
1083
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $j .= $_;  | 
| 
1084
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }  | 
| 
1085
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $p = Haineko::JSON->loadjson( $j );  | 
| 
1086
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $submission->add_response( Haineko::SMTPD::Response->new( %$p ) );  | 
| 
1087
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
1088
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1089
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
1090
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             # Haineko does not fork when the number of recipients is ``1''  | 
| 
1091
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $sendmailto->();  | 
| 
1092
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
1093
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1094
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # End of SENDMAIL  | 
| 
1095
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1096
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Respond to the client  | 
| 
1097
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $nekosyslog->w( 'notice', $submission->damn );  | 
| 
1098
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return $httpd->res->json( 200, $submission->damn );  | 
| 
1099
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
1101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
1102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
1103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |