File Coverage

lib/Sisimai.pm
Criterion Covered Total %
statement 77 77 100.0
branch 18 22 81.8
condition 11 12 91.6
subroutine 11 11 100.0
pod 6 7 85.7
total 123 129 95.3


line stmt bran cond sub pod time code
1             package Sisimai;
2 10     10   1970662 use v5.26;
  10         55  
3 10     10   49 use strict;
  10         24  
  10         341  
4 10     10   41 use warnings;
  10         14  
  10         606  
5 10     10   3920 use version; our $VERSION = version->declare('v5.6.0'); our $PATCHLV = 0;
  10         20593  
  10         79  
6 1 50   1 1 24 sub version { return substr($VERSION->stringify, 1).($PATCHLV > 0 ? 'p'.$PATCHLV : '') }
7 1     1 0 358267 sub libname { 'Sisimai' }
8              
9             sub rise {
10             # Wrapper method for decoding mailbox or Maildir/
11             # @param [String] argv0 Path to mbox or Maildir/
12             # @param [Hash] argv0 or Hash (decoded JSON)
13             # @param [Handle] argv0 or STDIN
14             # @param [Hash] argv1 Options for decoding
15             # @options argv1 [Integer] delivered 1 = Including "delivered" reason
16             # @options argv1 [Integer] vacation 1 = Including "vacation" reason
17             # @options argv1 [Array] c___ Code references to a callback method for the message and each file
18             # @return [Array] Decoded objects
19             # @return [undef] undef if the argument was wrong or an empty array
20 112     112 1 9170941 my $class = shift;
21 112 100 100     504 my $argv0 = shift // return undef; die ' ***error: wrong number of arguments' if scalar @_ % 2;
  111         497  
22 110         345 my $argv1 = { @_ };
23              
24 110         4005 require Sisimai::Mail;
25 110         2866 require Sisimai::Fact;
26              
27 110   50     771 my $mail = Sisimai::Mail->new($argv0) || return undef;
28 110         606 my $kind = $mail->kind;
29 110 100       1300 my $c___ = ref $argv1->{'c___'} eq 'ARRAY' ? $argv1->{'c___'} : [undef, undef];
30 110         242 my $sisi = [];
31              
32 110         341 while( my $r = $mail->data->read ) {
33             # Read and decode each email file
34 2868         14392 my $path = $mail->data->path;
35             my $args = {
36             'data' => $r, 'hook' => $c___->[0], 'origin' => $path,
37 2868         52189 'delivered' => $argv1->{'delivered'}, 'vacation' => $argv1->{'vacation'}
38             };
39 2868   100     20577 my $fact = Sisimai::Fact->rise($args) || [];
40              
41 2868 100       14027 if( $c___->[1] ) {
42             # Run the callback function specified with "c___" parameter of Sisimai->rise after reading
43             # each email file in Maildir/ every time
44 667         9553 $args = {'kind' => $kind, 'mail' => \$r, 'path' => $path, 'fact' => $fact};
45 667 50       1878 eval { $c___->[1]->($args) if ref $c___->[1] eq 'CODE' };
  667         6065  
46 667 50       135931 warn sprintf(" ***warning: Something is wrong in the second element of the 'c___': %s", $@) if $@;
47             }
48 2868 100       39415 push @$sisi, @$fact if scalar @$fact;
49             }
50 110 100       530 return undef unless scalar @$sisi;
51 104         1771 return $sisi;
52             }
53              
54             sub dump {
55             # Wrapper method to decode mailbox/Maildir and dump as JSON
56             # @param [String] argv0 Path to mbox or Maildir/
57             # @param [Hash] argv0 or Hash (decoded JSON)
58             # @param [Handle] argv0 or STDIN
59             # @param [Hash] argv1 Options for decoding
60             # @options argv1 [Integer] delivered 1 = Including "delivered" reason
61             # @options argv1 [Integer] vacation 1 = Including "vacation" reason
62             # @options argv1 [Code] hook Code reference to a callback method
63             # @return [String] Decoded data as JSON text
64 8     8 1 827000 my $class = shift;
65 8 100 100     48 my $argv0 = shift // return undef; die ' ***error: wrong number of arguments' if scalar @_ % 2;
  7         44  
66 6         19 my $argv1 = { @_ };
67 6   100     37 my $nyaan = __PACKAGE__->rise($argv0, %$argv1) // [];
68              
69 6         63 for my $e ( @$nyaan ) {
70             # Set UTF8 flag before converting to JSON string
71 688         2362 utf8::decode $e->{'subject'};
72 688         1968 utf8::decode $e->{'diagnosticcode'};
73             }
74              
75 6         1012 require Module::Load;
76 6         1872 Module::Load::load('JSON', '-convert_blessed_universally');
77 6         2465 my $jsonparser = JSON->new->allow_blessed->convert_blessed->utf8;
78 6         270 my $jsonstring = $jsonparser->encode($nyaan);
79              
80 6 50       288 utf8::encode $jsonstring if utf8::is_utf8 $jsonstring;
81 6         10326 return $jsonstring;
82             }
83              
84             sub engine {
85             # Decoding engine list (MTA modules)
86             # @return [Hash] Decoding engine table
87 1     1 1 2911 my $class = shift;
88 1         5 my $table = {};
89              
90 1         3 for my $e ('Lhost', 'ARF', 'RFC3464', 'RFC3834') {
91 4         11 my $r = 'Sisimai::'.$e;
92 4         28 (my $loads = $r) =~ s|::|/|g;
93 4         20 require $loads.'.pm';
94              
95 4 100       16 if( $e eq 'Lhost' ) {
96             # Sisimai::Lhost::*
97 1         19 for my $ee ( $r->index->@* ) {
98             # Load and get the value of "description" from each module
99 37         51 my $rr = 'Sisimai::'.$e.'::'.$ee;
100 37         161 ($loads = $rr) =~ s|::|/|g;
101 37         127 require $loads.'.pm';
102 37         193 $table->{ $rr } = $rr->description;
103             }
104             } else {
105             # Sisimai::ARF, Sisimai::RFC3464, and Sisimai::RFC3834
106 3         17 $table->{ $r } = $r->description;
107             }
108             }
109 1         5 return $table;
110             }
111              
112             sub reason {
113             # Reason list Sisimai can detect
114             # @return [Hash] Reason list table
115 2     2 1 73376 my $class = shift;
116 2         5 my $table = {};
117              
118             # These reasons are not included in the results of Sisimai::Reason->index
119 2         15 require Sisimai::Reason;
120 2         14 my @names = ( Sisimai::Reason->index->@*, qw|Delivered Feedback Undefined Vacation|);
121              
122 2         15 for my $e ( @names ) {
123             # Call ->description() method of Sisimai::Reason::*
124 68         84 my $r = 'Sisimai::Reason::'.$e;
125 68         226 (my $loads = $r) =~ s|::|/|g;
126 68         15583 require $loads.'.pm';
127 68         371 $table->{ $e } = $r->description;
128             }
129 2         14 return $table;
130             }
131              
132             sub match {
133             # Try to match with message patterns
134             # @param [String] Error message text
135             # @return [String] Reason text
136 95     95 1 42232 my $class = shift;
137 95   100     214 my $argvs = shift || return "";
138              
139 94         458 require Sisimai::Reason;
140 94         405 return Sisimai::Reason->match(lc $argvs);
141             }
142              
143             1;
144             __END__