Cache encoded and decoded addresses

pull/161/head
Unpublished 6 years ago
parent 1bb0d00b29
commit eb22d2b531

@ -987,12 +987,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvBcc.setVisibility(show_addresses && !TextUtils.isEmpty(bcc) ? View.VISIBLE : View.GONE);
tvBcc.setText(bcc);
InternetAddress via = null;
if (message.identityEmail != null)
try {
via = new InternetAddress(message.identityEmail, message.identityName);
} catch (UnsupportedEncodingException ignored) {
}
Address via = message.getVia();
tvIdentityTitle.setVisibility(show_addresses && via != null ? View.VISIBLE : View.GONE);
tvIdentity.setVisibility(show_addresses && via != null ? View.VISIBLE : View.GONE);

@ -18,20 +18,27 @@ import androidx.sqlite.db.SupportSQLiteDatabase;
import com.getkeepsafe.relinker.ReLinker;
import org.json.JSONAddress;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.mail.Address;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetAddressImpl;
import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory;
@ -76,6 +83,15 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory;
@TypeConverters({DB.Converters.class})
public abstract class DB extends RoomDatabase {
protected static final ConcurrentHashMap<JSONAddress, Address> addressCache = new ConcurrentHashMap<>();
protected static final ConcurrentHashMap<Address, JSONAddress> inverseAddressCache = new ConcurrentHashMap<>();
public static String getCacheStats() {
return "AddressCache: " + addressCache.mappingCount() + System.lineSeparator() +
"inverseCache: " + inverseAddressCache.mappingCount();
}
public abstract DaoAccount account();
public abstract DaoIdentity identity();
@ -1034,25 +1050,39 @@ public abstract class DB extends RoomDatabase {
if (addresses == null)
return null;
JSONArray jaddresses = new JSONArray();
for (Address address : addresses)
for (Address address : addresses) {
JSONObject jaddress = inverseAddressCache.get(address);
if (jaddress == null) {
try {
jaddress = new JSONObject();
InternetAddress internetAddress = null;
if (address instanceof InternetAddress) {
String a = ((InternetAddress) address).getAddress();
String p = ((InternetAddress) address).getPersonal();
JSONObject jaddress = new JSONObject();
internetAddress = (InternetAddress) address;
String a = internetAddress.getAddress();
String p = internetAddress.getPersonal();
if (a != null)
jaddress.put("address", a);
if (p != null)
jaddress.put("personal", p);
jaddresses.put(jaddress);
} else {
JSONObject jaddress = new JSONObject();
jaddress.put("address", address.toString());
jaddresses.put(jaddress);
}
} catch (JSONException ex) {
JSONAddress key = new JSONAddress(jaddress);
if (!(internetAddress instanceof InternetAddressImpl)) {
address = new InternetAddressImpl(internetAddress);
}
synchronized (addressCache) {
addressCache.put(key, address);
inverseAddressCache.put(address, key);
}
} catch (JSONException | UnsupportedEncodingException ex) {
Log.e(ex);
}
} else {
jaddress = ((JSONAddress) jaddress).jsonObject;
}
jaddresses.put(jaddress);
}
return jaddresses.toString();
}
@ -1074,12 +1104,21 @@ public abstract class DB extends RoomDatabase {
}
for (int i = 0; i < jaddresses.length(); i++) {
JSONObject jaddress = (JSONObject) jaddresses.get(i);
JSONAddress key = new JSONAddress(jaddress);
Address address = addressCache.get(key);
if (address == null) {
String email = jaddress.getString("address");
String personal = jaddress.optString("personal");
if (TextUtils.isEmpty(personal))
result.add(new InternetAddress(email));
address = new InternetAddressImpl(email);
else
result.add(new InternetAddress(email, personal));
address = new InternetAddressImpl(email, personal);
synchronized (addressCache) {
addressCache.put(key, address);
inverseAddressCache.put(address, key);
}
}
result.add(address);
}
} catch (Throwable ex) {
// Compose can store invalid addresses

@ -46,6 +46,7 @@ import javax.mail.Header;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetAddressImpl;
import static androidx.room.ForeignKey.CASCADE;
@ -323,7 +324,7 @@ public class EntityRule {
reply.inreplyto = message.msgid;
reply.thread = message.thread;
reply.to = (message.reply == null || message.reply.length == 0 ? message.from : message.reply);
reply.from = new InternetAddress[]{new InternetAddress(identity.email, identity.name)};
reply.from = new InternetAddressImpl[]{new InternetAddressImpl(identity.email, identity.name)};
if (cc)
reply.cc = message.cc;
reply.subject = context.getString(R.string.title_subject_reply, message.subject == null ? "" : message.subject);

@ -143,6 +143,7 @@ import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetAddressImpl;
import javax.mail.internet.MimeMessage;
import static android.app.Activity.RESULT_OK;
@ -1240,7 +1241,7 @@ public class FragmentCompose extends FragmentBase {
if (address != null)
list.addAll(Arrays.asList(address));
list.add(new InternetAddress(email, name));
list.add(new InternetAddressImpl(email, name));
if (requestCode == REQUEST_CONTACT_TO)
draft.to = list.toArray(new Address[0]);
@ -1622,7 +1623,7 @@ public class FragmentCompose extends FragmentBase {
if (contact != null && contact.moveToNext()) {
String name = contact.getString(0);
String email = contact.getString(1);
selected.add(new InternetAddress(email, name));
selected.add(new InternetAddressImpl(email, name));
}
}
}
@ -2078,7 +2079,7 @@ public class FragmentCompose extends FragmentBase {
String via = null;
if (ref.identity != null) {
EntityIdentity identity = db.identity().getIdentity(ref.identity);
draft.from = new Address[]{new InternetAddress(identity.email, identity.name)};
draft.from = new Address[]{new InternetAddressImpl(identity.email, identity.name)};
via = MessageHelper.canonicalAddress(identity.email);
}
@ -2162,7 +2163,7 @@ public class FragmentCompose extends FragmentBase {
String email = MessageHelper.canonicalAddress(identity.email);
if (email.equals(from)) {
draft.identity = identity.id;
draft.from = new InternetAddress[]{new InternetAddress(identity.email, identity.name)};
draft.from = new InternetAddressImpl[]{new InternetAddressImpl(identity.email, identity.name)};
break;
}
if (identity.account.equals(draft.account)) {
@ -2183,10 +2184,10 @@ public class FragmentCompose extends FragmentBase {
if (draft.identity == null) {
if (primary != null) {
draft.identity = primary.id;
draft.from = new InternetAddress[]{new InternetAddress(primary.email, primary.name)};
draft.from = new InternetAddressImpl[]{new InternetAddressImpl(primary.email, primary.name)};
} else if (first != null && icount == 1) {
draft.identity = first.id;
draft.from = new InternetAddress[]{new InternetAddress(first.email, first.name)};
draft.from = new InternetAddressImpl[]{new InternetAddressImpl(first.email, first.name)};
}
}
@ -2557,11 +2558,11 @@ public class FragmentCompose extends FragmentBase {
List<EntityAttachment> attachments = db.attachment().getAttachments(draft.id);
// Get data
InternetAddress afrom[] = (identity == null ? null : new InternetAddress[]{new InternetAddress(identity.email, identity.name)});
InternetAddressImpl afrom[] = (identity == null ? null : new InternetAddressImpl[]{new InternetAddressImpl(identity.email, identity.name)});
InternetAddress ato[] = null;
InternetAddress acc[] = null;
InternetAddress abcc[] = null;
InternetAddress[] ato = null;
InternetAddress[] acc = null;
InternetAddress[] abcc = null;
boolean lookup_mx = prefs.getBoolean("lookup_mx", false);

@ -72,6 +72,8 @@ import androidx.preference.PreferenceManager;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.sun.mail.iap.ConnectionException;
import com.sun.mail.util.FolderClosedIOException;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -876,4 +878,18 @@ public class Helper {
bundle.writeToParcel(p, 0);
return p.dataSize();
}
public static int computeAddressHashcode(JSONObject jsonObject) {
int ia = 0;
int ip = 0;
String address = null;
try {
ia = jsonObject.getString("address").hashCode();
if (jsonObject.has("personal")) {
ip = jsonObject.getString("personal").hashCode();
}
} catch (JSONException ignored) { }
return ia*2 + ip*8;
}
}

@ -80,7 +80,7 @@ import java.util.concurrent.TimeoutException;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetAddressImpl;
public class Log {
private static final String TAG = "fairemail";
@ -750,7 +750,7 @@ public class Log {
return (int) (getFreeMem() / 1024L / 1024L);
}
static InternetAddress myAddress() throws UnsupportedEncodingException {
return new InternetAddress("marcel+fairemail@faircode.eu", "FairCode");
static InternetAddressImpl myAddress() throws UnsupportedEncodingException {
return new InternetAddressImpl("marcel+fairemail@faircode.eu", "FairCode");
}
}

@ -67,6 +67,7 @@ import javax.mail.Session;
import javax.mail.internet.AddressException;
import javax.mail.internet.ContentType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetAddressImpl;
import javax.mail.internet.MailDateFormat;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
@ -553,7 +554,7 @@ public class MessageHelper {
try {
MailTo mailto = MailTo.parse(to.substring(lt + 1, gt));
if (mailto.getTo() != null)
return new Address[]{new InternetAddress(mailto.getTo().split(",")[0])};
return new Address[]{new InternetAddressImpl(mailto.getTo().split(",")[0])};
} catch (android.net.ParseException ex) {
Log.i(ex);
}
@ -1138,9 +1139,14 @@ public class MessageHelper {
if (a1.length != a2.length)
return false;
for (int i = 0; i < a1.length; i++)
if (!a1[i].toString().equals(a2[i].toString()))
Address address1;
Address address2;
for (int i = 0; i < a1.length; i++) {
address1 = a1[i];
address2 = a2[i];
if (!address1.equals(address2))
return false;
}
return true;
}

@ -55,7 +55,7 @@ import javax.mail.MessageRemovedException;
import javax.mail.MessagingException;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetAddressImpl;
import javax.mail.internet.MimeMessage;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
@ -326,7 +326,7 @@ public class ServiceSend extends ServiceBase {
// Add reply to
if (ident.replyto != null)
imessage.setReplyTo(new Address[]{new InternetAddress(ident.replyto)});
imessage.setReplyTo(new Address[]{new InternetAddressImpl(ident.replyto)});
// Add bcc
if (ident.bcc != null) {
@ -334,7 +334,7 @@ public class ServiceSend extends ServiceBase {
Address[] existing = imessage.getRecipients(Message.RecipientType.BCC);
if (existing != null)
bcc.addAll(Arrays.asList(existing));
bcc.add(new InternetAddress(ident.bcc));
bcc.add(new InternetAddressImpl(ident.bcc));
imessage.setRecipients(Message.RecipientType.BCC, bcc.toArray(new Address[0]));
}

@ -20,10 +20,16 @@ package eu.faircode.email;
*/
import androidx.room.Ignore;
import org.json.JSONAddress;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.util.Objects;
import javax.mail.Address;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.InternetAddressImpl;
public class TupleMessageEx extends EntityMessage {
public String accountName;
@ -47,6 +53,11 @@ public class TupleMessageEx extends EntityMessage {
@Ignore
public boolean duplicate;
@Ignore
public boolean calculatedVia = false;
@Ignore
public Address via = null;
@Override
public boolean equals(Object obj) {
if (obj instanceof TupleMessageEx) {
@ -72,4 +83,32 @@ public class TupleMessageEx extends EntityMessage {
}
return false;
}
public Address getVia() {
if (!calculatedVia && identityEmail != null) {
JSONObject jaddress = new JSONObject();
JSONAddress key = null;
try {
jaddress.put("address", identityEmail);
jaddress.put("personal", identityName);
key = new JSONAddress(jaddress);
via = DB.addressCache.get(key);
} catch (JSONException e) {
}
if (via == null) {
try {
via = new InternetAddressImpl(identityEmail, identityName);
if (key != null) {
synchronized (DB.addressCache) {
DB.inverseAddressCache.put(via, key);
DB.addressCache.put(key, via);
}
}
} catch (UnsupportedEncodingException ignored) {
}
}
calculatedVia = true;
}
return via;
}
}

@ -0,0 +1,51 @@
package javax.mail.internet;
import javax.mail.Address;
import java.io.UnsupportedEncodingException;
import java.util.Objects;
public class InternetAddressImpl extends InternetAddress {
public InternetAddressImpl() {
super();
}
public InternetAddressImpl(String address) throws AddressException {
super(address);
}
public InternetAddressImpl(String address, boolean strict) throws AddressException {
super(address, strict);
}
public InternetAddressImpl(String address, String personal) throws UnsupportedEncodingException {
super(address, personal);
}
public InternetAddressImpl(String address, String personal, String charset) throws UnsupportedEncodingException {
super(address, personal, charset);
}
public InternetAddressImpl(InternetAddress address) throws UnsupportedEncodingException {
setAddress(address.address);
setPersonal(address.personal);
}
@Override
public boolean equals(Object a) {
if (!super.equals(a)) return false;
InternetAddressImpl address1 = this;
InternetAddress address2 = (InternetAddress) a; // super.equals checked for a instanceof InternetAddress
// super.equals already checked this.address for equality
return Objects.equals(address1.getPersonal(), address2.getPersonal());
}
@Override
public int hashCode() {
String personal = this.getPersonal();
int personalHash = 0;
if (personal != null)
personalHash = personal.hashCode();
return super.hashCode() + personalHash*2;
}
}

@ -0,0 +1,22 @@
package org.json;
import eu.faircode.email.Helper;
public class JSONAddress extends JSONObject {
public final JSONObject jsonObject;
public JSONAddress(JSONObject jsonObject) {
this.jsonObject = jsonObject;
}
@Override
public int hashCode() {
return Helper.computeAddressHashcode(jsonObject);
}
@Override
public boolean equals(Object obj) {
return obj != null && this.hashCode() == obj.hashCode();
}
}
Loading…
Cancel
Save