#!/usr/bin/env python
#
# Reading NS1 files - http://www.stumbler.net/ns1files.html
#
# Rick van der Zwet <info@rickvanderzwet.nl>
#
import sys
import datetime

from struct import *

def parse_netstumbler(filename):
  fh = open(filename,'rb')
  
  def get_int32(size=1):
    v = unpack('<' + 'i'*size,fh.read(4*size))
    return v[0] if size == 1 else v
  
  def get_uint32(size=1):
    v = unpack('<' + 'I'*size,fh.read(4*size))
    return v[0] if size == 1 else v
  
  def get_uint64(size=1):
    v = unpack('<' + 'Q'*size,fh.read(8*size))
    return v[0] if size == 1 else v
  
  def get_uint8(size=1):
    v = unpack('<' + 'B'*size,fh.read(1*size))
    return v[0] if size == 1 else v
  
  def get_filetime():
    _FILETIME_null_date = datetime.datetime(1601, 1, 1, 0, 0, 0)
    ns = unpack('<Q',fh.read(8))[0] * 10
    sec = ns / 10**8
    d = datetime.timedelta(seconds=sec)
    return _FILETIME_null_date + d
  
  def get_char(size):
    return fh.read(size)
  
  def get_double(size=1):
    v = unpack('<' + 'd'*size,fh.read(8*size))
    return v[0] if size == 1 else v
  
  data = {}
  
  data["dwSignature"] = get_char(4)
  data["dwFileVerunpack"] = get_uint32()
  ApCount = get_uint32()
  data["ApCount"] = ApCount
  
  data["aps"] = []
  for a in range(0,ApCount):
    ap = {}
    SSIDLength = get_uint8()
    ap["SSIDLength"] = SSIDLength
    ap["SSID"] = get_char(SSIDLength)
    ap["BSSID"] = map(hex,unpack('BBBBBB',fh.read(6)))
    ap["MaxSignal"] = get_int32()
    ap["MinNoise"] = get_int32()
    ap["MaxSNR"] = get_int32()
    ap["Flags"] =  get_uint32()
    ap["BeaconInterval"] = get_uint32()
    ap["FirstSeen"] = get_filetime()
    ap["LastSeen"] = get_filetime()
    ap["BestLat"] = get_double()
    ap["BestLong"] = get_double()
    DataCount = get_uint32()
    ap["DataCount"] = DataCount
    ap["measurement"] = []
    for c in range(0,DataCount):
      ms = {}
      ms["Time"] = get_filetime()
      ms["Signal"] = get_int32()
      ms["Noice"] = get_int32()
      LocationSource = get_int32()
      ms["Location Source"] = LocationSource
      if LocationSource == 1:
        ms["Latitude"] = get_double()
        ms["Longitude"] = get_double()
        ms["Altitude"] = get_double()
        ms["NumStats"] = get_uint32()
        ms["Speed"] = get_double()
        ms["Track"] = get_double()
        ms["MagVariation"] = get_double()
        ms["Hdop"] = get_double()
      ap["measurement"].append(ms)
    NameLength = get_uint8()
    ap["NameLength"] = NameLength
    ap["Name"] = get_char(NameLength)
    ap["Channels"] = get_uint64()
    ap["LastChannel"] = get_uint32()
    ap["IPAddress"] = get_uint32()
    ap["MinSignal"] = get_int32()
    ap["MaxSignal"] = get_int32()
    ap["DataRate"] = get_uint32()
    ap["IPSubnet"] = get_uint32()
    ap["IPMask"] = get_uint32()
    ap["ApFlags"] = get_uint32()
    IELength = get_uint32()
    ap["IELength"] = IELength
    ap["InformationElements"] = get_uint8(IELength)
    data["aps"].append(ap)
  return data

print parse_netstumbler(sys.argv[1])
