derekneuberger
New Member
- Joined
- Aug 4, 2008
- Messages
- 14
- Reaction score
- 0
I was planning on posting this once I got it working, but I have been unable to get fully there. So, I figured I would post it now to tap into some the knowledge floating around here. Any help on this is *greatly* appreciated!
I also want everyone to know that the credit for this script goes to its respective author, Paul Marks of http://www.pcmarks.net . I understand the script works fine in a roll-your-own Asterisk 1.6 installation. I am just having trouble implementing it on a build with Freepbx (PIAF, in my case). Last but not least, I was made aware of this script by kmem in the #pbxinaflash channel on freenode. Some of the code I will post is his or came from him and all of the credit of finding this gem goes to him.
Without further ado:
Code is also attached (change filename ending from txt to agi) and available at original source: http://www.pmarks.net/posted_links/google-voice-dialout.agi .
This is where I am at:
I copied the script to "/var/lib/asterisk/agi-bin" and made it executable by issuing "chmod -x google-voice-dialout.agi" . I already have an inbound route setup for my gizmo account, so running the script manually (like instructed in the notes) successfully completes a call. However, when trying to complete an outbound call from an endpoint it fails. I have tracked what I believe to be the problem as the "agi_dnid" not being pulled properly (it is being delivered to the script as "unknown"). Further, I believe this problem is being caused by an improper outbound route on my part. My outbound route setup is as follows:
I have an outbound route pointing to a custom trunk. The custom trunk is:
I have the custom context, "gv-doout-custom", added to my "extensions_custom.conf" file:
I haven't gotten to the perils of ensuring the bridge statement in the inbound route functions. I am making the assumption that if someone points me down the right path with the outbound, the inbound might fall into place.
Thank you again for any help provided and looking forward to getting Google calling through PIAF a reality again!
~derek
I also want everyone to know that the credit for this script goes to its respective author, Paul Marks of http://www.pcmarks.net . I understand the script works fine in a roll-your-own Asterisk 1.6 installation. I am just having trouble implementing it on a build with Freepbx (PIAF, in my case). Last but not least, I was made aware of this script by kmem in the #pbxinaflash channel on freenode. Some of the code I will post is his or came from him and all of the credit of finding this gem goes to him.
Without further ado:
Code:
#!/usr/bin/env python
# google-voice-dialout.agi
# Paul Marks (www.pmarks.net)
#
# This is an Asterisk 1.6 script to place outgoing calls through Google Voice.
# It will automatically sign into the web interface, and submit a click2call
# request through your registered Gizmo number. Asterisk can then answer
# the incoming call, and Bridge() it into your original outgoing call.
#
# I deduced the click2call sequence by using the "Live HTTP Headers" Firefox
# plugin. If the website changes too much, this script will probably stop
# working, so don't use it for anything too important.
#
# This assumes you've already configured Asterisk to receive Gizmo calls.
#
#
# This rule will redirect outbound calls to this script:
# exten => _1NXXNXXXXXX,1,AGI(google-voice-dialout.agi)
#
# This rule will connect the inbound GV/Gizmo calls:
# exten => s/6502650000,1,Bridge(${DB_DELETE(gv_dialout/channel)}, p)
# ^-- Put your 10-digit Google Voice number here.
#
#
# To test this script from the command line without Asterisk, type the
# following. Be sure to type a few linefeeds at the end:
#
# $ ./google-voice-dialout.agi
# agi_channel:
# agi_dnid: 18004664411
#
# Put your Google login and Gizmo number here:
USERNAME = "bob"
PASSWORD = "hunter2"
GIZMO_NUMBER = "17470000000"
import httplib
import urllib
import re
import sys
import time
class Error(Exception):
pass
def ReadAgiEnvironment():
env = {}
while 1:
line = sys.stdin.readline().strip()
if not line:
break
key, data = line.split(':')
env[key.strip()] = data.strip()
return env
def SendAgi(cmd):
sys.stdout.write("%s\n" % cmd)
sys.stdout.flush()
sys.stdin.readline()
class SimpleCookieJar(object):
cookie_re = re.compile(r"(?i)set-cookie: (\w+)=([^;]+).*")
def __init__(self):
self.cookies = {}
def addCookies(self, response):
for header in response.msg.headers:
m = self.cookie_re.match(header)
if not m:
continue
self.cookies[m.group(1)] = m.group(2)
def get(self):
return "; ".join("%s=%s" % kv for kv in self.cookies.iteritems())
class GVClickToCall(object):
USER_AGENT = "google-voice-dialout.agi/1.1"
def __init__(self, username, password, via, dial):
self.username = username
self.password = password
self.via = via
self.dial = dial
self.cj = SimpleCookieJar()
self.h = httplib.HTTPSConnection("www.google.com")
self.login()
self.placeCall()
self.logout()
def login(self):
print >>sys.stderr, "Logging in."
postdata = urllib.urlencode({ "Email": self.username,
"Passwd": self.password })
self.doRequest(
method="POST", url="/accounts/ServiceLoginAuth",
body=postdata,
headers={ "Content-Type": "application/x-www-form-urlencoded" })
# Start at https://www.google.com/voice, and collect cookies as we
# follow all the redirects.
PREFIX = "https://www.google.com/"
location = "/voice"
for i in xrange(5):
response, html = self.doRequest(
method="GET", url=location,
headers={})
location = response.getheader("location")
if not location:
# No more redirects, yay!
break
# All redirects should fall within the same domain.
if not location.startswith(PREFIX):
raise Error("Unexpected redirect: %s" % location)
location = location[len(PREFIX)-1:]
# Scrape magic _rnr_se value from the HTML.
m = re.search(r'name="_rnr_se" type="hidden" value="([^"]+)"', html)
if not m:
raise Error("Can't find _rnr_se. Not logged in?")
self.magic_rnr_se = m.group(1)
def placeCall(self):
print >>sys.stderr, "Calling %s via %s" % (self.dial, self.via)
postdata = urllib.urlencode({ "outgoingNumber": self.dial,
"forwardingNumber": self.via,
"_rnr_se": self.magic_rnr_se })
response, http = self.doRequest(
method="POST", url="/voice/call/connect",
body=postdata,
headers={ "Content-Type": "application/x-www-form-urlencoded" })
print >>sys.stderr, "Dial response:", http
def logout(self):
self.doRequest(
method="GET", url="/accounts/Logout",
headers={ "Connection": "close" })
print >>sys.stderr, "Logged out."
def doRequest(self, headers, **kw):
headers["User-agent"] = self.USER_AGENT
headers["Cookie"] = self.cj.get()
self.h.request(headers=headers, **kw)
response = self.h.getresponse()
self.cj.addCookies(response)
return response, response.read()
def main():
env = ReadAgiEnvironment()
print >>sys.stderr, env
agi_channel = env["agi_channel"]
agi_dnid = env["agi_dnid"]
# Write the channel ID to Asterisk's database, so it can be accessed
# by the incoming call when it arrives.
SendAgi("database put gv_dialout channel %s" % agi_channel)
SendAgi("answer")
try:
GVClickToCall(username=USERNAME, password=PASSWORD,
dial=agi_dnid, via=GIZMO_NUMBER)
# Asterisk should patch in the incoming call while we're asleep.
time.sleep(10)
finally:
SendAgi("hangup")
if __name__ == '__main__':
main()
This is where I am at:
I copied the script to "/var/lib/asterisk/agi-bin" and made it executable by issuing "chmod -x google-voice-dialout.agi" . I already have an inbound route setup for my gizmo account, so running the script manually (like instructed in the notes) successfully completes a call. However, when trying to complete an outbound call from an endpoint it fails. I have tracked what I believe to be the problem as the "agi_dnid" not being pulled properly (it is being delivered to the script as "unknown"). Further, I believe this problem is being caused by an improper outbound route on my part. My outbound route setup is as follows:
I have an outbound route pointing to a custom trunk. The custom trunk is:
Code:
Custom Dial String: Local/$OUTNUM$@gv-doout-custom
Code:
[gv-doout-custom]
exten => _1NXXNXXXXXX,1,AGI(google-voice-dialout.agi)
Thank you again for any help provided and looking forward to getting Google calling through PIAF a reality again!
~derek