ExchangeStore.java revision 12b82d9374947c9268217f45befe8a74bd9b60d7
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.EmailContent.Account; 24import com.android.emailcommon.provider.HostAuth; 25import com.android.emailcommon.service.EmailServiceProxy; 26import com.android.emailcommon.service.IEmailService; 27 28import android.content.Context; 29import android.os.Bundle; 30import android.os.RemoteException; 31import android.text.TextUtils; 32 33import java.util.HashMap; 34 35/** 36 * Our Exchange service does not use the sender/store model. This class exists for exactly two 37 * purposes, (1) to provide a hook for checking account connections, and (2) to return 38 * "AccountSetupExchange.class" for getSettingActivityClass(). 39 */ 40public class ExchangeStore extends Store { 41 public static final String LOG_TAG = "ExchangeStore"; 42 @SuppressWarnings("hiding") 43 private final ExchangeTransport mTransport; 44 45 /** 46 * Static named constructor. 47 */ 48 public static Store newInstance(Account account, Context context, 49 PersistentDataCallbacks callbacks) throws MessagingException { 50 return new ExchangeStore(account, context, callbacks); 51 } 52 53 /** 54 * Creates a new store for the given account. 55 */ 56 private ExchangeStore(Account account, Context context, PersistentDataCallbacks callbacks) 57 throws MessagingException { 58 mTransport = ExchangeTransport.getInstance(account, context); 59 } 60 61 @Override 62 public Bundle checkSettings() throws MessagingException { 63 return mTransport.checkSettings(); 64 } 65 66 @Override 67 public Folder getFolder(String name) { 68 return null; 69 } 70 71 @Override 72 public Folder[] updateFolders() { 73 return null; 74 } 75 76 /** 77 * Get class of SettingActivity for this Store class. 78 * @return Activity class that has class method actionEditIncomingSettings() 79 */ 80 @Override 81 public Class<? extends android.app.Activity> getSettingActivityClass() { 82 return com.android.email.activity.setup.AccountSetupExchange.class; 83 } 84 85 /** 86 * Inform MessagingController that messages sent via EAS will be placed in the Sent folder 87 * automatically (server-side) and don't need to be uploaded. 88 * @return always false for EAS (assuming server-side copy is supported) 89 */ 90 @Override 91 public boolean requireCopyMessageToSentFolder() { 92 return false; 93 } 94 95 public static class ExchangeTransport { 96 private final Context mContext; 97 private String mHost; 98 private String mDomain; 99 private int mPort; 100 private boolean mSsl; 101 private boolean mTSsl; 102 private String mUsername; 103 private String mPassword; 104 105 private static final HashMap<String, ExchangeTransport> sUriToInstanceMap = 106 new HashMap<String, ExchangeTransport>(); 107 108 /** 109 * Public factory. The transport should be a singleton (per Uri) 110 */ 111 public synchronized static ExchangeTransport getInstance(Account account, Context context) 112 throws MessagingException { 113 final String storeKey = getStoreKey(context, account); 114 ExchangeTransport transport = sUriToInstanceMap.get(storeKey); 115 if (transport == null) { 116 transport = new ExchangeTransport(account, context); 117 sUriToInstanceMap.put(storeKey, transport); 118 } 119 return transport; 120 } 121 122 /** 123 * Private constructor - use public factory. 124 */ 125 private ExchangeTransport(Account account, Context context) throws MessagingException { 126 mContext = context.getApplicationContext(); 127 setAccount(account); 128 } 129 130 private void setAccount(final Account account) throws MessagingException { 131 HostAuth recvAuth = account.getOrCreateHostAuthRecv(mContext); 132 if (recvAuth == null || !STORE_SCHEME_EAS.equalsIgnoreCase(recvAuth.mProtocol)) { 133 throw new MessagingException("Unsupported protocol"); 134 } 135 mHost = recvAuth.mAddress; 136 if (mHost == null) { 137 throw new MessagingException("host not specified"); 138 } 139 mDomain = recvAuth.mDomain; 140 if (!TextUtils.isEmpty(mDomain)) { 141 mDomain = mDomain.substring(1); 142 } 143 mPort = 80; 144 if ((recvAuth.mFlags & HostAuth.FLAG_SSL) != 0) { 145 mPort = 443; 146 mSsl = true; 147 } 148 mTSsl = ((recvAuth.mFlags & HostAuth.FLAG_TRUST_ALL) != 0); 149 150 String[] userInfoParts = recvAuth.getLogin(); 151 if (userInfoParts != null) { 152 mUsername = userInfoParts[0]; 153 mPassword = userInfoParts[1]; 154 if (TextUtils.isEmpty(mPassword)) { 155 throw new MessagingException("user name and password not specified"); 156 } 157 } else { 158 throw new MessagingException("user information not specifed"); 159 } 160 } 161 162 /** 163 * Here's where we check the settings for EAS. 164 * @throws MessagingException if we can't authenticate the account 165 */ 166 public Bundle checkSettings() throws MessagingException { 167 try { 168 IEmailService svc = ExchangeUtils.getExchangeService(mContext, null); 169 // Use a longer timeout for the validate command. Note that the instanceof check 170 // shouldn't be necessary; we'll do it anyway, just to be safe 171 if (svc instanceof EmailServiceProxy) { 172 ((EmailServiceProxy)svc).setTimeout(90); 173 } 174 return svc.validate("eas", mHost, mUsername, mPassword, mPort, mSsl, mTSsl); 175 } catch (RemoteException e) { 176 throw new MessagingException("Call to validate generated an exception", e); 177 } 178 } 179 } 180 181 /** 182 * We handle AutoDiscover for Exchange 2007 (and later) here, wrapping the EmailService call. 183 * The service call returns a HostAuth and we return null if there was a service issue 184 */ 185 @Override 186 public Bundle autoDiscover(Context context, String username, String password) { 187 try { 188 return ExchangeUtils.getExchangeService(context, null).autoDiscover(username, password); 189 } catch (RemoteException e) { 190 return null; 191 } 192 } 193} 194