aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/thedevstack/conversationsplus/entities
diff options
context:
space:
mode:
authorlookshe <github@lookshe.org>2015-08-11 20:30:11 +0200
committerlookshe <github@lookshe.org>2015-08-11 20:30:11 +0200
commit639babfdb5289a035e0a22bf607c068caefa5c99 (patch)
tree6a11aa6a189f3a5988d5d1e1c733d2027bc3494f /src/main/java/de/thedevstack/conversationsplus/entities
parent1b5966ae3b1108c88a810d7d32a0aefa8812d11f (diff)
parent8fd688ca96005152be754eeba1be72c7c0aab9ad (diff)
Merge branch 'trz/rebase' into trz/rename
Conflicts: build.gradle src/main/java/de/thedevstack/conversationsplus/crypto/OtrEngine.java src/main/java/de/thedevstack/conversationsplus/entities/Account.java src/main/java/de/thedevstack/conversationsplus/entities/Contact.java src/main/java/de/thedevstack/conversationsplus/entities/Downloadable.java src/main/java/de/thedevstack/conversationsplus/entities/DownloadableFile.java src/main/java/de/thedevstack/conversationsplus/entities/DownloadablePlaceholder.java src/main/java/de/thedevstack/conversationsplus/entities/Message.java src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java src/main/java/de/thedevstack/conversationsplus/http/HttpConnection.java src/main/java/de/thedevstack/conversationsplus/http/HttpConnectionManager.java src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java src/main/java/de/thedevstack/conversationsplus/parser/PresenceParser.java src/main/java/de/thedevstack/conversationsplus/persistance/DatabaseBackend.java src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java src/main/java/de/thedevstack/conversationsplus/ui/StartConversationActivity.java src/main/java/de/thedevstack/conversationsplus/ui/adapter/AccountAdapter.java src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java src/main/java/de/thedevstack/conversationsplus/ui/adapter/ListItemAdapter.java src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java src/main/java/de/thedevstack/conversationsplus/utils/UIHelper.java src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnectionManager.java src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleInbandTransport.java src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleSocks5Transport.java src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/MessagePacket.java src/main/java/eu/siacs/conversations/crypto/OtrEngine.java src/main/java/eu/siacs/conversations/crypto/OtrService.java src/main/java/eu/siacs/conversations/entities/DownloadablePlaceholder.java src/main/java/eu/siacs/conversations/entities/TransferablePlaceholder.java src/main/java/eu/siacs/conversations/http/HttpConnection.java src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java src/main/res/layout/activity_about.xml
Diffstat (limited to 'src/main/java/de/thedevstack/conversationsplus/entities')
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Account.java32
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Bookmark.java16
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Contact.java42
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java16
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Downloadable.java28
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/DownloadableFile.java17
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Message.java339
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/MucOptions.java2
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Roster.java17
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/Transferable.java28
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/entities/TransferablePlaceholder.java (renamed from src/main/java/de/thedevstack/conversationsplus/entities/DownloadablePlaceholder.java)9
11 files changed, 328 insertions, 218 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Account.java b/src/main/java/de/thedevstack/conversationsplus/entities/Account.java
index 1b6539da..530adf06 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Account.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Account.java
@@ -44,6 +44,10 @@ public class Account extends AbstractEntity {
public static final int OPTION_REGISTER = 2;
public static final int OPTION_USECOMPRESSION = 3;
+ public boolean httpUploadAvailable() {
+ return xmppConnection != null && xmppConnection.getFeatures().httpUpload();
+ }
+
public static enum State {
DISABLED,
OFFLINE,
@@ -117,7 +121,7 @@ public class Account extends AbstractEntity {
protected JSONObject keys = new JSONObject();
protected String avatar;
protected boolean online = false;
- private OtrEngine otrEngine = null;
+ private OtrService mOtrService = null;
private XmppConnection xmppConnection = null;
private long mEndGracePeriod = 0L;
private String otrFingerprint;
@@ -229,11 +233,17 @@ public class Account extends AbstractEntity {
return jid.getResourcepart();
}
- public void setResource(final String resource) {
- try {
- jid = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), resource);
- } catch (final InvalidJidException ignored) {
+ public boolean setResource(final String resource) {
+ final String oldResource = jid.getResourcepart();
+ if (oldResource == null || !oldResource.equals(resource)) {
+ try {
+ jid = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), resource);
+ return true;
+ } catch (final InvalidJidException ignored) {
+ return true;
+ }
}
+ return false;
}
public Jid getJid() {
@@ -267,12 +277,12 @@ public class Account extends AbstractEntity {
return values;
}
- public void initOtrEngine(final XmppConnectionService context) {
- this.otrEngine = new OtrEngine(context, this);
+ public void initAccountServices(final XmppConnectionService context) {
+ this.mOtrService = new OtrService(context, this);
}
- public OtrEngine getOtrEngine() {
- return this.otrEngine;
+ public OtrService getOtrService() {
+ return this.mOtrService;
}
public XmppConnection getXmppConnection() {
@@ -286,10 +296,10 @@ public class Account extends AbstractEntity {
public String getOtrFingerprint() {
if (this.otrFingerprint == null) {
try {
- if (this.otrEngine == null) {
+ if (this.mOtrService == null) {
return null;
}
- final PublicKey publicKey = this.otrEngine.getPublicKey();
+ final PublicKey publicKey = this.mOtrService.getPublicKey();
if (publicKey == null || !(publicKey instanceof DSAPublicKey)) {
return null;
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Bookmark.java b/src/main/java/de/thedevstack/conversationsplus/entities/Bookmark.java
index 8a6b1405..9e67bf2d 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Bookmark.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Bookmark.java
@@ -2,6 +2,8 @@ package de.thedevstack.conversationsplus.entities;
import android.graphics.Color;
+import android.graphics.Color;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -82,12 +84,7 @@ public class Bookmark extends Element implements ListItem {
}
public String getNick() {
- Element nick = this.findChild("nick");
- if (nick != null) {
- return nick.getContent();
- } else {
- return null;
- }
+ return this.findChildContent("nick");
}
public void setNick(String nick) {
@@ -103,12 +100,7 @@ public class Bookmark extends Element implements ListItem {
}
public String getPassword() {
- Element password = this.findChild("password");
- if (password != null) {
- return password.getContent();
- } else {
- return null;
- }
+ return this.findChildContent("password");
}
public void setPassword(String password) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Contact.java b/src/main/java/de/thedevstack/conversationsplus/entities/Contact.java
index c4f1c9eb..d72a1197 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Contact.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Contact.java
@@ -16,6 +16,7 @@ import de.thedevstack.conversationsplus.utils.UIHelper;
import de.thedevstack.conversationsplus.xml.Element;
import de.thedevstack.conversationsplus.xmpp.jid.InvalidJidException;
import de.thedevstack.conversationsplus.xmpp.jid.Jid;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
public class Contact implements ListItem, Blockable {
public static final String TABLENAME = "contacts";
@@ -41,11 +42,11 @@ public class Contact implements ListItem, Blockable {
protected int subscription = 0;
protected String systemAccount;
protected String photoUri;
- protected String avatar;
protected JSONObject keys = new JSONObject();
protected JSONArray groups = new JSONArray();
protected Presences presences = new Presences();
protected Account account;
+ protected Avatar avatar;
public Contact(final String account, final String systemName, final String serverName,
final Jid jid, final int subscription, final String photoUri,
@@ -62,7 +63,11 @@ public class Contact implements ListItem, Blockable {
} catch (JSONException e) {
this.keys = new JSONObject();
}
- this.avatar = avatar;
+ if (avatar != null) {
+ this.avatar = new Avatar();
+ this.avatar.sha1sum = avatar;
+ this.avatar.origin = Avatar.Origin.VCARD; //always assume worst
+ }
try {
this.groups = (groups == null ? new JSONArray() : new JSONArray(groups));
} catch (JSONException e) {
@@ -136,10 +141,10 @@ public class Contact implements ListItem, Blockable {
tags.add(new Tag("away", 0xffff9800));
break;
case Presences.XA:
- tags.add(new Tag("not available", 0xffe51c23));
+ tags.add(new Tag("not available", 0xfff44336));
break;
case Presences.DND:
- tags.add(new Tag("dnd", 0xffe51c23));
+ tags.add(new Tag("dnd", 0xfff44336));
break;
}
if (isBlocked()) {
@@ -193,7 +198,7 @@ public class Contact implements ListItem, Blockable {
values.put(SYSTEMACCOUNT, systemAccount);
values.put(PHOTOURI, photoUri);
values.put(KEYS, keys.toString());
- values.put(AVATAR, avatar);
+ values.put(AVATAR, avatar == null ? null : avatar.getFilename());
values.put(LAST_PRESENCE, lastseen.presence);
values.put(LAST_TIME, lastseen.time);
values.put(GROUPS, groups.toString());
@@ -238,8 +243,16 @@ public class Contact implements ListItem, Blockable {
return this.presences.getMostAvailableStatus();
}
- public void setPhotoUri(String uri) {
- this.photoUri = uri;
+ public boolean setPhotoUri(String uri) {
+ if (uri != null && !uri.equals(this.photoUri)) {
+ this.photoUri = uri;
+ return true;
+ } else if (this.photoUri != null && uri == null) {
+ this.photoUri = null;
+ return true;
+ } else {
+ return false;
+ }
}
public void setServerName(String serverName) {
@@ -417,17 +430,20 @@ public class Contact implements ListItem, Blockable {
return getJid().toDomainJid();
}
- public boolean setAvatar(String filename) {
- if (this.avatar != null && this.avatar.equals(filename)) {
+ public boolean setAvatar(Avatar avatar) {
+ if (this.avatar != null && this.avatar.equals(avatar)) {
return false;
} else {
- this.avatar = filename;
+ if (this.avatar != null && this.avatar.origin == Avatar.Origin.PEP && avatar.origin == Avatar.Origin.VCARD) {
+ return false;
+ }
+ this.avatar = avatar;
return true;
}
}
public String getAvatar() {
- return this.avatar;
+ return avatar == null ? null : avatar.getFilename();
}
public boolean deleteOtrFingerprint(String fingerprint) {
@@ -484,6 +500,10 @@ public class Contact implements ListItem, Blockable {
}
}
+ public boolean isSelf() {
+ return account.getJid().toBareJid().equals(getJid().toBareJid());
+ }
+
public static class Lastseen {
public long time;
public String presence;
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java b/src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java
index 37cbff46..81c2eb4b 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Conversation.java
@@ -16,6 +16,7 @@ import java.security.interfaces.DSAPublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
import de.thedevstack.conversationsplus.Config;
@@ -218,6 +219,11 @@ public class Conversation extends AbstractEntity implements Blockable {
messages.clear();
messages.addAll(this.messages);
}
+ for(Iterator<Message> iterator = messages.iterator(); iterator.hasNext();) {
+ if (iterator.next().wasMergedIntoPrevious()) {
+ iterator.remove();
+ }
+ }
}
@Override
@@ -243,6 +249,12 @@ public class Conversation extends AbstractEntity implements Blockable {
this.mLastReceivedOtrMessageId = id;
}
+ public int countMessages() {
+ synchronized (this.messages) {
+ return this.messages.size();
+ }
+ }
+
public interface OnMessageFound {
public void onMessageFound(final Message message);
@@ -413,7 +425,7 @@ public class Conversation extends AbstractEntity implements Blockable {
final SessionID sessionId = new SessionID(this.getJid().toBareJid().toString(),
presence,
"xmpp");
- this.otrSession = new SessionImpl(sessionId, getAccount().getOtrEngine());
+ this.otrSession = new SessionImpl(sessionId, getAccount().getOtrService());
try {
if (sendStart) {
this.otrSession.startSession();
@@ -485,7 +497,7 @@ public class Conversation extends AbstractEntity implements Blockable {
return null;
}
DSAPublicKey remotePubKey = (DSAPublicKey) getOtrSession().getRemotePublicKey();
- this.otrFingerprint = getAccount().getOtrEngine().getFingerprint(remotePubKey);
+ this.otrFingerprint = getAccount().getOtrService().getFingerprint(remotePubKey);
} catch (final OtrCryptoException | UnsupportedOperationException ignored) {
return null;
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Downloadable.java b/src/main/java/de/thedevstack/conversationsplus/entities/Downloadable.java
deleted file mode 100644
index 20169dc8..00000000
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Downloadable.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package de.thedevstack.conversationsplus.entities;
-
-public interface Downloadable {
-
- public final String[] VALID_IMAGE_EXTENSIONS = {"webp", "jpeg", "jpg", "png", "jpe"};
- public final String[] VALID_CRYPTO_EXTENSIONS = {"pgp", "gpg", "otr"};
-
- public static final int STATUS_UNKNOWN = 0x200;
- public static final int STATUS_CHECKING = 0x201;
- public static final int STATUS_FAILED = 0x202;
- public static final int STATUS_OFFER = 0x203;
- public static final int STATUS_DOWNLOADING = 0x204;
- public static final int STATUS_DELETED = 0x205;
- public static final int STATUS_OFFER_CHECK_FILESIZE = 0x206;
- public static final int STATUS_UPLOADING = 0x207;
-
- public boolean start();
-
- public int getStatus();
-
- public long getFileSize();
-
- public int getProgress();
-
- public String getMimeType();
-
- public void cancel();
-}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/DownloadableFile.java b/src/main/java/de/thedevstack/conversationsplus/entities/DownloadableFile.java
index 7566c199..9a677cd0 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/DownloadableFile.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/DownloadableFile.java
@@ -20,6 +20,8 @@ import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.utils.MimeUtils;
+
import android.util.Log;
public class DownloadableFile extends File {
@@ -56,16 +58,11 @@ public class DownloadableFile extends File {
public String getMimeType() {
String path = this.getAbsolutePath();
- 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) {
+ int start = path.lastIndexOf('.') + 1;
+ if (start < path.length()) {
+ String mime = MimeUtils.guessMimeTypeFromExtension(path.substring(start));
+ return mime == null ? "" : mime;
+ } else {
return "";
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Message.java b/src/main/java/de/thedevstack/conversationsplus/entities/Message.java
index cd7556b3..68b47578 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Message.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Message.java
@@ -9,6 +9,8 @@ import java.util.Arrays;
import de.thedevstack.conversationsplus.Config;
import de.thedevstack.conversationsplus.utils.GeoHelper;
+import de.thedevstack.conversationsplus.utils.MimeUtils;
+import de.thedevstack.conversationsplus.utils.UIHelper;
import de.thedevstack.conversationsplus.xmpp.jid.InvalidJidException;
import de.thedevstack.conversationsplus.xmpp.jid.Jid;
@@ -16,6 +18,8 @@ public class Message extends AbstractEntity {
public static final String TABLENAME = "messages";
+ public static final String MERGE_SEPARATOR = " \u200B\n\n";
+
public static final int STATUS_RECEIVED = 0;
public static final int STATUS_UNSEND = 1;
public static final int STATUS_SEND = 2;
@@ -66,7 +70,7 @@ public class Message extends AbstractEntity {
protected String remoteMsgId = null;
protected String serverMsgId = null;
protected Conversation conversation = null;
- protected Downloadable downloadable = null;
+ protected Transferable transferable = null;
private Message mNextMessage = null;
private Message mPreviousMessage = null;
@@ -95,9 +99,9 @@ public class Message extends AbstractEntity {
}
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 String serverMsgId) {
+ 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;
@@ -179,7 +183,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);
+ values.put(SERVER_MSG_ID, serverMsgId);
return values;
}
@@ -211,7 +215,7 @@ public class Message extends AbstractEntity {
return null;
} else {
return this.conversation.getAccount().getRoster()
- .getContactFromRoster(this.trueCounterpart);
+ .getContactFromRoster(this.trueCounterpart);
}
}
}
@@ -304,12 +308,12 @@ public class Message extends AbstractEntity {
this.trueCounterpart = trueCounterpart;
}
- public Downloadable getDownloadable() {
- return this.downloadable;
+ public Transferable getTransferable() {
+ return this.transferable;
}
- public void setDownloadable(Downloadable downloadable) {
- this.downloadable = downloadable;
+ public void setTransferable(Transferable transferable) {
+ this.transferable = transferable;
}
public boolean equals(Message message) {
@@ -317,15 +321,25 @@ public class Message extends AbstractEntity {
return this.serverMsgId.equals(message.getServerMsgId());
} else if (this.body == null || this.counterpart == null) {
return false;
- } else if (message.getRemoteMsgId() != null) {
- return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid))
- && this.counterpart.equals(message.getCounterpart())
- && this.body.equals(message.getBody());
} else {
- return this.remoteMsgId == null
- && this.counterpart.equals(message.getCounterpart())
- && this.body.equals(message.getBody())
- && Math.abs(this.getTimeSent() - message.getTimeSent()) < Config.PING_TIMEOUT * 500;
+ String body, otherBody;
+ if (this.hasFileOnRemoteHost()) {
+ body = getFileParams().url.toString();
+ otherBody = message.body == null ? null : message.body.trim();
+ } else {
+ body = this.body;
+ otherBody = message.body;
+ }
+ if (message.getRemoteMsgId() != null) {
+ return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid))
+ && this.counterpart.equals(message.getCounterpart())
+ && body.equals(otherBody);
+ } else {
+ return this.remoteMsgId == null
+ && this.counterpart.equals(message.getCounterpart())
+ && body.equals(otherBody)
+ && Math.abs(this.getTimeSent() - message.getTimeSent()) < Config.MESSAGE_MERGE_WINDOW * 1000;
+ }
}
}
@@ -359,41 +373,43 @@ public class Message extends AbstractEntity {
public boolean mergeable(final Message message) {
return message != null &&
- (message.getType() == Message.TYPE_TEXT &&
- this.getDownloadable() == null &&
- message.getDownloadable() == null &&
- message.getEncryption() != Message.ENCRYPTION_PGP &&
- this.getType() == message.getType() &&
- //this.getStatus() == message.getStatus() &&
- isStatusMergeable(this.getStatus(),message.getStatus()) &&
- this.getEncryption() == message.getEncryption() &&
- this.getCounterpart() != null &&
- this.getCounterpart().equals(message.getCounterpart()) &&
- (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) &&
- !GeoHelper.isGeoUri(message.getBody()) &&
- !GeoHelper.isGeoUri(this.body) &&
- !message.bodyContainsDownloadable() &&
- !this.bodyContainsDownloadable() &&
- !message.getBody().startsWith(ME_COMMAND) &&
- !this.getBody().startsWith(ME_COMMAND)
- );
+ (message.getType() == Message.TYPE_TEXT &&
+ this.getTransferable() == null &&
+ message.getTransferable() == null &&
+ message.getEncryption() != Message.ENCRYPTION_PGP &&
+ this.getType() == message.getType() &&
+ //this.getStatus() == message.getStatus() &&
+ isStatusMergeable(this.getStatus(), message.getStatus()) &&
+ this.getEncryption() == message.getEncryption() &&
+ this.getCounterpart() != null &&
+ this.getCounterpart().equals(message.getCounterpart()) &&
+ (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) &&
+ !GeoHelper.isGeoUri(message.getBody()) &&
+ !GeoHelper.isGeoUri(this.body) &&
+ message.treatAsDownloadable() == Decision.NEVER &&
+ this.treatAsDownloadable() == Decision.NEVER &&
+ !message.getBody().startsWith(ME_COMMAND) &&
+ !this.getBody().startsWith(ME_COMMAND) &&
+ !this.bodyIsHeart() &&
+ !message.bodyIsHeart()
+ );
}
private static boolean isStatusMergeable(int a, int b) {
return a == b || (
- ( a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_UNSEND)
- || (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_SEND)
- || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND)
- || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND_RECEIVED)
- || (a == Message.STATUS_SEND && b == Message.STATUS_UNSEND)
- || (a == Message.STATUS_SEND && b == Message.STATUS_SEND_RECEIVED)
+ (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_UNSEND)
+ || (a == Message.STATUS_SEND_RECEIVED && b == Message.STATUS_SEND)
+ || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND)
+ || (a == Message.STATUS_UNSEND && b == Message.STATUS_SEND_RECEIVED)
+ || (a == Message.STATUS_SEND && b == Message.STATUS_UNSEND)
+ || (a == Message.STATUS_SEND && b == Message.STATUS_SEND_RECEIVED)
);
}
public String getMergedBody() {
final Message next = this.next();
if (this.mergeable(next)) {
- return getBody() + '\n' + next.getMergedBody();
+ return getBody() + MERGE_SEPARATOR + next.getMergedBody();
}
return getBody();
}
@@ -429,119 +445,175 @@ public class Message extends AbstractEntity {
return (status > STATUS_RECEIVED || (contact != null && contact.trusted()));
}
- public boolean bodyContainsDownloadable() {
- /**
- * there are a few cases where spaces result in an unwanted behavior, e.g.
- * "http://upload.mitsu-freunde-bw.de/uploads/2015/03/i43b4bpr8.png /abc.png"
- * or more than one image link in one message.
- */
- if (body.contains(" ")) {
- return false;
- }
- try {
- URL url = new URL(body);
- if (!url.getProtocol().equalsIgnoreCase("http")
- && !url.getProtocol().equalsIgnoreCase("https")) {
- return false;
- }
-
- String sUrlPath = url.getPath();
- if (sUrlPath == null || sUrlPath.isEmpty()) {
+ public boolean fixCounterpart() {
+ Presences presences = conversation.getContact().getPresences();
+ if (counterpart != null && presences.has(counterpart.getResourcepart())) {
+ return true;
+ } else if (presences.size() >= 1) {
+ try {
+ counterpart = Jid.fromParts(conversation.getJid().getLocalpart(),
+ conversation.getJid().getDomainpart(),
+ presences.asStringArray()[0]);
+ return true;
+ } catch (InvalidJidException e) {
+ counterpart = null;
return false;
}
+ } else {
+ counterpart = null;
+ return false;
+ }
+ }
- int iSlashIndex = sUrlPath.lastIndexOf('/') + 1;
+ public enum Decision {
+ MUST,
+ SHOULD,
+ NEVER,
+ }
- String sLastUrlPath = sUrlPath.substring(iSlashIndex).toLowerCase();
+ private static String extractRelevantExtension(URL url) {
+ String path = url.getPath();
+ if (path == null || path.isEmpty()) {
+ return null;
+ }
+ String filename = path.substring(path.lastIndexOf('/') + 1).toLowerCase();
+ String[] extensionParts = filename.split("\\.");
+ if (extensionParts.length == 2) {
+ return extensionParts[extensionParts.length - 1];
+ } else if (extensionParts.length == 3 && Arrays
+ .asList(Transferable.VALID_CRYPTO_EXTENSIONS)
+ .contains(extensionParts[extensionParts.length - 1])) {
+ return extensionParts[extensionParts.length -2];
+ }
+ return null;
+ }
- String[] extensionParts = sLastUrlPath.split("\\.");
- if (extensionParts.length == 2
- && Arrays.asList(Downloadable.VALID_IMAGE_EXTENSIONS).contains(
- 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])) {
- return true;
+ public String getMimeType() {
+ if (relativeFilePath != null) {
+ int start = relativeFilePath.lastIndexOf('.') + 1;
+ if (start < relativeFilePath.length()) {
+ return MimeUtils.guessMimeTypeFromExtension(relativeFilePath.substring(start));
} else {
- return false;
+ return null;
+ }
+ } else {
+ try {
+ return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(body.trim())));
+ } catch (MalformedURLException e) {
+ return null;
}
+ }
+ }
+
+ public Decision treatAsDownloadable() {
+ if (body.trim().contains(" ")) {
+ return Decision.NEVER;
+ }
+ try {
+ URL url = new URL(body);
+ if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) {
+ return Decision.NEVER;
+ }
+ String extension = extractRelevantExtension(url);
+ if (extension == null) {
+ return Decision.NEVER;
+ }
+ String ref = url.getRef();
+ boolean encrypted = ref != null && ref.matches("([A-Fa-f0-9]{2}){48}");
+
+ if (encrypted) {
+ if (MimeUtils.guessMimeTypeFromExtension(extension) != null) {
+ return Decision.MUST;
+ } else {
+ return Decision.NEVER;
+ }
+ } else if (Arrays.asList(Transferable.VALID_IMAGE_EXTENSIONS).contains(extension)
+ || Arrays.asList(Transferable.WELL_KNOWN_EXTENSIONS).contains(extension)) {
+ return Decision.SHOULD;
+ } else {
+ return Decision.NEVER;
+ }
+
} catch (MalformedURLException e) {
- return false;
+ return Decision.NEVER;
}
}
- public ImageParams getImageParams() {
- ImageParams params = getLegacyImageParams();
+ public boolean bodyIsHeart() {
+ return body != null && UIHelper.HEARTS.contains(body.trim());
+ }
+
+ public FileParams getFileParams() {
+ FileParams params = getLegacyFileParams();
if (params != null) {
return params;
}
- params = new ImageParams();
- if (this.downloadable != null) {
- params.size = this.downloadable.getFileSize();
+ params = new FileParams();
+ if (this.transferable != null) {
+ params.size = this.transferable.getFileSize();
}
if (body == null) {
return params;
}
String parts[] = body.split("\\|");
- if (parts.length == 1) {
- try {
- params.size = Long.parseLong(parts[0]);
- } catch (NumberFormatException e) {
- params.origin = parts[0];
+ switch (parts.length) {
+ case 1:
+ try {
+ params.size = Long.parseLong(parts[0]);
+ } catch (NumberFormatException e) {
+ try {
+ params.url = new URL(parts[0]);
+ } catch (MalformedURLException e1) {
+ params.url = null;
+ }
+ }
+ break;
+ case 2:
+ case 4:
try {
params.url = new URL(parts[0]);
} catch (MalformedURLException e1) {
params.url = null;
}
- }
- } else if (parts.length == 3) {
- try {
- params.size = Long.parseLong(parts[0]);
- } catch (NumberFormatException e) {
- params.size = 0;
- }
- try {
- params.width = Integer.parseInt(parts[1]);
- } catch (NumberFormatException e) {
- params.width = 0;
- }
- try {
- params.height = Integer.parseInt(parts[2]);
- } catch (NumberFormatException e) {
- params.height = 0;
- }
- } else if (parts.length == 4) {
- params.origin = parts[0];
- try {
- params.url = new URL(parts[0]);
- } catch (MalformedURLException e1) {
- params.url = null;
- }
- try {
- params.size = Long.parseLong(parts[1]);
- } catch (NumberFormatException e) {
- params.size = 0;
- }
- try {
- params.width = Integer.parseInt(parts[2]);
- } catch (NumberFormatException e) {
- params.width = 0;
- }
- try {
- params.height = Integer.parseInt(parts[3]);
- } catch (NumberFormatException e) {
- params.height = 0;
- }
+ try {
+ params.size = Long.parseLong(parts[1]);
+ } catch (NumberFormatException e) {
+ params.size = 0;
+ }
+ try {
+ params.width = Integer.parseInt(parts[2]);
+ } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
+ params.width = 0;
+ }
+ try {
+ params.height = Integer.parseInt(parts[3]);
+ } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
+ params.height = 0;
+ }
+ break;
+ case 3:
+ try {
+ params.size = Long.parseLong(parts[0]);
+ } catch (NumberFormatException e) {
+ params.size = 0;
+ }
+ try {
+ params.width = Integer.parseInt(parts[1]);
+ } catch (NumberFormatException e) {
+ params.width = 0;
+ }
+ try {
+ params.height = Integer.parseInt(parts[2]);
+ } catch (NumberFormatException e) {
+ params.height = 0;
+ }
+ break;
}
return params;
}
- public ImageParams getLegacyImageParams() {
- ImageParams params = new ImageParams();
+ public FileParams getLegacyFileParams() {
+ FileParams params = new FileParams();
if (body == null) {
return params;
}
@@ -577,11 +649,18 @@ public class Message extends AbstractEntity {
return type == TYPE_FILE || type == TYPE_IMAGE;
}
- public class ImageParams {
+ public boolean hasFileOnRemoteHost() {
+ return isFileOrImage() && getFileParams().url != null;
+ }
+
+ public boolean needsUploading() {
+ return isFileOrImage() && getFileParams().url == null;
+ }
+
+ public class FileParams {
public URL url;
public long size = 0;
public int width = 0;
public int height = 0;
- public String origin;
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/MucOptions.java b/src/main/java/de/thedevstack/conversationsplus/entities/MucOptions.java
index 860643e0..22155f3e 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/MucOptions.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/MucOptions.java
@@ -343,8 +343,6 @@ public class MucOptions {
setError(ERROR_BANNED);
} else if (error != null && error.hasChild("registration-required")) {
setError(ERROR_MEMBERS_ONLY);
- } else {
- setError(ERROR_UNKNOWN);
}
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Roster.java b/src/main/java/de/thedevstack/conversationsplus/entities/Roster.java
index 0c719ed9..b1cb78b4 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/Roster.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Roster.java
@@ -2,6 +2,7 @@ package de.thedevstack.conversationsplus.entities;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import de.thedevstack.conversationsplus.xmpp.jid.Jid;
@@ -55,12 +56,15 @@ public class Roster {
}
}
- public void clearSystemAccounts() {
- for (Contact contact : getContacts()) {
- contact.setPhotoUri(null);
- contact.setSystemName(null);
- contact.setSystemAccount(null);
+ public List<Contact> getWithSystemAccounts() {
+ List<Contact> with = getContacts();
+ for(Iterator<Contact> iterator = with.iterator(); iterator.hasNext();) {
+ Contact contact = iterator.next();
+ if (contact.getSystemAccount() == null) {
+ iterator.remove();
+ }
}
+ return with;
}
public List<Contact> getContacts() {
@@ -70,6 +74,9 @@ public class Roster {
}
public void initContact(final Contact contact) {
+ if (contact == null) {
+ return;
+ }
contact.setAccount(account);
contact.setOption(Contact.Options.IN_ROSTER);
synchronized (this.contacts) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Transferable.java b/src/main/java/de/thedevstack/conversationsplus/entities/Transferable.java
new file mode 100644
index 00000000..a5bdb5d7
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/Transferable.java
@@ -0,0 +1,28 @@
+package de.thedevstack.conversationsplus.entities;
+
+public interface Transferable {
+
+ String[] VALID_IMAGE_EXTENSIONS = {"webp", "jpeg", "jpg", "png", "jpe"};
+ String[] VALID_CRYPTO_EXTENSIONS = {"pgp", "gpg", "otr"};
+ String[] WELL_KNOWN_EXTENSIONS = {"pdf","m4a"};
+
+ int STATUS_UNKNOWN = 0x200;
+ int STATUS_CHECKING = 0x201;
+ int STATUS_FAILED = 0x202;
+ int STATUS_OFFER = 0x203;
+ int STATUS_DOWNLOADING = 0x204;
+ int STATUS_DELETED = 0x205;
+ int STATUS_OFFER_CHECK_FILESIZE = 0x206;
+ int STATUS_UPLOADING = 0x207;
+
+
+ boolean start();
+
+ int getStatus();
+
+ long getFileSize();
+
+ int getProgress();
+
+ void cancel();
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/DownloadablePlaceholder.java b/src/main/java/de/thedevstack/conversationsplus/entities/TransferablePlaceholder.java
index 741d2990..c51320d1 100644
--- a/src/main/java/de/thedevstack/conversationsplus/entities/DownloadablePlaceholder.java
+++ b/src/main/java/de/thedevstack/conversationsplus/entities/TransferablePlaceholder.java
@@ -1,10 +1,10 @@
package de.thedevstack.conversationsplus.entities;
-public class DownloadablePlaceholder implements Downloadable {
+public class TransferablePlaceholder implements Transferable {
private int status;
- public DownloadablePlaceholder(int status) {
+ public TransferablePlaceholder(int status) {
this.status = status;
}
@Override
@@ -28,11 +28,6 @@ public class DownloadablePlaceholder implements Downloadable {
}
@Override
- public String getMimeType() {
- return "";
- }
-
- @Override
public void cancel() {
}