sisimai 4.25.6 → 4.25.11

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sisimai might be problematic. Click here for more details.

Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -3
  3. data/ANALYTICAL-PRECISION +1 -1
  4. data/Benchmarks.mk +1 -1
  5. data/ChangeLog.md +71 -2
  6. data/Developers.mk +2 -2
  7. data/Makefile +1 -1
  8. data/README-JA.md +16 -16
  9. data/README.md +16 -16
  10. data/Repository.mk +1 -1
  11. data/lib/sisimai.rb +3 -3
  12. data/lib/sisimai/address.rb +6 -3
  13. data/lib/sisimai/arf.rb +25 -21
  14. data/lib/sisimai/data.rb +8 -29
  15. data/lib/sisimai/datetime.rb +18 -17
  16. data/lib/sisimai/lhost/amazonses.rb +1 -1
  17. data/lib/sisimai/lhost/domino.rb +29 -4
  18. data/lib/sisimai/lhost/einsundeins.rb +1 -1
  19. data/lib/sisimai/lhost/exchange2007.rb +1 -1
  20. data/lib/sisimai/lhost/exim.rb +12 -8
  21. data/lib/sisimai/lhost/ezweb.rb +1 -1
  22. data/lib/sisimai/lhost/fml.rb +0 -2
  23. data/lib/sisimai/lhost/gsuite.rb +5 -0
  24. data/lib/sisimai/lhost/imailserver.rb +1 -1
  25. data/lib/sisimai/lhost/mailfoundry.rb +3 -4
  26. data/lib/sisimai/lhost/mailmarshalsmtp.rb +2 -2
  27. data/lib/sisimai/lhost/mxlogic.rb +1 -1
  28. data/lib/sisimai/lhost/notes.rb +1 -1
  29. data/lib/sisimai/lhost/office365.rb +1 -1
  30. data/lib/sisimai/lhost/postfix.rb +3 -10
  31. data/lib/sisimai/lhost/qmail.rb +7 -7
  32. data/lib/sisimai/lhost/sendgrid.rb +2 -2
  33. data/lib/sisimai/lhost/sendmail.rb +1 -1
  34. data/lib/sisimai/lhost/verizon.rb +4 -4
  35. data/lib/sisimai/lhost/x3.rb +4 -0
  36. data/lib/sisimai/lhost/x4.rb +8 -8
  37. data/lib/sisimai/lhost/x5.rb +7 -3
  38. data/lib/sisimai/mail.rb +2 -21
  39. data/lib/sisimai/mda.rb +2 -2
  40. data/lib/sisimai/message.rb +47 -83
  41. data/lib/sisimai/reason/blocked.rb +40 -26
  42. data/lib/sisimai/reason/exceedlimit.rb +4 -1
  43. data/lib/sisimai/reason/expired.rb +2 -0
  44. data/lib/sisimai/reason/filtered.rb +1 -0
  45. data/lib/sisimai/reason/hostunknown.rb +3 -0
  46. data/lib/sisimai/reason/mailererror.rb +1 -1
  47. data/lib/sisimai/reason/norelaying.rb +5 -0
  48. data/lib/sisimai/reason/notaccept.rb +2 -0
  49. data/lib/sisimai/reason/policyviolation.rb +4 -0
  50. data/lib/sisimai/reason/rejected.rb +5 -1
  51. data/lib/sisimai/reason/securityerror.rb +5 -6
  52. data/lib/sisimai/reason/spamdetected.rb +17 -15
  53. data/lib/sisimai/reason/suspend.rb +1 -0
  54. data/lib/sisimai/reason/systemerror.rb +2 -0
  55. data/lib/sisimai/reason/userunknown.rb +25 -21
  56. data/lib/sisimai/rfc1894.rb +24 -22
  57. data/lib/sisimai/rfc3464.rb +4 -5
  58. data/lib/sisimai/rfc3834.rb +1 -1
  59. data/lib/sisimai/rfc5322.rb +8 -4
  60. data/lib/sisimai/rhost.rb +6 -8
  61. data/lib/sisimai/rhost/cox.rb +112 -0
  62. data/lib/sisimai/rhost/exchangeonline.rb +8 -1
  63. data/lib/sisimai/rhost/googleapps.rb +4 -1
  64. data/lib/sisimai/rhost/spectrum.rb +73 -0
  65. data/lib/sisimai/smtp/error.rb +8 -6
  66. data/lib/sisimai/smtp/reply.rb +1 -1
  67. data/lib/sisimai/smtp/status.rb +1 -1
  68. data/lib/sisimai/time.rb +1 -2
  69. data/lib/sisimai/version.rb +1 -1
  70. data/set-of-emails/README.md +5 -4
  71. data/set-of-emails/maildir/bsd/arf-25.eml +61 -0
  72. data/set-of-emails/maildir/bsd/lhost-aol-04.eml +23 -23
  73. data/set-of-emails/maildir/bsd/lhost-domino-02.eml +1 -2
  74. data/set-of-emails/maildir/bsd/lhost-exim-61.eml +40 -0
  75. data/set-of-emails/maildir/bsd/lhost-postfix-38.eml +1 -1
  76. data/set-of-emails/maildir/bsd/lhost-postfix-66.eml +80 -0
  77. data/set-of-emails/maildir/bsd/lhost-postfix-67.eml +80 -0
  78. data/set-of-emails/maildir/bsd/lhost-postfix-68.eml +82 -0
  79. data/set-of-emails/maildir/bsd/lhost-postfix-69.eml +80 -0
  80. data/set-of-emails/maildir/bsd/lhost-postfix-70.eml +87 -0
  81. data/set-of-emails/maildir/bsd/lhost-postfix-71.eml +81 -0
  82. data/set-of-emails/maildir/bsd/lhost-postfix-72.eml +81 -0
  83. data/set-of-emails/maildir/bsd/lhost-postfix-73.eml +79 -0
  84. data/set-of-emails/maildir/bsd/lhost-postfix-74.eml +83 -0
  85. data/set-of-emails/maildir/bsd/lhost-sendmail-08.eml +1 -1
  86. data/set-of-emails/maildir/bsd/lhost-sendmail-11.eml +1 -1
  87. data/set-of-emails/maildir/bsd/lhost-sendmail-57.eml +59 -0
  88. data/set-of-emails/maildir/bsd/lhost-sendmail-58.eml +70 -0
  89. data/set-of-emails/maildir/bsd/lhost-sendmail-59.eml +68 -0
  90. data/set-of-emails/maildir/bsd/lhost-x3-06.eml +53 -0
  91. data/set-of-emails/maildir/bsd/rhost-cox-01.eml +192 -0
  92. data/set-of-emails/maildir/bsd/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  93. data/set-of-emails/maildir/bsd/{rhost-exchange-online-02.eml → rhost-exchangeonline-02.eml} +0 -0
  94. data/set-of-emails/maildir/bsd/{rhost-exchange-online-03.eml → rhost-exchangeonline-03.eml} +0 -0
  95. data/set-of-emails/maildir/bsd/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  96. data/set-of-emails/maildir/bsd/{rhost-google-apps-02.eml → rhost-googleapps-02.eml} +0 -0
  97. data/set-of-emails/maildir/bsd/rhost-spectrum-01.eml +111 -0
  98. data/set-of-emails/maildir/dos/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  99. data/set-of-emails/maildir/dos/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  100. data/set-of-emails/maildir/mac/{rhost-exchange-online-01.eml → rhost-exchangeonline-01.eml} +0 -0
  101. data/set-of-emails/maildir/mac/{rhost-google-apps-01.eml → rhost-googleapps-01.eml} +0 -0
  102. data/sisimai-java.gemspec +4 -4
  103. data/sisimai.gemspec +4 -4
  104. metadata +39 -20
@@ -110,8 +110,7 @@ module Sisimai::Lhost
110
110
  # The mail system
111
111
  #
112
112
  # <userunknown@example.co.jp>: host mx.example.co.jp[192.0.2.153] said: 550
113
- # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO
114
- # command)
113
+ # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO command)
115
114
  if readslices[-2].start_with?('Diagnostic-Code:') && cv = e.match(/\A[ \t]+(.+)\z/)
116
115
  # Continued line of the value of Diagnostic-Code header
117
116
  v['diagnosis'] << ' ' << cv[1]
@@ -122,18 +121,12 @@ module Sisimai::Lhost
122
121
  emailsteak[1] << cv[1] << ': ' << cv[2] << "\n"
123
122
 
124
123
  else
125
- if cv = e.match(/[ \t][(]in reply to ([A-Z]{4}).*/)
124
+ if cv = e.match(/[ \t][(]in reply to (?:end of )?([A-Z]{4}).*/) ||
125
+ cv = e.match(/([A-Z]{4})[ \t]*.*command[)]\z/)
126
126
  # 5.1.1 <userunknown@example.co.jp>... User Unknown (in reply to RCPT TO
127
127
  commandset << cv[1]
128
128
  anotherset['diagnosis'] ||= ''
129
129
  anotherset['diagnosis'] << ' ' << e
130
-
131
- elsif cv = e.match(/([A-Z]{4})[ \t]*.*command[)]\z/)
132
- # to MAIL command)
133
- commandset << cv[1]
134
- anotherset['diagnosis'] ||= ''
135
- anotherset['diagnosis'] << ' ' << e
136
-
137
130
  else
138
131
  # Alternative error message and recipient
139
132
  if cv = e.match(/\A[<]([^ ]+[@][^ ]+)[>] [(]expanded from [<](.+)[>][)]:[ \t]*(.+)\z/)
@@ -23,29 +23,29 @@ module Sisimai::Lhost
23
23
  ReSMTP = {
24
24
  # Error text regular expressions which defined in qmail-remote.c
25
25
  # qmail-remote.c:225| if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
26
- 'conn' => %r/(?:Error:)?Connected to .+ but greeting failed[.]/,
26
+ 'conn' => %r/(?:Error:)?Connected to [^ ]+ but greeting failed[.]/,
27
27
  # qmail-remote.c:231| if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
28
- 'ehlo' => %r/(?:Error:)?Connected to .+ but my name was rejected[.]/,
28
+ 'ehlo' => %r/(?:Error:)?Connected to [^ ]+ but my name was rejected[.]/,
29
29
  # qmail-remote.c:238| if (code >= 500) quit("DConnected to "," but sender was rejected");
30
30
  # reason = rejected
31
- 'mail' => %r/(?:Error:)?Connected to .+ but sender was rejected[.]/,
31
+ 'mail' => %r/(?:Error:)?Connected to [^ ]+ but sender was rejected[.]/,
32
32
  # qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
33
33
  # qmail-remote.c:253| out("s"); outhost(); out(" does not like recipient.\n");
34
34
  # reason = userunknown
35
- 'rcpt' => %r/(?:Error:)?.+ does not like recipient[.]/,
35
+ 'rcpt' => %r/(?:Error:)?[^ ]+ does not like recipient[.]/,
36
36
  # qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
37
37
  # qmail-remote.c:266| if (code >= 400) quit("Z"," failed on DATA command");
38
38
  # qmail-remote.c:271| if (code >= 500) quit("D"," failed after I sent the message");
39
39
  # qmail-remote.c:272| if (code >= 400) quit("Z"," failed after I sent the message");
40
40
  'data' => %r{(?:
41
- (?:Error:)?.+[ ]failed[ ]on[ ]DATA[ ]command[.]
42
- |(?:Error:)?.+[ ]failed[ ]after[ ]I[ ]sent[ ]the[ ]message[.]
41
+ (?:Error:)?[^ ]+[ ]failed[ ]on[ ]DATA[ ]command[.]
42
+ |(?:Error:)?[^ ]+[ ]failed[ ]after[ ]I[ ]sent[ ]the[ ]message[.]
43
43
  )
44
44
  }x,
45
45
  }.freeze
46
46
  # qmail-remote.c:261| if (!flagbother) quit("DGiving up on ","");
47
47
  ReHost = %r{(?:
48
- Giving[ ]up[ ]on[ ](.+[0-9a-zA-Z])[.]?\z
48
+ Giving[ ]up[ ]on[ ]([^ ]+[0-9a-zA-Z])[.]?\z
49
49
  |Connected[ ]to[ ]([-0-9a-zA-Z.]+[0-9a-zA-Z])[ ]
50
50
  |remote[ ]host[ ]([-0-9a-zA-Z.]+[0-9a-zA-Z])[ ]said:
51
51
  )
@@ -86,7 +86,7 @@ module Sisimai::Lhost
86
86
  # Arrival-Date: 2012-12-31 23-59-59
87
87
  next unless cv = e.match(/\AArrival-Date: (\d{4})[-](\d{2})[-](\d{2}) (\d{2})[-](\d{2})[-](\d{2})\z/)
88
88
  o[1] << 'Thu, ' << cv[3] + ' '
89
- o[1] << Sisimai::DateTime.monthname(0)[cv[2].to_i - 1]
89
+ o[1] << Sisimai::DateTime.monthname(false)[cv[2].to_i - 1]
90
90
  o[1] << ' ' << cv[1] + ' ' << [cv[4], cv[5], cv[6]].join(':')
91
91
  o[1] << ' ' << Sisimai::DateTime.abbr2tz('CDT')
92
92
  else
@@ -124,7 +124,7 @@ module Sisimai::Lhost
124
124
  if e['status'] == '5.0.0' || e['status'] == '4.0.0'
125
125
  # Get the value of D.S.N. from the error message or the value of
126
126
  # Diagnostic-Code header.
127
- e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || ''
127
+ e['status'] = Sisimai::SMTP::Status.find(e['diagnosis']) || e['status']
128
128
  end
129
129
 
130
130
  if e['action'] == 'expired'
@@ -184,7 +184,7 @@ module Sisimai::Lhost
184
184
 
185
185
  if anotherset['status']
186
186
  # Check alternative status code
187
- if e['status'].empty? || e['status'] !~ /\A[45][.]\d[.]\d\z/
187
+ if e['status'].empty? || e['status'] !~ /\A[45][.]\d[.]\d{1,3}\z/
188
188
  # Override alternative status code
189
189
  e['status'] = anotherset['status']
190
190
  end
@@ -44,8 +44,8 @@ module Sisimai::Lhost
44
44
  # The attempted recipient address does not exist.
45
45
  'userunknown' => ['550 - Requested action not taken: no such user here'],
46
46
  }
47
- boundary00 = Sisimai::MIME.boundary(mhead['content-type']) || ''
48
- rebackbone = Regexp.new('^' << Regexp.escape('--' << boundary00 << '--')) unless boundary00.empty?
47
+ boundary00 = Sisimai::MIME.boundary(mhead['content-type'], 1) || ''
48
+ rebackbone = Regexp.new('^' << Regexp.escape(boundary00)) unless boundary00.empty?
49
49
  emailsteak = Sisimai::RFC5322.fillet(mbody, rebackbone)
50
50
  bodyslices = emailsteak[0].split("\n")
51
51
 
@@ -93,8 +93,8 @@ module Sisimai::Lhost
93
93
  # vzwpix.com
94
94
  startingof = { message: ['Message could not be delivered to mobile'] }
95
95
  messagesof = { 'userunknown' => ['No valid recipients for this MM'] }
96
- boundary00 = Sisimai::MIME.boundary(mhead['content-type'])
97
- rebackbone = Regexp.new('^' << Regexp.escape('--' << boundary00 << '--')) unless boundary00.empty?
96
+ boundary00 = Sisimai::MIME.boundary(mhead['content-type'], 1)
97
+ rebackbone = Regexp.new('^' << Regexp.escape(boundary00)) unless boundary00.empty?
98
98
  emailsteak = Sisimai::RFC5322.fillet(mbody, rebackbone)
99
99
  bodyslices = emailsteak[0].split("\n")
100
100
 
@@ -73,6 +73,10 @@ module Sisimai::Lhost
73
73
  elsif cv = e.match(/\ARouting: (.+)/)
74
74
  # Routing: Could not find a gateway for kijitora@example.co.jp
75
75
  v['diagnosis'] = cv[1]
76
+
77
+ elsif cv = e.match(/\ADiagnostic-Code: smtp; (.+)/)
78
+ # Diagnostic-Code: smtp; 552 5.2.2 Over quota
79
+ v['diagnosis'] = cv[1]
76
80
  end
77
81
  end
78
82
  end
@@ -19,7 +19,7 @@ module Sisimai::Lhost
19
19
  # Characters: K,Z,D in qmail-qmqpc.c, qmail-send.c, qmail-rspawn.c
20
20
  # K = success, Z = temporary error, D = permanent error
21
21
  message: %r{\A(?>
22
- He/Her[ ]is[ ]not.+[ ]user
22
+ He/Her[ ]is[ ]not[ ].+[ ]user
23
23
  |Hi[.][ ].+[ ]unable[ ]to[ ]deliver[ ]your[ ]message[ ]to[ ]
24
24
  the[ ]following[ ]addresses
25
25
  |Su[ ]mensaje[ ]no[ ]pudo[ ]ser[ ]entregado
@@ -41,29 +41,29 @@ module Sisimai::Lhost
41
41
  ReSMTP = {
42
42
  # Error text regular expressions which defined in qmail-remote.c
43
43
  # qmail-remote.c:225| if (smtpcode() != 220) quit("ZConnected to "," but greeting failed");
44
- 'conn' => %r/(?:Error:)?Connected to .+ but greeting failed[.]/,
44
+ 'conn' => %r/(?:Error:)?Connected to [^ ]+ but greeting failed[.]/,
45
45
  # qmail-remote.c:231| if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");
46
- 'ehlo' => %r/(?:Error:)?Connected to .+ but my name was rejected[.]/,
46
+ 'ehlo' => %r/(?:Error:)?Connected to [^ ]+ but my name was rejected[.]/,
47
47
  # qmail-remote.c:238| if (code >= 500) quit("DConnected to "," but sender was rejected");
48
48
  # reason = rejected
49
- 'mail' => %r/(?:Error:)?Connected to .+ but sender was rejected[.]/,
49
+ 'mail' => %r/(?:Error:)?Connected to [^ ]+ but sender was rejected[.]/,
50
50
  # qmail-remote.c:249| out("h"); outhost(); out(" does not like recipient.\n");
51
51
  # qmail-remote.c:253| out("s"); outhost(); out(" does not like recipient.\n");
52
52
  # reason = userunknown
53
- 'rcpt' => %r/(?:Error:)?.+ does not like recipient[.]/,
53
+ 'rcpt' => %r/(?:Error:)?[^ ]+ does not like recipient[.]/,
54
54
  # qmail-remote.c:265| if (code >= 500) quit("D"," failed on DATA command");
55
55
  # qmail-remote.c:266| if (code >= 400) quit("Z"," failed on DATA command");
56
56
  # qmail-remote.c:271| if (code >= 500) quit("D"," failed after I sent the message");
57
57
  # qmail-remote.c:272| if (code >= 400) quit("Z"," failed after I sent the message");
58
58
  'data' => %r{(?:
59
- (?:Error:)?.+[ ]failed[ ]on[ ]DATA[ ]command[.]
60
- |(?:Error:)?.+[ ]failed[ ]after[ ]I[ ]sent[ ]the[ ]message[.]
59
+ (?:Error:)?[^ ]+[ ]failed[ ]on[ ]DATA[ ]command[.]
60
+ |(?:Error:)?[^ ]+[ ]failed[ ]after[ ]I[ ]sent[ ]the[ ]message[.]
61
61
  )
62
62
  }x,
63
63
  }.freeze
64
64
  # qmail-remote.c:261| if (!flagbother) quit("DGiving up on ","");
65
65
  ReHost = %r{(?:
66
- Giving[ ]up[ ]on[ ](.+[0-9a-zA-Z])[.]?\z
66
+ Giving[ ]up[ ]on[ ]([^ ]+[0-9a-zA-Z])[.]?\z
67
67
  |Connected[ ]to[ ]([-0-9a-zA-Z.]+[0-9a-zA-Z])[ ]
68
68
  |remote[ ]host[ ]([-0-9a-zA-Z.]+[0-9a-zA-Z])[ ]said:
69
69
  )
@@ -39,13 +39,17 @@ module Sisimai::Lhost
39
39
  require 'sisimai/rfc1894'
40
40
  fieldtable = Sisimai::RFC1894.FIELDTABLE
41
41
  dscontents = [Sisimai::Lhost.DELIVERYSTATUS]
42
- emailsteak = Sisimai::RFC5322.fillet(mbody, ReBackbone)
43
- bodyslices = emailsteak[0].split("\n")
44
42
  readslices = ['']
45
43
  readcursor = 0 # (Integer) Points the current cursor position
46
44
  recipients = 0 # (Integer) The number of 'Final-Recipient' header
47
45
  v = nil
48
46
 
47
+ # Pick the second message/rfc822 part because the format of email-x5-*.eml is nested structure
48
+ prefillets = mbody.split(ReBackbone, 2)
49
+ prefillets[1].sub!(/\A.+?\n\n/s, '')
50
+ emailsteak = Sisimai::RFC5322.fillet(prefillets[1], ReBackbone)
51
+ bodyslices = emailsteak[0].split("\n")
52
+
49
53
  while e = bodyslices.shift do
50
54
  # Read error messages and delivery status lines from the head of the email
51
55
  # to the previous line of the beginning of the original message.
@@ -56,7 +60,7 @@ module Sisimai::Lhost
56
60
  readcursor |= Indicators[:deliverystatus] if e.start_with?(StartingOf[:message][0])
57
61
  next
58
62
  end
59
- next if (readcursor & Indicators['deliverystatus']) == 0
63
+ next if (readcursor & Indicators[:deliverystatus]) == 0
60
64
  next if e.empty?
61
65
 
62
66
  v = dscontents[-1]
data/lib/sisimai/mail.rb CHANGED
@@ -4,7 +4,6 @@ module Sisimai
4
4
  # Sisimai::Mail::Memory classes.
5
5
  class Mail
6
6
  # Imported from p5-Sisimail/lib/Sisimai/Mail.pm
7
- Until = 'v4.25.10'
8
7
 
9
8
  # :path [String] path to mbox or Maildir/
10
9
  # :kind [String] Data type: mailbox, maildir, or stdin
@@ -25,7 +24,7 @@ module Sisimai
25
24
  # Sisimai::Mail.new('<STDIN>')
26
25
  classname = self.class.to_s << '::STDIN'
27
26
  parameter['kind'] = 'stdin'
28
- parameter['path'] = $stdin
27
+ parameter['path'] = '<STDIN>'
29
28
  else
30
29
  # The argumenet is a mailbox or a Maildir/.
31
30
  mediatype = argv1.include?("\n") ? 'memory' : File.ftype(argv1)
@@ -52,6 +51,7 @@ module Sisimai
52
51
  # The argument neither a mailbox nor a Maildir/.
53
52
  classname = self.class.to_s << '::STDIN'
54
53
  parameter['kind'] = 'stdin'
54
+ parameter['path'] = '<STDIN>'
55
55
  end
56
56
  return nil unless classname
57
57
 
@@ -64,16 +64,6 @@ module Sisimai
64
64
  @data = parameter['data']
65
65
  end
66
66
 
67
- def mail
68
- warn " ***warning: Sisimai::Mail.mail will be removed at #{Until}. Use Sisimai::Mail.data instead"
69
- return data
70
- end
71
-
72
- def type
73
- warn " ***warning: Sisimai::Mail.type will be removed at #{Until}. Use Sisimai::Mail.kind instead"
74
- return kind
75
- end
76
-
77
67
  # Alias method of Sisimai::Mail.data.read()
78
68
  # @return [String] Contents of mbox/Maildir
79
69
  def read
@@ -81,15 +71,6 @@ module Sisimai
81
71
  return data.read
82
72
  end
83
73
 
84
- # Close the handle
85
- # @return [True,False] true: Successfully closed the handle
86
- # false: Mail handle is not defined
87
- def close
88
- warn " ***warning: Sisimai::Mail.close will be removed at #{Until}. The handle automatically closes at the EOF"
89
- return false unless data.handle
90
- data.handle = nil
91
- return true
92
- end
93
74
  end
94
75
  end
95
76
 
data/lib/sisimai/mda.rb CHANGED
@@ -7,7 +7,7 @@ module Sisimai
7
7
  # dovecot/src/deliver/deliver.c
8
8
  # 11: #define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
9
9
  # 12: "Your message to <%t> was automatically rejected:%n%r"
10
- 'dovecot' => %r/\AYour message to .+ was automatically rejected:\z/,
10
+ 'dovecot' => %r/\AYour message to [^ ]+ was automatically rejected:\z/,
11
11
  'mail.local' => %r/\Amail[.]local: /,
12
12
  'procmail' => %r/\Aprocmail: /,
13
13
  'maildrop' => %r/\Amaildrop: /,
@@ -16,7 +16,7 @@ module Sisimai
16
16
  }.freeze
17
17
  MarkingsOf = {
18
18
  message: %r{\A(?>
19
- Your[ ]message[ ]to[ ].+[ ]was[ ]automatically[ ]rejected:\z
19
+ Your[ ]message[ ]to[ ][^ ]+[ ]was[ ]automatically[ ]rejected:\z
20
20
  |(?:mail[.]local|procmail|maildrop|vdelivermail|vdeliver):[ ]
21
21
  )
22
22
  }x
@@ -32,102 +32,71 @@ module Sisimai
32
32
  # value of the arguments are missing
33
33
  def initialize(data: '', **argvs)
34
34
  return nil if data.empty?
35
+ param = {}
35
36
  email = data.scrub('?').gsub("\r\n", "\n")
37
+ thing = { 'from' => '','header' => {}, 'rfc822' => '', ds => [], 'catch' => nil }
36
38
 
37
- methodargv = { 'data' => email, 'hook' => argvs[:hook] || nil }
39
+ #methodargv = { 'data' => email, 'hook' => argvs[:hook] || nil }
40
+ # 1. Load specified MTA modules
38
41
  [:load, :order].each do |e|
39
42
  # Order of MTA modules
40
43
  next unless argvs[e]
41
44
  next unless argvs[e].is_a? Array
42
45
  next if argvs[e].empty?
43
- methodargv[e.to_s] = argvs[e]
46
+ param[e.to_s] = argvs[e]
44
47
  end
48
+ tobeloaded = Sisimai::Message.load(param)
45
49
 
46
- datasource = Sisimai::Message.make(methodargv)
47
- return nil unless datasource
48
- return nil unless datasource['ds']
49
-
50
- @from = datasource['from']
51
- @header = datasource['header']
52
- @ds = datasource['ds']
53
- @rfc822 = datasource['rfc822']
54
- @catch = datasource['catch'] || nil
55
- end
56
-
57
- # Check whether the object has valid content or not
58
- # @return [True,False] returns true if the object is void
59
- def void
60
- return true unless @ds
61
- return false
62
- end
63
-
64
- # Make data structure from the email message(a body part and headers)
65
- # @param [Hash] argvs Email data
66
- # @options argvs [String] data Entire email message
67
- # @options argvs [Array] load User defined MTA module list
68
- # @options argvs [Array] order The order of MTA modules
69
- # @options argvs [Code] hook Reference to callback method
70
- # @return [Hash] Resolved data structure
71
- def self.make(argvs)
72
- email = argvs['data']
73
-
74
- hookmethod = argvs['hook'] || nil
75
- processing = {
76
- 'from' => '', # From_ line
77
- 'header' => {}, # Email header
78
- 'rfc822' => '', # Original message part
79
- 'ds' => [], # Parsed data, Delivery Status
80
- 'catch' => nil, # Data parsed by callback method
81
- }
82
- methodargv = {
83
- 'load' => argvs['load'] || [],
84
- 'order' => argvs['order'] || []
85
- }
86
- tobeloaded = Sisimai::Message.load(methodargv)
87
-
88
- # 1. Split email data to headers and a body part.
50
+ # 2. Split email data to headers and a body part.
89
51
  return nil unless aftersplit = Sisimai::Message.divideup(email)
90
52
 
91
- # 2. Convert email headers from text to hash reference
92
- processing['from'] = aftersplit['from']
93
- processing['header'] = Sisimai::Message.makemap(aftersplit['header'])
53
+ # 3. Convert email headers from text to hash reference
54
+ thing['from'] = aftersplit[0]
55
+ thing['header'] = Sisimai::Message.makemap(aftersplit[1])
94
56
 
95
- # 3. Decode and rewrite the "Subject:" header
96
- unless processing['header']['subject'].empty?
57
+ # 4. Decode and rewrite the "Subject:" header
58
+ unless thing['header']['subject'].empty?
97
59
  # Decode MIME-Encoded "Subject:" header
98
- s = processing['header']['subject']
60
+ s = thing['header']['subject']
99
61
  q = Sisimai::MIME.is_mimeencoded(s) ? Sisimai::MIME.mimedecode(s.split(/[ ]/)) : s
100
62
 
101
63
  # Remove "Fwd:" string from the Subject: header
102
64
  if cv = q.downcase.match(/\A[ \t]*fwd?:[ ]*(.*)\z/)
103
65
  # Delete quoted strings, quote symbols(>)
104
66
  q = cv[1]
105
- aftersplit['body'] = aftersplit['body'].gsub(/^[>]+[ ]/, '').gsub(/^[>]$/, '')
67
+ aftersplit[2] = aftersplit[2].gsub(/^[>]+[ ]/, '').gsub(/^[>]$/, '')
106
68
  end
107
- processing['header']['subject'] = q
69
+ thing['header']['subject'] = q
108
70
  end
109
71
 
110
- # 4. Rewrite message body for detecting the bounce reason
111
- tryonfirst = Sisimai::Order.make(processing['header']['subject'])
112
- methodargv = {
113
- 'hook' => hookmethod,
114
- 'mail' => processing,
115
- 'body' => aftersplit['body'],
116
- 'tryonfirst' => tryonfirst,
72
+ # 5. Rewrite message body for detecting the bounce reason
73
+ param = {
74
+ 'hook' => argvs[:hook] || nil,
75
+ 'mail' => thing,
76
+ 'body' => aftersplit[2],
117
77
  'tobeloaded' => tobeloaded,
78
+ 'tryonfirst' => Sisimai::Order.make(thing['header']['subject'])
118
79
  }
119
- return nil unless bouncedata = Sisimai::Message.parse(methodargv)
80
+ return nil unless bouncedata = Sisimai::Message.parse(param)
120
81
  return nil if bouncedata.empty?
121
82
 
122
- # 5. Rewrite headers of the original message in the body part
123
- %w|ds catch rfc822|.each { |e| processing[e] = bouncedata[e] }
83
+ # 6. Rewrite headers of the original message in the body part
84
+ %w|ds catch rfc822|.each { |e| thing[e] = bouncedata[e] }
124
85
  p = bouncedata['rfc822']
125
- p = aftersplit['body'] if p.empty?
126
- processing['rfc822'] = p.is_a?(::String) ? Sisimai::Message.makemap(p, true) : p
127
-
128
- return processing
86
+ p = aftersplit[2] if p.empty?
87
+ thing['rfc822'] = p.is_a?(::String) ? Sisimai::Message.makemap(p, true) : p
88
+
89
+ @from = thing['from']
90
+ @header = thing['header']
91
+ @ds = thing['ds']
92
+ @rfc822 = thing['rfc822']
93
+ @catch = thing['catch'] || nil
129
94
  end
130
95
 
96
+ # Check whether the object has valid content or not
97
+ # @return [True,False] returns true if the object is void
98
+ def void; return @ds ? false : true; end
99
+
131
100
  # Load MTA modules which specified at 'order' and 'load' in the argument
132
101
  # @param [Hash] argvs Module information to be loaded
133
102
  # @options argvs [Array] load User defined MTA module list
@@ -171,28 +140,28 @@ module Sisimai
171
140
 
172
141
  # Divide email data up headers and a body part.
173
142
  # @param [String] email Email data
174
- # @return [Hash] Email data after split
143
+ # @return [Array] Email data after split
175
144
  def self.divideup(email)
176
145
  return nil if email.empty?
177
146
 
178
- block = { 'from' => '', 'header' => '', 'body' => '' }
147
+ block = ['', '', ''] # 0:From, 1:Header, 2:Body
179
148
  email.gsub!(/\r\n/, "\n") if email.include?("\r\n")
180
149
  email.gsub!(/[ \t]+$/, '') if email =~ /[ \t]+$/
181
150
 
182
- (block['header'], block['body']) = email.split(/\n\n/, 2)
183
- return nil unless block['header']
184
- return nil unless block['body']
151
+ (block[1], block[2]) = email.split(/\n\n/, 2)
152
+ return nil unless block[1]
153
+ return nil unless block[2]
185
154
 
186
- if block['header'].start_with?('From ')
155
+ if block[1].start_with?('From ')
187
156
  # From MAILER-DAEMON Tue Feb 11 00:00:00 2014
188
- block['from'] = block['header'].split(/\n/, 2)[0].delete("\r")
157
+ block[0] = block[1].split(/\n/, 2)[0].delete("\r")
189
158
  else
190
159
  # Set pseudo UNIX From line
191
- block['from'] = 'MAILER-DAEMON Tue Feb 11 00:00:00 2014'
160
+ block[0] = 'MAILER-DAEMON Tue Feb 11 00:00:00 2014'
192
161
  end
193
162
 
194
- block['header'] << "\n" unless block['header'].end_with?("\n")
195
- block['body'] << "\n"
163
+ block[1] << "\n" unless block[1].end_with?("\n")
164
+ block[2] << "\n"
196
165
  return block
197
166
  end
198
167
 
@@ -307,12 +276,7 @@ module Sisimai
307
276
  if hookmethod.is_a? Proc
308
277
  # Call the hook method
309
278
  begin
310
- p = {
311
- 'datasrc' => 'email',
312
- 'headers' => mailheader,
313
- 'message' => bodystring,
314
- 'bounces' => nil
315
- }
279
+ p = { 'headers' => mailheader, 'message' => bodystring }
316
280
  havecaught = hookmethod.call(p)
317
281
  rescue StandardError => ce
318
282
  warn ' ***warning: Something is wrong in hook method :' << ce.to_s