frenchfry wrote:Great job! The latest version is the best for me.
What is the source code written and compiled in?
This may help you
This is the public domain code for asterisk made by Paul Marks:
Code: Select all
#!/usr/bin/env python
# google-voice-dialout.agi
# Paul Marks (www.pmarks.net)
# This code is Public Domain.
#
# 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()