aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations/entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/eu/siacs/conversations/entities')
-rw-r--r--src/main/java/eu/siacs/conversations/entities/AbstractEntity.java1
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Account.java95
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Blockable.java11
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Bookmark.java16
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Contact.java64
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Conversation.java281
-rw-r--r--src/main/java/eu/siacs/conversations/entities/DownloadableFile.java16
-rw-r--r--src/main/java/eu/siacs/conversations/entities/ListItem.java8
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Message.java71
-rw-r--r--src/main/java/eu/siacs/conversations/entities/MucOptions.java66
-rw-r--r--src/main/java/eu/siacs/conversations/entities/Roster.java10
11 files changed, 429 insertions, 210 deletions
diff --git a/src/main/java/eu/siacs/conversations/entities/AbstractEntity.java b/src/main/java/eu/siacs/conversations/entities/AbstractEntity.java
index 92b8a729..957b0a14 100644
--- a/src/main/java/eu/siacs/conversations/entities/AbstractEntity.java
+++ b/src/main/java/eu/siacs/conversations/entities/AbstractEntity.java
@@ -17,5 +17,4 @@ public abstract class AbstractEntity {
public boolean equals(AbstractEntity entity) {
return this.getUuid().equals(entity.getUuid());
}
-
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java
index 538d0ec2..b0cde62c 100644
--- a/src/main/java/eu/siacs/conversations/entities/Account.java
+++ b/src/main/java/eu/siacs/conversations/entities/Account.java
@@ -10,9 +10,12 @@ import net.java.otr4j.crypto.OtrCryptoException;
import org.json.JSONException;
import org.json.JSONObject;
+import java.security.PublicKey;
import java.security.interfaces.DSAPublicKey;
+import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.CopyOnWriteArraySet;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
@@ -56,7 +59,7 @@ public class Account extends AbstractEntity {
SECURITY_ERROR(true),
INCOMPATIBLE_SERVER(true);
- private boolean isError;
+ private final boolean isError;
public boolean isError() {
return this.isError;
@@ -116,11 +119,11 @@ public class Account extends AbstractEntity {
protected boolean online = false;
private OtrEngine otrEngine = null;
private XmppConnection xmppConnection = null;
- private Presences presences = new Presences();
private long mEndGracePeriod = 0L;
private String otrFingerprint;
- private Roster roster = null;
+ private final Roster roster = new Roster(this);
private List<Bookmark> bookmarks = new CopyOnWriteArrayList<>();
+ private final Collection<Jid> blocklist = new CopyOnWriteArraySet<>();
public Account() {
this.uuid = "0";
@@ -150,7 +153,7 @@ public class Account extends AbstractEntity {
this.avatar = avatar;
}
- public static Account fromCursor(Cursor cursor) {
+ public static Account fromCursor(final Cursor cursor) {
Jid jid = null;
try {
jid = Jid.fromParts(cursor.getString(cursor.getColumnIndex(USERNAME)),
@@ -166,11 +169,11 @@ public class Account extends AbstractEntity {
cursor.getString(cursor.getColumnIndex(AVATAR)));
}
- public boolean isOptionSet(int option) {
+ public boolean isOptionSet(final int option) {
return ((options & (1 << option)) != 0);
}
- public void setOption(int option, boolean value) {
+ public void setOption(final int option, final boolean value) {
if (value) {
this.options |= 1 << option;
} else {
@@ -241,34 +244,18 @@ public class Account extends AbstractEntity {
return keys;
}
- public String getSSLFingerprint() {
- if (keys.has("ssl_cert")) {
- try {
- return keys.getString("ssl_cert");
- } catch (JSONException e) {
- return null;
- }
- } else {
- return null;
- }
- }
-
- public void setSSLCertFingerprint(String fingerprint) {
- this.setKey("ssl_cert", fingerprint);
- }
-
- public boolean setKey(String keyName, String keyValue) {
+ public boolean setKey(final String keyName, final String keyValue) {
try {
this.keys.put(keyName, keyValue);
return true;
- } catch (JSONException e) {
+ } catch (final JSONException e) {
return false;
}
}
@Override
public ContentValues getContentValues() {
- ContentValues values = new ContentValues();
+ final ContentValues values = new ContentValues();
values.put(UUID, uuid);
values.put(USERNAME, jid.getLocalpart());
values.put(SERVER, jid.getDomainpart());
@@ -280,7 +267,7 @@ public class Account extends AbstractEntity {
return values;
}
- public void initOtrEngine(XmppConnectionService context) {
+ public void initOtrEngine(final XmppConnectionService context) {
this.otrEngine = new OtrEngine(context, this);
}
@@ -292,7 +279,7 @@ public class Account extends AbstractEntity {
return this.xmppConnection;
}
- public void setXmppConnection(XmppConnection connection) {
+ public void setXmppConnection(final XmppConnection connection) {
this.xmppConnection = connection;
}
@@ -302,8 +289,8 @@ public class Account extends AbstractEntity {
if (this.otrEngine == null) {
return null;
}
- DSAPublicKey publicKey = (DSAPublicKey) this.otrEngine.getPublicKey();
- if (publicKey == null) {
+ final PublicKey publicKey = this.otrEngine.getPublicKey();
+ if (publicKey == null || !(publicKey instanceof DSAPublicKey)) {
return null;
}
this.otrFingerprint = new OtrCryptoEngineImpl().getFingerprint(publicKey);
@@ -324,31 +311,19 @@ public class Account extends AbstractEntity {
}
}
- public void setRosterVersion(String version) {
+ public void setRosterVersion(final String version) {
this.rosterVersion = version;
}
- public void updatePresence(String resource, int status) {
- this.presences.updatePresence(resource, status);
- }
-
- public void removePresence(String resource) {
- this.presences.removePresence(resource);
- }
-
- public void clearPresences() {
- this.presences = new Presences();
- }
-
public int countPresences() {
- return this.presences.size();
+ return this.getRoster().getContact(this.getJid().toBareJid()).getPresences().size();
}
public String getPgpSignature() {
if (keys.has("pgp_signature")) {
try {
return keys.getString("pgp_signature");
- } catch (JSONException e) {
+ } catch (final JSONException e) {
return null;
}
} else {
@@ -357,9 +332,6 @@ public class Account extends AbstractEntity {
}
public Roster getRoster() {
- if (this.roster == null) {
- this.roster = new Roster(this);
- }
return this.roster;
}
@@ -367,12 +339,12 @@ public class Account extends AbstractEntity {
return this.bookmarks;
}
- public void setBookmarks(List<Bookmark> bookmarks) {
+ public void setBookmarks(final List<Bookmark> bookmarks) {
this.bookmarks = bookmarks;
}
public boolean hasBookmarkFor(final Jid conferenceJid) {
- for (Bookmark bookmark : this.bookmarks) {
+ for (final Bookmark bookmark : this.bookmarks) {
final Jid jid = bookmark.getJid();
if (jid != null && jid.equals(conferenceJid.toBareJid())) {
return true;
@@ -381,7 +353,7 @@ public class Account extends AbstractEntity {
return false;
}
- public boolean setAvatar(String filename) {
+ public boolean setAvatar(final String filename) {
if (this.avatar != null && this.avatar.equals(filename)) {
return false;
} else {
@@ -408,11 +380,32 @@ public class Account extends AbstractEntity {
}
public String getShareableUri() {
- String fingerprint = this.getOtrFingerprint();
+ final String fingerprint = this.getOtrFingerprint();
if (fingerprint != null) {
return "xmpp:" + this.getJid().toBareJid().toString() + "?otr-fingerprint="+fingerprint;
} else {
return "xmpp:" + this.getJid().toBareJid().toString();
}
}
+
+ public boolean isBlocked(final ListItem contact) {
+ final Jid jid = contact.getJid();
+ return jid != null && (blocklist.contains(jid.toBareJid()) || blocklist.contains(jid.toDomainJid()));
+ }
+
+ public boolean isBlocked(final Jid jid) {
+ return jid != null && blocklist.contains(jid.toBareJid());
+ }
+
+ public Collection<Jid> getBlocklist() {
+ return this.blocklist;
+ }
+
+ public void clearBlocklist() {
+ getBlocklist().clear();
+ }
+
+ public boolean isOnlineAndConnected() {
+ return this.getStatus() == State.ONLINE && this.getXmppConnection() != null;
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Blockable.java b/src/main/java/eu/siacs/conversations/entities/Blockable.java
new file mode 100644
index 00000000..dbcd55c4
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/entities/Blockable.java
@@ -0,0 +1,11 @@
+package eu.siacs.conversations.entities;
+
+import eu.siacs.conversations.xmpp.jid.Jid;
+
+public interface Blockable {
+ public boolean isBlocked();
+ public boolean isDomainBlocked();
+ public Jid getBlockedJid();
+ public Jid getJid();
+ public Account getAccount();
+}
diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
index 559e2f2d..f81f1a87 100644
--- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java
+++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java
@@ -6,7 +6,6 @@ import java.util.Locale;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
public class Bookmark extends Element implements ListItem {
@@ -60,16 +59,7 @@ public class Bookmark extends Element implements ListItem {
@Override
public Jid getJid() {
- final String jid = this.getAttribute("jid");
- if (jid != null) {
- try {
- return Jid.fromString(jid);
- } catch (final InvalidJidException e) {
- return null;
- }
- } else {
- return null;
- }
+ return this.getAttributeAsJid("jid");
}
@Override
@@ -102,9 +92,7 @@ public class Bookmark extends Element implements ListItem {
}
public boolean autojoin() {
- String autojoin = this.getAttribute("autojoin");
- return (autojoin != null && (autojoin.equalsIgnoreCase("true") || autojoin
- .equalsIgnoreCase("1")));
+ return this.getAttributeAsBoolean("autojoin");
}
public String getPassword() {
diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java
index 6a6b41d6..698e0322 100644
--- a/src/main/java/eu/siacs/conversations/entities/Contact.java
+++ b/src/main/java/eu/siacs/conversations/entities/Contact.java
@@ -16,7 +16,7 @@ import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
-public class Contact implements ListItem {
+public class Contact implements ListItem, Blockable {
public static final String TABLENAME = "contacts";
public static final String SYSTEMNAME = "systemname";
@@ -47,8 +47,8 @@ public class Contact implements ListItem {
protected Account account;
public Contact(final String account, final String systemName, final String serverName,
- final Jid jid, final int subscription, final String photoUri,
- final String systemAccount, final String keys, final String avatar, final Lastseen lastseen, final String groups) {
+ final Jid jid, final int subscription, final String photoUri,
+ final String systemAccount, final String keys, final String avatar, final Lastseen lastseen, final String groups) {
this.accountUuid = account;
this.systemName = systemName;
this.serverName = serverName;
@@ -122,11 +122,10 @@ public class Contact implements ListItem {
@Override
public List<Tag> getTags() {
- ArrayList<Tag> tags = new ArrayList<Tag>();
- for (String group : getGroups()) {
+ final ArrayList<Tag> tags = new ArrayList<>();
+ for (final String group : getGroups()) {
tags.add(new Tag(group, UIHelper.getColorForName(group)));
}
- int status = getMostAvailableStatus();
switch (getMostAvailableStatus()) {
case Presences.CHAT:
case Presences.ONLINE:
@@ -142,6 +141,9 @@ public class Contact implements ListItem {
tags.add(new Tag("dnd", 0xffe51c23));
break;
}
+ if (isBlocked()) {
+ tags.add(new Tag("blocked", 0xff2e2f3b));
+ }
return tags;
}
@@ -176,7 +178,7 @@ public class Contact implements ListItem {
}
public ContentValues getContentValues() {
- ContentValues values = new ContentValues();
+ final ContentValues values = new ContentValues();
values.put(ACCOUNT, accountUuid);
values.put(SYSTEMNAME, systemName);
values.put(SERVERNAME, serverName);
@@ -213,11 +215,11 @@ public class Contact implements ListItem {
this.presences = pres;
}
- public void updatePresence(String resource, int status) {
+ public void updatePresence(final String resource, final int status) {
this.presences.updatePresence(resource, status);
}
- public void removePresence(String resource) {
+ public void removePresence(final String resource) {
this.presences.removePresence(resource);
}
@@ -266,13 +268,15 @@ public class Contact implements ListItem {
}
public ArrayList<String> getOtrFingerprints() {
- ArrayList<String> fingerprints = new ArrayList<String>();
+ final ArrayList<String> fingerprints = new ArrayList<String>();
try {
if (this.keys.has("otr_fingerprints")) {
- JSONArray prints = this.keys
- .getJSONArray("otr_fingerprints");
+ final JSONArray prints = this.keys.getJSONArray("otr_fingerprints");
for (int i = 0; i < prints.length(); ++i) {
- fingerprints.add(prints.getString(i));
+ final String print = prints.isNull(i) ? null : prints.getString(i);
+ if (print != null && !print.isEmpty()) {
+ fingerprints.add(prints.getString(i));
+ }
}
}
} catch (final JSONException ignored) {
@@ -335,8 +339,8 @@ public class Contact implements ListItem {
public boolean showInRoster() {
return (this.getOption(Contact.Options.IN_ROSTER) && (!this
- .getOption(Contact.Options.DIRTY_DELETE)))
- || (this.getOption(Contact.Options.DIRTY_PUSH));
+ .getOption(Contact.Options.DIRTY_DELETE)))
+ || (this.getOption(Contact.Options.DIRTY_PUSH));
}
public void parseSubscriptionFromElement(Element item) {
@@ -426,7 +430,7 @@ public class Contact implements ListItem {
if (this.keys.has("otr_fingerprints")) {
JSONArray newPrints = new JSONArray();
JSONArray oldPrints = this.keys
- .getJSONArray("otr_fingerprints");
+ .getJSONArray("otr_fingerprints");
for (int i = 0; i < oldPrints.length(); ++i) {
if (!oldPrints.getString(i).equals(fingerprint)) {
newPrints.put(oldPrints.getString(i));
@@ -449,28 +453,46 @@ public class Contact implements ListItem {
public String getShareableUri() {
if (getOtrFingerprints().size() >= 1) {
String otr = getOtrFingerprints().get(0);
- return "xmpp:" + getJid().toBareJid().toString() + "?otr-fingerprint=" + otr.replace(" ", "");
+ return "xmpp:" + getJid().toBareJid().toString() + "?otr-fingerprint=" + otr;
} else {
return "xmpp:" + getJid().toBareJid().toString();
}
}
+ @Override
+ public boolean isBlocked() {
+ return getAccount().isBlocked(this);
+ }
+
+ @Override
+ public boolean isDomainBlocked() {
+ return getAccount().isBlocked(this.getJid().toDomainJid());
+ }
+
+ @Override
+ public Jid getBlockedJid() {
+ if (isDomainBlocked()) {
+ return getJid().toDomainJid();
+ } else {
+ return getJid();
+ }
+ }
+
public static class Lastseen {
public long time;
public String presence;
public Lastseen() {
- time = 0;
- presence = null;
+ this(null, 0);
}
public Lastseen(final String presence, final long time) {
- this.time = time;
this.presence = presence;
+ this.time = time;
}
}
- public class Options {
+ public final class Options {
public static final int TO = 0;
public static final int FROM = 1;
public static final int ASKING = 2;
diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java
index a7da0bc2..470bd290 100644
--- a/src/main/java/eu/siacs/conversations/entities/Conversation.java
+++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java
@@ -16,12 +16,15 @@ import org.json.JSONObject;
import java.security.interfaces.DSAPublicKey;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
-public class Conversation extends AbstractEntity {
+public class Conversation extends AbstractEntity implements Blockable {
public static final String TABLENAME = "conversations";
public static final int STATUS_AVAILABLE = 0;
@@ -43,6 +46,7 @@ public class Conversation extends AbstractEntity {
public static final String ATTRIBUTE_NEXT_ENCRYPTION = "next_encryption";
public static final String ATTRIBUTE_MUC_PASSWORD = "muc_password";
public static final String ATTRIBUTE_MUTED_TILL = "muted_till";
+ public static final String ATTRIBUTE_LAST_MESSAGE_TRANSMITTED = "last_message_transmitted";
private String name;
private String contactUuid;
@@ -72,6 +76,140 @@ public class Conversation extends AbstractEntity {
private Bookmark bookmark;
+ private boolean messagesLeftOnServer = true;
+
+ public boolean hasMessagesLeftOnServer() {
+ return messagesLeftOnServer;
+ }
+
+ public void setHasMessagesLeftOnServer(boolean value) {
+ this.messagesLeftOnServer = value;
+ }
+
+ public Message findUnsentMessageWithUuid(String uuid) {
+ synchronized(this.messages) {
+ for (final Message message : this.messages) {
+ final int s = message.getStatus();
+ if ((s == Message.STATUS_UNSEND || s == Message.STATUS_WAITING) && message.getUuid().equals(uuid)) {
+ return message;
+ }
+ }
+ }
+ return null;
+ }
+
+ public void findWaitingMessages(OnMessageFound onMessageFound) {
+ synchronized (this.messages) {
+ for(Message message : this.messages) {
+ if (message.getStatus() == Message.STATUS_WAITING) {
+ onMessageFound.onMessageFound(message);
+ }
+ }
+ }
+ }
+
+ public void findMessagesWithFiles(OnMessageFound onMessageFound) {
+ synchronized (this.messages) {
+ for (Message message : this.messages) {
+ if ((message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE)
+ && message.getEncryption() != Message.ENCRYPTION_PGP) {
+ onMessageFound.onMessageFound(message);
+ }
+ }
+ }
+ }
+
+ public Message findMessageWithFileAndUuid(String uuid) {
+ synchronized (this.messages) {
+ for (Message message : this.messages) {
+ if (message.getType() == Message.TYPE_IMAGE
+ && message.getEncryption() != Message.ENCRYPTION_PGP
+ && message.getUuid().equals(uuid)) {
+ return message;
+ }
+ }
+ }
+ return null;
+ }
+
+ public void clearMessages() {
+ synchronized (this.messages) {
+ this.messages.clear();
+ }
+ }
+
+ public void trim() {
+ synchronized (this.messages) {
+ final int size = messages.size();
+ final int maxsize = Config.PAGE_SIZE * Config.MAX_NUM_PAGES;
+ if (size > maxsize) {
+ this.messages.subList(0, size - maxsize).clear();
+ }
+ }
+ }
+
+ public void findUnsentMessagesWithOtrEncryption(OnMessageFound onMessageFound) {
+ synchronized (this.messages) {
+ for (Message message : this.messages) {
+ if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_WAITING)
+ && (message.getEncryption() == Message.ENCRYPTION_OTR)) {
+ onMessageFound.onMessageFound(message);
+ }
+ }
+ }
+ }
+
+ public void findUnsentTextMessages(OnMessageFound onMessageFound) {
+ synchronized (this.messages) {
+ for (Message message : this.messages) {
+ if (message.getType() != Message.TYPE_IMAGE
+ && message.getStatus() == Message.STATUS_UNSEND) {
+ onMessageFound.onMessageFound(message);
+ }
+ }
+ }
+ }
+
+ public Message findSentMessageWithUuid(String uuid) {
+ synchronized (this.messages) {
+ for (Message message : this.messages) {
+ if (uuid.equals(message.getUuid())
+ || (message.getStatus() >= Message.STATUS_SEND && uuid
+ .equals(message.getRemoteMsgId()))) {
+ return message;
+ }
+ }
+ }
+ return null;
+ }
+
+ public void populateWithMessages(final List<Message> messages) {
+ synchronized (this.messages) {
+ messages.clear();
+ messages.addAll(this.messages);
+ }
+ }
+
+ @Override
+ public boolean isBlocked() {
+ return getContact().isBlocked();
+ }
+
+ @Override
+ public boolean isDomainBlocked() {
+ return getContact().isDomainBlocked();
+ }
+
+ @Override
+ public Jid getBlockedJid() {
+ return getContact().getBlockedJid();
+ }
+
+
+ public interface OnMessageFound {
+ public void onMessageFound(final Message message);
+ }
+
public Conversation(final String name, final Account account, final Jid contactJid,
final int mode) {
this(java.util.UUID.randomUUID().toString(), name, null, account
@@ -98,18 +236,11 @@ public class Conversation extends AbstractEntity {
}
}
- public List<Message> getMessages() {
- return messages;
- }
-
public boolean isRead() {
- return (this.messages == null) || (this.messages.size() == 0) || this.messages.get(this.messages.size() - 1).isRead();
- }
+ return (this.messages.size() == 0) || this.messages.get(this.messages.size() - 1).isRead();
+ }
public void markRead() {
- if (this.messages == null) {
- return;
- }
for (int i = this.messages.size() - 1; i >= 0; --i) {
if (messages.get(i).isRead()) {
break;
@@ -119,9 +250,6 @@ public class Conversation extends AbstractEntity {
}
public Message getLatestMarkableMessage() {
- if (this.messages == null) {
- return null;
- }
for (int i = this.messages.size() - 1; i >= 0; --i) {
if (this.messages.get(i).getStatus() <= Message.STATUS_RECEIVED
&& this.messages.get(i).markable) {
@@ -130,13 +258,13 @@ public class Conversation extends AbstractEntity {
} else {
return this.messages.get(i);
}
- }
+ }
}
return null;
}
public Message getLatestMessage() {
- if ((this.messages == null) || (this.messages.size() == 0)) {
+ if (this.messages.size() == 0) {
Message message = new Message(this, "", Message.ENCRYPTION_NONE);
message.setTime(getCreated());
return message;
@@ -158,7 +286,7 @@ public class Conversation extends AbstractEntity {
if (generatedName != null) {
return generatedName;
} else {
- return getContactJid().getLocalpart();
+ return getJid().getLocalpart();
}
}
} else {
@@ -166,10 +294,6 @@ public class Conversation extends AbstractEntity {
}
}
- public String getProfilePhotoString() {
- return this.getContact().getProfilePhoto();
- }
-
public String getAccountUuid() {
return this.accountUuid;
}
@@ -182,11 +306,12 @@ public class Conversation extends AbstractEntity {
return this.account.getRoster().getContact(this.contactJid);
}
- public void setAccount(Account account) {
+ public void setAccount(final Account account) {
this.account = account;
}
- public Jid getContactJid() {
+ @Override
+ public Jid getJid() {
return this.contactJid;
}
@@ -213,14 +338,14 @@ public class Conversation extends AbstractEntity {
}
public static Conversation fromCursor(Cursor cursor) {
- Jid jid;
- try {
- jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID)));
- } catch (final InvalidJidException e) {
- // Borked DB..
- jid = null;
- }
- return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
+ Jid jid;
+ try {
+ jid = Jid.fromString(cursor.getString(cursor.getColumnIndex(CONTACTJID)));
+ } catch (final InvalidJidException e) {
+ // Borked DB..
+ jid = null;
+ }
+ return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
cursor.getString(cursor.getColumnIndex(NAME)),
cursor.getString(cursor.getColumnIndex(CONTACT)),
cursor.getString(cursor.getColumnIndex(ACCOUNT)),
@@ -247,9 +372,9 @@ public class Conversation extends AbstractEntity {
if (this.otrSession != null) {
return this.otrSession;
} else {
- final SessionID sessionId = new SessionID(this.getContactJid().toBareJid().toString(),
- presence,
- "xmpp");
+ final SessionID sessionId = new SessionID(this.getJid().toBareJid().toString(),
+ presence,
+ "xmpp");
this.otrSession = new SessionImpl(sessionId, getAccount().getOtrEngine());
try {
if (sendStart) {
@@ -288,7 +413,7 @@ public class Conversation extends AbstractEntity {
} catch (OtrException e) {
this.resetOtrSession();
}
- }
+ }
}
public boolean endOtrIfNeeded() {
@@ -315,30 +440,29 @@ public class Conversation extends AbstractEntity {
return this.otrSession != null;
}
- public String getOtrFingerprint() {
+ public synchronized String getOtrFingerprint() {
if (this.otrFingerprint == null) {
try {
- if (getOtrSession() == null) {
- return "";
+ if (getOtrSession() == null || getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) {
+ return null;
}
- DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession()
- .getRemotePublicKey();
- StringBuilder builder = new StringBuilder(
- new OtrCryptoEngineImpl().getFingerprint(remotePubKey));
- builder.insert(8, " ");
- builder.insert(17, " ");
- builder.insert(26, " ");
- builder.insert(35, " ");
- this.otrFingerprint = builder.toString();
- } catch (final OtrCryptoException ignored) {
-
+ DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession().getRemotePublicKey();
+ this.otrFingerprint = getAccount().getOtrEngine().getFingerprint(remotePubKey);
+ } catch (final OtrCryptoException | UnsupportedOperationException ignored) {
+ return null;
}
}
return this.otrFingerprint;
}
- public void verifyOtrFingerprint() {
- getContact().addOtrFingerprint(getOtrFingerprint());
+ public boolean verifyOtrFingerprint() {
+ final String fingerprint = getOtrFingerprint();
+ if (fingerprint != null) {
+ getContact().addOtrFingerprint(fingerprint);
+ return true;
+ } else {
+ return false;
+ }
}
public boolean isOtrFingerprintVerified() {
@@ -450,9 +574,11 @@ public class Conversation extends AbstractEntity {
}
public boolean hasDuplicateMessage(Message message) {
- for (int i = this.getMessages().size() - 1; i >= 0; --i) {
- if (this.messages.get(i).equals(message)) {
- return true;
+ synchronized (this.messages) {
+ for (int i = this.messages.size() - 1; i >= 0; --i) {
+ if (this.messages.get(i).equals(message)) {
+ return true;
+ }
}
}
return false;
@@ -460,7 +586,7 @@ public class Conversation extends AbstractEntity {
public Message findSentMessageWithBody(String body) {
synchronized (this.messages) {
- for (int i = this.getMessages().size() - 1; i >= 0; --i) {
+ for (int i = this.messages.size() - 1; i >= 0; --i) {
Message message = this.messages.get(i);
if ((message.getStatus() == Message.STATUS_UNSEND || message.getStatus() == Message.STATUS_SEND) && message.getBody() != null && message.getBody().equals(body)) {
return message;
@@ -470,6 +596,31 @@ public class Conversation extends AbstractEntity {
}
}
+ public boolean setLastMessageTransmitted(long value) {
+ long before = getLastMessageTransmitted();
+ if (value - before > 1000) {
+ this.setAttribute(ATTRIBUTE_LAST_MESSAGE_TRANSMITTED, String.valueOf(value));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public long getLastMessageTransmitted() {
+ long timestamp = getLongAttribute(ATTRIBUTE_LAST_MESSAGE_TRANSMITTED,0);
+ if (timestamp == 0) {
+ synchronized (this.messages) {
+ for(int i = this.messages.size() - 1; i >= 0; --i) {
+ Message message = this.messages.get(i);
+ if (message.getStatus() == Message.STATUS_RECEIVED) {
+ return message.getTimeSent();
+ }
+ }
+ }
+ }
+ return timestamp;
+ }
+
public void setMutedTill(long value) {
this.setAttribute(ATTRIBUTE_MUTED_TILL, String.valueOf(value));
}
@@ -535,12 +686,32 @@ public class Conversation extends AbstractEntity {
}
}
+ public void sort() {
+ synchronized (this.messages) {
+ Collections.sort(this.messages, new Comparator<Message>() {
+ @Override
+ public int compare(Message left, Message right) {
+ if (left.getTimeSent() < right.getTimeSent()) {
+ return -1;
+ } else if (left.getTimeSent() > right.getTimeSent()) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ });
+ for(Message message : this.messages) {
+ message.untie();
+ }
+ }
+ }
+
public class Smp {
public static final int STATUS_NONE = 0;
public static final int STATUS_CONTACT_REQUESTED = 1;
public static final int STATUS_WE_REQUESTED = 2;
public static final int STATUS_FAILED = 3;
- public static final int STATUS_FINISHED = 4;
+ public static final int STATUS_VERIFIED = 4;
public String secret = null;
public String hint = null;
diff --git a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java
index 25f33907..7c8f95d1 100644
--- a/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java
+++ b/src/main/java/eu/siacs/conversations/entities/DownloadableFile.java
@@ -56,12 +56,16 @@ public class DownloadableFile extends File {
public String getMimeType() {
String path = this.getAbsolutePath();
- String mime = URLConnection.guessContentTypeFromName(path);
- if (mime != null) {
- return mime;
- } else if (mime == null && path.endsWith(".webp")) {
- return "image/webp";
- } else {
+ try {
+ String mime = URLConnection.guessContentTypeFromName(path.replace("#",""));
+ if (mime != null) {
+ return mime;
+ } else if (mime == null && path.endsWith(".webp")) {
+ return "image/webp";
+ } else {
+ return "";
+ }
+ } catch (final StringIndexOutOfBoundsException e) {
return "";
}
}
diff --git a/src/main/java/eu/siacs/conversations/entities/ListItem.java b/src/main/java/eu/siacs/conversations/entities/ListItem.java
index db9fbc37..efc1c2b9 100644
--- a/src/main/java/eu/siacs/conversations/entities/ListItem.java
+++ b/src/main/java/eu/siacs/conversations/entities/ListItem.java
@@ -12,10 +12,10 @@ public interface ListItem extends Comparable<ListItem> {
public List<Tag> getTags();
public final class Tag {
- private String name;
- private int color;
+ private final String name;
+ private final int color;
- public Tag(String name, int color) {
+ public Tag(final String name, final int color) {
this.name = name;
this.color = color;
}
@@ -28,4 +28,6 @@ public interface ListItem extends Comparable<ListItem> {
return this.name;
}
}
+
+ public boolean match(final String needle);
}
diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java
index 47861d06..b5a1897d 100644
--- a/src/main/java/eu/siacs/conversations/entities/Message.java
+++ b/src/main/java/eu/siacs/conversations/entities/Message.java
@@ -45,6 +45,7 @@ public class Message extends AbstractEntity {
public static String STATUS = "status";
public static String TYPE = "type";
public static String REMOTE_MSG_ID = "remoteMsgId";
+ public static String SERVER_MSG_ID = "serverMsgId";
public static String RELATIVE_FILE_PATH = "relativeFilePath";
public boolean markable = false;
protected String conversationUuid;
@@ -59,6 +60,7 @@ public class Message extends AbstractEntity {
protected String relativeFilePath;
protected boolean read = true;
protected String remoteMsgId = null;
+ protected String serverMsgId = null;
protected Conversation conversation = null;
protected Downloadable downloadable = null;
private Message mNextMessage = null;
@@ -75,7 +77,7 @@ public class Message extends AbstractEntity {
public Message(Conversation conversation, String body, int encryption, int status) {
this(java.util.UUID.randomUUID().toString(),
conversation.getUuid(),
- conversation.getContactJid() == null ? null : conversation.getContactJid().toBareJid(),
+ conversation.getJid() == null ? null : conversation.getJid().toBareJid(),
null,
body,
System.currentTimeMillis(),
@@ -83,13 +85,15 @@ public class Message extends AbstractEntity {
status,
TYPE_TEXT,
null,
+ null,
null);
this.conversation = conversation;
}
private Message(final String uuid, final String conversationUUid, final Jid counterpart,
- final Jid trueCounterpart, final String body, final long timeSent,
- final int encryption, final int status, final int type, final String remoteMsgId, final String relativeFilePath) {
+ final Jid trueCounterpart, final String body, final long timeSent,
+ final int encryption, final int status, final int type, final String remoteMsgId,
+ final String relativeFilePath, final String serverMsgId) {
this.uuid = uuid;
this.conversationUuid = conversationUUid;
this.counterpart = counterpart;
@@ -101,6 +105,7 @@ public class Message extends AbstractEntity {
this.type = type;
this.remoteMsgId = remoteMsgId;
this.relativeFilePath = relativeFilePath;
+ this.serverMsgId = serverMsgId;
}
public static Message fromCursor(Cursor cursor) {
@@ -136,7 +141,8 @@ public class Message extends AbstractEntity {
cursor.getInt(cursor.getColumnIndex(STATUS)),
cursor.getInt(cursor.getColumnIndex(TYPE)),
cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)),
- cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)));
+ cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)),
+ cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)));
}
public static Message createStatusMessage(Conversation conversation) {
@@ -168,6 +174,7 @@ public class Message extends AbstractEntity {
values.put(TYPE, type);
values.put(REMOTE_MSG_ID, remoteMsgId);
values.put(RELATIVE_FILE_PATH, relativeFilePath);
+ values.put(SERVER_MSG_ID,serverMsgId);
return values;
}
@@ -199,7 +206,7 @@ public class Message extends AbstractEntity {
return null;
} else {
return this.conversation.getAccount().getRoster()
- .getContactFromRoster(this.trueCounterpart);
+ .getContactFromRoster(this.trueCounterpart);
}
}
}
@@ -248,6 +255,14 @@ public class Message extends AbstractEntity {
this.remoteMsgId = id;
}
+ public String getServerMsgId() {
+ return this.serverMsgId;
+ }
+
+ public void setServerMsgId(String id) {
+ this.serverMsgId = id;
+ }
+
public boolean isRead() {
return this.read;
}
@@ -293,38 +308,43 @@ public class Message extends AbstractEntity {
}
public boolean equals(Message message) {
- return (this.remoteMsgId != null) && (this.body != null) && (this.counterpart != null) && this.remoteMsgId.equals(message.getRemoteMsgId()) && this.body.equals(message.getBody()) && this.counterpart.equals(message.getCounterpart());
+ if (this.serverMsgId != null && message.getServerMsgId() != null) {
+ return this.serverMsgId.equals(message.getServerMsgId());
+ } else {
+ return this.body != null
+ && this.counterpart != null
+ && ((this.remoteMsgId != null && this.remoteMsgId.equals(message.getRemoteMsgId()))
+ || this.uuid.equals(message.getRemoteMsgId())) && this.body.equals(message.getBody())
+ && this.counterpart.equals(message.getCounterpart());
+ }
}
public Message next() {
- if (this.mNextMessage == null) {
- synchronized (this.conversation.messages) {
+ synchronized (this.conversation.messages) {
+ if (this.mNextMessage == null) {
int index = this.conversation.messages.indexOf(this);
- if (index < 0
- || index >= this.conversation.getMessages().size() - 1) {
+ if (index < 0 || index >= this.conversation.messages.size() - 1) {
this.mNextMessage = null;
} else {
- this.mNextMessage = this.conversation.messages
- .get(index + 1);
+ this.mNextMessage = this.conversation.messages.get(index + 1);
}
}
+ return this.mNextMessage;
}
- return this.mNextMessage;
}
public Message prev() {
- if (this.mPreviousMessage == null) {
- synchronized (this.conversation.messages) {
+ synchronized (this.conversation.messages) {
+ if (this.mPreviousMessage == null) {
int index = this.conversation.messages.indexOf(this);
if (index <= 0 || index > this.conversation.messages.size()) {
this.mPreviousMessage = null;
} else {
- this.mPreviousMessage = this.conversation.messages
- .get(index - 1);
+ this.mPreviousMessage = this.conversation.messages.get(index - 1);
}
}
+ return this.mPreviousMessage;
}
- return this.mPreviousMessage;
}
public boolean mergeable(final Message message) {
@@ -368,7 +388,7 @@ public class Message extends AbstractEntity {
if (!url.getProtocol().equalsIgnoreCase("http")
&& !url.getProtocol().equalsIgnoreCase("https")) {
return false;
- }
+ }
if (url.getPath() == null) {
return false;
}
@@ -382,14 +402,14 @@ public class Message extends AbstractEntity {
String[] extensionParts = filename.split("\\.");
if (extensionParts.length == 2
&& Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains(
- extensionParts[extensionParts.length - 1])) {
+ extensionParts[extensionParts.length - 1])) {
return true;
} else if (extensionParts.length == 3
&& Arrays
.asList(Downloadable.VALID_CRYPTO_EXTENSIONS)
.contains(extensionParts[extensionParts.length - 1])
&& Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains(
- extensionParts[extensionParts.length - 2])) {
+ extensionParts[extensionParts.length - 2])) {
return true;
} else {
return false;
@@ -493,6 +513,15 @@ public class Message extends AbstractEntity {
}
}
+ public void untie() {
+ this.mNextMessage = null;
+ this.mPreviousMessage = null;
+ }
+
+ public boolean isFileOrImage() {
+ return type == TYPE_FILE || type == TYPE_IMAGE;
+ }
+
public class ImageParams {
public URL url;
public long size = 0;
diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
index c8706fc9..97a63532 100644
--- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
@@ -80,20 +80,20 @@ public class MucOptions {
public void setRole(String role) {
role = role.toLowerCase();
- switch (role) {
- case "moderator":
- this.role = ROLE_MODERATOR;
- break;
- case "participant":
- this.role = ROLE_PARTICIPANT;
- break;
- case "visitor":
- this.role = ROLE_VISITOR;
- break;
- default:
- this.role = ROLE_NONE;
- break;
- }
+ switch (role) {
+ case "moderator":
+ this.role = ROLE_MODERATOR;
+ break;
+ case "participant":
+ this.role = ROLE_PARTICIPANT;
+ break;
+ case "visitor":
+ this.role = ROLE_VISITOR;
+ break;
+ default:
+ this.role = ROLE_NONE;
+ break;
+ }
}
public int getAffiliation() {
@@ -164,7 +164,7 @@ public class MucOptions {
}
public void processPacket(PresencePacket packet, PgpEngine pgp) {
- final Jid from = packet.getFrom();
+ final Jid from = packet.getFrom();
if (!from.isBareJid()) {
final String name = from.getResourcepart();
final String type = packet.getAttribute("type");
@@ -179,7 +179,7 @@ public class MucOptions {
user.setAffiliation(item.getAttribute("affiliation"));
user.setRole(item.getAttribute("role"));
user.setJid(item.getAttributeAsJid("jid"));
- if (codes.contains(STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(this.conversation.getContactJid())) {
+ if (codes.contains(STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(this.conversation.getJid())) {
this.isOnline = true;
this.error = ERROR_NO_ERROR;
self = user;
@@ -204,14 +204,14 @@ public class MucOptions {
msg = "";
}
user.setPgpKeyId(pgp.fetchKeyId(account, msg,
- signed.getContent()));
+ signed.getContent()));
}
}
}
}
} else if (type.equals("unavailable")) {
if (codes.contains(STATUS_CODE_SELF_PRESENCE) ||
- packet.getFrom().equals(this.conversation.getContactJid())) {
+ packet.getFrom().equals(this.conversation.getJid())) {
if (codes.contains(STATUS_CODE_CHANGED_NICK)) {
this.mNickChangingInProgress = true;
} else if (codes.contains(STATUS_CODE_KICKED)) {
@@ -282,8 +282,8 @@ public class MucOptions {
&& conversation.getBookmark().getNick() != null
&& !conversation.getBookmark().getNick().isEmpty()) {
return conversation.getBookmark().getNick();
- } else if (!conversation.getContactJid().isBareJid()) {
- return conversation.getContactJid().getResourcepart();
+ } else if (!conversation.getJid().isBareJid()) {
+ return conversation.getJid().getResourcepart();
} else {
return account.getUsername();
}
@@ -334,14 +334,14 @@ public class MucOptions {
public String createNameFromParticipants() {
if (users.size() >= 2) {
List<String> names = new ArrayList<String>();
- for (User user : users) {
- Contact contact = user.getContact();
- if (contact != null && !contact.getDisplayName().isEmpty()) {
- names.add(contact.getDisplayName().split("\\s+")[0]);
- } else {
- names.add(user.getName());
- }
+ for (User user : users) {
+ Contact contact = user.getContact();
+ if (contact != null && !contact.getDisplayName().isEmpty()) {
+ names.add(contact.getDisplayName().split("\\s+")[0]);
+ } else {
+ names.add(user.getName());
}
+ }
StringBuilder builder = new StringBuilder();
for (int i = 0; i < names.size(); ++i) {
builder.append(names.get(i));
@@ -388,12 +388,12 @@ public class MucOptions {
}
public Jid createJoinJid(String nick) {
- try {
- return Jid.fromString(this.conversation.getContactJid().toBareJid().toString() + "/"+nick);
- } catch (final InvalidJidException e) {
- return null;
- }
- }
+ try {
+ return Jid.fromString(this.conversation.getJid().toBareJid().toString() + "/"+nick);
+ } catch (final InvalidJidException e) {
+ return null;
+ }
+ }
public Jid getTrueCounterpart(String counterpart) {
for (User user : this.getUsers()) {
diff --git a/src/main/java/eu/siacs/conversations/entities/Roster.java b/src/main/java/eu/siacs/conversations/entities/Roster.java
index 12a89cec..1a81a419 100644
--- a/src/main/java/eu/siacs/conversations/entities/Roster.java
+++ b/src/main/java/eu/siacs/conversations/entities/Roster.java
@@ -7,7 +7,7 @@ import java.util.concurrent.ConcurrentHashMap;
import eu.siacs.conversations.xmpp.jid.Jid;
public class Roster {
- Account account;
+ final Account account;
final ConcurrentHashMap<String, Contact> contacts = new ConcurrentHashMap<>();
private String version = null;
@@ -19,7 +19,7 @@ public class Roster {
if (jid == null) {
return null;
}
- Contact contact = contacts.get(jid.toBareJid().toString());
+ final Contact contact = contacts.get(jid.toBareJid().toString());
if (contact != null && contact.showInRoster()) {
return contact;
} else {
@@ -32,7 +32,7 @@ public class Roster {
if (contacts.containsKey(bareJid.toString())) {
return contacts.get(bareJid.toString());
} else {
- Contact contact = new Contact(bareJid);
+ final Contact contact = new Contact(bareJid);
contact.setAccount(account);
contacts.put(bareJid.toString(), contact);
return contact;
@@ -46,13 +46,13 @@ public class Roster {
}
public void markAllAsNotInRoster() {
- for (Contact contact : getContacts()) {
+ for (final Contact contact : getContacts()) {
contact.resetOption(Contact.Options.IN_ROSTER);
}
}
public void clearSystemAccounts() {
- for (Contact contact : getContacts()) {
+ for (final Contact contact : getContacts()) {
contact.setPhotoUri(null);
contact.setSystemName(null);
contact.setSystemAccount(null);