#! /usr/bin/env python
# -*- coding: utf-8 -*-

import time, commands
from gen_confs import gen_config, ERREUR, OK, anim

import sys, os, shutil
sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, BorneWifi

class conf_wifi_ng(gen_config) :
    """ Génération de la configuration de isakmpd dans ISAKMPD_CONF
        Le fichier est constitué en 5 parties :
            1) Configuration générale insérée telle quelle
            2) Phase 1 : une ligne par host suivant template
            3) Phase 2 : une entrée par machine
            4) Bloc par machine suivant template
            5) Ajout de net_crans

        Configuration des bornes
    """
    ######################################PARTIE DE CONFIGURATION
        
    # Fichiers à écrire
    # Répertoire d'écriture des fichiers de zone
    ISAKMPD_CONF='/etc/isakmpd/isakmpd.conf'
    # Correspondance MAC/IP
    MACIP='/etc/wifi/wifi-update-ng/common/etc/macip'

    restart_cmd = 'kill -HUP $(cat /var/run/isakmpd.pid 2>/dev/null )'
    
    ######################################FIN PARTIE DE CONFIGURATION
    
    def __init__(self, bornes=None) :
        self.db = crans_ldap()
        self._bornes = bornes

    def lockname(self):
        # On change le nom du lock pour avoir un nom unique pour tout ce qui
        # concerne le wifi
        # return ".".join(str(self.__class__).split(".")[0:-1])
        return "gen_confs.wifi"

    def __str__(self) :
        return 'wifi'
    
    def _gen(self):
        self.anim=anim('\r\tRecherche base LDAP')
        clients = self.db.search('host=*.wifi.crans.org&paiement=ok')['machineWifi']
        bornes = self.db.search('host=*.wifi.crans.org&canal=*')['borneWifi']
        
        print OK
        if not self._bornes:
            self.gen_isakmpd(clients)
            self.gen_macip(clients, bornes)
        self.gen_bornes(bornes)
        self.anim=anim('\tfin reconfigurations')

    def gen_bornes(self, bornes):
        """Génération de la configuration des bornes"""

        TARGET = "/var/www/wifi-update"
        WORK = "%s/work" % TARGET
        ROOT = "/etc/wifi/wifi-update-ng"
        COMMON = "%s/common" % ROOT
        DEFAULT = "%s/default" % ROOT
        for borne in bornes:
            if self._bornes and borne.nom().split(".")[0] not in self._bornes:
                continue
            self.anim=anim('\treconfiguration de %s' % borne.nom())
            # Il s'agit de faire l'union du répertoire common et du
            # répertoire propre (s'il existe) ou alors du répertoire default
            # On supprime le répertoire de travail
            if os.path.isdir(WORK):
                shutil.rmtree(WORK)
            # On copie COMMON
            shutil.copytree(COMMON, WORK)
            # Est-ce qu'un répertoire spécifique existe ?
            top = os.path.join(ROOT, borne.nom())
            if not os.path.isdir(top):
                top = DEFAULT
            # On en copie aussi le contenu
            for root, dirs, files in os.walk(top, topdown=True):
                # On créé les répertoires
                for name in dirs:
                    try:
                        os.mkdir(os.path.join("%s%s" % (WORK, root[len(top):]),
                                              name))
                    except OSError, e:
                        pass
                # Et on copie
                for name in files:
                    shutil.copy(os.path.join(root, name),
                                os.path.join("%s%s" % (WORK, root[len(top):]),
                                             name))
            # On créé/complète le fichier /etc/nvram.updates
            if isinstance(borne, BorneWifi) and borne.nom() != "non-configure.wifi.crans.org":
                fd = file(os.path.join(WORK, "etc", "nvram.updates"), "a")
                data = { 'HOST': borne.nom().split('.')[0],
                         'IP': borne.ip(),
                         'CANAL': borne.canal(raw=True),
                         'PUISSANCE': abs(int(borne.puissance() or 0)),
                         'ON': ((int(borne.puissance() or 0) > 0) and 1 or 0),
                         'HOTSPOT': borne.hotspot() and 1 or 0,
                         }
                fd.write("""
variables="${variables} lan_ipaddr wan_hostname crans_channels txpower wl0_radio crans_hotspot"
NVRAM_lan_ipaddr=%(IP)s
NVRAM_wan_hostname=%(HOST)s
NVRAM_crans_channels=%(CANAL)s
NVRAM_txpower=%(PUISSANCE)d
NVRAM_wl0_radio=%(ON)d
NVRAM_crans_hotspot=%(HOTSPOT)d

""" % data)
                # On complète par les variables de la NVRAM
                for info in borne.nvram():
                    fd.write('variables="${variables} %s"\n' % info.split("=")[0])
                    fd.write("NVRAM_%s\n" % info)
                fd.close()

            # On fait du menage
            os.system("find %s -name CVS -type d -exec rm -rf {} \\; 2> /dev/null" % WORK)
            os.system("find %s -name '*~' -type f -exec rm -f {} \\;" % WORK)
            # Ensuite, on créé le tar
            os.system("tar zcf %s/%s.tmp.tar.gz -C %s ." % (TARGET, borne.nom(), WORK))
            # Et on le renomme (on espère que c'est atomique)
            os.rename("%s/%s.tmp.tar.gz" % (TARGET, borne.nom()),
                      "%s/%s.tar.gz" % (TARGET, borne.nom()))
            print OK

    def gen_macip(self, clients, bornes):
        """Génération de la correspondance MAC/IP"""
        self.anim=anim('\r\tFichier MAC/IP',len(clients + bornes))
        fd = file(self.MACIP, "w")
        for machine in clients + bornes:
            self.anim.cycle()
            if 'bloq' in machine.blacklist_actif() : continue
            fd.write("%s %s\n" % (machine.mac(), machine.ip()))
        self.anim.reinit()
        print OK

    def gen_isakmpd(self, clients):
        """Génération du fichier pour isakmpd"""

        # Config générale de ISAKMPd
        general="""
[General]
Listen-on=              138.231.148.1
Retransmits=            5
Exchange-max-time=      40
Logverbose=             1
Loglevel=               A=90
Check-interval=         60
Default-phase-1-lifetime=       1200,90:86400
Default-phase-2-lifetime=       1800,120:86400

[Default-main-mode]
DOI=                    IPSEC
EXCHANGE_TYPE=          ID_PROT
Transforms=             3DES-SHA,3DES-MD5

[Default-quick-mode]

DOI=                    IPSEC
EXCHANGE_TYPE=          QUICK_MODE
Suites=                 QM-ESP-AES-SHA-SUITE, QM-ESP-AES-MD5-SUITE, \\
                        QM-ESP-BLF-SHA-SUITE, QM-ESP-BLF-MD5-SUITE, \\
                        QM-ESP-3DES-SHA-SUITE, QM-ESP-3DES-MD5-SUITE, \\
                        QM-ESP-AES-SHA-PFS-SUITE, QM-ESP-AES-MD5-PFS-SUITE, \\
                        QM-ESP-BLF-SHA-PFS-SUITE, QM-ESP-BLF-MD5-PFS-SUITE, \\
                        QM-ESP-3DES-SHA-PFS-SUITE, QM-ESP-3DES-MD5-PFS-SUITE

"""

        # Phase 1
        phase1_debut="[Phase 1]\n"
        phase1_template="%(IP)s= ISAKMP-peer-%(HOST)s\n"

        # Phase 2
        phase2_debut="[Phase 2]\nPassive-connections= "
        phase2_template="IPsec-%(HOST)s"
        phase2_sep=', \\\n  '

        #Lignes necessaires pour chaque machine
        host_template="""
[ISAKMP-peer-%(HOST)s]
Phase= 1
Transport= udp
Address= %(IP)s
Configuration= Default-main-mode
Authentication=%(KEY)s

[IPsec-%(HOST)s]
Phase= 2
ISAKMP-peer= ISAKMP-peer-%(HOST)s
Configuration= Default-quick-mode
Local-ID= Net-crans
Remote-ID= Net-%(HOST)s

[Net-%(HOST)s]
ID-type= IPV4_ADDR
Address= %(IP)s
"""
        # Dernière partie du fichier
        net_crans="""
[Net-crans]
ID-type=                IPV4_ADDR_SUBNET
Network=                0.0.0.0
Netmask=                0.0.0.0
"""

        phase1 = phase1_debut
        phase2 = phase2_debut
        blocs=''
        self.anim=anim('\r\tFichier isakmpd.conf',len(clients))
        for machine in clients :
            self.anim.cycle()
            if 'bloq' in machine.blacklist_actif() : continue
            data = { 'HOST' : machine.nom().split('.')[0] ,
                     'IP'   : machine.ip() ,
                     'KEY'  : machine.ipsec()}

            # Phase 1
            phase1 += phase1_template % data
            
            # Phase 2
            if blocs != '' :
                # Ce n'est pas la première machine, il faut insérer un séparateur
                phase2 += phase2_sep
            phase2 += phase2_template % data
            
            # Blocs machine
            blocs += host_template % data

        # Ecriture du fichier isakmpd.conf
        fd = self._open_conf(self.ISAKMPD_CONF,'#')
        fd.write(general)
        fd.write(phase1)
        fd.write('\n')
        fd.write(phase2)
        fd.write('\n')
        fd.write(blocs)
        fd.write(net_crans)
        fd.close()
        self.anim.reinit()
        print OK
