package com.fsck.k9; import android.content.Context; import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.Uri; import android.util.Log; import com.fsck.k9.crypto.Apg; import com.fsck.k9.crypto.CryptoProvider; import com.fsck.k9.helper.Utility; import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Folder; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.Store; import com.fsck.k9.mail.store.LocalStore; import com.fsck.k9.mail.store.StorageManager; import com.fsck.k9.mail.store.LocalStore.LocalFolder; import com.fsck.k9.mail.store.StorageManager.StorageProvider; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Random; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** * Account stores all of the settings for a single account defined by the user. It is able to save * and delete itself given a Preferences to work with. Each account is defined by a UUID. */ public class Account implements BaseAccount { /** * @see Account#setLocalStoreMigrationListener(LocalStoreMigrationListener) * */ public interface LocalStoreMigrationListener { void onLocalStoreMigration(String oldStoreUri, String newStoreUri) throws MessagingException; } public static final String EXPUNGE_IMMEDIATELY = "EXPUNGE_IMMEDIATELY"; public static final String EXPUNGE_MANUALLY = "EXPUNGE_MANUALLY"; public static final String EXPUNGE_ON_POLL = "EXPUNGE_ON_POLL"; public static final int DELETE_POLICY_NEVER = 0; public static final int DELETE_POLICY_7DAYS = 1; public static final int DELETE_POLICY_ON_DELETE = 2; public static final int DELETE_POLICY_MARK_AS_READ = 3; public static final String TYPE_WIFI = "WIFI"; public static final String TYPE_MOBILE = "MOBILE"; public static final String TYPE_OTHER = "OTHER"; private static final String[] networkTypes = { TYPE_WIFI, TYPE_MOBILE, TYPE_OTHER }; private static final String DEFAULT_QUOTE_PREFIX = ">"; private static final boolean DEFAULT_REPLY_AFTER_QUOTE = false; /** *
* 0 - Never (DELETE_POLICY_NEVER) * 1 - After 7 days (DELETE_POLICY_7DAYS) * 2 - When I delete from inbox (DELETE_POLICY_ON_DELETE) * 3 - Mark as read (DELETE_POLICY_MARK_AS_READ) **/ private int mDeletePolicy; private final String mUuid; private String mStoreUri; /** * Storage provider ID, used to locate and manage the underlying DB/file * storage */ private String mLocalStorageProviderId; /** * True if {@link #mLocalStoreUri} may be in use at * the moment. */ private final boolean mIsInUse = false; private LocalStoreMigrationListener mLocalStoreMigrationListener; private String mTransportUri; private String mDescription; private String mAlwaysBcc; private int mAutomaticCheckIntervalMinutes; private int mDisplayCount; private int mChipColor; private long mLastAutomaticCheckTime; private boolean mNotifyNewMail; private boolean mNotifySelfNewMail; private String mDraftsFolderName; private String mSentFolderName; private String mTrashFolderName; private String mArchiveFolderName; private String mSpamFolderName; private String mOutboxFolderName; private String mAutoExpandFolderName; private FolderMode mFolderDisplayMode; private FolderMode mFolderSyncMode; private FolderMode mFolderPushMode; private FolderMode mFolderTargetMode; private int mAccountNumber; private boolean mSaveAllHeaders; private boolean mPushPollOnConnect; private boolean mNotifySync; private HideButtons mHideMessageViewButtons; private HideButtons mHideMessageViewMoveButtons; private ShowPictures mShowPictures; private boolean mEnableMoveButtons; private boolean mIsSignatureBeforeQuotedText; private String mExpungePolicy = EXPUNGE_IMMEDIATELY; private int mMaxPushFolders; private int mIdleRefreshMinutes; private boolean goToUnreadMessageSearch; private final Map
null
if not available
* @throws MessagingException
* @see {@link #isAvailable(Context)}
*/
public AccountStats getStats(Context context) throws MessagingException
{
if (!isAvailable(context))
{
return null;
}
long startTime = System.currentTimeMillis();
AccountStats stats = new AccountStats();
int unreadMessageCount = 0;
int flaggedMessageCount = 0;
LocalStore localStore = getLocalStore();
if (K9.measureAccounts())
{
stats.size = localStore.getSize();
}
Account.FolderMode aMode = getFolderDisplayMode();
Preferences prefs = Preferences.getPreferences(context);
long folderLoadStart = System.currentTimeMillis();
List extends Folder> folders = localStore.getPersonalNamespaces(false);
long folderLoadEnd = System.currentTimeMillis();
for (Folder folder : folders)
{
LocalFolder localFolder = (LocalFolder)folder;
//folder.refresh(prefs);
Folder.FolderClass fMode = localFolder.getDisplayClass(prefs);
// Always get stats about the INBOX (see issue 1817)
if (folder.getName().equals(K9.INBOX) || (
!folder.getName().equals(getTrashFolderName()) &&
!folder.getName().equals(getDraftsFolderName()) &&
!folder.getName().equals(getArchiveFolderName()) &&
!folder.getName().equals(getSpamFolderName()) &&
!folder.getName().equals(getOutboxFolderName()) &&
!folder.getName().equals(getSentFolderName()) &&
!folder.getName().equals(getErrorFolderName())))
{
if (aMode == Account.FolderMode.NONE)
{
continue;
}
if (aMode == Account.FolderMode.FIRST_CLASS &&
fMode != Folder.FolderClass.FIRST_CLASS)
{
continue;
}
if (aMode == Account.FolderMode.FIRST_AND_SECOND_CLASS &&
fMode != Folder.FolderClass.FIRST_CLASS &&
fMode != Folder.FolderClass.SECOND_CLASS)
{
continue;
}
if (aMode == Account.FolderMode.NOT_SECOND_CLASS &&
fMode == Folder.FolderClass.SECOND_CLASS)
{
continue;
}
unreadMessageCount += folder.getUnreadMessageCount();
flaggedMessageCount += folder.getFlaggedMessageCount();
}
}
long folderEvalEnd = System.currentTimeMillis();
stats.unreadMessageCount = unreadMessageCount;
stats.flaggedMessageCount = flaggedMessageCount;
long endTime = System.currentTimeMillis();
if (K9.DEBUG)
Log.d(K9.LOG_TAG, "Account.getStats() on " + getDescription() + " took " + (endTime - startTime) + " ms;"
+ " loading " + folders.size() + " took " + (folderLoadEnd - folderLoadStart) + " ms;"
+ " evaluating took " + (folderEvalEnd - folderLoadEnd) + " ms");
return stats;
}
public synchronized void setChipColor(int color)
{
mChipColor = color;
}
public synchronized int getChipColor()
{
return mChipColor;
}
public String getUuid()
{
return mUuid;
}
public Uri getContentUri()
{
return Uri.parse("content://accounts/" + getUuid());
}
public synchronized String getStoreUri()
{
return mStoreUri;
}
public synchronized void setStoreUri(String storeUri)
{
this.mStoreUri = storeUri;
}
public synchronized String getTransportUri()
{
return mTransportUri;
}
public synchronized void setTransportUri(String transportUri)
{
this.mTransportUri = transportUri;
}
public synchronized String getDescription()
{
return mDescription;
}
public synchronized void setDescription(String description)
{
this.mDescription = description;
}
public synchronized String getName()
{
return identities.get(0).getName();
}
public synchronized void setName(String name)
{
identities.get(0).setName(name);
}
public synchronized boolean getSignatureUse()
{
return identities.get(0).getSignatureUse();
}
public synchronized void setSignatureUse(boolean signatureUse)
{
identities.get(0).setSignatureUse(signatureUse);
}
public synchronized String getSignature()
{
return identities.get(0).getSignature();
}
public synchronized void setSignature(String signature)
{
identities.get(0).setSignature(signature);
}
public synchronized String getEmail()
{
return identities.get(0).getEmail();
}
public synchronized void setEmail(String email)
{
identities.get(0).setEmail(email);
}
public synchronized String getAlwaysBcc()
{
return mAlwaysBcc;
}
public synchronized void setAlwaysBcc(String alwaysBcc)
{
this.mAlwaysBcc = alwaysBcc;
}
/* Have we sent a new mail notification on this account */
public boolean isRingNotified()
{
return mRingNotified;
}
public void setRingNotified(boolean ringNotified)
{
mRingNotified = ringNotified;
}
public String getLocalStorageProviderId()
{
return mLocalStorageProviderId;
}
public void setLocalStorageProviderId(String id)
{
if (!mLocalStorageProviderId.equals(id))
{
boolean successful = false;
try
{
switchLocalStorage(id);
successful = true;
}
catch (MessagingException e)
{
}
finally
{
// if migration to/from SD-card failed once, it will fail again.
if (!successful)
{
return;
}
}
mLocalStorageProviderId = id;
}
}
// public synchronized void setLocalStoreUri(String localStoreUri)
// {
// this.mLocalStoreUri = localStoreUri;
// }
/**
* Returns -1 for never.
*/
public synchronized int getAutomaticCheckIntervalMinutes()
{
return mAutomaticCheckIntervalMinutes;
}
/**
* @param automaticCheckIntervalMinutes or -1 for never.
*/
public synchronized boolean setAutomaticCheckIntervalMinutes(int automaticCheckIntervalMinutes)
{
int oldInterval = this.mAutomaticCheckIntervalMinutes;
this.mAutomaticCheckIntervalMinutes = automaticCheckIntervalMinutes;
return (oldInterval != automaticCheckIntervalMinutes);
}
public synchronized int getDisplayCount()
{
return mDisplayCount;
}
public synchronized void setDisplayCount(int displayCount)
{
if (displayCount != -1)
{
this.mDisplayCount = displayCount;
}
else
{
this.mDisplayCount = K9.DEFAULT_VISIBLE_LIMIT;
}
resetVisibleLimits();
}
public synchronized long getLastAutomaticCheckTime()
{
return mLastAutomaticCheckTime;
}
public synchronized void setLastAutomaticCheckTime(long lastAutomaticCheckTime)
{
this.mLastAutomaticCheckTime = lastAutomaticCheckTime;
}
public synchronized boolean isNotifyNewMail()
{
return mNotifyNewMail;
}
public synchronized void setNotifyNewMail(boolean notifyNewMail)
{
this.mNotifyNewMail = notifyNewMail;
}
public synchronized int getDeletePolicy()
{
return mDeletePolicy;
}
public synchronized void setDeletePolicy(int deletePolicy)
{
this.mDeletePolicy = deletePolicy;
}
public synchronized String getDraftsFolderName()
{
return mDraftsFolderName;
}
public synchronized void setDraftsFolderName(String draftsFolderName)
{
mDraftsFolderName = draftsFolderName;
}
public synchronized String getSentFolderName()
{
return mSentFolderName;
}
public synchronized String getErrorFolderName()
{
return K9.ERROR_FOLDER_NAME;
}
public synchronized void setSentFolderName(String sentFolderName)
{
mSentFolderName = sentFolderName;
}
public synchronized String getTrashFolderName()
{
return mTrashFolderName;
}
public synchronized void setTrashFolderName(String trashFolderName)
{
mTrashFolderName = trashFolderName;
}
public synchronized String getArchiveFolderName()
{
return mArchiveFolderName;
}
public synchronized void setArchiveFolderName(String archiveFolderName)
{
mArchiveFolderName = archiveFolderName;
}
public synchronized String getSpamFolderName()
{
return mSpamFolderName;
}
public synchronized void setSpamFolderName(String spamFolderName)
{
mSpamFolderName = spamFolderName;
}
public synchronized String getOutboxFolderName()
{
return mOutboxFolderName;
}
public synchronized void setOutboxFolderName(String outboxFolderName)
{
mOutboxFolderName = outboxFolderName;
}
public synchronized String getAutoExpandFolderName()
{
return mAutoExpandFolderName;
}
public synchronized void setAutoExpandFolderName(String autoExpandFolderName)
{
mAutoExpandFolderName = autoExpandFolderName;
}
public synchronized int getAccountNumber()
{
return mAccountNumber;
}
public synchronized FolderMode getFolderDisplayMode()
{
return mFolderDisplayMode;
}
public synchronized boolean setFolderDisplayMode(FolderMode displayMode)
{
FolderMode oldDisplayMode = mFolderDisplayMode;
mFolderDisplayMode = displayMode;
return oldDisplayMode != displayMode;
}
public synchronized FolderMode getFolderSyncMode()
{
return mFolderSyncMode;
}
public synchronized boolean setFolderSyncMode(FolderMode syncMode)
{
FolderMode oldSyncMode = mFolderSyncMode;
mFolderSyncMode = syncMode;
if (syncMode == FolderMode.NONE && oldSyncMode != FolderMode.NONE)
{
return true;
}
if (syncMode != FolderMode.NONE && oldSyncMode == FolderMode.NONE)
{
return true;
}
return false;
}
public synchronized FolderMode getFolderPushMode()
{
return mFolderPushMode;
}
public synchronized boolean setFolderPushMode(FolderMode pushMode)
{
FolderMode oldPushMode = mFolderPushMode;
mFolderPushMode = pushMode;
return pushMode != oldPushMode;
}
public synchronized boolean isShowOngoing()
{
return mNotifySync;
}
public synchronized void setShowOngoing(boolean showOngoing)
{
this.mNotifySync = showOngoing;
}
public synchronized HideButtons getHideMessageViewButtons()
{
return mHideMessageViewButtons;
}
public synchronized void setHideMessageViewButtons(HideButtons hideMessageViewButtons)
{
mHideMessageViewButtons = hideMessageViewButtons;
}
public synchronized HideButtons getHideMessageViewMoveButtons()
{
return mHideMessageViewMoveButtons;
}
public synchronized void setHideMessageViewMoveButtons(HideButtons hideMessageViewButtons)
{
mHideMessageViewMoveButtons = hideMessageViewButtons;
}
public synchronized ShowPictures getShowPictures()
{
return mShowPictures;
}
public synchronized void setShowPictures(ShowPictures showPictures)
{
mShowPictures = showPictures;
}
public synchronized FolderMode getFolderTargetMode()
{
return mFolderTargetMode;
}
public synchronized void setFolderTargetMode(FolderMode folderTargetMode)
{
mFolderTargetMode = folderTargetMode;
}
public synchronized boolean isSignatureBeforeQuotedText()
{
return mIsSignatureBeforeQuotedText;
}
public synchronized void setSignatureBeforeQuotedText(boolean mIsSignatureBeforeQuotedText)
{
this.mIsSignatureBeforeQuotedText = mIsSignatureBeforeQuotedText;
}
public synchronized boolean isNotifySelfNewMail()
{
return mNotifySelfNewMail;
}
public synchronized void setNotifySelfNewMail(boolean notifySelfNewMail)
{
mNotifySelfNewMail = notifySelfNewMail;
}
public synchronized String getExpungePolicy()
{
return mExpungePolicy;
}
public synchronized void setExpungePolicy(String expungePolicy)
{
mExpungePolicy = expungePolicy;
}
public synchronized int getMaxPushFolders()
{
return mMaxPushFolders;
}
public synchronized boolean setMaxPushFolders(int maxPushFolders)
{
int oldMaxPushFolders = mMaxPushFolders;
mMaxPushFolders = maxPushFolders;
return oldMaxPushFolders != maxPushFolders;
}
public LocalStore getLocalStore() throws MessagingException
{
return Store.getLocalInstance(this, K9.app);
}
public Store getRemoteStore() throws MessagingException
{
return Store.getRemoteInstance(this);
}
@Override
public synchronized String toString()
{
return mDescription;
}
public synchronized void setCompression(String networkType, boolean useCompression)
{
compressionMap.put(networkType, useCompression);
}
public synchronized boolean useCompression(String networkType)
{
Boolean useCompression = compressionMap.get(networkType);
if (useCompression == null)
{
return true;
}
else
{
return useCompression;
}
}
public boolean useCompression(int type)
{
String networkType = TYPE_OTHER;
switch (type)
{
case ConnectivityManager.TYPE_MOBILE:
networkType = TYPE_MOBILE;
break;
case ConnectivityManager.TYPE_WIFI:
networkType = TYPE_WIFI;
break;
}
return useCompression(networkType);
}
@Override
public boolean equals(Object o)
{
if (o instanceof Account)
{
return ((Account)o).mUuid.equals(mUuid);
}
return super.equals(o);
}
@Override
public int hashCode()
{
return mUuid.hashCode();
}
private synchronized Listnull
.
* @throws MessagingException
*/
public void switchLocalStorage(String newStorageProviderId) throws MessagingException
{
if (this.mLocalStoreMigrationListener != null && !mLocalStorageProviderId.equals(newStorageProviderId))
{
mLocalStoreMigrationListener.onLocalStoreMigration(mLocalStorageProviderId,
newStorageProviderId);
}
}
public synchronized boolean goToUnreadMessageSearch()
{
return goToUnreadMessageSearch;
}
public synchronized void setGoToUnreadMessageSearch(boolean goToUnreadMessageSearch)
{
this.goToUnreadMessageSearch = goToUnreadMessageSearch;
}
public synchronized boolean subscribedFoldersOnly()
{
return subscribedFoldersOnly;
}
public synchronized void setSubscribedFoldersOnly(boolean subscribedFoldersOnly)
{
this.subscribedFoldersOnly = subscribedFoldersOnly;
}
public synchronized int getMaximumPolledMessageAge()
{
return maximumPolledMessageAge;
}
public synchronized void setMaximumPolledMessageAge(int maximumPolledMessageAge)
{
this.maximumPolledMessageAge = maximumPolledMessageAge;
}
public synchronized int getMaximumAutoDownloadMessageSize()
{
return maximumAutoDownloadMessageSize;
}
public synchronized void setMaximumAutoDownloadMessageSize(int maximumAutoDownloadMessageSize)
{
this.maximumAutoDownloadMessageSize = maximumAutoDownloadMessageSize;
}
public Date getEarliestPollDate()
{
int age = getMaximumPolledMessageAge();
if (age >= 0)
{
Calendar now = Calendar.getInstance();
now.set(Calendar.HOUR_OF_DAY, 0);
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
if (age < 28)
{
now.add(Calendar.DATE, age * -1);
}
else switch (age)
{
case 28:
now.add(Calendar.MONTH, -1);
break;
case 56:
now.add(Calendar.MONTH, -2);
break;
case 84:
now.add(Calendar.MONTH, -3);
break;
case 168:
now.add(Calendar.MONTH, -6);
break;
case 365:
now.add(Calendar.YEAR, -1);
break;
}
return now.getTime();
}
else
{
return null;
}
}
public synchronized String getQuotePrefix()
{
return mQuotePrefix;
}
public synchronized void setQuotePrefix(String quotePrefix)
{
mQuotePrefix = quotePrefix;
}
public synchronized boolean isReplyAfterQuote()
{
return mReplyAfterQuote;
}
public synchronized void setReplyAfterQuote(boolean replyAfterQuote)
{
mReplyAfterQuote = replyAfterQuote;
}
public boolean getEnableMoveButtons()
{
return mEnableMoveButtons;
}
public void setEnableMoveButtons(boolean enableMoveButtons)
{
mEnableMoveButtons = enableMoveButtons;
}
public String getCryptoApp()
{
return mCryptoApp;
}
public void setCryptoApp(String cryptoApp)
{
mCryptoApp = cryptoApp;
// invalidate the provider
mCryptoProvider = null;
}
public boolean getCryptoAutoSignature()
{
return mCryptoAutoSignature;
}
public void setCryptoAutoSignature(boolean cryptoAutoSignature)
{
mCryptoAutoSignature = cryptoAutoSignature;
}
public synchronized boolean syncRemoteDeletions()
{
return mSyncRemoteDeletions;
}
public synchronized void setSyncRemoteDeletions(boolean syncRemoteDeletions)
{
mSyncRemoteDeletions = syncRemoteDeletions;
}
public synchronized String getLastSelectedFolderName()
{
return lastSelectedFolderName;
}
public synchronized void setLastSelectedFolderName(String folderName)
{
lastSelectedFolderName = folderName;
}
public boolean isInUse()
{
return mIsInUse;
}
/**
* Set a listener to be informed when the underlying {@link StorageProvider}
* of the {@link LocalStore} of this account changes. (e.g. via
* {@link #switchLocalStorage(Context, String)})
*
* @param listener
* @see #switchLocalStorage(Context, String)
*/
public void setLocalStoreMigrationListener(LocalStoreMigrationListener listener)
{
this.mLocalStoreMigrationListener = listener;
}
public synchronized CryptoProvider getCryptoProvider()
{
if (mCryptoProvider == null)
{
mCryptoProvider = CryptoProvider.createInstance(getCryptoApp());
}
return mCryptoProvider;
}
public synchronized NotificationSetting getNotificationSetting()
{
return mNotificationSetting;
}
/**
* @return true
if our {@link StorageProvider} is ready. (e.g.
* card inserted)
*/
public boolean isAvailable(Context context)
{
String localStorageProviderId = getLocalStorageProviderId();
if (localStorageProviderId == null)
{
return true; // defaults to internal memory
}
return StorageManager.getInstance(K9.app).isReady(localStorageProviderId);
}
}