diff --git a/sip/asterisk.py b/sip/asterisk.py index 2df97b4c..7338bd90 100644 --- a/sip/asterisk.py +++ b/sip/asterisk.py @@ -10,7 +10,9 @@ import shutil import syslog import socket import base64 +import syslog import psycopg2 +import threading import psycopg2.extras from datetime import datetime @@ -202,7 +204,7 @@ class History(object): class Manager(object): - def __init__(self, username, password, timeout=10, server='asterisk.adm.crans.org', port=5038, debug=False, event=False, auto_connect=True): + def __init__(self, username, password, timeout=10, server='asterisk.adm.crans.org', port=5038, debug=False, event=False, auto_connect=True, agi=None): self.timeout = timeout self.server = server self.port = port @@ -214,6 +216,7 @@ class Manager(object): self._event=[] self._event_callback = {} self._toread = "" + self._agi = agi self.fullybooted = False self.username = username @@ -223,6 +226,11 @@ class Manager(object): if auto_connect: self.connect() + def agi(self, *args, **kwargs): + if not self._agi: + self._agi = AGI(*args, manager=self, **kwargs) + return self._agi + def _FullyBooted(self, manager, params): manager.fullybooted = True @@ -246,7 +254,7 @@ class Manager(object): def _parse_msg(self, msg): msg = msg.strip().split('\r\n') type, value = msg[0].split(': ', 1) - params = dict([line.split(': ', 1) for line in msg[1:]]) + params = dict([line.split(': ', 1) if len(line.split(': ', 1))==2 else (line.split(': ', 1)[0], '') for line in msg[1:]]) handler = getattr(self, "_do_"+type, None) handler(value, params) @@ -339,6 +347,10 @@ class Manager(object): raise EnvironmentError("%r should be a list or a bool" % param) return self.action('events', eventmask=eventmask) + def hangup(self, channel): + """Hangup a channel""" + return self.action('hangup', channel=channel) + def reload(self, module): """Synopsis: Send a reload event Privilege: system,config,all""" @@ -351,3 +363,103 @@ class Manager(object): if body_type == "str": body = base64.b64encode(body).strip() return self._action('messageSend', {'to':dst, 'from':src, 'base64body':body}) + + + +class AGI(object): + """voir http://www.voip-info.org/wiki/view/Asterisk+AGI""" + def __init__(self, read=sys.stdin, write=sys.stdout, manager=None, **params): + self.debug = True + self.read=read + self.write=write + self.params=params + self._manager=manager + self._lock=False + self._locklock = threading.Lock() + + self._read_params() + + def manager(self, *args, **kwargs): + if not self._manager: + self._manager=Manager(*args, agi=self, **kwargs) + return self._manager + + def __getitem__(self, key): + try: + return self.params[key] + except KeyError: + (result, data) = self.command("GET VARIABLE", key) + if int(result) != 1: + raise KeyError(key) + return data[1:-2] + + def __setitem__(self, key, value): + if key in self.params.keys(): + raise ValueError("ReadOnly value") + else: + (result, data) = self.command("SET VARIABLE", key, value) + return result + + def _read_params(self): + line=self.read.readline() + while line.strip(): + syslog.syslog(line) + if line.startswith('agi_'): + (key, data) = line[4:].split(':',1) + self.params[key.strip()]=data.strip() + line = self.read.readline() + + def command(self, name, *params): + with self._locklock: + if self._lock: + raise AsteriskError("Cannot lauch AGI command %s, an other command is processing" % name, name, params) + else: + self._lock = True + cmd=' '.join([name] + ["%s" % p for p in params]) + if self.debug: + syslog.syslog("%s\n" % cmd) + self.write.write("%s\n" % cmd) + self.write.flush() + line=self.read.readline() + if self.debug: + syslog.syslog(line) + lines=[line] + code=int(line[0:3]) + type=line[3] + if type == '-': + while not "%s End of " % code not in line: + line=self.read.readline() + if self.debug: + syslog.syslog("%s\n" % cmd) + lines.append(line) + + self._lock=False + if code != 200: + raise AsteriskError((code, '\n'.join(lines)), name, params) + + try: + (result, data) = lines[0][4:].split(' ', 1) + except ValueError: + result = lines[0][4:] + data="" + result=result.split('=',1)[1].strip() + return (int(result), data) + + def hangup(self): + self.command("hangup") + def set_callerid(self, callerid): + self.command("set_callerid", callerid) + def noop(self, str): + self.command("noop", str) + def launch_app(self, app, *params): + self.command("exec", app, *params) + def dial(self, to): + self.launch_app("dial", to) + def goto(self, arg): + self.launch_app("goto", arg) + + +### TODO +class FastAGI(object): + def __init__(self, bind, port, *args,**kwargs): + pass