EasServerConnection.java revision 9c7165d4c6b90101b781f90b17451efd42a17929
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; 42c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Huimport com.android.mail.utils.LogUtils; 43b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 44b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.HttpEntity; 45b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.client.HttpClient; 46bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Huimport org.apache.http.client.methods.HttpOptions; 47b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.client.methods.HttpPost; 48b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Huimport org.apache.http.client.methods.HttpUriRequest; 49b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.entity.ByteArrayEntity; 50b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.impl.client.DefaultHttpClient; 51b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.params.BasicHttpParams; 52b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.params.HttpConnectionParams; 53b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport org.apache.http.params.HttpParams; 541d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albertimport org.apache.http.protocol.BasicHttpProcessor; 55b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 56b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport java.io.IOException; 57b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Huimport java.net.URI; 58b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Huimport java.security.cert.CertificateException; 59b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 60b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu/** 61b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * Base class for communicating with an EAS server. Anything that needs to send messages to the 62b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * server can subclass this to get access to the {@link #sendHttpClientPost} family of functions. 63c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu * TODO: This class has a regrettable name. It's not a connection, but rather a task that happens 64c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu * to have (and use) a connection to the server. 65b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 66ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hupublic class EasServerConnection { 67c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu /** Logging tag. */ 68110837ebff288a75f9bda067c38e2c46797d99b5Alon Albert private static final String TAG = Eas.LOG_TAG; 69c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu 70b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu /** 71b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * Timeout for establishing a connection to the server. 72b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 73b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu private static final long CONNECTION_TIMEOUT = 20 * DateUtils.SECOND_IN_MILLIS; 74b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 75b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu /** 76b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * Timeout for http requests after the connection has been established. 77b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 78b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu protected static final long COMMAND_TIMEOUT = 30 * DateUtils.SECOND_IN_MILLIS; 79b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 80b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu private static final String DEVICE_TYPE = "Android"; 81328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu private static final String USER_AGENT = DEVICE_TYPE + '/' + Build.VERSION.RELEASE + '-' + 82b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu Eas.CLIENT_VERSION; 83b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 84ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu /** Message MIME type for EAS version 14 and later. */ 85ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu private static final String EAS_14_MIME_TYPE = "application/vnd.ms-sync.wbxml"; 86b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 87ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu /** 88ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * Value for {@link #mStoppedReason} when we haven't been stopped. 89ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu */ 90ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu public static final int STOPPED_REASON_NONE = 0; 91ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu 92ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu /** 93ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * Passed to {@link #stop} to indicate that this stop request should terminate this task. 94ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu */ 95ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu public static final int STOPPED_REASON_ABORT = 1; 96ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu 97ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu /** 98ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * Passed to {@link #stop} to indicate that this stop request should restart this task (e.g. in 99ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * order to reload parameters). 100ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu */ 101ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu public static final int STOPPED_REASON_RESTART = 2; 102ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu 103328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu private static final String[] ACCOUNT_SECURITY_KEY_PROJECTION = 104328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu { EmailContent.AccountColumns.SECURITY_SYNC_KEY }; 105328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu 106f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu private static String sDeviceId = null; 107f928e7f3743c8fa0d00218408fbbbbb000821f34Yu Ping Hu 108b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu protected final Context mContext; 1090a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu // TODO: Make this private if possible. Subclasses must be careful about altering the HostAuth 1100a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu // to not screw up any connection caching (use redirectHostAuth). 11125b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu protected final HostAuth mHostAuth; 1120a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu protected final Account mAccount; 113328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu private final long mAccountId; 114b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 115b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu // Bookkeeping for interrupting a request. This is primarily for use by Ping (there's currently 116b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // no mechanism for stopping a sync). 117b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // Access to these variables should be synchronized on this. 118b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu private HttpUriRequest mPendingRequest = null; 119b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu private boolean mStopped = false; 120ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu private int mStoppedReason = STOPPED_REASON_NONE; 121b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 122b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu /** The protocol version to use, as a double. */ 123ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu private double mProtocolVersion = 0.0d; 124b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu /** Whether {@link #setProtocolVersion} was last called with a non-null value. */ 125b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu private boolean mProtocolVersionIsSet = false; 126d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu 127ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu /** 128ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * The client for any requests made by this object. This is created lazily, and cleared 129ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * whenever our host auth is redirected. 130ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu */ 131ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu private HttpClient mClient; 132ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 133ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu /** 134ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * The connection manager for any requests made by this object. This is created lazily, and 135ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * cleared whenever our host auth is redirected. 136ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu */ 137ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu private EmailClientConnectionManager mConnectionManager; 138ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 139ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public EasServerConnection(final Context context, final Account account, 1400a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu final HostAuth hostAuth) { 141b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu mContext = context; 14225b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu mHostAuth = hostAuth; 1430a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu mAccount = account; 144328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu mAccountId = account.mId; 145ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu setProtocolVersion(account.mProtocolVersion); 146b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 147b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 148ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public EasServerConnection(final Context context, final Account account) { 149c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu this(context, account, HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv)); 150c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu } 151c35d2fa94faa0f9abeded869a01108bac2bcedccYu Ping Hu 15225b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu protected EmailClientConnectionManager getClientConnectionManager() { 153ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu if (mConnectionManager == null) { 1549383babdbd7c0049a0eb238819a5d9737232e8ecYu Ping Hu mConnectionManager = 1559383babdbd7c0049a0eb238819a5d9737232e8ecYu Ping Hu EasConnectionCache.instance().getConnectionManager(mContext, mHostAuth); 156ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 157ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu return mConnectionManager; 15897f38cd6004b54afe9a949658d9962abe8f1f24eYu Ping Hu } 15997f38cd6004b54afe9a949658d9962abe8f1f24eYu Ping Hu 160ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public void redirectHostAuth(final String newAddress) { 161ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu mClient = null; 162ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu mConnectionManager = null; 16325b95fe9881e51399ea906af6758447d726fb8a5Yu Ping Hu mHostAuth.mAddress = newAddress; 164c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu if (mHostAuth.isSaved()) { 1659383babdbd7c0049a0eb238819a5d9737232e8ecYu Ping Hu EasConnectionCache.instance().uncacheConnectionManager(mHostAuth); 166c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu final ContentValues cv = new ContentValues(1); 167c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu cv.put(EmailContent.HostAuthColumns.ADDRESS, newAddress); 168c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu mHostAuth.update(mContext, cv); 169c516a47f1fd034a3819cd71beca92becf598de8eYu Ping Hu } 170b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 171b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 172ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu private HttpClient getHttpClient(final long timeout) { 173ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu if (mClient == null) { 174ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu final HttpParams params = new BasicHttpParams(); 175ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu HttpConnectionParams.setConnectionTimeout(params, (int)(CONNECTION_TIMEOUT)); 176ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu HttpConnectionParams.setSoTimeout(params, (int)(timeout)); 177ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu HttpConnectionParams.setSocketBufferSize(params, 8192); 1781d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert mClient = new DefaultHttpClient(getClientConnectionManager(), params) { 1799c7165d4c6b90101b781f90b17451efd42a17929Martin Hibdon @Override 1801d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert protected BasicHttpProcessor createHttpProcessor() { 1811d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert final BasicHttpProcessor processor = super.createHttpProcessor(); 1821d800e0ba4820bdff46b6ef2bd16576930033d49Alon Albert processor.addRequestInterceptor(new CurlLogger()); 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 */ 259ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu protected EasResponse sendHttpClientOptions() throws IOException { 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"); 288ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu if (contentType != null) { 289ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.setHeader("Content-Type", contentType); 290ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 291b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu if (usePolicyKey) { 292b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // If there's an account in existence, use its key; otherwise (we're creating the 293b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // account), send "0". The server will respond with code 449 if there are policies 294b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // to be enforced 2950a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu final String key; 296328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu final String accountKey; 297328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu if (mAccountId == Account.NO_ACCOUNT) { 298328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu accountKey = null; 299328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu } else { 300328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu accountKey = Utility.getFirstRowString(mContext, 301328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu ContentUris.withAppendedId(Account.CONTENT_URI, mAccountId), 302328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu ACCOUNT_SECURITY_KEY_PROJECTION, null, null, null, 0); 303328ca0d959f7e729e96f19538c8f3af8fe782a09Yu Ping Hu } 3040a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu if (!TextUtils.isEmpty(accountKey)) { 3050a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu key = accountKey; 3060a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu } else { 3070a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu key = "0"; 308b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 309ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.setHeader("X-MS-PolicyKey", key); 310b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 311ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu post.setEntity(entity); 312ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu return post; 313bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Hu } 314bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Hu 315bc278f1e81ef1d44c28093e830ebe84faa960843Yu Ping Hu /** 316b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * Make an {@link HttpOptions} request for this connection. 317b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * @return The {@link HttpOptions} object. 318b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu */ 319b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu public HttpOptions makeOptions() { 320b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu final HttpOptions method = new HttpOptions(URI.create(makeBaseUriString())); 321b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu method.setHeader("Authorization", makeAuthString()); 322b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu method.setHeader("User-Agent", getUserAgent()); 323b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return method; 324b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 325b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu 326b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu /** 327b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * Send a POST request to the server. 328b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @param cmd The command we're sending to the server. 329b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @param entity The {@link HttpEntity} containing the payload of the message. 330b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @param timeout The timeout for this POST. 331b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @return The response from the Exchange server. 332b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu * @throws IOException 333b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 3340a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu protected EasResponse sendHttpClientPost(String cmd, final HttpEntity entity, 3350a62e7f88662942c434f629af6495d64dfae7902Yu Ping Hu final long timeout) throws IOException { 336b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu final boolean isPingCommand = cmd.equals("Ping"); 337b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 338b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // Split the mail sending commands 339b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu String extra = null; 340b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu boolean msg = false; 341b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu if (cmd.startsWith("SmartForward&") || cmd.startsWith("SmartReply&")) { 342b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu final int cmdLength = cmd.indexOf('&'); 343b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu extra = cmd.substring(cmdLength); 344b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu cmd = cmd.substring(0, cmdLength); 345b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu msg = true; 346b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } else if (cmd.startsWith("SendMail&")) { 347b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu msg = true; 348b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 349b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 350b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // Send the proper Content-Type header; it's always wbxml except for messages when 351b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // the EAS protocol version is < 14.0 352b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // If entity is null (e.g. for attachments), don't set this header 353ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu final String contentType; 354d738c447d8597062f2f20ecb94b96e8bee12a531Yu Ping Hu if (msg && (getProtocolVersion() < Eas.SUPPORTED_PROTOCOL_EX2010_DOUBLE)) { 355ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu contentType = MimeUtility.MIME_TYPE_RFC822; 356b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } else if (entity != null) { 357ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu contentType = EAS_14_MIME_TYPE; 358b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 359ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu else { 360ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu contentType = null; 361ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 362ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final String uriString; 363ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (extra == null) { 364ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu uriString = makeUriString(cmd); 365ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } else { 366ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu uriString = makeUriString(cmd, extra); 367ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 368ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final HttpPost method = makePost(uriString, entity, contentType, !isPingCommand); 369b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // NOTE 370b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // The next lines are added at the insistence of $VENDOR, who is seeing inappropriate 371b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // network activity related to the Ping command on some networks with some servers. 372b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // This code should be removed when the underlying issue is resolved 373b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu if (isPingCommand) { 374b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu method.setHeader("Connection", "close"); 375b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 376b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return executeHttpUriRequest(method, timeout); 377ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 378b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 379ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public EasResponse sendHttpClientPost(final String cmd, final byte[] bytes, 380ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu final long timeout) throws IOException { 381da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu final ByteArrayEntity entity; 382da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu if (bytes == null) { 383da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu entity = null; 384da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu } else { 385da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu entity = new ByteArrayEntity(bytes); 386da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu } 387da835b7580108777bb0fa4a4d7287676a1cd7e53Yu Ping Hu return sendHttpClientPost(cmd, entity, timeout); 388ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 389ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 390ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu protected EasResponse sendHttpClientPost(final String cmd, final byte[] bytes) 391ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu throws IOException { 392ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu return sendHttpClientPost(cmd, bytes, COMMAND_TIMEOUT); 393ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu } 394ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu 395ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu /** 396b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * Executes an {@link HttpUriRequest}. 397ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * Note: this function must not be called by multiple threads concurrently. Only one thread may 398ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * send server requests from a particular object at a time. 399ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @param method The post to execute. 400ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @param timeout The timeout to use. 401ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @return The response from the Exchange server. 402ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * @throws IOException 403ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu */ 404b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu public EasResponse executeHttpUriRequest(final HttpUriRequest method, final long timeout) 405ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu throws IOException { 406ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu // The synchronized blocks are here to support the stop() function, specifically to handle 407ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu // when stop() is called first. Notably, they are NOT here in order to guard against 408ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu // concurrent access to this function, which is not supported. 409b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu synchronized (this) { 410b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu if (mStopped) { 411b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu mStopped = false; 412b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // If this gets stopped after the POST actually starts, it throws an IOException. 413b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu // Therefore if we get stopped here, let's throw the same sort of exception, so 414ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // callers can equate IOException with "this POST got killed for some reason". 415ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu throw new IOException("Command was stopped before POST"); 416b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 417b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu mPendingRequest = method; 418b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 419ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu boolean postCompleted = false; 420b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu try { 421ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu final EasResponse response = EasResponse.fromHttpRequest(getClientConnectionManager(), 422ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu getHttpClient(timeout), method); 423ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu postCompleted = true; 424ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu return response; 425b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } finally { 426b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu synchronized (this) { 427b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu mPendingRequest = null; 428ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (postCompleted) { 429ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu mStoppedReason = STOPPED_REASON_NONE; 430ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 431b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 432b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 433b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 434b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 435ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu protected EasResponse executePost(final HttpPost method) throws IOException { 436b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return executeHttpUriRequest(method, COMMAND_TIMEOUT); 437b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 438b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu 439b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu /** 440ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * If called while this object is executing a POST, interrupt it with an {@link IOException}. 441ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * Otherwise cause the next attempt to execute a POST to be interrupted with an 442ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * {@link IOException}. 443ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * @param reason The reason for requesting a stop. This should be one of the STOPPED_REASON_* 444ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * constants defined in this class, other than {@link #STOPPED_REASON_NONE} which 445ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * is used to signify that no stop has occurred. 446ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * This class simply stores the value; subclasses are responsible for checking 447ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * this value when catching the {@link IOException} and responding appropriately. 448b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu */ 449ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public synchronized void stop(final int reason) { 450ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu // Only process legitimate reasons. 451ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (reason >= STOPPED_REASON_ABORT && reason <= STOPPED_REASON_RESTART) { 452b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu final boolean isMidPost = (mPendingRequest != null); 453ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu LogUtils.i(TAG, "%s with reason %d", (isMidPost ? "Interrupt" : "Stop next"), reason); 454ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu mStoppedReason = reason; 455ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu if (isMidPost) { 456b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu mPendingRequest.abort(); 457ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } else { 458ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu mStopped = true; 459ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu } 460b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 461ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu } 462ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu 463ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu /** 464ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu * @return The reason supplied to the last call to {@link #stop}, or 465ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * {@link #STOPPED_REASON_NONE} if {@link #stop} hasn't been called since the last 466ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * successful POST. 467ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu */ 468ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu public synchronized int getStoppedReason() { 469ae6c69d73448bd4184724dfa351d17ca0cf378b2Yu Ping Hu return mStoppedReason; 470b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu } 471b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Hu 472b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Hu /** 473b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * Try to register our client certificate, if needed. 474b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * @return True if we succeeded or didn't need a client cert, false if we failed to register it. 475b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu */ 476b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu public boolean registerClientCert() { 477b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu if (mHostAuth.mClientCertAlias != null) { 478b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu try { 479b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu getClientConnectionManager().registerClientCert(mContext, mHostAuth); 480b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } catch (final CertificateException e) { 481b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu // The client certificate the user specified is invalid/inaccessible. 482b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return false; 483b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 484b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 485b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return true; 486b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 487b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu 488b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu /** 489b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * @return Whether {@link #setProtocolVersion} was last called with a non-null value. Note that 490b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu * at construction time it is set to whatever protocol version is in the account. 491b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu */ 492b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu public boolean isProtocolVersionSet() { 493b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu return mProtocolVersionIsSet; 494b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu } 495b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu 496b6ef78e8c4112d47d965b5b274d52fe8885f58faYu Ping Hu /** 497b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Hu * Convenience method for adding a Message to an account's outbox 498ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * @param account The {@link Account} from which to send the message. 499ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu * @param msg The message to send 500b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Hu */ 501ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu protected void sendMessage(final Account account, final EmailContent.Message msg) { 502ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu long mailboxId = Mailbox.findMailboxOfType(mContext, account.mId, Mailbox.TYPE_OUTBOX); 50333620ab2d10ba408d69a2daa177ad949d4b46f62Yu Ping Hu // TODO: Improve system mailbox handling. 50433620ab2d10ba408d69a2daa177ad949d4b46f62Yu Ping Hu if (mailboxId == Mailbox.NO_MAILBOX) { 505ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu LogUtils.d(TAG, "No outbox for account %d, creating it", account.mId); 50633620ab2d10ba408d69a2daa177ad949d4b46f62Yu Ping Hu final Mailbox outbox = 507ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu Mailbox.newSystemMailbox(mContext, account.mId, Mailbox.TYPE_OUTBOX); 50833620ab2d10ba408d69a2daa177ad949d4b46f62Yu Ping Hu outbox.save(mContext); 50933620ab2d10ba408d69a2daa177ad949d4b46f62Yu Ping Hu mailboxId = outbox.mId; 510b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Hu } 51133620ab2d10ba408d69a2daa177ad949d4b46f62Yu Ping Hu msg.mMailboxKey = mailboxId; 512ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu msg.mAccountKey = account.mId; 51333620ab2d10ba408d69a2daa177ad949d4b46f62Yu Ping Hu msg.save(mContext); 514ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu requestSyncForMailbox(new android.accounts.Account(account.mEmailAddress, 51533620ab2d10ba408d69a2daa177ad949d4b46f62Yu Ping Hu Eas.EXCHANGE_ACCOUNT_MANAGER_TYPE), EmailContent.AUTHORITY, mailboxId); 516b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Hu } 517b31070f7484eeeb15c4bce89dbc61388d05d0bfcYu Ping Hu 51862c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu /** 51962c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu * Issue a {@link android.content.ContentResolver#requestSync} for a specific mailbox. 52062c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu * @param amAccount The {@link android.accounts.Account} for the account we're pinging. 52162c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu * @param authority The authority for the mailbox that needs to sync. 52262c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu * @param mailboxId The id of the mailbox that needs to sync. 52362c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu */ 52462c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu protected static void requestSyncForMailbox(final android.accounts.Account amAccount, 52562c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu final String authority, final long mailboxId) { 52662c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu final Bundle extras = new Bundle(1); 52762c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu extras.putLong(Mailbox.SYNC_EXTRA_MAILBOX_ID, mailboxId); 52862c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu ContentResolver.requestSync(amAccount, authority, extras); 5299c7165d4c6b90101b781f90b17451efd42a17929Martin Hibdon LogUtils.i(TAG, "requestSync EasServerConnection requestSyncForMailbox %s, %s", 5309c7165d4c6b90101b781f90b17451efd42a17929Martin Hibdon amAccount.toString(), extras.toString()); 53162c287af3bed45818accf595c56879ad5c57aaf9Yu Ping Hu } 532b6503ab0ba4f4e323fb09e6522cd7c898ea3431eYu Ping Hu} 533