/** * galaxy inc. * meetup client for android */ package com.galaxy.meetup.client.android.xmpp; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import android.accounts.AuthenticatorException; import android.accounts.OperationCanceledException; import android.content.Context; import android.content.res.Resources; import android.preference.PreferenceManager; import android.util.Base64; import android.util.Log; import com.galaxy.meetup.client.android.AuthData; import com.galaxy.meetup.client.android.R; import com.galaxy.meetup.client.android.content.EsAccount; import com.galaxy.meetup.client.util.EsLog; /** * * @author sihai * */ public abstract class GoogleTalkClient { private boolean mActive; private final String mAddress; private final String mBackendAddress; private final Context mContext; private final boolean mDebugModeEnabled; private final EsAccount mEsAccount; private String mGoogleToken; private String mJabberId; private final String mResource; private Socket mSocket; private GoogleTalkThread mThread; private BufferedWriter mWriter; //====================================================================================== // Inner class //====================================================================================== private final class GoogleTalkThread extends Thread { private volatile boolean mConnected; public GoogleTalkThread() { super(); mConnected = true; } public final void run() { try { mGoogleToken = AuthData.getAuthToken(mContext, mEsAccount.getName(), "webupdates"); } catch(Exception exception) { disconnect(3); if(EsLog.isLoggable("GoogleTalkClient", 3)) Log.d("GoogleTalkClient", "authentication failed", exception); exception.printStackTrace(); } if(null == mGoogleToken) { if(EsLog.isLoggable("GoogleTalkClient", 3)) Log.d("GoogleTalkClient", "authentication failed, null token"); disconnect(3); return; } try { if(EsLog.isLoggable("GoogleTalkClient", 3)) Log.d("GoogleTalkClient", (new StringBuilder("token ")).append(mGoogleToken).toString()); mSocket = new Socket("talk.google.com", 5222); resetWriter(); if(!mConnected) { if(EsLog.isLoggable("GoogleTalkClient", 3)) Log.d("GoogleTalkClient", "thread finished"); return; } else { MessageReader messagereader = new MessageReader(mSocket.getInputStream(), mDebugModeEnabled); while(mConnected) { switch(messagereader.read()) { case UNEXPECTED_FEATURES: if(EsLog.isLoggable("GoogleTalkClient", 4)) Log.i("GoogleTalkClient", "unexpected features"); disconnect(5); break; case END_OF_STREAM: if(EsLog.isLoggable("GoogleTalkClient", 4)) Log.i("GoogleTalkClient", "end of stream"); disconnect(4); break; case TLS_REQUIRED: if(EsLog.isLoggable("GoogleTalkClient", 4)) Log.i("GoogleTalkClient", "TLS required"); write("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); break; case PROCEED_WITH_TLS: if(EsLog.isLoggable("GoogleTalkClient", 4)) Log.i("GoogleTalkClient", "Proceed with TLS"); GoogleTalkClient.access$700(GoogleTalkClient.this); break; case AUTHENTICATION_REQUIRED: if(EsLog.isLoggable("GoogleTalkClient", 4)) Log.i("GoogleTalkClient", "Authenticated required"); write(Commands.authenticate(mGoogleToken)); break; case AUTHENTICATION_SUCCEEDED: break; case AUTHENTICATION_FAILED: if(EsLog.isLoggable("GoogleTalkClient", 4)) Log.i("GoogleTalkClient", "Authentication failed"); AuthData.invalidateAuthToken(mContext, mEsAccount.getName(), "webupdates"); mGoogleToken = null; disconnect(3); break; case STREAM_READY: if(EsLog.isLoggable("GoogleTalkClient", 4)) Log.i("GoogleTalkClient", "Authenticated successfully"); break; case JID_AVAILABLE: if(EsLog.isLoggable("GoogleTalkClient", 4)) Log.i("GoogleTalkClient", "jid available"); mJabberId = messagereader.getEventData(); break; case DATA_RECEIVED: onMessageReceived(Base64.decode(messagereader.getEventData(), 0)); break; default: break; } } if(EsLog.isLoggable("GoogleTalkClient", 3)) Log.d("GoogleTalkClient", "thread finished"); return; } } catch (IOException e) { if(EsLog.isLoggable("GoogleTalkClient", 3)) Log.d("GoogleTalkClient", "io exception"); disconnect(3); } catch (AuthenticatorException e) { if(EsLog.isLoggable("GoogleTalkClient", 3)) Log.d("GoogleTalkClient", "authenticator exception"); disconnect(3); } catch (OperationCanceledException e) { if(EsLog.isLoggable("GoogleTalkClient", 3)) Log.d("GoogleTalkClient", "operation canceled exception"); disconnect(3); } } public final void setDisconnected() { mConnected = false; } } public GoogleTalkClient(EsAccount esaccount, Context context, String s, String s1, String s2) { mEsAccount = esaccount; mContext = context; mAddress = s; mBackendAddress = s1; mResource = s2; mActive = false; Resources resources = context.getResources(); mDebugModeEnabled = PreferenceManager.getDefaultSharedPreferences(context).getBoolean(resources.getString(R.string.realtimechat_notify_setting_key), resources.getBoolean(R.bool.realtimechat_notify_setting_default_value)); } private void resetWriter() throws IOException { mWriter = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream())); } public final boolean active() { return mActive; } public final synchronized void connect() { mActive = true; if(mThread == null) { mThread = new GoogleTalkThread(); mThread.start(); } } public void disconnect() { disconnect(1); } public final synchronized void disconnect(int i) { if(EsLog.isLoggable("GoogleTalkClient", 3)) Log.d("GoogleTalkClient", (new StringBuilder("disconnect ")).append(i).toString()); mActive = false; if(null != mThread) { mThread.setDisconnected(); } if(null != mSocket) { try { mSocket.close(); } catch(IOException ioexception) { } } mSocket = null; mThread = null; onDisconnected(i); } public final EsAccount getAccount() { return mEsAccount; } public final Context getContext() { return mContext; } protected abstract void onConnected(); protected abstract void onDisconnected(int i); protected abstract void onMessageReceived(byte abyte0[]); public final boolean sendMessage(byte abyte0[]) { String s = mJabberId; boolean flag = false; if(s != null) { String s1 = mJabberId.split("/")[0]; String s2 = mJabberId; String s3 = mAddress; String s4 = Base64.encodeToString(abyte0, 0); flag = write((new StringBuilder("<message to='")).append(s1).append("' from='").append(s2).append("' type='headline'><push xmlns='google:push' channel='realtime-chat'><recipient to='").append(s3).append("' data=''/><data>").append(s4).append("</data></push></message>").toString()); } return flag; } public final synchronized boolean write(String s) { try { mWriter.write(s); mWriter.flush(); return true; } catch (IOException e) { if(EsLog.isLoggable("GoogleTalkClient", 4)) Log.i("GoogleTalkClient", "IOException while writing message"); disconnect(6); return false; } } static void access$700(GoogleTalkClient googletalkclient) { try { SSLContext sslcontext = SSLContext.getInstance("TLS"); sslcontext.init(null, null, null); Socket socket = sslcontext.getSocketFactory().createSocket(googletalkclient.mSocket, googletalkclient.mSocket.getInetAddress().getHostName(), googletalkclient.mSocket.getPort(), true); googletalkclient.mSocket = socket; googletalkclient.mSocket.setKeepAlive(true); googletalkclient.mSocket.setSoTimeout(60000); ((SSLSocket)socket).startHandshake(); googletalkclient.resetWriter(); } catch (Exception exception) { if(EsLog.isLoggable("GoogleTalkClient", 5)) Log.w("GoogleTalkClient", "Exception while starting TLS"); googletalkclient.disconnect(2); } } }