Creating an outgoing call using Asterisk Manager and "pyst" - python

I am trying to write some automation tests which make a phone call to my local Asterisk instance and then check that a receiving SIP client has received the call.
It is my understanding that I can create an outgoing call event using the Asterisk Manager. To do this I have been trying to use the Python 'pyst' library.
I have not been able to find any working examples of how to implement this scenario. From the information I have managed to gather, I have come up with this script:
from asterisk import manager
HOST = 'localhost'
PORT = 5068
m = manager.Manager()
m.connect( HOST )
m.login( 'admin', 'temp123' )
targetURL = '441610000001'
response = m.originate(
targetURL ,
's',
context='outgoing',
priority='1'
)
print m.status()
m.logoff()
m.close()
This script reports a 'success' response from Asterisk Manager but does not actually create an outgoing call.
Has anyone written a script to do this in python?
I am only familiar with the Python language so solutions in other languages wouldn't be very helpful for me!

Please read again documentation
"Targeturl" in your program actually have be channel, so in your code it have no channel type and host(if that sip).
Valid examples are:
targetURL = 'SIP/441610000001#myprovider_name'
targetURL = 'Local/441610000001#outbound_context'
Context "outbound" have be valid and have deliver call.
PYST is opensource framework. If you are realy "familar" with python, i recommend you read source of originate method and check what it send with asterisk doc
http://www.voip-info.org/wiki/view/Asterisk+Manager+API+Action+Originate
Note: it is very bad idea program for asterisk using framework like PYST if you have no general knowledge about asterisk itself. First you need read asterisk book.

Related

How to access the Custom Protocol URL used to invoke the MACOS App which comprises of a single python file (from inside the python code)

I have written a small python file which I am packaging as a .app and installing on macos (latest version). The app is intended to be invoked using a custom protocol similar to "abc://efg/ijk/lmn". The python file employs pyobjc package and intends to use it to implement the business logic. I have option of using, only the Python language to implement my business logic because of legacy reasons.
I have to access the invoking custom URL "abc://efg/ijk/lmn" from inside the python code and parse the values. The "efg" "ijk" and "lmn" in the custom URL will vary and will be used to take some decisions further down the flow.
I have tried multiple things from whatever I could find from the internet but i am unable to access the custom url from with in the python code. The value of sys.argv come as below
sys.argv = ['/Applications/XXXXXApp.app/Contents/MacOS/XXXXXApp', '-psn_0_4490312']
But on windows sys.argv[0] is populated with the custom url.
Will appreciate any directions.
Below code is what I have tried among many other variations of it.
`
from Cocoa import NSObject
mylogger = open(os.path.expanduser("~/Desktop/somefile.txt"), 'w+')
class apple_event_handler(NSObject):
def applicationWillFinishLaunching_(self, notification):
mylogger.write("Will finish ")
def applicationDidFinishLaunching_(self, notification):
mylogger.write("Did Finish")
def handleAppleEvent_withReplyEvent_(self, event, reply_event):
theURL = event.descriptorForKeyword_(fourCharToInt(b'----'))
mylogger.write("********* Handler Invoked !!! *********")
mylogger.write("********* the URL = " + str(theURL))
mylogger.write(*self.args)
aem = NSAppleEventManager.sharedAppleEventManager()
aeh = apple_event_handler.alloc().init()
aem.setEventHandler_andSelector_forEventClass_andEventID_(aeh,
"handleAppleEvent:withReplyEvent:", 1, 1)
`

Strange way to pass data between modules in Python: How does it work?

I'm supposed to work with some messy code that I haven't written myself, and amidst the mess I found out two scripts that communicate by this strange fashion (via a 3rd middleman script):
message.py, the 'middleman' script:
class m():
pass
sender.py, who wants to send some info to the receiver:
from message import m
someCalculationResult = 1 + 2
m.result = someCalculationResult
receiver.py, who wants to print some results produced by sender.py:
from message import m
mInstance = m()
print mInstance.result
And, by magic, in the interpreter, importing sender.py then receiver.py does indeed print 3...
Now, what the hell is happening behind the scenes here? Are we storing our results into the class definition itself and recovering them via a particular instance? If so, why can't we recover the results from the definition itself also? Is there a more elegant way to pass stuff inbetween scripts ran sucessively in the interpreter?
Using Python 2.6.6
That is just a convoluted way to set a global.
m is a class, m.result a class attribute. Both the sender and receiver can access it directly, just as they can access m.
They could have done this too:
# sender
import message
message.result = someCalculationResult
# receiver
import message
print message.result
Here result is just a name in the message module top-level module.
It should be noted that what you are doing is not running separate scripts; you are importing modules into the same interpreter. If you ran python sender.py first, without ever importing reciever.py, then separately running python receiver.py without ever importing sender.py this whole scheme doesn't work.
There are myriad ways to pass data from one section of code to another section, too many to name here, all fitting for a different scenario and need. Threading, separate processes, separate computers all introduce different constraints on how message passing can and should take place, for example.

Pass command line variables between Python files. Totally stuck

I have what seems like a very easy problem with an easy solution just beyond my reach.
My setup:
A) Driver file (runs the test script)
B) Connection file (using Requests)
C) Parameters file
The paramenters file has 6 variables with things like server IP, login, pass etc.
The Driver file has a praser which reads the properties file and fills in the blanks.
driver.py paramtersfile.csv
This works fine. However, I added a PORT variable to the parameters file which needs to be seen by B) Connection file. This connections file is never called explicitly, rather just imported into the driver file for its connection and cookie methods.
How do I carry over the parsed variables (from sys.argv) from paramtersfile.csv to the Connections file (or any other file which is used to run my script?
Thank you stackoverflow community
Edit:
I got it to work using the obvious way of passing on the arguments into the class (self.foo) of whatever module/file I needed.
My question from before was along the lines of this idea:
You do something like
loadproperties(propertiesfile)
then from any other python script you could just do
import propertyloader
which would load a list of immutable properties into the current space
Seems very convenient to just do
url = propertyloader.url
instead of
class Connect (host, port, pass, url):
self.url = url
loader = requests(secure, url)
blah blah blah...
Seems like a headache free way of sharing common parameters between different parts of the script.
Maybe there's still a way of doing this (extra credit question)
From the driver.py file, import the connections file as a module and pass the arguments you've parsed to the methods inside the module. Something like this:
#===inside driver.py===
import connections
params = parseFile(sys.argv) #get parameters from the csv file that is passed to the command line
connections.connect(params) #pass them to whatever method you need to call from connections
EDIT: It sounds like you're not writing your code in a modular way. You should stop thinking about your code in terms of files, but instead think of them in terms of modules: bits and pieces of interchangeable code that you can use in many different places. The main flaw with your design that I see (forgive me if I didn't understand correctly) is that you're hard-coding a value inside the connections file that you use to create connection objects. I'm guessing this is what your code looks like (or at least captures the spirit of your code adequately):
#connections.py
MY_SERVER = ??? #WHAT DO I SET THIS TO?
class Connection:
def __init__(self):
self.server = MY_SERVER
def connect():
connection = Connection() #create a new connection object
The above code is not designed well since you're defining a variable MY_SERVER that shouldn't be defined there in the first place! The connections class doesn't know or care what server it should use, it should work with any server. So where do you get the server variable? You pass it in via a constructor or a method. You could do something like this:
#connections.py
class Connection:
def __init__(self, server):
self.server = server
def connect(server):
connection = Connection(server) #create a new connection object with the server passed to the method
With this design, the Connection object becomes much more flexible. It is basically saying "I am a connection object that can handle any server. If you want to use me, just tell me what server you want to use!".
This way, in your drivers file you can first parse the server from your csv, and then simply call the method connections.connect by passing it the server you want!

Basic example of AMI connection to Asterisk from Python script w/Starpy

I have some years of solid experience working with asterisk but am new to python.
I want to connect from a python script and receive some events. I have created a manager user with AMIUSERNAME and AMIPASSWORD as credentials and tested working OK. I have also installed StarPy.
Then I run with the command python ami.py USERNAME PASSWORD the following script:
import sys
from starpy import manager
f = manager.AMIFactory(sys.argv[1], sys.argv[2])
df = f.login('127.0.0.1',5038)
While monitoring the asterisk console and nothing happens.
Does anyone know what I am missing?
I would like to send a Ping action and wait for a Pong response.
I suppose that f.login() returns you an AMIProtocol instance that has a ping() method.
I don't know anything about starpy, so some vague advice:
Start Python as an interactive shell. Execute code and examine results on the spot. help function is your friend; try help(df) after the last line of your script.
Look at the examples directory in starpy distribution. Maybe 90% of the code you need is already there.
The following is pulled from the ami module (and a few other places) in the Asterisk Test Suite. We use starpy extensively throughout the Test Suite, so you may want to check it out for some examples. Assume that the following code resides in some class with member method login.
def login(self):
def on_login_success(self, ami):
self.ami_factory.ping().addCallback(ping_response)
return ami
def on_login_error(self, reason):
print "Failed to log into AMI"
return reason
def ping_response(self, ami)
print "Got a ping response!"
return ami
self.ami_factory = manager.AMIFactory("user", "mysecret")
self.ami_factory.login("127.0.0.1", 5038).addCallbacks(on_login_success, on_login_error)
Make sure as well that your manager.conf is configured properly. For the Asterisk Test Suite, we use the following:
[general]
enabled = yes
webenabled = yes
port = 5038
bindaddr = 127.0.0.1
[user]
secret = mysecret
read = system,call,log,verbose,agent,user,config,dtmf,reporting,cdr,dialplan,test
write = system,call,agent,user,config,command,reporting,originate

Dispatching an external script from Trace32's PRACTICE II script?

Is it possible to dispatch an external (python) script from Trace32 using its PRACTICE II scripting language?
For future googlers, like me, here is how to use the Lauterbach c-API to execute PRACTICE commands from Python. The TRACE32 application has to be open before you run your script. You also have to add 5 lines (including two blank lines) to your config.t32 file:
#You must have an empty line before
RCL=NETASSIST
PACKLEN=1024
PORT=20010
#and after these three parameters
At least the PORT parameter value is arbitary, but it has to match in your config and script. It defines the UDP port over which the API will be available.
This code demonstrates how you can use the the API in Python:
from ctypes import *
node = (c_char_p('NODE='),c_char_p('localhost'))
port = (c_char_p('PORT='),c_char_p('20010'))
plen = (c_char_p('PACKLEN='),c_char_p('1024'))
mydll = cdll.LoadLibrary(r'C:\T32\demo\api\capi\dll\T32api.dll')
error = mydll.T32_Config(*node)
error = mydll.T32_Config(*port)
error = mydll.T32_Config(*plen)
error = mydll.T32_Init()
error = mydll.T32_Attach(1)
#Try a PRACTICE command
cmd = c_char_p('DATA.DUMP 0xFF800000')
mydll.T32_Cmd(cmd)
Check that the T32api.dll is in the directory specified in the script.
Lauterbach provides more documentation for this api. Take a look in the demo\api\capi folder and this document http://www2.lauterbach.com/pdf/api_remote.pdf
Use OS.Screen to make a command prompt session.

Categories