ExchangeStore.java revision 22409fcffae4c6e551fb3e6ead4cdc92e33fded1
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 HostAuth mHostAuth; 99 100 private static final HashMap<Long, ExchangeTransport> sHostAuthToInstanceMap = 101 new HashMap<Long, ExchangeTransport>(); 102 103 /** 104 * Public factory. The transport should be a singleton 105 */ 106 public synchronized static ExchangeTransport getInstance(Account account, Context context) 107 throws MessagingException { 108 HostAuth hostAuth = HostAuth.restoreHostAuthWithId(context, account.mHostAuthKeyRecv); 109 if (hostAuth == null) { 110 hostAuth = new HostAuth(); 111 } 112 final long storeKey = hostAuth.mId; 113 ExchangeTransport transport = sHostAuthToInstanceMap.get(storeKey); 114 if (transport == null) { 115 transport = new ExchangeTransport(account, context); 116 // Only cache a saved HostAuth key 117 if (storeKey != EmailContent.NOT_SAVED) { 118 sHostAuthToInstanceMap.put(storeKey, transport); 119 } 120 } 121 return transport; 122 } 123 124 /** 125 * Private constructor - use public factory. 126 */ 127 private ExchangeTransport(Account account, Context context) throws MessagingException { 128 mContext = context.getApplicationContext(); 129 setAccount(account); 130 } 131 132 private void setAccount(final Account account) throws MessagingException { 133 HostAuth recvAuth = account.getOrCreateHostAuthRecv(mContext); 134 if (recvAuth == null || !STORE_SCHEME_EAS.equalsIgnoreCase(recvAuth.mProtocol)) { 135 throw new MessagingException("Unsupported protocol"); 136 } 137 if (recvAuth.mAddress == null) { 138 throw new MessagingException("host not specified"); 139 } 140 if (!TextUtils.isEmpty(recvAuth.mDomain)) { 141 recvAuth.mDomain = recvAuth.mDomain.substring(1); 142 } 143 recvAuth.mPort = 80; 144 if ((recvAuth.mFlags & HostAuth.FLAG_SSL) != 0) { 145 recvAuth.mPort = 443; 146 } 147 148 String[] userInfoParts = recvAuth.getLogin(); 149 if (userInfoParts != null) { 150 if (TextUtils.isEmpty(userInfoParts[0]) || TextUtils.isEmpty(userInfoParts[1])) { 151 throw new MessagingException("user name and password not specified"); 152 } 153 } else { 154 throw new MessagingException("user information not specifed"); 155 } 156 mHostAuth = recvAuth; 157 } 158 159 /** 160 * Here's where we check the settings for EAS. 161 * @throws MessagingException if we can't authenticate the account 162 */ 163 public Bundle checkSettings() throws MessagingException { 164 try { 165 IEmailService svc = ExchangeUtils.getExchangeService(mContext, null); 166 // Use a longer timeout for the validate command. Note that the instanceof check 167 // shouldn't be necessary; we'll do it anyway, just to be safe 168 if (svc instanceof EmailServiceProxy) { 169 ((EmailServiceProxy)svc).setTimeout(90); 170 } 171 return svc.validate(mHostAuth); 172 } catch (RemoteException e) { 173 throw new MessagingException("Call to validate generated an exception", e); 174 } 175 } 176 } 177 178 /** 179 * We handle AutoDiscover for Exchange 2007 (and later) here, wrapping the EmailService call. 180 * The service call returns a HostAuth and we return null if there was a service issue 181 */ 182 @Override 183 public Bundle autoDiscover(Context context, String username, String password) { 184 try { 185 return ExchangeUtils.getExchangeService(context, null).autoDiscover(username, password); 186 } catch (RemoteException e) { 187 return null; 188 } 189 } 190} 191