package eu.faircode.email;
/*
This file is part of FairEmail.
FairEmail is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FairEmail is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FairEmail. If not, see .
Copyright 2018-2023 by Marcel Bokhorst (M66B)
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.text.Spanned;
import android.text.TextUtils;
import android.util.Pair;
import android.widget.Toast;
import androidx.preference.PreferenceManager;
import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.regex.Pattern;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessageRemovedException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
public abstract class LoaderComposeAction extends SimpleTask {
private static final int MAX_REASONABLE_SIZE = 5 * 1024 * 1024;
@Override
protected EntityMessage onExecute(final Context context, Bundle args) throws Throwable {
// Get data
long id = args.getLong("id");
int action = args.getInt("action");
long aid = args.getLong("account");
long iid = args.getLong("identity");
String extra = args.getString("extra");
String to = args.getString("to");
String cc = args.getString("cc");
String bcc = args.getString("bcc");
String subject = args.getString("subject");
Spanned loaded = (Spanned) args.getCharSequence("loaded");
Spanned spanned = (Spanned) args.getCharSequence("spanned");
boolean signature = args.getBoolean("signature");
boolean empty = args.getBoolean("empty");
boolean notext = args.getBoolean("notext");
Bundle extras = args.getBundle("extras");
boolean silent = extras.getBoolean("silent");
boolean dirty = false;
String body = HtmlHelper.toHtml(spanned, context);
EntityMessage draft;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean discard_delete = prefs.getBoolean("discard_delete", true);
boolean write_below = prefs.getBoolean("write_below", false);
boolean save_drafts = prefs.getBoolean("save_drafts", true);
int send_delayed = prefs.getInt("send_delayed", 0);
DB db = DB.getInstance(context);
try {
db.beginTransaction();
// Get draft & selected identity
draft = db.message().getMessage(id);
EntityIdentity identity = db.identity().getIdentity(iid);
// Draft deleted by server
if (draft == null || draft.ui_hide)
throw new MessageRemovedException("Draft for action was deleted hide=" + (draft != null));
Log.i("Load action id=" + draft.id + " action=" + getActionName(action));
if (action == R.id.action_delete) {
dirty = true;
EntityFolder trash = db.folder().getFolderByType(draft.account, EntityFolder.TRASH);
EntityFolder drafts = db.folder().getFolderByType(draft.account, EntityFolder.DRAFTS);
if (empty || trash == null || discard_delete || !save_drafts || (drafts != null && drafts.local))
EntityOperation.queue(context, draft, EntityOperation.DELETE);
else {
Map c = new HashMap<>();
c.put("id", draft.id == null ? null : Long.toString(draft.id));
c.put("encrypt", draft.encrypt + "/" + draft.ui_encrypt);
Log.breadcrumb("Discard draft", c);
EntityOperation.queue(context, draft, EntityOperation.ADD);
EntityOperation.queue(context, draft, EntityOperation.MOVE, trash.id);
}
ApplicationEx.getMainHandler().post(new Runnable() {
public void run() {
ToastEx.makeText(context, R.string.title_draft_deleted, Toast.LENGTH_LONG).show();
}
});
} else {
// Move draft to new account
if (draft.account != aid && aid >= 0) {
Log.i("Account changed");
Long uid = draft.uid;
String msgid = draft.msgid;
boolean content = draft.content;
Boolean ui_hide = draft.ui_hide;
// To prevent violating constraints
draft.uid = null;
draft.msgid = null;
db.message().updateMessage(draft);
// Create copy to delete
draft.id = null;
draft.uid = uid;
draft.msgid = msgid;
draft.content = false;
draft.ui_hide = true;
draft.id = db.message().insertMessage(draft);
EntityOperation.queue(context, draft, EntityOperation.DELETE);
// Restore original with new account, no uid and new msgid
draft.id = id;
draft.account = aid;
draft.folder = db.folder().getFolderByType(aid, EntityFolder.DRAFTS).id;
draft.uid = null;
draft.msgid = EntityMessage.generateMessageId();
draft.content = content;
draft.ui_hide = ui_hide;
db.message().updateMessage(draft);
if (draft.content)
dirty = true;
}
Map crumb = new HashMap<>();
crumb.put("draft", draft.folder + ":" + draft.id);
crumb.put("content", Boolean.toString(draft.content));
crumb.put("revision", Integer.toString(draft.revision == null ? -1 : draft.revision));
crumb.put("revisions", Integer.toString(draft.revisions == null ? -1 : draft.revisions));
crumb.put("file", Boolean.toString(draft.getFile(context).exists()));
crumb.put("action", getActionName(action));
Log.breadcrumb("compose", crumb);
List attachments = db.attachment().getAttachments(draft.id);
// Get data
InternetAddress[] afrom = (identity == null ? null : new InternetAddress[]{new InternetAddress(identity.email, identity.name, StandardCharsets.UTF_8.name())});
InternetAddress[] ato = MessageHelper.dedup(MessageHelper.parseAddresses(context, to));
InternetAddress[] acc = MessageHelper.dedup(MessageHelper.parseAddresses(context, cc));
InternetAddress[] abcc = MessageHelper.dedup(MessageHelper.parseAddresses(context, bcc));
// Safe guard
if (action == R.id.action_send) {
checkAddress(ato, context);
checkAddress(acc, context);
checkAddress(abcc, context);
}
if (TextUtils.isEmpty(extra))
extra = null;
List eparts = new ArrayList<>();
for (EntityAttachment attachment : attachments)
if (attachment.available)
if (attachment.isEncryption())
eparts.add(attachment.encryption);
if (EntityMessage.PGP_SIGNONLY.equals(draft.ui_encrypt)) {
if (!eparts.contains(EntityAttachment.PGP_KEY) ||
!eparts.contains(EntityAttachment.PGP_SIGNATURE) ||
!eparts.contains(EntityAttachment.PGP_CONTENT))
dirty = true;
} else if (EntityMessage.PGP_ENCRYPTONLY.equals(draft.ui_encrypt)) {
if (!eparts.contains(EntityAttachment.PGP_MESSAGE))
dirty = true;
} else if (EntityMessage.PGP_SIGNENCRYPT.equals(draft.ui_encrypt)) {
if (!eparts.contains(EntityAttachment.PGP_KEY) ||
!eparts.contains(EntityAttachment.PGP_MESSAGE))
dirty = true;
} else if (EntityMessage.SMIME_SIGNONLY.equals(draft.ui_encrypt)) {
if (!eparts.contains(EntityAttachment.SMIME_SIGNATURE) ||
!eparts.contains(EntityAttachment.SMIME_CONTENT))
dirty = true;
} else if (EntityMessage.SMIME_SIGNENCRYPT.equals(draft.ui_encrypt)) {
if (!eparts.contains(EntityAttachment.SMIME_MESSAGE))
dirty = true;
}
Long ident = (identity == null ? null : identity.id);
Pair> last = get();
if (!Objects.equals(draft.identity, ident) ||
!Objects.equals(draft.extra, extra) ||
!MessageHelper.equal(draft.from, afrom) ||
!MessageHelper.equal(draft.to, ato) ||
!MessageHelper.equal(draft.cc, acc) ||
!MessageHelper.equal(draft.bcc, abcc) ||
!Objects.equals(draft.subject, subject) ||
!draft.signature.equals(signature) ||
!Objects.equals(last.first, draft.plain_only) ||
!EntityAttachment.equals(last.second, attachments))
dirty = true;
set(draft.plain_only, attachments);
if (dirty) {
// Update draft
draft.identity = ident;
draft.extra = extra;
draft.from = afrom;
draft.to = ato;
draft.cc = acc;
draft.bcc = abcc;
draft.subject = subject;
draft.signature = signature;
draft.sender = MessageHelper.getSortKey(draft.from);
Uri lookupUri = ContactInfo.getLookupUri(draft.from);
draft.avatar = (lookupUri == null ? null : lookupUri.toString());
db.message().updateMessage(draft);
}
Document doc = JsoupEx.parse(draft.getFile(context));
Element first = (doc.body().childrenSize() == 0 ? null : doc.body().child(0));
boolean below = (first != null && first.attr("fairemail").equals("reference"));
doc.select("div[fairemail=signature]").remove();
Elements ref = doc.select("div[fairemail=reference]");
ref.remove();
if (extras.containsKey("html"))
dirty = true;
boolean wb = (draft == null || draft.write_below == null ? write_below : draft.write_below);
if (below != wb &&
doc.body().childrenSize() > 0 &&
draft.wasforwardedfrom == null)
dirty = true;
if (!dirty)
if (loaded == null) {
Document b = JsoupEx.parse(body); // Is-dirty
if (!Objects.equals(b.body().html(), doc.body().html()))
dirty = true;
} else {
// Was not dirty before
String hloaded = HtmlHelper.toHtml(loaded, context);
String hspanned = HtmlHelper.toHtml(spanned, context);
if (!Objects.equals(hloaded, hspanned))
dirty = true;
}
if (draft.revision == null) {
draft.revision = 1;
draft.revisions = 1;
}
int revision = draft.revision; // Save for undo/redo
if (dirty) {
dirty = true;
// Get saved body
Document d;
if (extras.containsKey("html")) {
// Save current revision
Document c = JsoupEx.parse(body);
for (Element e : ref)
if (wb && draft.wasforwardedfrom == null)
c.body().prependChild(e);
else
c.body().appendChild(e);
ComposeHelper.addSignature(context, c, draft, identity);
Helper.writeText(draft.getFile(context, draft.revision), c.html());
d = JsoupEx.parse(extras.getString("html"));
} else {
d = JsoupEx.parse(body); // Save
for (Element e : ref)
if (wb && draft.wasforwardedfrom == null)
d.body().prependChild(e);
else
d.body().appendChild(e);
ComposeHelper.addSignature(context, d, draft, identity);
}
body = d.html();
// Create new revision
draft.revisions++;
draft.revision = draft.revisions;
Helper.writeText(draft.getFile(context, draft.revision), body);
} else
body = Helper.readText(draft.getFile(context));
if (action == R.id.action_undo || action == R.id.action_redo) {
if (action == R.id.action_undo) {
if (revision > 1)
draft.revision = revision - 1;
else
draft.revision = revision;
} else {
if (revision < draft.revisions)
draft.revision = revision + 1;
else
draft.revision = revision;
}
// Restore revision
Log.i("Restoring revision=" + draft.revision);
File file = draft.getFile(context, draft.revision);
if (file.exists())
body = Helper.readText(file);
else
Log.e("Missing" +
" revision=" + draft.revision + "/" + draft.revisions +
" action=" + getActionName(action));
dirty = true;
} else if (action == R.id.action_send) {
if (!draft.isPlainOnly()) {
// Remove unused inline images
List cids = new ArrayList<>();
Document d = JsoupEx.parse(body);
for (Element element : d.select("img")) {
String src = element.attr("src");
if (src.startsWith("cid:"))
cids.add("<" + src.substring(4) + ">");
}
for (EntityAttachment attachment : new ArrayList<>(attachments))
if (attachment.isInline() && attachment.isImage() &&
attachment.cid != null && !cids.contains(attachment.cid)) {
Log.i("Removing unused inline attachment cid=" + attachment.cid);
attachments.remove(attachment);
db.attachment().deleteAttachment(attachment.id);
dirty = true;
}
} else {
// Convert inline images to attachments
for (EntityAttachment attachment : new ArrayList<>(attachments))
if (attachment.isInline() && attachment.isImage()) {
Log.i("Converting to attachment cid=" + attachment.cid);
attachment.disposition = Part.ATTACHMENT;
attachment.cid = null;
db.attachment().setDisposition(attachment.id, attachment.disposition, attachment.cid);
dirty = true;
}
}
}
File f = draft.getFile(context);
Helper.writeText(f, body);
if (f.length() > MAX_REASONABLE_SIZE)
args.putBoolean("large", true);
String full = HtmlHelper.getFullText(body);
draft.preview = HtmlHelper.getPreview(full);
draft.language = HtmlHelper.getLanguage(context, draft.subject, full);
db.message().setMessageContent(draft.id,
true,
draft.language,
draft.plain_only, // unchanged
draft.preview,
null);
db.message().setMessageRevision(draft.id, draft.revision);
db.message().setMessageRevisions(draft.id, draft.revisions);
if (dirty) {
draft.received = new Date().getTime();
draft.sent = draft.received;
db.message().setMessageReceived(draft.id, draft.received);
db.message().setMessageSent(draft.id, draft.sent);
}
if (silent) {
// Skip storing on the server, etc
db.setTransactionSuccessful();
return draft;
}
// Execute action
boolean encrypted = extras.getBoolean("encrypted");
boolean shouldEncrypt = EntityMessage.PGP_ENCRYPTONLY.equals(draft.ui_encrypt) ||
EntityMessage.PGP_SIGNENCRYPT.equals(draft.ui_encrypt) ||
(EntityMessage.PGP_SIGNONLY.equals(draft.ui_encrypt) && action == R.id.action_send) ||
EntityMessage.SMIME_SIGNENCRYPT.equals(draft.ui_encrypt) ||
(EntityMessage.SMIME_SIGNONLY.equals(draft.ui_encrypt) && action == R.id.action_send);
boolean needsEncryption = (dirty && !encrypted && shouldEncrypt);
boolean autosave = extras.getBoolean("autosave");
if (needsEncryption && !autosave) {
args.putBoolean("needsEncryption", true);
db.setTransactionSuccessful();
return draft;
}
if (!shouldEncrypt && !autosave)
for (EntityAttachment attachment : attachments)
if (attachment.isEncryption())
db.attachment().deleteAttachment(attachment.id);
if (action == R.id.action_save ||
action == R.id.action_undo ||
action == R.id.action_redo ||
action == R.id.action_check) {
boolean unencrypted =
(!EntityMessage.PGP_ENCRYPTONLY.equals(draft.ui_encrypt) &&
!EntityMessage.PGP_SIGNENCRYPT.equals(draft.ui_encrypt) &&
!EntityMessage.SMIME_SIGNENCRYPT.equals(draft.ui_encrypt));
if ((dirty && unencrypted) || encrypted) {
if (save_drafts) {
Map c = new HashMap<>();
c.put("id", draft.id == null ? null : Long.toString(draft.id));
c.put("dirty", Boolean.toString(dirty));
c.put("encrypt", draft.encrypt + "/" + draft.ui_encrypt);
c.put("encrypted", Boolean.toString(encrypted));
c.put("needsEncryption", Boolean.toString(needsEncryption));
c.put("autosave", Boolean.toString(autosave));
Log.breadcrumb("Save draft", c);
EntityOperation.queue(context, draft, EntityOperation.ADD);
}
}
if (action == R.id.action_check) {
// Check data
if (draft.identity == null)
throw new IllegalArgumentException(context.getString(R.string.title_from_missing));
if (false) {
EntityAccount account = db.account().getAccount(draft.account);
EntityFolder sent = db.folder().getFolderByType(draft.account, EntityFolder.SENT);
if (account != null && account.protocol == EntityAccount.TYPE_IMAP && sent == null)
args.putBoolean("sent_missing", true);
}
try {
checkAddress(ato, context);
checkAddress(acc, context);
checkAddress(abcc, context);
List check = new ArrayList<>();
List checked = new ArrayList<>();
List dup = new ArrayList<>();
if (ato != null)
check.addAll(Arrays.asList(ato));
if (acc != null)
check.addAll(Arrays.asList(acc));
if (abcc != null)
check.addAll(Arrays.asList(abcc));
for (InternetAddress a : check) {
String email = a.getAddress();
if (TextUtils.isEmpty(email))
continue;
if (checked.contains(a.getAddress()))
dup.add(email);
else
checked.add(email);
}
if (dup.size() > 0)
throw new AddressException(context.getString(
R.string.title_address_duplicate,
TextUtils.join(", ", dup)));
} catch (AddressException ex) {
args.putString("address_error", ex.getMessage());
}
if (draft.to == null && draft.cc == null && draft.bcc == null &&
(identity == null || (identity.cc == null && identity.bcc == null)))
args.putBoolean("remind_to", true);
//if (TextUtils.isEmpty(draft.extra) &&
// identity != null && identity.sender_extra)
// args.putBoolean("remind_extra", true);
List recipients = new ArrayList<>();
if (draft.to != null)
recipients.addAll(Arrays.asList(draft.to));
if (draft.cc != null)
recipients.addAll(Arrays.asList(draft.cc));
if (draft.bcc != null)
recipients.addAll(Arrays.asList(draft.bcc));
boolean noreply = false;
for (Address recipient : recipients)
if (MessageHelper.isNoReply(recipient)) {
noreply = true;
break;
}
args.putBoolean("remind_noreply", noreply);
if (identity != null && !TextUtils.isEmpty(identity.internal)) {
boolean external = false;
String[] internals = identity.internal.split(",");
for (Address recipient : recipients) {
String email = ((InternetAddress) recipient).getAddress();
String domain = UriHelper.getEmailDomain(email);
if (domain == null)
continue;
boolean found = false;
for (String internal : internals)
if (internal.equalsIgnoreCase(domain)) {
found = true;
break;
}
if (!found) {
external = true;
break;
}
}
args.putBoolean("remind_external", external);
}
if ((draft.dsn == null ||
EntityMessage.DSN_NONE.equals(draft.dsn)) &&
(draft.ui_encrypt == null ||
EntityMessage.ENCRYPT_NONE.equals(draft.ui_encrypt))) {
args.putBoolean("remind_pgp", PgpHelper.hasPgpKey(context, recipients, false));
args.putBoolean("remind_smime", SmimeHelper.hasSmimeKey(context, recipients, false));
}
if (TextUtils.isEmpty(draft.subject))
args.putBoolean("remind_subject", true);
Document d = JsoupEx.parse(body);
if (notext &&
d.select("div[fairemail=reference]").isEmpty())
args.putBoolean("remind_text", true);
boolean styled = HtmlHelper.isStyled(d);
args.putBoolean("styled", styled);
int attached = 0;
List dangerous = new ArrayList<>();
for (EntityAttachment attachment : attachments) {
if (!attachment.available)
throw new IllegalArgumentException(context.getString(R.string.title_attachments_missing));
else if (attachment.isAttachment())
attached++;
String ext = Helper.getExtension(attachment.name);
if (Helper.DANGEROUS_EXTENSIONS.contains(ext))
dangerous.add(attachment.name);
}
if (dangerous.size() > 0)
args.putString("remind_extension", String.join(", ", dangerous));
// Check for missing attachments
if (attached == 0) {
List keywords = new ArrayList<>();
for (String text : Helper.getStrings(context, R.string.title_attachment_keywords))
keywords.addAll(Arrays.asList(text.split(",")));
d.select("div[fairemail=signature]").remove();
d.select("div[fairemail=reference]").remove();
String text = d.text();
for (String keyword : keywords)
if (text.matches("(?si).*\\b" + Pattern.quote(keyword.trim()) + "\\b.*")) {
args.putBoolean("remind_attachment", true);
break;
}
}
if (EntityMessage.DSN_HARD_BOUNCE.equals(draft.dsn))
args.putBoolean("remind_dsn", true);
// Check size
if (identity != null && identity.max_size != null)
try {
Properties props = MessageHelper.getSessionProperties(true);
if (identity.unicode)
props.put("mail.mime.allowutf8", "true");
Session isession = Session.getInstance(props, null);
Message imessage = MessageHelper.from(context, draft, identity, isession, false);
File file = draft.getRawFile(context);
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
imessage.writeTo(os);
}
long size = file.length();
if (size > identity.max_size) {
args.putBoolean("remind_size", true);
args.putLong("size", size);
args.putLong("max_size", identity.max_size);
}
} catch (Throwable ex) {
Log.e(ex);
}
args.putBoolean("remind_internet", !ConnectionHelper.getNetworkState(context).isConnected());
} else {
int mid;
if (action == R.id.action_undo)
mid = R.string.title_undo;
else if (action == R.id.action_redo)
mid = R.string.title_redo;
else
mid = R.string.title_draft_saved;
final String msg = context.getString(mid) +
(BuildConfig.DEBUG
? " " + draft.revision + (dirty ? "*" : "")
: "");
ApplicationEx.getMainHandler().post(new Runnable() {
public void run() {
ToastEx.makeText(context, msg, Toast.LENGTH_LONG).show();
}
});
}
} else if (action == R.id.action_send) {
EntityFolder outbox = EntityFolder.getOutbox(context);
// Delay sending message
if (draft.ui_snoozed == null && send_delayed != 0) {
if (extras.getBoolean("now"))
draft.ui_snoozed = null;
else
draft.ui_snoozed = new Date().getTime() + send_delayed * 1000L;
}
if (draft.ui_snoozed != null)
draft.received = draft.ui_snoozed;
// Copy message to outbox
long did = draft.id;
draft.id = null;
draft.folder = outbox.id;
draft.uid = null;
draft.fts = false;
draft.ui_hide = false;
draft.id = db.message().insertMessage(draft);
Helper.writeText(draft.getFile(context), body);
// Move attachments
for (EntityAttachment attachment : attachments)
db.attachment().setMessage(attachment.id, draft.id);
// Send message
if (draft.ui_snoozed == null)
EntityOperation.queue(context, draft, EntityOperation.SEND);
// Delete draft (cannot move to outbox)
EntityMessage tbd = db.message().getMessage(did);
if (tbd != null)
EntityOperation.queue(context, tbd, EntityOperation.DELETE);
final String feedback;
if (draft.ui_snoozed == null) {
boolean suitable = ConnectionHelper.getNetworkState(context).isSuitable();
if (suitable)
feedback = context.getString(R.string.title_queued);
else
feedback = context.getString(R.string.title_notification_waiting);
} else {
DateFormat DTF = Helper.getDateTimeInstance(context);
feedback = context.getString(R.string.title_queued_at, DTF.format(draft.ui_snoozed));
}
toast(feedback);
if (extras.getBoolean("archive")) {
EntityFolder archive = db.folder().getFolderByType(draft.account, EntityFolder.ARCHIVE);
if (archive != null) {
List messages = db.message().getMessagesByMsgId(draft.account, draft.inreplyto);
if (messages != null)
for (EntityMessage message : messages)
EntityOperation.queue(context, message, EntityOperation.MOVE, archive.id);
}
}
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
if (action == R.id.action_check)
try {
InternetAddress[] ato = MessageHelper.dedup(MessageHelper.parseAddresses(context, to));
InternetAddress[] acc = MessageHelper.dedup(MessageHelper.parseAddresses(context, cc));
InternetAddress[] abcc = MessageHelper.dedup(MessageHelper.parseAddresses(context, bcc));
try {
checkMx(ato, context);
checkMx(acc, context);
checkMx(abcc, context);
} catch (UnknownHostException ex) {
args.putString("mx_error", ex.getMessage());
}
} catch (Throwable ignored) {
}
args.putBoolean("dirty", dirty);
if (dirty)
ServiceSynchronize.eval(context, "compose/action");
if (action == R.id.action_send)
if (draft.ui_snoozed == null)
ServiceSend.start(context);
else {
Log.i("Delayed send id=" + draft.id + " at " + new Date(draft.ui_snoozed));
EntityMessage.snooze(context, draft.id, draft.ui_snoozed);
}
return draft;
}
protected Pair> get() {
throw new NotImplementedException("LoaderAction");
}
protected void set(Integer plain_only, List attachments) {
throw new NotImplementedException("LoaderAction");
}
protected void toast(String feedback) {
throw new NotImplementedException("LoaderAction");
}
private void checkAddress(InternetAddress[] addresses, Context context) throws AddressException {
if (addresses == null)
return;
for (InternetAddress address : addresses)
try {
address.validate();
} catch (AddressException ex) {
throw new AddressException(context.getString(R.string.title_address_parse_error,
MessageHelper.formatAddressesCompose(new Address[]{address}), ex.getMessage()));
}
}
private void checkMx(InternetAddress[] addresses, Context context) throws UnknownHostException {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean lookup_mx = prefs.getBoolean("lookup_mx", false);
if (!lookup_mx)
return;
if (addresses == null)
return;
ConnectivityManager cm = Helper.getSystemService(context, ConnectivityManager.class);
NetworkInfo ani = (cm == null ? null : cm.getActiveNetworkInfo());
if (ani != null && ani.isConnected())
DnsHelper.checkMx(context, addresses);
}
static String getActionName(int id) {
if (id == R.id.action_delete) {
return "delete";
} else if (id == R.id.action_undo) {
return "undo";
} else if (id == R.id.action_redo) {
return "redo";
} else if (id == R.id.action_save) {
return "save";
} else if (id == R.id.action_check) {
return "check";
} else if (id == R.id.action_send) {
return "send";
}
return Integer.toString(id);
}
}