Monthly Archives: June 2009

Google Voice your personal PBX if you can get by the Privacy Policy


Last Thursday, I received an invite to Google Voice (a.k.a. GrandCentral) after signing up for the beta months ago, a detail I’d practically forgotten. Google Voice is:

…a service that gives you one number for all your phones, voicemail that is easy as email, and many enhanced calling features like call blocking and screening, voicemail transcripts, call conferencing, international calls, and more.

imageIn other words it’s sort of like having a personal PBX. The feature set (see below) is rich not to mention free, at least for now:

I could easily see Google extending this for small businesses much like Google Apps for Domains which could be an interesting play in that space particularly given my company’s need for a phone system.

When you sign up for Google Voice you get to select your phone number with an option to choose from within a specific area or zip code. My area code (831) was available and within that area code I could choose a Santa Cruz prefix (among other surrounding cities/towns) and I paired that with a memorable last 4 digits.

Another feature of Google Voice optional transcription of calls though in a few test calls I’ve found it might convey the “gist” of the call but can get quite mangled. For example, you can see above a test call where I said “This is a test call using Google Voice trying to call my cell phone from my home phone in Scotts Valley California.” and you can see the result. Nonetheless, it’s a cool feature I’m sure will improve over time.

Here’s the GMail-like web UI (running in Prism):

Google Voice web UI

One minor detail: The Privacy Policy

This is all very cool although the biggest hurdle for me is the Privacy Policy which details the kind of information Google collects through this service. While it’s not really unusual nor unexpected it details how your information will be collected and used including:

When you use Google Voice, Google’s servers automatically record certain information about your use of Google Voice. Similar to other web services, Google Voice records information such as account activity (including storage usage, number of log-ins), data displayed or clicked on (including UI elements, links); and other log information (including browser type, IP-address, date and time of access, cookie ID, and referrer URL). Google’s servers also automatically collect telephony log information (including calling-party number, forwarding numbers, time and date of calls, duration of calls, SMS routing information, and types of calls).

There’s also a bit about transcription:

Voicemail Transcription – if you use Google Voice’s voicemail transcription service, Google may transcribe voicemail messages into text and email and/or SMS the resulting text to the email account or phone number(s) designated in your user settings. Google’s computers process the information in your messages for various purposes, including formatting and displaying the information to you, delivering related links, backing up your messages, and other purposes relating to offering you Google Voice.

Clearly, Google mines your data like it does for everything it offers though this service IMO goes further in that you’re more or less accepting the Privacy Policy on behalf of anyone calling you especially considering there’s no way for a caller to know you’re using Google Voice as it’s transparent.

I’ll experiment Google Voice for awhile but I’m not sure I’m ready to turn this amount of information over to Google regardless of Don’t be Evil.

Are you using Google Voice?

An HttpHandler for use with Facebook

imageIn my SocialMine Facebook application, which uses MIT’s Simile Exhibit, I needed to fetch Facebook FQL query results from the Exhibit client-side JavaScript. While it may not sound that complicated it’s not something directly supported by the Facebook Developer Toolkit (FDT). I created an HttpHandler to respond to the Exhibit requests for the JSON data which populates the Exhibit. The HTTP request includes a Referrer header that contains the necessary data, fb_sig_user and fb_sig_session_key to construct an instance of facebook.Components.FacebookService. For completeness here is a list of the queryparams contained in the Referrer URL with the important lines highlighted:

auth_token=1379094a2a42e1c0037a33048912a875
fb_sig_in_iframe=1
fb_sig_locale=en_US
fb_sig_in_new_facebook=1
fb_sig_time=1245301045.1412
fb_sig_added=1
fb_sig_profile_update_time=1241328269
fb_sig_expires=0
fb_sig_user=719571200
fb_sig_session_key=c93185e145713ce98d72dfc2-719571700
fb_sig_ss=57abbef0284354d029fe8a19fa00dfce
fb_sig_ext_perms=offline_access,email,auto_publish_recent_activity
fb_sig_api_key=33c52d0a0c9867f677a1f05154c28478
fb_sig_app_id=5012360767
fb_sig=9ad664af23910ca18aeb203203c366cd

My HttpHandler is an abstract class with a single abstract method called FacebookRequest that descendents override to handle the request. As you can see below the handler itself is quite simple, parsing the queryparams into a Dictionary, creating an instance of the FacebookService and calling FacebookRequest passing the service instance and the HttpContext passed to the handler.

public abstract class FacebookHandler : IHttpHandler
{
    private const string REQUEST_SESSION_KEY = "fb_sig_session_key";
    private const string REQUEST_USER_ID = "fb_sig_user";
    #region IHttpHandler Members
    public bool IsReusable
    {
        get { return false; }
    }
    void IHttpHandler.ProcessRequest(HttpContext ctxt)
    {
        facebook.Components.FacebookService f = new facebook.Components.FacebookService();
        f.ApplicationKey = WebConfigurationManager.AppSettings["APIKey"];
        f.Secret = WebConfigurationManager.AppSettings["Secret"];
        Dictionary<string, string> dic = new Dictionary<string, string>();
        string[] split = ctxt.Request.UrlReferrer.Query.Split(new char[] { '?', '&', '=' });
        // Skip the first item since it’s the "?"
        for (int i = 1; i < split.Length - 1; i += 2)
        {
            if(i < split.Length)
                dic.Add(split[i], split[i + 1]);
        }
        f.SessionKey = dic[REQUEST_SESSION_KEY];
        f.uid = Convert.ToInt64(dic[REQUEST_USER_ID]);
        FacebookRequest(f, ctxt);
    }
    #endregion
    protected abstract void FacebookRequest(facebook.Components.FacebookService fbservice, HttpContext ctxt);
}

The JavaScript of Simile Exhibit requests the JSON data using the following LINK tag:

<link href="friendsjson.aspx" type="application/json" rel="exhibit/data" />    

The reference to friendsjson.aspx isn’t actually an ASPX as it’s handled by a descendent of this HttpHandler which is registered in the httpHandlers section of the web.config as follows:

<add verb="*" path="friendsjson.aspx" type="FBFQL.JSONHandler" />

In my application the FacebookRequest method queries using FQL for profile data and returns a JSON result that populates the Exhibit.

Btw, if you’re looking for help on Facebook development be sure to read my wiki article.

EDI Purchase Order system goes live

If you’ve been reading my blog for long you probably have read a few previous posts where I blogged about EDI processing using CCNET. Well, yesterday the Purchase Order portion of the system went live so I sent a screenshot of the CCNET web dashboard to the Team at Falafel and our CTO, John Water’s replied with his modified version (right). I figure for those of you programming types you’d enjoy this…

image  image

At least, I got a good laugh from it.
For those familiar with EDI this custom system handles 810, 850, 855, 856 and 997 documents. Also, based on my FTP Provider for CCNET there should be a new source provider showing up on that project in the near future as one of the leads approached me about adding it.