#!/bin/bash /usr/scripts/python.sh
# -*- coding: utf-8 -*-
import os
import sys
import time
import socket
import syslog
import thread
from threading import Thread
import gestion.secrets_new as secrets
from sip.asterisk import AGI, Manager, NullRecv


# Pour quitter, j'utilise os._exit(0) qui quitte un peut violement (comme un kill -9), sinon les threads ne se termine pas.
# En vrai, il faudrait appeler os.exit (qui lève une exception dans le thread où il est appelé), rattraper l'exception,
# faire se terminer tous les autres threads, puis quitter, mais j'ai la flemme.

## Redirection de stderr vers le fichier /tmp/breakage.log pour débugguer, c'est bien pratique
se = os.open("/tmp/breakage.log", os.O_WRONLY|os.O_APPEND|os.O_CREAT)
os.dup2(se, sys.stderr.fileno())
os.close(se)


def hangup_callback(manager, params):
    agi=manager.agi()
    if params['Channel'] == agi['channel']:
        os._exit(0)

def unreachble_callback(manager, params):
    agi=manager.agi()
    if params['Peer'] == "SIP/%s" % agi['callerid'] and params['PeerStatus'] in ['Unregistered','Unreachable']:
        manager.hangup(agi['channel'])
        os._exit(0)

def start_billing(agi, src, dest):
    syslog.syslog("Start billing from %s to %s" % (src, dest))
    while True:
        time.sleep(60)
        syslog.syslog("Billing from %s to %s, one more minutes" % (src, dest))


def Newstate_callback(manager, params):
    agi=manager.agi()
    syslog.syslog(params['ChannelStateDesc'])
    if params['ChannelStateDesc'] in ['Up'] and params['Channel'] == agi['channel']:
        t=Thread(target=start_billing, args=(agi, agi['callerid'], agi['extension']))
        t.start()

def dial(agi, to):
    agi.dial(to)
    os._exit(0)

if __name__ == '__main__' :
    # initialisation d'un AMI
    manager=Manager("billing", secrets.get('asterisk_billig_passwd') , server="127.0.0.1", event=True, auto_connect=False, timeout=10)
    syslog.openlog('billing')
    # initialisation d'un AGI (on lit des paramètres sur stdin, donc c'est bloquant jusqu'à la lecture d'une ligne vide)
    agi=manager.agi()
    # On lance le decompte du temps lorsque l'on passe à l'état Up.
    manager.register_events_callback('Newstate', Newstate_callback)
    # On coupe la communication si le client se déconnecte ou devient injoiniable (ce qui l'empêche de raccrocher lui même).
    manager.register_events_callback('PeerStatus', unreachble_callback)
    # Des choses à faire lorsque l'un des deux participant raccroche.
    manager.register_events_callback('Hangup', hangup_callback)

    # On récupère le domain sip de la destination
    SIPDOMAIN=agi['SIPDOMAIN']
    syslog.syslog('%r' % SIPDOMAIN)
    # Si le domaine est absent ou local, alors c'est un appel vers le RTC, on passe par la ligne SIP ovh
    if not SIPDOMAIN or SIPDOMAIN in ['crans.org']:
        SIPDOMAIN='forfait-ovh'
    agi.answer()
    # On compose le numéro dans un thread a part puisque cela est bloquant jusqu'à ce que quelqu'un raccroche. On limite la communication à 30min (1800000 milliseconde)
    t=Thread(target=dial, args=(agi, "SIP/%s@%s,60,L(1800000:60000:20000)" % (agi['extension'], SIPDOMAIN)))
    t.start()

    # On se connecte a l'AMI et on attent de recevoir des events
    while True:
        manager.connect()
        try:
            while True:
                manager.process_events()
                # Si le thread éxécutant dial est mort, c'est que quelqu'un à raccrocher, on quitte.
                if not t.isAlive():
                    os._exit(0)
        except (socket.error, NullRecv):
            pass
    os._exit(0)
