#!/usr/bin/env python2.7
import os
import sys
import threading
import time
import re
import BaseHTTPServer
import signal
import ConfigParser

class Config(object):
    @classmethod
    def load(cls):
        config = ConfigParser.RawConfigParser(allow_no_value=True)
        config.optionxform = str
        config.read('/usr/local/etc/stalker.conf')
        cls.macs = config.items('MAC')
        cls.routers = map(lambda x: x[0], config.items('Router'))

cmd = 'ssh -o PasswordAuthentication=no root@%s iwinfo wlan0 assoclist'

active_station_list = []

def http_server():
    class handler(BaseHTTPServer.BaseHTTPRequestHandler):
        def log_message(self, format, *args):
            return

        def do_GET(s):
            if s.path == '/reload_config':
                return s.reload_config()
            s.send_response(200)
            s.send_header("Content-type", "text/html")
            s.end_headers()

            response = "<!DOCTYPE html><html><head></head><body>"

            for name, mac in Config.macs:
                if mac is None or len(mac) == 0:
                    response += "%s is ?<br>" % name
                elif mac.lower() in active_station_list:
                    response += "%s is <font color='#3fab58'>here</font><br>" % name
                else:
                    response += "%s is <font color='#d10000'>out</font><br>" % name

            response += "<br><a href='/reload_config'>Reload configuration</a>"
            response += "</body></html>"

            s.wfile.write(response)

        def reload_config(s):
            Config.load()
            s.send_response(302)
            s.send_header('Location', '/')
            s.end_headers()

    print "starting http server!"

    try:
        httpd = BaseHTTPServer.HTTPServer(("0.0.0.0", 1337), handler)
        httpd.serve_forever()
    except KeyboardInterrupt:
        httpd.server_close()
        os.kill(os.getpid(), 9)

def station_monitor():
    global active_station_list

    print "station monitoring thread started!"

    while True:
        stations = ""
        for router in Config.routers:
            stations += os.popen(cmd % router).read()

        macs = re.findall(":".join(["[0-9A-F]+"]*6), stations)

        active_station_list = [m.lower() for m in macs]

        #print "active_station_list updated = %s" % active_station_list

        time.sleep(10)

def main():
    print "stalker v0.2"

    signal.signal(signal.SIGTERM, lambda signum, frame: os.kill(os.getpid(), 9))
    open('/var/run/stalker.pid', 'wb').write('%d\n' % os.getpid())

    Config.load()
    signal.signal(signal.SIGHUP, lambda signum, frame: Config.load())

    smt = threading.Thread(target=station_monitor)
    smt.start()

    http_server()

if __name__ == "__main__":
    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)
    except OSError, e:
        print >>sys.stderr, 'fork #1 failed: %d (%s)' % (e.errno, e.strerror)
        sys.exit(1)

    os.chdir('/')
    os.setsid()
    os.umask(0)

    try:
        pid = os.fork()
        if pid > 0:
            sys.exit(0)
    except OSError, e:
        print >>sys.stderr, 'fork #2 failed: %d (%s)' % (e.errno, e.strerror)
        sys.exit(1)

    main()
