ExchangeStore.java revision f5418f1f93b02e7fab9f15eb201800b65510998e
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.email.mail.store; 18 19import com.android.email.ExchangeUtils; 20import com.android.email.mail.Store; 21import com.android.emailcommon.mail.Folder; 22import com.android.emailcommon.mail.MessagingException; 23import com.android.emailcommon.provider.Account; 24import com.android.emailcommon.provider.EmailContent; 25import com.android.emailcommon.provider.HostAuth; 26import com.android.emailcommon.service.EmailServiceProxy; 27import com.android.emailcommon.service.IEmailService; 28 29import android.content.Context; 30import android.os.Bundle; 31import android.os.RemoteException; 32import android.text.TextUtils; 33 34import java.util.HashMap; 35 36/** 37 * Our Exchange service does not use the sender/store model. This class exists for exactly two 38 * purposes, (1) to provide a hook for checking account connections, and (2) to return 39 * "AccountSetupExchange.class" for getSettingActivityClass(). 40 */ 41public class ExchangeStore extends Store { 42 public static final String LOG_TAG = "ExchangeStore"; 43 @SuppressWarnings("hiding") 44 private final ExchangeTransport mTransport; 45 46 /** 47 * Static named constructor. 48 */ 49 public static Store newInstance(Account account, Context context, 50 PersistentDataCallbacks callbacks) throws MessagingException { 51 return new ExchangeStore(account, context, callbacks); 52 } 53 54 /** 55 * Creates a new store for the given account. 56 */ 57 private ExchangeStore(Account account, Context context, PersistentDataCallbacks callbacks) 58 throws MessagingException { 59 mTransport = ExchangeTransport.getInstance(account, context); 60 } 61 62 @Override 63 public Bundle checkSettings() throws MessagingException { 64 return mTransport.checkSettings(); 65 } 66 67 @Override 68 public Folder getFolder(String name) { 69 return null; 70 } 71 72 @Override 73 public Folder[] updateFolders() { 74 return null; 75 } 76 77 /** 78 * Get class of SettingActivity for this Store class. 79 * @return Activity class that has class method actionEditIncomingSettings() 80 */ 81 @Override 82 public Class<? extends android.app.Activity> getSettingActivityClass() { 83 return com.android.email.activity.setup.AccountSetupExchange.class; 84 } 85 86 /** 87 * Inform MessagingController that messages sent via EAS will be placed in the Sent folder 88 * automatically (server-side) and don't need to be uploaded. 89 * @return always false for EAS (assuming server-side copy is supported) 90 */ 91 @Override 92 public boolean requireCopyMessageToSentFolder() { 93 return false; 94 } 95 96 public static class ExchangeTransport { 97 private final Context mContext; 98 private String mHost; 99 private String mDomain; 100 private int mPort; 101 private boolean mSsl; 102 private boolean mTSsl; 103 private String mUsername; 104 private String mPassword; 105 106 private static final HashMap<Long, ExchangeTransport> sHostAuthToInstanceMap = 107 new HashMap<Long, ExchangeTransport>(); 108 109 /** 110 * Public factory. The transport should be a singleton 111 */ 112 public synchronized static ExchangeTransport getInstance(Account account, Context context) 113 throws MessagingException { 114 HostAuth hostAuth = HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv); 115 if (hostAuth == null) { 116 hostAuth = new HostAuth(); 117 } 118 final long storeKey = hostAuth.mId; 119 ExchangeTransport transport = sHostAuthToInstanceMap.get(storeKey); 120 if (transport == null) { 121 transport = new ExchangeTransport(account, context); 122 // Only cache a saved HostAuth key 123 if (storeKey != EmailContent.NOT_SAVED) { 124 sHostAuthToInstanceMap.put(storeKey, transport); 125 } 126 } 127 return transport; 128 } 129 130 /** 131 * Private constructor - use public factory. 132 */ 133 private ExchangeTransport(Account account, Context context) throws MessagingException { 134 mContext = context.getApplicationContext(); 135 setAccount(account); 136 } 137 138 private void setAccount(final Account account) throws MessagingException { 139 HostAuth recvAuth = account.getOrCreateHostAuthRecv(mContext); 140 if (recvAuth == null || !STORE_SCHEME_EAS.equalsIgnoreCase(recvAuth.mProtocol)) { 141 throw new MessagingException("Unsupported protocol"); 142 } 143 mHost = recvAuth.mAddress; 144 if (mHost == null) { 145 throw new MessagingException("host not specified"); 146 } 147 mDomain = recvAuth.mDomain; 148 if (!TextUtils.isEmpty(mDomain)) { 149 mDomain = mDomain.substring(1); 150 } 151 mPort = 80; 152 if ((recvAuth.mFlags & HostAuth.FLAG_SSL) != 0) { 153 mPort = 443; 154 mSsl = true; 155 } 156 mTSsl = ((recvAuth.mFlags & HostAuth.FLAG_TRUST_ALL) != 0); 157 158 String[] userInfoParts = recvAuth.getLogin(); 159 if (userInfoParts != null) { 160 mUsername = userInfoParts[0]; 161 mPassword = userInfoParts[1]; 162 if (TextUtils.isEmpty(mPassword)) { 163 throw new MessagingException("user name and password not specified"); 164 } 165 } else { 166 throw new MessagingException("user information not specifed"); 167 } 168 } 169 170 /** 171 * Here's where we check the settings for EAS. 172 * @throws MessagingException if we can't authenticate the account 173 */ 174 public Bundle checkSettings() throws MessagingException { 175 try { 176 IEmailService svc = ExchangeUtils.getExchangeService(mContext, null); 177 // Use a longer timeout for the validate command. Note that the instanceof check 178 // shouldn't be necessary; we'll do it anyway, just to be safe 179 if (svc instanceof EmailServiceProxy) { 180 ((EmailServiceProxy)svc).setTimeout(90); 181 } 182 return svc.validate("eas", mHost, mUsername, mPassword, mPort, mSsl, mTSsl); 183 } catch (RemoteException e) { 184 throw new MessagingException("Call to validate generated an exception", e); 185 } 186 } 187 } 188 189 /** 190 * We handle AutoDiscover for Exchange 2007 (and later) here, wrapping the EmailService call. 191 * The service call returns a HostAuth and we return null if there was a service issue 192 */ 193 @Override 194 public Bundle autoDiscover(Context context, String username, String password) { 195 try { 196 return ExchangeUtils.getExchangeService(context, null).autoDiscover(username, password); 197 } catch (RemoteException e) { 198 return null; 199 } 200 } 201} 202