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