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);
+
+ }
+
+}