[sip/asterisk] Ménage dans le code

This commit is contained in:
Valentin Samir 2015-09-30 11:16:38 +02:00
parent ef0e8bb22e
commit 588eba0515

View file

@ -1,19 +1,14 @@
# -*- coding: utf-8 -
# liste d'event http://www.voip-info.org/wiki/view/asterisk+manager+events
# liste d'action http://www.voip-info.org/wiki/view/Asterisk+manager+API
import os
import sys
import time
import errno
import shutil
import syslog
import socket
import base64
import syslog
import psycopg2
import threading
import psycopg2.extras
from datetime import datetime
if '/usr/scripts' not in sys.path:
sys.path.append('/usr/scripts')
@ -22,9 +17,11 @@ import lc_ldap.objets
import gestion.secrets_new as secrets
class NullRecv(EnvironmentError):
pass
class AsteriskError(ValueError):
def __init__(self, message, action, params):
self.message = message
@ -34,6 +31,7 @@ class AsteriskError(ValueError):
def __str__(self):
return '%s, Action:%s, params:%s' % (self.message, self.action, self.params)
class Profile(object):
def __init__(self, sql_params=None, database=None):
self.sql_params = sql_params
@ -42,7 +40,10 @@ class Profile(object):
def update_pin(self, num, pin):
conn = psycopg2.connect(self.sql_params)
cur = conn.cursor()
cur.execute("UPDATE %s SET voicemail_password=%%s WHERE num=%%s" % self.database, (pin, num))
cur.execute(
"UPDATE %s SET voicemail_password=%%s WHERE num=%%s" % self.database,
(pin, num)
)
conn.commit()
cur.close()
conn.close()
@ -55,7 +56,12 @@ class Profile(object):
def alias_to_num(self, alias):
try:
conn = lc_ldap.shortcuts.lc_ldap_readonly()
ret=conn.search(u"(|(uid=%(alias)s)(mailAlias=%(alias)s@crans.org)(canonicalAlias=%(alias)s@crans.org))" % {'alias' : alias})
ret = conn.search(
(
u"(|(uid=%(alias)s)(mailAlias=%(alias)s@crans.org)"
+ "(canonicalAlias=%(alias)s@crans.org))"
) % {'alias': alias}
)
if len(ret) == 1:
return "1%04d" % ret[0]['aid'][0].value
else:
@ -82,13 +88,21 @@ class Profile(object):
except:
return num
class Sms(object):
def __init__(self, sql_params=None, database=None):
self.sql_params = sql_params
self.database = database
def sms_daemon(self, server, port, user, password, timeout=360):
manager = Manager(user, password, server=server, event=True, auto_connect=False, timeout=timeout)
manager = Manager(
user,
password,
server=server,
event=True,
auto_connect=False,
timeout=timeout
)
manager.register_events_callback('PeerStatus', self._send_sms)
while True:
manager.connect()
@ -99,11 +113,15 @@ class Sms(object):
pass
def sms_delay(self, src, dst, body, user, body_type='str'):
if not body_type in ["str", "base64"]:
if body_type not in ["str", "base64"]:
raise EnvironmentError("body_type sould be 'str' ou 'base64' not %r" % body_type)
conn = psycopg2.connect(self.sql_params)
cur = conn.cursor()
cur.execute('INSERT INTO %s (date, "from", "to", body, "user") VALUES (NOW(), %%s, %%s, %%s, %%s)' % self.database, (src, dst, base64.b64encode(body).strip() if body_type=='str' else body, user))
cur.execute(
'INSERT INTO %s (date, "from", "to", body, "user") VALUES (NOW(), %%s, %%s, %%s, %%s)' %
self.database,
(src, dst, base64.b64encode(body).strip() if body_type == 'str' else body, user)
)
conn.commit()
cur.close()
conn.close()
@ -113,15 +131,22 @@ class Sms(object):
num = params['Peer'].split('/')[1]
conn = psycopg2.connect(self.sql_params)
cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
cur.execute('SELECT * FROM %s WHERE "user"=%%s ORDER BY "date" ASC' % self.database, (num,))
cur.execute(
'SELECT * FROM %s WHERE "user"=%%s ORDER BY "date" ASC' % self.database,
(num,)
)
for sms in cur.fetchall():
try:
manager.messageSend(sms['from'], sms['to'], sms['body'], body_type='base64')
syslog.syslog("Message from %s successfully delivered to %s" % (sms['from'], sms['to']))
syslog.syslog(
"Message from %s successfully delivered to %s" % (sms['from'], sms['to'])
)
cur.execute('DELETE FROM %s WHERE id=%%s' % self.database, (sms['id'],))
conn.commit()
except AsteriskError as error:
syslog.syslog("Message from %s to %s : %s" % (sms['from'], sms['to'], params['Message']))
except AsteriskError:
syslog.syslog(
"Message from %s to %s : %s" % (sms['from'], sms['to'], params['Message'])
)
cur.close()
conn.close()
@ -149,7 +174,13 @@ class Sms(object):
ast_manager.messageSend(caller, to, msg)
except AsteriskError as error:
if error.message == "Message failed to send.":
self.sms_delay(error.params['from'], error.params['to'], error.params['base64body'], error.params['to'].split(':',1)[1], body_type='base64')
self.sms_delay(
error.params['from'],
error.params['to'],
error.params['base64body'],
error.params['to'].split(':', 1)[1],
body_type='base64'
)
else:
raise
@ -163,7 +194,10 @@ class History(object):
def add(self, id, src, dst):
conn = psycopg2.connect(self.sql_params)
cur = conn.cursor()
cur.execute("INSERT INTO %s (uniq_id,src,dst) VALUES (%%s, %%s, %%s)" % self.database, (id, src, dst))
cur.execute(
"INSERT INTO %s (uniq_id,src,dst) VALUES (%%s, %%s, %%s)" % self.database,
(id, src, dst)
)
conn.commit()
cur.close()
conn.close()
@ -179,7 +213,9 @@ class History(object):
def update(self, id, duration):
conn = psycopg2.connect(self.sql_params)
cur = conn.cursor()
cur.execute("UPDATE %s SET duration=%%s WHERE uniq_id=%%s" % self.database, (int(duration), id))
cur.execute(
"UPDATE %s SET duration=%%s WHERE uniq_id=%%s" % self.database, (int(duration), id)
)
conn.commit()
cur.close()
conn.close()
@ -189,10 +225,21 @@ class History(object):
try:
conn = psycopg2.connect(self.sql_params)
cur = conn.cursor()
cur.execute("SELECT count(DISTINCT dst) FROM %s WHERE date>='%s' AND dst LIKE '+%%'" % (self.database, time.strftime('%Y-%m-01')))
cur.execute(
"SELECT count(DISTINCT dst) FROM %s WHERE date>='%s' AND dst LIKE '+%%'" % (
self.database,
time.strftime('%Y-%m-01')
)
)
outgoing_call_num = cur.fetchall()[0][0]
if outgoing_call_num >= self.quota_limit:
cur.execute("SELECT count(dst)>0 FROM %s WHERE date>'%s' AND dst=%%s" % (self.database, time.strftime('%Y-%m-01')), (number,))
cur.execute(
"SELECT count(dst)>0 FROM %s WHERE date>'%s' AND dst=%%s" % (
self.database,
time.strftime('%Y-%m-01')
),
(number,)
)
allowed = cur.fetchall()[0][0]
else:
allowed = True
@ -202,9 +249,14 @@ class History(object):
pass
sys.stdout.write('ALLOWED' if allowed else 'DENY')
class Manager(object):
def __init__(self, username, password, timeout=10, server='idefisk.adm.crans.org', port=5038, debug=False, event=False, auto_connect=True, agi=None, wait_fullybooted=True):
def __init__(
self, username, password, timeout=10, server='idefisk.adm.crans.org',
port=5038, debug=False, event=False, auto_connect=True, agi=None,
wait_fullybooted=True
):
self.timeout = timeout
self.server = server
self.port = port
@ -256,7 +308,10 @@ 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) if len(line.split(': ', 1))==2 else (line.split(': ', 1)[0], '') 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)
@ -268,7 +323,6 @@ class Manager(object):
def _do_Event(self, type, params):
self._event.append((type, params))
def _gen_actionID(self):
id = time.time()
while id in self._pending_action:
@ -284,7 +338,7 @@ class Manager(object):
self._pending_action.append(id)
self._send('')
while not id in self._response.keys():
while id not in self._response.keys():
self._recv()
response = self._response[id]
@ -317,19 +371,22 @@ class Manager(object):
def process_events(self):
if not self._event:
try: self._recv()
except socket.timeout: pass
try:
self._recv()
except socket.timeout:
pass
for event in self._event:
(type, params) = event
for func in self._event_callback.get(type, []):
func(self, params)
self._event = []
def login(self, username=None, secret=None):
"""Login Manager"""
if username is None: username = self.username
if secret is None: secret = self.password
if username is None:
username = self.username
if secret is None:
secret = self.password
return self.action('login', username=username, secret=secret)
def logoff(self):
@ -340,8 +397,8 @@ class Manager(object):
def events(self, param):
"""Control Event Flow
params should be a boolean or a list among system,call,log,verbose,command,agent,user to select
which flags events should have to be sent."""
params should be a boolean or a list among system,call,log,verbose,command,agent,user
to select which flags events should have to be sent."""
if isinstance(param, list):
eventmask = ','.join(param)
elif isinstance(param, bool):
@ -357,18 +414,16 @@ class Manager(object):
def reload(self, module):
"""Synopsis: Send a reload event
Privilege: system,config,all"""
privilege = ['system', 'config', 'all']
return self.action('reload', module=module)
def messageSend(self, src, dst, body, body_type="str"):
if not body_type in ["str", "base64"]:
if body_type not in ["str", "base64"]:
raise EnvironmentError("body_type sould be 'str' ou 'base64' not %r" % body_type)
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):
@ -415,7 +470,11 @@ class AGI(object):
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)
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])
@ -435,7 +494,6 @@ class AGI(object):
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)
@ -450,21 +508,27 @@ class AGI(object):
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 answer(self):
self.launch_app("Answer")
def goto(self, arg):
self.launch_app("goto", arg)
### TODO
# TODO
class FastAGI(object):
def __init__(self, bind, port, *args, **kwargs):
pass