1
0
مراية لـ https://github.com/postalserver/postal.git تم المزامنة 2025-12-01 05:43:04 +00:00
الملفات
postal/lib/postal/message_parser.rb
2021-07-29 11:20:47 +00:00

152 أسطر
4.0 KiB
Ruby

module Postal
class MessageParser
URL_REGEX = /(?<url>(?<protocol>https?)\:\/\/(?<domain>[A-Za-z0-9\-\.\:]+)(?<path>\/[A-Za-z0-9\.\/\+\?\&\-\_\%\=\~\:\;\(\)\[\]#]*)?+)/
def initialize(message)
@message = message
@actioned = false
@tracked_links = 0
@tracked_images = 0
@domain = @message.server.track_domains.where(:domain => @message.domain, :dns_status => "OK").first
if @domain
@parsed_output = generate
end
end
attr_reader :tracked_links
attr_reader :tracked_images
def actioned?
@actioned || @tracked_links > 0 || @tracked_images > 0
end
def new_body
@parsed_output.split("\r\n\r\n", 2)[1]
end
private
def generate
@mail = Mail.new(@message.raw_message)
@original_message = @message.raw_message
if @mail.parts.empty?
if @mail.mime_type
if @mail.mime_type =~ /text\/plain/
@mail.body = parse(@mail.body.decoded.dup, :text)
@mail.content_transfer_encoding = nil
@mail.charset = 'UTF-8'
elsif @mail.mime_type =~ /text\/html/
@mail.body = parse(@mail.body.decoded.dup, :html)
@mail.content_transfer_encoding = nil
@mail.charset = 'UTF-8'
end
end
else
parse_parts(@mail.parts)
end
@mail.to_s
rescue => e
if Rails.env.development?
raise
else
if defined?(Raven)
Raven.capture_exception(e)
end
@actioned = false
@tracked_links = 0
@tracked_images = 0
@original_message
end
end
def parse_parts(parts)
parts.each do |part|
if part.content_type =~ /text\/html/
part.body = parse(part.body.decoded.dup, :html)
part.content_transfer_encoding = nil
part.charset = 'UTF-8'
elsif part.content_type =~ /text\/plain/
part.body = parse(part.body.decoded.dup, :text)
part.content_transfer_encoding = nil
part.charset = 'UTF-8'
elsif part.content_type =~ /multipart\/(alternative|related)/
unless part.parts.empty?
parse_parts(part.parts)
end
end
end
end
def parse(part, type = nil)
if @domain.track_clicks?
part = insert_links(part, type)
end
if @domain.track_loads? && type == :html
part = insert_tracking_image(part)
end
part
end
def insert_links(part, type = nil)
if type == :text
part.gsub!(/(#{URL_REGEX})(?=\s|$)/) do
if track_domain?($~[:domain])
@tracked_links += 1
url = $~[:url]
while url =~ /[^\w]$/ do
theend = url.size - 2
url = url[0..theend]
end
token = @message.create_link(url)
"#{domain}/#{@message.server.token}/#{token}"
else
$&
end
end
end
if type == :html
part.gsub!(/href=([\'\"])(#{URL_REGEX})[\'\"]/) do
if track_domain?($~[:domain])
@tracked_links += 1
token = @message.create_link($~[:url])
"href='#{domain}/#{@message.server.token}/#{token}'"
else
$&
end
end
end
part.gsub!(/(https?)\+notrack\:\/\//) do
@actioned = true
"#{$1}://"
end
part
end
def insert_tracking_image(part)
@tracked_images += 1
container = "<p class='ampimg' style='display:none;visibility:none;margin:0;padding:0;line-height:0;'><img src='#{domain}/img/#{@message.server.token}/#{@message.token}' alt=''></p>"
if part =~ /\<\/body\>/
part.gsub("</body>", "#{container}</body>")
else
part + container
end
end
def domain
"#{@domain.use_ssl? ? 'https' : 'http'}://#{@domain.full_name}"
end
def track_domain?(domain)
!@domain.excluded_click_domains_array.include?(domain)
end
end
end