# -*- coding: utf-8 -*-

import sys
import subprocess
import time
import ldap
if '/usr/scripts' not in sys.path:
    sys.path.append('/usr/scripts')

import lc_ldap.shortcuts
import lc_ldap.objets
from iptools import AddrInNet, NetSubnets, IpSubnet
def _get_ldap_connection():
    return lc_ldap.shortcuts.lc_ldap_readonly(user=u'root')
QUERY = _get_ldap_connection()

cache={}
cache_time=60.0
cleanup_time=3600.0
next_cleanup=time.time() + cleanup_time

def cleanup(now):
    global cleanup_time, cache, cache_time, next_cleanup
    if next_cleanup < now:
        for ip in cache.keys(): 
            if cache[ip]['time']<(now - cache_time):
                del cache[ip]
        next_cleanup=time.time() + cleanup_time
        


deco={
    'non_inscrit': 'ERR_CUSTOM_NON_INSCRIT.html',
    'inscrit': 'ERR_CUSTOM_INSCRIT.html',

    'ex_crous': 'ERR_CUSTOM_EX_CROUS.html',
    'ex_crous_enable': 'ERR_CUSTOM_EX_CROUS_ENABLE.html',
    'confirmation': 'ERR_RECONNECT_CONFIRM.html',
    
    'age': 'ERR_CUSTOM_AGE.html',
    'ago': 'ERR_CUSTOM_AGO.html',
    
    'autodisc_p2p': 'ERR_CUSTOM_BL_AUTO_P2P.html',
    'p2p':'ERR_CUSTOM_BL_P2P.html',
    'autodisc_upload':'ERR_CUSTOM_BL_AUTO_UPLOAD.html',
    'upload':'ERR_CUSTOM_BL_UPLOAD.html',
    'chambre_invalide': 'ERR_CUSTOM_BL_CHAMBRE.html',
    'carte_etudiant':'ERR_CUSTOM_BL_NO_CARTE.html',
    'mail_invalide':'ERR_CUSTOM_BL_NO_MAIL.html',
    'mail_invalide_inscription':'ERR_DISABLED_CUSTOM_BL_NO_MAIL.html',
    'warez':'ERR_CUSTOM_BL_WAREZ.html',
    'bloq':'ERR_CUSTOM_BLOQ.html',
    
    'nouvelle_annee':'ERR_CUSTOM_NOUVELLE_ANNEE.html',
    'paiement':'ERR_CUSTOM_NOUVELLE_ANNEE.html',

    # en cas de sursis, la page donne une url pour continuer à naviguer
    # sur Internet
    'paiement_sursis': 'ERR_CUSTOM_READHESION.html',
    'proxy_local':'ERR_CUSTOM_PROXY_LOCAL.html',
    
    'virus':'ERR_CUSTOM_BL_VIRUS.html',
    'ipv6_ra':'ERR_CUSTOM_RA.html',
    'autodisc_virus':'ERR_CUSTOM_BL_AUTO_VIRUS.html',
}
    
for bl in deco.keys():
     deco[bl]="/crans-deco/%s" % deco[bl]
    
blacklist_key = [
    'non_inscrit',
    'age','ago',
    'virus','autodisc_virus','ipv6_ra',
    'p2p','autodisc_p2p','upload','autodisc_uplaod','warez',
    'carte_etudiant','chambre_invalide','mail_invalide',
    'bloq',
    'nouvelle_annee','proxy_local', 'paiement',
    'inscrit'
    ]

def mac_from_ip(ip):
    if ip == "10.51.0.10": return u"02:72:6f:75:74:07"
    cmd = '/usr/sbin/arp -na %s' % ip
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
    output, errors = p.communicate()
    if output is not None : 
        mac_addr = output.split()[3]
        return mac_addr.strip()
    else:
        return None

def enable_access(ip):
    """Lance la commande idoine pour autoriser l'adresse IP"""
    cmd = ['/usr/sbin/ipset', 'add', 'CONFIRMATION', ip]
    p = subprocess.Popen(['sudo', '-n'] + cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)
    out, err = p.communicate()
    if out or err:
        print "ipset_allow:"
        print out
        print "---"
        print err
        return False
    return True

def get(str):
    global  QUERY
    try:
        return QUERY.search(str)
    except ldap.SERVER_DOWN:
        QUERY = _get_ldap_connection()
        return QUERY.search(str)
        
def get_machine_by_mac(ip):
        mac_addr=mac_from_ip(ip)
        machines = get(u'macAddress=%s' % mac_addr)
        #if machines and isinstance(machines[0], lc_ldap.objets.machineWifi):
        #    if not 'ipHostNumber' in machines[0].attrs.keys():
        #        machine = QUERY.search(u'macAddress=%s' % mac_addr, mode='rw')[0]
        #        machine.set_ipv4()
        return machines
        

def get_machine_by_ip(ip):
    return get(u'ipHostNumber=%s' % ip)
    
def get_page(ip, by_mac=False, accueil=False):
    try:
        if by_mac:
            machines=get_machine_by_mac(ip)
        else:
            machines=get_machine_by_ip(ip)
        adherent=machines[0].proprio()
    except IndexError:
        return deco['non_inscrit']
    blacklist=[bl.value['type'] for bl in adherent.blacklist_actif()]
    for machine in machines:
        blacklist.extend([bl.value['type'] for bl in machine.blacklist_actif()])
    for bl in blacklist_key:
        if bl in blacklist:
            return deco[bl]
    if accueil:
        return deco['inscrit']
    return None

def special(action, ip, environ, start_response):
    mac = mac_from_ip(ip)
    url = "https://intranet.crans.org/machines/add/"
    if 'wifi' in action:
        url += 'wifi/'
    else:
        url += 'fil/'
    if mac is not None:
        url += mac + '/'
    start_response("302 OK", [
        ("Content-Type", "text/html"),
        ("Cache-Control", "no-cache, must-revalidate"),
        ("Expires", "Thu, 01 Jan 1970 00:00:00 GMT"),
        ("Location", url),
        ("Content-Length", 0)
    ])
    return ""
    
    
def app(environ, start_response):
    if 'HTTP_K_REAL_IP' in environ.keys():
        ip=environ['HTTP_K_REAL_IP']
    else:
        ip=environ['HTTP_REAL_IP']
    now=time.time()
    cleanup(now)
    if environ.get('RAW_URI', '').startswith('/special'):
        return special(environ.get('RAW_URI','')[9:], ip, environ, start_response)
    if AddrInNet(ip, '10.231.137.0/24'):
        if environ.get('RAW_URI', '').startswith('/enable'):
            enable_access(ip)
            data = deco['ex_crous_enable']
        else:
            data = deco['ex_crous']
    elif environ.get('RAW_URI', '').startswith('/enable'):
        enable_access(ip)
        data = deco['confirmation']
    elif ip in cache.keys() and cache[ip]['time']>(now - cache_time):
        data=cache[ip]['page']
    else:
        if AddrInNet(ip,'10.51.0.0/16'):
            data=get_page(ip,True,True)
        elif AddrInNet(ip,'10.52.0.0/16'):
            page=get_page(ip,True)
            if page:
                data=page
            else:
                data=deco['autodisc_virus']
        elif AddrInNet(ip,'138.231.136.0/21') or AddrInNet(ip,'138.231.144.0/21') or AddrInNet(ip,'10.2.9.0/24'):
            page=get_page(ip)
            if page:
                data=page
            else:
                data="/crans-proxy/"
        else:
            data = deco['non_inscrit']
        cache[ip]={'time':time.time(),'page':data}
    start_response("200 OK", [
        ("Content-Type", "text/html"),
        ("Cache-Control", "no-cache, must-revalidate"),
        ("Expires", "Thu, 01 Jan 1970 00:00:00 GMT"),
        ("X-Accel-Redirect", data),
        ("Content-Length", 0)
    ])

    return ""
