[Freeswitch-svn] [commit] r5828 - freeswitch/trunk/scripts/socket/freepy

Freeswitch SVN greenlizard at freeswitch.org
Sun Oct 7 12:47:11 EDT 2007


Author: greenlizard
Date: Sun Oct  7 12:47:10 2007
New Revision: 5828

Added:
   freeswitch/trunk/scripts/socket/freepy/
   freeswitch/trunk/scripts/socket/freepy/INSTALL
   freeswitch/trunk/scripts/socket/freepy/README
   freeswitch/trunk/scripts/socket/freepy/__init__.py
   freeswitch/trunk/scripts/socket/freepy/apirequest.sm
   freeswitch/trunk/scripts/socket/freepy/apirequest_sm.py
   freeswitch/trunk/scripts/socket/freepy/bgapirequest.sm
   freeswitch/trunk/scripts/socket/freepy/bgapirequest_sm.py
   freeswitch/trunk/scripts/socket/freepy/fseventlistener.py
   freeswitch/trunk/scripts/socket/freepy/fshelper.py
   freeswitch/trunk/scripts/socket/freepy/loginrequest.sm
   freeswitch/trunk/scripts/socket/freepy/loginrequest_sm.py
   freeswitch/trunk/scripts/socket/freepy/models.py
   freeswitch/trunk/scripts/socket/freepy/request.py

Log:
event_socket connection lib for twisted python apps

Added: freeswitch/trunk/scripts/socket/freepy/INSTALL
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/INSTALL	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,4 @@
+
+- Add /path/to/freeswitch/scripts/socket to your PYTHONPATH
+- Copy/Paste the code from test1() in fshelper.py to your own test module
+- Adapt code as needed and run
\ No newline at end of file

Added: freeswitch/trunk/scripts/socket/freepy/README
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/README	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,3 @@
+
+Socket library to interface w/ freeswitch mod_event_socket from Twisted python applications.
+

Added: freeswitch/trunk/scripts/socket/freepy/__init__.py
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/__init__.py	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,336 @@
+""" 
+FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+
+Version: MPL 1.1
+
+The contents of this file are subject to the Mozilla Public License Version
+1.1 (the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+
+The Initial Developer of the Original Code is
+Anthony Minessale II <anthmct at yahoo.com>
+Portions created by the Initial Developer are Copyright (C)
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): Traun Leyden <tleyden at branchcut.com>
+"""
+
+import sys
+
+from twisted.internet import reactor, defer
+from twisted.protocols.basic import LineReceiver
+from twisted.internet.protocol import Protocol, ClientFactory
+from twisted.python import failure
+import time, re
+from time import strftime
+from Queue import Queue
+from freepy import request
+
+"""
+freepy library -- connect to freeswitch mod_socket_event via python/twisted
+
+All commands currently use api instead of bgapi.  For the networking model
+used (twisted), this seems to work well and is simpler.
+
+"""
+
+class FreepyDispatcher(LineReceiver):
+
+    def __init__(self, conncb, discocb=None):
+        self.delimiter='\n' # parent class uses this 
+        self.conncb=conncb
+        self.discocb=discocb
+        self.requestq = Queue() # queue of pending requests
+        self.active_request = None # the current active (de-queued) request
+
+    def connectionMade(self):
+        self.conncb(self)
+        
+    def connectionLost(self, reason):
+        if self.discocb:
+            self.discocb(reason)        
+        print "connectionLost: %s" % reason
+
+
+    def login(self, passwd):
+        """
+        send login request
+        """
+        msg = "auth %s" % passwd
+        req = request.LoginRequest()
+        self.requestq.put(req)
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+    def confdialout(self, conf_name, sofia_url, bgapi=True):
+        """
+        Instruct conference to join a particular user via dialout
+        @param conf_name - the name of the conference (arbitrary)
+        @param party2dial - a freeswitch sofia url, eg, sofia/mydomain.com/foo at bar.com
+        @return - a deferred that will be called back with a string like:
+                  Reply-Text: +OK Job-UUID: 4d410a8e-2409-11dc-99bf-a5e17fab9c65
+
+
+        """
+        if bgapi == True:
+            msg = "bgapi conference %s dial %s" % (conf_name,
+                                                   sofia_url)
+            req = request.BgDialoutRequest()            
+        else:
+            msg = "api conference %s dial %s" % (conf_name,
+                                                 sofia_url)
+            req = request.DialoutRequest()
+        self.requestq.put(req)
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+    def originate(self, party2dial, dest_ext_app, bgapi=True):
+
+        if bgapi == True:
+            msg = "bgapi originate %s %s" % (party2dial,
+                                             dest_ext_app)
+            req = request.BgDialoutRequest()            
+        else:
+            msg = "api originate %s %s" % (party2dial,
+                                           dest_ext_app)
+            req = request.DialoutRequest()
+        self.requestq.put(req)
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+    def listconf(self, conf_name):
+        """
+        List users in a conf
+        @param conf_name - the name of the conference (arbitrary)
+        @return - a deferred that will be called back with an array
+                  of models.ConfMember instances
+        """
+        msg = "api conference %s list" % (conf_name)
+        req = request.ListConfRequest()
+        self.requestq.put(req)
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+        
+
+    def confkick(self, member_id, conf_name, bgapi=False):
+        """
+        Kick member_id from conf
+        conf_name - name of conf
+        member_id - member id of user to kick, eg, "7"
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this        
+        """
+        if bgapi == True:
+            msg = "bgapi conference %s kick %s" % (conf_name, member_id)
+            req = request.BgConfKickRequest()
+        else:
+            msg = "api conference %s kick %s" % (conf_name, member_id)
+            req = request.ConfKickRequest()
+        self.requestq.put(req)
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+    def confdtmf(self, member_id, conf_name, dtmf, bgapi=False):
+        """
+        Send dtmf to member_id or to all members
+        conf_name - name of conf
+        member_id - member id of user to kick, eg, "7"
+        dtmf - a single dtmf or a string of dtms, eg "1" or "123"        
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this        
+        """
+        print "confdtmf called"        
+        if bgapi == True:
+            msg = "bgapi conference %s dtmf %s %s" % \
+                  (conf_name, member_id, dtmf)
+            req = request.BgApiRequest()
+        else:
+            msg = "api conference %s dtmf %s %s" % \
+                  (conf_name, member_id, dtmf)
+            req = request.ApiRequest()
+        self.requestq.put(req)
+        print "sending to fs: %s" % msg
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+    def confsay(self, conf_name, text2speak, bgapi=False):
+        """
+        Speak text all members
+        conf_name - name of conf
+        dtmf - text to speak
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this        
+        """
+        if bgapi == True:
+            msg = "bgapi conference %s say %s" % \
+                  (conf_name, text2speak)
+            req = request.BgApiRequest()
+        else:
+            msg = "api conference %s say %s" % \
+                  (conf_name, text2speak)
+            req = request.ApiRequest()
+        self.requestq.put(req)
+        print "sending to fs: %s" % msg
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+    def confplay(self, conf_name, snd_url, bgapi=False):
+        """
+        Play a file to all members
+        conf_name - name of conf
+        dtmf - text to speak
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this        
+        """
+        if bgapi == True:
+            msg = "bgapi conference %s play %s" % \
+                  (conf_name, snd_url)
+            req = request.BgApiRequest()
+        else:
+            msg = "api conference %s play %s" % \
+                  (conf_name, snd_url)
+            req = request.ApiRequest()
+        self.requestq.put(req)
+        print "sending to fs: %s" % msg
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+    def confstop(self, conf_name, bgapi=False):
+        """
+        Stop playback of all sound files
+        conf_name - name of conf
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this        
+        """
+        if bgapi == True:
+            msg = "bgapi conference %s stop" % \
+                  (conf_name)
+            req = request.BgApiRequest()
+        else:
+            msg = "api conference %s stop" % \
+                  (conf_name)
+            req = request.ApiRequest()
+        self.requestq.put(req)
+        print "sending to fs: %s" % msg
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+
+    def showchannels(self, bgapi=False):
+        """
+        Get a list of all live channels on switch
+        
+        returns - a deferred that will be called back with a result
+
+        <result row_count="2">
+          <row row_id="1">
+            <uuid>21524b8c-6d19-11dc-9380-357de4a7a612</uuid>
+            <created>2007-09-27 11:46:01</created>
+            <name>sofia/test/4761</name>
+            <state>CS_LOOPBACK</state>
+            <cid_name>FreeSWITCH</cid_name>
+            <cid_num>0000000000</cid_num>
+            <ip_addr></ip_addr>
+            <dest>outgoing2endpoint-6207463</dest>
+            <application>echo</application>
+            <application_data></application_data>
+            <read_codec>PCMU</read_codec>
+            <read_rate>8000</read_rate>
+            <write_codec>PCMU</write_codec>
+            <write_rate>8000</write_rate>
+          </row>
+          ...
+        </result>
+        """
+        if bgapi == True:
+            msg = "bgapi show channels as xml"
+            req = request.BgApiRequest()            
+        else:
+            msg = "api show channels as xml"            
+            req = request.ApiRequest()
+        self.requestq.put(req)
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+    def sofia_status_profile(self, profile_name, bgapi=False):
+        # DO NOT USE - TOTALLY BROKEN
+        # FS DOES NOT RETURN XML IN THIS CASE
+        if bgapi == True:
+            msg = "bgapi sofia status profile %s as xml" % (profile_name)
+            req = request.BgApiRequest()
+        else:
+            msg = "api sofia status profile %s as xml" % (profile_name)
+            req = request.ApiRequest()
+        self.requestq.put(req)
+        print "sending to fs: %s" % msg
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+        
+    def sofia_profile_restart(self, sofia_profile_name, bgapi = False):
+        if bgapi == True:
+            msg = "bgapi sofia profile %s restart" % \
+                  (sofia_profile_name)
+            req = request.BgApiRequest()
+        else:
+            msg = "api sofia profile %s restart" % \
+                  (sofia_profile_name)
+            req = request.ApiRequest()
+        self.requestq.put(req)
+        print "sending to fs: %s" % msg
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+
+    def killchan(self, uuid, bgapi = False):
+        if bgapi == True:
+            msg = "bgapi killchan %s" % (uuid)
+            req = request.BgApiRequest()
+        else:
+            msg = "api killchan %s" % (uuid)            
+            req = request.ApiRequest()
+        self.requestq.put(req)
+        print "sending to fs: %s" % msg
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+
+        
+        
+    def lineReceived(self, line):
+        if not self.active_request:
+            # if no active request, dequeue a new one
+            if self.requestq.empty():
+                # we are receiving data from fs without an
+                # active request pending.  that means that
+                # there is a bug in the protocol handler
+                # (or possibly in fs)                
+                raise Exception("Received line: %s w/ no pending requests" % line)
+            self.active_request = self.requestq.get()
+
+        # tell the request to process the line, and tell us
+        # if its finished or not.  if its finished, we remove it
+        # as the active request so that a new active request will
+        # be de-queued.
+        finished = self.active_request.process(line)
+        if finished == True:
+            self.active_request = None
+

Added: freeswitch/trunk/scripts/socket/freepy/apirequest.sm
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/apirequest.sm	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,96 @@
+%start MainMap::Startup
+%class ApiRequest
+
+%map MainMap
+%%
+
+Startup
+{
+        ApiResponse
+                ApiResponseStarted
+                {
+                }
+}
+
+ApiResponseStarted
+{
+        ContentLength
+                ContentPreStarted
+                {
+                }
+
+}
+
+ContentPreStarted
+{
+        BlankLine
+                ContentStarted
+                {
+                }
+
+}
+
+ContentStarted
+{
+        ProcessLine(line)
+           [ctxt.add_content(line) == True]
+                Startup
+                {
+		setRequestFinished(); callbackDeferred(ctxt.getResponse());		
+                }
+
+        ProcessLine(line)
+                nil
+                {
+		// for some reason, have to add doNothing() here or
+                // importing smc will fail.  looks like smc bug.
+		doNothing();
+                }
+
+
+
+}
+
+
+
+
+
+Default
+{
+    	BlankLine			
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+    	ContentFinished		
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+    	ContentLength
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+    	ApiResponse			
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+        ProcessLine(line)
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+}
+
+%%
\ No newline at end of file

Added: freeswitch/trunk/scripts/socket/freepy/apirequest_sm.py
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/apirequest_sm.py	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,206 @@
+
+# DO NOT MODIFY THIS CODE - AUTOMATICALLY GENERATED BY SMC
+
+import statemap
+
+class ApiRequestState(statemap.State):
+
+    def Entry(self, fsm):
+        pass
+
+    def Exit(self, fsm):
+        pass
+
+    def ApiResponse(self, fsm):
+        self.Default(fsm)
+
+    def BlankLine(self, fsm):
+        self.Default(fsm)
+
+    def ContentFinished(self, fsm):
+        self.Default(fsm)
+
+    def ContentLength(self, fsm):
+        self.Default(fsm)
+
+    def ProcessLine(self, fsm, line):
+        self.Default(fsm)
+
+    def Default(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write('TRANSITION   : Default\n')
+        msg = "\n\tState: %s\n\tTransition: %s" % (
+            fsm.getState().getName(), fsm.getTransition())
+        raise TransitionUndefinedException, msg
+
+class MainMap_Default(ApiRequestState):
+
+    def BlankLine(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.BlankLine()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def ContentFinished(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.ContentFinished()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def ContentLength(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.ContentLength()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def ApiResponse(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.ApiResponse()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def ProcessLine(self, fsm, line):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.ProcessLine(line)\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+class MainMap_Startup(MainMap_Default):
+
+    def ApiResponse(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Startup.ApiResponse()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.setState(MainMap.ApiResponseStarted)
+        fsm.getState().Entry(fsm)
+
+class MainMap_ApiResponseStarted(MainMap_Default):
+
+    def ContentLength(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.ApiResponseStarted.ContentLength()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.setState(MainMap.ContentPreStarted)
+        fsm.getState().Entry(fsm)
+
+class MainMap_ContentPreStarted(MainMap_Default):
+
+    def BlankLine(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.ContentPreStarted.BlankLine()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.setState(MainMap.ContentStarted)
+        fsm.getState().Entry(fsm)
+
+class MainMap_ContentStarted(MainMap_Default):
+
+    def ProcessLine(self, fsm, line):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.ContentStarted.ProcessLine(line)\n")
+
+        if ctxt.add_content(line) == True :
+            fsm.getState().Exit(fsm)
+            fsm.clearState()
+            try:
+                ctxt.setRequestFinished()
+                ctxt.callbackDeferred(ctxt.getResponse())
+            finally:
+                fsm.setState(MainMap.Startup)
+                fsm.getState().Entry(fsm)
+        else:
+            endState = fsm.getState()
+            fsm.clearState()
+            try:
+                ctxt.doNothing()
+            finally:
+                fsm.setState(endState)
+
+
+class MainMap:
+
+    Startup = MainMap_Startup('MainMap.Startup', 0)
+    ApiResponseStarted = MainMap_ApiResponseStarted('MainMap.ApiResponseStarted', 1)
+    ContentPreStarted = MainMap_ContentPreStarted('MainMap.ContentPreStarted', 2)
+    ContentStarted = MainMap_ContentStarted('MainMap.ContentStarted', 3)
+    Default = MainMap_Default('MainMap.Default', -1)
+
+class ApiRequest_sm(statemap.FSMContext):
+
+    def __init__(self, owner):
+        statemap.FSMContext.__init__(self)
+        self._owner = owner
+        self.setState(MainMap.Startup)
+        MainMap.Startup.Entry(self)
+
+    def ApiResponse(self):
+        self._transition = 'ApiResponse'
+        self.getState().ApiResponse(self)
+        self._transition = None
+
+    def BlankLine(self):
+        self._transition = 'BlankLine'
+        self.getState().BlankLine(self)
+        self._transition = None
+
+    def ContentFinished(self):
+        self._transition = 'ContentFinished'
+        self.getState().ContentFinished(self)
+        self._transition = None
+
+    def ContentLength(self):
+        self._transition = 'ContentLength'
+        self.getState().ContentLength(self)
+        self._transition = None
+
+    def ProcessLine(self, *arglist):
+        self._transition = 'ProcessLine'
+        self.getState().ProcessLine(self, *arglist)
+        self._transition = None
+
+    def getState(self):
+        if self._state == None:
+            raise statemap.StateUndefinedException
+        return self._state
+
+    def getOwner(self):
+        return self._owner
+

Added: freeswitch/trunk/scripts/socket/freepy/bgapirequest.sm
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/bgapirequest.sm	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,72 @@
+%start MainMap::Startup
+%class BgApiRequest
+
+%map MainMap
+%%
+
+Startup
+{
+        CommandReply
+                ApiResponseStarted
+                {
+                }
+}
+
+ApiResponseStarted
+{
+        ReplyText
+                GotReplyText
+                {
+                }
+
+}
+
+
+GotReplyText
+{
+        BlankLine
+		Startup                
+                {
+		setRequestFinished(); callOrErrback();		
+                }
+
+
+}
+
+
+
+
+
+Default
+{
+    	BlankLine			
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+    	CommandReply		
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+    	ReplyText
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+        ProcessLine(line)
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+}
+
+%%
\ No newline at end of file

Added: freeswitch/trunk/scripts/socket/freepy/bgapirequest_sm.py
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/bgapirequest_sm.py	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,165 @@
+
+# DO NOT MODIFY THIS CODE - AUTOMATICALLY GENERATED BY SMC
+
+import statemap
+
+class BgApiRequestState(statemap.State):
+
+    def Entry(self, fsm):
+        pass
+
+    def Exit(self, fsm):
+        pass
+
+    def BlankLine(self, fsm):
+        self.Default(fsm)
+
+    def CommandReply(self, fsm):
+        self.Default(fsm)
+
+    def ProcessLine(self, fsm, line):
+        self.Default(fsm)
+
+    def ReplyText(self, fsm):
+        self.Default(fsm)
+
+    def Default(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write('TRANSITION   : Default\n')
+        msg = "\n\tState: %s\n\tTransition: %s" % (
+            fsm.getState().getName(), fsm.getTransition())
+        raise TransitionUndefinedException, msg
+
+class MainMap_Default(BgApiRequestState):
+
+    def BlankLine(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.BlankLine()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def CommandReply(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.CommandReply()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def ReplyText(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.ReplyText()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def ProcessLine(self, fsm, line):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.ProcessLine(line)\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+class MainMap_Startup(MainMap_Default):
+
+    def CommandReply(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Startup.CommandReply()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.setState(MainMap.ApiResponseStarted)
+        fsm.getState().Entry(fsm)
+
+class MainMap_ApiResponseStarted(MainMap_Default):
+
+    def ReplyText(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.ApiResponseStarted.ReplyText()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.setState(MainMap.GotReplyText)
+        fsm.getState().Entry(fsm)
+
+class MainMap_GotReplyText(MainMap_Default):
+
+    def BlankLine(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.GotReplyText.BlankLine()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.callOrErrback()
+        finally:
+            fsm.setState(MainMap.Startup)
+            fsm.getState().Entry(fsm)
+
+class MainMap:
+
+    Startup = MainMap_Startup('MainMap.Startup', 0)
+    ApiResponseStarted = MainMap_ApiResponseStarted('MainMap.ApiResponseStarted', 1)
+    GotReplyText = MainMap_GotReplyText('MainMap.GotReplyText', 2)
+    Default = MainMap_Default('MainMap.Default', -1)
+
+class BgApiRequest_sm(statemap.FSMContext):
+
+    def __init__(self, owner):
+        statemap.FSMContext.__init__(self)
+        self._owner = owner
+        self.setState(MainMap.Startup)
+        MainMap.Startup.Entry(self)
+
+    def BlankLine(self):
+        self._transition = 'BlankLine'
+        self.getState().BlankLine(self)
+        self._transition = None
+
+    def CommandReply(self):
+        self._transition = 'CommandReply'
+        self.getState().CommandReply(self)
+        self._transition = None
+
+    def ProcessLine(self, *arglist):
+        self._transition = 'ProcessLine'
+        self.getState().ProcessLine(self, *arglist)
+        self._transition = None
+
+    def ReplyText(self):
+        self._transition = 'ReplyText'
+        self.getState().ReplyText(self)
+        self._transition = None
+
+    def getState(self):
+        if self._state == None:
+            raise statemap.StateUndefinedException
+        return self._state
+
+    def getOwner(self):
+        return self._owner
+

Added: freeswitch/trunk/scripts/socket/freepy/fseventlistener.py
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/fseventlistener.py	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,258 @@
+""" 
+FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+
+Version: MPL 1.1
+
+The contents of this file are subject to the Mozilla Public License Version
+1.1 (the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+
+The Initial Developer of the Original Code is
+Anthony Minessale II <anthmct at yahoo.com>
+Portions created by the Initial Developer are Copyright (C)
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): Traun Leyden <tleyden at branchcut.com>
+"""
+
+import sys
+
+from twisted.internet import reactor, defer
+from twisted.protocols.basic import LineReceiver
+from twisted.internet.protocol import Protocol, ClientFactory
+from twisted.python import failure
+import time, re
+from time import strftime
+from Queue import Queue
+from freepy import request
+
+"""
+This class connects to freeswitch and listens for
+events and calls callback with the events.
+
+Example messages
+=================
+
+Content-Length: 675
+Content-Type: text/event-xml
+
+<event>
+  <header name="force-contact" value="nat-connectile-dysfunction"></header>
+  etc..
+</event>
+Content-Length: 875
+Content-Type: text/event-xml
+
+<event>
+...
+</event>
+
+"""
+
+class FreeswitchEventListener(LineReceiver):
+
+    def __init__(self, conncb, discocb=None):
+        self.delimiter='\n' # parent class uses this 
+        self.conncb=conncb
+        self.discocb=discocb
+        self.bufferlines = []
+        self.receiving_event = False # state to track if in <event>..</event>
+        self.requestq = Queue() # queue of pending requests
+        self.active_request = None # the current active (de-queued) request
+
+    def connectionMade(self):
+        self.conncb(self)
+        
+    def connectionLost(self, reason):
+        if self.discocb:
+            self.discocb(reason)        
+        print "connectionLost: %s" % reason
+
+
+    def login(self, passwd):
+        """
+        send login request
+        """
+        msg = "auth %s" % passwd
+        req = request.LoginRequest()
+        self.active_request = req
+        self.transport.write("%s\n\n" % msg)
+        return req.getDeferred()
+
+    def sniff_events(self, output_type, events):
+        """
+        @param output_type - eg, xml or plain
+        @param events - list of events, eg ['all']
+        """
+        event_list = " ".join(events)
+        msg = "event %s %s" % (output_type, event_list)
+        self.transport.write("%s\n\n" % msg)
+
+    def sniff_custom_events(self, output_type, events):
+        """
+        when sniffing custom events, the CUSTOM keyword
+        must be present in message
+        http://wiki.freeswitch.org/wiki/Event_Socket#event
+        
+        @param output_type - eg, xml or plain
+        @param events - list of events, eg ['all']
+        """
+        event_list = " ".join(events)
+        msg = "event %s CUSTOM %s" % (output_type, event_list)
+        self.transport.write("%s\n\n" % msg)
+
+    def sniff_all_events(self, output_type):
+        """
+        @param output_type - eg, xml or plain
+        """
+        msg = "event %s all" % output_type
+        self.transport.write("%s\n\n" % msg)
+
+    def lineReceived(self, line):
+        if not self.active_request:
+            if line.find("<event>") != -1:
+                self.receiving_event = True
+            if self.receiving_event:
+                self.bufferlines.append(line)
+            if line.find("</event>") != -1:
+                event_xml_str = "\n".join(self.bufferlines)
+                self.eventReceived(event_xml_str)
+                self.bufferlines = []
+                self.receiving_event = False
+        else:
+            # we have an active request (seperate state machine)
+            # tell the request to process the line, and tell us
+            # if its finished or not.  if its finished, we remove it
+            # as the active request so that a new active request will
+            # be de-queued.
+            finished = self.active_request.process(line)
+            if finished == True:
+                self.active_request = None
+
+    def eventReceived(self, event_xml_str):
+        """
+        should be overridden by subclasses
+        """
+        raise Exception("This is an abstract class, should be overridden "
+                        "in a subclass")
+
+class FreeswitchEventListenerFactory(ClientFactory):
+
+    def __init__(self, protoclass, host=None, passwd=None, port=None):
+        """
+        @param protoclass - a class (not instance) of the protocol
+                            should be a subclass of a FreeswitchEventListener
+        """
+
+        self.protoclass=protoclass
+        
+        if host:
+            self.host = host
+        if passwd:
+            self.passwd = passwd
+        if port:
+            self.port = port        
+            
+        self.protocol = None
+        self.connection_deferred = None
+        self.num_attempts = 0
+
+    def reset(self):
+        self.protocol = None
+        self.connection_deferred = None
+        
+    def connect(self):
+            
+        if self.protocol:
+            # if we have a protocol object, we are connected (since we always
+            # null it upon any disconnection)
+            return defer.succeed(self.protocol)
+
+        #if self.connection_deferred:
+            # we are already connecting, return existing dfrd
+        #    return self.connection_deferred
+
+        # connect and automatically login after connection
+        if not self.connection_deferred:
+            self.connection_deferred = defer.Deferred()
+            self.connection_deferred.addCallback(self.dologin)
+            self.connection_deferred.addErrback(self.generalError)
+        reactor.connectTCP(self.host, self.port, self)
+        return self.connection_deferred
+
+    def conncb(self, protocol):
+        self.protocol = protocol
+        deferred2callback = self.connection_deferred
+        self.connection_deferred = None
+        deferred2callback.callback(self.protocol)
+
+
+    def generalError(self, failure):
+        print "General error: %s" % failure
+        return failure
+
+    def startedConnecting(self, connector):
+        pass
+    
+    def buildProtocol(self, addr):
+        return self.protoclass(self.conncb, self.discocb)
+    
+    def clientConnectionLost(self, connector, reason):
+        print "clientConnectionLost! conn=%s, reason=%s" % (connector,
+                                                            reason)
+        self.connection_deferred = None        
+        self.protocol = None
+    
+    def clientConnectionFailed(self, connector, reason):
+        print "clientConnectionFailed! conn=%s, reason=%s" % (connector,
+                                                              reason)
+        #self.protocol = None
+        if self.num_attempts < 100:
+            self.num_attempts += 1
+            return reactor.callLater(5, self.connect)
+        else:
+            deferred2callback = self.connection_deferred
+            deferred2callback.errback(reason)
+
+    def discocb(self, reason):
+        print "disconnected.  reason: %s" % reason
+        self.protocol = None
+
+    def dologin(self, connectmsg):
+        return self.protocol.login(self.passwd)
+        
+
+def test1():
+    fel = FreeswitchEventListener
+    factory = FreeswitchEventListenerFactory(protoclass=fel,
+                                             host="127.0.0.1",
+                                             port=8021,
+                                             passwd="ClueCon")
+
+    def connected(result):
+        print "We connected, result: %s" % result
+        events=['sofia::register','sofia::expire']
+        factory.protocol.sniff_custom_events(output_type="xml", events=events)
+        #factory.protocol.sniff_all_events(output_type="xml")
+    
+    def failure(failure):
+        print "Failed to connect: %s" % failure
+        
+    d = factory.connect()
+    d.addCallbacks(connected, failure)
+    d.addErrback(failure)
+
+    reactor.run()    
+    
+if __name__=="__main__":
+    test1()
+

Added: freeswitch/trunk/scripts/socket/freepy/fshelper.py
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/fshelper.py	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,400 @@
+#!/usr/bin/env python
+
+""" 
+FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+
+Version: MPL 1.1
+
+The contents of this file are subject to the Mozilla Public License Version
+1.1 (the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+
+The Initial Developer of the Original Code is
+Anthony Minessale II <anthmct at yahoo.com>
+Portions created by the Initial Developer are Copyright (C)
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): Traun Leyden <tleyden at branchcut.com>
+"""
+
+
+from twisted.internet import reactor, defer
+from twisted.internet.protocol import ClientFactory
+import freepy
+
+class FsHelper(ClientFactory):
+
+    def __init__(self, host=None, passwd=None, port=None):
+        if host:
+            self.host = host
+        if passwd:
+            self.passwd = passwd
+        if port:
+            self.port = port        
+            
+        self.freepyd = None
+        self.connection_deferred = None
+
+    def reset(self):
+        self.freepyd = None
+        self.connection_deferred = None
+        
+    def connect(self):
+            
+        if self.freepyd:
+            # if we have a protocol object, we are connected (since we always
+            # null it upon any disconnection)
+            return defer.succeed("Connected")
+
+        if self.connection_deferred:
+            # we are already connecting, return existing dfrd
+            return self.connection_deferred
+        
+        self.connection_deferred = defer.Deferred()
+        self.connection_deferred.addCallback(self.dologin)
+        self.connection_deferred.addErrback(self.generalError)
+        print "freepy connecting to %s:%s" % (self.host, self.port)
+        reactor.connectTCP(self.host, self.port, self)
+        return self.connection_deferred
+
+    def conncb(self, freepyd):
+        self.freepyd = freepyd
+        deferred2callback = self.connection_deferred
+        self.connection_deferred = None
+        deferred2callback.callback("Connected")
+
+
+    def generalError(self, failure):
+        print "General error: %s" % failure
+        return failure
+
+    def startedConnecting(self, connector):
+        pass
+    
+    def buildProtocol(self, addr):
+        return freepy.FreepyDispatcher(self.conncb, self.discocb)
+    
+    def clientConnectionLost(self, connector, reason):
+        print "clientConnectionLost! conn=%s, reason=%s" % (connector,
+                                                            reason)
+        self.connection_deferred = None        
+        self.freepyd = None
+    
+    def clientConnectionFailed(self, connector, reason):
+        print "clientConnectionFailed! conn=%s, reason=%s" % (connector,
+                                                              reason)
+        self.freepyd = None
+        deferred2callback = self.connection_deferred
+        self.connection_deferred = None                
+        deferred2callback.errback(reason)
+
+    def discocb(self, reason):
+        print "disconnected.  reason: %s" % reason
+        self.freepyd = None
+
+    def dologin(self, connectmsg):
+        return self.freepyd.login(self.passwd)                                     
+
+    def originate(self, party2dial, dest_ext_app, bgapi=True):
+        """
+        party2dial - the first argument to the originate command,
+                     eg, sofia/profile_name/1234 at domain.com
+        dest_ext_app - the second argument to the originate command,
+                       eg, &park() or 4761
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  ([(True, 'Reply-Text: +OK Job-UUID: d07ad7de-2406-11dc-aea3-e3b2e56b7a2c')],)
+
+        """
+
+        def originate_inner(ignored):
+            deferreds = []
+            deferred = self.freepyd.originate(party2dial,
+                                              dest_ext_app,
+                                              bgapi)
+            return deferred
+
+        d = self.connect()
+        d.addCallback(originate_inner)
+        return d
+
+
+
+
+    def dialconf(self, people2dial, conf_name, bgapi=True):
+        """
+        conf_name - name of conf TODO: change to match db
+        people2dial - an array of dictionaries:
+                     'name': name
+                     'number': number
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  ([(True, 'Reply-Text: +OK Job-UUID: d07ad7de-2406-11dc-aea3-e3b2e56b7a2c')],)
+
+                  Its a bit ugly because its a deferred list callback.
+
+        """
+
+        def dialconf_inner(ignored):
+            deferreds = []
+            for person2dial in people2dial:
+                sofia_url = person2dial['number']
+                deferred = self.freepyd.confdialout(conf_name,
+                                                    sofia_url,
+                                                    bgapi)
+                deferreds.append(deferred)
+            return defer.DeferredList(deferreds)
+
+        d = self.connect()
+        d.addCallback(dialconf_inner)
+        return d
+
+    def listconf(self, conf_name):
+        """
+        conf_name - name of conf 
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this
+        """
+        def listconf_inner(ignored):
+            deferred = self.freepyd.listconf(conf_name)
+            return deferred
+
+        d = self.connect()
+        d.addCallback(listconf_inner)
+        return d
+
+    def confkick(self, member_id, conf_name, bgapi=True):
+        """
+        conf_name - name of conf
+        member_id - member id of user to kick, eg, "7"
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this
+        """
+        def confkick_inner(ignored):
+            #if type(member_id) == type(""):
+            #    member_id = int(member_id)
+            deferred = self.freepyd.confkick(member_id, conf_name, bgapi)
+            return deferred
+
+        d = self.connect()
+        d.addCallback(confkick_inner)
+        return d
+
+    def confdtmf(self, member_id, conf_name, dtmf, bgapi=True):
+        """
+        Send dtmf(s) to a conference
+        conf_name - name of conf
+        member_id - member id of user to kick, eg, "7", or "all"
+        dtmf - a single dtmf or a string of dtms, eg "1" or "123"
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this
+        """
+        def confdtmf_inner(ignored):
+            print "confdtmf_inner called"
+            deferred = self.freepyd.confdtmf(member_id, conf_name, dtmf, bgapi)
+            return deferred
+
+        d = self.connect()
+        d.addCallback(confdtmf_inner)
+        return d
+
+
+    def confsay(self, conf_name, text2speak, bgapi=True):
+        """
+        conf_name - name of conf
+        text2speak - text to speak
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this
+        """
+        def confsay_inner(ignored):
+            deferred = self.freepyd.confsay(conf_name, text2speak, bgapi)
+            return deferred
+
+        d = self.connect()
+        d.addCallback(confsay_inner)
+        return d
+
+    def confplay(self, conf_name, snd_url, bgapi=True):
+        """
+        conf_name - name of conf
+        snd_url - url to sound file
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this
+        """
+        def confplay_inner(ignored):
+            deferred = self.freepyd.confplay(conf_name, snd_url, bgapi)
+            return deferred
+
+        d = self.connect()
+        d.addCallback(confplay_inner)
+        return d
+
+    def confstop(self, conf_name, bgapi=True):
+        """
+        stop playback of all sounds
+        
+        conf_name - name of conf
+        returns - a deferred that will be called back with a result
+                  like:
+
+                  TODO: add this
+        """
+        def confstop_inner(ignored):
+            deferred = self.freepyd.confstop(conf_name, bgapi)
+            return deferred
+
+        d = self.connect()
+        d.addCallback(confstop_inner)
+        return d
+
+
+    def showchannels(self, bgapi=True):
+
+        def showchannels_inner(ignored):
+            df = self.freepyd.showchannels(bgapi)
+            return df
+
+        d = self.connect()
+        d.addCallback(showchannels_inner)
+        return d
+
+    def killchan(self, uuid, bgapi=True):
+
+        def killchan_inner(ignored):
+            df = self.freepyd.killchan(uuid, bgapi)
+            return df
+
+        d = self.connect()
+        d.addCallback(killchan_inner)
+        return d
+
+
+    def sofia_profile_restart(self, profile_name, bgapi=True):
+
+        def sofia_profile_restart_inner(ignored):
+            df = self.freepyd.sofia_profile_restart(profile_name,
+                                                    bgapi)
+            return df
+
+        d = self.connect()
+        d.addCallback(sofia_profile_restart_inner)
+        return d
+
+
+    def sofia_status_profile(self, profile_name, bgapi=True):
+
+        def sofia_status_profile_inner(ignored):
+            df = self.freepyd.sofia_status_profile(profile_name,
+                                                    bgapi)
+            return df
+
+        d = self.connect()
+        d.addCallback(sofia_status_profile_inner)
+        return d
+
+
+class FsHelperTest:
+    def __init__(self, fshelper):
+        self.fshelper=fshelper
+        pass
+
+    def test_dialconf(self):
+
+        people2dial = [{'name':'freeswitch',
+                        'number':'888 at conference.freeswitch.org'},
+                       {'name':'mouselike',
+                        'number':'904 at mouselike.org'}]
+        d = self.fshelper.dialconf(people2dial, "freeswitch", bgapi=False)
+        def failed(error):
+            print "Failed to dial users!"
+            reactor.stop()
+            return error
+        d.addErrback(failed)
+        def worked(*args):
+            print "Worked! Dialed user result: %s" % str(args)
+            #reactor.stop()
+        d.addCallback(worked)        
+        return d
+
+    def test_listconf(self):
+
+        d = self.fshelper.listconf("freeswitch")
+        def failed(failure):
+            print "Failed to list users!"
+            reactor.stop()
+            return failure
+        d.addErrback(failed)
+        def worked(*args):
+            print "List of users in conf: %s" % str(args)
+            return args[0]
+        d.addCallback(worked)
+        return d
+
+    def test_confkick(self, member_id="6", conf_name="freeswitch"):
+
+        d = self.fshelper.confkick(member_id, conf_name)
+        def failed(failure):
+            print "Failed to kick user!"
+            reactor.stop()
+            return failure
+        d.addErrback(failed)
+        def worked(*args):
+            print "Kicked user from conf, result: %s" % str(args)
+        d.addCallback(worked)
+        
+
+def test1():
+    kick_everyone = False
+    fshelper = FsHelper("mydomain.com")
+    fsht = FsHelperTest(fshelper)
+    fsht.test_dialconf()
+    d = fsht.test_listconf()
+    def kickeveryone(members):
+        print "Kickeveryone called w/ %s (type: %s)" % (members,
+                                                        type(members))
+        for member in members:
+            fsht.test_confkick(member.member_id)
+
+    def failed(failure):
+        print "failed: %s" % str(failure)
+        reactor.stop()
+    if kick_everyone:
+        d.addCallback(kickeveryone)        
+        d.addErrback(failed)
+    #fsht.test_confkick()
+    #d = fshelper.connect()
+    #def connected(*args):
+    #    fsht.test_dialconf()
+    #    fsht.test_listconf()
+    #d.addCallback(connected)
+    reactor.run()
+
+def test2():
+    fshelper = FsHelper("mydomain.com")
+    fshelper.sofia_profile_restart("mydomain.com")
+    reactor.run()    
+    
+if __name__=="__main__":
+    #test1()
+    test2()

Added: freeswitch/trunk/scripts/socket/freepy/loginrequest.sm
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/loginrequest.sm	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,92 @@
+%start MainMap::Startup
+%class LoginRequest
+
+%map MainMap
+%%
+
+Startup
+{
+        AuthRequest
+                AuthRequestStarted
+                {
+                }
+}
+
+AuthRequestStarted
+{
+        BlankLine
+                AuthRequestFinished
+                {
+                }
+
+}
+
+AuthRequestFinished
+{
+        CommandReply
+                CommandReplyStarted
+                {
+                }
+
+}
+
+CommandReplyStarted
+{
+        ReplyText
+                GotReplyText
+                {
+                }
+
+}
+
+
+GotReplyText
+{
+        BlankLine
+		Startup                
+                {
+		setRequestFinished(); callOrErrback();		
+                }
+
+}
+
+
+Default
+{
+    	BlankLine			
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+    	AuthRequest			
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+    	CommandReply			
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+    	ReplyText			
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+        ProcessLine(line)
+		nil			
+		{ 
+		setRequestFinished();
+		errbackDeferred("Protocol failure");		
+		}
+
+}
+%%
\ No newline at end of file

Added: freeswitch/trunk/scripts/socket/freepy/loginrequest_sm.py
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/loginrequest_sm.py	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,209 @@
+
+# DO NOT MODIFY THIS CODE - AUTOMATICALLY GENERATED BY SMC
+
+import statemap
+
+
+class LoginRequestState(statemap.State):
+
+    def Entry(self, fsm):
+        pass
+
+    def Exit(self, fsm):
+        pass
+
+    def AuthRequest(self, fsm):
+        self.Default(fsm)
+
+    def BlankLine(self, fsm):
+        self.Default(fsm)
+
+    def CommandReply(self, fsm):
+        self.Default(fsm)
+
+    def ProcessLine(self, fsm, line):
+        self.Default(fsm)
+
+    def ReplyText(self, fsm):
+        self.Default(fsm)
+
+    def Default(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write('TRANSITION   : Default\n')
+        msg = "\n\tState: %s\n\tTransition: %s" % (
+            fsm.getState().getName(), fsm.getTransition())
+        raise TransitionUndefinedException, msg
+
+class MainMap_Default(LoginRequestState):
+
+    def BlankLine(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.BlankLine()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def AuthRequest(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.AuthRequest()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def CommandReply(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.CommandReply()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def ReplyText(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.ReplyText()\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+    def ProcessLine(self, fsm, line):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Default.ProcessLine(line)\n")
+
+        endState = fsm.getState()
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.errbackDeferred("Protocol failure")
+        finally:
+            fsm.setState(endState)
+
+class MainMap_Startup(MainMap_Default):
+
+    def AuthRequest(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.Startup.AuthRequest()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.setState(MainMap.AuthRequestStarted)
+        fsm.getState().Entry(fsm)
+
+class MainMap_AuthRequestStarted(MainMap_Default):
+
+    def BlankLine(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.AuthRequestStarted.BlankLine()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.setState(MainMap.AuthRequestFinished)
+        fsm.getState().Entry(fsm)
+
+class MainMap_AuthRequestFinished(MainMap_Default):
+
+    def CommandReply(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.AuthRequestFinished.CommandReply()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.setState(MainMap.CommandReplyStarted)
+        fsm.getState().Entry(fsm)
+
+class MainMap_CommandReplyStarted(MainMap_Default):
+
+    def ReplyText(self, fsm):
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.CommandReplyStarted.ReplyText()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.setState(MainMap.GotReplyText)
+        fsm.getState().Entry(fsm)
+
+class MainMap_GotReplyText(MainMap_Default):
+
+    def BlankLine(self, fsm):
+        ctxt = fsm.getOwner()
+        if fsm.getDebugFlag() == True:
+            fsm.getDebugStream().write("TRANSITION   : MainMap.GotReplyText.BlankLine()\n")
+
+        fsm.getState().Exit(fsm)
+        fsm.clearState()
+        try:
+            ctxt.setRequestFinished()
+            ctxt.callOrErrback()
+        finally:
+            fsm.setState(MainMap.Startup)
+            fsm.getState().Entry(fsm)
+
+class MainMap:
+
+    Startup = MainMap_Startup('MainMap.Startup', 0)
+    AuthRequestStarted = MainMap_AuthRequestStarted('MainMap.AuthRequestStarted', 1)
+    AuthRequestFinished = MainMap_AuthRequestFinished('MainMap.AuthRequestFinished', 2)
+    CommandReplyStarted = MainMap_CommandReplyStarted('MainMap.CommandReplyStarted', 3)
+    GotReplyText = MainMap_GotReplyText('MainMap.GotReplyText', 4)
+    Default = MainMap_Default('MainMap.Default', -1)
+
+class LoginRequest_sm(statemap.FSMContext):
+
+    def __init__(self, owner):
+        statemap.FSMContext.__init__(self)
+        self._owner = owner
+        self.setState(MainMap.Startup)
+        MainMap.Startup.Entry(self)
+
+    def AuthRequest(self):
+        self._transition = 'AuthRequest'
+        self.getState().AuthRequest(self)
+        self._transition = None
+
+    def BlankLine(self):
+        self._transition = 'BlankLine'
+        self.getState().BlankLine(self)
+        self._transition = None
+
+    def CommandReply(self):
+        self._transition = 'CommandReply'
+        self.getState().CommandReply(self)
+        self._transition = None
+
+    def ProcessLine(self, *arglist):
+        self._transition = 'ProcessLine'
+        self.getState().ProcessLine(self, *arglist)
+        self._transition = None
+
+    def ReplyText(self):
+        self._transition = 'ReplyText'
+        self.getState().ReplyText(self)
+        self._transition = None
+
+    def getState(self):
+        if self._state == None:
+            raise statemap.StateUndefinedException
+        return self._state
+
+    def getOwner(self):
+        return self._owner
+

Added: freeswitch/trunk/scripts/socket/freepy/models.py
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/models.py	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,81 @@
+""" 
+FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+
+Version: MPL 1.1
+
+The contents of this file are subject to the Mozilla Public License Version
+1.1 (the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+
+The Initial Developer of the Original Code is
+Anthony Minessale II <anthmct at yahoo.com>
+Portions created by the Initial Developer are Copyright (C)
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): Traun Leyden <tleyden at branchcut.com>
+"""
+ 
+"""
+Data models for objects inside freeswitch
+"""
+
+import re
+
+class ConfMember:
+
+    def __init__(self, rawstring):
+        self.rawstring = rawstring
+        self.member_id = None
+        self.member_uri = None
+        self.uuid = None
+        self.caller_id_name = None
+        self.caller_id_number = None
+        self.flags = None
+        self.volume_in = None
+        self.volume_out = None
+        self.energy_level = None
+
+        self.parse(self.rawstring)
+        
+    def parse(self, rawstring):
+        """
+        1;sofia/mydomain.com/user at somewhere.com;898e6552-24ab-11dc-9df7-9fccd4095451;FreeSWITCH;0000000000;hear|speak;0;0;300
+        """
+        fields = rawstring.split(";")
+        self.member_id = fields[0]
+        self.member_uri = fields[1]
+        self.uuid = fields[2]
+        self.caller_id_name = fields[3]
+        self.caller_id_number = fields[4]
+        self.flags = fields[5]
+        self.volume_in = fields[6]
+        self.volume_out = fields[7]
+        self.energy_level = fields[8]
+
+    def brief_member_uri(self):
+        """
+        if self.member_uri is sofia/mydomain.com/foo at bar.com
+        return foo at bar.com
+        """
+        if not self.member_uri:
+            return None
+
+        if self.member_uri.find("/") == -1:
+            return self.member_uri
+        r = self.member_uri.split("/")[-1]  # tokenize on "/" and return last item
+        return r
+
+    def __repr__(self):
+        return self.__str__()
+    
+    def __str__(self):
+        return "%s (%s)" % (self.member_id, self.member_uri)

Added: freeswitch/trunk/scripts/socket/freepy/request.py
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/freepy/request.py	Sun Oct  7 12:47:10 2007
@@ -0,0 +1,425 @@
+""" 
+FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+Copyright (C) 2005/2006, Anthony Minessale II <anthmct at yahoo.com>
+
+Version: MPL 1.1
+
+The contents of this file are subject to the Mozilla Public License Version
+1.1 (the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+http://www.mozilla.org/MPL/
+
+Software distributed under the License is distributed on an "AS IS" basis,
+WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+for the specific language governing rights and limitations under the
+License.
+
+The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+
+The Initial Developer of the Original Code is
+Anthony Minessale II <anthmct at yahoo.com>
+Portions created by the Initial Developer are Copyright (C)
+the Initial Developer. All Rights Reserved.
+
+Contributor(s): Traun Leyden <tleyden at branchcut.com>
+"""
+
+import sys
+
+from twisted.internet import reactor, defer
+from twisted.protocols.basic import LineReceiver
+from twisted.internet.protocol import Protocol, ClientFactory
+from twisted.python import failure
+import time, re
+from time import strftime
+from Queue import Queue
+
+from freepy import models
+
+"""
+These are response handlers for different types of requests.
+It reads the response from freeswitch, and calls back
+self.deferred with the result.
+
+The naming could be improved, but here is the translation:
+
+LoginRequest - Response handler for a login request
+
+"""
+
+class FreepyRequest(object):
+
+    def __init__(self):
+        self.deferred = defer.Deferred()
+        self.response_content = ""
+        self.finished = False
+
+    def isRequestFinished(self):
+        return self.finished
+
+    def setRequestFinished(self):
+        self.finished = True
+        
+    def getDeferred(self):
+        return self.deferred
+
+    def callbackDeferred(self, cbval):
+        self.deferred.callback(cbval)
+
+    def errbackDeferred(self, result):
+        self.deferred.errback(result)
+
+    def process(self, line):
+        """
+        processs a line from the fs response.  if the fs response has been
+        detected to be finished, then:
+
+        * create an appropriate response based on request type
+        * callback deferred with response
+        * rturn True to indicate we are finished
+
+        otherwise, if the fs response is incomplete, just buffer the data
+        """
+        if not line or len(line) == 0:
+            self._fsm.BlankLine()
+            return self.isRequestFinished()
+        
+        matchstr = re.compile("auth/request", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            self._fsm.AuthRequest()
+            return self.isRequestFinished()
+
+
+        matchstr = re.compile("command/reply", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            self._fsm.CommandReply()
+            return self.isRequestFinished()
+
+
+        matchstr = re.compile("Reply-Text", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            fields = line.split(":") # eg, ['Reply-Text','+OK Job-UUID', '882']
+            endfields = fields[1:]
+            self.response_content = "".join(endfields)
+            self._fsm.ReplyText()
+            return self.isRequestFinished()
+
+
+        matchstr = re.compile("api/response", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            self._fsm.ApiResponse()
+            return self.isRequestFinished()
+
+        matchstr = re.compile("Content-Length", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            # line: Content-Length: 34
+            self.content_length = int(line.split(":")[1].strip())
+            self._fsm.ContentLength()
+            return self.isRequestFinished()
+
+
+        self._fsm.ProcessLine(line)
+        return self.isRequestFinished()
+
+
+
+
+    def callOrErrback(self):
+        matchstr = re.compile("OK", re.I)
+        result = matchstr.search(self.response_content)
+        if (result != None):
+            self.callbackDeferred(self.response_content)
+            return
+        
+        self.errbackDeferred(self.response_content)
+
+
+    def doNothing(self):
+        # weird smc issue workaround attempt
+        pass
+
+
+class LoginRequest(FreepyRequest):
+    """
+    Example success response
+    ========================
+        
+    lineReceived: Content-Type: auth/request
+    lineReceived:
+    lineReceived: Content-Type: command/reply
+    lineReceived: Reply-Text: +OK accepted
+    lineReceived:
+
+    Example failure response
+    ========================
+
+    lineReceived: Content-Type: auth/request
+    lineReceived:
+    lineReceived: Content-Type: command/reply
+    lineReceived: Reply-Text: -ERR invalid
+    lineReceived:
+
+    """
+    
+    def __init__(self):
+        super(LoginRequest, self).__init__()
+        import loginrequest_sm
+        self._fsm = loginrequest_sm.LoginRequest_sm(self)
+        
+    def processOLD(self, line):
+
+        if not line or len(line) == 0:
+            self._fsm.BlankLine()
+            return self.isRequestFinished()
+        
+        matchstr = re.compile("auth/request", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            self._fsm.AuthRequest()
+            return self.isRequestFinished()
+
+
+        matchstr = re.compile("command/reply", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            self._fsm.CommandReply()
+            return self.isRequestFinished()
+
+
+        matchstr = re.compile("Reply-Text", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            fields = line.split(":") # eg, ['Reply-Text','+OK Job-UUID', '882']
+            endfields = fields[1:]
+            self.response_content = "".join(endfields)
+            self._fsm.ReplyText()
+            return self.isRequestFinished()
+
+
+        self._fsm.ProcessLine(line)
+        return self.isRequestFinished()
+
+
+    def getReplyText(self):
+        self.response_content
+
+
+class BgApiRequest(FreepyRequest):
+
+    """
+    Here is one of the 'bgapi requests' this class
+    supports:
+
+
+    linereceived: Content-Type: command/reply
+    linereceived: Reply-Text: +OK Job-UUID: 788da080-24e0-11dc-85f6-3d7b12..
+    linereceived: 
+
+    """
+    
+    def __init__(self):
+        super(BgApiRequest, self).__init__()
+        import bgapirequest_sm
+        self._fsm = bgapirequest_sm.BgApiRequest_sm(self)
+
+
+    def processOLD(self, line):
+
+        if not line or len(line) == 0:
+            self._fsm.BlankLine()
+            return self.isRequestFinished()
+        
+        matchstr = re.compile("command/reply", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            self._fsm.CommandReply()
+            return self.isRequestFinished()
+
+        matchstr = re.compile("Reply-Text", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            self.response_content = line.split(":")[1]
+            self._fsm.ReplyText()
+            return self.isRequestFinished()
+
+        self._fsm.ProcessLine(line)
+        return self.isRequestFinished()
+
+
+
+    def getResponse(self):
+
+        # subclasses may want to parse this into a meaningful
+        # object or set of objects (eg, see ListConfRequest)
+        # By default, just return accumulated string
+        return self.response_content
+
+
+
+class ApiRequest(FreepyRequest):
+
+    """
+    Here is one of the 'api requests' this class
+    supports:
+
+    lineReceived: Content-Type: api/response
+    lineReceived: Content-Length: 34
+    lineReceived:
+    lineReceived: Call Requested: result: [SUCCESS]
+    """
+    
+    def __init__(self):
+        super(ApiRequest, self).__init__()
+        import apirequest_sm
+        self._fsm = apirequest_sm.ApiRequest_sm(self)
+        self.response_content = ""
+
+    def processOLD(self, line):
+
+        if not line or len(line) == 0:
+            self._fsm.BlankLine()
+            return self.isRequestFinished()
+        
+        matchstr = re.compile("api/response", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            self._fsm.ApiResponse()
+            return self.isRequestFinished()
+
+        matchstr = re.compile("Content-Length", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            # line: Content-Length: 34
+            self.content_length = int(line.split(":")[1].strip())
+            self._fsm.ContentLength()
+            return self.isRequestFinished()
+
+        self._fsm.ProcessLine(line)
+        return self.isRequestFinished()
+
+    def doNothing(self):
+        # weird smc issue workaround attempt
+        pass
+
+    def add_content(self, line):
+        """
+        Add content to local buffer
+        return - True if finished adding content, False otherwise
+        """
+
+        # since the twisted LineReceiver strips off the newline,
+        # we need to add it back .. otherwise the Content-length
+        # will be off by one
+        line += "\n"
+        
+        self.response_content += line
+        if len(self.response_content) == self.content_length:
+            return True
+        elif len(self.response_content) > self.content_length:
+            return True
+        else:
+            return False
+
+
+    def getResponse(self):
+
+        # subclasses may want to parse this into a meaningful
+        # object or set of objects (eg, see ListConfRequest)
+        # By default, just return accumulated string
+        return self.response_content
+
+        
+class DialoutRequest(ApiRequest):
+    """
+    Example raw dialout response
+    ============================
+
+    lineReceived: Content-Type: api/response
+    lineReceived: Content-Length: 34
+    lineReceived:
+    lineReceived: Call Requested: result: [SUCCESS]
+    """
+
+    def __init__(self):
+        super(DialoutRequest, self).__init__()
+
+
+class BgDialoutRequest(BgApiRequest):
+    def __init__(self):
+        super(BgDialoutRequest, self).__init__()
+        
+
+class ConfKickRequest(ApiRequest):
+    """
+    Example response
+    ================
+
+
+    """
+
+    def __init__(self):
+        super(ConfKickRequest, self).__init__()
+
+class BgConfKickRequest(BgApiRequest):
+    """
+    Example response
+    ================
+
+
+    """
+
+    def __init__(self):
+        super(BgConfKickRequest, self).__init__()
+        
+
+class ListConfRequest(ApiRequest):
+    """
+    Response to request to list conferences:
+    ========================================
+    
+    lineReceived: Content-Type: api/response
+    lineReceived: Content-Length: 233
+    lineReceived:
+    lineReceived: 2;sofia/mydomain.com/foo at bar.com;e9be6e72-2410-11dc-8daf-7bcec6dda2ae;FreeSWITCH;0000000000;hear|speak;0;0;300
+    lineReceived: 1;sofia/mydomain.com/foo2 at bar.com;e9be5fcc-2410-11dc-8daf-7bcec6dda2ae;FreeSWITCH;0000000000;hear|speak;0;0;300
+
+    """
+
+    def __init__(self):
+        super(ListConfRequest, self).__init__()
+        self.conf_members = []
+        
+    def add_content(self, line):
+        """
+        conf not empty example
+        ======================
+        1;sofia/mydomain.com/888 at conference.freeswitch.org;898e6552-24ab-11dc-9df7-9fccd4095451;FreeSWITCH;0000000000;hear|speak;0;0;300
+
+        conf empty example
+        ==================
+        Conference foo not found
+        """
+
+        matchstr = re.compile("not found", re.I)
+        result = matchstr.search(line)
+        if (result != None):
+            # no conf found..
+            pass
+        else:
+            confmember = models.ConfMember(line)
+            self.conf_members.append(confmember)
+        
+        return super(ListConfRequest, self).add_content(line)
+        
+    def getResponse(self):
+
+        # TODO: parse this content into a meaningful
+        # 'object' .. though, not sure this is really
+        # necessary.   wait till there's a need
+        return self.conf_members
+        



More information about the Freeswitch-svn mailing list