URI: 
       Create a little more structure around the tools - warvox - VoIP based wardialing tool, forked from rapid7/warvox.
   DIR Log
   DIR Files
   DIR Refs
   DIR README
       ---
   DIR commit 60be9accc104b2d63ff2ab74bf586b4ce054a524
   DIR parent 18b3b7c1dbb56be8aed57018765ebad24655d98b
  HTML Author: HD Moore <hd_moore@rapid7.com>
       Date:   Fri, 13 Feb 2009 06:23:40 +0000
       
       Create a little more structure around the tools
       
       
       Diffstat:
         M bin/create_flow.rb                  |      91 ++-----------------------------
         A bin/create_flowdb.rb                |      40 +++++++++++++++++++++++++++++++
         M bin/create_samples.rb               |      15 ++++++---------
         M bin/create_sig.rb                   |      84 ++++---------------------------
         A data/test.db.bz2                    |       0 
         M lib/warvox.rb                       |       5 +++--
         A lib/warvox/audio.rb                 |       2 ++
         A lib/warvox/audio/error.rb           |       7 +++++++
         A lib/warvox/audio/raw.rb             |     129 +++++++++++++++++++++++++++++++
         A lib/warvox/db.rb                    |     113 +++++++++++++++++++++++++++++++
       
       10 files changed, 316 insertions(+), 170 deletions(-)
       ---
   DIR diff --git a/bin/create_flow.rb b/bin/create_flow.rb
       @@ -13,93 +13,12 @@ require 'warvox'
        
        #
        # Script
       -# 
       -
       -#
       -# Parameters
       -#
       -lo_lim = 100
       -lo_min = 5
       -lo_cnt = 0
       -hi_min = 5
       -hi_cnt = 0
       -
       -#
       -# Input
        #
       -cnt = 0
       -inp = ARGV.shift || exit
       -raw = File.read(inp)
       -data = raw.unpack("s*").map {|c| c.abs}
       -
       -#
       -# Granular hi/low state change list
       -#
       -fprint = []
       -state  = :lo
       -idx    = 0
       -buff   = []
       -
       -while (idx < data.length)
       -        case state
       -        when :lo
       -                while(idx < data.length and data[idx] <= lo_lim)
       -                        buff << data[idx]
       -                        idx += 1
       -                end
       -                
       -                # Ignore any sequence that is too small
       -                fprint << [:lo, buff.length, buff - [0]] if buff.length > lo_min
       -                state  = :hi
       -                buff   = []
       -                next
       -        when :hi
       -                while(idx < data.length and data[idx] > lo_lim)
       -                        buff << data[idx]
       -                        idx += 1
       -                end        
       -                
       -                # Ignore any sequence that is too small
       -                fprint << [:hi, buff.length, buff] if buff.length > hi_min
       -                state  = :lo
       -                buff   = []
       -                next
       -        end
       -end
       -
       -
       -#
       -# Merge similar blocks
       -#
       -final = []
       -prev  = fprint[0]
       -idx   = 1
       -
       -while(idx < fprint.length)
       -        
       -        if(fprint[idx][0] == prev[0])
       -                prev[1] += fprint[idx][1]
       -                prev[2] += fprint[idx][2]
       -        else
       -                final << prev
       -                prev  = fprint[idx]
       -        end
       -        
       -        idx += 1
       -end
       -final << prev
       -
       -
       -#
       -# Process results
       -# 
       -sig = "#{inp} "
        
       -final.each do |f|
       -        sum = 0
       -        f[2].each {|i| sum += i }
       -        avg = (sum == 0) ? 0 : sum / f[2].length
       -        sig << "#{f[0].to_s.upcase[0,1]},#{f[1]},#{avg} "
       +def usage
       +        $stderr.puts "#{$0} [audio.raw]"
       +        exit
        end
        
       -puts sig
       +raw = WarVOX::Audio::Raw.from_file(ARGV.shift || usage)
       +puts raw.to_flow
   DIR diff --git a/bin/create_flowdb.rb b/bin/create_flowdb.rb
       @@ -0,0 +1,40 @@
       +#!/usr/bin/env ruby
       +###################
       +
       +#
       +# Load the library path
       +# 
       +base = __FILE__
       +while File.symlink?(base)
       +        base = File.expand_path(File.readlink(base), File.dirname(base))
       +end
       +$:.unshift(File.join(File.expand_path(File.dirname(base)), '..', 'lib'))
       +require 'warvox'
       +
       +#
       +# Script
       +#
       +
       +def usage
       +        $stderr.puts "#{$0} [/path/to/audio/] [output.db]"
       +        exit
       +end
       +
       +src = ARGV.shift || usage
       +dst = ARGV.shift || usage
       +db  = File.new(dst, "w")
       +dir = Dir.new(src)
       +cnt = 0
       +
       +set = dir.entries.sort.grep(/\.raw$/)
       +set.each do |ent|
       +        next if not ent =~ /\.raw$/
       +        puts "[*] [#{sprintf("%.5d/%.5d", cnt+1, set.length)}] Processing #{ent}..."
       +        raw = WarVOX::Audio::Raw.from_file( File.join(src, ent) )
       +        db.write( ent.gsub('.raw', '') + " " + raw.to_flow + "\n" )
       +        cnt += 1
       +end
       +
       +db.close
       +
       +puts "[*] Wrote #{cnt} database entries into #{dst}"
   DIR diff --git a/bin/create_samples.rb b/bin/create_samples.rb
       @@ -15,17 +15,14 @@ require 'warvox'
        # Script
        # 
        
       -=begin
       -        8,000 samples per second
       -        160 samples per block of data
       -=end
       +def usage
       +        $stderr.puts "#{$0} [audio.raw]"
       +        exit
       +end
        
        cnt = 0
       -inp = ARGV.shift || exit
       -raw = File.read(inp)
       -raw.unpack("v*").each do |s|
       -        val = (s > 0x7fff) ? (0x10000 - s) * -1 : s
       +raw = WarVOX::Audio::Raw.from_file(ARGV.shift || usage)
       +raw.samples.each do |val|
                puts "#{cnt} #{val}"
                cnt += 1
        end
       -
   DIR diff --git a/bin/create_sig.rb b/bin/create_sig.rb
       @@ -15,81 +15,19 @@ require 'warvox'
        # Script
        # 
        
       -inp = ARGV.shift()
       -num1 = ARGV.shift() || exit
       -num2 = ARGV.shift() || exit
       -
       -min_len = 800
       -
       -
       -info1 = []
       -info2 = []
       -
       -fd = File.open(inp, "r")
       -fd.each_line do |line|
       -        data = line.strip.split(/\s+/)
       -        name = data.shift
       -        next if name !~ /#{num1}|#{num2}/
       -        
       -        # Bump the leading silence off
       -        data.shift if data[0] =~ /^L/
       -        
       -        data.each do |d|
       -                s,l,a = d.split(",")
       -                next if l.to_i < min_len
       -                plot = [s, l.to_i, a.to_i]
       -                name =~ /#{num1}/ ? info1 << plot : info2 << plot
       -        end
       -        
       -        break if (info1.length > 0 and info2.length > 0)
       -end
       -
       -if (not (info1.length > 0 and info2.length > 0))
       -        $stderr.puts "error: could not find both numbers in the database"
       +def usage
       +        $stderr.puts "#{$0} [warvox.db] [num1] [num2] <fuzz-factor> <db-threshold>"
                exit
        end
        
       +inp     = ARGV.shift() || usage
       +num1    = ARGV.shift() || usage
       +num2    = ARGV.shift() || usage
       +fuzz    = (ARGV.shift() || 100).to_i
       +thresh  = (ARGV.shift() || 800).to_i
        
       -min_sig = 2
       -fuzz    = 100
       -idx     = 0
       -fnd     = nil
       -r       = 0
       -
       -while(idx < info1.length-min_sig)
       -        sig  = info1[idx,info1.length]
       -        idx2 = 0
       -
       -        while (idx2 < info2.length)
       -                c = 0 
       -                0.upto(sig.length-1) do |si|
       -                        break if not info2[idx2+si]
       -                        break if not ( 
       -                                sig[si][0] == info2[idx2+si][0] and
       -                                info2[idx2 + si][1] > sig[si][1]-fuzz and
       -                                info2[idx2 + si][1] < sig[si][1]+fuzz
       -                        )
       -                        c += 1
       -                end
       -                
       -                if (c > r)
       -                        r = c
       -                        fnd = sig[0, r]
       -                end        
       -                idx2 += 1
       -        end
       -        idx += 1
       -end
       -
       -
       -
       -
       -version = "1.0"
       +info1 = []
       +info2 = []
        
       -if(fnd)
       -        sig = "V=#{version},F=#{fuzz},S1=#{num1},S2=#{num2},L=#{r} "
       -        fnd.each do |i|
       -                sig << i.join(",") + " "
       -        end
       -        puts sig
       -end
       +wdb   = WarVOX::DB.new(inp, thresh)
       +puts wdb.find_sig(num1, num2, { :fuzz => fuzz }).inspect
   DIR diff --git a/data/test.db.bz2 b/data/test.db.bz2
       Binary files differ.
   DIR diff --git a/lib/warvox.rb b/lib/warvox.rb
       @@ -3,6 +3,7 @@
        ##
        
        module WarVOX
       -
       -
        end
       +
       +require 'warvox/audio'
       +require 'warvox/db'
   DIR diff --git a/lib/warvox/audio.rb b/lib/warvox/audio.rb
       @@ -0,0 +1,2 @@
       +require 'warvox/audio/error'
       +require 'warvox/audio/raw'
   DIR diff --git a/lib/warvox/audio/error.rb b/lib/warvox/audio/error.rb
       @@ -0,0 +1,7 @@
       +module WarVOX
       +module Audio
       +class Error < ::RuntimeError
       +
       +end
       +end
       +end
   DIR diff --git a/lib/warvox/audio/raw.rb b/lib/warvox/audio/raw.rb
       @@ -0,0 +1,129 @@
       +module WarVOX
       +module Audio
       +class Raw
       +
       +        ##
       +        # RAW AUDIO - 8khz little-endian 16-bit signed
       +        ##
       +
       +        ##
       +        # Static methods
       +        ## 
       +        
       +        def self.from_str(str)
       +                self.class.new(str)
       +        end
       +        
       +        def self.from_file(path)
       +                if(not path)
       +                        raise Error, "No audio path specified"
       +                end
       +                
       +                if(path == "-")
       +                        return self.new($stdin.read)
       +                end
       +                
       +                if(not File.readable?(path))
       +                        raise Error, "The specified audio file does not exist"
       +                end
       +        
       +                self.new(File.read(path, File.size(path)))
       +        end
       +
       +        ##
       +        # Class methods
       +        ## 
       +        
       +        attr_accessor :samples
       +        
       +        def initialize(data)
       +                self.samples = data.unpack('v*').map do |s| 
       +                        (s > 0x7fff) ? (0x10000 - s) * -1 : s
       +                end
       +        end
       +        
       +        def to_flow(opts={})
       +
       +                lo_lim = (opts[:lo_lim] || 100).to_i
       +                lo_min = (opts[:lo_min] || 5).to_i
       +                hi_min = (opts[:hi_min] || 5).to_i
       +                lo_cnt = 0                
       +                hi_cnt = 0
       +
       +                data = self.samples.map {|c| c.abs}
       +
       +                #
       +                # Granular hi/low state change list
       +                #
       +                fprint = []
       +                state  = :lo
       +                idx    = 0
       +                buff   = []
       +
       +                while (idx < data.length)
       +                        case state
       +                        when :lo
       +                                while(idx < data.length and data[idx] <= lo_lim)
       +                                        buff << data[idx]
       +                                        idx += 1
       +                                end
       +
       +                                # Ignore any sequence that is too small
       +                                fprint << [:lo, buff.length, buff - [0]] if buff.length > lo_min
       +                                state  = :hi
       +                                buff   = []
       +                                next
       +                        when :hi
       +                                while(idx < data.length and data[idx] > lo_lim)
       +                                        buff << data[idx]
       +                                        idx += 1
       +                                end        
       +
       +                                # Ignore any sequence that is too small
       +                                fprint << [:hi, buff.length, buff] if buff.length > hi_min
       +                                state  = :lo
       +                                buff   = []
       +                                next
       +                        end
       +                end
       +
       +                #
       +                # Merge similar blocks
       +                #
       +                final = []
       +                prev  = fprint[0]
       +                idx   = 1
       +
       +                while(idx < fprint.length)
       +
       +                        if(fprint[idx][0] == prev[0])
       +                                prev[1] += fprint[idx][1]
       +                                prev[2] += fprint[idx][2]
       +                        else
       +                                final << prev
       +                                prev  = fprint[idx]
       +                        end
       +
       +                        idx += 1
       +                end
       +                final << prev
       +
       +                #
       +                # Process results
       +                # 
       +                sig = ""
       +
       +                final.each do |f|
       +                        sum = 0
       +                        f[2].each {|i| sum += i }
       +                        avg = (sum == 0) ? 0 : sum / f[2].length
       +                        sig << "#{f[0].to_s.upcase[0,1]},#{f[1]},#{avg} "
       +                end
       +                
       +                # Return the results
       +                return sig
       +        end
       +
       +end
       +end
       +end
   DIR diff --git a/lib/warvox/db.rb b/lib/warvox/db.rb
       @@ -0,0 +1,113 @@
       +module WarVOX
       +class DB
       +                
       +        VERSION = '1.0'
       +        
       +        class Error < ::RuntimeError
       +        end
       +        
       +        attr_accessor :path, :nums, :threshold, :version
       +
       +        def initialize(path, threshold=800)
       +                self.path      = path
       +                self.threshold = threshold
       +                self.nums      = {}
       +                self.version   = VERSION
       +                
       +                File.open(path, "r") do |fd|
       +                        fd.each_line do |line|
       +                                line.strip!
       +                                next if line.empty?
       +                                bits = line.split(/\s+/)
       +                                name = bits.shift
       +
       +                                self.nums[name] = []
       +                                bits.each do |d|
       +                                        s,l,a = d.split(',')
       +                                        next if l.to_i < self.threshold
       +                                        self.nums[name] << [s, l.to_i, a.to_i]
       +                                end
       +                        end
       +                end
       +        end
       +        
       +        def [](num)
       +                self.nums[num]
       +        end
       +        
       +        def []=(num,val)
       +                self.nums[num] = val
       +        end
       +        
       +        #
       +        # Utility methods
       +        #
       +        
       +        def find_sig(num1, num2, opts={})
       +                
       +                fuzz  = opts[:fuzz] || 100
       +                info1 = self[num1]
       +                info2 = self[num2]
       +                
       +                # Make sure both samples exist in the database
       +                if ( not (info1 and info2 and not (info1.empty? or info2.empty?) ) )
       +                        raise Error, "The database must contain both numbers"
       +                end
       +                
       +                min_sig = 2
       +                idx     = 0
       +                fnd     = nil
       +                mat     = nil
       +                r       = 0
       +
       +                while(idx < info1.length-min_sig)
       +                        sig  = info1[idx,info1.length]
       +                        idx2 = 0
       +
       +                        while (idx2 < info2.length)
       +                                c = 0 
       +                                0.upto(sig.length-1) do |si|
       +                                        break if not info2[idx2+si]
       +                                        break if not ( 
       +                                                sig[si][0] == info2[idx2+si][0] and
       +                                                info2[idx2 + si][1] > sig[si][1]-fuzz and
       +                                                info2[idx2 + si][1] < sig[si][1]+fuzz
       +                                        )
       +                                        c += 1
       +                                end
       +
       +                                if (c > r)
       +                                        r = c
       +                                        fnd = sig[0, r]
       +                                        mat = info2[idx2, r]
       +                                end        
       +                                idx2 += 1
       +                        end
       +                        idx += 1
       +                end
       +                
       +                return nil if not fnd
       +                
       +                sig = []
       +                fnd.each_index do |i|        
       +                        sig << 
       +                        [
       +                                (fnd[i][0]),
       +                                (fnd[i][1] + mat[i][1] / 2.0).to_i,
       +                                (fnd[i][2] + mat[i][2] / 2.0).to_i
       +                        ]
       +                end
       +                
       +                {
       +                        :version    => self.version,
       +                        :fuzz       => fuzz,
       +                        :threshold  => self.threshold,
       +                        :num1       => num1,
       +                        :num2       => num2,
       +                        :len        => r,
       +                        :sig        => sig
       +                }
       +        end
       +
       +end
       +end