File Coverage

lib/Sisimai/SMTP/Command.pm
Criterion Covered Total %
statement 47 47 100.0
branch 22 24 91.6
condition 19 31 61.2
subroutine 7 7 100.0
pod 2 2 100.0
total 97 111 87.3


line stmt bran cond sub pod time code
1             package Sisimai::SMTP::Command;
2 92     92   93615 use v5.26;
  92         250  
3 92     92   338 use strict;
  92         132  
  92         1865  
4 92     92   297 use warnings;
  92         147  
  92         5070  
5 92     92   397 use constant ExceptDATA => ["CONN", "EHLO", "HELO", "MAIL", "RCPT"];
  92         134  
  92         6563  
6 92     92   439 use constant BeforeRCPT => ["CONN", "EHLO", "EHLO", "MAIL", "AUTH", "STARTTLS"];
  92         163  
  92         40192  
7             state $Availables = [
8             "HELO", "EHLO", "MAIL", "RCPT", "DATA", "QUIT", "RSET", "NOOP", "VRFY", "ETRN", "EXPN", "HELP",
9             "AUTH", "STARTTLS", "XFORWARD",
10             "CONN", # CONN is a pseudo SMTP command used only in Sisimai
11             ];
12             state $Detectable = [
13             "HELO", "EHLO", "STARTTLS", "AUTH PLAIN", "AUTH LOGIN", "AUTH CRAM-", "AUTH DIGEST-", "MAIL F",
14             "RCPT", "RCPT T", "DATA", "QUIT", "XFORWARD",
15             ];
16              
17             sub test {
18             # Check that an SMTP command in the argument is valid or not
19             # @param [String] argv0 An SMTP command
20             # @return [Boolean] 0: Is not a valid SMTP command, 1: Is a valid SMTP command
21             # @since v5.0.0
22 7148     7148 1 270642 my $class = shift;
23 7148 100 100     11094 my $argv0 = shift // return 0; return 0 unless length $argv0 > 3;
  7147         13495  
24 5190 100       7380 return 1 if grep { index($argv0, $_) > -1 } @$Availables;
  83040         99670  
25 1971         7747 return 0;
26             }
27              
28             sub find {
29             # Pick an SMTP command from the given string
30             # @param [String] argv0 A transcript text MTA returned
31             # @return [String] An SMTP command
32             # @since v5.0.0
33 3500     3500 1 13062 my $class = shift;
34 3500 100 100     6026 my $argv0 = shift // return ""; return "" unless __PACKAGE__->test($argv0);
  3499         7526  
35              
36 1518         3064 my $issuedcode = ' '.lc($argv0).' ';
37 1518         4747 my $commandmap = {'STAR' => 'STARTTLS', 'XFOR' => 'XFORWARD'};
38 1518         1963 my $commandset = [];
39              
40 1518         2197 for my $e ( @$Detectable ) {
41             # Find an SMTP command from the given string
42 19734 100       19749 my $p0 = index($argv0, $e); next if $p0 < 0;
  19734         22583  
43 2085 100       3927 if( index($e, " ") < 0 ) {
44             # For example, "RCPT T" does not appear in an email address or a domain name
45 1282         1395 my $cx = 1; while(1) {
  1282         1332  
46             # Exclude an SMTP command in the part of an email address, a domain name, such as
47             # DATABASE@EXAMPLE.JP, EMAIL.EXAMPLE.COM, and so on.
48 1282         1995 my $ca = ord(substr($issuedcode, $p0, 1));
49 1282         1938 my $cz = ord(substr($issuedcode, $p0 + length($e) + 1, 1));
50              
51 1282 50 66     5712 last if $ca > 47 && $ca < 58 || $cz > 47 && $cz < 58; # 0-9
      66        
      33        
52 1282 100 66     5581 last if $ca > 63 && $ca < 91 || $cz > 63 && $cz < 91; # @-Z
      100        
      66        
53 1281 50 33     4622 last if $ca > 96 && $ca < 123 || $cz > 96 && $cz < 123; # `-z
      33        
      33        
54 1281         1312 $cx = 0; last;
  1281         1792  
55             }
56 1282 100       2173 next if $cx == 1;
57             }
58              
59             # There is the same command in the "commanset" or nor
60 2084 100       2940 my $cv = substr($e, 0, 4); next if grep { index($cv, $_) == 0 } @$commandset;
  2084         3711  
  571         1446  
61 1529 100       2673 $cv = $commandmap->{ $cv } if exists $commandmap->{ $cv };
62 1529         2893 push @$commandset, $cv;
63             }
64 1518 100       2530 return "" unless scalar @$commandset;
65 1513         5869 return pop @$commandset;
66             }
67              
68             1;
69             __END__