1# frozen_string_literal: true
2
3class IncomingMMS
4 def self.for(to, json)
5 raise "Unknown encoding: #{json.inspect}" if json["encoding"] != "native"
6
7 txt, media = extract_parts(json)
8
9 EMPromise.all(
10 txt.map { |u|
11 EM::HttpRequest.new(u, tls: { verify_peer: true }).get.then(&:response)
12 }
13 ).then do |fetched_txt|
14 new(to, fetched_txt, media, clean_fake_array(json["recip"]))
15 end
16 end
17
18 def self.extract_parts(json)
19 clean_fake_array(json["files"])
20 .grep_v(/\.smil\Z/i)
21 .map { |part| "#{json['url']}&authkey=#{json['authkey']}&file=#{part}" }
22 .partition { |url| url.end_with?(".txt") }
23 end
24
25 def self.clean_fake_array(str)
26 # Instead of arrays we get sent comma-seperated strings
27 # which sometimes contain blank elements or random whitespace
28 str.to_s.split(",").map(&:strip).reject(&:empty?)
29 end
30
31 def initialize(to, txt, media, recip)
32 @to = to
33 @txt = txt
34 @media = media
35 @recip = recip
36 end
37
38 # MMS text parts are separate fetched .txt files; join with paragraph breaks
39 def body_text
40 @txt.empty? ? "" : @txt.join("\n\n")
41 end
42
43 def media_urls
44 @media
45 end
46
47 def unproxied_to
48 ProxiedJID.new(@to).unproxied
49 end
50
51 def oobs
52 @media.map(&OOB.method(:new))
53 end
54
55 def addresses
56 return nil if @recip.empty?
57
58 @addresses ||= Addresses.new(
59 [{ type: "to", jid: unproxied_to }] +
60 @recip.map { |r| { type: "to", uri: "sms:+#{r}", delivered: true } }
61 )
62 end
63
64 def to_stanza
65 Blather::Stanza::Message.new(
66 addresses ? unproxied_to.domain : unproxied_to,
67 @txt.empty? ? nil : @txt.join("\n\n")
68 ).tap do |m|
69 oobs.each { |oob| m << oob }
70 m << addresses if addresses
71 end
72 end
73end