# -*- coding: binary -*-
require 'rexml/document'

module Rex
module Parser


class IP360XMLStreamParser

  attr_accessor :on_found_host

  def initialize(&block)
    reset_state
    on_found_host = block if block
  end

  def reset_state
    @host = {'hname' => nil, 'hid' => nil, 'addr' => nil, 'mac' => nil, 'os' => nil,
      'vulns' => ['vuln' => {'vulnid' => nil, 'port' => nil, 'proto' => nil} ],
      'apps' => ['app' => {'appid' => nil, 'svcid' => nil, 'port' => nil, 'proto' => nil } ],
    }
    @state = :generic_state
  end

  def tag_start(name, attributes)
    case name
    when "host"
      @host['hid'] = attributes['persistent_id']
    when "ip"
      @state = :is_ip
    when "dnsName"
      @state = :is_fqdn
    when "macAddress"
      @state = :is_mac
    when "os"
      @host['os'] = attributes['id']
    when "vulnerability"
      @x = Hash.new
      @x['vulnid'] = attributes['id']
    when "port"
      @state = :is_port
    when "protocol"
      @state = :is_proto
    when "application"
      @y = Hash.new
      @y['appid'] = attributes['application_id']
      @y['svcid'] = attributes['svcid']
      @y['port'] = attributes['port']
      @y['proto'] = attributes['protocol']
      @host['apps'].push @y
    end
  end

  def text(str)
    case @state
    when :is_fqdn
      @host['hname'] = str
    when :is_ip
      @host['addr'] = str
    when :is_mac
      @host['mac'] = str
    when :is_port
      @x['port'] = str
    when :is_proto
      @x['proto'] = str
    end
  end

  def tag_end(name)
    case name
    when "host"
      on_found_host.call(@host) if on_found_host
      reset_state
    when "vulnerability"
      @host['vulns'].push @x
    end
    @state = :generic_state
  end

  def cdata(d)
    #do nothing
  end

  # We don't need these methods, but they're necessary to keep REXML happy
  #
  def xmldecl(version, encoding, standalone) # :nodoc:
  end
  def comment(str) # :nodoc:
  end
  def instruction(name, instruction) # :nodoc:
  end
  def attlist # :nodoc:
  end
end

end
end
