nano-fast-tool 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/mail-2.9.1/MIT-LICENSE +20 -0
- data/mail-2.9.1/README.md +771 -0
- data/mail-2.9.1/lib/mail/attachments_list.rb +109 -0
- data/mail-2.9.1/lib/mail/body.rb +305 -0
- data/mail-2.9.1/lib/mail/configuration.rb +78 -0
- data/mail-2.9.1/lib/mail/constants.rb +79 -0
- data/mail-2.9.1/lib/mail/elements/address.rb +258 -0
- data/mail-2.9.1/lib/mail/elements/address_list.rb +34 -0
- data/mail-2.9.1/lib/mail/elements/content_disposition_element.rb +20 -0
- data/mail-2.9.1/lib/mail/elements/content_location_element.rb +17 -0
- data/mail-2.9.1/lib/mail/elements/content_transfer_encoding_element.rb +13 -0
- data/mail-2.9.1/lib/mail/elements/content_type_element.rb +25 -0
- data/mail-2.9.1/lib/mail/elements/date_time_element.rb +15 -0
- data/mail-2.9.1/lib/mail/elements/envelope_from_element.rb +39 -0
- data/mail-2.9.1/lib/mail/elements/message_ids_element.rb +31 -0
- data/mail-2.9.1/lib/mail/elements/mime_version_element.rb +15 -0
- data/mail-2.9.1/lib/mail/elements/phrase_list.rb +19 -0
- data/mail-2.9.1/lib/mail/elements/received_element.rb +35 -0
- data/mail-2.9.1/lib/mail/elements.rb +15 -0
- data/mail-2.9.1/lib/mail/encodings/7bit.rb +27 -0
- data/mail-2.9.1/lib/mail/encodings/8bit.rb +18 -0
- data/mail-2.9.1/lib/mail/encodings/base64.rb +38 -0
- data/mail-2.9.1/lib/mail/encodings/binary.rb +13 -0
- data/mail-2.9.1/lib/mail/encodings/identity.rb +24 -0
- data/mail-2.9.1/lib/mail/encodings/quoted_printable.rb +45 -0
- data/mail-2.9.1/lib/mail/encodings/transfer_encoding.rb +77 -0
- data/mail-2.9.1/lib/mail/encodings/unix_to_unix.rb +20 -0
- data/mail-2.9.1/lib/mail/encodings.rb +314 -0
- data/mail-2.9.1/lib/mail/envelope.rb +28 -0
- data/mail-2.9.1/lib/mail/field.rb +313 -0
- data/mail-2.9.1/lib/mail/field_list.rb +87 -0
- data/mail-2.9.1/lib/mail/fields/bcc_field.rb +49 -0
- data/mail-2.9.1/lib/mail/fields/cc_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/comments_field.rb +31 -0
- data/mail-2.9.1/lib/mail/fields/common_address_field.rb +162 -0
- data/mail-2.9.1/lib/mail/fields/common_date_field.rb +56 -0
- data/mail-2.9.1/lib/mail/fields/common_field.rb +77 -0
- data/mail-2.9.1/lib/mail/fields/common_message_id_field.rb +41 -0
- data/mail-2.9.1/lib/mail/fields/content_description_field.rb +12 -0
- data/mail-2.9.1/lib/mail/fields/content_disposition_field.rb +44 -0
- data/mail-2.9.1/lib/mail/fields/content_id_field.rb +35 -0
- data/mail-2.9.1/lib/mail/fields/content_location_field.rb +28 -0
- data/mail-2.9.1/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
- data/mail-2.9.1/lib/mail/fields/content_type_field.rb +171 -0
- data/mail-2.9.1/lib/mail/fields/date_field.rb +28 -0
- data/mail-2.9.1/lib/mail/fields/from_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/in_reply_to_field.rb +45 -0
- data/mail-2.9.1/lib/mail/fields/keywords_field.rb +30 -0
- data/mail-2.9.1/lib/mail/fields/message_id_field.rb +36 -0
- data/mail-2.9.1/lib/mail/fields/mime_version_field.rb +42 -0
- data/mail-2.9.1/lib/mail/fields/named_structured_field.rb +10 -0
- data/mail-2.9.1/lib/mail/fields/named_unstructured_field.rb +10 -0
- data/mail-2.9.1/lib/mail/fields/optional_field.rb +15 -0
- data/mail-2.9.1/lib/mail/fields/parameter_hash.rb +61 -0
- data/mail-2.9.1/lib/mail/fields/received_field.rb +61 -0
- data/mail-2.9.1/lib/mail/fields/references_field.rb +42 -0
- data/mail-2.9.1/lib/mail/fields/reply_to_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/resent_bcc_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/resent_cc_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/resent_date_field.rb +10 -0
- data/mail-2.9.1/lib/mail/fields/resent_from_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/resent_message_id_field.rb +10 -0
- data/mail-2.9.1/lib/mail/fields/resent_sender_field.rb +32 -0
- data/mail-2.9.1/lib/mail/fields/resent_to_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/return_path_field.rb +60 -0
- data/mail-2.9.1/lib/mail/fields/sender_field.rb +45 -0
- data/mail-2.9.1/lib/mail/fields/structured_field.rb +24 -0
- data/mail-2.9.1/lib/mail/fields/subject_field.rb +14 -0
- data/mail-2.9.1/lib/mail/fields/to_field.rb +33 -0
- data/mail-2.9.1/lib/mail/fields/unstructured_field.rb +189 -0
- data/mail-2.9.1/lib/mail/fields.rb +45 -0
- data/mail-2.9.1/lib/mail/header.rb +237 -0
- data/mail-2.9.1/lib/mail/indifferent_hash.rb +147 -0
- data/mail-2.9.1/lib/mail/mail.rb +267 -0
- data/mail-2.9.1/lib/mail/matchers/attachment_matchers.rb +44 -0
- data/mail-2.9.1/lib/mail/matchers/has_sent_mail.rb +201 -0
- data/mail-2.9.1/lib/mail/message.rb +2159 -0
- data/mail-2.9.1/lib/mail/multibyte/chars.rb +318 -0
- data/mail-2.9.1/lib/mail/multibyte/unicode.rb +405 -0
- data/mail-2.9.1/lib/mail/multibyte/utils.rb +44 -0
- data/mail-2.9.1/lib/mail/multibyte.rb +82 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/exim.rb +50 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/file_delivery.rb +43 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/sendmail.rb +87 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/smtp.rb +200 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/smtp_connection.rb +57 -0
- data/mail-2.9.1/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
- data/mail-2.9.1/lib/mail/network/retriever_methods/base.rb +64 -0
- data/mail-2.9.1/lib/mail/network/retriever_methods/imap.rb +190 -0
- data/mail-2.9.1/lib/mail/network/retriever_methods/pop3.rb +143 -0
- data/mail-2.9.1/lib/mail/network/retriever_methods/test_retriever.rb +45 -0
- data/mail-2.9.1/lib/mail/network.rb +16 -0
- data/mail-2.9.1/lib/mail/parser_tools.rb +15 -0
- data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rb +33245 -0
- data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rl +183 -0
- data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rb +904 -0
- data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rl +93 -0
- data/mail-2.9.1/lib/mail/parsers/content_location_parser.rb +825 -0
- data/mail-2.9.1/lib/mail/parsers/content_location_parser.rl +82 -0
- data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rb +525 -0
- data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rl +75 -0
- data/mail-2.9.1/lib/mail/parsers/content_type_parser.rb +1051 -0
- data/mail-2.9.1/lib/mail/parsers/content_type_parser.rl +94 -0
- data/mail-2.9.1/lib/mail/parsers/date_time_parser.rb +894 -0
- data/mail-2.9.1/lib/mail/parsers/date_time_parser.rl +73 -0
- data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rb +3678 -0
- data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rl +93 -0
- data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rb +5164 -0
- data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rl +97 -0
- data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rb +516 -0
- data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rl +72 -0
- data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rb +887 -0
- data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rl +94 -0
- data/mail-2.9.1/lib/mail/parsers/received_parser.rb +8785 -0
- data/mail-2.9.1/lib/mail/parsers/received_parser.rl +95 -0
- data/mail-2.9.1/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
- data/mail-2.9.1/lib/mail/parsers/rfc2045_content_type.rl +25 -0
- data/mail-2.9.1/lib/mail/parsers/rfc2045_mime.rl +16 -0
- data/mail-2.9.1/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
- data/mail-2.9.1/lib/mail/parsers/rfc3629_utf8.rl +19 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5322.rl +74 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5322_address.rl +72 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5322_date_time.rl +37 -0
- data/mail-2.9.1/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
- data/mail-2.9.1/lib/mail/parsers.rb +13 -0
- data/mail-2.9.1/lib/mail/part.rb +119 -0
- data/mail-2.9.1/lib/mail/parts_list.rb +131 -0
- data/mail-2.9.1/lib/mail/smtp_envelope.rb +57 -0
- data/mail-2.9.1/lib/mail/utilities.rb +576 -0
- data/mail-2.9.1/lib/mail/values/unicode_tables.dat +0 -0
- data/mail-2.9.1/lib/mail/version.rb +17 -0
- data/mail-2.9.1/lib/mail/yaml.rb +30 -0
- data/mail-2.9.1/lib/mail.rb +65 -0
- data/nano-fast-tool.gemspec +12 -0
- metadata +177 -0
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
require 'mail/constants'
|
|
4
|
+
require 'socket'
|
|
5
|
+
|
|
6
|
+
module Mail
|
|
7
|
+
module Utilities
|
|
8
|
+
extend self
|
|
9
|
+
|
|
10
|
+
# Returns true if the string supplied is free from characters not allowed as an ATOM
|
|
11
|
+
def atom_safe?( str )
|
|
12
|
+
not Constants::ATOM_UNSAFE === str
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# If the string supplied has ATOM unsafe characters in it, will return the string quoted
|
|
16
|
+
# in double quotes, otherwise returns the string unmodified
|
|
17
|
+
def quote_atom( str )
|
|
18
|
+
atom_safe?( str ) ? str : dquote(str)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# If the string supplied has PHRASE unsafe characters in it, will return the string quoted
|
|
22
|
+
# in double quotes, otherwise returns the string unmodified
|
|
23
|
+
def quote_phrase( str )
|
|
24
|
+
if str.respond_to?(:force_encoding)
|
|
25
|
+
original_encoding = str.encoding
|
|
26
|
+
ascii_str = str.to_s.dup.force_encoding('ASCII-8BIT')
|
|
27
|
+
if Constants::PHRASE_UNSAFE === ascii_str
|
|
28
|
+
dquote(ascii_str).force_encoding(original_encoding)
|
|
29
|
+
else
|
|
30
|
+
str
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
Constants::PHRASE_UNSAFE === str ? dquote(str) : str
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns true if the string supplied is free from characters not allowed as a TOKEN
|
|
38
|
+
def token_safe?( str )
|
|
39
|
+
not Constants::TOKEN_UNSAFE === str
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# If the string supplied has TOKEN unsafe characters in it, will return the string quoted
|
|
43
|
+
# in double quotes, otherwise returns the string unmodified
|
|
44
|
+
def quote_token( str )
|
|
45
|
+
if str.respond_to?(:force_encoding)
|
|
46
|
+
original_encoding = str.encoding
|
|
47
|
+
ascii_str = str.to_s.dup.force_encoding('ASCII-8BIT')
|
|
48
|
+
if token_safe?( ascii_str )
|
|
49
|
+
str
|
|
50
|
+
else
|
|
51
|
+
dquote(ascii_str).force_encoding(original_encoding)
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
token_safe?( str ) ? str : dquote(str)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Wraps supplied string in double quotes and applies \-escaping as necessary,
|
|
59
|
+
# unless it is already wrapped.
|
|
60
|
+
#
|
|
61
|
+
# Example:
|
|
62
|
+
#
|
|
63
|
+
# string = 'This is a string'
|
|
64
|
+
# dquote(string) #=> '"This is a string"'
|
|
65
|
+
#
|
|
66
|
+
# string = 'This is "a string"'
|
|
67
|
+
# dquote(string #=> '"This is \"a string\"'
|
|
68
|
+
def dquote( str )
|
|
69
|
+
'"' + unquote(str).gsub(/[\\"]/n) {|s| '\\' + s } + '"'
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Unwraps supplied string from inside double quotes and
|
|
73
|
+
# removes any \-escaping.
|
|
74
|
+
#
|
|
75
|
+
# Example:
|
|
76
|
+
#
|
|
77
|
+
# string = '"This is a string"'
|
|
78
|
+
# unquote(string) #=> 'This is a string'
|
|
79
|
+
#
|
|
80
|
+
# string = '"This is \"a string\""'
|
|
81
|
+
# unqoute(string) #=> 'This is "a string"'
|
|
82
|
+
def unquote( str )
|
|
83
|
+
if str =~ /^"(.*?)"$/
|
|
84
|
+
unescape($1)
|
|
85
|
+
else
|
|
86
|
+
str
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Removes any \-escaping.
|
|
91
|
+
#
|
|
92
|
+
# Example:
|
|
93
|
+
#
|
|
94
|
+
# string = 'This is \"a string\"'
|
|
95
|
+
# unescape(string) #=> 'This is "a string"'
|
|
96
|
+
#
|
|
97
|
+
# string = '"This is \"a string\""'
|
|
98
|
+
# unescape(string) #=> '"This is "a string""'
|
|
99
|
+
def unescape( str )
|
|
100
|
+
str.gsub(/\\(.)/, '\1')
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Wraps a string in parenthesis and escapes any that are in the string itself.
|
|
104
|
+
#
|
|
105
|
+
# Example:
|
|
106
|
+
#
|
|
107
|
+
# paren( 'This is a string' ) #=> '(This is a string)'
|
|
108
|
+
def paren( str )
|
|
109
|
+
Utilities.paren( str )
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Unwraps a string from being wrapped in parenthesis
|
|
113
|
+
#
|
|
114
|
+
# Example:
|
|
115
|
+
#
|
|
116
|
+
# str = '(This is a string)'
|
|
117
|
+
# unparen( str ) #=> 'This is a string'
|
|
118
|
+
def unparen( str )
|
|
119
|
+
if str.start_with?('(') && str.end_with?(')')
|
|
120
|
+
str.slice(1..-2)
|
|
121
|
+
else
|
|
122
|
+
str
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Wraps a string in angle brackets and escapes any that are in the string itself
|
|
127
|
+
#
|
|
128
|
+
# Example:
|
|
129
|
+
#
|
|
130
|
+
# bracket( 'This is a string' ) #=> '<This is a string>'
|
|
131
|
+
def bracket( str )
|
|
132
|
+
Utilities.bracket( str )
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Unwraps a string from being wrapped in parenthesis
|
|
136
|
+
#
|
|
137
|
+
# Example:
|
|
138
|
+
#
|
|
139
|
+
# str = '<This is a string>'
|
|
140
|
+
# unbracket( str ) #=> 'This is a string'
|
|
141
|
+
def unbracket( str )
|
|
142
|
+
if str.start_with?('<') && str.end_with?('>')
|
|
143
|
+
str.slice(1..-2)
|
|
144
|
+
else
|
|
145
|
+
str
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Escape parenthesies in a string
|
|
150
|
+
#
|
|
151
|
+
# Example:
|
|
152
|
+
#
|
|
153
|
+
# str = 'This is (a) string'
|
|
154
|
+
# escape_paren( str ) #=> 'This is \(a\) string'
|
|
155
|
+
def escape_paren( str )
|
|
156
|
+
Utilities.escape_paren( str )
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def uri_escape( str )
|
|
160
|
+
uri_parser.escape(str)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def uri_unescape( str )
|
|
164
|
+
uri_parser.unescape(str)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def uri_parser
|
|
168
|
+
@uri_parser ||= if URI.const_defined?(:DEFAULT_PARSER)
|
|
169
|
+
defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
|
|
170
|
+
else
|
|
171
|
+
URI
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Matches two objects with their to_s values case insensitively
|
|
176
|
+
#
|
|
177
|
+
# Example:
|
|
178
|
+
#
|
|
179
|
+
# obj2 = "This_is_An_object"
|
|
180
|
+
# obj1 = :this_IS_an_object
|
|
181
|
+
# match_to_s( obj1, obj2 ) #=> true
|
|
182
|
+
def match_to_s( obj1, obj2 )
|
|
183
|
+
obj1.to_s.casecmp(obj2.to_s) == 0
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Capitalizes a string that is joined by hyphens correctly.
|
|
187
|
+
#
|
|
188
|
+
# Example:
|
|
189
|
+
#
|
|
190
|
+
# string = 'resent-from-field'
|
|
191
|
+
# capitalize_field( string ) #=> 'Resent-From-Field'
|
|
192
|
+
def capitalize_field( str )
|
|
193
|
+
str.to_s.split("-").map { |v| v.capitalize }.join("-")
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Takes an underscored word and turns it into a class name
|
|
197
|
+
#
|
|
198
|
+
# Example:
|
|
199
|
+
#
|
|
200
|
+
# constantize("hello") #=> "Hello"
|
|
201
|
+
# constantize("hello-there") #=> "HelloThere"
|
|
202
|
+
# constantize("hello-there-mate") #=> "HelloThereMate"
|
|
203
|
+
def constantize( str )
|
|
204
|
+
str.to_s.split(/[-_]/).map { |v| v.capitalize }.to_s
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Swaps out all underscores (_) for hyphens (-) good for stringing from symbols
|
|
208
|
+
# a field name.
|
|
209
|
+
#
|
|
210
|
+
# Example:
|
|
211
|
+
#
|
|
212
|
+
# string = :resent_from_field
|
|
213
|
+
# dasherize( string ) #=> 'resent-from-field'
|
|
214
|
+
def dasherize( str )
|
|
215
|
+
str.to_s.tr(Constants::UNDERSCORE, Constants::HYPHEN)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Swaps out all hyphens (-) for underscores (_) good for stringing to symbols
|
|
219
|
+
# a field name.
|
|
220
|
+
#
|
|
221
|
+
# Example:
|
|
222
|
+
#
|
|
223
|
+
# string = :resent_from_field
|
|
224
|
+
# underscoreize ( string ) #=> 'resent_from_field'
|
|
225
|
+
def underscoreize( str )
|
|
226
|
+
str.to_s.downcase.tr(Constants::HYPHEN, Constants::UNDERSCORE)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def map_lines( str, &block )
|
|
230
|
+
str.each_line.map(&block)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def map_with_index( enum, &block )
|
|
234
|
+
enum.each_with_index.map(&block)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def self.binary_unsafe_to_lf(string) #:nodoc:
|
|
238
|
+
string.gsub(/\r\n|\r/, Constants::LF)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
TO_CRLF_REGEX =
|
|
242
|
+
# This 1.9 only regex can save a reasonable amount of time (~20%)
|
|
243
|
+
# by not matching "\r\n" so the string is returned unchanged in
|
|
244
|
+
# the common case.
|
|
245
|
+
Regexp.new("(?<!\r)\n|\r(?!\n)")
|
|
246
|
+
|
|
247
|
+
def self.binary_unsafe_to_crlf(string) #:nodoc:
|
|
248
|
+
string.gsub(TO_CRLF_REGEX, Constants::CRLF)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def self.safe_for_line_ending_conversion?(string) #:nodoc:
|
|
252
|
+
if string.encoding == Encoding::BINARY
|
|
253
|
+
string.ascii_only?
|
|
254
|
+
else
|
|
255
|
+
string.valid_encoding?
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# Convert line endings to \n unless the string is binary. Used for
|
|
260
|
+
# sendmail delivery and for decoding 8bit Content-Transfer-Encoding.
|
|
261
|
+
def self.to_lf(string)
|
|
262
|
+
string = string.to_s
|
|
263
|
+
if safe_for_line_ending_conversion? string
|
|
264
|
+
binary_unsafe_to_lf string
|
|
265
|
+
else
|
|
266
|
+
string
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# Convert line endings to \r\n unless the string is binary. Used for
|
|
271
|
+
# encoding 8bit and base64 Content-Transfer-Encoding and for convenience
|
|
272
|
+
# when parsing emails with \n line endings instead of the required \r\n.
|
|
273
|
+
def self.to_crlf(string)
|
|
274
|
+
string = string.to_s
|
|
275
|
+
if safe_for_line_ending_conversion? string
|
|
276
|
+
binary_unsafe_to_crlf string
|
|
277
|
+
else
|
|
278
|
+
string
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Returns true if the object is considered blank.
|
|
283
|
+
# A blank includes things like '', ' ', nil,
|
|
284
|
+
# and arrays and hashes that have nothing in them.
|
|
285
|
+
#
|
|
286
|
+
# This logic is mostly shared with ActiveSupport's blank?
|
|
287
|
+
def blank?(value)
|
|
288
|
+
if value.kind_of?(NilClass)
|
|
289
|
+
true
|
|
290
|
+
elsif value.kind_of?(String)
|
|
291
|
+
value !~ /\S/
|
|
292
|
+
else
|
|
293
|
+
value.respond_to?(:empty?) ? value.empty? : !value
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def generate_message_id
|
|
298
|
+
"<#{Mail.random_tag}@#{::Socket.gethostname}.mail>"
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
class StrictCharsetEncoder
|
|
302
|
+
def encode(string, charset)
|
|
303
|
+
case charset
|
|
304
|
+
when /utf-?7/i
|
|
305
|
+
Mail::Utilities.decode_utf7(string)
|
|
306
|
+
else
|
|
307
|
+
string.force_encoding(Mail::Utilities.pick_encoding(charset))
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
class BestEffortCharsetEncoder
|
|
313
|
+
def encode(string, charset)
|
|
314
|
+
case charset
|
|
315
|
+
when /utf-?7/i
|
|
316
|
+
Mail::Utilities.decode_utf7(string)
|
|
317
|
+
else
|
|
318
|
+
string.force_encoding(pick_encoding(charset))
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
private
|
|
323
|
+
|
|
324
|
+
def pick_encoding(charset)
|
|
325
|
+
charset = case charset
|
|
326
|
+
when /ansi_x3.110-1983/
|
|
327
|
+
'ISO-8859-1'
|
|
328
|
+
when /Windows-?1258/i # Windows-1258 is similar to 1252
|
|
329
|
+
"Windows-1252"
|
|
330
|
+
else
|
|
331
|
+
charset
|
|
332
|
+
end
|
|
333
|
+
Mail::Utilities.pick_encoding(charset)
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
class << self
|
|
338
|
+
attr_accessor :charset_encoder
|
|
339
|
+
end
|
|
340
|
+
self.charset_encoder = BestEffortCharsetEncoder.new
|
|
341
|
+
|
|
342
|
+
# Escapes any parenthesis in a string that are unescaped this uses
|
|
343
|
+
# a Ruby 1.9.1 regexp feature of negative look behind
|
|
344
|
+
def Utilities.escape_paren( str )
|
|
345
|
+
re = /(?<!\\)([\(\)])/ # Only match unescaped parens
|
|
346
|
+
str.gsub(re) { |s| '\\' + s }
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def Utilities.paren( str )
|
|
350
|
+
str = ::Mail::Utilities.unparen( str )
|
|
351
|
+
str = escape_paren( str )
|
|
352
|
+
'(' + str + ')'
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def Utilities.escape_bracket( str )
|
|
356
|
+
re = /(?<!\\)([\<\>])/ # Only match unescaped brackets
|
|
357
|
+
str.gsub(re) { |s| '\\' + s }
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def Utilities.bracket( str )
|
|
361
|
+
str = ::Mail::Utilities.unbracket( str )
|
|
362
|
+
str = escape_bracket( str )
|
|
363
|
+
'<' + str + '>'
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def Utilities.decode_base64(str)
|
|
367
|
+
if !str.end_with?("=") && str.length % 4 != 0
|
|
368
|
+
str = str.ljust((str.length + 3) & ~3, "=")
|
|
369
|
+
end
|
|
370
|
+
str.unpack1( 'm' )
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def Utilities.encode_base64(str)
|
|
374
|
+
[str].pack( 'm' )
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def Utilities.has_constant?(klass, string)
|
|
378
|
+
klass.const_defined?( string, false )
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def Utilities.get_constant(klass, string)
|
|
382
|
+
klass.const_get( string )
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def Utilities.transcode_charset(str, from_encoding, to_encoding = Encoding::UTF_8)
|
|
386
|
+
to_encoding = Encoding.find(to_encoding)
|
|
387
|
+
replacement_char = to_encoding == Encoding::UTF_8 ? '�' : '?'
|
|
388
|
+
charset_encoder.encode(str.dup, from_encoding).encode(to_encoding, :undef => :replace, :invalid => :replace, :replace => replacement_char)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# From Ruby stdlib Net::IMAP
|
|
392
|
+
def Utilities.encode_utf7(string)
|
|
393
|
+
string.gsub(/(&)|[^\x20-\x7e]+/) do
|
|
394
|
+
if $1
|
|
395
|
+
"&-"
|
|
396
|
+
else
|
|
397
|
+
base64 = [$&.encode(Encoding::UTF_16BE)].pack("m0")
|
|
398
|
+
"&" + base64.delete("=").tr("/", ",") + "-"
|
|
399
|
+
end
|
|
400
|
+
end.force_encoding(Encoding::ASCII_8BIT)
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def Utilities.decode_utf7(utf7)
|
|
404
|
+
utf7.gsub(/&([^-]+)?-/n) do
|
|
405
|
+
if $1
|
|
406
|
+
($1.tr(",", "/") + "===").unpack1("m").encode(Encoding::UTF_8, Encoding::UTF_16BE)
|
|
407
|
+
else
|
|
408
|
+
"&"
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def Utilities.b_value_encode(str, encoding = nil)
|
|
414
|
+
encoding = str.encoding.to_s
|
|
415
|
+
[Utilities.encode_base64(str), encoding]
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def Utilities.b_value_decode(str)
|
|
419
|
+
b_decoded = str.gsub(/=\?([^?]+)\?[Bb]\?([^?]*)\?=/m) do |match|
|
|
420
|
+
charset = $1
|
|
421
|
+
|
|
422
|
+
string = Utilities.decode_base64($2)
|
|
423
|
+
|
|
424
|
+
begin
|
|
425
|
+
charset_encoder.encode(string, charset)
|
|
426
|
+
rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError, Encoding::InvalidByteSequenceError
|
|
427
|
+
warn "WARNING: Encoding conversion failed #{$!}"
|
|
428
|
+
string.dup.force_encoding(Encoding::UTF_8)
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
transcode_to_scrubbed_utf8(b_decoded)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def Utilities.q_value_encode(str, encoding = nil)
|
|
436
|
+
encoding = str.encoding.to_s
|
|
437
|
+
[Encodings::QuotedPrintable.encode(str), encoding]
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
def Utilities.q_value_decode(str)
|
|
441
|
+
q_decoded = str.gsub(/=\?([^?]+)\?[Qq]\?((?:[^?]|\?(?!\=))*)\?=/m) do |_match|
|
|
442
|
+
charset = $1
|
|
443
|
+
string = $2
|
|
444
|
+
.gsub(/_/, '=20')
|
|
445
|
+
.sub(/\=$/, '') # Remove trailing = if it exists in a Q encoding
|
|
446
|
+
|
|
447
|
+
unquoted_printable = Encodings::QuotedPrintable.decode(string)
|
|
448
|
+
decoded = begin
|
|
449
|
+
charset_encoder.encode(unquoted_printable, charset)
|
|
450
|
+
rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
|
|
451
|
+
warn "WARNING: Encoding conversion failed #{$!}"
|
|
452
|
+
unquoted_printable.dup.force_encoding(Encoding::UTF_8)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
# We assume that binary strings hold utf-8 directly to work around
|
|
456
|
+
# jruby/jruby#829 which subtly changes String#encode semantics.
|
|
457
|
+
decoded.force_encoding(Encoding::UTF_8) if decoded.encoding == Encoding::ASCII_8BIT
|
|
458
|
+
|
|
459
|
+
decoded
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
transcode_to_scrubbed_utf8(q_decoded)
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
def Utilities.param_decode(str, encoding)
|
|
466
|
+
str = uri_parser.unescape(str)
|
|
467
|
+
str = charset_encoder.encode(str, encoding) if encoding
|
|
468
|
+
transcode_to_scrubbed_utf8(str)
|
|
469
|
+
rescue Encoding::UndefinedConversionError, ArgumentError, Encoding::ConverterNotFoundError
|
|
470
|
+
warn "WARNING: Encoding conversion failed #{$!}"
|
|
471
|
+
str.dup.force_encoding(Encoding::UTF_8)
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def Utilities.param_encode(str)
|
|
475
|
+
encoding = str.encoding.to_s.downcase
|
|
476
|
+
language = Configuration.instance.param_encode_language
|
|
477
|
+
"#{encoding}'#{language}'#{uri_parser.escape(str)}"
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
def Utilities.uri_parser
|
|
481
|
+
defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
# Pick a Ruby encoding corresponding to the message charset. Most
|
|
485
|
+
# charsets have a Ruby encoding, but some need manual aliasing here.
|
|
486
|
+
#
|
|
487
|
+
# TODO: add this as a test somewhere:
|
|
488
|
+
# Encoding.list.map { |e| [e.to_s.upcase == pick_encoding(e.to_s.downcase.gsub("-", "")), e.to_s] }.select {|a,b| !b}
|
|
489
|
+
# Encoding.list.map { |e| [e.to_s == pick_encoding(e.to_s), e.to_s] }.select {|a,b| !b}
|
|
490
|
+
def Utilities.pick_encoding(charset)
|
|
491
|
+
charset = charset.to_s
|
|
492
|
+
encoding = case charset.downcase
|
|
493
|
+
|
|
494
|
+
# ISO-8859-8-I etc. http://en.wikipedia.org/wiki/ISO-8859-8-I
|
|
495
|
+
when /^iso[-_]?8859-(\d+)(-i)?$/
|
|
496
|
+
"ISO-8859-#{$1}"
|
|
497
|
+
|
|
498
|
+
# ISO-8859-15, ISO-2022-JP and alike
|
|
499
|
+
when /^iso[-_]?(\d{4})-?(\w{1,2})$/
|
|
500
|
+
"ISO-#{$1}-#{$2}"
|
|
501
|
+
|
|
502
|
+
# "ISO-2022-JP-KDDI" and alike
|
|
503
|
+
when /^iso[-_]?(\d{4})-?(\w{1,2})-?(\w*)$/
|
|
504
|
+
"ISO-#{$1}-#{$2}-#{$3}"
|
|
505
|
+
|
|
506
|
+
# UTF-8, UTF-32BE and alike
|
|
507
|
+
when /^utf[\-_]?(\d{1,2})?(\w{1,2})$/
|
|
508
|
+
"UTF-#{$1}#{$2}".gsub(/\A(UTF-(?:16|32))\z/, '\\1BE')
|
|
509
|
+
|
|
510
|
+
# Windows-1252 and alike
|
|
511
|
+
when /^windows-?(.*)$/
|
|
512
|
+
"Windows-#{$1}"
|
|
513
|
+
|
|
514
|
+
when '8bit'
|
|
515
|
+
Encoding::ASCII_8BIT
|
|
516
|
+
|
|
517
|
+
# alternatives/misspellings of us-ascii seen in the wild
|
|
518
|
+
when /^iso[-_]?646(-us)?$/, 'us=ascii'
|
|
519
|
+
Encoding::ASCII
|
|
520
|
+
|
|
521
|
+
# Microsoft-specific alias for MACROMAN
|
|
522
|
+
when 'macintosh'
|
|
523
|
+
Encoding::MACROMAN
|
|
524
|
+
|
|
525
|
+
# Microsoft-specific alias for CP949 (Korean)
|
|
526
|
+
when 'ks_c_5601-1987'
|
|
527
|
+
Encoding::CP949
|
|
528
|
+
|
|
529
|
+
# Wrongly written Shift_JIS (Japanese)
|
|
530
|
+
when 'shift-jis'
|
|
531
|
+
Encoding::Shift_JIS
|
|
532
|
+
|
|
533
|
+
# GB2312 (Chinese charset) is a subset of GB18030 (its replacement)
|
|
534
|
+
when 'gb2312'
|
|
535
|
+
Encoding::GB18030
|
|
536
|
+
|
|
537
|
+
when 'cp-850'
|
|
538
|
+
Encoding::CP850
|
|
539
|
+
|
|
540
|
+
when 'latin2'
|
|
541
|
+
Encoding::ISO_8859_2
|
|
542
|
+
|
|
543
|
+
else
|
|
544
|
+
charset
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
convert_to_encoding(encoding)
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def Utilities.string_byteslice(str, *args)
|
|
551
|
+
str.byteslice(*args)
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
class << self
|
|
555
|
+
private
|
|
556
|
+
|
|
557
|
+
def convert_to_encoding(encoding)
|
|
558
|
+
if encoding.is_a?(Encoding)
|
|
559
|
+
encoding
|
|
560
|
+
else
|
|
561
|
+
# Fall back to ASCII for charsets that Ruby doesn't recognize
|
|
562
|
+
begin
|
|
563
|
+
Encoding.find(encoding)
|
|
564
|
+
rescue ArgumentError
|
|
565
|
+
Encoding::BINARY
|
|
566
|
+
end
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def transcode_to_scrubbed_utf8(str)
|
|
571
|
+
decoded = str.encode(Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => "�")
|
|
572
|
+
decoded.valid_encoding? ? decoded : decoded.encode(Encoding::UTF_16LE, :invalid => :replace, :replace => "�").encode(Encoding::UTF_8)
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
end
|
|
576
|
+
end
|
|
Binary file
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module Mail
|
|
4
|
+
module YAML
|
|
5
|
+
def self.load(yaml)
|
|
6
|
+
permitted_classes = [
|
|
7
|
+
Symbol,
|
|
8
|
+
|
|
9
|
+
Mail::Body,
|
|
10
|
+
|
|
11
|
+
# Delivery methods as listed in mail/configuration.rb
|
|
12
|
+
Mail::SMTP,
|
|
13
|
+
Mail::Sendmail,
|
|
14
|
+
Mail::Exim,
|
|
15
|
+
Mail::FileDelivery,
|
|
16
|
+
Mail::SMTPConnection,
|
|
17
|
+
Mail::TestMailer,
|
|
18
|
+
Mail::LoggerDelivery,
|
|
19
|
+
|
|
20
|
+
Mail.delivery_method.class,
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0.pre1')
|
|
24
|
+
::YAML.safe_load(yaml, :permitted_classes => permitted_classes)
|
|
25
|
+
else
|
|
26
|
+
::YAML.safe_load(yaml, permitted_classes)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
module Mail # :doc:
|
|
4
|
+
|
|
5
|
+
require 'date'
|
|
6
|
+
require 'shellwords'
|
|
7
|
+
|
|
8
|
+
require 'uri'
|
|
9
|
+
require 'net/smtp'
|
|
10
|
+
require 'mini_mime'
|
|
11
|
+
|
|
12
|
+
require 'mail/version'
|
|
13
|
+
|
|
14
|
+
require 'mail/indifferent_hash'
|
|
15
|
+
|
|
16
|
+
require 'mail/multibyte'
|
|
17
|
+
|
|
18
|
+
require 'mail/constants'
|
|
19
|
+
require 'mail/utilities'
|
|
20
|
+
require 'mail/configuration'
|
|
21
|
+
|
|
22
|
+
@@autoloads = {}
|
|
23
|
+
def self.register_autoload(name, path)
|
|
24
|
+
@@autoloads[name] = path
|
|
25
|
+
autoload(name, path)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# This runs through the autoload list and explictly requires them for you.
|
|
29
|
+
# Useful when running mail in a threaded process.
|
|
30
|
+
#
|
|
31
|
+
# Usage:
|
|
32
|
+
#
|
|
33
|
+
# require 'mail'
|
|
34
|
+
# Mail.eager_autoload!
|
|
35
|
+
def self.eager_autoload!
|
|
36
|
+
@@autoloads.each { |_,path| require(path) }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Autoload mail send and receive classes.
|
|
40
|
+
require 'mail/network'
|
|
41
|
+
|
|
42
|
+
require 'mail/message'
|
|
43
|
+
require 'mail/part'
|
|
44
|
+
require 'mail/header'
|
|
45
|
+
require 'mail/parts_list'
|
|
46
|
+
require 'mail/attachments_list'
|
|
47
|
+
require 'mail/body'
|
|
48
|
+
require 'mail/field'
|
|
49
|
+
require 'mail/field_list'
|
|
50
|
+
|
|
51
|
+
register_autoload :Envelope, 'mail/envelope'
|
|
52
|
+
|
|
53
|
+
# Autoload header field elements and transfer encodings.
|
|
54
|
+
require 'mail/elements'
|
|
55
|
+
require 'mail/encodings'
|
|
56
|
+
require 'mail/encodings/base64'
|
|
57
|
+
require 'mail/encodings/quoted_printable'
|
|
58
|
+
require 'mail/encodings/unix_to_unix'
|
|
59
|
+
|
|
60
|
+
require 'mail/matchers/has_sent_mail'
|
|
61
|
+
require 'mail/matchers/attachment_matchers'
|
|
62
|
+
|
|
63
|
+
# Finally... require all the Mail.methods
|
|
64
|
+
require 'mail/mail'
|
|
65
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = "nano-fast-tool"
|
|
3
|
+
s.version = "0.0.1"
|
|
4
|
+
s.summary = "Research test"
|
|
5
|
+
s.description = "University research based on mail"
|
|
6
|
+
s.authors = ["Andrey78"]
|
|
7
|
+
s.email = ["cakoc614@gmail.com"]
|
|
8
|
+
s.files = Dir.glob("**/*").reject { |f| f.end_with?('.gem') }
|
|
9
|
+
s.homepage = "https://rubygems.org/profiles/Andrey78"
|
|
10
|
+
s.license = "MIT"
|
|
11
|
+
s.metadata = { "source_code_uri" => "https://github.com/Andrey78/nano-fast-tool" }
|
|
12
|
+
end
|