From 5012994b1a498916096b7925e2bc7dfdd470c3ad Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:25:55 -0700 Subject: [PATCH 01/17] Removing trailing whitespace from README. --- README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README b/README index 2e8c624..45ca7e8 100644 --- a/README +++ b/README @@ -44,7 +44,7 @@ package can only be run on Asterisk platforms. Credits ------- -Thanks to Karl Putland for writing the original package. +Thanks to Karl Putland for writing the original package. Thanks to Matthew Nicholson for maintaining the package for some years and for handing over maintenance when he was no longer interested. @@ -154,7 +154,7 @@ Version 0.3: Minor feature enhancements New maintainer Ralf Schlatterbeck, this is my first release, please report any problems via the Sourceforge Bug-Tracker or email me -directly. Thanks to Karl Putland for writing the original package. +directly. Thanks to Karl Putland for writing the original package. Thanks to Matthew Nicholson for maintaining the package for some years and for handing over maintenance when he was no longer interested. The parsing of answers from asterisk was completely rewritten. This From 5109880bf59cf85e65121542664bed9662834b55 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:26:25 -0700 Subject: [PATCH 02/17] Removing sourceforge logo from README. --- README | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README b/README index 45ca7e8..8b43de0 100644 --- a/README +++ b/README @@ -1,9 +1,3 @@ -.. image:: http://sflogo.sourceforge.net/sflogo.php?group_id=134329&type=7 - :height: 62 - :width: 210 - :alt: SourceForge.net Logo - :target: http://sourceforge.net/projects/pyst/ - pyst: A Python Interface to Asterisk ==================================== From 92f257474d51ee07c429e84526f9666ad68bf964 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:27:15 -0700 Subject: [PATCH 03/17] Removing trailing whitespace from ChangeLog. --- ChangeLog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index b2b58a0..daf17f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,14 +28,14 @@ and quoted arguments. 2006-10-24 Matthew Nicholson - + * asterisk/agi.py: Added get_variable_full command. 2006-10-18 Matthew Nicholson * asterisk/agitb.py: Make error output default to sys.stderr instead of sys.stdout. - + 2006-09-19 Matthew Nicholson * debian/control: Removed XS-Python-Versions header to make it default From caa2ba7f10ec1a29e82c2f553a80e7324b9f4cbc Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:27:38 -0700 Subject: [PATCH 04/17] Renaming ChangeLog -> CHANGELOG. Looks a lot nicer this way. --- ChangeLog => CHANGELOG | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename ChangeLog => CHANGELOG (100%) diff --git a/ChangeLog b/CHANGELOG similarity index 100% rename from ChangeLog rename to CHANGELOG From 3327fe4764431c1815f0395be0fdb70259c9bd01 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:48:16 -0700 Subject: [PATCH 05/17] Updating project name in setup.py. Changing to `pyst2` (forked name). --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 251ef48..6f335f2 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ licenses = ( 'Python Software Foundation License' setup \ - ( name = 'pyst' + ( name = 'pyst2' , version = VERSION , description = 'A Python Interface to Asterisk' , long_description = ''.join (description) From 9f08b0171b8a5397e19937df9980ea5630663a46 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:48:55 -0700 Subject: [PATCH 06/17] Removing rpm specs. This is a python package--should have all of this stuff stored separately out of the project code. --- rpm/python-pyst.spec | 48 -------------------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 rpm/python-pyst.spec diff --git a/rpm/python-pyst.spec b/rpm/python-pyst.spec deleted file mode 100644 index c793ee8..0000000 --- a/rpm/python-pyst.spec +++ /dev/null @@ -1,48 +0,0 @@ -Summary: An interface to AGI -Name: python-pyst -Version: 0.0.5 -Release: 2.centos4.0 -Source0: http://prdownloads.sourceforge.net/pyst/pyst-%{version}.tar.gz -License: LGPL -Group: Development/Libraries -BuildRoot: %{_tmppath}/%{name}-buildroot -URL: http://sourceforge.net/projects/pyst -Requires: python -BuildRequires: python-devel -BuildRequires: python Distutils - -%description -Pyst consists of a set of interfaces and libraries to allow -programming of Asterisk from python. The library currently -supports AGI, AMI, and the parsing of Asterisk configuration -files. The library also includes debugging facilities for AGI. - -%prep -%setup -q -n pyst-%{version} - -%build -CFLAGS="$RPM_OPT_FLAGS" python setup.py build - -%install -python setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES -mkdir -p $RPM_BUILD_ROOT/usr/share/doc/python-pyst -cp debian/copyright $RPM_BUILD_ROOT/usr/share/doc/python-pyst - -%clean -rm -rf $RPM_BUILD_ROOT - -%files -f INSTALLED_FILES -%defattr(-,root,root) -%doc /usr/share/doc/python-pyst/* -%{_libdir}/python*/site-packages/asterisk/ - -%changelog -* Tue Mar 21 2006 Matthew Nicholson el4.3 -- Bumped version number. - -* Thu Feb 23 2006 Antoine Brenner el4.2 -- Fixed source0 line - -* Tue Feb 9 2006 Antoine Brenner el4.1 -- Initial Package - From 73d509255969ba1b29642f10e4701c67b3342551 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:49:34 -0700 Subject: [PATCH 07/17] Removing debian files. These should be kept separately, not with the project code. This package is the python package (for pip!). This stuff should be dealt with by the debian maintainer. --- debian/changelog | 63 -------------------------------------- debian/compat | 1 - debian/control | 21 ------------- debian/copyright | 79 ------------------------------------------------ debian/rules | 10 ------ debian/watch | 3 -- 6 files changed, 177 deletions(-) delete mode 100644 debian/changelog delete mode 100644 debian/compat delete mode 100644 debian/control delete mode 100644 debian/copyright delete mode 100755 debian/rules delete mode 100644 debian/watch diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 0053b7b..0000000 --- a/debian/changelog +++ /dev/null @@ -1,63 +0,0 @@ -pyst (0.2-1) unstable; urgency=low - - * New release. - * Package updated to reflect new python policy. - - -- Matthew Nicholson Tue, 19 Sep 2006 19:22:51 -0500 - -pyst (0.1.0-1) unstable; urgency=low - - * New release. - - -- Matthew Nicholson Mon, 5 Jun 2006 15:11:24 -0500 - -pyst (0.0.4rc13-1) unstable; urgency=low - - * New release. - - -- Matthew Nicholson Tue, 21 Mar 2006 12:25:03 -0600 - -pyst (0.0.4rc12-1) unstable; urgency=low - - * New release. - - -- Matthew Nicholson Thu, 14 Apr 2005 17:15:46 -0500 - -pyst (0.0.4rc11-1) unstable; urgency=low - - * New release. - - -- Matthew Nicholson Thu, 3 Feb 2005 18:46:32 -0600 - -pyst (0.0.4rc10-1) unstable; urgency=low - - * Bug fixes in config.py and more docs. - * Version number correction. - * Added line number tracking to config.py - - -- Matthew Nicholson Tue, 11 Jan 2005 11:30:59 -0600 - -pyst (0.0.4rc9-1) unstable; urgency=low - - * Removed DEBUG flag - - -- Matthew Nicholson Mon, 10 Jan 2005 18:40:04 -0600 - -pyst (0.0.4rc8-1) unstable; urgency=low - - * More manager.py updates - - -- Matthew Nicholson Thu, 6 Jan 2005 12:19:42 -0600 - -pyst (0.0.4rc7-1) unstable; urgency=low - - * A bunch of fixes to make the manager interface useable - - -- Matthew Nicholson Wed, 5 Jan 2005 19:02:38 -0600 - -pyst (0.0.4rc6-1) unstable; urgency=low - - * Initial Release. - - -- Matthew Nicholson Mon, 29 Nov 2004 14:06:42 -0600 - diff --git a/debian/compat b/debian/compat deleted file mode 100644 index b8626c4..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -4 diff --git a/debian/control b/debian/control deleted file mode 100644 index 1e4a037..0000000 --- a/debian/control +++ /dev/null @@ -1,21 +0,0 @@ -Source: pyst -Section: python -Priority: optional -Maintainer: Matthew Nicholson -Build-Depends-Indep: debhelper (>= 5.0.37.2), cdbs (>= 0.4.43), python-all-dev (>= 2.3.5-11), python-support (>= 0.3) -Standards-Version: 3.6.1 - -Package: python-pyst -Architecture: all -Depends: ${python:Depends} -Provides: ${python:Provides} -Replaces: python2.3-pyst (<< 0.2) -Conflicts: python2.3-pyst (<< 0.2) -XB-Python-Version: ${python:Versions} -Suggests: asterisk -Description: Python module for interacting with the Asterisk PBX (dummy) - Pyst is a python module for interacting with the asterisk pbx through - the manager interface and agi interface. This package also includes - debugging tools such as the agitb module, and tools to parse asterisk - config files. - diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 19c1736..0000000 --- a/debian/copyright +++ /dev/null @@ -1,79 +0,0 @@ -This package was debianized by Matthew Nicholson on -Mon, 29 Nov 2004 14:06:42 -0600. - -It was downloaded from http://ftp1.sourceforge.net/pyst/pyst-0.0.4.tar.gz - -Copyright (C) 2004 Karl Putland - -Upstream Author: Karl Putland - -License: - -Most of pyst is licensed under the terms of the GNU LGPL. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -The agitb.py modules is licensed under the terms of the Python Software -Foundation License: - -PSF LICENSE AGREEMENT FOR PYTHON 2.3 ------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using Python 2.3 software in source or binary form and its -associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 2.3 -alone or in any derivative version, provided, however, that PSF's -License Agreement and PSF's notice of copyright, i.e., "Copyright (c) -2001, 2002 Python Software Foundation; All Rights Reserved" are -retained in Python 2.3 alone or in any derivative version prepared by -Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 2.3 or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 2.3. - -4. PSF is making Python 2.3 available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.3 WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -2.3 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.3, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python 2.3, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 82f8489..0000000 --- a/debian/rules +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/make -f - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -DEB_PYTHON_SYSTEM=pysupport - -include /usr/share/cdbs/1/rules/debhelper.mk -include /usr/share/cdbs/1/class/python-distutils.mk - diff --git a/debian/watch b/debian/watch deleted file mode 100644 index f761a92..0000000 --- a/debian/watch +++ /dev/null @@ -1,3 +0,0 @@ -# Site Directory Pattern Version Script -version=2 -http://ftp1.sourceforge.net/pyst/pyst-(.*)\.tar\.gz debian uupdate From 5f8112eea9e19b847ada5e0638ff9fc3bdaed8c8 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:50:25 -0700 Subject: [PATCH 08/17] Removing debian/rpm includes from MANIFEST.in. --- MANIFEST.in | 7 ------- 1 file changed, 7 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index e435903..2a437ae 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,10 +1,3 @@ -include debian/watch -include debian/rules -include debian/changelog -include debian/control -include debian/compat -include debian/copyright -include rpm/python-pyst.spec include ChangeLog include README include README.html From 8bc535826881721a518568b3490ecb6bd9a749fa Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:50:42 -0700 Subject: [PATCH 09/17] Adding CHANGELOG to MANIFEST.in. --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 2a437ae..c8cef7e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include ChangeLog +include CHANGELOG include README include README.html include MANIFEST.in From c468e105cdf83299110dc110de452fcb0237afc0 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:51:23 -0700 Subject: [PATCH 10/17] Removing README.html from MANIFEST.in. This file doesn't exist... --- MANIFEST.in | 1 - 1 file changed, 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index c8cef7e..5a7b17f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,3 @@ include CHANGELOG include README -include README.html include MANIFEST.in From ff3cd79f080cb17c4c3006ad30c8c56821a5d0ec Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:53:55 -0700 Subject: [PATCH 11/17] Adding a note to the README file about the fork. --- README | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README b/README index 8b43de0..eae2adb 100644 --- a/README +++ b/README @@ -35,6 +35,17 @@ directly on the host where Asterisk is running. Since Asterisk doesn't run on windows platforms (and probably never will) the agi part of the package can only be run on Asterisk platforms. +.. note:: + This project has been forked because it was impossible for me to contact + the project maintainer (after several attempts), and I'd like to bring the + project up-to-date, fix bugs, and make it more usable overall. + + My plans immediate plans include adding full documentation, re-writing some + of the core routines, adding a test suite, and accepting pull requests. + + If you are one of the current maintainers, and would like to take over the + fork, please contact me: rdegges@gmail.com, so we can get that setup! + Credits ------- From c1b0b6657fa7f214729112585fc6fefe8ecdf4af Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:56:06 -0700 Subject: [PATCH 12/17] Adding myself as the maintainer. --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 6f335f2..14ea3fc 100644 --- a/setup.py +++ b/setup.py @@ -28,8 +28,8 @@ setup \ , long_description = ''.join (description) , author = 'Karl Putland' , author_email = 'kputland@users.sourceforge.net' - , maintainer = 'Ralf Schlatterbeck' - , maintainer_email = 'rsc@runtux.com' + , maintainer = 'Randall Degges' + , maintainer_email = 'rdegges@gmail.com' , url = 'http://www.sourceforge.net/projects/pyst/' , packages = ['asterisk'] , license = ', '.join (licenses) From 85fc17017e352433f7d9eb3028339c47a984a4c4 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 12:56:57 -0700 Subject: [PATCH 13/17] Removing trailing whitespace from files. --- asterisk/agi.py | 38 ++++++++++---------- asterisk/agitb.py | 8 ++--- asterisk/config.py | 8 ++--- asterisk/manager.py | 84 ++++++++++++++++++++++----------------------- 4 files changed, 69 insertions(+), 69 deletions(-) diff --git a/asterisk/agi.py b/asterisk/agi.py index 3b00b96..d67734a 100644 --- a/asterisk/agi.py +++ b/asterisk/agi.py @@ -52,9 +52,9 @@ class AGI: """ This class encapsulates communication between Asterisk an a python script. It handles encoding commands to Asterisk and parsing responses from - Asterisk. + Asterisk. """ - + def __init__(self): self._got_sighup = False signal.signal(signal.SIGHUP, self._handle_sighup) # handle SIGHUP @@ -93,7 +93,7 @@ class AGI: """This function throws AGIHangup if we have recieved a SIGHUP""" if self._got_sighup: raise AGISIGHUPHangup("Received SIGHUP from Asterisk") - + def execute(self, command, *args): self.test_hangup() @@ -208,17 +208,17 @@ class AGI: def tdd_mode(self, mode='off'): """agi.tdd_mode(mode='on'|'off') --> None - Enable/Disable TDD transmission/reception on a channel. + Enable/Disable TDD transmission/reception on a channel. Throws AGIAppError if channel is not TDD-capable. """ res = self.execute('TDD MODE', mode)['result'][0] if res == '0': raise AGIAppError('Channel %s is not TDD-capable') - + def stream_file(self, filename, escape_digits='', sample_offset=0): """agi.stream_file(filename, escape_digits='', sample_offset=0) --> digit Send the given file, allowing playback to be interrupted by the given - digits, if any. escape_digits is a string '12345' or a list of + digits, if any. escape_digits is a string '12345' or a list of ints [1,2,3,4,5] or strings ['1','2','3'] or mixed [1,'2',3,'4'] If sample offset is provided then the audio will seek to sample offset before play starts. Returns digit if one was pressed. @@ -235,11 +235,11 @@ class AGI: return chr(int(res)) except: raise AGIError('Unable to convert result to char: %s' % res) - + def control_stream_file(self, filename, escape_digits='', skipms=3000, fwd='', rew='', pause=''): """ Send the given file, allowing playback to be interrupted by the given - digits, if any. escape_digits is a string '12345' or a list of + digits, if any. escape_digits is a string '12345' or a list of ints [1,2,3,4,5] or strings ['1','2','3'] or mixed [1,'2',3,'4'] If sample offset is provided then the audio will seek to sample offset before play starts. Returns digit if one was pressed. @@ -270,7 +270,7 @@ class AGI: def say_digits(self, digits, escape_digits=''): """agi.say_digits(digits, escape_digits='') --> digit Say a given digit string, returning early if any of the given DTMF digits - are received on the channel. + are received on the channel. Throws AGIError on channel failure """ digits = self._process_digit_list(digits) @@ -287,7 +287,7 @@ class AGI: def say_number(self, number, escape_digits=''): """agi.say_number(number, escape_digits='') --> digit Say a given digit string, returning early if any of the given DTMF digits - are received on the channel. + are received on the channel. Throws AGIError on channel failure """ number = self._process_digit_list(number) @@ -304,7 +304,7 @@ class AGI: def say_alpha(self, characters, escape_digits=''): """agi.say_alpha(string, escape_digits='') --> digit Say a given character string, returning early if any of the given DTMF - digits are received on the channel. + digits are received on the channel. Throws AGIError on channel failure """ characters = self._process_digit_list(characters) @@ -321,7 +321,7 @@ class AGI: def say_phonetic(self, characters, escape_digits=''): """agi.say_phonetic(string, escape_digits='') --> digit Phonetically say a given character string, returning early if any of - the given DTMF digits are received on the channel. + the given DTMF digits are received on the channel. Throws AGIError on channel failure """ characters = self._process_digit_list(characters) @@ -364,7 +364,7 @@ class AGI: return chr(int(res)) except: raise AGIError('Unable to convert result to char: %s' % res) - + def say_datetime(self, seconds, escape_digits='', format='', zone=''): """agi.say_datetime(seconds, escape_digits='', format='', zone='') --> digit Say a given date in the format specfied (see voicemail.conf), returning @@ -389,11 +389,11 @@ class AGI: result = self.execute('GET DATA', filename, timeout, max_digits) res, value = result['result'] return res - + def get_option(self, filename, escape_digits='', timeout=0): """agi.get_option(filename, escape_digits='', timeout=0) --> digit Send the given file, allowing playback to be interrupted by the given - digits, if any. escape_digits is a string '12345' or a list of + digits, if any. escape_digits is a string '12345' or a list of ints [1,2,3,4,5] or strings ['1','2','3'] or mixed [1,'2',3,'4'] Returns digit if one was pressed. Throws AGIError if the channel was disconnected. Remember, the file @@ -449,9 +449,9 @@ class AGI: def record_file(self, filename, format='gsm', escape_digits='#', timeout=DEFAULT_RECORD, offset=0, beep='beep'): """agi.record_file(filename, format, escape_digits, timeout=DEFAULT_TIMEOUT, offset=0, beep='beep') --> None Record to a file until a given dtmf digit in the sequence is received - The format will specify what kind of file will be recorded. The timeout - is the maximum record time in milliseconds, or -1 for no timeout. Offset - samples is optional, and if provided will seek to the offset without + The format will specify what kind of file will be recorded. The timeout + is the maximum record time in milliseconds, or -1 for no timeout. Offset + samples is optional, and if provided will seek to the offset without exceeding the end of the file """ escape_digits = self._process_digit_list(escape_digits) @@ -589,7 +589,7 @@ class AGI: res, value = result['result'] if res == '0': raise AGIDBError('Unable to put vaule in databale: family=%s, key=%s, value=%s' % (family, key, value)) - + def database_del(self, family, key): """agi.database_del(family, key) --> None Deletes an entry in the Asterisk database for a diff --git a/asterisk/agitb.py b/asterisk/agitb.py index f13c76f..9eea166 100644 --- a/asterisk/agitb.py +++ b/asterisk/agitb.py @@ -12,7 +12,7 @@ at the top of your script. The optional arguments to enable() are: agi - the agi handle to write verbose messages to display - if true, tracebacks are displayed on the asterisk console - (used with the agi option) + (used with the agi option) logdir - if set, tracebacks are written to files in this directory context - number of lines of source code to show for each stack frame @@ -194,7 +194,7 @@ class Hook: self.agi.verbose(msg, 4) else: self.file.write(msg + '\n') - + try: self.file.flush() except: pass @@ -210,7 +210,7 @@ def enable(agi=None, display=1, logdir=None, context=5): except_hook = Hook(display=display, logdir=logdir, context=context, agi=agi) sys.excepthook = except_hook - + global handler handler = except_hook.handle - + diff --git a/asterisk/config.py b/asterisk/config.py index 3326e28..916f636 100644 --- a/asterisk/config.py +++ b/asterisk/config.py @@ -7,7 +7,7 @@ This module provides parsing functionality for asterisk config files. import asterisk.config import sys - + # load and parse the config file try: config = asterisk.config.Config('/etc/asterisk/extensions.conf') @@ -68,7 +68,7 @@ class Category(Line): self.items = [] self.comments = [] - + def get_line(self): if self.comment: return '[%s]\t;%s' % (self.name, self.comment) @@ -86,7 +86,7 @@ class Category(Line): def remove(self, item): self.items.remove(item) - + class Item(Line): def __init__(self, line='', num=-1, name=None, value=None): Line.__init__(self, line, num) @@ -98,7 +98,7 @@ class Item(Line): self.value = value else: raise Exception("Must provide name or value representing an item") - + def parse(self): try: name, value = self.line.split('=', 1) diff --git a/asterisk/manager.py b/asterisk/manager.py index 7b3a74b..da183f0 100644 --- a/asterisk/manager.py +++ b/asterisk/manager.py @@ -13,21 +13,21 @@ This module provides a Python API for interfacing with the asterisk manager. print "Recieved shutdown event" manager.close() # we could analize the event and reconnect here - + def handle_event(event, manager): print "Recieved event: %s" % event.name - + manager = asterisk.manager.Manager() try: # connect to the manager try: - manager.connect('host') + manager.connect('host') manager.login('user', 'secret') # register some callbacks manager.register_event('Shutdown', handle_shutdown) # shutdown manager.register_event('*', handle_event) # catch all - + # get a status report response = manager.status() @@ -41,7 +41,7 @@ This module provides a Python API for interfacing with the asterisk manager. except asterisk.manager.ManagerException, reason: print "Error: %s" % reason sys.exit(1) - + finally: # remember to clean up manager.close() @@ -63,14 +63,14 @@ from time import sleep EOL = '\r\n' -class ManagerMsg(object): +class ManagerMsg(object): """A manager interface message""" def __init__(self, response): # the raw response, straight from the horse's mouth: self.response = response self.data = '' self.headers = {} - + # parse the response self.parse(response) @@ -94,7 +94,7 @@ class ManagerMsg(object): self.headers['Event'] = 'NoClue' else: self.headers['Response'] = 'Generated Header' - + def parse(self, response): """Parse a manager message""" @@ -143,7 +143,7 @@ class Event(object): # 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) @@ -151,11 +151,11 @@ class Event(object): def get_header(self, hname, defval = None): """Return the specfied header""" return self.headers.get(hname, defval) - + def __getitem__(self, hname): """Return the specfied header""" return self.headers[hname] - + def __repr__(self): return self.headers['Event'] @@ -168,7 +168,7 @@ class Manager(object): self.title = None # set by received greeting self._connected = threading.Event() self._running = threading.Event() - + # our hostname self.hostname = socket.gethostname() @@ -185,11 +185,11 @@ class Manager(object): # sequence stuff self._seqlock = threading.Lock() self._seq = 0 - + # some threads self.message_thread = threading.Thread(target=self.message_loop) self.event_dispatch_thread = threading.Thread(target=self.event_dispatch) - + self.message_thread.setDaemon(True) self.event_dispatch_thread.setDaemon(True) @@ -211,11 +211,11 @@ class Manager(object): finally: self._seq += 1 self._seqlock.release() - + def send_action(self, cdict={}, **kwargs): """ Send a command to the manager - + If a list is passed to the cdict argument, each item in the list will be sent to asterisk under the same header in the following manner: @@ -232,7 +232,7 @@ class Manager(object): if not self._connected.isSet(): raise ManagerException("Not connected") - + # fill in our args cdict.update(kwargs) @@ -258,7 +258,7 @@ class Manager(object): self._sock.flush() except socket.error, (errno, reason): raise ManagerSocketException(errno, reason) - + self._reswaiting.insert(0,1) response = self._response_queue.get() self._reswaiting.pop(0) @@ -281,7 +281,7 @@ class Manager(object): try: lines = [] 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: # store the title of the manager we are connecting to: self.title = line.split('/')[0].strip() @@ -333,7 +333,7 @@ class Manager(object): self._connected.clear() self._message_queue.put(None) - + def register_event(self, event, function): """ Register a callback for the specfied event. @@ -395,7 +395,7 @@ class Manager(object): finally: # wait for our data receiving thread to exit t.join() - + def event_dispatch(self): """This thread is responsible for dispatching events""" @@ -408,14 +408,14 @@ class Manager(object): # if we got None as an event, we are finished if not ev: break - + # dispatch our events # first build a list of the functions to execute callbacks = (self._event_callbacks.get(ev.name, []) + self._event_callbacks.get('*', [])) - # now execute the functions + # now execute the functions for callback in callbacks: if callback(ev, self): break @@ -455,11 +455,11 @@ class Manager(object): def close(self): """Shutdown the connection to the manager""" - + # if we are still running, logout if self._running.isSet() and self._connected.isSet(): self.logoff() - + if self._running.isSet(): # put None in the message_queue to kill our threads self._message_queue.put(None) @@ -471,22 +471,22 @@ class Manager(object): if threading.currentThread() != self.event_dispatch_thread: # wait for the dispatch thread to exit self.event_dispatch_thread.join() - + self._running.clear() # Manager actions def login(self, username, secret): """Login to the manager, throws ManagerAuthException when login falis""" - + 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')) - + return response def ping(self): @@ -500,16 +500,16 @@ class Manager(object): cdict = {'Action':'Logoff'} response = self.send_action(cdict) - + return response def hangup(self, channel): """Hangup the specified channel""" - + cdict = {'Action':'Hangup'} cdict['Channel'] = channel response = self.send_action(cdict) - + return response def status(self, channel = ''): @@ -518,12 +518,12 @@ class Manager(object): cdict = {'Action':'Status'} cdict['Channel'] = channel response = self.send_action(cdict) - + return response def redirect(self, channel, exten, priority='1', extra_channel='', context=''): """Redirect a channel""" - + cdict = {'Action':'Redirect'} cdict['Channel'] = channel cdict['Exten'] = exten @@ -531,7 +531,7 @@ class Manager(object): if context: cdict['Context'] = context if extra_channel: cdict['ExtraChannel'] = extra_channel response = self.send_action(cdict) - + return response def originate(self, channel, exten, context='', priority='', timeout='', caller_id='', async=False, account='', variables={}): @@ -550,18 +550,18 @@ class Manager(object): # 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()] - + response = self.send_action(cdict) - + return response def mailbox_status(self, mailbox): """Get the status of the specfied mailbox""" - + cdict = {'Action':'MailboxStatus'} cdict['Mailbox'] = mailbox response = self.send_action(cdict) - + return response def command(self, command): @@ -570,7 +570,7 @@ class Manager(object): cdict = {'Action':'Command'} cdict['Command'] = command response = self.send_action(cdict) - + return response def extension_state(self, exten, context): @@ -580,7 +580,7 @@ class Manager(object): cdict['Exten'] = exten cdict['Context'] = context response = self.send_action(cdict) - + return response def playdtmf (self, channel, digit) : @@ -594,7 +594,7 @@ class Manager(object): def absolute_timeout(self, channel, timeout): """Set an absolute timeout on a channel""" - + cdict = {'Action':'AbsoluteTimeout'} cdict['Channel'] = channel cdict['Timeout'] = timeout From 60b904bf106829b2cc03322a7ffc1dcff51278ce Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 17:12:23 -0700 Subject: [PATCH 14/17] Adding in bugfix for issue with manager.status(). The problem is that the status command returns output in a special format, that was not being parsed correctly. This fix is a bit ugly, but is the only way (afaik) to cleanly handle the status command so that its output can be used. --- asterisk/manager.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/asterisk/manager.py b/asterisk/manager.py index da183f0..70541f6 100644 --- a/asterisk/manager.py +++ b/asterisk/manager.py @@ -274,6 +274,7 @@ class Manager(object): """ multiline = False + status = False wait_for_marker = False eolcount = 0 # loop while we are sill running and connected @@ -303,6 +304,11 @@ class Manager(object): break # ignore empty lines at start continue + # If the user executed the status command, it's a special + # case, so we need to look for a marker. + if 'status will follow' in line: + status = True + wait_for_marker = True lines.append(line) # line not ending in \r\n or without ':' isn't a # valid header and starts multiline response @@ -310,13 +316,17 @@ class Manager(object): multiline = True # Response: Follows indicates we should wait for end # marker --END COMMAND-- - if not multiline and line.startswith('Response') and \ + if not (multiline or status) and line.startswith('Response') and \ line.split(':', 1)[1].strip() == 'Follows': wait_for_marker = True # same when seeing end of multiline response if multiline and line.startswith('--END COMMAND--'): wait_for_marker = False multiline = False + # same when seeing end of status response + if status and 'StatusComplete' in line: + wait_for_marker = False + status = False if not self._connected.isSet(): break else: From 9782b612805bbc9f86b24b72c240b32ad72b4fa4 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 17:21:46 -0700 Subject: [PATCH 15/17] Adding sane version import code to setup module. This will allow us to actually specify a legitimate version for PyPI. --- setup.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 14ea3fc..403fc0e 100644 --- a/setup.py +++ b/setup.py @@ -2,10 +2,8 @@ from distutils.core import setup -try : - from asterisk.Version import VERSION -except : - VERSION = None +from asterisk import __version__ as version + description = [] f = open ('README') @@ -23,7 +21,7 @@ licenses = ( 'Python Software Foundation License' setup \ ( name = 'pyst2' - , version = VERSION + , version = version , description = 'A Python Interface to Asterisk' , long_description = ''.join (description) , author = 'Karl Putland' From fc8c193dcdd93ad6c74f4c237f5cebab996e6edf Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 17:22:11 -0700 Subject: [PATCH 16/17] Adding module variable __version__. --- asterisk/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/asterisk/__init__.py b/asterisk/__init__.py index 6156039..847f0b2 100644 --- a/asterisk/__init__.py +++ b/asterisk/__init__.py @@ -11,4 +11,4 @@ manager - a module for interacting with the asterisk manager interface """ __all__ = ['agi', 'agitb', 'config', 'manager'] - +__version__ = '0.4' From 35f05578177dfffd5bd326d8a0bea147572084f9 Mon Sep 17 00:00:00 2001 From: Randall Degges Date: Tue, 31 May 2011 17:24:03 -0700 Subject: [PATCH 17/17] Updating CHANGELOG. --- CHANGELOG | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index daf17f4..6f1c8d4 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +2011-05-31 Randall Degges * asterisk/manager.py: Make get_header() functions work like