| /* |
| * Copyright (C) 2007 Esmertec AG. |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.im.imps; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| |
| import com.android.im.engine.Contact; |
| import com.android.im.engine.ImErrorInfo; |
| import com.android.im.engine.ImException; |
| import com.android.im.engine.LoginInfo; |
| import com.android.im.imps.ImpsConnectionConfig.CirMethod; |
| import com.android.im.imps.ImpsConnectionConfig.TransportType; |
| |
| /** |
| * Represents the context of an IMPS session. The IMPS session is a framework in |
| * which the IMPS services are provided to the IMPS client. It's established |
| * when the client logs in and terminated when either the client logs out or the |
| * SAP decides to disconnect the session. |
| */ |
| public class ImpsSession { |
| private static final String KEY_CIR_HTTP_ADDRESS = "cirHttpAddress"; |
| private static final String KEY_CIR_TCP_PORT = "cirTcpPort"; |
| private static final String KEY_CIR_TCP_ADDRESS = "cirTcpAddress"; |
| private static final String KEY_CIR_METHOD = "CirMethod"; |
| private static final String KEY_SERVER_POLL_MIN = "serverPollMin"; |
| private static final String KEY_PASSWORD = "password"; |
| private static final String KEY_USERNAME = "username"; |
| private static final String KEY_KEEP_ALIVE_TIME = "keepAliveTime"; |
| private static final String KEY_SESSION_COOKIE = "sessionCookie"; |
| private static final String KEY_SESSION_ID = "sessionId"; |
| |
| private static final int DEFAULT_TCP_PORT = 3171; |
| |
| private ImpsConnection mConnection; |
| private String mId; |
| private String mCookie; |
| private long mKeepAliveTime; |
| private CirMethod mCurrentCirMethod; |
| private String mCirTcpAddress; |
| private int mCirTcpPort = DEFAULT_TCP_PORT; |
| private long mServerPollMin; |
| private String mCirHttpAddress; |
| private LoginInfo mLoginInfo; |
| |
| private boolean mCapablityRequest; |
| private List<CirMethod> mSupportedCirMethod; |
| |
| private Contact mLoginUser; |
| |
| PrimitiveElement mServiceTree; |
| |
| /** |
| * Flag that indicates this is a new created session or not. |
| */ |
| private boolean mNew; |
| |
| ImpsSession(ImpsConnection connection, LoginInfo info) throws ImException{ |
| mConnection = connection; |
| setLoginInfo(info); |
| |
| mNew = true; |
| mCookie = ImpsUtils.genSessionCookie(); |
| |
| mCirTcpPort = DEFAULT_TCP_PORT; |
| mServerPollMin = connection.getConfig().getDefaultServerPollMin(); |
| } |
| |
| ImpsSession(ImpsConnection connection, HashMap<String, String> values) |
| throws ImException { |
| mConnection = connection; |
| mNew = false; |
| mId = values.get(KEY_SESSION_ID); |
| if (mId == null || mId.length() == 0) { |
| throw new ImException(ImErrorInfo.INVALID_SESSION_CONTEXT, |
| "Missing session id"); |
| } |
| mCookie = values.get(KEY_SESSION_COOKIE); |
| if (mCookie == null || mCookie.length() == 0) { |
| throw new ImException(ImErrorInfo.INVALID_SESSION_CONTEXT, |
| "Missing session cookie"); |
| } |
| try { |
| mKeepAliveTime = Long.parseLong(values.get(KEY_KEEP_ALIVE_TIME)); |
| } catch (NumberFormatException e) { |
| throw new ImException(ImErrorInfo.INVALID_SESSION_CONTEXT, |
| "Invalid keepAliveTime"); |
| } |
| try { |
| mServerPollMin = Long.parseLong(values.get(KEY_SERVER_POLL_MIN)); |
| } catch (NumberFormatException e) { |
| throw new ImException(ImErrorInfo.INVALID_SESSION_CONTEXT, |
| "Invalid serverPollMin"); |
| } |
| String username = values.get(KEY_USERNAME); |
| String password = values.get(KEY_PASSWORD); |
| // Empty password might be valid |
| if (username == null || username.length() == 0 || password == null) { |
| throw new ImException(ImErrorInfo.INVALID_SESSION_CONTEXT, |
| "Invalid username or password"); |
| } |
| setLoginInfo(new LoginInfo(username, password)); |
| |
| mCurrentCirMethod = CirMethod.valueOf(values.get(KEY_CIR_METHOD)); |
| if (mCurrentCirMethod == CirMethod.STCP) { |
| mCirTcpAddress = values.get(KEY_CIR_TCP_ADDRESS); |
| if (mCirTcpAddress == null || mCirTcpAddress.length() == 0) { |
| throw new ImException(ImErrorInfo.INVALID_SESSION_CONTEXT, |
| "Missing CirTcpAddress"); |
| } |
| try { |
| mCirTcpPort = Integer.parseInt(values.get(KEY_CIR_TCP_PORT)); |
| } catch (NumberFormatException e) { |
| throw new ImException(ImErrorInfo.INVALID_SESSION_CONTEXT, |
| "Invalid CirTcpPort"); |
| } |
| } else if (mCurrentCirMethod == CirMethod.SHTTP) { |
| mCirHttpAddress = values.get(KEY_CIR_HTTP_ADDRESS); |
| } |
| } |
| |
| public HashMap<String, String> getContext() { |
| HashMap<String, String> values = new HashMap<String, String>(); |
| |
| values.put(KEY_SESSION_ID, mId); |
| values.put(KEY_SESSION_COOKIE, mCookie); |
| values.put(KEY_KEEP_ALIVE_TIME, Long.toString(mKeepAliveTime)); |
| values.put(KEY_USERNAME, mLoginInfo.getUserName()); |
| values.put(KEY_PASSWORD, mLoginInfo.getPassword()); |
| values.put(KEY_SERVER_POLL_MIN, Long.toString(mServerPollMin)); |
| |
| values.put(KEY_CIR_METHOD, mCurrentCirMethod.name()); |
| if(mCurrentCirMethod == CirMethod.STCP) { |
| values.put(KEY_CIR_TCP_ADDRESS, mCirTcpAddress); |
| values.put(KEY_CIR_TCP_PORT, Integer.toString(mCirTcpPort)); |
| } else if (mCurrentCirMethod == CirMethod.SHTTP) { |
| values.put(KEY_CIR_HTTP_ADDRESS, mCirHttpAddress); |
| } |
| return values; |
| } |
| |
| /** |
| * Gets the unique id of the session. |
| * |
| * @return the unique id of the session. |
| */ |
| public String getID() { |
| return mId; |
| } |
| |
| public void setId(String id) { |
| mId = id; |
| } |
| |
| public String getCookie() { |
| return mCookie; |
| } |
| |
| public String getUserName() { |
| return mLoginInfo.getUserName(); |
| } |
| |
| public String getPassword() { |
| return mLoginInfo.getPassword(); |
| } |
| |
| public LoginInfo getLoginInfo() { |
| return mLoginInfo; |
| } |
| /** |
| * Gets the auto logout timer value. |
| * |
| * @return the auto logout timer value. |
| */ |
| public long getKeepAliveTime() { |
| return mKeepAliveTime; |
| } |
| |
| public void setKeepAliveTime(long keepAliveTime) { |
| mKeepAliveTime = keepAliveTime; |
| } |
| |
| /** |
| * Gets if further capability request is required in the session. |
| * |
| * @return <code>true</code> if further capability request is required. |
| */ |
| public boolean isCapablityRequestRequired() { |
| return mCapablityRequest || mNew; |
| } |
| |
| public void setCapablityRequestRequired(boolean required) { |
| mCapablityRequest = required; |
| } |
| |
| public ImpsUserAddress getLoginUserAddress() { |
| return (ImpsUserAddress) mLoginUser.getAddress(); |
| } |
| |
| public Contact getLoginUser() { |
| return mLoginUser; |
| } |
| |
| /** |
| * Sets the Login information. After login successfully, the login |
| * information should be saved in the session context so that we can auto |
| * login when reconnect to the server. |
| * |
| * @param loginInfo the login information. |
| * @throws ImException |
| */ |
| private void setLoginInfo(LoginInfo loginInfo) throws ImException { |
| try { |
| ImpsAddress address = new ImpsUserAddress(loginInfo.getUserName()); |
| mLoginUser = new Contact(address, address.getScreenName()); |
| mLoginInfo = loginInfo; |
| } catch (IllegalArgumentException e) { |
| throw new ImException(ImErrorInfo.INVALID_USERNAME, |
| "Invalid username"); |
| } |
| } |
| |
| /** |
| * Gets a collection of CIR methods that are supported by both the client |
| * and the server. |
| * |
| * @return a collection of supported CIR methods |
| */ |
| public List<CirMethod> getSupportedCirMethods() { |
| return mSupportedCirMethod; |
| } |
| |
| public CirMethod getCurrentCirMethod() { |
| return mCurrentCirMethod; |
| } |
| |
| public void setCurrentCirMethod(CirMethod cirMethod) { |
| mCurrentCirMethod = cirMethod; |
| } |
| |
| /** |
| * Gets the IP address for standalone TCP/IP CIR method. |
| * |
| * @return the IP address for standalone TCP/IP CIR method |
| */ |
| public String getCirTcpAddress() { |
| return mCirTcpAddress; |
| } |
| |
| /** |
| * Gets the port number for the standalone TCP/IP CIR method. |
| * |
| * @return the port number for the standalone TCP/IP CIR method. |
| */ |
| public int getCirTcpPort() { |
| return mCirTcpPort; |
| } |
| |
| /** |
| * Gets the minimum time interval (in seconds) that MUST pass before two |
| * subsequent PollingRequest transactions. |
| * |
| * @return the minimum time interval in seconds. |
| */ |
| public long getServerPollMin() { |
| return mServerPollMin; |
| } |
| |
| /** |
| * Gets the URL used for standalone HTTP binding of CIR channel. |
| * |
| * @return the URL. |
| */ |
| public String getCirHttpAddress() { |
| return mCirHttpAddress; |
| } |
| |
| /** |
| * Gets the service tree of the features and functions that the server |
| * supports. |
| * |
| * @return the service tree. |
| */ |
| public PrimitiveElement getServiceTree() { |
| return mServiceTree; |
| } |
| |
| /** |
| * Perform client capability negotiation with the server asynchronously. |
| * |
| * @param completion Async completion object. |
| */ |
| public void negotiateCapabilityAsync(AsyncCompletion completion) { |
| Primitive capabilityRequest = buildCapabilityRequest(); |
| |
| AsyncTransaction tx = new AsyncTransaction( |
| mConnection.getTransactionManager(), completion) { |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| extractCapability(response); |
| } |
| |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { } |
| }; |
| |
| tx.sendRequest(capabilityRequest); |
| } |
| |
| /** |
| * Perform service negotiation with the server asynchronously. |
| * |
| * @param completion Async completion object. |
| */ |
| public void negotiateServiceAsync(AsyncCompletion completion) { |
| Primitive serviceRequest = buildServiceRequest(); |
| AsyncTransaction tx = new AsyncTransaction( |
| mConnection.getTransactionManager(), completion) { |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| mServiceTree = response.getElement(ImpsTags.AllFunctions).getFirstChild(); |
| } |
| |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { } |
| }; |
| |
| tx.sendRequest(serviceRequest); |
| } |
| |
| private Primitive buildCapabilityRequest() { |
| Primitive capabilityRequest = new Primitive(ImpsTags.ClientCapability_Request); |
| PrimitiveElement list = capabilityRequest.addElement(ImpsTags.CapabilityList); |
| list.addChild(ImpsTags.ClientType, ImpsClientCapability.getClientType()); |
| list.addChild(ImpsTags.AcceptedContentLength, Integer |
| .toString(ImpsClientCapability.getAcceptedContentLength())); |
| list.addChild(ImpsTags.ParserSize, |
| Integer.toString(ImpsClientCapability.getParserSize())); |
| list.addChild(ImpsTags.MultiTrans, |
| Integer.toString(ImpsClientCapability.getMultiTrans())); |
| |
| // TODO: MultiTransPerMessage is IMPS 1.3 |
| //list.addChild(ImpsTags.MultiTransPerMessage, |
| // Integer.toString(ImpsClientCapability.getMultiTransPerMessage())); |
| list.addChild(ImpsTags.InitialDeliveryMethod, |
| ImpsClientCapability.getInitialDeliveryMethod()); |
| list.addChild(ImpsTags.ServerPollMin, Long.toString(mServerPollMin)); |
| |
| for(TransportType supportedBear : ImpsClientCapability.getSupportedBearers()) { |
| list.addChild(ImpsTags.SupportedBearer, supportedBear.toString()); |
| } |
| |
| for(CirMethod supportedCirMethod : ImpsClientCapability.getSupportedCirMethods()) { |
| list.addChild(ImpsTags.SupportedCIRMethod, supportedCirMethod.toString()); |
| if (CirMethod.SUDP.equals(supportedCirMethod)) { |
| list.addChild(ImpsTags.UDPPort, |
| Integer.toString(mConnection.getConfig().getUdpPort())); |
| } |
| } |
| |
| return capabilityRequest; |
| } |
| |
| /* keep this method package private instead of private to avoid the |
| * overhead of calling from a inner class. |
| */ |
| void extractCapability(Primitive capabilityResponse) { |
| mSupportedCirMethod = new ArrayList<CirMethod>(); |
| |
| PrimitiveElement agreedList = capabilityResponse.getContentElement() |
| .getFirstChild(); |
| for (PrimitiveElement element : agreedList.getChildren()) { |
| String tag = element.getTagName(); |
| if (tag.equals(ImpsTags.SupportedCIRMethod)) { |
| try { |
| mSupportedCirMethod.add(CirMethod.valueOf(element.getContents())); |
| } catch (IllegalArgumentException e) { |
| ImpsLog.log("Unrecognized CIR method " + element.getContents()); |
| } |
| } else if (tag.equals(ImpsTags.TCPAddress)) { |
| mCirTcpAddress = element.getContents(); |
| } else if (tag.equals(ImpsTags.TCPPort)) { |
| mCirTcpPort = (int)ImpsUtils.parseLong(element.getContents(), |
| DEFAULT_TCP_PORT); |
| } else if (tag.equals(ImpsTags.ServerPollMin)) { |
| long defaultPollMin = mConnection.getConfig().getDefaultServerPollMin(); |
| mServerPollMin = ImpsUtils.parseLong(element.getContents(), |
| defaultPollMin); |
| if (mServerPollMin <= 0) { |
| mServerPollMin = defaultPollMin; |
| } |
| } else if (tag.equals(ImpsTags.CIRHTTPAddress) |
| || tag.equals(ImpsTags.CIRURL)) { |
| // This tag is CIRHTTPAddress in 1.3 and CIRURL in 1.2 |
| mCirHttpAddress = element.getChildContents(ImpsTags.URL); |
| } |
| } |
| } |
| |
| private Primitive buildServiceRequest() { |
| Primitive serviceRequest = new Primitive(ImpsTags.Service_Request); |
| PrimitiveElement functions = serviceRequest.addElement(ImpsTags.Functions); |
| PrimitiveElement features = functions.addChild(ImpsTags.WVCSPFeat); |
| features.addChild(ImpsTags.FundamentalFeat); |
| features.addChild(ImpsTags.PresenceFeat); |
| features.addChild(ImpsTags.IMFeat); |
| features.addChild(ImpsTags.GroupFeat); |
| serviceRequest.addElement(ImpsTags.AllFunctionsRequest, true); |
| return serviceRequest; |
| } |
| } |