commit
2664927f02
19
CHANGELOG
19
CHANGELOG
|
@ -1,21 +1,25 @@
|
||||||
2011-05-31 Randall Degges <rdegges@gmail.com
|
|
||||||
|
2012-11-11 Arezqui Belaid <areski@gmail.com>
|
||||||
|
* PEP8 Fixes
|
||||||
|
|
||||||
|
2011-05-31 Randall Degges <rdegges@gmail.com>
|
||||||
* BUGFIX: Fixing issue that prevented manager.status command from returning
|
* BUGFIX: Fixing issue that prevented manager.status command from returning
|
||||||
proper output.
|
proper output.
|
||||||
|
|
||||||
2007-01-26 Matthew Nicholson <mnicholson@digium.com>
|
2007-01-26 Matthew Nicholson <mnicholson@digium.com>
|
||||||
|
|
||||||
* asterisk/manager.py: Make get_header() functions work like
|
* asterisk/manager.py: Make get_header() functions work like
|
||||||
dict.get().
|
dict.get().
|
||||||
* UPGRADE: Updated.
|
* UPGRADE: Updated.
|
||||||
|
|
||||||
2007-01-16 Matthew Nicholson <mnicholson@digium.com>
|
2007-01-16 Matthew Nicholson <mnicholson@digium.com>
|
||||||
|
|
||||||
* asterisk/manager.py: Fix support for Manager.command(). Patch from
|
* asterisk/manager.py: Fix support for Manager.command(). Patch from
|
||||||
Karl Putland <karl@klasstek.com>.
|
Karl Putland <karl@klasstek.com>.
|
||||||
|
|
||||||
2007-01-02 Matthew Nicholson <mnicholson@digium.com>
|
2007-01-02 Matthew Nicholson <mnicholson@digium.com>
|
||||||
|
|
||||||
* asterisk/agi.py (AGI.set_autohangup): Fixed syntax error.
|
* asterisk/agi.py (AGI.set_autohangup): Fixed syntax error.
|
||||||
|
|
||||||
2006-11-28 Matthew Nicholson <mnicholson@digium.com>
|
2006-11-28 Matthew Nicholson <mnicholson@digium.com>
|
||||||
|
|
||||||
|
@ -94,4 +98,3 @@
|
||||||
* ChangeLog: Added.
|
* ChangeLog: Added.
|
||||||
* TODO: Added.
|
* TODO: Added.
|
||||||
* MANIFEST.in: Added ChangeLog and TODO.
|
* MANIFEST.in: Added ChangeLog and TODO.
|
||||||
|
|
||||||
|
|
144
asterisk/agi.py
144
asterisk/agi.py
|
@ -19,34 +19,65 @@ pyvr
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys, pprint, re
|
import sys
|
||||||
|
import pprint
|
||||||
|
import re
|
||||||
from types import ListType
|
from types import ListType
|
||||||
import signal
|
import signal
|
||||||
|
|
||||||
DEFAULT_TIMEOUT = 2000 # 2sec timeout used as default for functions that take timeouts
|
DEFAULT_TIMEOUT = 2000 # 2sec timeout used as default for functions that take timeouts
|
||||||
DEFAULT_RECORD = 20000 # 20sec record time
|
DEFAULT_RECORD = 20000 # 20sec record time
|
||||||
|
|
||||||
re_code = re.compile(r'(^\d*)\s*(.*)')
|
re_code = re.compile(r'(^\d*)\s*(.*)')
|
||||||
re_kv = re.compile(r'(?P<key>\w+)=(?P<value>[^\s]+)\s*(?:\((?P<data>.*)\))*')
|
re_kv = re.compile(r'(?P<key>\w+)=(?P<value>[^\s]+)\s*(?:\((?P<data>.*)\))*')
|
||||||
|
|
||||||
class AGIException(Exception): pass
|
|
||||||
class AGIError(AGIException): pass
|
|
||||||
|
|
||||||
class AGIUnknownError(AGIError): pass
|
class AGIException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class AGIAppError(AGIError): pass
|
|
||||||
|
class AGIError(AGIException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AGIUnknownError(AGIError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AGIAppError(AGIError):
|
||||||
|
pass
|
||||||
|
|
||||||
# there are several different types of hangups we can detect
|
# there are several different types of hangups we can detect
|
||||||
# they all are derrived from AGIHangup
|
# they all are derrived from AGIHangup
|
||||||
class AGIHangup(AGIAppError): pass
|
|
||||||
class AGISIGHUPHangup(AGIHangup): pass
|
|
||||||
class AGISIGPIPEHangup(AGIHangup): pass
|
|
||||||
class AGIResultHangup(AGIHangup): pass
|
|
||||||
|
|
||||||
class AGIDBError(AGIAppError): pass
|
|
||||||
|
|
||||||
class AGIUsageError(AGIError): pass
|
class AGIHangup(AGIAppError):
|
||||||
class AGIInvalidCommand(AGIError): pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AGISIGHUPHangup(AGIHangup):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AGISIGPIPEHangup(AGIHangup):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AGIResultHangup(AGIHangup):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AGIDBError(AGIAppError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AGIUsageError(AGIError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AGIInvalidCommand(AGIError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AGI:
|
class AGI:
|
||||||
"""
|
"""
|
||||||
|
@ -73,10 +104,10 @@ class AGI:
|
||||||
if line == '':
|
if line == '':
|
||||||
#blank line signals end
|
#blank line signals end
|
||||||
break
|
break
|
||||||
key,data = line.split(':')[0], ':'.join(line.split(':')[1:])
|
key, data = line.split(':')[0], ':'.join(line.split(':')[1:])
|
||||||
key = key.strip()
|
key = key.strip()
|
||||||
data = data.strip()
|
data = data.strip()
|
||||||
if key <> '':
|
if key != '':
|
||||||
self.env[key] = data
|
self.env[key] = data
|
||||||
sys.stderr.write('class AGI: self.env = ')
|
sys.stderr.write('class AGI: self.env = ')
|
||||||
sys.stderr.write(pprint.pformat(self.env))
|
sys.stderr.write(pprint.pformat(self.env))
|
||||||
|
@ -92,7 +123,7 @@ class AGI:
|
||||||
def test_hangup(self):
|
def test_hangup(self):
|
||||||
"""This function throws AGIHangup if we have recieved a SIGHUP"""
|
"""This function throws AGIHangup if we have recieved a SIGHUP"""
|
||||||
if self._got_sighup:
|
if self._got_sighup:
|
||||||
raise AGISIGHUPHangup("Received SIGHUP from Asterisk")
|
raise AGISIGHUPHangup("Received SIGHUP from Asterisk")
|
||||||
|
|
||||||
def execute(self, command, *args):
|
def execute(self, command, *args):
|
||||||
self.test_hangup()
|
self.test_hangup()
|
||||||
|
@ -100,7 +131,7 @@ class AGI:
|
||||||
try:
|
try:
|
||||||
self.send_command(command, *args)
|
self.send_command(command, *args)
|
||||||
return self.get_result()
|
return self.get_result()
|
||||||
except IOError,e:
|
except IOError, e:
|
||||||
if e.errno == 32:
|
if e.errno == 32:
|
||||||
# Broken Pipe * let us go
|
# Broken Pipe * let us go
|
||||||
raise AGISIGPIPEHangup("Received SIGPIPE")
|
raise AGISIGPIPEHangup("Received SIGPIPE")
|
||||||
|
@ -110,7 +141,7 @@ class AGI:
|
||||||
def send_command(self, command, *args):
|
def send_command(self, command, *args):
|
||||||
"""Send a command to Asterisk"""
|
"""Send a command to Asterisk"""
|
||||||
command = command.strip()
|
command = command.strip()
|
||||||
command = '%s %s' % (command, ' '.join(map(str,args)))
|
command = '%s %s' % (command, ' '.join(map(str, args)))
|
||||||
command = command.strip()
|
command = command.strip()
|
||||||
if command[-1] != '\n':
|
if command[-1] != '\n':
|
||||||
command += '\n'
|
command += '\n'
|
||||||
|
@ -121,7 +152,7 @@ class AGI:
|
||||||
def get_result(self, stdin=sys.stdin):
|
def get_result(self, stdin=sys.stdin):
|
||||||
"""Read the result of a command from Asterisk"""
|
"""Read the result of a command from Asterisk"""
|
||||||
code = 0
|
code = 0
|
||||||
result = {'result':('','')}
|
result = {'result': ('', '')}
|
||||||
line = stdin.readline().strip()
|
line = stdin.readline().strip()
|
||||||
sys.stderr.write(' RESULT_LINE: %s\n' % line)
|
sys.stderr.write(' RESULT_LINE: %s\n' % line)
|
||||||
m = re_code.search(line)
|
m = re_code.search(line)
|
||||||
|
@ -130,7 +161,7 @@ class AGI:
|
||||||
code = int(code)
|
code = int(code)
|
||||||
|
|
||||||
if code == 200:
|
if code == 200:
|
||||||
for key,value,data in re_kv.findall(response):
|
for key, value, data in re_kv.findall(response):
|
||||||
result[key] = (value, data)
|
result[key] = (value, data)
|
||||||
|
|
||||||
# If user hangs up... we get 'hangup' in the data
|
# If user hangs up... we get 'hangup' in the data
|
||||||
|
@ -226,7 +257,8 @@ class AGI:
|
||||||
extension must not be included in the filename.
|
extension must not be included in the filename.
|
||||||
"""
|
"""
|
||||||
escape_digits = self._process_digit_list(escape_digits)
|
escape_digits = self._process_digit_list(escape_digits)
|
||||||
response = self.execute('STREAM FILE', filename, escape_digits, sample_offset)
|
response = self.execute(
|
||||||
|
'STREAM FILE', filename, escape_digits, sample_offset)
|
||||||
res = response['result'][0]
|
res = response['result'][0]
|
||||||
if res == '0':
|
if res == '0':
|
||||||
return ''
|
return ''
|
||||||
|
@ -265,7 +297,8 @@ class AGI:
|
||||||
"""
|
"""
|
||||||
res = self.execute('SEND IMAGE', filename)['result'][0]
|
res = self.execute('SEND IMAGE', filename)['result'][0]
|
||||||
if res != '0':
|
if res != '0':
|
||||||
raise AGIAppError('Channel falure on channel %s' % self.env.get('agi_channel','UNKNOWN'))
|
raise AGIAppError('Channel falure on channel %s' %
|
||||||
|
self.env.get('agi_channel', 'UNKNOWN'))
|
||||||
|
|
||||||
def say_digits(self, digits, escape_digits=''):
|
def say_digits(self, digits, escape_digits=''):
|
||||||
"""agi.say_digits(digits, escape_digits='') --> digit
|
"""agi.say_digits(digits, escape_digits='') --> digit
|
||||||
|
@ -326,7 +359,8 @@ class AGI:
|
||||||
"""
|
"""
|
||||||
characters = self._process_digit_list(characters)
|
characters = self._process_digit_list(characters)
|
||||||
escape_digits = self._process_digit_list(escape_digits)
|
escape_digits = self._process_digit_list(escape_digits)
|
||||||
res = self.execute('SAY PHONETIC', characters, escape_digits)['result'][0]
|
res = self.execute(
|
||||||
|
'SAY PHONETIC', characters, escape_digits)['result'][0]
|
||||||
if res == '0':
|
if res == '0':
|
||||||
return ''
|
return ''
|
||||||
else:
|
else:
|
||||||
|
@ -372,8 +406,10 @@ class AGI:
|
||||||
in seconds since the UNIX Epoch (Jan 1, 1970 00:00:00).
|
in seconds since the UNIX Epoch (Jan 1, 1970 00:00:00).
|
||||||
"""
|
"""
|
||||||
escape_digits = self._process_digit_list(escape_digits)
|
escape_digits = self._process_digit_list(escape_digits)
|
||||||
if format: format = self._quote(format)
|
if format:
|
||||||
res = self.execute('SAY DATETIME', seconds, escape_digits, format, zone)['result'][0]
|
format = self._quote(format)
|
||||||
|
res = self.execute(
|
||||||
|
'SAY DATETIME', seconds, escape_digits, format, zone)['result'][0]
|
||||||
if res == '0':
|
if res == '0':
|
||||||
return ''
|
return ''
|
||||||
else:
|
else:
|
||||||
|
@ -401,7 +437,8 @@ class AGI:
|
||||||
"""
|
"""
|
||||||
escape_digits = self._process_digit_list(escape_digits)
|
escape_digits = self._process_digit_list(escape_digits)
|
||||||
if timeout:
|
if timeout:
|
||||||
response = self.execute('GET OPTION', filename, escape_digits, timeout)
|
response = self.execute(
|
||||||
|
'GET OPTION', filename, escape_digits, timeout)
|
||||||
else:
|
else:
|
||||||
response = self.execute('GET OPTION', filename, escape_digits)
|
response = self.execute('GET OPTION', filename, escape_digits)
|
||||||
|
|
||||||
|
@ -455,7 +492,8 @@ class AGI:
|
||||||
exceeding the end of the file
|
exceeding the end of the file
|
||||||
"""
|
"""
|
||||||
escape_digits = self._process_digit_list(escape_digits)
|
escape_digits = self._process_digit_list(escape_digits)
|
||||||
res = self.execute('RECORD FILE', self._quote(filename), format, escape_digits, timeout, offset, beep)['result'][0]
|
res = self.execute('RECORD FILE', self._quote(filename), format,
|
||||||
|
escape_digits, timeout, offset, beep)['result'][0]
|
||||||
try:
|
try:
|
||||||
return chr(int(res))
|
return chr(int(res))
|
||||||
except:
|
except:
|
||||||
|
@ -510,11 +548,11 @@ class AGI:
|
||||||
7 Line is busy
|
7 Line is busy
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
result = self.execute('CHANNEL STATUS', channel)
|
result = self.execute('CHANNEL STATUS', channel)
|
||||||
except AGIHangup:
|
except AGIHangup:
|
||||||
raise
|
raise
|
||||||
except AGIAppError:
|
except AGIAppError:
|
||||||
result = {'result': ('-1','')}
|
result = {'result': ('-1', '')}
|
||||||
|
|
||||||
return int(result['result'][0])
|
return int(result['result'][0])
|
||||||
|
|
||||||
|
@ -530,27 +568,28 @@ class AGI:
|
||||||
the variable is not set, an empty string is returned.
|
the variable is not set, an empty string is returned.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
result = self.execute('GET VARIABLE', self._quote(name))
|
result = self.execute('GET VARIABLE', self._quote(name))
|
||||||
except AGIResultHangup:
|
except AGIResultHangup:
|
||||||
result = {'result': ('1', 'hangup')}
|
result = {'result': ('1', 'hangup')}
|
||||||
|
|
||||||
res, value = result['result']
|
res, value = result['result']
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def get_full_variable(self, name, channel = None):
|
def get_full_variable(self, name, channel=None):
|
||||||
"""Get a channel variable.
|
"""Get a channel variable.
|
||||||
|
|
||||||
This function returns the value of the indicated channel variable. If
|
This function returns the value of the indicated channel variable. If
|
||||||
the variable is not set, an empty string is returned.
|
the variable is not set, an empty string is returned.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if channel:
|
if channel:
|
||||||
result = self.execute('GET FULL VARIABLE', self._quote(name), self._quote(channel))
|
result = self.execute('GET FULL VARIABLE',
|
||||||
else:
|
self._quote(name), self._quote(channel))
|
||||||
result = self.execute('GET FULL VARIABLE', self._quote(name))
|
else:
|
||||||
|
result = self.execute('GET FULL VARIABLE', self._quote(name))
|
||||||
|
|
||||||
except AGIResultHangup:
|
except AGIResultHangup:
|
||||||
result = {'result': ('1', 'hangup')}
|
result = {'result': ('1', 'hangup')}
|
||||||
|
|
||||||
res, value = result['result']
|
res, value = result['result']
|
||||||
return value
|
return value
|
||||||
|
@ -571,10 +610,12 @@ class AGI:
|
||||||
"""
|
"""
|
||||||
family = '"%s"' % family
|
family = '"%s"' % family
|
||||||
key = '"%s"' % key
|
key = '"%s"' % key
|
||||||
result = self.execute('DATABASE GET', self._quote(family), self._quote(key))
|
result = self.execute(
|
||||||
|
'DATABASE GET', self._quote(family), self._quote(key))
|
||||||
res, value = result['result']
|
res, value = result['result']
|
||||||
if res == '0':
|
if res == '0':
|
||||||
raise AGIDBError('Key not found in database: family=%s, key=%s' % (family, key))
|
raise AGIDBError('Key not found in database: family=%s, key=%s' %
|
||||||
|
(family, key))
|
||||||
elif res == '1':
|
elif res == '1':
|
||||||
return value
|
return value
|
||||||
else:
|
else:
|
||||||
|
@ -585,7 +626,8 @@ class AGI:
|
||||||
Adds or updates an entry in the Asterisk database for a
|
Adds or updates an entry in the Asterisk database for a
|
||||||
given family, key, and value.
|
given family, key, and value.
|
||||||
"""
|
"""
|
||||||
result = self.execute('DATABASE PUT', self._quote(family), self._quote(key), self._quote(value))
|
result = self.execute('DATABASE PUT', self._quote(
|
||||||
|
family), self._quote(key), self._quote(value))
|
||||||
res, value = result['result']
|
res, value = result['result']
|
||||||
if res == '0':
|
if res == '0':
|
||||||
raise AGIDBError('Unable to put vaule in databale: family=%s, key=%s, value=%s' % (family, key, value))
|
raise AGIDBError('Unable to put vaule in databale: family=%s, key=%s, value=%s' % (family, key, value))
|
||||||
|
@ -595,7 +637,8 @@ class AGI:
|
||||||
Deletes an entry in the Asterisk database for a
|
Deletes an entry in the Asterisk database for a
|
||||||
given family and key.
|
given family and key.
|
||||||
"""
|
"""
|
||||||
result = self.execute('DATABASE DEL', self._quote(family), self._quote(key))
|
result = self.execute(
|
||||||
|
'DATABASE DEL', self._quote(family), self._quote(key))
|
||||||
res, value = result['result']
|
res, value = result['result']
|
||||||
if res == '0':
|
if res == '0':
|
||||||
raise AGIDBError('Unable to delete from database: family=%s, key=%s' % (family, key))
|
raise AGIDBError('Unable to delete from database: family=%s, key=%s' % (family, key))
|
||||||
|
@ -605,7 +648,8 @@ class AGI:
|
||||||
Deletes a family or specific keytree with in a family
|
Deletes a family or specific keytree with in a family
|
||||||
in the Asterisk database.
|
in the Asterisk database.
|
||||||
"""
|
"""
|
||||||
result = self.execute('DATABASE DELTREE', self._quote(family), self._quote(key))
|
result = self.execute(
|
||||||
|
'DATABASE DELTREE', self._quote(family), self._quote(key))
|
||||||
res, value = result['result']
|
res, value = result['result']
|
||||||
if res == '0':
|
if res == '0':
|
||||||
raise AGIDBError('Unable to delete tree from database: family=%s, key=%s' % (family, key))
|
raise AGIDBError('Unable to delete tree from database: family=%s, key=%s' % (family, key))
|
||||||
|
@ -616,7 +660,7 @@ class AGI:
|
||||||
"""
|
"""
|
||||||
self.execute('NOOP')
|
self.execute('NOOP')
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__ == '__main__':
|
||||||
agi = AGI()
|
agi = AGI()
|
||||||
#agi.appexec('festival','Welcome to Klass Technologies. Thank you for calling.')
|
#agi.appexec('festival','Welcome to Klass Technologies. Thank you for calling.')
|
||||||
#agi.appexec('festival','This is a test of the text to speech engine.')
|
#agi.appexec('festival','This is a test of the text to speech engine.')
|
||||||
|
@ -638,11 +682,12 @@ if __name__=='__main__':
|
||||||
#agi.appexec('background','demo-congrats')
|
#agi.appexec('background','demo-congrats')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
agi.appexec('backgrounder','demo-congrats')
|
agi.appexec('backgrounder', 'demo-congrats')
|
||||||
except AGIAppError:
|
except AGIAppError:
|
||||||
sys.stderr.write("Handled exception for missing application backgrounder\n")
|
sys.stderr.write(
|
||||||
|
"Handled exception for missing application backgrounder\n")
|
||||||
|
|
||||||
agi.set_variable('foo','bar')
|
agi.set_variable('foo', 'bar')
|
||||||
agi.get_variable('foo')
|
agi.get_variable('foo')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -661,6 +706,7 @@ if __name__=='__main__':
|
||||||
agi.database_del('foo', 'bar')
|
agi.database_del('foo', 'bar')
|
||||||
agi.database_deltree('foo')
|
agi.database_deltree('foo')
|
||||||
except AGIDBError:
|
except AGIDBError:
|
||||||
sys.stderr.write("Handled exception for missing database entry bar:foo\n")
|
sys.stderr.write(
|
||||||
|
"Handled exception for missing database entry bar:foo\n")
|
||||||
|
|
||||||
agi.hangup()
|
agi.hangup()
|
||||||
|
|
|
@ -36,6 +36,7 @@ import sys
|
||||||
|
|
||||||
__UNDEF__ = [] # a special sentinel object
|
__UNDEF__ = [] # a special sentinel object
|
||||||
|
|
||||||
|
|
||||||
def lookup(name, frame, locals):
|
def lookup(name, frame, locals):
|
||||||
"""Find the value for a given name in the given environment."""
|
"""Find the value for a given name in the given environment."""
|
||||||
if name in locals:
|
if name in locals:
|
||||||
|
@ -44,7 +45,7 @@ def lookup(name, frame, locals):
|
||||||
return 'global', frame.f_globals[name]
|
return 'global', frame.f_globals[name]
|
||||||
if '__builtins__' in frame.f_globals:
|
if '__builtins__' in frame.f_globals:
|
||||||
builtins = frame.f_globals['__builtins__']
|
builtins = frame.f_globals['__builtins__']
|
||||||
if type(builtins) is type({}):
|
if isinstance(builtins, type({})):
|
||||||
if name in builtins:
|
if name in builtins:
|
||||||
return 'builtin', builtins[name]
|
return 'builtin', builtins[name]
|
||||||
else:
|
else:
|
||||||
|
@ -52,12 +53,15 @@ def lookup(name, frame, locals):
|
||||||
return 'builtin', getattr(builtins, name)
|
return 'builtin', getattr(builtins, name)
|
||||||
return None, __UNDEF__
|
return None, __UNDEF__
|
||||||
|
|
||||||
|
|
||||||
def scanvars(reader, frame, locals):
|
def scanvars(reader, frame, locals):
|
||||||
"""Scan one logical line of Python and look up values of variables used."""
|
"""Scan one logical line of Python and look up values of variables used."""
|
||||||
import tokenize, keyword
|
import tokenize
|
||||||
|
import keyword
|
||||||
vars, lasttoken, parent, prefix, value = [], None, None, '', __UNDEF__
|
vars, lasttoken, parent, prefix, value = [], None, None, '', __UNDEF__
|
||||||
for ttype, token, start, end, line in tokenize.generate_tokens(reader):
|
for ttype, token, start, end, line in tokenize.generate_tokens(reader):
|
||||||
if ttype == tokenize.NEWLINE: break
|
if ttype == tokenize.NEWLINE:
|
||||||
|
break
|
||||||
if ttype == tokenize.NAME and token not in keyword.kwlist:
|
if ttype == tokenize.NAME and token not in keyword.kwlist:
|
||||||
if lasttoken == '.':
|
if lasttoken == '.':
|
||||||
if parent is not __UNDEF__:
|
if parent is not __UNDEF__:
|
||||||
|
@ -77,9 +81,15 @@ def scanvars(reader, frame, locals):
|
||||||
|
|
||||||
def text((etype, evalue, etb), context=5):
|
def text((etype, evalue, etb), context=5):
|
||||||
"""Return a plain text document describing a given traceback."""
|
"""Return a plain text document describing a given traceback."""
|
||||||
import os, types, time, traceback, linecache, inspect, pydoc
|
import os
|
||||||
|
import types
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
import linecache
|
||||||
|
import inspect
|
||||||
|
import pydoc
|
||||||
|
|
||||||
if type(etype) is types.ClassType:
|
if isinstance(etype, types.ClassType):
|
||||||
etype = etype.__name__
|
etype = etype.__name__
|
||||||
pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
|
pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
|
||||||
date = time.ctime(time.time())
|
date = time.ctime(time.time())
|
||||||
|
@ -97,13 +107,16 @@ function calls leading up to the error, in the order they occurred.
|
||||||
if func != '?':
|
if func != '?':
|
||||||
call = 'in ' + func + \
|
call = 'in ' + func + \
|
||||||
inspect.formatargvalues(args, varargs, varkw, locals,
|
inspect.formatargvalues(args, varargs, varkw, locals,
|
||||||
formatvalue=lambda value: '=' + pydoc.text.repr(value))
|
formatvalue=lambda value: '=' + pydoc.text.repr(value))
|
||||||
|
|
||||||
highlight = {}
|
highlight = {}
|
||||||
|
|
||||||
def reader(lnum=[lnum]):
|
def reader(lnum=[lnum]):
|
||||||
highlight[lnum[0]] = 1
|
highlight[lnum[0]] = 1
|
||||||
try: return linecache.getline(file, lnum[0])
|
try:
|
||||||
finally: lnum[0] += 1
|
return linecache.getline(file, lnum[0])
|
||||||
|
finally:
|
||||||
|
lnum[0] += 1
|
||||||
vars = scanvars(reader, frame, locals)
|
vars = scanvars(reader, frame, locals)
|
||||||
|
|
||||||
rows = [' %s %s' % (file, call)]
|
rows = [' %s %s' % (file, call)]
|
||||||
|
@ -111,17 +124,21 @@ function calls leading up to the error, in the order they occurred.
|
||||||
i = lnum - index
|
i = lnum - index
|
||||||
for line in lines:
|
for line in lines:
|
||||||
num = '%5d ' % i
|
num = '%5d ' % i
|
||||||
rows.append(num+line.rstrip())
|
rows.append(num + line.rstrip())
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
done, dump = {}, []
|
done, dump = {}, []
|
||||||
for name, where, value in vars:
|
for name, where, value in vars:
|
||||||
if name in done: continue
|
if name in done:
|
||||||
|
continue
|
||||||
done[name] = 1
|
done[name] = 1
|
||||||
if value is not __UNDEF__:
|
if value is not __UNDEF__:
|
||||||
if where == 'global': name = 'global ' + name
|
if where == 'global':
|
||||||
elif where == 'local': name = name
|
name = 'global ' + name
|
||||||
else: name = where + name.split('.')[-1]
|
elif where == 'local':
|
||||||
|
name = name
|
||||||
|
else:
|
||||||
|
name = where + name.split('.')[-1]
|
||||||
dump.append('%s = %s' % (name, pydoc.text.repr(value)))
|
dump.append('%s = %s' % (name, pydoc.text.repr(value)))
|
||||||
else:
|
else:
|
||||||
dump.append(name + ' undefined')
|
dump.append(name + ' undefined')
|
||||||
|
@ -130,10 +147,10 @@ function calls leading up to the error, in the order they occurred.
|
||||||
frames.append('\n%s\n' % '\n'.join(rows))
|
frames.append('\n%s\n' % '\n'.join(rows))
|
||||||
|
|
||||||
exception = ['%s: %s' % (str(etype), str(evalue))]
|
exception = ['%s: %s' % (str(etype), str(evalue))]
|
||||||
if type(evalue) is types.InstanceType:
|
if isinstance(evalue, types.InstanceType):
|
||||||
for name in dir(evalue):
|
for name in dir(evalue):
|
||||||
value = pydoc.text.repr(getattr(evalue, name))
|
value = pydoc.text.repr(getattr(evalue, name))
|
||||||
exception.append('\n%s%s = %s' % (" "*4, name, value))
|
exception.append('\n%s%s = %s' % (" " * 4, name, value))
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
return head + ''.join(frames) + ''.join(exception) + '''
|
return head + ''.join(frames) + ''.join(exception) + '''
|
||||||
|
@ -144,11 +161,12 @@ the original traceback:
|
||||||
%s
|
%s
|
||||||
''' % ''.join(traceback.format_exception(etype, evalue, etb))
|
''' % ''.join(traceback.format_exception(etype, evalue, etb))
|
||||||
|
|
||||||
|
|
||||||
class Hook:
|
class Hook:
|
||||||
"""A hook to replace sys.excepthook that shows tracebacks in HTML."""
|
"""A hook to replace sys.excepthook that shows tracebacks in HTML."""
|
||||||
|
|
||||||
def __init__(self, display=1, logdir=None, context=5, file=None,
|
def __init__(self, display=1, logdir=None, context=5, file=None,
|
||||||
agi=None):
|
agi=None):
|
||||||
self.display = display # send tracebacks to browser if true
|
self.display = display # send tracebacks to browser if true
|
||||||
self.logdir = logdir # log tracebacks to files if not None
|
self.logdir = logdir # log tracebacks to files if not None
|
||||||
self.context = context # number of source code lines per frame
|
self.context = context # number of source code lines per frame
|
||||||
|
@ -180,7 +198,8 @@ class Hook:
|
||||||
self.file.write('A problem occured in a python script\n')
|
self.file.write('A problem occured in a python script\n')
|
||||||
|
|
||||||
if self.logdir is not None:
|
if self.logdir is not None:
|
||||||
import os, tempfile
|
import os
|
||||||
|
import tempfile
|
||||||
(fd, path) = tempfile.mkstemp(suffix='.txt', dir=self.logdir)
|
(fd, path) = tempfile.mkstemp(suffix='.txt', dir=self.logdir)
|
||||||
try:
|
try:
|
||||||
file = os.fdopen(fd, 'w')
|
file = os.fdopen(fd, 'w')
|
||||||
|
@ -197,20 +216,22 @@ class Hook:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.file.flush()
|
self.file.flush()
|
||||||
except: pass
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
handler = Hook().handle
|
handler = Hook().handle
|
||||||
|
|
||||||
|
|
||||||
def enable(agi=None, display=1, logdir=None, context=5):
|
def enable(agi=None, display=1, logdir=None, context=5):
|
||||||
"""Install an exception handler that formats tracebacks as HTML.
|
"""Install an exception handler that formats tracebacks as HTML.
|
||||||
|
|
||||||
The optional argument 'display' can be set to 0 to suppress sending the
|
The optional argument 'display' can be set to 0 to suppress sending the
|
||||||
traceback to the browser, and 'logdir' can be set to a directory to cause
|
traceback to the browser, and 'logdir' can be set to a directory to cause
|
||||||
tracebacks to be written to files there."""
|
tracebacks to be written to files there."""
|
||||||
except_hook = Hook(display=display, logdir=logdir,
|
except_hook = Hook(display=display, logdir=logdir,
|
||||||
context=context, agi=agi)
|
context=context, agi=agi)
|
||||||
sys.excepthook = except_hook
|
sys.excepthook = except_hook
|
||||||
|
|
||||||
global handler
|
global handler
|
||||||
handler = except_hook.handle
|
handler = except_hook.handle
|
||||||
|
|
||||||
|
|
|
@ -28,18 +28,22 @@ This module provides parsing functionality for asterisk config files.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
class ParseError(Exception): pass
|
|
||||||
|
class ParseError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Line(object):
|
class Line(object):
|
||||||
def __init__(self, line, number):
|
def __init__(self, line, number):
|
||||||
self.line = ''
|
self.line = ''
|
||||||
self.comment = ''
|
self.comment = ''
|
||||||
line = line.strip() # I guess we don't preserve indentation
|
line = line.strip() # I guess we don't preserve indentation
|
||||||
self.number = number
|
self.number = number
|
||||||
parts = line.split(';')
|
parts = line.split(';')
|
||||||
if len(parts) >= 2:
|
if len(parts) >= 2:
|
||||||
self.line = parts[0].strip()
|
self.line = parts[0].strip()
|
||||||
self.comment = ';'.join(parts[1:]) #Just in case the comment contained ';'
|
self.comment = ';'.join(
|
||||||
|
parts[1:]) # Just in case the comment contained ';'
|
||||||
else:
|
else:
|
||||||
self.line = line
|
self.line = line
|
||||||
|
|
||||||
|
@ -59,12 +63,14 @@ class Category(Line):
|
||||||
Line.__init__(self, line, num)
|
Line.__init__(self, line, num)
|
||||||
if self.line:
|
if self.line:
|
||||||
if (self.line[0] != '[' or self.line[-1] != ']'):
|
if (self.line[0] != '[' or self.line[-1] != ']'):
|
||||||
raise ParseError(self.number, "Missing '[' or ']' in category definition")
|
raise ParseError(
|
||||||
|
self.number, "Missing '[' or ']' in category definition")
|
||||||
self.name = self.line[1:-1]
|
self.name = self.line[1:-1]
|
||||||
elif name:
|
elif name:
|
||||||
self.name = name
|
self.name = name
|
||||||
else:
|
else:
|
||||||
raise Exception("Must provide name or line representing a category")
|
raise Exception(
|
||||||
|
"Must provide name or line representing a category")
|
||||||
|
|
||||||
self.items = []
|
self.items = []
|
||||||
self.comments = []
|
self.comments = []
|
||||||
|
@ -106,10 +112,11 @@ class Item(Line):
|
||||||
if self.line.strip()[-1] == ']':
|
if self.line.strip()[-1] == ']':
|
||||||
raise ParseError(self.number, "Category name missing '['")
|
raise ParseError(self.number, "Category name missing '['")
|
||||||
else:
|
else:
|
||||||
raise ParseError(self.number, "Item must be in name = value pairs")
|
raise ParseError(
|
||||||
|
self.number, "Item must be in name = value pairs")
|
||||||
|
|
||||||
if value and value[0] == '>':
|
if value and value[0] == '>':
|
||||||
self.style = '>' #preserve the style of the original
|
self.style = '>' # preserve the style of the original
|
||||||
value = value[1:].strip()
|
value = value[1:].strip()
|
||||||
self.name = name.strip()
|
self.name = name.strip()
|
||||||
self.value = value
|
self.value = value
|
||||||
|
@ -119,6 +126,7 @@ class Item(Line):
|
||||||
return '%s =%s %s\t;%s' % (self.name, self.style, self.value, self.comment)
|
return '%s =%s %s\t;%s' % (self.name, self.style, self.value, self.comment)
|
||||||
return '%s =%s %s' % (self.name, self.style, self.value)
|
return '%s =%s %s' % (self.name, self.style, self.value)
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
def __init__(self, filename):
|
def __init__(self, filename):
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
|
@ -127,8 +135,8 @@ class Config(object):
|
||||||
self.categories = []
|
self.categories = []
|
||||||
|
|
||||||
# load and parse the file
|
# load and parse the file
|
||||||
self.load()
|
self.load()
|
||||||
self.parse()
|
self.parse()
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
self.raw_lines = open(self.filename).readlines()
|
self.raw_lines = open(self.filename).readlines()
|
||||||
|
@ -140,14 +148,15 @@ class Config(object):
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
cat = None
|
cat = None
|
||||||
num = 0
|
num = 0
|
||||||
for line in self.raw_lines:
|
for line in self.raw_lines:
|
||||||
num += 1
|
num += 1
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not line or line[0] == ';':
|
if not line or line[0] == ';':
|
||||||
item = Line(line or '', num)
|
item = Line(line or '', num)
|
||||||
self.lines.append(item)
|
self.lines.append(item)
|
||||||
if cat: cat.comments.append(item)
|
if cat:
|
||||||
|
cat.comments.append(item)
|
||||||
continue
|
continue
|
||||||
elif line[0] == '[':
|
elif line[0] == '[':
|
||||||
cat = Category(line, num)
|
cat = Category(line, num)
|
||||||
|
@ -157,6 +166,6 @@ class Config(object):
|
||||||
else:
|
else:
|
||||||
item = Item(line, num)
|
item = Item(line, num)
|
||||||
self.lines.append(item)
|
self.lines.append(item)
|
||||||
if cat: cat.append(item)
|
if cat:
|
||||||
|
cat.append(item)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,8 @@ Not all manager actions are implmented as of yet, feel free to add them
|
||||||
and submit patches.
|
and submit patches.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys,os
|
import sys
|
||||||
|
import os
|
||||||
import socket
|
import socket
|
||||||
import threading
|
import threading
|
||||||
import Queue
|
import Queue
|
||||||
|
@ -63,6 +64,7 @@ from time import sleep
|
||||||
|
|
||||||
EOL = '\r\n'
|
EOL = '\r\n'
|
||||||
|
|
||||||
|
|
||||||
class ManagerMsg(object):
|
class ManagerMsg(object):
|
||||||
"""A manager interface message"""
|
"""A manager interface message"""
|
||||||
def __init__(self, response):
|
def __init__(self, response):
|
||||||
|
@ -99,13 +101,13 @@ class ManagerMsg(object):
|
||||||
"""Parse a manager message"""
|
"""Parse a manager message"""
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
for n, line in enumerate (response):
|
for n, line in enumerate(response):
|
||||||
# all valid header lines end in \r\n
|
# all valid header lines end in \r\n
|
||||||
if not line.endswith ('\r\n'):
|
if not line.endswith('\r\n'):
|
||||||
data.extend(response[n:])
|
data.extend(response[n:])
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
k, v = (x.strip() for x in line.split(':',1))
|
k, v = (x.strip() for x in line.split(':', 1))
|
||||||
self.headers[k] = v
|
self.headers[k] = v
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# invalid header, start of multi-line data response
|
# invalid header, start of multi-line data response
|
||||||
|
@ -115,9 +117,9 @@ class ManagerMsg(object):
|
||||||
|
|
||||||
def has_header(self, hname):
|
def has_header(self, hname):
|
||||||
"""Check for a header"""
|
"""Check for a header"""
|
||||||
return self.headers.has_key(hname)
|
return hname in self.headers
|
||||||
|
|
||||||
def get_header(self, hname, defval = None):
|
def get_header(self, hname, defval=None):
|
||||||
"""Return the specfied header"""
|
"""Return the specfied header"""
|
||||||
return self.headers.get(hname, defval)
|
return self.headers.get(hname, defval)
|
||||||
|
|
||||||
|
@ -143,16 +145,17 @@ class Event(object):
|
||||||
|
|
||||||
# if this is not an event message we have a problem
|
# if this is not an event message we have a problem
|
||||||
if not message.has_header('Event'):
|
if not message.has_header('Event'):
|
||||||
raise ManagerException('Trying to create event from non event message')
|
raise ManagerException(
|
||||||
|
'Trying to create event from non event message')
|
||||||
|
|
||||||
# get the event name
|
# get the event name
|
||||||
self.name = message.get_header('Event')
|
self.name = message.get_header('Event')
|
||||||
|
|
||||||
def has_header(self, hname):
|
def has_header(self, hname):
|
||||||
"""Check for a header"""
|
"""Check for a header"""
|
||||||
return self.headers.has_key(hname)
|
return hname in self.headers
|
||||||
|
|
||||||
def get_header(self, hname, defval = None):
|
def get_header(self, hname, defval=None):
|
||||||
"""Return the specfied header"""
|
"""Return the specfied header"""
|
||||||
return self.headers.get(hname, defval)
|
return self.headers.get(hname, defval)
|
||||||
|
|
||||||
|
@ -164,7 +167,8 @@ class Event(object):
|
||||||
return self.headers['Event']
|
return self.headers['Event']
|
||||||
|
|
||||||
def get_action_id(self):
|
def get_action_id(self):
|
||||||
return self.headers.get('ActionID',0000)
|
return self.headers.get('ActionID', 0000)
|
||||||
|
|
||||||
|
|
||||||
class Manager(object):
|
class Manager(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -192,12 +196,12 @@ class Manager(object):
|
||||||
|
|
||||||
# some threads
|
# some threads
|
||||||
self.message_thread = threading.Thread(target=self.message_loop)
|
self.message_thread = threading.Thread(target=self.message_loop)
|
||||||
self.event_dispatch_thread = threading.Thread(target=self.event_dispatch)
|
self.event_dispatch_thread = threading.Thread(
|
||||||
|
target=self.event_dispatch)
|
||||||
|
|
||||||
self.message_thread.setDaemon(True)
|
self.message_thread.setDaemon(True)
|
||||||
self.event_dispatch_thread.setDaemon(True)
|
self.event_dispatch_thread.setDaemon(True)
|
||||||
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
@ -241,18 +245,19 @@ class Manager(object):
|
||||||
cdict.update(kwargs)
|
cdict.update(kwargs)
|
||||||
|
|
||||||
# set the action id
|
# set the action id
|
||||||
if not cdict.has_key('ActionID'): cdict['ActionID'] = '%s-%08x' % (self.hostname, self.next_seq())
|
if 'ActionID' not in cdict:
|
||||||
|
cdict['ActionID'] = '%s-%08x' % (self.hostname, self.next_seq())
|
||||||
clist = []
|
clist = []
|
||||||
|
|
||||||
# generate the command
|
# generate the command
|
||||||
for key, value in cdict.items():
|
for key, value in cdict.items():
|
||||||
if isinstance(value, list):
|
if isinstance(value, list):
|
||||||
for item in value:
|
for item in value:
|
||||||
item = tuple([key, item])
|
item = tuple([key, item])
|
||||||
clist.append('%s: %s' % item)
|
clist.append('%s: %s' % item)
|
||||||
else:
|
else:
|
||||||
item = tuple([key, value])
|
item = tuple([key, value])
|
||||||
clist.append('%s: %s' % item)
|
clist.append('%s: %s' % item)
|
||||||
clist.append(EOL)
|
clist.append(EOL)
|
||||||
command = EOL.join(clist)
|
command = EOL.join(clist)
|
||||||
|
|
||||||
|
@ -263,7 +268,7 @@ class Manager(object):
|
||||||
except socket.error, (errno, reason):
|
except socket.error, (errno, reason):
|
||||||
raise ManagerSocketException(errno, reason)
|
raise ManagerSocketException(errno, reason)
|
||||||
|
|
||||||
self._reswaiting.insert(0,1)
|
self._reswaiting.insert(0, 1)
|
||||||
response = self._response_queue.get()
|
response = self._response_queue.get()
|
||||||
self._reswaiting.pop(0)
|
self._reswaiting.pop(0)
|
||||||
|
|
||||||
|
@ -285,7 +290,7 @@ class Manager(object):
|
||||||
while self._running.isSet() and self._connected.isSet():
|
while self._running.isSet() and self._connected.isSet():
|
||||||
try:
|
try:
|
||||||
lines = []
|
lines = []
|
||||||
for line in self._sock :
|
for line in self._sock:
|
||||||
# check to see if this is the greeting line
|
# check to see if this is the greeting line
|
||||||
if not self.title and '/' in line and not ':' in line:
|
if not self.title and '/' in line and not ':' in line:
|
||||||
# store the title of the manager we are connecting to:
|
# store the title of the manager we are connecting to:
|
||||||
|
@ -293,8 +298,8 @@ class Manager(object):
|
||||||
# store the version of the manager we are connecting to:
|
# store the version of the manager we are connecting to:
|
||||||
self.version = line.split('/')[1].strip()
|
self.version = line.split('/')[1].strip()
|
||||||
# fake message header
|
# fake message header
|
||||||
lines.append ('Response: Generated Header\r\n')
|
lines.append('Response: Generated Header\r\n')
|
||||||
lines.append (line)
|
lines.append(line)
|
||||||
break
|
break
|
||||||
# If the line is EOL marker we have a complete message.
|
# If the line is EOL marker we have a complete message.
|
||||||
# Some commands are broken and contain a \n\r\n
|
# Some commands are broken and contain a \n\r\n
|
||||||
|
@ -302,7 +307,7 @@ class Manager(object):
|
||||||
# have such a command where the data ends with the
|
# have such a command where the data ends with the
|
||||||
# marker --END COMMAND--, so we ignore embedded
|
# marker --END COMMAND--, so we ignore embedded
|
||||||
# newlines until we see that marker
|
# newlines until we see that marker
|
||||||
if line == EOL and not wait_for_marker :
|
if line == EOL and not wait_for_marker:
|
||||||
multiline = False
|
multiline = False
|
||||||
if lines or not self._connected.isSet():
|
if lines or not self._connected.isSet():
|
||||||
break
|
break
|
||||||
|
@ -321,7 +326,7 @@ class Manager(object):
|
||||||
# Response: Follows indicates we should wait for end
|
# Response: Follows indicates we should wait for end
|
||||||
# marker --END COMMAND--
|
# marker --END COMMAND--
|
||||||
if not (multiline or status) and line.startswith('Response') and \
|
if not (multiline or status) and line.startswith('Response') and \
|
||||||
line.split(':', 1)[1].strip() == 'Follows':
|
line.split(':', 1)[1].strip() == 'Follows':
|
||||||
wait_for_marker = True
|
wait_for_marker = True
|
||||||
# same when seeing end of multiline response
|
# same when seeing end of multiline response
|
||||||
if multiline and line.startswith('--END COMMAND--'):
|
if multiline and line.startswith('--END COMMAND--'):
|
||||||
|
@ -347,7 +352,6 @@ class Manager(object):
|
||||||
self._connected.clear()
|
self._connected.clear()
|
||||||
self._message_queue.put(None)
|
self._message_queue.put(None)
|
||||||
|
|
||||||
|
|
||||||
def register_event(self, event, function):
|
def register_event(self, event, function):
|
||||||
"""
|
"""
|
||||||
Register a callback for the specfied event.
|
Register a callback for the specfied event.
|
||||||
|
@ -410,7 +414,6 @@ class Manager(object):
|
||||||
# wait for our data receiving thread to exit
|
# wait for our data receiving thread to exit
|
||||||
t.join()
|
t.join()
|
||||||
|
|
||||||
|
|
||||||
def event_dispatch(self):
|
def event_dispatch(self):
|
||||||
"""This thread is responsible for dispatching events"""
|
"""This thread is responsible for dispatching events"""
|
||||||
|
|
||||||
|
@ -427,12 +430,12 @@ class Manager(object):
|
||||||
|
|
||||||
# first build a list of the functions to execute
|
# first build a list of the functions to execute
|
||||||
callbacks = (self._event_callbacks.get(ev.name, [])
|
callbacks = (self._event_callbacks.get(ev.name, [])
|
||||||
+ self._event_callbacks.get('*', []))
|
+ self._event_callbacks.get('*', []))
|
||||||
|
|
||||||
# now execute the functions
|
# now execute the functions
|
||||||
for callback in callbacks:
|
for callback in callbacks:
|
||||||
if callback(ev, self):
|
if callback(ev, self):
|
||||||
break
|
break
|
||||||
|
|
||||||
def connect(self, host, port=5038):
|
def connect(self, host, port=5038):
|
||||||
"""Connect to the manager interface"""
|
"""Connect to the manager interface"""
|
||||||
|
@ -448,9 +451,9 @@ class Manager(object):
|
||||||
# create our socket and connect
|
# create our socket and connect
|
||||||
try:
|
try:
|
||||||
_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
_sock.connect((host,port))
|
_sock.connect((host, port))
|
||||||
self._sock = _sock.makefile ()
|
self._sock = _sock.makefile()
|
||||||
_sock.close ()
|
_sock.close()
|
||||||
except socket.error, (errno, reason):
|
except socket.error, (errno, reason):
|
||||||
raise ManagerSocketException(errno, reason)
|
raise ManagerSocketException(errno, reason)
|
||||||
|
|
||||||
|
@ -493,26 +496,26 @@ class Manager(object):
|
||||||
def login(self, username, secret):
|
def login(self, username, secret):
|
||||||
"""Login to the manager, throws ManagerAuthException when login falis"""
|
"""Login to the manager, throws ManagerAuthException when login falis"""
|
||||||
|
|
||||||
cdict = {'Action':'Login'}
|
cdict = {'Action': 'Login'}
|
||||||
cdict['Username'] = username
|
cdict['Username'] = username
|
||||||
cdict['Secret'] = secret
|
cdict['Secret'] = secret
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
if response.get_header('Response') == 'Error':
|
if response.get_header('Response') == 'Error':
|
||||||
raise ManagerAuthException(response.get_header('Message'))
|
raise ManagerAuthException(response.get_header('Message'))
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def ping(self):
|
def ping(self):
|
||||||
"""Send a ping action to the manager"""
|
"""Send a ping action to the manager"""
|
||||||
cdict = {'Action':'Ping'}
|
cdict = {'Action': 'Ping'}
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def logoff(self):
|
def logoff(self):
|
||||||
"""Logoff from the manager"""
|
"""Logoff from the manager"""
|
||||||
|
|
||||||
cdict = {'Action':'Logoff'}
|
cdict = {'Action': 'Logoff'}
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
@ -520,16 +523,16 @@ class Manager(object):
|
||||||
def hangup(self, channel):
|
def hangup(self, channel):
|
||||||
"""Hangup the specified channel"""
|
"""Hangup the specified channel"""
|
||||||
|
|
||||||
cdict = {'Action':'Hangup'}
|
cdict = {'Action': 'Hangup'}
|
||||||
cdict['Channel'] = channel
|
cdict['Channel'] = channel
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def status(self, channel = ''):
|
def status(self, channel=''):
|
||||||
"""Get a status message from asterisk"""
|
"""Get a status message from asterisk"""
|
||||||
|
|
||||||
cdict = {'Action':'Status'}
|
cdict = {'Action': 'Status'}
|
||||||
cdict['Channel'] = channel
|
cdict['Channel'] = channel
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
|
@ -538,12 +541,14 @@ class Manager(object):
|
||||||
def redirect(self, channel, exten, priority='1', extra_channel='', context=''):
|
def redirect(self, channel, exten, priority='1', extra_channel='', context=''):
|
||||||
"""Redirect a channel"""
|
"""Redirect a channel"""
|
||||||
|
|
||||||
cdict = {'Action':'Redirect'}
|
cdict = {'Action': 'Redirect'}
|
||||||
cdict['Channel'] = channel
|
cdict['Channel'] = channel
|
||||||
cdict['Exten'] = exten
|
cdict['Exten'] = exten
|
||||||
cdict['Priority'] = priority
|
cdict['Priority'] = priority
|
||||||
if context: cdict['Context'] = context
|
if context:
|
||||||
if extra_channel: cdict['ExtraChannel'] = extra_channel
|
cdict['Context'] = context
|
||||||
|
if extra_channel:
|
||||||
|
cdict['ExtraChannel'] = extra_channel
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
@ -551,19 +556,27 @@ class Manager(object):
|
||||||
def originate(self, channel, exten, context='', priority='', timeout='', caller_id='', async=False, account='', variables={}):
|
def originate(self, channel, exten, context='', priority='', timeout='', caller_id='', async=False, account='', variables={}):
|
||||||
"""Originate a call"""
|
"""Originate a call"""
|
||||||
|
|
||||||
cdict = {'Action':'Originate'}
|
cdict = {'Action': 'Originate'}
|
||||||
cdict['Channel'] = channel
|
cdict['Channel'] = channel
|
||||||
cdict['Exten'] = exten
|
cdict['Exten'] = exten
|
||||||
if context: cdict['Context'] = context
|
if context:
|
||||||
if priority: cdict['Priority'] = priority
|
cdict['Context'] = context
|
||||||
if timeout: cdict['Timeout'] = timeout
|
if priority:
|
||||||
if caller_id: cdict['CallerID'] = caller_id
|
cdict['Priority'] = priority
|
||||||
if async: cdict['Async'] = 'yes'
|
if timeout:
|
||||||
if account: cdict['Account'] = account
|
cdict['Timeout'] = timeout
|
||||||
|
if caller_id:
|
||||||
|
cdict['CallerID'] = caller_id
|
||||||
|
if async:
|
||||||
|
cdict['Async'] = 'yes'
|
||||||
|
if account:
|
||||||
|
cdict['Account'] = account
|
||||||
# join dict of vairables together in a string in the form of 'key=val|key=val'
|
# join dict of vairables together in a string in the form of 'key=val|key=val'
|
||||||
# with the latest CVS HEAD this is no longer necessary
|
# with the latest CVS HEAD this is no longer necessary
|
||||||
# if variables: cdict['Variable'] = '|'.join(['='.join((str(key), str(value))) for key, value in variables.items()])
|
# if variables: cdict['Variable'] = '|'.join(['='.join((str(key), str(value))) for key, value in variables.items()])
|
||||||
if variables: cdict['Variable'] = ['='.join((str(key), str(value))) for key, value in variables.items()]
|
if variables:
|
||||||
|
cdict['Variable'] = ['='.join(
|
||||||
|
(str(key), str(value))) for key, value in variables.items()]
|
||||||
|
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
|
@ -572,7 +585,7 @@ class Manager(object):
|
||||||
def mailbox_status(self, mailbox):
|
def mailbox_status(self, mailbox):
|
||||||
"""Get the status of the specfied mailbox"""
|
"""Get the status of the specfied mailbox"""
|
||||||
|
|
||||||
cdict = {'Action':'MailboxStatus'}
|
cdict = {'Action': 'MailboxStatus'}
|
||||||
cdict['Mailbox'] = mailbox
|
cdict['Mailbox'] = mailbox
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
|
@ -581,7 +594,7 @@ class Manager(object):
|
||||||
def command(self, command):
|
def command(self, command):
|
||||||
"""Execute a command"""
|
"""Execute a command"""
|
||||||
|
|
||||||
cdict = {'Action':'Command'}
|
cdict = {'Action': 'Command'}
|
||||||
cdict['Command'] = command
|
cdict['Command'] = command
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
|
@ -590,16 +603,16 @@ class Manager(object):
|
||||||
def extension_state(self, exten, context):
|
def extension_state(self, exten, context):
|
||||||
"""Get the state of an extension"""
|
"""Get the state of an extension"""
|
||||||
|
|
||||||
cdict = {'Action':'ExtensionState'}
|
cdict = {'Action': 'ExtensionState'}
|
||||||
cdict['Exten'] = exten
|
cdict['Exten'] = exten
|
||||||
cdict['Context'] = context
|
cdict['Context'] = context
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def playdtmf (self, channel, digit) :
|
def playdtmf(self, channel, digit):
|
||||||
"""Plays a dtmf digit on the specified channel"""
|
"""Plays a dtmf digit on the specified channel"""
|
||||||
cdict = {'Action':'PlayDTMF'}
|
cdict = {'Action': 'PlayDTMF'}
|
||||||
cdict['Channel'] = channel
|
cdict['Channel'] = channel
|
||||||
cdict['Digit'] = digit
|
cdict['Digit'] = digit
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
@ -609,7 +622,7 @@ class Manager(object):
|
||||||
def absolute_timeout(self, channel, timeout):
|
def absolute_timeout(self, channel, timeout):
|
||||||
"""Set an absolute timeout on a channel"""
|
"""Set an absolute timeout on a channel"""
|
||||||
|
|
||||||
cdict = {'Action':'AbsoluteTimeout'}
|
cdict = {'Action': 'AbsoluteTimeout'}
|
||||||
cdict['Channel'] = channel
|
cdict['Channel'] = channel
|
||||||
cdict['Timeout'] = timeout
|
cdict['Timeout'] = timeout
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
@ -617,25 +630,31 @@ class Manager(object):
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def mailbox_count(self, mailbox):
|
def mailbox_count(self, mailbox):
|
||||||
cdict = {'Action':'MailboxCount'}
|
cdict = {'Action': 'MailboxCount'}
|
||||||
cdict['Mailbox'] = mailbox
|
cdict['Mailbox'] = mailbox
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def sippeers(self):
|
def sippeers(self):
|
||||||
cdict = {'Action' : 'Sippeers'}
|
cdict = {'Action': 'Sippeers'}
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def sipshowpeer(self, peer):
|
def sipshowpeer(self, peer):
|
||||||
cdict = {'Action' : 'SIPshowpeer'}
|
cdict = {'Action': 'SIPshowpeer'}
|
||||||
cdict['Peer'] = peer
|
cdict['Peer'] = peer
|
||||||
response = self.send_action(cdict)
|
response = self.send_action(cdict)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
class ManagerException(Exception): pass
|
class ManagerException(Exception):
|
||||||
class ManagerSocketException(ManagerException): pass
|
pass
|
||||||
class ManagerAuthException(ManagerException): pass
|
|
||||||
|
|
||||||
|
|
||||||
|
class ManagerSocketException(ManagerException):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ManagerAuthException(ManagerException):
|
||||||
|
pass
|
||||||
|
|
72
setup.py
72
setup.py
|
@ -6,45 +6,43 @@ from asterisk import __version__ as version
|
||||||
|
|
||||||
|
|
||||||
description = []
|
description = []
|
||||||
f = open ('README')
|
f = open('README')
|
||||||
|
|
||||||
logo_stripped = False
|
logo_stripped = False
|
||||||
for line in f :
|
for line in f:
|
||||||
if not logo_stripped and line.strip () :
|
if not logo_stripped and line.strip():
|
||||||
continue
|
continue
|
||||||
logo_stripped = True
|
logo_stripped = True
|
||||||
description.append (line)
|
description.append(line)
|
||||||
|
|
||||||
licenses = ( 'Python Software Foundation License'
|
licenses = ('Python Software Foundation License',
|
||||||
, 'GNU Library or Lesser General Public License (LGPL)'
|
'GNU Library or Lesser General Public License (LGPL)')
|
||||||
)
|
|
||||||
|
|
||||||
|
setup(
|
||||||
setup \
|
name='pyst2',
|
||||||
( name = 'pyst2'
|
version=version,
|
||||||
, version = version
|
description='A Python Interface to Asterisk',
|
||||||
, description = 'A Python Interface to Asterisk'
|
long_description=''.join(description), author='Karl Putland',
|
||||||
, long_description = ''.join (description)
|
author_email='kputland@users.sourceforge.net',
|
||||||
, author = 'Karl Putland'
|
maintainer='Randall Degges',
|
||||||
, author_email = 'kputland@users.sourceforge.net'
|
maintainer_email='rdegges@gmail.com',
|
||||||
, maintainer = 'Randall Degges'
|
url='http://www.sourceforge.net/projects/pyst/',
|
||||||
, maintainer_email = 'rdegges@gmail.com'
|
packages=['asterisk'],
|
||||||
, url = 'http://www.sourceforge.net/projects/pyst/'
|
license=', '.join(licenses),
|
||||||
, packages = ['asterisk']
|
platforms='Any',
|
||||||
, license = ', '.join (licenses)
|
classifiers=[
|
||||||
, platforms = 'Any'
|
'Development Status :: 5 - Production/Stable',
|
||||||
, classifiers =
|
'Environment :: Other Environment',
|
||||||
[ 'Development Status :: 5 - Production/Stable'
|
'Intended Audience :: Developers',
|
||||||
, 'Environment :: Other Environment'
|
'Intended Audience :: Telecommunications Industry',
|
||||||
, 'Intended Audience :: Developers'
|
'Operating System :: OS Independent',
|
||||||
, 'Intended Audience :: Telecommunications Industry'
|
'Programming Language :: Python',
|
||||||
, 'Operating System :: OS Independent'
|
'Programming Language :: Python :: 2.4',
|
||||||
, 'Programming Language :: Python'
|
'Programming Language :: Python :: 2.5',
|
||||||
, 'Programming Language :: Python :: 2.4'
|
'Programming Language :: Python :: 2.6',
|
||||||
, 'Programming Language :: Python :: 2.5'
|
'Programming Language :: Python :: 2.7',
|
||||||
, 'Programming Language :: Python :: 2.6'
|
'Topic :: Communications :: Internet Phone',
|
||||||
, 'Programming Language :: Python :: 2.7'
|
'Topic :: Communications :: Telephony',
|
||||||
, 'Topic :: Communications :: Internet Phone'
|
'Topic :: Software Development :: Libraries :: Python Modules'
|
||||||
, 'Topic :: Communications :: Telephony'
|
] + ['License :: OSI Approved :: ' + l for l in licenses]
|
||||||
, 'Topic :: Software Development :: Libraries :: Python Modules'
|
)
|
||||||
] + ['License :: OSI Approved :: ' + l for l in licenses]
|
|
||||||
)
|
|
||||||
|
|
Loading…
Reference in New Issue