1b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu/* 2b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * Copyright (C) 2013 The Android Open Source Project 3b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * 4b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * Licensed under the Apache License, Version 2.0 (the "License"); 5b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * you may not use this file except in compliance with the License. 6b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * You may obtain a copy of the License at 7b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * 8b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * http://www.apache.org/licenses/LICENSE-2.0 9b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * 10b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * Unless required by applicable law or agreed to in writing, software 11b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * distributed under the License is distributed on an "AS IS" BASIS, 12b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * See the License for the specific language governing permissions and 14b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * limitations under the License. 15b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu */ 16b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu 17b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hupackage com.android.exchange.service; 18b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 1962c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Huimport android.content.ContentResolver; 20328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport android.content.ContentUris; 21c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Huimport android.content.ContentValues; 22b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport android.content.Context; 23b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport android.net.Uri; 24b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport android.os.Build; 2562c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Huimport android.os.Bundle; 26b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport android.text.TextUtils; 27b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport android.text.format.DateUtils; 28b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport android.util.Base64; 29b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 30ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport com.android.emailcommon.internet.MimeUtility; 31b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport com.android.emailcommon.provider.Account; 32c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Huimport com.android.emailcommon.provider.EmailContent; 33b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport com.android.emailcommon.provider.HostAuth; 34b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Huimport com.android.emailcommon.provider.Mailbox; 35f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Huimport com.android.emailcommon.service.AccountServiceProxy; 36b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport com.android.emailcommon.utility.EmailClientConnectionManager; 37328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Huimport com.android.emailcommon.utility.Utility; 38b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport com.android.exchange.Eas; 39b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport com.android.exchange.EasResponse; 409383babdbd7c0049a0eb238819a5d9737232e8ecYu Ping Huimport com.android.exchange.eas.EasConnectionCache; 416ac502883abcecc4c80b26ed2b1a2a1e7308505cAlon Albertimport com.android.exchange.utility.CurlLogger; 42a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Leeimport com.android.exchange.utility.WbxmlResponseLogger; 43c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Huimport com.android.mail.utils.LogUtils; 44b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 45b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.HttpEntity; 46b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.client.HttpClient; 4703735a839ba61710f887fffd6d3f605c0b127c2eMartin Hibdonimport org.apache.http.client.methods.HttpGet; 48bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Huimport org.apache.http.client.methods.HttpOptions; 49b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.client.methods.HttpPost; 50b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Huimport org.apache.http.client.methods.HttpUriRequest; 51b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.entity.ByteArrayEntity; 52b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.impl.client.DefaultHttpClient; 53b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.params.BasicHttpParams; 54b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.params.HttpConnectionParams; 55b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.params.HttpParams; 561d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albertimport org.apache.http.protocol.BasicHttpProcessor; 57b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 58b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport java.io.IOException; 59b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport java.net.URI; 60b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Huimport java.security.cert.CertificateException; 61b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 62b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu/** 63b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * Base class for communicating with an EAS server. Anything that needs to send messages to the 64b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * server can subclass this to get access to the {@link #sendHttpClientPost} family of functions. 65c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu * TODO: This class has a regrettable name. It's not a connection, but rather a task that happens 66c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu * to have (and use) a connection to the server. 67b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 68ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hupublic class EasServerConnection { 69c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu /** Logging tag. */ 70110837ebff288a75f9bda067c38e2c46797d99b5Alon Albert private static final String TAG = Eas.LOG_TAG; 71c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu 72b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu /** 73b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * Timeout for establishing a connection to the server. 74b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 75b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu private static final long CONNECTION_TIMEOUT = 20 * DateUtils.SECOND_IN_MILLIS; 76b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 77b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu /** 78b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * Timeout for http requests after the connection has been established. 79b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 80b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu protected static final long COMMAND_TIMEOUT = 30 * DateUtils.SECOND_IN_MILLIS; 81b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 82b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu private static final String DEVICE_TYPE = "Android"; 83328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu private static final String USER_AGENT = DEVICE_TYPE + '/' + Build.VERSION.RELEASE + '-' + 84b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu Eas.CLIENT_VERSION; 85b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 86ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu /** Message MIME type for EAS version 14 and later. */ 87ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu private static final String EAS_14_MIME_TYPE = "application/vnd.ms-sync.wbxml"; 88b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 89ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu /** 90ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * Value for {@link #mStoppedReason} when we haven't been stopped. 91ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu */ 92ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu public static final int STOPPED_REASON_NONE = 0; 93ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu 94ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu /** 95ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * Passed to {@link #stop} to indicate that this stop request should terminate this task. 96ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu */ 97ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu public static final int STOPPED_REASON_ABORT = 1; 98ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu 99ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu /** 100ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * Passed to {@link #stop} to indicate that this stop request should restart this task (e.g. in 101ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * order to reload parameters). 102ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu */ 103ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu public static final int STOPPED_REASON_RESTART = 2; 104ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu 105328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu private static final String[] ACCOUNT_SECURITY_KEY_PROJECTION = 106328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu { EmailContent.AccountColumns.SECURITY_SYNC_KEY }; 107328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu 108f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu private static String sDeviceId = null; 109f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu 110b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu protected final Context mContext; 1110a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu // TODO: Make this private if possible. Subclasses must be careful about altering the HostAuth 1120a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu // to not screw up any connection caching (use redirectHostAuth). 11325b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu protected final HostAuth mHostAuth; 1140a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu protected final Account mAccount; 115328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu private final long mAccountId; 116b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 117b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu // Bookkeeping for interrupting a request. This is primarily for use by Ping (there's currently 118b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // no mechanism for stopping a sync). 119b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // Access to these variables should be synchronized on this. 120b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu private HttpUriRequest mPendingRequest = null; 121b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu private boolean mStopped = false; 122ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu private int mStoppedReason = STOPPED_REASON_NONE; 123b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 124b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu /** The protocol version to use, as a double. */ 125ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu private double mProtocolVersion = 0.0d; 126b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu /** Whether {@link #setProtocolVersion} was last called with a non-null value. */ 127b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu private boolean mProtocolVersionIsSet = false; 128d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu 129ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu /** 130ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * The client for any requests made by this object. This is created lazily, and cleared 131ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * whenever our host auth is redirected. 132ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu */ 133ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu private HttpClient mClient; 134ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 1353054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu /** 1363054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu * This is used only to check when our client needs to be refreshed. 1373054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu */ 1383054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu private EmailClientConnectionManager mClientConnectionManager; 1393054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu 140ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public EasServerConnection(final Context context, final Account account, 141275e73703e09a1211ae6aa6fc2a43226e1fcdeedMartin Hibdon final HostAuth hostAuth) { 142b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu mContext = context; 14325b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu mHostAuth = hostAuth; 1440a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu mAccount = account; 145328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu mAccountId = account.mId; 146ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu setProtocolVersion(account.mProtocolVersion); 147b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 148b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 149d92a75c707461188e8743149476e8f49ef191b42Tony Mantler protected EmailClientConnectionManager getClientConnectionManager() 150d92a75c707461188e8743149476e8f49ef191b42Tony Mantler throws CertificateException { 1513054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu final EmailClientConnectionManager connManager = 1523054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu EasConnectionCache.instance().getConnectionManager(mContext, mHostAuth); 1533054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu if (mClientConnectionManager != connManager) { 1543054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu mClientConnectionManager = connManager; 1553054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu mClient = null; 1563054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu } 1573054f5a5cb02250643af387b9107780fcbc8ac25Yu Ping Hu return connManager; 15897f38cd6004b54afe9a949658d9962abe8f1f24eYu Ping Hu } 15997f38cd6004b54afe9a949658d9962abe8f1f24eYu Ping Hu 160ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public void redirectHostAuth(final String newAddress) { 161ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu mClient = null; 16225b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu mHostAuth.mAddress = newAddress; 163c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu if (mHostAuth.isSaved()) { 1649383babdbd7c0049a0eb238819a5d9737232e8ecYu Ping Hu EasConnectionCache.instance().uncacheConnectionManager(mHostAuth); 165c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu final ContentValues cv = new ContentValues(1); 166c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu cv.put(EmailContent.HostAuthColumns.ADDRESS, newAddress); 167c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu mHostAuth.update(mContext, cv); 168c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu } 169b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 170b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 171d92a75c707461188e8743149476e8f49ef191b42Tony Mantler private HttpClient getHttpClient(final long timeout) throws CertificateException { 172ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu if (mClient == null) { 173ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu final HttpParams params = new BasicHttpParams(); 174ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu HttpConnectionParams.setConnectionTimeout(params, (int)(CONNECTION_TIMEOUT)); 175ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu HttpConnectionParams.setSoTimeout(params, (int)(timeout)); 176ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu HttpConnectionParams.setSocketBufferSize(params, 8192); 1771d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert mClient = new DefaultHttpClient(getClientConnectionManager(), params) { 1789c7165d4c6b90101b781f90b17451efd42a17929Martin Hibdon @Override 1791d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert protected BasicHttpProcessor createHttpProcessor() { 1801d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert final BasicHttpProcessor processor = super.createHttpProcessor(); 1811d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert processor.addRequestInterceptor(new CurlLogger()); 182a5fd5a343a8698978a88c7d8907de19a07fce2abAnthony Lee processor.addResponseInterceptor(new WbxmlResponseLogger()); 1831d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert return processor; 1841d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert } 1851d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert }; 186ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 187ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu return mClient; 188b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 189b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 19025b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu private String makeAuthString() { 19125b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu final String cs = mHostAuth.mLogin + ":" + mHostAuth.mPassword; 192b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu return "Basic " + Base64.encodeToString(cs.getBytes(), Base64.NO_WRAP); 193b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 194b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 19525b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu private String makeUserString() { 196f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu if (sDeviceId == null) { 197f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu sDeviceId = new AccountServiceProxy(mContext).getDeviceId(); 198f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu if (sDeviceId == null) { 199f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu LogUtils.e(TAG, "Could not get device id, defaulting to '0'"); 200f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu sDeviceId = "0"; 201f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu } 202b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 20325b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu return "&User=" + Uri.encode(mHostAuth.mLogin) + "&DeviceId=" + 204f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu sDeviceId + "&DeviceType=" + DEVICE_TYPE; 205b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 206b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 20725b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu private String makeBaseUriString() { 20825b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu return EmailClientConnectionManager.makeScheme(mHostAuth.shouldUseSsl(), 20925b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu mHostAuth.shouldTrustAllServerCerts(), mHostAuth.mClientCertAlias) + 21025b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu "://" + mHostAuth.mAddress + "/Microsoft-Server-ActiveSync"; 211b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 212b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 213ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public String makeUriString(final String cmd) { 21425b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu String uriString = makeBaseUriString(); 215b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu if (cmd != null) { 21625b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu uriString += "?Cmd=" + cmd + makeUserString(); 217b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 218b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu return uriString; 219b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 220b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 221ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu private String makeUriString(final String cmd, final String extra) { 222ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return makeUriString(cmd) + extra; 223b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 224b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 225b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu /** 226d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu * If a sync causes us to update our protocol version, this function must be called so that 227d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu * subsequent calls to {@link #getProtocolVersion()} will do the right thing. 228b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * @return Whether the protocol version changed. 229d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu */ 230b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu public boolean setProtocolVersion(String protocolVersionString) { 231be22ff8b8b3aa6057de165b76da433cabad4dcfdYu Ping Hu mProtocolVersionIsSet = (protocolVersionString != null); 232ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (protocolVersionString == null) { 233ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu protocolVersionString = Eas.DEFAULT_PROTOCOL_VERSION; 234ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 235b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu final double oldProtocolVersion = mProtocolVersion; 236ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu mProtocolVersion = Eas.getProtocolVersionDouble(protocolVersionString); 237b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return (oldProtocolVersion != mProtocolVersion); 238d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu } 239d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu 240d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu /** 241ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * @return The protocol version for this connection. 242d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu */ 243ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public double getProtocolVersion() { 244ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return mProtocolVersion; 245d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu } 246d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu 247d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu /** 248328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu * @return The useragent string for our client. 249328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu */ 250328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu public final String getUserAgent() { 251328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu return USER_AGENT; 252328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu } 253328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu 254328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu /** 255ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * Send an http OPTIONS request to server. 256ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @return The {@link EasResponse} from the Exchange server. 257ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @throws IOException 258b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 259d92a75c707461188e8743149476e8f49ef191b42Tony Mantler protected EasResponse sendHttpClientOptions() throws IOException, CertificateException { 260ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu // For OPTIONS, just use the base string and the single header 261ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu final HttpOptions method = new HttpOptions(URI.create(makeBaseUriString())); 26225b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu method.setHeader("Authorization", makeAuthString()); 263328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu method.setHeader("User-Agent", getUserAgent()); 264ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu return EasResponse.fromHttpRequest(getClientConnectionManager(), 265ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu getHttpClient(COMMAND_TIMEOUT), method); 266ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 267ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 268ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu protected void resetAuthorization(final HttpPost post) { 269ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.removeHeaders("Authorization"); 270ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.setHeader("Authorization", makeAuthString()); 271ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 272ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 273ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu /** 274ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * Make an {@link HttpPost} for a specific request. 275ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @param uri The uri for this request, as a {@link String}. 276ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @param entity The {@link HttpEntity} for this request. 277ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @param contentType The Content-Type for this request. 278ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @param usePolicyKey Whether or not a policy key should be sent. 279ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @return 280ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu */ 281ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public HttpPost makePost(final String uri, final HttpEntity entity, final String contentType, 282ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu final boolean usePolicyKey) { 283ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu final HttpPost post = new HttpPost(uri); 284ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.setHeader("Authorization", makeAuthString()); 285ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu post.setHeader("MS-ASProtocolVersion", String.valueOf(mProtocolVersion)); 286328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu post.setHeader("User-Agent", getUserAgent()); 287ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.setHeader("Accept-Encoding", "gzip"); 288b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // If there is no entity, we should not be setting a content-type since this will 289b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee // result in a 400 from the server in the case of loading an attachment. 290b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee if (contentType != null && entity != null) { 291ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.setHeader("Content-Type", contentType); 292ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 293b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu if (usePolicyKey) { 294b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // If there's an account in existence, use its key; otherwise (we're creating the 295b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // account), send "0". The server will respond with code 449 if there are policies 296b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // to be enforced 2970a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu final String key; 298328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu final String accountKey; 299328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu if (mAccountId == Account.NO_ACCOUNT) { 300328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu accountKey = null; 301328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu } else { 302328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu accountKey = Utility.getFirstRowString(mContext, 303328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId), 304328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu ACCOUNT_SECURITY_KEY_PROJECTION, null, null, null, 0); 305328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu } 3060a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu if (!TextUtils.isEmpty(accountKey)) { 3070a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu key = accountKey; 3080a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu } else { 3090a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu key = "0"; 310b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 311ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.setHeader("X-MS-PolicyKey", key); 312b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 313ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.setEntity(entity); 314ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu return post; 315bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Hu } 316bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Hu 31703735a839ba61710f887fffd6d3f605c0b127c2eMartin Hibdon public HttpGet makeGet(final String uri) { 31803735a839ba61710f887fffd6d3f605c0b127c2eMartin Hibdon final HttpGet get = new HttpGet(uri); 31903735a839ba61710f887fffd6d3f605c0b127c2eMartin Hibdon return get; 32003735a839ba61710f887fffd6d3f605c0b127c2eMartin Hibdon } 32103735a839ba61710f887fffd6d3f605c0b127c2eMartin Hibdon 322bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Hu /** 323b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * Make an {@link HttpOptions} request for this connection. 324b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * @return The {@link HttpOptions} object. 325b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu */ 326b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu public HttpOptions makeOptions() { 327b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu final HttpOptions method = new HttpOptions(URI.create(makeBaseUriString())); 328b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu method.setHeader("Authorization", makeAuthString()); 329b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu method.setHeader("User-Agent", getUserAgent()); 330b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return method; 331b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 332b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu 333b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu /** 334b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * Send a POST request to the server. 335b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @param cmd The command we're sending to the server. 336b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @param entity The {@link HttpEntity} containing the payload of the message. 337b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @param timeout The timeout for this POST. 338b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @return The response from the Exchange server. 339b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @throws IOException 340b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 3410a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu protected EasResponse sendHttpClientPost(String cmd, final HttpEntity entity, 342d92a75c707461188e8743149476e8f49ef191b42Tony Mantler final long timeout) throws IOException, CertificateException { 343b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu final boolean isPingCommand = cmd.equals("Ping"); 344b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 345b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // Split the mail sending commands 346e0743ba69a35b525daef103dd273ec1cd1c349f4Martin Hibdon // TODO: This logic should not be here, the command should be generated correctly 347e0743ba69a35b525daef103dd273ec1cd1c349f4Martin Hibdon // in a subclass of EasOperation. 348b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu String extra = null; 349b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu boolean msg = false; 350b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu if (cmd.startsWith("SmartForward&") || cmd.startsWith("SmartReply&")) { 351b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu final int cmdLength = cmd.indexOf('&'); 352b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu extra = cmd.substring(cmdLength); 353b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu cmd = cmd.substring(0, cmdLength); 354b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu msg = true; 355b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } else if (cmd.startsWith("SendMail&")) { 356b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu msg = true; 357b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 358b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 359b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // Send the proper Content-Type header; it's always wbxml except for messages when 360b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // the EAS protocol version is < 14.0 361b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // If entity is null (e.g. for attachments), don't set this header 362ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu final String contentType; 363d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu if (msg && (getProtocolVersion() < Eas.SUPPORTED_PROTOCOL_EX2010_DOUBLE)) { 364ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu contentType = MimeUtility.MIME_TYPE_RFC822; 365b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } else if (entity != null) { 366ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu contentType = EAS_14_MIME_TYPE; 367b19dfd15473dfedec2aa481d453b17a24486b05dAnthony Lee } else { 368ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu contentType = null; 369ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 370ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final String uriString; 371ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (extra == null) { 372ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu uriString = makeUriString(cmd); 373ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } else { 374ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu uriString = makeUriString(cmd, extra); 375ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 376ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final HttpPost method = makePost(uriString, entity, contentType, !isPingCommand); 377b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // NOTE 378b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // The next lines are added at the insistence of $VENDOR, who is seeing inappropriate 379b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // network activity related to the Ping command on some networks with some servers. 380b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // This code should be removed when the underlying issue is resolved 381b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu if (isPingCommand) { 382b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu method.setHeader("Connection", "close"); 383b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 384b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return executeHttpUriRequest(method, timeout); 385ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 386b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 387ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public EasResponse sendHttpClientPost(final String cmd, final byte[] bytes, 388d92a75c707461188e8743149476e8f49ef191b42Tony Mantler final long timeout) throws IOException, CertificateException { 389da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu final ByteArrayEntity entity; 390da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu if (bytes == null) { 391da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu entity = null; 392da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu } else { 393da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu entity = new ByteArrayEntity(bytes); 394da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu } 395da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu return sendHttpClientPost(cmd, entity, timeout); 396ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 397ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 398ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu protected EasResponse sendHttpClientPost(final String cmd, final byte[] bytes) 399d92a75c707461188e8743149476e8f49ef191b42Tony Mantler throws IOException, CertificateException { 400ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu return sendHttpClientPost(cmd, bytes, COMMAND_TIMEOUT); 401ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 402ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 403ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu /** 404b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * Executes an {@link HttpUriRequest}. 405ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * Note: this function must not be called by multiple threads concurrently. Only one thread may 406ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * send server requests from a particular object at a time. 407ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @param method The post to execute. 408ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @param timeout The timeout to use. 409ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @return The response from the Exchange server. 410ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @throws IOException 411ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu */ 412b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu public EasResponse executeHttpUriRequest(final HttpUriRequest method, final long timeout) 413d92a75c707461188e8743149476e8f49ef191b42Tony Mantler throws IOException, CertificateException { 414dc15b97b8975b994992d14d2cf3e6c8a80645b5dYu Ping Hu LogUtils.d(TAG, "EasServerConnection about to make request %s", method.getRequestLine()); 415ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu // The synchronized blocks are here to support the stop() function, specifically to handle 416ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu // when stop() is called first. Notably, they are NOT here in order to guard against 417ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu // concurrent access to this function, which is not supported. 418b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu synchronized (this) { 419b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu if (mStopped) { 420b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu mStopped = false; 421b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // If this gets stopped after the POST actually starts, it throws an IOException. 422b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // Therefore if we get stopped here, let's throw the same sort of exception, so 423ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // callers can equate IOException with "this POST got killed for some reason". 424ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu throw new IOException("Command was stopped before POST"); 425b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 426b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu mPendingRequest = method; 427b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 428ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu boolean postCompleted = false; 429b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu try { 430ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final EasResponse response = EasResponse.fromHttpRequest(getClientConnectionManager(), 431ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu getHttpClient(timeout), method); 432ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu postCompleted = true; 433ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return response; 434b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } finally { 435b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu synchronized (this) { 436b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu mPendingRequest = null; 437ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (postCompleted) { 438ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu mStoppedReason = STOPPED_REASON_NONE; 439ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 440b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 441b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 442b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 443b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 444d92a75c707461188e8743149476e8f49ef191b42Tony Mantler protected EasResponse executePost(final HttpPost method) 445d92a75c707461188e8743149476e8f49ef191b42Tony Mantler throws IOException, CertificateException { 446b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return executeHttpUriRequest(method, COMMAND_TIMEOUT); 447b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 448b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 449b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu /** 450ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * If called while this object is executing a POST, interrupt it with an {@link IOException}. 451ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * Otherwise cause the next attempt to execute a POST to be interrupted with an 452ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * {@link IOException}. 453ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * @param reason The reason for requesting a stop. This should be one of the STOPPED_REASON_* 454ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * constants defined in this class, other than {@link #STOPPED_REASON_NONE} which 455ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * is used to signify that no stop has occurred. 456ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * This class simply stores the value; subclasses are responsible for checking 457ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * this value when catching the {@link IOException} and responding appropriately. 458b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 459ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public synchronized void stop(final int reason) { 460ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // Only process legitimate reasons. 461ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (reason >= STOPPED_REASON_ABORT && reason <= STOPPED_REASON_RESTART) { 462b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu final boolean isMidPost = (mPendingRequest != null); 463ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu LogUtils.i(TAG, "%s with reason %d", (isMidPost ? "Interrupt" : "Stop next"), reason); 464ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu mStoppedReason = reason; 465ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (isMidPost) { 466b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu mPendingRequest.abort(); 467ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } else { 468ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu mStopped = true; 469ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 470b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 471ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu } 472ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu 473ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu /** 474ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * @return The reason supplied to the last call to {@link #stop}, or 475ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * {@link #STOPPED_REASON_NONE} if {@link #stop} hasn't been called since the last 476ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * successful POST. 477ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu */ 478ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public synchronized int getStoppedReason() { 479ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu return mStoppedReason; 480b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 481b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Hu 482b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Hu /** 483b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * Try to register our client certificate, if needed. 484b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * @return True if we succeeded or didn't need a client cert, false if we failed to register it. 485b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu */ 486b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu public boolean registerClientCert() { 487b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu if (mHostAuth.mClientCertAlias != null) { 488b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu try { 489b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu getClientConnectionManager().registerClientCert(mContext, mHostAuth); 490b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } catch (final CertificateException e) { 491b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu // The client certificate the user specified is invalid/inaccessible. 492b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return false; 493b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 494b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 495b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return true; 496b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 497b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu 498b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu /** 499b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * @return Whether {@link #setProtocolVersion} was last called with a non-null value. Note that 500b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * at construction time it is set to whatever protocol version is in the account. 501b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu */ 502b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu public boolean isProtocolVersionSet() { 503b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return mProtocolVersionIsSet; 504b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 505b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu} 506