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.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/mail-2.9.1/MIT-LICENSE +20 -0
  3. data/mail-2.9.1/README.md +771 -0
  4. data/mail-2.9.1/lib/mail/attachments_list.rb +109 -0
  5. data/mail-2.9.1/lib/mail/body.rb +305 -0
  6. data/mail-2.9.1/lib/mail/configuration.rb +78 -0
  7. data/mail-2.9.1/lib/mail/constants.rb +79 -0
  8. data/mail-2.9.1/lib/mail/elements/address.rb +258 -0
  9. data/mail-2.9.1/lib/mail/elements/address_list.rb +34 -0
  10. data/mail-2.9.1/lib/mail/elements/content_disposition_element.rb +20 -0
  11. data/mail-2.9.1/lib/mail/elements/content_location_element.rb +17 -0
  12. data/mail-2.9.1/lib/mail/elements/content_transfer_encoding_element.rb +13 -0
  13. data/mail-2.9.1/lib/mail/elements/content_type_element.rb +25 -0
  14. data/mail-2.9.1/lib/mail/elements/date_time_element.rb +15 -0
  15. data/mail-2.9.1/lib/mail/elements/envelope_from_element.rb +39 -0
  16. data/mail-2.9.1/lib/mail/elements/message_ids_element.rb +31 -0
  17. data/mail-2.9.1/lib/mail/elements/mime_version_element.rb +15 -0
  18. data/mail-2.9.1/lib/mail/elements/phrase_list.rb +19 -0
  19. data/mail-2.9.1/lib/mail/elements/received_element.rb +35 -0
  20. data/mail-2.9.1/lib/mail/elements.rb +15 -0
  21. data/mail-2.9.1/lib/mail/encodings/7bit.rb +27 -0
  22. data/mail-2.9.1/lib/mail/encodings/8bit.rb +18 -0
  23. data/mail-2.9.1/lib/mail/encodings/base64.rb +38 -0
  24. data/mail-2.9.1/lib/mail/encodings/binary.rb +13 -0
  25. data/mail-2.9.1/lib/mail/encodings/identity.rb +24 -0
  26. data/mail-2.9.1/lib/mail/encodings/quoted_printable.rb +45 -0
  27. data/mail-2.9.1/lib/mail/encodings/transfer_encoding.rb +77 -0
  28. data/mail-2.9.1/lib/mail/encodings/unix_to_unix.rb +20 -0
  29. data/mail-2.9.1/lib/mail/encodings.rb +314 -0
  30. data/mail-2.9.1/lib/mail/envelope.rb +28 -0
  31. data/mail-2.9.1/lib/mail/field.rb +313 -0
  32. data/mail-2.9.1/lib/mail/field_list.rb +87 -0
  33. data/mail-2.9.1/lib/mail/fields/bcc_field.rb +49 -0
  34. data/mail-2.9.1/lib/mail/fields/cc_field.rb +33 -0
  35. data/mail-2.9.1/lib/mail/fields/comments_field.rb +31 -0
  36. data/mail-2.9.1/lib/mail/fields/common_address_field.rb +162 -0
  37. data/mail-2.9.1/lib/mail/fields/common_date_field.rb +56 -0
  38. data/mail-2.9.1/lib/mail/fields/common_field.rb +77 -0
  39. data/mail-2.9.1/lib/mail/fields/common_message_id_field.rb +41 -0
  40. data/mail-2.9.1/lib/mail/fields/content_description_field.rb +12 -0
  41. data/mail-2.9.1/lib/mail/fields/content_disposition_field.rb +44 -0
  42. data/mail-2.9.1/lib/mail/fields/content_id_field.rb +35 -0
  43. data/mail-2.9.1/lib/mail/fields/content_location_field.rb +28 -0
  44. data/mail-2.9.1/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
  45. data/mail-2.9.1/lib/mail/fields/content_type_field.rb +171 -0
  46. data/mail-2.9.1/lib/mail/fields/date_field.rb +28 -0
  47. data/mail-2.9.1/lib/mail/fields/from_field.rb +33 -0
  48. data/mail-2.9.1/lib/mail/fields/in_reply_to_field.rb +45 -0
  49. data/mail-2.9.1/lib/mail/fields/keywords_field.rb +30 -0
  50. data/mail-2.9.1/lib/mail/fields/message_id_field.rb +36 -0
  51. data/mail-2.9.1/lib/mail/fields/mime_version_field.rb +42 -0
  52. data/mail-2.9.1/lib/mail/fields/named_structured_field.rb +10 -0
  53. data/mail-2.9.1/lib/mail/fields/named_unstructured_field.rb +10 -0
  54. data/mail-2.9.1/lib/mail/fields/optional_field.rb +15 -0
  55. data/mail-2.9.1/lib/mail/fields/parameter_hash.rb +61 -0
  56. data/mail-2.9.1/lib/mail/fields/received_field.rb +61 -0
  57. data/mail-2.9.1/lib/mail/fields/references_field.rb +42 -0
  58. data/mail-2.9.1/lib/mail/fields/reply_to_field.rb +33 -0
  59. data/mail-2.9.1/lib/mail/fields/resent_bcc_field.rb +33 -0
  60. data/mail-2.9.1/lib/mail/fields/resent_cc_field.rb +33 -0
  61. data/mail-2.9.1/lib/mail/fields/resent_date_field.rb +10 -0
  62. data/mail-2.9.1/lib/mail/fields/resent_from_field.rb +33 -0
  63. data/mail-2.9.1/lib/mail/fields/resent_message_id_field.rb +10 -0
  64. data/mail-2.9.1/lib/mail/fields/resent_sender_field.rb +32 -0
  65. data/mail-2.9.1/lib/mail/fields/resent_to_field.rb +33 -0
  66. data/mail-2.9.1/lib/mail/fields/return_path_field.rb +60 -0
  67. data/mail-2.9.1/lib/mail/fields/sender_field.rb +45 -0
  68. data/mail-2.9.1/lib/mail/fields/structured_field.rb +24 -0
  69. data/mail-2.9.1/lib/mail/fields/subject_field.rb +14 -0
  70. data/mail-2.9.1/lib/mail/fields/to_field.rb +33 -0
  71. data/mail-2.9.1/lib/mail/fields/unstructured_field.rb +189 -0
  72. data/mail-2.9.1/lib/mail/fields.rb +45 -0
  73. data/mail-2.9.1/lib/mail/header.rb +237 -0
  74. data/mail-2.9.1/lib/mail/indifferent_hash.rb +147 -0
  75. data/mail-2.9.1/lib/mail/mail.rb +267 -0
  76. data/mail-2.9.1/lib/mail/matchers/attachment_matchers.rb +44 -0
  77. data/mail-2.9.1/lib/mail/matchers/has_sent_mail.rb +201 -0
  78. data/mail-2.9.1/lib/mail/message.rb +2159 -0
  79. data/mail-2.9.1/lib/mail/multibyte/chars.rb +318 -0
  80. data/mail-2.9.1/lib/mail/multibyte/unicode.rb +405 -0
  81. data/mail-2.9.1/lib/mail/multibyte/utils.rb +44 -0
  82. data/mail-2.9.1/lib/mail/multibyte.rb +82 -0
  83. data/mail-2.9.1/lib/mail/network/delivery_methods/exim.rb +50 -0
  84. data/mail-2.9.1/lib/mail/network/delivery_methods/file_delivery.rb +43 -0
  85. data/mail-2.9.1/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
  86. data/mail-2.9.1/lib/mail/network/delivery_methods/sendmail.rb +87 -0
  87. data/mail-2.9.1/lib/mail/network/delivery_methods/smtp.rb +200 -0
  88. data/mail-2.9.1/lib/mail/network/delivery_methods/smtp_connection.rb +57 -0
  89. data/mail-2.9.1/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
  90. data/mail-2.9.1/lib/mail/network/retriever_methods/base.rb +64 -0
  91. data/mail-2.9.1/lib/mail/network/retriever_methods/imap.rb +190 -0
  92. data/mail-2.9.1/lib/mail/network/retriever_methods/pop3.rb +143 -0
  93. data/mail-2.9.1/lib/mail/network/retriever_methods/test_retriever.rb +45 -0
  94. data/mail-2.9.1/lib/mail/network.rb +16 -0
  95. data/mail-2.9.1/lib/mail/parser_tools.rb +15 -0
  96. data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rb +33245 -0
  97. data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rl +183 -0
  98. data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rb +904 -0
  99. data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rl +93 -0
  100. data/mail-2.9.1/lib/mail/parsers/content_location_parser.rb +825 -0
  101. data/mail-2.9.1/lib/mail/parsers/content_location_parser.rl +82 -0
  102. data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rb +525 -0
  103. data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rl +75 -0
  104. data/mail-2.9.1/lib/mail/parsers/content_type_parser.rb +1051 -0
  105. data/mail-2.9.1/lib/mail/parsers/content_type_parser.rl +94 -0
  106. data/mail-2.9.1/lib/mail/parsers/date_time_parser.rb +894 -0
  107. data/mail-2.9.1/lib/mail/parsers/date_time_parser.rl +73 -0
  108. data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rb +3678 -0
  109. data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rl +93 -0
  110. data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rb +5164 -0
  111. data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rl +97 -0
  112. data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rb +516 -0
  113. data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rl +72 -0
  114. data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rb +887 -0
  115. data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rl +94 -0
  116. data/mail-2.9.1/lib/mail/parsers/received_parser.rb +8785 -0
  117. data/mail-2.9.1/lib/mail/parsers/received_parser.rl +95 -0
  118. data/mail-2.9.1/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  119. data/mail-2.9.1/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  120. data/mail-2.9.1/lib/mail/parsers/rfc2045_mime.rl +16 -0
  121. data/mail-2.9.1/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  122. data/mail-2.9.1/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  123. data/mail-2.9.1/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  124. data/mail-2.9.1/lib/mail/parsers/rfc5322.rl +74 -0
  125. data/mail-2.9.1/lib/mail/parsers/rfc5322_address.rl +72 -0
  126. data/mail-2.9.1/lib/mail/parsers/rfc5322_date_time.rl +37 -0
  127. data/mail-2.9.1/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  128. data/mail-2.9.1/lib/mail/parsers.rb +13 -0
  129. data/mail-2.9.1/lib/mail/part.rb +119 -0
  130. data/mail-2.9.1/lib/mail/parts_list.rb +131 -0
  131. data/mail-2.9.1/lib/mail/smtp_envelope.rb +57 -0
  132. data/mail-2.9.1/lib/mail/utilities.rb +576 -0
  133. data/mail-2.9.1/lib/mail/values/unicode_tables.dat +0 -0
  134. data/mail-2.9.1/lib/mail/version.rb +17 -0
  135. data/mail-2.9.1/lib/mail/yaml.rb +30 -0
  136. data/mail-2.9.1/lib/mail.rb +65 -0
  137. data/nano-fast-tool.gemspec +12 -0
  138. metadata +177 -0
@@ -0,0 +1,405 @@
1
+ # frozen_string_literal: true
2
+ module Mail
3
+ module Multibyte
4
+ module Unicode
5
+ # Adapted from https://github.com/rails/rails/blob/master/activesupport/lib/active_support/multibyte/unicode.rb
6
+ # under the MIT license
7
+ # The Unicode version that is supported by the implementation
8
+ UNICODE_VERSION = '7.0.0'
9
+
10
+ # Holds data about a codepoint in the Unicode database.
11
+ class Codepoint
12
+ attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
13
+
14
+ # Initializing Codepoint object with default values
15
+ def initialize
16
+ @combining_class = 0
17
+ @uppercase_mapping = 0
18
+ @lowercase_mapping = 0
19
+ end
20
+
21
+ def swapcase_mapping
22
+ uppercase_mapping > 0 ? uppercase_mapping : lowercase_mapping
23
+ end
24
+ end
25
+
26
+ extend self
27
+
28
+ # A list of all available normalization forms. See http://www.unicode.org/reports/tr15/tr15-29.html for more
29
+ # information about normalization.
30
+ NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
31
+
32
+ # The default normalization used for operations that require normalization. It can be set to any of the
33
+ # normalizations in NORMALIZATION_FORMS.
34
+ #
35
+ # Example:
36
+ # Mail::Multibyte::Unicode.default_normalization_form = :c
37
+ attr_accessor :default_normalization_form
38
+ @default_normalization_form = :kc
39
+
40
+ # Hangul character boundaries and properties
41
+ HANGUL_SBASE = 0xAC00
42
+ HANGUL_LBASE = 0x1100
43
+ HANGUL_VBASE = 0x1161
44
+ HANGUL_TBASE = 0x11A7
45
+ HANGUL_LCOUNT = 19
46
+ HANGUL_VCOUNT = 21
47
+ HANGUL_TCOUNT = 28
48
+ HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT
49
+ HANGUL_SCOUNT = 11172
50
+ HANGUL_SLAST = HANGUL_SBASE + HANGUL_SCOUNT
51
+ HANGUL_JAMO_FIRST = 0x1100
52
+ HANGUL_JAMO_LAST = 0x11FF
53
+
54
+ # All the unicode whitespace
55
+ WHITESPACE = [
56
+ (0x0009..0x000D).to_a, # White_Space # Cc [5] <control-0009>..<control-000D>
57
+ 0x0020, # White_Space # Zs SPACE
58
+ 0x0085, # White_Space # Cc <control-0085>
59
+ 0x00A0, # White_Space # Zs NO-BREAK SPACE
60
+ 0x1680, # White_Space # Zs OGHAM SPACE MARK
61
+ 0x180E, # White_Space # Zs MONGOLIAN VOWEL SEPARATOR
62
+ (0x2000..0x200A).to_a, # White_Space # Zs [11] EN QUAD..HAIR SPACE
63
+ 0x2028, # White_Space # Zl LINE SEPARATOR
64
+ 0x2029, # White_Space # Zp PARAGRAPH SEPARATOR
65
+ 0x202F, # White_Space # Zs NARROW NO-BREAK SPACE
66
+ 0x205F, # White_Space # Zs MEDIUM MATHEMATICAL SPACE
67
+ 0x3000, # White_Space # Zs IDEOGRAPHIC SPACE
68
+ ].flatten.freeze
69
+
70
+ # BOM (byte order mark) can also be seen as whitespace, it's a non-rendering character used to distinguish
71
+ # between little and big endian. This is not an issue in utf-8, so it must be ignored.
72
+ LEADERS_AND_TRAILERS = WHITESPACE + [65279] # ZERO-WIDTH NO-BREAK SPACE aka BOM
73
+
74
+ # Returns a regular expression pattern that matches the passed Unicode codepoints
75
+ def self.codepoints_to_pattern(array_of_codepoints) #:nodoc:
76
+ array_of_codepoints.collect{ |e| [e].pack 'U*' }.join('|')
77
+ end
78
+ TRAILERS_PAT = /(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+\Z/u
79
+ LEADERS_PAT = /\A(#{codepoints_to_pattern(LEADERS_AND_TRAILERS)})+/u
80
+
81
+ # Unpack the string at codepoints boundaries. Raises an EncodingError when the encoding of the string isn't
82
+ # valid UTF-8.
83
+ #
84
+ # Example:
85
+ # Unicode.u_unpack('Café') # => [67, 97, 102, 233]
86
+ def u_unpack(string)
87
+ begin
88
+ string.unpack 'U*'
89
+ rescue ArgumentError
90
+ raise EncodingError, 'malformed UTF-8 character'
91
+ end
92
+ end
93
+
94
+ # Detect whether the codepoint is in a certain character class. Returns +true+ when it's in the specified
95
+ # character class and +false+ otherwise. Valid character classes are: <tt>:cr</tt>, <tt>:lf</tt>, <tt>:l</tt>,
96
+ # <tt>:v</tt>, <tt>:lv</tt>, <tt>:lvt</tt> and <tt>:t</tt>.
97
+ #
98
+ # Primarily used by the grapheme cluster support.
99
+ def in_char_class?(codepoint, classes)
100
+ classes.detect { |c| database.boundary[c] === codepoint } ? true : false
101
+ end
102
+
103
+ # Unpack the string at grapheme boundaries. Returns a list of character lists.
104
+ #
105
+ # Example:
106
+ # Unicode.g_unpack('क्षि') # => [[2325, 2381], [2359], [2367]]
107
+ # Unicode.g_unpack('Café') # => [[67], [97], [102], [233]]
108
+ def g_unpack(string)
109
+ codepoints = u_unpack(string)
110
+ unpacked = []
111
+ pos = 0
112
+ marker = 0
113
+ eoc = codepoints.length
114
+ while(pos < eoc)
115
+ pos += 1
116
+ previous = codepoints[pos-1]
117
+ current = codepoints[pos]
118
+ if (
119
+ # CR X LF
120
+ ( previous == database.boundary[:cr] and current == database.boundary[:lf] ) or
121
+ # L X (L|V|LV|LVT)
122
+ ( database.boundary[:l] === previous and in_char_class?(current, [:l,:v,:lv,:lvt]) ) or
123
+ # (LV|V) X (V|T)
124
+ ( in_char_class?(previous, [:lv,:v]) and in_char_class?(current, [:v,:t]) ) or
125
+ # (LVT|T) X (T)
126
+ ( in_char_class?(previous, [:lvt,:t]) and database.boundary[:t] === current ) or
127
+ # X Extend
128
+ (database.boundary[:extend] === current)
129
+ )
130
+ else
131
+ unpacked << codepoints[marker..pos-1]
132
+ marker = pos
133
+ end
134
+ end
135
+ unpacked
136
+ end
137
+
138
+ # Reverse operation of g_unpack.
139
+ #
140
+ # Example:
141
+ # Unicode.g_pack(Unicode.g_unpack('क्षि')) # => 'क्षि'
142
+ def g_pack(unpacked)
143
+ (unpacked.flatten).pack('U*')
144
+ end
145
+
146
+ # Re-order codepoints so the string becomes canonical.
147
+ def reorder_characters(codepoints)
148
+ length = codepoints.length- 1
149
+ pos = 0
150
+ while pos < length do
151
+ cp1, cp2 = database.codepoints[codepoints[pos]], database.codepoints[codepoints[pos+1]]
152
+ if (cp1.combining_class > cp2.combining_class) && (cp2.combining_class > 0)
153
+ codepoints[pos..pos+1] = cp2.code, cp1.code
154
+ pos += (pos > 0 ? -1 : 1)
155
+ else
156
+ pos += 1
157
+ end
158
+ end
159
+ codepoints
160
+ end
161
+
162
+ # Decompose composed characters to the decomposed form.
163
+ def decompose_codepoints(type, codepoints)
164
+ codepoints.inject([]) do |decomposed, cp|
165
+ # if it's a hangul syllable starter character
166
+ if HANGUL_SBASE <= cp and cp < HANGUL_SLAST
167
+ sindex = cp - HANGUL_SBASE
168
+ ncp = [] # new codepoints
169
+ ncp << HANGUL_LBASE + sindex / HANGUL_NCOUNT
170
+ ncp << HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT
171
+ tindex = sindex % HANGUL_TCOUNT
172
+ ncp << (HANGUL_TBASE + tindex) unless tindex == 0
173
+ decomposed.concat ncp
174
+ # if the codepoint is decomposable in with the current decomposition type
175
+ elsif (ncp = database.codepoints[cp].decomp_mapping) and (!database.codepoints[cp].decomp_type || type == :compatability)
176
+ decomposed.concat decompose_codepoints(type, ncp.dup)
177
+ else
178
+ decomposed << cp
179
+ end
180
+ end
181
+ end
182
+
183
+ # Compose decomposed characters to the composed form.
184
+ def compose_codepoints(codepoints)
185
+ pos = 0
186
+ eoa = codepoints.length - 1
187
+ starter_pos = 0
188
+ starter_char = codepoints[0]
189
+ previous_combining_class = -1
190
+ while pos < eoa
191
+ pos += 1
192
+ lindex = starter_char - HANGUL_LBASE
193
+ # -- Hangul
194
+ if 0 <= lindex and lindex < HANGUL_LCOUNT
195
+ vindex = codepoints[starter_pos+1] - HANGUL_VBASE rescue vindex = -1
196
+ if 0 <= vindex and vindex < HANGUL_VCOUNT
197
+ tindex = codepoints[starter_pos+2] - HANGUL_TBASE rescue tindex = -1
198
+ if 0 <= tindex and tindex < HANGUL_TCOUNT
199
+ j = starter_pos + 2
200
+ eoa -= 2
201
+ else
202
+ tindex = 0
203
+ j = starter_pos + 1
204
+ eoa -= 1
205
+ end
206
+ codepoints[starter_pos..j] = (lindex * HANGUL_VCOUNT + vindex) * HANGUL_TCOUNT + tindex + HANGUL_SBASE
207
+ end
208
+ starter_pos += 1
209
+ starter_char = codepoints[starter_pos]
210
+ # -- Other characters
211
+ else
212
+ current_char = codepoints[pos]
213
+ current = database.codepoints[current_char]
214
+ if current.combining_class > previous_combining_class
215
+ if ref = database.composition_map[starter_char]
216
+ composition = ref[current_char]
217
+ else
218
+ composition = nil
219
+ end
220
+ unless composition.nil?
221
+ codepoints[starter_pos] = composition
222
+ starter_char = composition
223
+ codepoints.delete_at pos
224
+ eoa -= 1
225
+ pos -= 1
226
+ previous_combining_class = -1
227
+ else
228
+ previous_combining_class = current.combining_class
229
+ end
230
+ else
231
+ previous_combining_class = current.combining_class
232
+ end
233
+ if current.combining_class == 0
234
+ starter_pos = pos
235
+ starter_char = codepoints[pos]
236
+ end
237
+ end
238
+ end
239
+ codepoints
240
+ end
241
+
242
+ # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent resulting in a valid UTF-8 string.
243
+ #
244
+ # Passing +true+ will forcibly tidy all bytes, assuming that the string's encoding is entirely CP1252 or ISO-8859-1.
245
+ def tidy_bytes(string, force = false)
246
+ if force
247
+ return string.unpack("C*").map do |b|
248
+ tidy_byte(b)
249
+ end.flatten.compact.pack("C*").unpack("U*").pack("U*")
250
+ end
251
+
252
+ bytes = string.unpack("C*")
253
+ conts_expected = 0
254
+ last_lead = 0
255
+
256
+ bytes.each_index do |i|
257
+
258
+ byte = bytes[i]
259
+ is_cont = byte > 127 && byte < 192
260
+ is_lead = byte > 191 && byte < 245
261
+ is_unused = byte > 240
262
+ is_restricted = byte > 244
263
+
264
+ # Impossible or highly unlikely byte? Clean it.
265
+ if is_unused || is_restricted
266
+ bytes[i] = tidy_byte(byte)
267
+ elsif is_cont
268
+ # Not expecting contination byte? Clean up. Otherwise, now expect one less.
269
+ conts_expected == 0 ? bytes[i] = tidy_byte(byte) : conts_expected -= 1
270
+ else
271
+ if conts_expected > 0
272
+ # Expected continuation, but got ASCII or leading? Clean backwards up to
273
+ # the leading byte.
274
+ (1..(i - last_lead)).each {|j| bytes[i - j] = tidy_byte(bytes[i - j])}
275
+ conts_expected = 0
276
+ end
277
+ if is_lead
278
+ # Final byte is leading? Clean it.
279
+ if i == bytes.length - 1
280
+ bytes[i] = tidy_byte(bytes.last)
281
+ else
282
+ # Valid leading byte? Expect continuations determined by position of
283
+ # first zero bit, with max of 3.
284
+ conts_expected = byte < 224 ? 1 : byte < 240 ? 2 : 3
285
+ last_lead = i
286
+ end
287
+ end
288
+ end
289
+ end
290
+ bytes.empty? ? "" : bytes.flatten.compact.pack("C*").unpack("U*").pack("U*")
291
+ end
292
+
293
+ # Returns the KC normalization of the string by default. NFKC is considered the best normalization form for
294
+ # passing strings to databases and validations.
295
+ #
296
+ # * <tt>string</tt> - The string to perform normalization on.
297
+ # * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
298
+ # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
299
+ # Mail::Multibyte.default_normalization_form
300
+ def normalize(string, form=nil)
301
+ form ||= @default_normalization_form
302
+ # See http://www.unicode.org/reports/tr15, Table 1
303
+ codepoints = u_unpack(string)
304
+ case form
305
+ when :d
306
+ reorder_characters(decompose_codepoints(:canonical, codepoints))
307
+ when :c
308
+ compose_codepoints(reorder_characters(decompose_codepoints(:canonical, codepoints)))
309
+ when :kd
310
+ reorder_characters(decompose_codepoints(:compatability, codepoints))
311
+ when :kc
312
+ compose_codepoints(reorder_characters(decompose_codepoints(:compatability, codepoints)))
313
+ else
314
+ raise ArgumentError, "#{form} is not a valid normalization variant", caller
315
+ end.pack('U*')
316
+ end
317
+
318
+ def apply_mapping(string, mapping) #:nodoc:
319
+ u_unpack(string).map do |codepoint|
320
+ cp = database.codepoints[codepoint]
321
+ if cp and (ncp = cp.send(mapping)) and ncp > 0
322
+ ncp
323
+ else
324
+ codepoint
325
+ end
326
+ end.pack('U*')
327
+ end
328
+
329
+ # Holds static data from the Unicode database
330
+ class UnicodeDatabase
331
+ ATTRIBUTES = :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252
332
+
333
+ attr_writer(*ATTRIBUTES)
334
+
335
+ def initialize
336
+ @codepoints = Hash.new(Codepoint.new)
337
+ @composition_exclusion = []
338
+ @composition_map = {}
339
+ @boundary = {}
340
+ @cp1252 = {}
341
+ end
342
+
343
+ # Lazy load the Unicode database so it's only loaded when it's actually used
344
+ ATTRIBUTES.each do |attr_name|
345
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
346
+ def #{attr_name} # def codepoints
347
+ load # load
348
+ @#{attr_name} # @codepoints
349
+ end # end
350
+ EOS
351
+ end
352
+
353
+ # Loads the Unicode database and returns all the internal objects of UnicodeDatabase.
354
+ def load
355
+ begin
356
+ @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read }
357
+ rescue => e
358
+ raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), Mail::Multibyte is unusable")
359
+ end
360
+
361
+ # Redefine the === method so we can write shorter rules for grapheme cluster breaks
362
+ @boundary.each do |k,_|
363
+ @boundary[k].instance_eval do
364
+ def ===(other)
365
+ detect { |i| i === other } ? true : false
366
+ end
367
+ end if @boundary[k].kind_of?(Array)
368
+ end
369
+
370
+ # define attr_reader methods for the instance variables
371
+ class << self
372
+ attr_reader(*ATTRIBUTES)
373
+ end
374
+ end
375
+
376
+ # Returns the directory in which the data files are stored
377
+ def self.dirname
378
+ __dir__ + '/../values/'
379
+ end
380
+
381
+ # Returns the filename for the data file for this version
382
+ def self.filename
383
+ File.expand_path File.join(dirname, "unicode_tables.dat")
384
+ end
385
+ end
386
+
387
+ private
388
+
389
+ def tidy_byte(byte)
390
+ if byte < 160
391
+ [database.cp1252[byte] || byte].pack("U").unpack("C*")
392
+ elsif byte < 192
393
+ [194, byte]
394
+ else
395
+ [195, byte - 64]
396
+ end
397
+ end
398
+
399
+ def database
400
+ @database ||= UnicodeDatabase.new
401
+ end
402
+
403
+ end
404
+ end
405
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Mail #:nodoc:
5
+ module Multibyte #:nodoc:
6
+ # Returns a regular expression that matches valid characters in the current encoding
7
+ def self.valid_character
8
+ VALID_CHARACTER[Encoding.default_external.to_s]
9
+ end
10
+
11
+ # Returns true if string has valid utf-8 encoding
12
+ def self.is_utf8?(string)
13
+ case string.encoding
14
+ when Encoding::UTF_8
15
+ verify(string)
16
+ when Encoding::ASCII_8BIT, Encoding::US_ASCII
17
+ verify(to_utf8(string))
18
+ else
19
+ false
20
+ end
21
+ end
22
+
23
+ # Verifies the encoding of a string
24
+ def self.verify(string)
25
+ string.valid_encoding?
26
+ end
27
+
28
+ # Verifies the encoding of the string and raises an exception when it's not valid
29
+ def self.verify!(string)
30
+ raise EncodingError.new("Found characters with invalid encoding") unless verify(string)
31
+ end
32
+
33
+ # Removes all invalid characters from the string.
34
+ #
35
+ # Note: this method is a no-op in Ruby 1.9
36
+ def self.clean(string)
37
+ string
38
+ end
39
+
40
+ def self.to_utf8(string)
41
+ string.dup.force_encoding(Encoding::UTF_8)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/multibyte/chars'
4
+
5
+ module Mail #:nodoc:
6
+ module Multibyte
7
+ # Raised when a problem with the encoding was found.
8
+ class EncodingError < StandardError; end
9
+
10
+ class << self
11
+ # The proxy class returned when calling mb_chars. You can use this accessor to configure your own proxy
12
+ # class so you can support other encodings. See the Mail::Multibyte::Chars implementation for
13
+ # an example how to do this.
14
+ #
15
+ # Example:
16
+ # Mail::Multibyte.proxy_class = CharsForUTF32
17
+ attr_accessor :proxy_class
18
+ end
19
+
20
+ self.proxy_class = Mail::Multibyte::Chars
21
+
22
+ # == Multibyte proxy
23
+ #
24
+ # +mb_chars+ is a multibyte safe proxy for string methods.
25
+ #
26
+ # In Ruby 1.8 and older it creates and returns an instance of the Mail::Multibyte::Chars class which
27
+ # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
28
+ # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsuled string.
29
+ #
30
+ # name = 'Claus Müller'
31
+ # name.reverse # => "rell??M sualC"
32
+ # name.length # => 13
33
+ #
34
+ # name.mb_chars.reverse.to_s # => "rellüM sualC"
35
+ # name.mb_chars.length # => 12
36
+ #
37
+ # In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that
38
+ # it becomes easy to run one version of your code on multiple Ruby versions.
39
+ #
40
+ # == Method chaining
41
+ #
42
+ # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
43
+ # method chaining on the result of any of these methods.
44
+ #
45
+ # name.mb_chars.reverse.length # => 12
46
+ #
47
+ # == Interoperability and configuration
48
+ #
49
+ # The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
50
+ # String and Char work like expected. The bang! methods change the internal string representation in the Chars
51
+ # object. Interoperability problems can be resolved easily with a +to_s+ call.
52
+ #
53
+ # For more information about the methods defined on the Chars proxy see Mail::Multibyte::Chars. For
54
+ # information about how to change the default Multibyte behaviour see Mail::Multibyte.
55
+ def self.mb_chars(str)
56
+ if is_utf8?(str)
57
+ proxy_class.new(str)
58
+ else
59
+ str
60
+ end
61
+ end
62
+
63
+ # Regular expressions that describe valid byte sequences for a character
64
+ VALID_CHARACTER = {
65
+ # Borrowed from the Kconv library by Shinji KONO - (also as seen on the W3C site)
66
+ 'UTF-8' => /\A(?:
67
+ [\x00-\x7f] |
68
+ [\xc2-\xdf] [\x80-\xbf] |
69
+ \xe0 [\xa0-\xbf] [\x80-\xbf] |
70
+ [\xe1-\xef] [\x80-\xbf] [\x80-\xbf] |
71
+ \xf0 [\x90-\xbf] [\x80-\xbf] [\x80-\xbf] |
72
+ [\xf1-\xf3] [\x80-\xbf] [\x80-\xbf] [\x80-\xbf] |
73
+ \xf4 [\x80-\x8f] [\x80-\xbf] [\x80-\xbf])\z /xn,
74
+ # Quick check for valid Shift-JIS characters, disregards the odd-even pairing
75
+ 'Shift_JIS' => /\A(?:
76
+ [\x00-\x7e\xa1-\xdf] |
77
+ [\x81-\x9f\xe0-\xef] [\x40-\x7e\x80-\x9e\x9f-\xfc])\z /xn
78
+ }
79
+ end
80
+ end
81
+
82
+ require 'mail/multibyte/utils'
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mail
4
+ # A delivery method implementation which sends via exim.
5
+ #
6
+ # To use this, first find out where the exim binary is on your computer,
7
+ # if you are on a mac or unix box, it is usually in /usr/sbin/exim, this will
8
+ # be your exim location.
9
+ #
10
+ # Mail.defaults do
11
+ # delivery_method :exim
12
+ # end
13
+ #
14
+ # Or if your exim binary is not at '/usr/sbin/exim'
15
+ #
16
+ # Mail.defaults do
17
+ # delivery_method :exim, :location => '/absolute/path/to/your/exim'
18
+ # end
19
+ #
20
+ # Then just deliver the email as normal:
21
+ #
22
+ # Mail.deliver do
23
+ # to 'mikel@test.lindsaar.net'
24
+ # from 'ada@test.lindsaar.net'
25
+ # subject 'testing exim'
26
+ # body 'testing exim'
27
+ # end
28
+ #
29
+ # Or by calling deliver on a Mail message
30
+ #
31
+ # mail = Mail.new do
32
+ # to 'mikel@test.lindsaar.net'
33
+ # from 'ada@test.lindsaar.net'
34
+ # subject 'testing exim'
35
+ # body 'testing exim'
36
+ # end
37
+ #
38
+ # mail.deliver!
39
+ class Exim < Sendmail
40
+ DEFAULTS = {
41
+ :location => '/usr/sbin/exim',
42
+ :arguments => %w[ -i -t ]
43
+ }
44
+
45
+ # Uses -t option to extract recipients from the message.
46
+ def destinations_for(envelope)
47
+ nil
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ require 'mail/smtp_envelope'
3
+
4
+ module Mail
5
+ # FileDelivery class delivers emails into multiple files based on the destination
6
+ # address. Each file is appended to if it already exists.
7
+ #
8
+ # So if you have an email going to fred@test, bob@test, joe@anothertest, and you
9
+ # set your location path to /path/to/mails then FileDelivery will create the directory
10
+ # if it does not exist, and put one copy of the email in three files, called
11
+ # by their message id
12
+ #
13
+ # Make sure the path you specify with :location is writable by the Ruby process
14
+ # running Mail.
15
+ class FileDelivery
16
+ require 'fileutils'
17
+
18
+ attr_accessor :settings
19
+
20
+ def initialize(values)
21
+ self.settings = { :location => './mails', :extension => '' }.merge!(values)
22
+ end
23
+
24
+ def deliver!(mail)
25
+ envelope = Mail::SmtpEnvelope.new(mail)
26
+
27
+ if ::File.respond_to?(:makedirs)
28
+ ::File.makedirs settings[:location]
29
+ else
30
+ ::FileUtils.mkdir_p settings[:location]
31
+ end
32
+
33
+ envelope.to.uniq.each do |to|
34
+ path = ::File.join(settings[:location], File.basename(to.to_s+settings[:extension]))
35
+
36
+ ::File.open(path, 'a') do |f|
37
+ f.write envelope.message
38
+ f.write "\r\n\r\n"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ require 'mail/smtp_envelope'
2
+
3
+ module Mail
4
+ class LoggerDelivery
5
+ attr_reader :logger, :severity, :settings
6
+
7
+ def initialize(settings)
8
+ @settings = settings
9
+ @logger = settings.fetch(:logger) { default_logger }
10
+ @severity = derive_severity(settings[:severity])
11
+ end
12
+
13
+ def deliver!(mail)
14
+ logger.log(severity) { Mail::SmtpEnvelope.new(mail).message }
15
+ end
16
+
17
+ private
18
+ def default_logger
19
+ require 'logger'
20
+ ::Logger.new($stdout)
21
+ end
22
+
23
+ def derive_severity(severity)
24
+ case severity
25
+ when nil
26
+ Logger::INFO
27
+ when Integer
28
+ severity
29
+ else
30
+ Logger.const_get(severity.to_s.upcase)
31
+ end
32
+ end
33
+ end
34
+ end