From 0b62640eacc2f146d934ef7613c18a94d7a29296 Mon Sep 17 00:00:00 2001 From: Jesse Vincent Date: Wed, 18 Aug 2010 02:49:13 +0000 Subject: [PATCH] Provisional initial commit of MessagingProvider code by stephane.lajeunesse and koxx33 We're going to try it out in the 3.1 dev series. if it ends up looking good, it'll be in 3.2 --- AndroidManifest.xml | 20 + res/values/strings.xml | 4 + src/com/fsck/k9/K9.java | 4 + .../fsck/k9/activity/FolderInfoHolder.java | 267 ++++++++++++ src/com/fsck/k9/activity/FolderList.java | 161 +------- .../fsck/k9/activity/MessageInfoHolder.java | 310 ++++++++++++++ src/com/fsck/k9/activity/MessageList.java | 286 +------------ src/com/fsck/k9/provider/MessageProvider.java | 390 ++++++++++++++++++ 8 files changed, 1012 insertions(+), 430 deletions(-) create mode 100644 src/com/fsck/k9/activity/FolderInfoHolder.java create mode 100644 src/com/fsck/k9/activity/MessageInfoHolder.java create mode 100644 src/com/fsck/k9/provider/MessageProvider.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 94fa2c742..e880fb7c4 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -37,6 +37,18 @@ android:label="@string/remote_control_label" android:description="@string/remote_control_desc"/> + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 4b254f25c..fccc94841 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10,6 +10,10 @@ read Email attachments Allows this application to read your Email attachments. + read Emails + Allows this application to read your Emails. + Delete Emails + Allows this application to delete your Emails. About %s Accounts diff --git a/src/com/fsck/k9/K9.java b/src/com/fsck/k9/K9.java index 440b25e1a..dc30f1c6a 100644 --- a/src/com/fsck/k9/K9.java +++ b/src/com/fsck/k9/K9.java @@ -20,6 +20,7 @@ import com.fsck.k9.mail.Address; import com.fsck.k9.mail.Message; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.internet.BinaryTempFileBody; +import com.fsck.k9.provider.MessageProvider; import com.fsck.k9.service.BootReceiver; import com.fsck.k9.service.MailService; @@ -252,6 +253,7 @@ public class K9 extends Application { public static final String ACTION_EMAIL_RECEIVED = "com.fsck.k9.intent.action.EMAIL_RECEIVED"; public static final String ACTION_EMAIL_DELETED = "com.fsck.k9.intent.action.EMAIL_DELETED"; + public static final String ACTION_REFRESH_OBSERVER = "com.fsck.k9.intent.action.REFRESH_OBSERVER"; public static final String EXTRA_ACCOUNT = "com.fsck.k9.intent.extra.ACCOUNT"; public static final String EXTRA_FOLDER = "com.fsck.k9.intent.extra.FOLDER"; public static final String EXTRA_SENT_DATE = "com.fsck.k9.intent.extra.SENT_DATE"; @@ -393,6 +395,8 @@ public class K9 extends Application K9.setK9Language(sprefs.getString("language", "")); K9.setK9Theme(sprefs.getInt("theme", android.R.style.Theme_Light)); MessagingController.getInstance(this).resetVisibleLimits(prefs.getAccounts()); + MessageProvider mp = new MessageProvider(); + mp.setApplication(this); /* * We have to give MimeMessage a temp directory because File.createTempFile(String, String) diff --git a/src/com/fsck/k9/activity/FolderInfoHolder.java b/src/com/fsck/k9/activity/FolderInfoHolder.java new file mode 100644 index 000000000..3907213d8 --- /dev/null +++ b/src/com/fsck/k9/activity/FolderInfoHolder.java @@ -0,0 +1,267 @@ +package com.fsck.k9.activity; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.text.Spannable; +import android.text.style.TextAppearanceSpan; +import android.util.Config; +import android.util.Log; +import android.util.TypedValue; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.GestureDetector; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.BaseAdapter; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.ImageButton; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; +import android.text.format.DateFormat; + +import com.fsck.k9.Account; +import com.fsck.k9.AccountStats; +import com.fsck.k9.FontSizes; +import com.fsck.k9.K9; +import com.fsck.k9.Preferences; +import com.fsck.k9.R; +import com.fsck.k9.SearchSpecification; +import com.fsck.k9.activity.setup.AccountSettings; +import com.fsck.k9.activity.setup.FolderSettings; +import com.fsck.k9.activity.setup.Prefs; +import com.fsck.k9.controller.MessagingController; +import com.fsck.k9.controller.MessagingController.SORT_TYPE; +import com.fsck.k9.controller.MessagingListener; +import com.fsck.k9.helper.Utility; +import com.fsck.k9.mail.Address; +import com.fsck.k9.mail.Flag; +import com.fsck.k9.mail.Folder; +import com.fsck.k9.mail.Message; +import com.fsck.k9.mail.Message.RecipientType; +import com.fsck.k9.mail.MessagingException; +import com.fsck.k9.mail.store.LocalStore; +import com.fsck.k9.mail.store.LocalStore.LocalFolder; +import com.fsck.k9.mail.store.LocalStore.LocalMessage; + +public class FolderInfoHolder implements Comparable +{ + public String name; + public String displayName; + public long lastChecked; + public int unreadMessageCount; + public int flaggedMessageCount; + public boolean loading; + public String status; + public boolean lastCheckFailed; + public Folder folder; + public boolean pushActive; + + /** + * Outbox is handled differently from any other folder. + */ + public boolean outbox; + + @Override + public boolean equals(Object o) + { + return this.name.equals(((FolderInfoHolder)o).name); + } + + @Override + public int hashCode() + { + return name.hashCode(); + } + + public int compareTo(FolderInfoHolder o) + { + String s1 = this.name; + String s2 = o.name; + + int ret = s1.compareToIgnoreCase(s2); + if (ret != 0) + { + return ret; + } + else + { + return s1.compareTo(s2); + } + + } + + private String truncateStatus(String mess) + { + if (mess != null && mess.length() > 27) + { + mess = mess.substring(0, 27); + } + return mess; + } + + // constructor for an empty object for comparisons + public FolderInfoHolder() + { + } + + public FolderInfoHolder(Context context, Folder folder, Account account) + { + populate(context, folder, account); + } + + public FolderInfoHolder(Context context, Folder folder, Account mAccount, int unreadCount) + { + populate(context, folder, mAccount, unreadCount); + } + + public void populate(Context context, Folder folder, Account mAccount, int unreadCount) + { + + try + { + folder.open(Folder.OpenMode.READ_WRITE); + // unreadCount = folder.getUnreadMessageCount(); + } + catch (MessagingException me) + { + Log.e(K9.LOG_TAG, "Folder.getUnreadMessageCount() failed", me); + } + + this.name = folder.getName(); + + if (this.name.equalsIgnoreCase(K9.INBOX)) + { + this.displayName = context.getString(R.string.special_mailbox_name_inbox); + } + else + { + this.displayName = folder.getName(); + } + + if (this.name.equals(mAccount.getOutboxFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_outbox_fmt), this.name); + this.outbox = true; + } + + if (this.name.equals(mAccount.getDraftsFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_drafts_fmt), this.name); + } + + if (this.name.equals(mAccount.getTrashFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_trash_fmt), this.name); + } + + if (this.name.equals(mAccount.getSentFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_sent_fmt), this.name); + } + + if (this.name.equals(mAccount.getArchiveFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_archive_fmt), this.name); + } + + if (this.name.equals(mAccount.getSpamFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_spam_fmt), this.name); + } + + this.lastChecked = folder.getLastUpdate(); + + String mess = truncateStatus(folder.getStatus()); + + this.status = mess; + + this.unreadMessageCount = unreadCount; + + try + { + this.flaggedMessageCount = folder.getFlaggedMessageCount(); + } + catch (Exception e) + { + Log.e(K9.LOG_TAG, "Unable to get flaggedMessageCount", e); + } + + folder.close(); + + } + + + public void populate(Context context, Folder folder, Account account) + { + this.folder = folder; + this.name = folder.getName(); + + if (this.name.equalsIgnoreCase(K9.INBOX)) + { + this.displayName = context.getString(R.string.special_mailbox_name_inbox); + } + else + { + this.displayName = this.name; + } + + if (this.name.equals(account.getOutboxFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_outbox_fmt), this.name); + this.outbox = true; + } + + if (this.name.equals(account.getDraftsFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_drafts_fmt), this.name); + } + + if (this.name.equals(account.getTrashFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_trash_fmt), this.name); + } + + if (this.name.equals(account.getSentFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_sent_fmt), this.name); + } + + if (this.name.equals(account.getArchiveFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_archive_fmt), this.name); + } + + if (this.name.equals(account.getSpamFolderName())) + { + this.displayName = String.format(context.getString(R.string.special_mailbox_name_spam_fmt), this.name); + } + } +} diff --git a/src/com/fsck/k9/activity/FolderList.java b/src/com/fsck/k9/activity/FolderList.java index fb44ad6e6..ea2e447bd 100644 --- a/src/com/fsck/k9/activity/FolderList.java +++ b/src/com/fsck/k9/activity/FolderList.java @@ -20,6 +20,7 @@ import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; import com.fsck.k9.*; import com.fsck.k9.Account.FolderMode; +import com.fsck.k9.activity.FolderInfoHolder; import com.fsck.k9.activity.setup.Prefs; import com.fsck.k9.activity.setup.AccountSettings; import com.fsck.k9.activity.setup.FolderSettings; @@ -69,6 +70,7 @@ public class FolderList extends K9ListActivity private int mUnreadMessageCount; private FontSizes mFontSizes = K9.getFontSizes(); + private Context context; class FolderListHandler extends Handler { @@ -293,6 +295,8 @@ public class FolderList extends K9ListActivity mInflater = getLayoutInflater(); onNewIntent(getIntent()); + + context = this; } @Override @@ -776,16 +780,6 @@ public class FolderList extends K9ListActivity menu.setHeaderTitle(folder.displayName); } - private String truncateStatus(String mess) - { - if (mess != null && mess.length() > 27) - { - mess = mess.substring(0, 27); - } - - return mess; - } - class FolderListAdapter extends BaseAdapter { private ArrayList mFolders = new ArrayList(); @@ -932,11 +926,11 @@ public class FolderList extends K9ListActivity if (holder == null) { - holder = new FolderInfoHolder(folder, unreadMessageCount); + holder = new FolderInfoHolder(context, folder, mAccount, unreadMessageCount); } else { - holder.populate(folder, unreadMessageCount); + holder.populate(context, folder, mAccount, unreadMessageCount); } if (folder.isInTopGroup()) @@ -1039,7 +1033,7 @@ public class FolderList extends K9ListActivity FolderInfoHolder folderHolder = getFolder(folderName); if (folderHolder != null) { - folderHolder.populate(localFolder, unreadMessageCount); + folderHolder.populate(context, localFolder, mAccount, unreadMessageCount); mHandler.dataChanged(); } } @@ -1385,147 +1379,6 @@ public class FolderList extends K9ListActivity } - public class FolderInfoHolder implements Comparable - { - public String name; - - public String displayName; - - public long lastChecked; - - public int unreadMessageCount; - - public int flaggedMessageCount; - - public boolean loading; - - public String status; - - public boolean pushActive; - - public boolean lastCheckFailed; - - /** - * Outbox is handled differently from any other folder. - */ - public boolean outbox; - - - @Override - public boolean equals(Object o) - { - return this.name.equals(((FolderInfoHolder)o).name); - } - - @Override - public int hashCode() - { - return name.hashCode(); - } - - public int compareTo(FolderInfoHolder o) - { - String s1 = this.name; - String s2 = o.name; - - int ret = s1.compareToIgnoreCase(s2); - if (ret != 0) - { - return ret; - } - else - { - return s1.compareTo(s2); - } - - } - - // constructor for an empty object for comparisons - public FolderInfoHolder() - { - } - - public FolderInfoHolder(Folder folder, int unreadCount) - { - populate(folder, unreadCount); - } - public void populate(Folder folder, int unreadCount) - { - - try - { - folder.open(Folder.OpenMode.READ_WRITE); - // unreadCount = folder.getUnreadMessageCount(); - } - catch (MessagingException me) - { - Log.e(K9.LOG_TAG, "Folder.getUnreadMessageCount() failed", me); - } - - this.name = folder.getName(); - - if (this.name.equalsIgnoreCase(K9.INBOX)) - { - this.displayName = getString(R.string.special_mailbox_name_inbox); - } - else - { - this.displayName = folder.getName(); - } - - if (this.name.equals(mAccount.getOutboxFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_outbox_fmt), this.name); - this.outbox = true; - } - - if (this.name.equals(mAccount.getDraftsFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_drafts_fmt), this.name); - } - - if (this.name.equals(mAccount.getTrashFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_trash_fmt), this.name); - } - - if (this.name.equals(mAccount.getSentFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_sent_fmt), this.name); - } - - if (this.name.equals(mAccount.getArchiveFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_archive_fmt), this.name); - } - - if (this.name.equals(mAccount.getSpamFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_spam_fmt), this.name); - } - - this.lastChecked = folder.getLastUpdate(); - - String mess = truncateStatus(folder.getStatus()); - - this.status = mess; - - this.unreadMessageCount = unreadCount; - - try - { - this.flaggedMessageCount = folder.getFlaggedMessageCount(); - } - catch (Exception e) - { - Log.e(K9.LOG_TAG, "Unable to get flaggedMessageCount", e); - } - - folder.close(); - - } - } - class FolderViewHolder { public TextView folderName; diff --git a/src/com/fsck/k9/activity/MessageInfoHolder.java b/src/com/fsck/k9/activity/MessageInfoHolder.java new file mode 100644 index 000000000..8fe94873a --- /dev/null +++ b/src/com/fsck/k9/activity/MessageInfoHolder.java @@ -0,0 +1,310 @@ +package com.fsck.k9.activity; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Handler; +import android.text.Spannable; +import android.text.style.TextAppearanceSpan; +import android.util.Config; +import android.util.Log; +import android.util.TypedValue; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.GestureDetector; +import android.view.GestureDetector.SimpleOnGestureListener; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.BaseAdapter; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.ImageButton; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; +import android.text.format.DateFormat; + +import com.fsck.k9.Account; +import com.fsck.k9.AccountStats; +import com.fsck.k9.FontSizes; +import com.fsck.k9.K9; +import com.fsck.k9.Preferences; +import com.fsck.k9.R; +import com.fsck.k9.SearchSpecification; +import com.fsck.k9.activity.setup.AccountSettings; +import com.fsck.k9.activity.setup.FolderSettings; +import com.fsck.k9.activity.setup.Prefs; +import com.fsck.k9.activity.FolderInfoHolder; +import com.fsck.k9.controller.MessagingController; +import com.fsck.k9.controller.MessagingController.SORT_TYPE; +import com.fsck.k9.controller.MessagingListener; +import com.fsck.k9.helper.Utility; +import com.fsck.k9.mail.Address; +import com.fsck.k9.mail.Flag; +import com.fsck.k9.mail.Folder; +import com.fsck.k9.mail.Message; +import com.fsck.k9.mail.Message.RecipientType; +import com.fsck.k9.mail.MessagingException; +import com.fsck.k9.mail.store.LocalStore; +import com.fsck.k9.mail.store.LocalStore.LocalFolder; +import com.fsck.k9.mail.store.LocalStore.LocalMessage; + +public class MessageInfoHolder implements Comparable +{ + public String subject; + public String date; + public String fullDate; + public Date compareDate; + public String compareSubject; + public String sender; + public String senderAddress; + public String compareCounterparty; + public String preview; + public String[] recipients; + public boolean hasAttachments; + public String uid; + public boolean read; + public boolean answered; + public boolean flagged; + public boolean downloaded; + public boolean partially_downloaded; + public Message message; + public FolderInfoHolder folder; + public boolean selected; + public String account; + public String uri; + + private SORT_TYPE sortType = SORT_TYPE.SORT_DATE; + + private boolean sortAscending = true; + private boolean sortDateAscending = false; + private MessagingController mController; + + // Empty constructor for comparison + public MessageInfoHolder() + { + this.selected = false; + } + + public MessageInfoHolder(Context context, Message m) + { + this(); + Account account = m.getFolder().getAccount(); + mController = MessagingController.getInstance(K9.app); + sortType = mController.getSortType(); + sortAscending = mController.isSortAscending(sortType); + sortDateAscending = mController.isSortAscending(SORT_TYPE.SORT_DATE); + populate(context, m, new FolderInfoHolder(context, m.getFolder(), m.getFolder().getAccount()), account); + } + + public MessageInfoHolder(Context context ,Message m, SORT_TYPE t_sort, boolean asc) + { + this(); + Account account = m.getFolder().getAccount(); + mController = MessagingController.getInstance(K9.app); + sortType = t_sort; + sortAscending = asc; + sortDateAscending = asc; + populate(context, m, new FolderInfoHolder(context, m.getFolder(), m.getFolder().getAccount()), account); + } + + public MessageInfoHolder(Context context, Message m, FolderInfoHolder folder, Account account) + { + this(); + mController = MessagingController.getInstance(K9.app); + sortType = mController.getSortType(); + sortAscending = mController.isSortAscending(sortType); + sortDateAscending = mController.isSortAscending(SORT_TYPE.SORT_DATE); + populate(context, m, folder, account); + } + + public void populate(Context context, Message m, FolderInfoHolder folder, Account account) + { + try + { + LocalMessage message = (LocalMessage) m; + Date date = message.getSentDate(); + this.compareDate = message.getSentDate(); + if (this.compareDate == null) + { + this.compareDate = message.getInternalDate(); + } + + this.folder = folder; + + if (Utility.isDateToday(date)) + { + this.date = android.text.format.DateFormat.getTimeFormat(context).format(date); + } + else + { + this.date = DateFormatter.getDateFormat(context).format(date); + } + + this.hasAttachments = message.getAttachmentCount() > 0; + + this.read = message.isSet(Flag.SEEN); + this.answered = message.isSet(Flag.ANSWERED); + this.flagged = message.isSet(Flag.FLAGGED); + this.downloaded = message.isSet(Flag.X_DOWNLOADED_FULL); + this.partially_downloaded = message.isSet(Flag.X_DOWNLOADED_PARTIAL); + + Address[] addrs = message.getFrom(); + + if (addrs.length > 0 && account.isAnIdentity(addrs[0])) + { + this.compareCounterparty = Address.toFriendly(message .getRecipients(RecipientType.TO)); + this.sender = String.format(context.getString(R.string.message_list_to_fmt), this.compareCounterparty); + } + else + { + this.sender = Address.toFriendly(addrs); + this.compareCounterparty = this.sender; + } + + if (addrs.length > 0) + { + this.senderAddress = addrs[0].getAddress(); + } + else + { + // a reasonable fallback "whomever we were corresponding with + this.senderAddress = this.compareCounterparty; + } + + this.subject = message.getSubject(); + + this.uid = message.getUid(); + this.message = m; + this.preview = message.getPreview(); + + this.fullDate = DateFormatter.getDateFormat(context).format(date)+" "+android.text.format.DateFormat.getTimeFormat(context).format(date); + this.account = account.getDescription(); + this.uri = "email://messages/"+account.getAccountNumber()+"/"+m.getFolder().getName()+"/"+m.getUid(); + + } + catch (MessagingException me) + { + if (Config.LOGV) + { + Log.v(K9.LOG_TAG, "Unable to load message info", me); + } + } + } + + @Override + public boolean equals(Object o) + { + if (o instanceof MessageInfoHolder == false) + { + return false; + } + MessageInfoHolder other = (MessageInfoHolder)o; + return message.equals(other.message); + } + + @Override + public int hashCode() + { + return uid.hashCode(); + } + + public int compareTo(MessageInfoHolder o) + { + int ascender = (sortAscending ? 1 : -1); + int comparison = 0; + + if (sortType == SORT_TYPE.SORT_SUBJECT) + { + if (compareSubject == null) + { + compareSubject = stripPrefixes(subject).toLowerCase(); + } + + if (o.compareSubject == null) + { + o.compareSubject = stripPrefixes(o.subject).toLowerCase(); + } + + comparison = this.compareSubject.compareTo(o.compareSubject); + } + else if (sortType == SORT_TYPE.SORT_SENDER) + { + comparison = this.compareCounterparty.toLowerCase().compareTo(o.compareCounterparty.toLowerCase()); + } + else if (sortType == SORT_TYPE.SORT_FLAGGED) + { + comparison = (this.flagged ? 0 : 1) - (o.flagged ? 0 : 1); + } + else if (sortType == SORT_TYPE.SORT_UNREAD) + { + comparison = (this.read ? 1 : 0) - (o.read ? 1 : 0); + } + else if (sortType == SORT_TYPE.SORT_ATTACHMENT) + { + comparison = (this.hasAttachments ? 0 : 1) - (o.hasAttachments ? 0 : 1); + } + + if (comparison != 0) + { + return comparison * ascender; + } + + int dateAscender = (sortDateAscending ? 1 : -1); + + return this.compareDate.compareTo(o.compareDate) * dateAscender; + } + + Pattern pattern = null; + String patternString = "^ *(re|aw|fw|fwd): *"; + private String stripPrefixes(String in) + { + synchronized (patternString) + { + if (pattern == null) + { + pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE); + } + } + + Matcher matcher = pattern.matcher(in); + + int lastPrefix = -1; + + while (matcher.find()) + { + lastPrefix = matcher.end(); + } + + if (lastPrefix > -1 && lastPrefix < in.length() - 1) + { + return in.substring(lastPrefix); + } + else + { + return in; + } + } +} diff --git a/src/com/fsck/k9/activity/MessageList.java b/src/com/fsck/k9/activity/MessageList.java index f02ac2995..eadbf99aa 100644 --- a/src/com/fsck/k9/activity/MessageList.java +++ b/src/com/fsck/k9/activity/MessageList.java @@ -44,6 +44,7 @@ import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import android.text.format.DateFormat; import com.fsck.k9.Account; import com.fsck.k9.AccountStats; @@ -68,7 +69,8 @@ import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.store.LocalStore; import com.fsck.k9.mail.store.LocalStore.LocalFolder; import com.fsck.k9.mail.store.LocalStore.LocalMessage; - +import com.fsck.k9.activity.MessageInfoHolder; +import com.fsck.k9.activity.FolderInfoHolder; /** * MessageList is the primary user interface for the program. This Activity @@ -159,6 +161,8 @@ public class MessageList private Bundle mState = null; private MessageInfoHolder mSelectedMessage = null; + private Context context = null; + class MessageListHandler { public void removeMessage(final List messages) @@ -437,6 +441,7 @@ public class MessageList mInflater = getLayoutInflater(); initializeLayout(); onNewIntent(getIntent()); + context=this; } @Override @@ -2029,7 +2034,7 @@ public class MessageList { if (updateForMe(account, folder)) { - m = new MessageInfoHolder(message); + m = new MessageInfoHolder(context, message); messagesToAdd.add(m); } else @@ -2042,7 +2047,7 @@ public class MessageList } else { - m = new MessageInfoHolder(message); + m = new MessageInfoHolder(context, message); messagesToAdd.add(m); } } @@ -2050,7 +2055,7 @@ public class MessageList } else { - m.populate(message, new FolderInfoHolder(message.getFolder(), account), account); + m.populate(context, message, new FolderInfoHolder(context, message.getFolder(), account), account); needsSort = true; } } @@ -2121,7 +2126,7 @@ public class MessageList { LocalStore localStore = account.getLocalStore(); local_folder = localStore.getFolder(folder); - return new FolderInfoHolder((Folder)local_folder, account); + return new FolderInfoHolder(context, (Folder)local_folder, account); } catch (Exception e) { @@ -2473,213 +2478,6 @@ public class MessageList } } - public class MessageInfoHolder implements Comparable - { - public String subject; - public String date; - public Date compareDate; - public String compareSubject; - public String sender; - public String senderAddress; - public String compareCounterparty; - public String preview; - public String[] recipients; - public boolean hasAttachments; - public String uid; - public boolean read; - public boolean answered; - public boolean flagged; - public boolean downloaded; - public boolean partially_downloaded; - public Message message; - public FolderInfoHolder folder; - public boolean selected; - - // Empty constructor for comparison - public MessageInfoHolder() - { - this.selected = false; - } - - public MessageInfoHolder(Message m) - { - this(); - Account account = m.getFolder().getAccount(); - populate(m, new FolderInfoHolder(m.getFolder(), m.getFolder().getAccount()), account); - } - - public MessageInfoHolder(Message m, FolderInfoHolder folder, Account account) - { - this(); - populate(m, folder, account); - } - - public void populate(Message m, FolderInfoHolder folder, Account account) - { - try - { - LocalMessage message = (LocalMessage) m; - Date date = message.getSentDate(); - this.compareDate = message.getSentDate(); - if (this.compareDate == null) - { - this.compareDate = message.getInternalDate(); - } - - this.folder = folder; - - if (Utility.isDateToday(date)) - { - this.date = getTimeFormat().format(date); - } - else - { - this.date = getDateFormat().format(date); - } - - this.hasAttachments = message.getAttachmentCount() > 0; - - this.read = message.isSet(Flag.SEEN); - this.answered = message.isSet(Flag.ANSWERED); - this.flagged = message.isSet(Flag.FLAGGED); - this.downloaded = message.isSet(Flag.X_DOWNLOADED_FULL); - this.partially_downloaded = message.isSet(Flag.X_DOWNLOADED_PARTIAL); - - Address[] addrs = message.getFrom(); - - if (addrs.length > 0 && account.isAnIdentity(addrs[0])) - { - this.compareCounterparty = Address.toFriendly(message .getRecipients(RecipientType.TO)); - this.sender = String.format(getString(R.string.message_list_to_fmt), this.compareCounterparty); - } - else - { - this.sender = Address.toFriendly(addrs); - this.compareCounterparty = this.sender; - } - - if (addrs.length > 0) - { - this.senderAddress = addrs[0].getAddress(); - } - else - { - // a reasonable fallback "whomever we were corresponding with - this.senderAddress = this.compareCounterparty; - } - - - this.subject = message.getSubject(); - - this.uid = message.getUid(); - this.message = m; - this.preview = message.getPreview(); - } - catch (MessagingException me) - { - if (Config.LOGV) - { - Log.v(K9.LOG_TAG, "Unable to load message info", me); - } - } - } - - @Override - public boolean equals(Object o) - { - if (o instanceof MessageInfoHolder == false) - { - return false; - } - MessageInfoHolder other = (MessageInfoHolder)o; - return message.equals(other.message); - } - - @Override - public int hashCode() - { - return uid.hashCode(); - } - - @Override - public int compareTo(MessageInfoHolder o) - { - int ascender = (sortAscending ? 1 : -1); - int comparison = 0; - - if (sortType == SORT_TYPE.SORT_SUBJECT) - { - if (compareSubject == null) - { - compareSubject = stripPrefixes(subject).toLowerCase(); - } - - if (o.compareSubject == null) - { - o.compareSubject = stripPrefixes(o.subject).toLowerCase(); - } - - comparison = this.compareSubject.compareTo(o.compareSubject); - } - else if (sortType == SORT_TYPE.SORT_SENDER) - { - comparison = this.compareCounterparty.toLowerCase().compareTo(o.compareCounterparty.toLowerCase()); - } - else if (sortType == SORT_TYPE.SORT_FLAGGED) - { - comparison = (this.flagged ? 0 : 1) - (o.flagged ? 0 : 1); - } - else if (sortType == SORT_TYPE.SORT_UNREAD) - { - comparison = (this.read ? 1 : 0) - (o.read ? 1 : 0); - } - else if (sortType == SORT_TYPE.SORT_ATTACHMENT) - { - comparison = (this.hasAttachments ? 0 : 1) - (o.hasAttachments ? 0 : 1); - } - - if (comparison != 0) - { - return comparison * ascender; - } - - int dateAscender = (sortDateAscending ? 1 : -1); - - return this.compareDate.compareTo(o.compareDate) * dateAscender; - } - - Pattern pattern = null; - String patternString = "^ *(re|aw|fw|fwd): *"; - private String stripPrefixes(String in) - { - synchronized (patternString) - { - if (pattern == null) - { - pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE); - } - } - - Matcher matcher = pattern.matcher(in); - - int lastPrefix = -1; - - while (matcher.find()) - { - lastPrefix = matcher.end(); - } - - if (lastPrefix > -1 && lastPrefix < in.length() - 1) - { - return in.substring(lastPrefix); - } - else - { - return in; - } - } - } - class MessageViewHolder implements OnCheckedChangeListener { @@ -2791,70 +2589,6 @@ public class MessageList public TextView main; } - public class FolderInfoHolder - { - public String name; - public String displayName; - public boolean loading; - public boolean lastCheckFailed; - public Folder folder; - - /** - * Outbox is handled differently from any other folder. - */ - public boolean outbox; - - public FolderInfoHolder(Folder folder, Account account) - { - populate(folder, account); - } - - public void populate(Folder folder, Account account) - { - this.folder = folder; - this.name = folder.getName(); - - if (this.name.equalsIgnoreCase(K9.INBOX)) - { - this.displayName = getString(R.string.special_mailbox_name_inbox); - } - else - { - this.displayName = this.name; - } - - if (this.name.equals(account.getOutboxFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_outbox_fmt), this.name); - this.outbox = true; - } - - if (this.name.equals(account.getDraftsFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_drafts_fmt), this.name); - } - - if (this.name.equals(account.getTrashFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_trash_fmt), this.name); - } - - if (this.name.equals(account.getSentFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_sent_fmt), this.name); - } - - if (this.name.equals(account.getArchiveFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_archive_fmt), this.name); - } - - if (this.name.equals(account.getSpamFolderName())) - { - this.displayName = String.format(getString(R.string.special_mailbox_name_spam_fmt), this.name); - } - } - } private boolean computeBatchDirection(boolean flagged) { diff --git a/src/com/fsck/k9/provider/MessageProvider.java b/src/com/fsck/k9/provider/MessageProvider.java new file mode 100644 index 000000000..41456e973 --- /dev/null +++ b/src/com/fsck/k9/provider/MessageProvider.java @@ -0,0 +1,390 @@ +package com.fsck.k9.provider; + +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.Date; +import java.text.SimpleDateFormat; + +import android.app.Application; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.Context; +import android.content.res.Resources; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; +import android.util.Log; +import android.os.Bundle; +import android.util.Config; +import android.text.format.DateFormat; +import android.provider.Settings; +import android.content.Intent; + +import com.fsck.k9.Account; +import com.fsck.k9.AccountStats; +import com.fsck.k9.K9; +import com.fsck.k9.controller.MessagingController; +import com.fsck.k9.controller.MessagingListener; +import com.fsck.k9.Preferences; +import com.fsck.k9.mail.Flag; +import com.fsck.k9.mail.Folder; +import com.fsck.k9.mail.Message; +import com.fsck.k9.mail.Address; +import com.fsck.k9.mail.MessagingException; +import com.fsck.k9.mail.store.LocalStore; +import com.fsck.k9.SearchAccount; +import com.fsck.k9.Account; +import com.fsck.k9.mail.Message.RecipientType; +import com.fsck.k9.R; +import com.fsck.k9.mail.store.LocalStore.LocalMessage; +import com.fsck.k9.AccountStats; +import com.fsck.k9.helper.Utility; +import com.fsck.k9.controller.MessagingController.SORT_TYPE; +import com.fsck.k9.activity.DateFormatter; +import com.fsck.k9.activity.MessageInfoHolder; +import com.fsck.k9.controller.MessagingController.SORT_TYPE; + +public class MessageProvider extends ContentProvider +{ + + public static final String AUTHORITY = "com.fsck.k9.messageprovider"; + + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY); + + private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); + + private static final int URI_INBOX_MESSAGES = 0; + private static final int URI_DELETE_MESSAGE = 1; + private static final int URI_ACCOUNTS = 2; + private static final int URI_ACCOUNT_UNREAD = 3; + + private static String mCurrentEmailAccount = ""; + private static Context context = null; + private static boolean mIsListenerRegister = false; + private static boolean inSync = false; + + private static Application mApp; + + private List glb_messages; + private static MatrixCursor mCursor; + + static + { + URI_MATCHER.addURI(AUTHORITY, "inbox_messages/", URI_INBOX_MESSAGES); + URI_MATCHER.addURI(AUTHORITY, "delete_message/", URI_DELETE_MESSAGE); + URI_MATCHER.addURI(AUTHORITY, "accounts", URI_ACCOUNTS); + URI_MATCHER.addURI(AUTHORITY, "account_unread/#", URI_ACCOUNT_UNREAD); + } + + static String[] messages_projection = new String[] + { + "id", + "date", + "sender", + "subject", + "preview", + "account", + "uri", + "delUri" + }; + MessagingListener mListener = new MessagingListener() + { + + public void messageDeleted(Account account, String folder, Message message) + { + } + + public void folderStatusChanged(Account account, String folderName, int unreadMessageCount) + { + if (inSync == false) + { + inSync = true; + glb_messages = new ArrayList(); + SearchAccount integratedInboxAccount = new SearchAccount(getContext(), true, null, null); + MessagingController msgController = MessagingController.getInstance(mApp); + msgController.searchLocalMessages(integratedInboxAccount, null, mListener); + } + } + + public void listLocalMessagesStarted(Account account, String folder) + { + } + + public void listLocalMessagesFinished(Account account, String folder) + { + } + + public void searchStats(AccountStats stats) + { + int id = -1; + Collections.sort(glb_messages); + MatrixCursor tmpCur = new MatrixCursor(messages_projection); + for (MessageInfoHolder mi : glb_messages) + { + ++id; + Message msg = mi.message; + tmpCur.addRow(new Object[] {id,mi.fullDate,mi.sender,mi.subject,mi.preview,mi.account,mi.uri,CONTENT_URI+"/delete_message/"+msg.getFolder().getAccount().getAccountNumber()+"/"+msg.getFolder().getName()+"/"+msg.getUid()}); + } + mCursor = tmpCur; + inSync=false; + notifyDatabaseModification(); + } + + public void listLocalMessagesAddMessages(Account account, String folder, List messages) + { +// We will by default sort by DATE desc + SORT_TYPE t_sort = SORT_TYPE.SORT_DATE; + + for (Message m : messages) + { + MessageInfoHolder m1 = new MessageInfoHolder(context,m,t_sort,false); + glb_messages.add(m1); + } + } + + }; + + public Cursor getAllAccounts() + { + String[] projection = new String[] { "accountNumber", "accountName" }; + + MatrixCursor ret = new MatrixCursor(projection); + + for (Account account : Preferences.getPreferences(getContext()).getAccounts()) + { + Object[] values = new Object[2]; + values[0] = account.getAccountNumber(); + values[1] = account.getDescription(); + ret.addRow(values); + } + + return ret; + } + + public Cursor getAccountUnread(int accountNumber) + { + String[] projection = new String[] { "accountName", "unread" }; + + MatrixCursor ret = new MatrixCursor(projection); + + Account myAccount; + AccountStats myAccountStats = null; + + Object[] values = new Object[2]; + + for (Account account : Preferences.getPreferences(getContext()).getAccounts()) + { + if (account.getAccountNumber()==accountNumber) + { + myAccount = account; + try + { + myAccountStats = account.getStats(getContext()); + values[0] = myAccount.getDescription(); + values[1] = myAccountStats.unreadMessageCount; + ret.addRow(values); + } + catch (MessagingException e) + { + Log.e(K9.LOG_TAG, e.getMessage()); + values[0] = "Unknown"; + values[1] = 0; + } + } + } + + return ret; + } + + public void setApplication(Application app) + { + + if (app != null) + { + mApp = app; + MessagingController msgController = MessagingController.getInstance(mApp); + if ((msgController != null) && (!mIsListenerRegister)) + { + msgController.addListener(mListener); + mIsListenerRegister = true; + } + } + + } + + @Override + public boolean onCreate() + { + context = getContext(); + + if (mApp != null) + { + MessagingController msgController = MessagingController.getInstance(mApp); + if ((msgController != null) && (!mIsListenerRegister)) + { + msgController.addListener(mListener); + mIsListenerRegister = true; + } + } + + return false; + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) + { + + if (K9.DEBUG) + Log.d(K9.LOG_TAG, "delete"); + + if (mApp == null) + { + Log.d(K9.LOG_TAG, "K9 not ready"); + return 0; + } + + // Nota : can only delete a message + + List segments = null; + int accountId = -1; + String folderName = null; + String msgUid = null; + + segments = uri.getPathSegments(); + accountId = Integer.parseInt(segments.get(1)); + folderName = segments.get(2); + msgUid = segments.get(3); + + // get account + Account myAccount = null; + for (Account account : Preferences.getPreferences(getContext()).getAccounts()) + { + if (account.getAccountNumber() == accountId) + { + myAccount = account; + } + } + + // get localstore parameter + Message msg = null; + try + { + Folder lf = LocalStore.getLocalInstance(myAccount, mApp).getFolder(folderName); + int msgCount = lf.getMessageCount(); + if (K9.DEBUG) + Log.d(K9.LOG_TAG, "folder msg count = " + msgCount); + msg = lf.getMessage(msgUid); + } + catch (MessagingException e) + { + Log.e(K9.LOG_TAG, e.getMessage()); + } + + // launch command to delete the message + if ((myAccount != null) && (msg != null)) + { + MessagingController.getInstance(mApp).deleteMessages(new Message[] { msg }, mListener); + } + + return 0; + } + + @Override + public String getType(Uri uri) + { + return null; + } + + @Override + public Uri insert(Uri uri, ContentValues values) + { + return null; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) + { + + if (K9.DEBUG) + Log.d(K9.LOG_TAG, "query"); + + if (mApp == null) + { + Log.d(K9.LOG_TAG, "K9 not ready"); + return null; + } + + Cursor cursor; + switch (URI_MATCHER.match(uri)) + { + case URI_INBOX_MESSAGES: + + + if (mCursor == null) + { + mCursor = new MatrixCursor(messages_projection); + // new code for integrated inbox, only execute this once as it will be processed afterwards via the listener + glb_messages = new ArrayList(); + SearchAccount integratedInboxAccount = new SearchAccount(getContext(), true, null, null); + MessagingController msgController = MessagingController.getInstance(mApp); + msgController.searchLocalMessages(integratedInboxAccount, null, mListener); + } + + int id = -1; + +// Process messages + +//cursor = getAllMessages(projection, selection, selectionArgs, sortOrder); + cursor = (Cursor)mCursor; + break; + + case URI_ACCOUNTS: + cursor = getAllAccounts(); + break; + + case URI_ACCOUNT_UNREAD: + + List segments = null; + int accountId = -1; + segments = uri.getPathSegments(); + accountId = Integer.parseInt(segments.get(1)); + cursor = getAccountUnread(accountId); + break; + + default: + throw new IllegalStateException("Unrecognized URI:" + uri); + } + + return cursor; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) + { + + if (K9.DEBUG) + Log.d(K9.LOG_TAG, "update"); + +//TBD + + return 0; + } + + public static void notifyDatabaseModification() + { + + if (K9.DEBUG) + Log.d(K9.LOG_TAG, "notifyDatabaseModification -> UPDATE"); + + Intent intent = new Intent(K9.Intents.EmailReceived.ACTION_REFRESH_OBSERVER, null); + context.sendBroadcast(intent); + + context.getContentResolver().notifyChange(CONTENT_URI, null); + + } + +}