#-- # Copyright (c) 2007-2010 by Mike Mondragon (mikemondragon@gmail.com) # # Please see the LICENSE file for licensing information. #++ require 'net/http' require 'rubygems' require 'nokogiri' require 'cgi' module MMS2R class Media ## # Sprint version of MMS2R::Media # # Sprint is an annoying carrier because they don't actually transmit user # generated content (like images or videos) directly in the MMS message. # Instead, they hijack the media that is sent from the cellular subscriber # and place that content on a content server. In place of the media # the recipient receives a HTML message with unsolicited Sprint # advertising and links back to their content server. The recipient has # to click through Sprint more pages to view the content. # # The default subject on these messages from the # carrier is "You have new Picture Mail!" class Sprint < MMS2R::Media ## # Override process() because Sprint doesn't attach media (images, video, # etc.) to its MMS. Media such as images and videos are hosted on a # Sprint content server. MMS2R::Media::Sprint has to pick apart an # HTML attachment to find the URL to the media on Sprint's content # server and download each piece of content. Any text message part of # the MMS if it exists is embedded in the html. def process unless @was_processed log("#{self.class} processing", :info) #sprint MMS are multipart parts = @mail.parts #find the payload html doc = nil parts.each do |p| next unless p.part_type? == 'text/html' d = Nokogiri(p.body.decoded) title = d.at('title').inner_html if title =~ /You have new Picture Mail!/ doc = d @is_video = (p.body.decoded =~ /type="VIDEO">/m ? true : false) end end return if doc.nil? # it was a dud @is_video ||= false # break it down sprint_phone_number(doc) sprint_process_text(doc) sprint_process_media(doc) @was_processed = true end # when process acts upon a block if block_given? media.each do |k, v| yield(k, v) end end end private ## # Digs out where Sprint hides the phone number def sprint_phone_number(doc) c = doc.search("/html/head/comment()").last t = c.content.gsub(/\s+/m," ").strip #@number returned in parent's #number @number = / name="MDN">(\d+)</.match(t)[1] end ## # Pulls out the user text form the MMS and adds the text to media hash def sprint_process_text(doc) # there is at least one
 with MMS text if text has been included by
        # the user.  (note) we'll have to verify that if they attach multiple texts
        # to the MMS then Sprint stacks it up in multiple 
's.  The only 
        # tag in the document is for text from the user.
        doc.search("/html/body//pre").each do |pre|
          type = 'text/plain'
          text = pre.inner_html.strip
          next if text.empty?
          type, text = transform_text(type, text)
          type, file = sprint_write_file(type, text.strip)
          add_file(type, file) unless type.nil? || file.nil?
        end
      end

      ##
      # Fetch all the media that is referred to in the doc

      def sprint_process_media(doc)
        srcs = Array.new
        # collect all the images in the document, even though
        # they are  tag some might actually refer to video.
        # To know the link refers to vide one must look at the
        # content type on the http GET response.
        imgs = doc.search("/html/body//img")
        imgs.each do |i|
          src = i.attributes['src']
          next unless src
          src = src.text
          # we don't want to double fetch content and we only
          # want to fetch media from the content server, you get
          # a clue about that as there is a RECIPIENT in the URI path
          # of real content
          next unless /mmps\/RECIPIENT\//.match(src)
          next if srcs.detect{|s| s.eql?(src)}
          srcs << src
        end

        #we've got the payload now, go fetch them
        cnt = 0
        srcs.each do |src|
          begin

            url = URI.parse(CGI.unescapeHTML(src))
            unless @is_video
              query={}
              url.query.split('&').each{|a| p=a.split('='); query[p[0]] = p[1]}
              query.delete_if{|k, v| k == 'limitsize' or k == 'squareoutput' }
              url.query = query.map{|k,v| "#{k}=#{v}"}.join("&")
            end
            # sprint is a ghetto, they expect to see & for video request
            url.query = url.query.gsub(/&/, "&") if @is_video

            res = Net::HTTP.get_response(url)
          rescue StandardError => err
            log("#{self.class} processing error, #{$!}", :error)
            next
          end

          # if the Sprint content server uses response code 500 when the content is purged
          # the content type will text/html and the body will be the message
          if res.content_type == 'text/html' && res.code == "500"
            log("Sprint content server returned response code 500", :error)
            next
          end

          # setup the file path and file
          base = /\/RECIPIENT\/([^\/]+)\//.match(src)[1]
          type = res.content_type
          file_name = "#{base}-#{cnt}.#{self.class.default_ext(type)}"
          file = File.join(msg_tmp_dir(),File.basename(file_name))

          # write it and add it to the media hash
          type, file = sprint_write_file(type, res.body, file)
          add_file(type, file) unless type.nil? || file.nil?
          cnt = cnt + 1
        end

      end

      ##
      # Creates a temporary file based on the type

      def sprint_temp_file(type)
        file_name = "#{Time.now.to_f}.#{self.class.default_ext(type)}"
        File.join(msg_tmp_dir(),File.basename(file_name))
      end

      ##
      # Writes the content to a file and returns the type, file as a tuple.

      def sprint_write_file(type, content, file = nil)
        file = sprint_temp_file(type) if file.nil?
        log("#{self.class} writing file #{file}", :info)
        File.open(file,'w'){ |f| f.write(content) }
        return type, file
      end

    end
  end
end