1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-12 04:25:08 -05:00

Issue 117

Issue 30

Provide support for multiple identities.  Identities can be managed in
the Account Settings.  While composing a message, an identity can be
chosen for sending.  Identity information and signature edits are
saved in a header field, so that they survive being synced to the
server and back.

Provide support for editing the quoted text, either for replies or
forwards.  The quoted text is immediately editable, in a separate
editor from the main body.  When saved in a draft, the two are
contatenated, but the length of the main body is saved with the
identity information, and is used to split the two parts again, when
opening the draft.
This commit is contained in:
Daniel Applebaum 2009-06-09 03:11:35 +00:00
parent 8e52a4efed
commit 10b9b0a05b
19 changed files with 1238 additions and 142 deletions

View File

@ -72,6 +72,22 @@
android:label="@string/choose_folder_title" android:label="@string/choose_folder_title"
> >
</activity> </activity>
<activity
android:name="com.android.email.activity.ChooseIdentity"
android:theme="@style/Theme.K9Dialog"
android:label="@string/choose_identity_title"
>
</activity>
<activity
android:name="com.android.email.activity.ManageIdentities"
android:label="@string/manage_identities_title"
>
</activity>
<activity
android:name="com.android.email.activity.EditIdentity"
android:label="@string/edit_identity_title"
>
</activity>
<!-- XXX Note: this activity is hacked to ignore config changes, <!-- XXX Note: this activity is hacked to ignore config changes,
since it doesn't currently handle them correctly in code. --> since it doesn't currently handle them correctly in code. -->
<activity <activity

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbarStyle="outsideInset">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:text="@string/edit_identity_description_label"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary" />
<EditText
android:id="@+id/description"
android:singleLine="true"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:hint="@string/edit_identity_description_hint"
/>
<TextView
android:text="@string/edit_identity_name_label"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary" />
<EditText
android:id="@+id/name"
android:singleLine="true"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:hint="@string/edit_identity_name_hint"
/>
<TextView
android:text="@string/edit_identity_email_label"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
/>
<EditText
android:id="@+id/email"
android:singleLine="true"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:hint="@string/edit_identity_email_hint"
/>
<!--
<TextView
android:text="@string/edit_identity_always_bcc_label"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary" />
<EditText
android:id="@+id/account_always_bcc"
android:singleLine="true"
android:layout_height="wrap_content"
android:layout_width="fill_parent" />
-->
<TextView
android:text="@string/edit_identity_signature_label"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary" />
<EditText
android:id="@+id/signature"
android:singleLine="false"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:hint="@string/edit_identity_signature_hint"
/>
</LinearLayout>
</ScrollView>

View File

@ -11,6 +11,15 @@
<LinearLayout android:orientation="vertical" <LinearLayout android:orientation="vertical"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:background="#ededed"> android:layout_height="wrap_content" android:background="#ededed">
<TextView android:id="@+id/from"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorSecondary"
android:layout_marginLeft="6px"
android:layout_marginRight="6px"/>
<MultiAutoCompleteTextView <MultiAutoCompleteTextView
android:id="@+id/to" android:layout_width="fill_parent" android:id="@+id/to" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -67,8 +76,20 @@
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="left|top" android:gravity="left|top"
android:minLines="3" android:autoText="true" android:minLines="3" android:autoText="true"
android:capitalize="sentences" /> android:capitalize="sentences"
android:hint="@string/message_compose_content_hint" />
<!-- quoted text bar --> <!-- quoted text bar -->
<EditText android:id="@+id/upper_signature"
android:textColor="?android:attr/textColorSecondary"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="left|top"
android:editable="false"
android:minLines="0" android:autoText="true"
android:capitalize="sentences" />
<RelativeLayout android:id="@+id/quoted_text_bar" <RelativeLayout android:id="@+id/quoted_text_bar"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="45px" android:background="@drawable/email_quoted_bar"> android:layout_height="45px" android:background="@drawable/email_quoted_bar">
@ -86,9 +107,26 @@
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_alignParentRight="true" /> android:layout_alignParentRight="true" />
</RelativeLayout> </RelativeLayout>
<WebView android:id="@+id/quoted_text" <EditText android:id="@+id/quoted_text"
android:textColor="?android:attr/textColorSecondary"
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="fill_parent" /> android:layout_weight="1.0"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="left|top"
android:minLines="3" android:autoText="true"
android:capitalize="sentences" />
<EditText android:id="@+id/lower_signature"
android:textColor="?android:attr/textColorSecondary"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="left|top"
android:editable="false"
android:minLines="0" android:autoText="true"
android:capitalize="sentences" />
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/edit"
android:title="@string/manage_identities_edit_action" />
<item android:id="@+id/up"
android:title="@string/manage_identities_move_up_action" />
<item android:id="@+id/down"
android:title="@string/manage_identities_move_down_action" />
<item android:id="@+id/top"
android:title="@string/manage_identities_move_top_action" />
<item android:id="@+id/remove"
android:title="@string/manage_identities_remove_action" />
</menu>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/new_identity"
android:alphabeticShortcut="n"
android:title="@string/new_identity_action"
android:icon="@drawable/ic_menu_add"
/>
</menu>

View File

@ -30,4 +30,10 @@
android:title="@string/discard_action" android:title="@string/discard_action"
android:icon="@drawable/ic_menu_close_clear_cancel" android:icon="@drawable/ic_menu_close_clear_cancel"
/> />
<item
android:id="@+id/choose_identity"
android:alphabeticShortcut="i"
android:title="@string/choose_identity"
android:icon="@drawable/ic_menu_cc"
/>
</menu> </menu>

View File

@ -185,8 +185,9 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
<string name="message_compose_cc_hint">Cc</string> <string name="message_compose_cc_hint">Cc</string>
<string name="message_compose_bcc_hint">Bcc</string> <string name="message_compose_bcc_hint">Bcc</string>
<string name="message_compose_subject_hint">Subject</string> <string name="message_compose_subject_hint">Subject</string>
<string name="message_compose_fwd_header_fmt">\n\n-------- Original Message --------\nSubject: <xliff:g id="subject">%s</xliff:g>\nFrom: <xliff:g id="sender">%s</xliff:g>\nTo: <xliff:g id="to">%s</xliff:g>\nCC: <xliff:g id="cc">%s</xliff:g>\n\n</string> <string name="message_compose_content_hint">Message text</string>
<string name="message_compose_reply_header_fmt">\n\n<xliff:g id="sender">%s</xliff:g> wrote:\n\n</string> <string name="message_compose_fwd_header_fmt">\n-------- Original Message --------\nSubject: <xliff:g id="subject">%s</xliff:g>\nFrom: <xliff:g id="sender">%s</xliff:g>\nTo: <xliff:g id="to">%s</xliff:g>\nCC: <xliff:g id="cc">%s</xliff:g>\n\n</string>
<string name="message_compose_reply_header_fmt">\n<xliff:g id="sender">%s</xliff:g> wrote:\n\n</string>
<string name="message_compose_quoted_text_label">Quoted text</string> <string name="message_compose_quoted_text_label">Quoted text</string>
<string name="message_compose_error_no_recipients">You must add at least one recipient.</string> <string name="message_compose_error_no_recipients">You must add at least one recipient.</string>
<string name="message_compose_downloading_attachments_toast">Some attachments were not downloaded. They will be downloaded automatically before this message is sent.</string> <string name="message_compose_downloading_attachments_toast">Some attachments were not downloaded. They will be downloaded automatically before this message is sent.</string>
@ -194,6 +195,7 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
<string name="message_list_to_fmt">To:<xliff:g id="counterParty">%s</xliff:g></string> <string name="message_list_to_fmt">To:<xliff:g id="counterParty">%s</xliff:g></string>
<string name="message_view_from_format">From: <xliff:g id="name">%s</xliff:g> &lt;<xliff:g id="email">%s</xliff:g>&gt;</string>
<string name="message_view_to_label">To:</string> <string name="message_view_to_label">To:</string>
<string name="message_view_attachment_view_action">Open</string> <string name="message_view_attachment_view_action">Open</string>
<string name="message_view_attachment_download_action">Save</string> <string name="message_view_attachment_download_action">Save</string>
@ -411,14 +413,46 @@ Welcome to K-9 Mail setup. K-9 is an open source email client for Android based
<string name="account_settings_composition_title">Message composition options</string> <string name="account_settings_composition_title">Message composition options</string>
<string name="account_settings_composition_label">Composing messages</string> <string name="account_settings_composition_label">Composing messages</string>
<string name="account_settings_identities_label">Manage identities</string>
<string name="manage_identities_title">Manage identities</string>
<string name="manage_identities_context_menu_title">Manage identity</string>
<string name="edit_identity_title">Edit identities</string>
<string name="new_identity_action">Create new identity</string>
<string name="account_settings_always_bcc_label">Bcc all messages to</string> <string name="account_settings_always_bcc_label">Bcc all messages to</string>
<string name="account_settings_always_bcc_summary">Send this address a copy of every outgoing message</string> <string name="account_settings_always_bcc_summary">Send this address a copy of every outgoing message</string>
<string name="manage_identities_edit_action">Edit</string>
<string name="manage_identities_move_up_action">Move up</string>
<string name="manage_identities_move_down_action">Move down</string>
<string name="manage_identities_move_top_action">Move to top / make default</string>
<string name="manage_identities_remove_action">Remove</string>
<string name="edit_identity_description_label">Identity description</string>
<string name="edit_identity_description_hint">(Optional)</string>
<string name="edit_identity_name_label">Your name</string>
<string name="edit_identity_name_hint">(Optional)</string>
<string name="edit_identity_email_label">Email address</string>
<string name="edit_identity_email_hint">(Required)</string>
<string name="edit_identity_signature_label">Signature</string>
<string name="edit_identity_signature_hint">(Optional)</string>
<string name="account_settings_signature_label">Signature</string> <string name="account_settings_signature_label">Signature</string>
<string name="account_settings_signature_summary">Append a signature to every message you send</string> <string name="account_settings_signature_summary">Append a signature to every message you send</string>
<string name="default_signature">--\nSent from my Android phone with K-9. Please excuse my brevity.</string>
<string name="default_identity_description">Initial identity</string>
<string name="choose_identity">Choose identity</string>
<string name="choose_identity_title">Choose identity</string>
<string name="no_identities">Go to Account Settings -&gt; Manage Identities to create identities</string>
<string name="no_removable_identity">Cannot remove only identity</string>
<string name="identity_has_no_email">Cannot choose an identity which has no email address</string>
<string name="identity_will_not_be_saved">Identity choice and signature edits will not be saved with a draft</string>
<string name="sort_earliest_first">Earliest messages first</string> <string name="sort_earliest_first">Earliest messages first</string>
<string name="sort_latest_first">Latest messages first</string> <string name="sort_latest_first">Latest messages first</string>
<string name="sort_sender_alpha">Sender alphabetical</string> <string name="sort_sender_alpha">Sender alphabetical</string>

View File

@ -98,6 +98,10 @@
android:key="composition" android:key="composition"
android:title="@string/account_settings_composition_label" /> android:title="@string/account_settings_composition_label" />
<PreferenceScreen
android:key="manage_identities"
android:title="@string/account_settings_identities_label" />
</PreferenceCategory> </PreferenceCategory>

View File

@ -2,7 +2,9 @@
package com.android.email; package com.android.email;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import com.android.email.mail.Address; import com.android.email.mail.Address;
@ -35,9 +37,6 @@ public class Account implements Serializable {
String mLocalStoreUri; String mLocalStoreUri;
String mTransportUri; String mTransportUri;
String mDescription; String mDescription;
String mName;
String mEmail;
String mSignature;
String mAlwaysBcc; String mAlwaysBcc;
int mAutomaticCheckIntervalMinutes; int mAutomaticCheckIntervalMinutes;
int mDisplayCount; int mDisplayCount;
@ -57,6 +56,7 @@ public class Account implements Serializable {
boolean mNotifySync; boolean mNotifySync;
HideButtons mHideMessageViewButtons; HideButtons mHideMessageViewButtons;
boolean mIsSignatureBeforeQuotedText; boolean mIsSignatureBeforeQuotedText;
List<Identity> identities;
public enum FolderMode { public enum FolderMode {
ALL, FIRST_CLASS, FIRST_AND_SECOND_CLASS, NOT_SECOND_CLASS; ALL, FIRST_CLASS, FIRST_AND_SECOND_CLASS, NOT_SECOND_CLASS;
@ -84,7 +84,6 @@ public class Account implements Serializable {
mAccountNumber = -1; mAccountNumber = -1;
mNotifyNewMail = true; mNotifyNewMail = true;
mNotifySync = true; mNotifySync = true;
mSignature = "Sent from my Android phone with K-9. Please excuse my brevity.";
mVibrate = false; mVibrate = false;
mFolderDisplayMode = FolderMode.NOT_SECOND_CLASS; mFolderDisplayMode = FolderMode.NOT_SECOND_CLASS;
mFolderSyncMode = FolderMode.FIRST_CLASS; mFolderSyncMode = FolderMode.FIRST_CLASS;
@ -92,6 +91,57 @@ public class Account implements Serializable {
mHideMessageViewButtons = HideButtons.NEVER; mHideMessageViewButtons = HideButtons.NEVER;
mRingtoneUri = "content://settings/system/notification_sound"; mRingtoneUri = "content://settings/system/notification_sound";
mIsSignatureBeforeQuotedText = false; mIsSignatureBeforeQuotedText = false;
identities = new ArrayList<Identity>();
Identity identity = new Identity();
identity.setSignature(context.getString(R.string.default_signature));
identity.setDescription(context.getString(R.string.default_identity_description));
identities.add(identity);
}
public class Identity implements Serializable
{
String mDescription;
String mName;
String mEmail;
String mSignature;
public String getName()
{
return mName;
}
public void setName(String name)
{
mName = name;
}
public String getEmail()
{
return mEmail;
}
public void setEmail(String email)
{
mEmail = email;
}
public String getSignature()
{
return mSignature;
}
public void setSignature(String signature)
{
mSignature = signature;
}
public String getDescription()
{
return mDescription;
}
public void setDescription(String description)
{
mDescription = description;
}
public String toString()
{
return "Account.Identity(description=" + mDescription + ", name=" + mName + ", email=" + mEmail + ", signature=" + mSignature;
}
} }
Account(Preferences preferences, String uuid) { Account(Preferences preferences, String uuid) {
@ -110,9 +160,6 @@ public class Account implements Serializable {
+ ".transportUri", null)); + ".transportUri", null));
mDescription = preferences.getPreferences().getString(mUuid + ".description", null); mDescription = preferences.getPreferences().getString(mUuid + ".description", null);
mAlwaysBcc = preferences.getPreferences().getString(mUuid + ".alwaysBcc", mAlwaysBcc); mAlwaysBcc = preferences.getPreferences().getString(mUuid + ".alwaysBcc", mAlwaysBcc);
mName = preferences.getPreferences().getString(mUuid + ".name", mName);
mEmail = preferences.getPreferences().getString(mUuid + ".email", mEmail);
mSignature = preferences.getPreferences().getString(mUuid + ".signature", mSignature);
mAutomaticCheckIntervalMinutes = preferences.getPreferences().getInt(mUuid mAutomaticCheckIntervalMinutes = preferences.getPreferences().getInt(mUuid
+ ".automaticCheckIntervalMinutes", -1); + ".automaticCheckIntervalMinutes", -1);
mDisplayCount = preferences.getPreferences().getInt(mUuid + ".displayCount", -1); mDisplayCount = preferences.getPreferences().getInt(mUuid + ".displayCount", -1);
@ -202,6 +249,93 @@ public class Account implements Serializable {
} }
mIsSignatureBeforeQuotedText = preferences.getPreferences().getBoolean(mUuid + ".signatureBeforeQuotedText", false); mIsSignatureBeforeQuotedText = preferences.getPreferences().getBoolean(mUuid + ".signatureBeforeQuotedText", false);
identities = loadIdentities(preferences.getPreferences());
}
private List<Identity> loadIdentities(SharedPreferences prefs)
{
List<Identity> newIdentities = new ArrayList<Identity>();
int ident = 0;
boolean gotOne = false;
do
{
gotOne = false;
String name = prefs.getString(mUuid + ".name." + ident, null);
String email = prefs.getString(mUuid + ".email." + ident, null);
String signature = prefs.getString(mUuid + ".signature." + ident, null);
String description = prefs.getString(mUuid + ".description." + ident, null);
if (email != null)
{
Identity identity = new Identity();
identity.setName(name);
identity.setEmail(email);
identity.setSignature(signature);
identity.setDescription(description);
newIdentities.add(identity);
gotOne = true;
}
ident++;
} while (gotOne);
if (newIdentities.size() == 0)
{
String name = prefs.getString(mUuid + ".name", null);
String email = prefs.getString(mUuid + ".email", null);
String signature = prefs.getString(mUuid + ".signature", null);
Identity identity = new Identity();
identity.setName(name);
identity.setEmail(email);
identity.setSignature(signature);
identity.setDescription(email);
newIdentities.add(identity);
}
return newIdentities;
}
private void deleteIdentities(SharedPreferences prefs, SharedPreferences.Editor editor)
{
int ident = 0;
boolean gotOne = false;
do
{
gotOne = false;
String email = prefs.getString(mUuid + ".email." + ident, null);
if (email != null)
{
editor.remove(mUuid + ".name." + ident);
editor.remove(mUuid + ".email." + ident);
editor.remove(mUuid + ".signature." + ident);
editor.remove(mUuid + ".description." + ident);
gotOne = true;
}
ident++;
} while (gotOne);
}
private void saveIdentities(SharedPreferences prefs, SharedPreferences.Editor editor)
{
deleteIdentities(prefs, editor);
int ident = 0;
for (Identity identity : identities)
{
editor.putString(mUuid + ".name." + ident, identity.getName());
editor.putString(mUuid + ".email." + ident, identity.getEmail());
editor.putString(mUuid + ".signature." + ident, identity.getSignature());
editor.putString(mUuid + ".description." + ident, identity.getDescription());
ident++;
}
}
public List<Identity> getIdentities()
{
return identities;
}
public void setIdentities(List<Identity> newIdentities)
{
identities = newIdentities;
} }
public String getUuid() { public String getUuid() {
@ -233,27 +367,27 @@ public class Account implements Serializable {
} }
public String getName() { public String getName() {
return mName; return identities.get(0).getName();
} }
public void setName(String name) { public void setName(String name) {
this.mName = name; identities.get(0).setName(name);
} }
public String getSignature() { public String getSignature() {
return mSignature; return identities.get(0).getSignature();
} }
public void setSignature(String signature) { public void setSignature(String signature) {
this.mSignature = signature; identities.get(0).setSignature(signature);
} }
public String getEmail() { public String getEmail() {
return mEmail; return identities.get(0).getEmail();
} }
public void setEmail(String email) { public void setEmail(String email) {
this.mEmail = email; identities.get(0).setEmail(email);
} }
public String getAlwaysBcc() { public String getAlwaysBcc() {
@ -264,6 +398,14 @@ public class Account implements Serializable {
this.mAlwaysBcc = alwaysBcc; this.mAlwaysBcc = alwaysBcc;
} }
public Identity getIdentity(int i)
{
if (i < identities.size())
{
return identities.get(i);
}
return null;
}
public boolean isVibrate() { public boolean isVibrate() {
return mVibrate; return mVibrate;
@ -321,6 +463,7 @@ public class Account implements Serializable {
editor.remove(mUuid + ".folderTargetMode"); editor.remove(mUuid + ".folderTargetMode");
editor.remove(mUuid + ".hideButtonsEnum"); editor.remove(mUuid + ".hideButtonsEnum");
editor.remove(mUuid + ".signatureBeforeQuotedText"); editor.remove(mUuid + ".signatureBeforeQuotedText");
deleteIdentities(preferences.getPreferences(), editor);
editor.commit(); editor.commit();
} }
@ -362,9 +505,6 @@ public class Account implements Serializable {
editor.putString(mUuid + ".localStoreUri", mLocalStoreUri); editor.putString(mUuid + ".localStoreUri", mLocalStoreUri);
editor.putString(mUuid + ".transportUri", Utility.base64Encode(mTransportUri)); editor.putString(mUuid + ".transportUri", Utility.base64Encode(mTransportUri));
editor.putString(mUuid + ".description", mDescription); editor.putString(mUuid + ".description", mDescription);
editor.putString(mUuid + ".name", mName);
editor.putString(mUuid + ".email", mEmail);
editor.putString(mUuid + ".signature", mSignature);
editor.putString(mUuid + ".alwaysBcc", mAlwaysBcc); editor.putString(mUuid + ".alwaysBcc", mAlwaysBcc);
editor.putInt(mUuid + ".automaticCheckIntervalMinutes", mAutomaticCheckIntervalMinutes); editor.putInt(mUuid + ".automaticCheckIntervalMinutes", mAutomaticCheckIntervalMinutes);
editor.putInt(mUuid + ".displayCount", mDisplayCount); editor.putInt(mUuid + ".displayCount", mDisplayCount);
@ -386,6 +526,8 @@ public class Account implements Serializable {
editor.putString(mUuid + ".folderTargetMode", mFolderTargetMode.name()); editor.putString(mUuid + ".folderTargetMode", mFolderTargetMode.name());
editor.putBoolean(mUuid + ".signatureBeforeQuotedText", this.mIsSignatureBeforeQuotedText); editor.putBoolean(mUuid + ".signatureBeforeQuotedText", this.mIsSignatureBeforeQuotedText);
saveIdentities(preferences.getPreferences(), editor);
editor.commit(); editor.commit();
} }
@ -455,10 +597,17 @@ public class Account implements Serializable {
} }
// TODO: When there are multiple identities, this method should try all of them
public boolean isAnIdentity(Address addr) public boolean isAnIdentity(Address addr)
{ {
return getEmail().equals(addr.getAddress()); for (Identity identity : identities)
{
String email = identity.getEmail();
if (email != null && email.equalsIgnoreCase(addr.getAddress()))
{
return true;
}
}
return false;
} }
public int getDisplayCount() { public int getDisplayCount() {

View File

@ -99,14 +99,12 @@ public class Email extends Application {
*/ */
public static final String FOLDER_NONE = "-NONE-"; public static final String FOLDER_NONE = "-NONE-";
public static final String LOCAL_UID_PREFIX = "K9LOCAL:";
// The next time the LocalStore.java DB_VERSION is incremented, please delete the current
// LOCAL_UID_PREFIX and this comment, and uncomment the K9LOCAL: version of this static string
public static final String LOCAL_UID_PREFIX = "Local";
//public static final String LOCAL_UID_PREFIX = "K9LOCAL:";
public static final String REMOTE_UID_PREFIX = "K9REMOTE:"; public static final String REMOTE_UID_PREFIX = "K9REMOTE:";
public static final String K9MAIL_IDENTITY = "X-K9mail-Identity";
/** /**
* Specifies how many messages will be shown in a folder by default. This number is set * Specifies how many messages will be shown in a folder by default. This number is set
* on each new folder and can be incremented with "Load more messages..." by the * on each new folder and can be incremented with "Load more messages..." by the

View File

@ -0,0 +1,138 @@
package com.android.email.activity;
import java.util.List;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.android.email.Account;
import com.android.email.Preferences;
import com.android.email.R;
public class ChooseIdentity extends ListActivity
{
Account mAccount;
String mUID;
ArrayAdapter<String> adapter;
private ChooseIdentityHandler mHandler = new ChooseIdentityHandler();
public static final String EXTRA_ACCOUNT = "com.android.email.ChooseIdentity_account";
public static final String EXTRA_IDENTITY = "com.android.email.ChooseIdentity_identity";
protected List<Account.Identity> identities = null;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
getListView().setTextFilterEnabled(true);
getListView().setItemsCanFocus(false);
getListView().setChoiceMode(ListView.CHOICE_MODE_NONE);
Intent intent = getIntent();
mAccount = (Account) intent.getSerializableExtra(EXTRA_ACCOUNT);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
setListAdapter(adapter);
setupClickListeners();
}
@Override
public void onResume()
{
super.onResume();
refreshView();
}
protected void refreshView()
{
adapter.clear();
identities = mAccount.getIdentities();
for (Account.Identity identity : identities)
{
String email = identity.getEmail();
String description = identity.getDescription();
if (description == null || description.trim().length() == 0)
{
description = getString(R.string.message_view_from_format, identity.getName(), identity.getEmail());
}
adapter.add(description);
}
}
protected void setupClickListeners()
{
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView adapterview, View view, int i, long l)
{
Account.Identity identity = mAccount.getIdentity(i);
String email = identity.getEmail();
if (email != null && email.trim().equals("") == false)
{
Intent intent = new Intent();
intent.putExtra(EXTRA_IDENTITY, mAccount.getIdentity(i));
setResult(RESULT_OK, intent);
finish();
}
else
{
Toast.makeText(ChooseIdentity.this, getString(R.string.identity_has_no_email),
Toast.LENGTH_LONG).show();
}
}
});
}
class ChooseIdentityHandler extends Handler
{
private static final int MSG_PROGRESS = 2;
private static final int MSG_DATA_CHANGED = 3;
public void handleMessage(android.os.Message msg)
{
switch (msg.what)
{
case MSG_PROGRESS:
setProgressBarIndeterminateVisibility(msg.arg1 != 0);
break;
case MSG_DATA_CHANGED:
adapter.notifyDataSetChanged();
break;
}
}
public void progress(boolean progress)
{
android.os.Message msg = new android.os.Message();
msg.what = MSG_PROGRESS;
msg.arg1 = progress ? 1 : 0;
sendMessage(msg);
}
public void dataChanged()
{
sendEmptyMessage(MSG_DATA_CHANGED);
}
}
}

View File

@ -0,0 +1,120 @@
package com.android.email.activity;
import java.util.List;
import com.android.email.Account;
import com.android.email.Preferences;
import com.android.email.R;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
import android.widget.EditText;
public class EditIdentity extends Activity
{
public static final String EXTRA_IDENTITY = "com.android.email.EditIdentity_identity";
public static final String EXTRA_IDENTITY_INDEX = "com.android.email.EditIdentity_identity_index";
public static final String EXTRA_ACCOUNT = "com.android.email.EditIdentity_account";
private Account mAccount;
private Account.Identity mIdentity;
private int mIdentityIndex;
private EditText mDescriptionView;
private EditText mSignatureView;
private EditText mEmailView;
// private EditText mAlwaysBccView;
private EditText mNameView;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mIdentity = (Account.Identity)getIntent().getSerializableExtra(EXTRA_IDENTITY);
mIdentityIndex = getIntent().getIntExtra(EXTRA_IDENTITY_INDEX, -1);
mAccount = (Account) getIntent().getSerializableExtra(EXTRA_ACCOUNT);
if (mIdentityIndex == -1)
{
mIdentity = mAccount.new Identity();
}
setContentView(R.layout.edit_identity);
/*
* If we're being reloaded we override the original account with the one
* we saved
*/
if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_IDENTITY))
{
mIdentity = (Account.Identity)savedInstanceState.getSerializable(EXTRA_IDENTITY);
}
mDescriptionView = (EditText)findViewById(R.id.description);
mDescriptionView.setText(mIdentity.getDescription());
mNameView = (EditText)findViewById(R.id.name);
mNameView.setText(mIdentity.getName());
mEmailView = (EditText)findViewById(R.id.email);
mEmailView.setText(mIdentity.getEmail());
// mAccountAlwaysBcc = (EditText)findViewById(R.id.bcc);
// mAccountAlwaysBcc.setText(mIdentity.getAlwaysBcc());
mSignatureView = (EditText)findViewById(R.id.signature);
mSignatureView.setText(mIdentity.getSignature());
}
@Override
public void onResume()
{
super.onResume();
}
private void saveIdentity()
{
mIdentity.setDescription(mDescriptionView.getText().toString());
mIdentity.setEmail(mEmailView.getText().toString());
// mIdentity.setAlwaysBcc(mAccountAlwaysBcc.getText().toString());
mIdentity.setName(mNameView.getText().toString());
mIdentity.setSignature(mSignatureView.getText().toString());
List<Account.Identity> identities = mAccount.getIdentities();
if (mIdentityIndex == -1)
{
identities.add(mIdentity);
}
else
{
identities.remove(mIdentityIndex);
identities.add(mIdentityIndex, mIdentity);
}
mAccount.save(Preferences.getPreferences(getApplication().getApplicationContext()));
finish();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
saveIdentity();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable(EXTRA_IDENTITY, mIdentity);
}
}

View File

@ -0,0 +1,161 @@
package com.android.email.activity;
import android.content.Intent;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import com.android.email.Account;
import com.android.email.Preferences;
import com.android.email.R;
public class ManageIdentities extends ChooseIdentity
{
private boolean mIdentitiesChanged = false;
public static final String EXTRA_IDENTITIES = "com.android.email.EditIdentity_identities";
private static final int ACTIVITY_EDIT_IDENTITY = 1;
protected void setupClickListeners()
{
this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView adapterview, View view, int i, long l)
{
editItem(i);
}
});
ListView listView = getListView();
registerForContextMenu(listView);
}
private void editItem(int i)
{
Intent intent = new Intent(ManageIdentities.this, EditIdentity.class);
intent.putExtra(EditIdentity.EXTRA_ACCOUNT, mAccount);
intent.putExtra(EditIdentity.EXTRA_IDENTITY, mAccount.getIdentity(i));
intent.putExtra(EditIdentity.EXTRA_IDENTITY_INDEX, i);
startActivityForResult(intent, ACTIVITY_EDIT_IDENTITY);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.manage_identities_option, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.new_identity:
Intent intent = new Intent(ManageIdentities.this, EditIdentity.class);
intent.putExtra(EditIdentity.EXTRA_ACCOUNT, mAccount);
startActivityForResult(intent, ACTIVITY_EDIT_IDENTITY);
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
{
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle(R.string.manage_identities_context_menu_title);
getMenuInflater().inflate(R.menu.manage_identities_context, menu);
}
public boolean onContextItemSelected(MenuItem item)
{
AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo)item.getMenuInfo();
switch (item.getItemId())
{
case R.id.edit:
editItem(menuInfo.position);
break;
case R.id.up:
if (menuInfo.position > 0)
{
Account.Identity identity = identities.remove(menuInfo.position);
identities.add(menuInfo.position - 1, identity);
mIdentitiesChanged = true;
refreshView();
}
break;
case R.id.down:
if (menuInfo.position < identities.size() - 1)
{
Account.Identity identity = identities.remove(menuInfo.position);
identities.add(menuInfo.position + 1, identity);
mIdentitiesChanged = true;
refreshView();
}
break;
case R.id.top:
Account.Identity identity = identities.remove(menuInfo.position);
identities.add(0, identity);
mIdentitiesChanged = true;
refreshView();
break;
case R.id.remove:
if (identities.size() > 1)
{
identities.remove(menuInfo.position);
mIdentitiesChanged = true;
refreshView();
}
else
{
Toast.makeText(this, getString(R.string.no_removable_identity),
Toast.LENGTH_LONG).show();
}
break;
}
return true;
}
@Override
public void onResume()
{
super.onResume();
mAccount.refresh(Preferences.getPreferences(getApplication().getApplicationContext()));
refreshView();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
saveIdentities();
}
return super.onKeyDown(keyCode, event);
}
private void saveIdentities()
{
if (mIdentitiesChanged)
{
mAccount.setIdentities(identities);
mAccount.save(Preferences.getPreferences(getApplication().getApplicationContext()));
}
finish();
}
}

View File

@ -4,6 +4,7 @@ package com.android.email.activity;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.StringTokenizer;
import com.android.email.K9Activity; import com.android.email.K9Activity;
import android.content.ContentResolver; import android.content.ContentResolver;
@ -68,6 +69,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private static final String ACTION_FORWARD = "com.android.email.intent.action.FORWARD"; private static final String ACTION_FORWARD = "com.android.email.intent.action.FORWARD";
private static final String ACTION_EDIT_DRAFT = "com.android.email.intent.action.EDIT_DRAFT"; private static final String ACTION_EDIT_DRAFT = "com.android.email.intent.action.EDIT_DRAFT";
private static final String EXTRA_ACCOUNT = "account"; private static final String EXTRA_ACCOUNT = "account";
private static final String EXTRA_FOLDER = "folder"; private static final String EXTRA_FOLDER = "folder";
private static final String EXTRA_MESSAGE = "message"; private static final String EXTRA_MESSAGE = "message";
@ -84,6 +86,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
"com.android.email.activity.MessageCompose.stateKeySourceMessageProced"; "com.android.email.activity.MessageCompose.stateKeySourceMessageProced";
private static final String STATE_KEY_DRAFT_UID = private static final String STATE_KEY_DRAFT_UID =
"com.android.email.activity.MessageCompose.draftUid"; "com.android.email.activity.MessageCompose.draftUid";
private static final String STATE_IDENTITY_CHANGED =
"com.android.email.activity.MessageCompose.identityChanged";
private static final String STATE_IDENTITY =
"com.android.email.activity.MessageCompose.identity";
private static final int MSG_PROGRESS_ON = 1; private static final int MSG_PROGRESS_ON = 1;
private static final int MSG_PROGRESS_OFF = 2; private static final int MSG_PROGRESS_OFF = 2;
@ -93,8 +99,12 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
private static final int MSG_DISCARDED_DRAFT = 6; private static final int MSG_DISCARDED_DRAFT = 6;
private static final int ACTIVITY_REQUEST_PICK_ATTACHMENT = 1; private static final int ACTIVITY_REQUEST_PICK_ATTACHMENT = 1;
private static final int ACTIVITY_CHOOSE_IDENTITY = 2;
private Account mAccount; private Account mAccount;
private Account.Identity mIdentity;
private boolean mIdentityChanged = false;
private boolean mSignatureChanged = false;
private String mFolder; private String mFolder;
private String mSourceMessageUid; private String mSourceMessageUid;
private Message mSourceMessage; private Message mSourceMessage;
@ -105,18 +115,18 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
*/ */
private boolean mSourceMessageProcessed = false; private boolean mSourceMessageProcessed = false;
private TextView mFromView;
private MultiAutoCompleteTextView mToView; private MultiAutoCompleteTextView mToView;
private MultiAutoCompleteTextView mCcView; private MultiAutoCompleteTextView mCcView;
private MultiAutoCompleteTextView mBccView; private MultiAutoCompleteTextView mBccView;
private EditText mSubjectView; private EditText mSubjectView;
private EditText mSignatureView;
private EditText mMessageContentView; private EditText mMessageContentView;
private Button mSendButton;
private Button mDiscardButton;
private Button mSaveButton;
private LinearLayout mAttachments; private LinearLayout mAttachments;
private View mQuotedTextBar; private View mQuotedTextBar;
private ImageButton mQuotedTextDelete; private ImageButton mQuotedTextDelete;
private WebView mQuotedText; private EditText mQuotedText;
private boolean mDraftNeedsSaving = false; private boolean mDraftNeedsSaving = false;
@ -258,15 +268,22 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mAddressAdapter = new EmailAddressAdapter(this); mAddressAdapter = new EmailAddressAdapter(this);
mAddressValidator = new EmailAddressValidator(); mAddressValidator = new EmailAddressValidator();
mFromView = (TextView)findViewById(R.id.from);
mToView = (MultiAutoCompleteTextView)findViewById(R.id.to); mToView = (MultiAutoCompleteTextView)findViewById(R.id.to);
mCcView = (MultiAutoCompleteTextView)findViewById(R.id.cc); mCcView = (MultiAutoCompleteTextView)findViewById(R.id.cc);
mBccView = (MultiAutoCompleteTextView)findViewById(R.id.bcc); mBccView = (MultiAutoCompleteTextView)findViewById(R.id.bcc);
mSubjectView = (EditText)findViewById(R.id.subject); mSubjectView = (EditText)findViewById(R.id.subject);
EditText upperSignature = (EditText)findViewById(R.id.upper_signature);
EditText lowerSignature = (EditText)findViewById(R.id.lower_signature);
mMessageContentView = (EditText)findViewById(R.id.message_content); mMessageContentView = (EditText)findViewById(R.id.message_content);
mAttachments = (LinearLayout)findViewById(R.id.attachments); mAttachments = (LinearLayout)findViewById(R.id.attachments);
mQuotedTextBar = findViewById(R.id.quoted_text_bar); mQuotedTextBar = findViewById(R.id.quoted_text_bar);
mQuotedTextDelete = (ImageButton)findViewById(R.id.quoted_text_delete); mQuotedTextDelete = (ImageButton)findViewById(R.id.quoted_text_delete);
mQuotedText = (WebView)findViewById(R.id.quoted_text); mQuotedText = (EditText)findViewById(R.id.quoted_text);
TextWatcher watcher = new TextWatcher() { TextWatcher watcher = new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, public void beforeTextChanged(CharSequence s, int start,
@ -280,10 +297,24 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
public void afterTextChanged(android.text.Editable s) { } public void afterTextChanged(android.text.Editable s) { }
}; };
TextWatcher sigwatcher = new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start,
int before, int after) { }
public void onTextChanged(CharSequence s, int start,
int before, int count) {
mDraftNeedsSaving = true;
mSignatureChanged = true;
}
public void afterTextChanged(android.text.Editable s) { }
};
mToView.addTextChangedListener(watcher); mToView.addTextChangedListener(watcher);
mCcView.addTextChangedListener(watcher); mCcView.addTextChangedListener(watcher);
mBccView.addTextChangedListener(watcher); mBccView.addTextChangedListener(watcher);
mSubjectView.addTextChangedListener(watcher); mSubjectView.addTextChangedListener(watcher);
mMessageContentView.addTextChangedListener(watcher); mMessageContentView.addTextChangedListener(watcher);
/* /*
@ -295,6 +326,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mQuotedTextDelete.setOnClickListener(this); mQuotedTextDelete.setOnClickListener(this);
mFromView.setVisibility(View.GONE);
mToView.setAdapter(mAddressAdapter); mToView.setAdapter(mAddressAdapter);
mToView.setTokenizer(new Rfc822Tokenizer()); mToView.setTokenizer(new Rfc822Tokenizer());
mToView.setValidator(mAddressValidator); mToView.setValidator(mAddressValidator);
@ -447,6 +480,26 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mSourceMessageUid = (String) intent.getStringExtra(EXTRA_MESSAGE); mSourceMessageUid = (String) intent.getStringExtra(EXTRA_MESSAGE);
} }
if (mIdentity == null)
{
mIdentity = mAccount.getIdentity(0);
}
if (mAccount.isSignatureBeforeQuotedText())
{
mSignatureView = upperSignature;
lowerSignature.setVisibility(View.GONE);
}
else
{
mSignatureView = lowerSignature;
upperSignature.setVisibility(View.GONE);
}
mSignatureView.addTextChangedListener(sigwatcher);
updateFrom();
updateSignature();
Log.d(Email.LOG_TAG, "action = " + action + ", mAccount = " + mAccount + ", mFolder = " + mFolder + ", mSourceMessageUid = " + mSourceMessageUid); Log.d(Email.LOG_TAG, "action = " + action + ", mAccount = " + mAccount + ", mFolder = " + mFolder + ", mSourceMessageUid = " + mSourceMessageUid);
if ((ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action)) && mAccount != null && mFolder != null && mSourceMessageUid != null) { if ((ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action)) && mAccount != null && mFolder != null && mSourceMessageUid != null) {
Log.d(Email.LOG_TAG, "Setting message ANSWERED flag to true"); Log.d(Email.LOG_TAG, "Setting message ANSWERED flag to true");
@ -471,12 +524,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
} }
if (!ACTION_EDIT_DRAFT.equals(action)) { if (!ACTION_EDIT_DRAFT.equals(action)) {
if (mAccount.isSignatureBeforeQuotedText()) {
String signature = getSignature();
if (signature!=null) {
mMessageContentView.setText(signature);
}
}
addAddress(mBccView, new Address(mAccount.getAlwaysBcc(), "")); addAddress(mBccView, new Address(mAccount.getAlwaysBcc(), ""));
} }
@ -518,6 +565,8 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
outState.putBoolean(STATE_KEY_QUOTED_TEXT_SHOWN, mQuotedTextBar.getVisibility() == View.VISIBLE); outState.putBoolean(STATE_KEY_QUOTED_TEXT_SHOWN, mQuotedTextBar.getVisibility() == View.VISIBLE);
outState.putBoolean(STATE_KEY_SOURCE_MESSAGE_PROCED, mSourceMessageProcessed); outState.putBoolean(STATE_KEY_SOURCE_MESSAGE_PROCED, mSourceMessageProcessed);
outState.putString(STATE_KEY_DRAFT_UID, mDraftUid); outState.putString(STATE_KEY_DRAFT_UID, mDraftUid);
outState.putSerializable(STATE_IDENTITY, mIdentity);
outState.putBoolean(STATE_IDENTITY_CHANGED, mIdentityChanged);
} }
@Override @Override
@ -535,6 +584,11 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mQuotedTextBar.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? View.VISIBLE : View.GONE); mQuotedTextBar.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? View.VISIBLE : View.GONE);
mQuotedText.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? View.VISIBLE : View.GONE); mQuotedText.setVisibility(savedInstanceState.getBoolean(STATE_KEY_QUOTED_TEXT_SHOWN) ? View.VISIBLE : View.GONE);
mDraftUid = savedInstanceState.getString(STATE_KEY_DRAFT_UID); mDraftUid = savedInstanceState.getString(STATE_KEY_DRAFT_UID);
mIdentity = (Account.Identity)savedInstanceState.getSerializable(STATE_IDENTITY);
mIdentityChanged = savedInstanceState.getBoolean(STATE_IDENTITY_CHANGED);
updateFrom();
updateSignature();
mDraftNeedsSaving = false; mDraftNeedsSaving = false;
} }
@ -570,10 +624,10 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
return addresses; return addresses;
} }
private MimeMessage createMessage() throws MessagingException { private MimeMessage createMessage(boolean appendSig) throws MessagingException {
MimeMessage message = new MimeMessage(); MimeMessage message = new MimeMessage();
message.setSentDate(new Date()); message.setSentDate(new Date());
Address from = new Address(mAccount.getEmail(), mAccount.getName()); Address from = new Address(mIdentity.getEmail(), mIdentity.getName());
message.setFrom(from); message.setFrom(from);
message.setRecipients(RecipientType.TO, getAddresses(mToView)); message.setRecipients(RecipientType.TO, getAddresses(mToView));
message.setRecipients(RecipientType.CC, getAddresses(mCcView)); message.setRecipients(RecipientType.CC, getAddresses(mCcView));
@ -582,48 +636,24 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
// XXX TODO - not sure why this won't add header // XXX TODO - not sure why this won't add header
// message.setHeader("X-User-Agent", getString(R.string.message_header_mua)); // message.setHeader("X-User-Agent", getString(R.string.message_header_mua));
/* /*
* Build the Body that will contain the text of the message. We'll decide where to * Build the Body that will contain the text of the message. We'll decide where to
* include it later. * include it later.
*/ */
String text = mMessageContentView.getText().toString(); String text = mMessageContentView.getText().toString();
if (appendSig && mAccount.isSignatureBeforeQuotedText()) {
text = appendSignature(text);
}
String action = getIntent().getAction();
if (mQuotedTextBar.getVisibility() == View.VISIBLE) { if (mQuotedTextBar.getVisibility() == View.VISIBLE) {
String quotedText = null; text += "\n" + mQuotedText.getText().toString();
Part part = MimeUtility.findFirstPartByMimeType(mSourceMessage, "text/plain");
if (part != null) {
quotedText = MimeUtility.getTextFromPart(part);
}
if (ACTION_REPLY.equals(action) || ACTION_REPLY_ALL.equals(action)) {
text += String.format( getString(R.string.message_compose_reply_header_fmt), Address.toString(mSourceMessage.getFrom()));
if (quotedText != null) {
text += quotedText.replaceAll("(?m)^", ">");
}
}
else if (ACTION_FORWARD.equals(action)) {
text += String.format(
getString(R.string.message_compose_fwd_header_fmt),
mSourceMessage.getSubject(),
Address.toString(mSourceMessage.getFrom()),
Address.toString( mSourceMessage.getRecipients(RecipientType.TO)),
Address.toString( mSourceMessage.getRecipients(RecipientType.CC)));
if (quotedText != null) {
text += quotedText;
}
}
} }
if (!mAccount.isSignatureBeforeQuotedText()
&& !ACTION_EDIT_DRAFT.equals(action)) { if (appendSig && mAccount.isSignatureBeforeQuotedText() == false) {
String signature = getSignature(); text = appendSignature(text);
if (signature!=null) {
text += signature;
} }
}//if isSignatureBeforeQuotedText DRAFT
TextBody body = new TextBody(text); TextBody body = new TextBody(text);
@ -660,18 +690,15 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
return message; return message;
} }
private String getSignature() { private String appendSignature (String text) {
String mSignature; String signature= mSignatureView.getText().toString();
mSignature = mAccount.getSignature();
if (mSignature != null && !mSignature.contentEquals("")) { if (signature != null && ! signature.contentEquals("")){
return "\n--\n" + mAccount.getSignature(); text += "\n" + signature;
}
else {
return null;
}
} }
return text;
}
private void sendOrSaveMessage(boolean save) { private void sendOrSaveMessage(boolean save) {
/* /*
@ -679,7 +706,7 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
*/ */
MimeMessage message; MimeMessage message;
try { try {
message = createMessage(); message = createMessage(!save); // Only append sig on save
} }
catch (MessagingException me) { catch (MessagingException me) {
Log.e(Email.LOG_TAG, "Failed to create new message for send or save.", me); Log.e(Email.LOG_TAG, "Failed to create new message for send or save.", me);
@ -700,6 +727,26 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
*/ */
message.setUid(mSourceMessageUid); message.setUid(mSourceMessageUid);
} }
String k9identity = Utility.base64Encode("" + mMessageContentView.getText().toString().length());
if (mIdentityChanged || mSignatureChanged)
{
String signature = mSignatureView.getText().toString();
k9identity += ":" + Utility.base64Encode(signature) ;
if (mIdentityChanged)
{
String name = mIdentity.getName();
String email = mIdentity.getEmail();
k9identity += ":" + Utility.base64Encode(name) + ":" + Utility.base64Encode(email);
}
}
Log.d(Email.LOG_TAG, "Saving identity: " + k9identity);
message.setHeader(Email.K9MAIL_IDENTITY, k9identity);
MessagingController.getInstance(getApplication()).saveDraft(mAccount, message); MessagingController.getInstance(getApplication()).saveDraft(mAccount, message);
mDraftUid = message.getUid(); mDraftUid = message.getUid();
@ -827,11 +874,50 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
@Override @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(resultCode != RESULT_OK)
return;
if (data == null) { if (data == null) {
return; return;
} }
switch(requestCode) {
case ACTIVITY_REQUEST_PICK_ATTACHMENT:
addAttachment(data.getData()); addAttachment(data.getData());
mDraftNeedsSaving = true; mDraftNeedsSaving = true;
break;
case ACTIVITY_CHOOSE_IDENTITY:
onIdentityChosen(data);
break;
}
}
private void onIdentityChosen(Intent intent)
{
Bundle bundle = intent.getExtras();;
mIdentity = (Account.Identity)bundle.getSerializable(ChooseIdentity.EXTRA_IDENTITY);
// if (mIdentityChanged == false)
// {
// Toast.makeText(this, getString(R.string.identity_will_not_be_saved),
// Toast.LENGTH_LONG).show();
// }
mIdentityChanged = true;
mDraftNeedsSaving = true;
updateFrom();
updateSignature();
}
private void updateFrom()
{
if (mIdentityChanged)
{
mFromView.setVisibility(View.VISIBLE);
}
mFromView.setText(getString(R.string.message_view_from_format, mIdentity.getName(), mIdentity.getEmail()));
}
private void updateSignature()
{
mSignatureView.setText(mIdentity.getSignature());
} }
public void onClick(View view) { public void onClick(View view) {
@ -870,15 +956,34 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
case R.id.add_attachment: case R.id.add_attachment:
onAddAttachment(); onAddAttachment();
break; break;
case R.id.choose_identity:
onChooseIdentity();
break;
default: default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
return true; return true;
} }
private void onChooseIdentity()
{
if (mAccount.getIdentities().size() > 1)
{
Intent intent = new Intent(this, ChooseIdentity.class);
intent.putExtra(ChooseIdentity.EXTRA_ACCOUNT, mAccount);
startActivityForResult(intent, ACTIVITY_CHOOSE_IDENTITY);
}
else
{
Toast.makeText(this, getString(R.string.no_identities),
Toast.LENGTH_LONG).show();
}
}
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.message_compose_option, menu); getMenuInflater().inflate(R.menu.message_compose_option, menu);
return true; return true;
} }
@ -942,9 +1047,24 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
else { else {
addAddresses(mToView, replyToAddresses = message.getFrom()); addAddresses(mToView, replyToAddresses = message.getFrom());
} }
Part part = MimeUtility.findFirstPartByMimeType(mSourceMessage,
"text/plain");
if (part != null) {
String quotedText = String.format(
getString(R.string.message_compose_reply_header_fmt),
Address.toString(mSourceMessage.getFrom()));
quotedText += MimeUtility.getTextFromPart(part).replaceAll("(?m)^", ">");
mQuotedText.setText(quotedText);
mQuotedTextBar.setVisibility(View.VISIBLE);
mQuotedText.setVisibility(View.VISIBLE);
}
if (ACTION_REPLY_ALL.equals(action)) { if (ACTION_REPLY_ALL.equals(action)) {
for (Address address : message.getRecipients(RecipientType.TO)) { for (Address address : message.getRecipients(RecipientType.TO)) {
if (!address.getAddress().equalsIgnoreCase(mAccount.getEmail())) { if (!mAccount.isAnIdentity(address)) {
addAddress(mToView, address); addAddress(mToView, address);
} }
} }
@ -957,19 +1077,6 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
mCcView.setVisibility(View.VISIBLE); mCcView.setVisibility(View.VISIBLE);
} }
} }
Part part = MimeUtility.findFirstPartByMimeType(message, "text/plain");
if (part == null) {
part = MimeUtility.findFirstPartByMimeType(message, "text/html");
}
if (part != null) {
String text = MimeUtility.getTextFromPart(part);
if (text != null) {
mQuotedTextBar.setVisibility(View.VISIBLE);
mQuotedText.setVisibility(View.VISIBLE);
mQuotedText.loadDataWithBaseURL("email://", text, part.getMimeType(), "utf-8", null);
}
}
} }
catch (MessagingException me) { catch (MessagingException me) {
/* /*
@ -986,17 +1093,26 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
else { else {
mSubjectView.setText(message.getSubject()); mSubjectView.setText(message.getSubject());
} }
Part part = MimeUtility.findFirstPartByMimeType(message, "text/plain"); Part part = MimeUtility.findFirstPartByMimeType(message, "text/plain");
if (part == null) { if (part == null) {
part = MimeUtility.findFirstPartByMimeType(message, "text/html"); part = MimeUtility.findFirstPartByMimeType(message, "text/html");
} }
if (part != null) { if (part != null) {
String text = MimeUtility.getTextFromPart(part); String quotedText = MimeUtility.getTextFromPart(part);
if (text != null) { if (quotedText != null) {
String text = String.format(
getString(R.string.message_compose_fwd_header_fmt),
mSourceMessage.getSubject(),
Address.toString(mSourceMessage.getFrom()),
Address.toString(
mSourceMessage.getRecipients(RecipientType.TO)),
Address.toString(
mSourceMessage.getRecipients(RecipientType.CC)));
text += quotedText;
mQuotedText.setText(text);
mQuotedTextBar.setVisibility(View.VISIBLE); mQuotedTextBar.setVisibility(View.VISIBLE);
mQuotedText.setVisibility(View.VISIBLE); mQuotedText.setVisibility(View.VISIBLE);
mQuotedText.loadDataWithBaseURL("email://", text, part.getMimeType(), "utf-8", null);
} }
} }
if (!mSourceMessageProcessed) { if (!mSourceMessageProcessed) {
@ -1024,13 +1140,106 @@ public class MessageCompose extends K9Activity implements OnClickListener, OnFoc
addAddresses(mBccView, message.getRecipients(RecipientType.BCC)); addAddresses(mBccView, message.getRecipients(RecipientType.BCC));
mBccView.setVisibility(View.VISIBLE); mBccView.setVisibility(View.VISIBLE);
} }
if (!mSourceMessageProcessed) {
loadAttachments(message, 0);
}
Integer bodyLength = null;
String[] k9identities = message.getHeader(Email.K9MAIL_IDENTITY);
if (k9identities != null && k9identities.length > 0)
{
String k9identity = k9identities[0];
if (k9identity != null)
{
Log.d(Email.LOG_TAG, "Got a saved identity: " + k9identity);
StringTokenizer tokens = new StringTokenizer(k9identity, ":", false);
String bodyLengthS = null;
String name = null;
String email = null;
String signature = null;
if (tokens.hasMoreTokens())
{
bodyLengthS = Utility.base64Decode(tokens.nextToken());
try
{
bodyLength = Integer.parseInt(bodyLengthS);
}
catch (Exception e)
{
Log.e(Email.LOG_TAG, "Unable to parse bodyLength '" + bodyLengthS + "'");
}
}
if (tokens.hasMoreTokens())
{
signature = Utility.base64Decode(tokens.nextToken());
}
if (tokens.hasMoreTokens())
{
name = Utility.base64Decode(tokens.nextToken());
}
if (tokens.hasMoreTokens())
{
email = Utility.base64Decode(tokens.nextToken());
}
Account.Identity newIdentity= mAccount.new Identity();
if (signature != null)
{
newIdentity.setSignature(signature);
mSignatureChanged = true;
}
else
{
newIdentity.setSignature(mIdentity.getSignature());
}
if (name != null)
{
newIdentity.setName(name);
mIdentityChanged = true;
}
else
{
newIdentity.setName(mIdentity.getName());
}
if (email != null)
{
newIdentity.setEmail(email);
mIdentityChanged = true;
}
else
{
newIdentity.setEmail(mIdentity.getEmail());
}
mIdentity = newIdentity;
updateSignature();
updateFrom();
}
}
Part part = MimeUtility.findFirstPartByMimeType(message, "text/plain"); Part part = MimeUtility.findFirstPartByMimeType(message, "text/plain");
if (part != null) { if (part != null) {
String text = MimeUtility.getTextFromPart(part); String text = MimeUtility.getTextFromPart(part);
if (bodyLength != null && bodyLength + 1 < text.length()) // + 1 to get rid of the newline we added when saving the draft
{
String bodyText = text.substring(0, bodyLength);
String quotedText = text.substring(bodyLength + 1, text.length());
mMessageContentView.setText(bodyText);
mQuotedText.setText(quotedText);
mQuotedTextBar.setVisibility(View.VISIBLE);
mQuotedText.setVisibility(View.VISIBLE);
}
else
{
mMessageContentView.setText(text); mMessageContentView.setText(text);
} }
if (!mSourceMessageProcessed) {
loadAttachments(message, 0);
} }
} }
catch (MessagingException me) { catch (MessagingException me) {

View File

@ -23,15 +23,20 @@ import com.android.email.Email;
import com.android.email.Preferences; import com.android.email.Preferences;
import com.android.email.R; import com.android.email.R;
import com.android.email.activity.ChooseFolder; import com.android.email.activity.ChooseFolder;
import com.android.email.activity.ChooseIdentity;
import com.android.email.activity.ManageIdentities;
public class AccountSettings extends K9PreferenceActivity { public class AccountSettings extends K9PreferenceActivity {
private static final String EXTRA_ACCOUNT = "account"; private static final String EXTRA_ACCOUNT = "account";
private static final int SELECT_AUTO_EXPAND_FOLDER = 1; private static final int SELECT_AUTO_EXPAND_FOLDER = 1;
private static final int ACTIVITY_MANAGE_IDENTITIES = 2;
private static final String PREFERENCE_TOP_CATERGORY = "account_settings"; private static final String PREFERENCE_TOP_CATERGORY = "account_settings";
private static final String PREFERENCE_DESCRIPTION = "account_description"; private static final String PREFERENCE_DESCRIPTION = "account_description";
private static final String PREFERENCE_COMPOSITION = "composition"; private static final String PREFERENCE_COMPOSITION = "composition";
private static final String PREFERENCE_MANAGE_IDENTITIES = "manage_identities";
private static final String PREFERENCE_FREQUENCY = "account_check_frequency"; private static final String PREFERENCE_FREQUENCY = "account_check_frequency";
private static final String PREFERENCE_DISPLAY_COUNT = "account_display_count"; private static final String PREFERENCE_DISPLAY_COUNT = "account_display_count";
private static final String PREFERENCE_DEFAULT = "account_default"; private static final String PREFERENCE_DEFAULT = "account_default";
@ -226,6 +231,14 @@ public class AccountSettings extends K9PreferenceActivity {
} }
}); });
findPreference(PREFERENCE_MANAGE_IDENTITIES).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
onManageIdentities();
return true;
}
});
findPreference(PREFERENCE_INCOMING).setOnPreferenceClickListener( findPreference(PREFERENCE_INCOMING).setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() { new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
@ -296,6 +309,12 @@ public class AccountSettings extends K9PreferenceActivity {
AccountSetupComposition.actionEditCompositionSettings(this, mAccount); AccountSetupComposition.actionEditCompositionSettings(this, mAccount);
} }
private void onManageIdentities() {
Intent intent = new Intent(this, ManageIdentities.class);
intent.putExtra(ChooseIdentity.EXTRA_ACCOUNT, mAccount);
startActivityForResult(intent, ACTIVITY_MANAGE_IDENTITIES);
}
private void onIncomingSettings() { private void onIncomingSettings() {
AccountSetupIncoming.actionEditIncomingSettings(this, mAccount); AccountSetupIncoming.actionEditIncomingSettings(this, mAccount);
} }

View File

@ -6,7 +6,9 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import com.android.email.Email;
import com.android.email.Utility; import com.android.email.Utility;
import com.android.email.mail.MessagingException; import com.android.email.mail.MessagingException;
@ -39,7 +41,7 @@ public class MimeHeader {
mFields.clear(); mFields.clear();
} }
public String getFirstHeader(String name) throws MessagingException { public String getFirstHeader(String name) {
String[] header = getHeader(name); String[] header = getHeader(name);
if (header == null) { if (header == null) {
return null; return null;
@ -47,11 +49,11 @@ public class MimeHeader {
return header[0]; return header[0];
} }
public void addHeader(String name, String value) throws MessagingException { public void addHeader(String name, String value) {
mFields.add(new Field(name, MimeUtility.foldAndEncode(value))); mFields.add(new Field(name, MimeUtility.foldAndEncode(value)));
} }
public void setHeader(String name, String value) throws MessagingException { public void setHeader(String name, String value) {
if (name == null || value == null) { if (name == null || value == null) {
return; return;
} }
@ -59,7 +61,16 @@ public class MimeHeader {
addHeader(name, value); addHeader(name, value);
} }
public String[] getHeader(String name) throws MessagingException { public List<String> getHeaderNames()
{
ArrayList<String> names = new ArrayList<String>();
for (Field field : mFields) {
names.add(field.name);
}
return names;
}
public String[] getHeader(String name) {
ArrayList<String> values = new ArrayList<String>(); ArrayList<String> values = new ArrayList<String>();
for (Field field : mFields) { for (Field field : mFields) {
if (field.name.equalsIgnoreCase(name)) { if (field.name.equalsIgnoreCase(name)) {
@ -72,7 +83,7 @@ public class MimeHeader {
return values.toArray(new String[] {}); return values.toArray(new String[] {});
} }
public void removeHeader(String name) throws MessagingException { public void removeHeader(String name) {
ArrayList<Field> removeFields = new ArrayList<Field>(); ArrayList<Field> removeFields = new ArrayList<Field>();
for (Field field : mFields) { for (Field field : mFields) {
if (field.name.equalsIgnoreCase(name)) { if (field.name.equalsIgnoreCase(name)) {

View File

@ -8,6 +8,7 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Stack; import java.util.Stack;
@ -43,20 +44,8 @@ public class MimeMessage extends Message {
protected int mSize; protected int mSize;
public MimeMessage() { public MimeMessage() {
setGeneratedMessageId();
}
public void setGeneratedMessageId () {
/*
* Every new messages gets a Message-ID
*/
try {
setHeader("Message-ID", generateMessageId()); setHeader("Message-ID", generateMessageId());
}
catch (MessagingException me) {
throw new RuntimeException("Unable to create MimeMessage", me);
}
} }
private String generateMessageId() { private String generateMessageId() {
@ -280,26 +269,31 @@ public class MimeMessage extends Message {
} }
} }
protected String getFirstHeader(String name) throws MessagingException { protected String getFirstHeader(String name) {
return mHeader.getFirstHeader(name); return mHeader.getFirstHeader(name);
} }
public void addHeader(String name, String value) throws MessagingException { public void addHeader(String name, String value) {
mHeader.addHeader(name, value); mHeader.addHeader(name, value);
} }
public void setHeader(String name, String value) throws MessagingException { public void setHeader(String name, String value) {
mHeader.setHeader(name, value); mHeader.setHeader(name, value);
} }
public String[] getHeader(String name) throws MessagingException { public String[] getHeader(String name) {
return mHeader.getHeader(name); return mHeader.getHeader(name);
} }
public void removeHeader(String name) throws MessagingException { public void removeHeader(String name) {
mHeader.removeHeader(name); mHeader.removeHeader(name);
} }
public List<String> getHeaderNames()
{
return mHeader.getHeaderNames();
}
public void writeTo(OutputStream out) throws IOException, MessagingException { public void writeTo(OutputStream out) throws IOException, MessagingException {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
mHeader.writeTo(out); mHeader.writeTo(out);

View File

@ -723,7 +723,8 @@ public class ImapStore extends Store {
if (fp.contains(FetchProfile.Item.ENVELOPE)) { if (fp.contains(FetchProfile.Item.ENVELOPE)) {
fetchFields.add("INTERNALDATE"); fetchFields.add("INTERNALDATE");
fetchFields.add("RFC822.SIZE"); fetchFields.add("RFC822.SIZE");
fetchFields.add("BODY.PEEK[HEADER.FIELDS (date subject from content-type to cc)]"); fetchFields.add("BODY.PEEK[HEADER.FIELDS (date subject from content-type to cc reply-to "
+ Email.K9MAIL_IDENTITY + ")]");
} }
if (fp.contains(FetchProfile.Item.STRUCTURE)) { if (fp.contains(FetchProfile.Item.STRUCTURE)) {
fetchFields.add("BODYSTRUCTURE"); fetchFields.add("BODYSTRUCTURE");

View File

@ -14,6 +14,11 @@ import java.net.URI;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import android.content.SharedPreferences; import android.content.SharedPreferences;
@ -62,10 +67,7 @@ import java.io.StringReader;
* </pre> * </pre>
*/ */
public class LocalStore extends Store implements Serializable { public class LocalStore extends Store implements Serializable {
// If you are going to change the DB_VERSION, please also go into Email.java and local for the comment private static final int DB_VERSION = 26;
// on LOCAL_UID_PREFIX and follow the instructions there. If you follow the instructions there,
// please delete this comment.
private static final int DB_VERSION = 25;
private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN }; private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED, Flag.X_DESTROYED, Flag.SEEN };
private String mPath; private String mPath;
@ -74,6 +76,12 @@ public class LocalStore extends Store implements Serializable {
private Application mApplication; private Application mApplication;
private String uUid = null; private String uUid = null;
private static Set<String> HEADERS_TO_SAVE = new HashSet<String>();
static
{
HEADERS_TO_SAVE.add(Email.K9MAIL_IDENTITY);
}
/** /**
* @param uri local://localhost/path/to/database/uuid.db * @param uri local://localhost/path/to/database/uuid.db
*/ */
@ -133,6 +141,10 @@ public class LocalStore extends Store implements Serializable {
+ "date INTEGER, flags TEXT, sender_list TEXT, to_list TEXT, cc_list TEXT, bcc_list TEXT, reply_to_list TEXT, " + "date INTEGER, flags TEXT, sender_list TEXT, to_list TEXT, cc_list TEXT, bcc_list TEXT, reply_to_list TEXT, "
+ "html_content TEXT, text_content TEXT, attachment_count INTEGER, internal_date INTEGER, message_id TEXT)"); + "html_content TEXT, text_content TEXT, attachment_count INTEGER, internal_date INTEGER, message_id TEXT)");
mDb.execSQL("DROP TABLE IF EXISTS headers");
mDb.execSQL("CREATE TABLE headers (id INTEGER PRIMARY KEY, message_id INTEGER, name TEXT, value TEXT)");
mDb.execSQL("CREATE INDEX IF NOT EXISTS header_folder ON headers (message_id)");
mDb.execSQL("CREATE INDEX IF NOT EXISTS msg_uid ON messages (uid, folder_id)"); mDb.execSQL("CREATE INDEX IF NOT EXISTS msg_uid ON messages (uid, folder_id)");
mDb.execSQL("DROP INDEX IF EXISTS msg_folder_id"); mDb.execSQL("DROP INDEX IF EXISTS msg_folder_id");
mDb.execSQL("CREATE INDEX IF NOT EXISTS msg_folder_id_date ON messages (folder_id,internal_date)"); mDb.execSQL("CREATE INDEX IF NOT EXISTS msg_folder_id_date ON messages (folder_id,internal_date)");
@ -149,7 +161,9 @@ public class LocalStore extends Store implements Serializable {
mDb.execSQL("CREATE TRIGGER delete_folder BEFORE DELETE ON folders BEGIN DELETE FROM messages WHERE old.id = folder_id; END;"); mDb.execSQL("CREATE TRIGGER delete_folder BEFORE DELETE ON folders BEGIN DELETE FROM messages WHERE old.id = folder_id; END;");
mDb.execSQL("DROP TRIGGER IF EXISTS delete_message"); mDb.execSQL("DROP TRIGGER IF EXISTS delete_message");
mDb.execSQL("CREATE TRIGGER delete_message BEFORE DELETE ON messages BEGIN DELETE FROM attachments WHERE old.id = message_id; END;"); mDb.execSQL("CREATE TRIGGER delete_message BEFORE DELETE ON messages BEGIN DELETE FROM attachments WHERE old.id = message_id; "
+ "DELETE FROM headers where old.id = message_id; END;");
mDb.setVersion(DB_VERSION); mDb.setVersion(DB_VERSION);
if (mDb.getVersion() != DB_VERSION) { if (mDb.getVersion() != DB_VERSION) {
throw new Error("Database upgrade failed!"); throw new Error("Database upgrade failed!");
@ -913,6 +927,54 @@ public class LocalStore extends Store implements Serializable {
"LocalStore.getMessages(int, int, MessageRetrievalListener) not yet implemented"); "LocalStore.getMessages(int, int, MessageRetrievalListener) not yet implemented");
} }
private void populateHeaders(List<LocalMessage> messages)
{
Cursor cursor = null;
if (messages.size() == 0)
{
return;
}
try {
Map<Long, LocalMessage> popMessages = new HashMap<Long, LocalMessage>();
List<String> ids = new ArrayList<String>();
StringBuffer questions = new StringBuffer();
for (int i = 0; i < messages.size(); i++)
{
if (i != 0)
{
questions.append(", ");
}
questions.append("?");
LocalMessage message = messages.get(i);
Long id = message.getId();
ids.add(Long.toString(id));
popMessages.put(id, message);
}
cursor = mDb.rawQuery(
"SELECT message_id, name, value "
+ "FROM headers " + "WHERE message_id in ( " + questions + ") ",
ids.toArray(new String[] {}));
while (cursor.moveToNext()) {
Long id = cursor.getLong(0);
String name = cursor.getString(1);
String value = cursor.getString(2);
//Log.i(Email.LOG_TAG, "Retrieved header name= " + name + ", value = " + value + " for message " + id);
popMessages.get(id).addHeader(name, value);
}
}
finally
{
if (cursor != null) {
cursor.close();
}
}
}
@Override @Override
public Message getMessage(String uid) throws MessagingException { public Message getMessage(String uid) throws MessagingException {
open(OpenMode.READ_WRITE); open(OpenMode.READ_WRITE);
@ -930,6 +992,9 @@ public class LocalStore extends Store implements Serializable {
return null; return null;
} }
populateMessageFromGetMessageCursor(message, cursor); populateMessageFromGetMessageCursor(message, cursor);
ArrayList<LocalMessage> messages = new ArrayList<LocalMessage>();
messages.add(message);
populateHeaders(messages);
} }
finally { finally {
if (cursor != null) { if (cursor != null) {
@ -942,7 +1007,7 @@ public class LocalStore extends Store implements Serializable {
@Override @Override
public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException { public Message[] getMessages(MessageRetrievalListener listener) throws MessagingException {
open(OpenMode.READ_WRITE); open(OpenMode.READ_WRITE);
ArrayList<Message> messages = new ArrayList<Message>(); ArrayList<LocalMessage> messages = new ArrayList<LocalMessage>();
Cursor cursor = null; Cursor cursor = null;
try { try {
// pull out messages most recent first, since that's what the default sort is // pull out messages most recent first, since that's what the default sort is
@ -959,12 +1024,14 @@ public class LocalStore extends Store implements Serializable {
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
LocalMessage message = new LocalMessage(null, this); LocalMessage message = new LocalMessage(null, this);
populateMessageFromGetMessageCursor(message, cursor); populateMessageFromGetMessageCursor(message, cursor);
messages.add(message); messages.add(message);
if (listener != null) { if (listener != null) {
listener.messageFinished(message, i, -1); listener.messageFinished(message, i, -1);
} }
i++; i++;
} }
populateHeaders(messages);
} }
finally { finally {
if (cursor != null) { if (cursor != null) {
@ -1126,6 +1193,7 @@ public class LocalStore extends Store implements Serializable {
for (Part attachment : attachments) { for (Part attachment : attachments) {
saveAttachment(messageId, attachment, copy); saveAttachment(messageId, attachment, copy);
} }
saveHeaders(messageId, (MimeMessage)message);
} catch (Exception e) { } catch (Exception e) {
throw new MessagingException("Error appending message", e); throw new MessagingException("Error appending message", e);
} }
@ -1204,11 +1272,41 @@ public class LocalStore extends Store implements Serializable {
Part attachment = attachments.get(i); Part attachment = attachments.get(i);
saveAttachment(message.mId, attachment, false); saveAttachment(message.mId, attachment, false);
} }
saveHeaders(message.getId(), message);
} catch (Exception e) { } catch (Exception e) {
throw new MessagingException("Error appending message", e); throw new MessagingException("Error appending message", e);
} }
} }
private void saveHeaders(long id, MimeMessage message)
{
deleteHeaders(id);
for (String name : message.getHeaderNames())
{
if (HEADERS_TO_SAVE.contains(name))
{
String[] values = message.getHeader(name);
for (String value : values)
{
ContentValues cv = new ContentValues();
cv.put("message_id", id);
cv.put("name", name);
cv.put("value", value);
//Log.i(Email.LOG_TAG, "Saving header name = " + name + ", value = " + value);
mDb.insert("headers", "name", cv);
}
}
}
}
private void deleteHeaders(long id)
{
mDb.execSQL("DELETE FROM headers WHERE id = ?",
new Object[] {
id
});
}
/** /**
* @param messageId * @param messageId
* @param attachment * @param attachment
@ -1536,10 +1634,6 @@ public class LocalStore extends Store implements Serializable {
public LocalMessage() { public LocalMessage() {
} }
// We don't want to do this for local messages
@Override public void setGeneratedMessageId () {}
LocalMessage(String uid, Folder folder) throws MessagingException { LocalMessage(String uid, Folder folder) throws MessagingException {
this.mUid = uid; this.mUid = uid;
this.mFolder = folder; this.mFolder = folder;
@ -1620,16 +1714,19 @@ public class LocalStore extends Store implements Serializable {
/* /*
* Delete all of the messages' attachments to save space. * Delete all of the messages' attachments to save space.
*/ */
// shouldn't the trigger take care of this? -- danapple
mDb.execSQL("DELETE FROM attachments WHERE id = ?", mDb.execSQL("DELETE FROM attachments WHERE id = ?",
new Object[] { new Object[] {
mId mId
}); });
((LocalFolder)mFolder).deleteHeaders(mId);
} }
else if (flag == Flag.X_DESTROYED && set) { else if (flag == Flag.X_DESTROYED && set) {
((LocalFolder) mFolder).deleteAttachments(getUid()); ((LocalFolder) mFolder).deleteAttachments(getUid());
mDb.execSQL("DELETE FROM messages WHERE id = ?", mDb.execSQL("DELETE FROM messages WHERE id = ?",
new Object[] { mId }); new Object[] { mId });
((LocalFolder)mFolder).deleteHeaders(mId);
} }
/* /*