/*==========================================================================*\ | $Id: GoogleVoice.java,v 1.1 2010/05/11 14:51:35 aallowat Exp $ |*-------------------------------------------------------------------------*| | Copyright (C) 2009 Virginia Tech | | This file is part of Web-CAT. | | Web-CAT is free software; you can redistribute it and/or modify | it under the terms of the GNU Affero General Public License as published | by the Free Software Foundation; either version 3 of the License, or | (at your option) any later version. | | Web-CAT is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU Affero General Public License | along with Web-CAT; if not, see <http://www.gnu.org/licenses/>. \*==========================================================================*/ package org.webcat.notifications.googlevoice; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.params.HttpClientParams; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultRedirectHandler; import org.apache.http.message.BasicNameValuePair; //------------------------------------------------------------------------- /** * Provides access to Google Voice services. Currently, only sending SMS * messages is supported. * * @author Tony Allevato * @version $Id: GoogleVoice.java,v 1.1 2010/05/11 14:51:35 aallowat Exp $ */ public class GoogleVoice { //~ Constructors .......................................................... // ---------------------------------------------------------- /** * Initializes the Google Voice service. * * @param username the username of the Google Voice account * @param password the account password * @param source a string that identifies the application using the service * @param delegate the delegate notified when operations succeed or fail */ public GoogleVoice(String username, String password, String source, GoogleVoiceDelegate delegate) { this.username = username; this.password = password; this.source = source; this.delegate = delegate; } //~ Methods ............................................................... // ---------------------------------------------------------- /** * Logs in to the Google Voice service. */ public void login() { HttpUriRequest request = buildRequest( CLIENT_LOGIN_URL, true, "accountType", "GOOGLE", "Email", username, "Passwd", password, "service", "grandcentral", "source", source); new AsyncURLConnection(request, new SimpleURLConnectionDelegate() { public void didFinishLoading() { if (statusCode() == HttpStatus.SC_OK) { Pattern pattern = Pattern.compile("^auth=(.*)$", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); Matcher matcher = pattern.matcher(responseString()); if (matcher.find()) { authToken = matcher.group(1); } if (authToken != null) { getRnrSeToken(); } else { delegate.loginFailed(GoogleVoice.this, new IOException( "No authorization token received.")); } } else { delegate.loginFailed(GoogleVoice.this, new IOException( "Google Voice login failed with status code " + statusCode())); } } public void didFailWithException(IOException e) { delegate.loginFailed(GoogleVoice.this, e); } }); } // ---------------------------------------------------------- /** * Logs out of the Google Voice service. */ public void logout() { HttpUriRequest request = buildRequest(CLIENT_LOGOUT_URL, false); new AsyncURLConnection(request, null); // Don't bother waiting for this to complete. } // ---------------------------------------------------------- /** * Sends a text message to a mobile phone. * * @param toNumber the destination number for the text message * @param content the text message to send */ public void sendSMS(String toNumber, String content) { HttpUriRequest request = buildRequest( SEND_SMS_URL, true, "auth", authToken, "phoneNumber", toNumber, "text", content, "_rnr_se", _rnr_se); new AsyncURLConnection(request, new SimpleURLConnectionDelegate() { public void didFinishLoading() { if (statusCode() == HttpStatus.SC_OK) { delegate.sendSMSSucceeded(GoogleVoice.this); } else { delegate.sendSMSFailed(GoogleVoice.this, new IOException("GoogleVoice.sendSMS responded " + "with status code " + statusCode())); } } public void didFailWithException(IOException e) { delegate.sendSMSFailed(GoogleVoice.this, e); } }); } // ---------------------------------------------------------- /** * Constructs an HTTP request with the given URL, method, and parameters. * * @param url the URL of the request * @param isPost true for a POST request, false for a GET request * @param params a list of parameter names and values */ private HttpUriRequest buildRequest(String url, boolean isPost, Object... params) { if (isPost) { ArrayList<BasicNameValuePair> paramList = new ArrayList<BasicNameValuePair>(); for (int i = 0; i < params.length; i += 2) { paramList.add(new BasicNameValuePair( params[i].toString(), params[i + 1].toString())); } HttpPost request = new HttpPost(url); request.addHeader("User-Agent", USER_AGENT); try { request.setEntity(new UrlEncodedFormEntity(paramList, "UTF-8")); } catch (UnsupportedEncodingException e) { // Do nothing. } return request; } else { StringBuffer buffer = new StringBuffer(); buffer.append(url); if (params.length > 0) { buffer.append("?"); buffer.append(params[0]); String encoded = params[1].toString(); try { encoded = URLEncoder.encode(encoded, "UTF-8"); } catch (UnsupportedEncodingException e) { // Do nothing; } buffer.append("="); buffer.append(encoded); for (int i = 2; i < params.length; i += 2) { buffer.append("&"); buffer.append(params[i]); encoded = params[i + 1].toString(); try { encoded = URLEncoder.encode(encoded, "UTF-8"); } catch (UnsupportedEncodingException e) { // Do nothing; } buffer.append("="); buffer.append(encoded); } } HttpGet request = new HttpGet(buffer.toString()); request.addHeader("User-Agent", USER_AGENT); return request; } } // ---------------------------------------------------------- /** * Gets the _rnr_se token needed for further POST requests after the login * method is called. */ private void getRnrSeToken() { HttpUriRequest request = buildRequest( GENERAL_PAGE_URL, false, "auth", authToken); new AsyncURLConnection(request, new SimpleURLConnectionDelegate() { public void didFinishLoading() { if (statusCode() == HttpStatus.SC_OK) { String p1 = responseString().split("'_rnr_se': '", 2)[1]; _rnr_se = p1.split("',", 2)[0]; delegate.loginSucceeded(GoogleVoice.this); } else { delegate.loginFailed(GoogleVoice.this, new IOException( "Could not retrieve _rnr_se token; status code " + statusCode())); } } public void didFailWithException(IOException e) { delegate.loginFailed(GoogleVoice.this, e); } }); } //~ Static/instance variables ............................................. public static final String GENERAL_PAGE_URL = "https://www.google.com/voice/"; public static final String CLIENT_LOGIN_URL = "https://www.google.com/accounts/ClientLogin"; public static final String CLIENT_LOGOUT_URL = "https://www.google.com/voice/account/logout"; public static final String SEND_SMS_URL = "https://www.google.com/voice/sms/send/"; final static String USER_AGENT = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) " + "AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.A.B.C " + "Safari/525.13"; private String username; private String password; private String source; private GoogleVoiceDelegate delegate; private String _rnr_se; private String authToken; }