1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
# frozen_string_literal: true
require 'delegate'
module Mail
class PartsList < DelegateClass(Array)
attr_reader :parts
def initialize(*args)
@parts = Array.new(*args)
super @parts
end
# The #encode_with and #to_yaml methods are just implemented
# for the sake of backward compatibility ; the delegator does
# not correctly delegate these calls to the delegated object
def encode_with(coder) # :nodoc:
coder.represent_object(nil, @parts)
end
def to_yaml(options = {}) # :nodoc:
@parts.to_yaml(options)
end
def attachments
Mail::AttachmentsList.new(@parts)
end
def collect
if block_given?
ary = PartsList.new
each { |o| ary << yield(o) }
ary
else
to_a
end
end
alias_method :map, :collect
def map!
raise NoMethodError, "#map! is not defined, please call #collect and create a new PartsList"
end
def collect!
raise NoMethodError, "#collect! is not defined, please call #collect and create a new PartsList"
end
def inspect_structure(parent_id = '')
enum_for(:map).with_index { |part, i|
i = i + 1 # Use 1-based indexes since this is for humans to read
id = parent_id.empty? ? "#{i}" : "#{parent_id}.#{i}"
if part.content_type == "message/rfc822"
sub_list = Mail.new(part.body).parts
else
sub_list = part.parts
end
id + '. ' + part.inspect +
if sub_list.any?
"\n" + sub_list.inspect_structure(id)
end.to_s
}.join("\n")
end
def recursive_each(&block)
each do |part|
if part.content_type == "message/rfc822"
sub_list = Mail.new(part.body).parts
else
sub_list = part.parts
end
yield part
sub_list.recursive_each(&block)
end
end
def recursive_size
i = 0
recursive_each {|p| i += 1 }
i
end
def recursive_delete_if
delete_if { |part|
if part.content_type == "message/rfc822"
sub_list = Mail.new(part.body).parts
else
sub_list = part.parts
end
(yield part).tap {
if sub_list.any?
sub_list.recursive_delete_if {|part| yield part }
end
}
}
end
def delete_attachments
recursive_delete_if { |part|
part.attachment?
}
end
def sort
self.class.new(@parts.sort)
end
def sort!(order)
# stable sort should be used to maintain the relative order as the parts are added
i = 0;
sorted = @parts.sort_by do |a|
# OK, 10000 is arbitrary... if anyone actually wants to explicitly sort 10000 parts of a
# single email message... please show me a use case and I'll put more work into this method,
# in the meantime, it works :)
get_order_value(a, order) << (i += 1)
end
@parts.clear
sorted.each { |p| @parts << p }
end
private
def get_order_value(part, order)
is_attachment = part.respond_to?(:attachment?) && part.attachment?
has_content_type = part.respond_to?(:content_type) && !part[:content_type].nil?
[is_attachment ? 1 : 0, (has_content_type ? order.index(part[:content_type].string.downcase) : nil) || 10000]
end
end
end
|