File Coverage

blib/lib/Mail/Colander/Session.pm
Criterion Covered Total %
statement 17 127 13.3
branch 0 20 0.0
condition 0 16 0.0
subroutine 6 22 27.2
pod 12 12 100.0
total 35 197 17.7


line stmt bran cond sub pod time code
1             package Mail::Colander::Session;
2 1     1   14 use v5.24;
  1         4  
3 1     1   5 use Moo;
  1         3  
  1         9  
4 1     1   571 use experimental qw< signatures >;
  1         2  
  1         6  
5             { our $VERSION = '0.004' }
6              
7 1     1   292 use Ouch qw< :trytiny_var >;
  1         2  
  1         8  
8 1     1   775 use Mail::Colander::Message;
  1         4  
  1         90  
9              
10             sub coerce_msg ($input) { Mail::Colander::Message->new(entity => $input) }
11              
12 1     1   6 use namespace::clean;
  1         3  
  1         5  
13              
14             has peer_ip => (is => 'ro', default => undef);
15             has peer_port => (is => 'ro', default => undef);
16             has peer_ip_port => (is => 'lazy');
17             has peer_identity => (is => 'rw', clearer => 1, predicate => 1);
18             has reverse_path => (is => 'rw', clearer => 1, predicate => 1);
19             has forward_path => (is => 'rw', clearer => 1, predicate => 1);
20             has mail_min_size => (is => 'rw', clearer => 1, predicate => 1);
21             has mail_data => (is => 'rw', clearer => 1, predicate => 1);
22             has last_op => (is => 'rw', default => 'RST');
23              
24             # the star
25             has message => (
26             is => 'lazy',
27             clearer => 1,
28             coerce => \&coerce_msg,
29             handles => [qw<
30             from
31             recipients to cc bcc
32             subject
33             bare_addresses
34             header_first
35             header_all
36             >],
37             );
38              
39 0     0     sub _build_peer_ip_port ($self) {
  0            
  0            
40 0   0       my $ip = $self->peer_ip // '*undefined*';
41 0   0       my $port = $self->peer_port // 0;
42 0           return "$ip:$port";
43             }
44              
45 0     0 1   sub mail_size ($self) {
  0            
  0            
46 0 0         ouch 400, 'no mail available' unless $self->has_mail_data;
47 0           return length(${$self->mail_data});
  0            
48             }
49              
50 0     0     sub _return ($self, $offset = 1) {
  0            
  0            
  0            
51 0           my (undef, undef, undef, $sub) = caller($offset);
52 0           $self->last_op($sub =~ s{\A .* ::}{}rmxs);
53 0           return $self;
54             }
55              
56 0     0 1   sub reset ($self) {
  0            
  0            
57 0           $self->reset_transaction;
58 0           $self->clear_peer_identity;
59 0           return $self->_return(2);
60             }
61              
62 0     0     sub _start_session ($self, $peer_identity) {
  0            
  0            
  0            
63 0           $self->reset->peer_identity($peer_identity);
64 0           return $self->_return(2);
65             }
66              
67 0     0 1   sub reset_transaction ($self) {
  0            
  0            
68 0           $self->clear_forward_path;
69 0           $self->clear_reverse_path;
70 0           $self->clear_mail_min_size;
71 0           $self->clear_mail_data;
72 0           $self->clear_message;
73 0           return $self->_return(2);
74             }
75              
76 0     0 1   sub HELO ($self, $srv, $peer) { $self->_start_session($peer) }
  0            
  0            
  0            
  0            
  0            
77 0     0 1   sub EHLO ($self, $srv, $peer, $exts) { $self->_start_session($peer) }
  0            
  0            
  0            
  0            
  0            
  0            
78 0     0 1   sub RST ($self, $srv) { $self->reset_transaction }
  0            
  0            
  0            
  0            
79 0     0 1   sub QUIT ($self, $srv) { $self->reset }
  0            
  0            
  0            
  0            
80              
81 0     0 1   sub MAIL ($self, $srv, $reverse_path) {
  0            
  0            
  0            
  0            
82 0 0 0       ouch 400, 'out of sync MAIL command'
      0        
83             if (! $self->has_peer_identity) # no HELO received so far
84             || ($self->has_reverse_path && (! $self->has_mail_data));
85 0           $self->reverse_path($reverse_path =~ s{\A < | > \z}{}rgmxs);
86 0           return $self->_return;
87             }
88              
89 0     0 1   sub RCPT ($self, $srv, $forward_path) {
  0            
  0            
  0            
  0            
90 0 0 0       ouch 400, 'out of sync RCPT command'
91             if (! $self->has_reverse_path) || ($self->has_mail_min_size);
92 0 0         my $fps = $self->has_forward_path ? $self->forward_path : [];
93 0           push($fps->@*, ($forward_path =~ s{\A < | > \z}{}rgmxs));
94 0 0         $self->forward_path($fps) unless $self->has_forward_path;
95 0           return $self->_return;
96             }
97              
98 0     0 1   sub DATA ($self, $srv, $mail_data) {
  0            
  0            
  0            
  0            
99 0 0         ouch 400, 'out of sync DATA, rejected initialization'
100             unless $self->has_mail_min_size;
101 0           $self->mail_data($mail_data);
102 0           return $self->_return;
103             }
104              
105 0     0 1   sub DATA_INIT ($self, $srv) {
  0            
  0            
  0            
106 0 0         ouch 400, 'out of sync DATA command, already receving?'
107             if $self->has_mail_min_size;
108 0 0 0       ouch 400, 'out of sync DATA command'
109             if (! $self->has_reverse_path) || ($self->has_mail_data);
110 0 0         ouch 400, 'no forward-path, DATA makes no sense'
111             unless $self->has_forward_path;
112 0           $self->mail_min_size(0);
113 0           return $self->_return;
114             }
115              
116 0     0 1   sub DATA_PART ($self, $srv, $chunk_ref) {
  0            
  0            
  0            
  0            
117 0 0         ouch 400, 'out of sync DATA-PART, rejected initialization'
118             unless $self->has_mail_min_size;
119 0           $self->mail_min_size($self->mail_min_size + length($$chunk_ref));
120 0           return $self->_return;
121             }
122              
123 0     0     sub _build_message ($self) { return $self->mail_data }
  0            
  0            
  0            
124              
125             1;