diff options
Diffstat (limited to 'src/main/java/de/thedevstack/conversationsplus/entities/Message.java')
-rw-r--r-- | src/main/java/de/thedevstack/conversationsplus/entities/Message.java | 763 |
1 files changed, 0 insertions, 763 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/entities/Message.java b/src/main/java/de/thedevstack/conversationsplus/entities/Message.java deleted file mode 100644 index 39fcdfb2..00000000 --- a/src/main/java/de/thedevstack/conversationsplus/entities/Message.java +++ /dev/null @@ -1,763 +0,0 @@ -package de.thedevstack.conversationsplus.entities; - -import android.content.ContentValues; -import android.database.Cursor; - -import java.net.MalformedURLException; -import java.net.URL; - -import de.thedevstack.conversationsplus.crypto.axolotl.XmppAxolotlSession; -import de.thedevstack.conversationsplus.utils.FileUtils; -import de.thedevstack.conversationsplus.utils.MimeUtils; -import de.thedevstack.conversationsplus.xmpp.jid.InvalidJidException; -import de.thedevstack.conversationsplus.xmpp.jid.Jid; - -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; - public static final int STATUS_SEND_FAILED = 3; - public static final int STATUS_WAITING = 5; - public static final int STATUS_OFFERED = 6; - public static final int STATUS_SEND_RECEIVED = 7; - public static final int STATUS_SEND_DISPLAYED = 8; - - public static final int ENCRYPTION_NONE = 0; - public static final int ENCRYPTION_PGP = 1; - public static final int ENCRYPTION_OTR = 2; - public static final int ENCRYPTION_DECRYPTED = 3; - public static final int ENCRYPTION_DECRYPTION_FAILED = 4; - public static final int ENCRYPTION_AXOLOTL = 5; - - public static final int TYPE_TEXT = 0; - public static final int TYPE_IMAGE = 1; - public static final int TYPE_FILE = 2; - public static final int TYPE_STATUS = 3; - public static final int TYPE_PRIVATE = 4; - - public static final String CONVERSATION = "conversationUuid"; - public static final String COUNTERPART = "counterpart"; - public static final String TRUE_COUNTERPART = "trueCounterpart"; - public static final String BODY = "body"; - public static final String TIME_SENT = "timeSent"; - public static final String ENCRYPTION = "encryption"; - public static final String STATUS = "status"; - public static final String TYPE = "type"; - public static final String CARBON = "carbon"; - public static final String OOB = "oob"; - public static final String EDITED = "edited"; - public static final String REMOTE_MSG_ID = "remoteMsgId"; - public static final String SERVER_MSG_ID = "serverMsgId"; - public static final String RELATIVE_FILE_PATH = "relativeFilePath"; - public static final String FINGERPRINT = "axolotl_fingerprint"; - public static final String READ = "read"; - public static final String ME_COMMAND = "/me "; - - - public boolean markable = false; - protected String conversationUuid; - protected Jid counterpart; - protected Jid trueCounterpart; - protected String body; - protected String encryptedBody; - protected long timeSent; - protected int encryption; - protected int status; - protected int type; - protected boolean carbon = false; - protected boolean oob = false; - protected String edited = null; - protected String relativeFilePath; - protected boolean read = true; - protected String remoteMsgId = null; - protected String serverMsgId = null; - protected Conversation conversation = null; - protected Transferable transferable = null; - private Message mNextMessage = null; - private Message mPreviousMessage = null; - private String axolotlFingerprint = null; - private Decision mTreatAsDownloadAble = Decision.NOT_DECIDED; - - private Message() { - - } - - public Message(Conversation conversation, String body, int encryption) { - this(conversation, body, encryption, STATUS_UNSEND); - } - - public Message(Conversation conversation, String body, int encryption, int status) { - this(java.util.UUID.randomUUID().toString(), - conversation.getUuid(), - conversation.getJid() == null ? null : conversation.getJid().toBareJid(), - null, - body, - System.currentTimeMillis(), - encryption, - status, - TYPE_TEXT, - false, - null, - null, - null, - null, - true, - null, - false); - 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 boolean carbon, - final String remoteMsgId, final String relativeFilePath, - final String serverMsgId, final String fingerprint, final boolean read, - final String edited, final boolean oob) { - this.uuid = uuid; - this.conversationUuid = conversationUUid; - this.counterpart = counterpart; - this.trueCounterpart = trueCounterpart; - this.body = body; - this.timeSent = timeSent; - this.encryption = encryption; - this.status = status; - this.type = type; - this.carbon = carbon; - this.remoteMsgId = remoteMsgId; - this.relativeFilePath = relativeFilePath; - this.serverMsgId = serverMsgId; - this.axolotlFingerprint = fingerprint; - this.read = read; - this.edited = edited; - this.oob = oob; - } - - public static Message fromCursor(Cursor cursor) { - Jid jid; - try { - String value = cursor.getString(cursor.getColumnIndex(COUNTERPART)); - if (value != null) { - jid = Jid.fromString(value, true); - } else { - jid = null; - } - } catch (InvalidJidException e) { - jid = null; - } - Jid trueCounterpart; - try { - String value = cursor.getString(cursor.getColumnIndex(TRUE_COUNTERPART)); - if (value != null) { - trueCounterpart = Jid.fromString(value, true); - } else { - trueCounterpart = null; - } - } catch (InvalidJidException e) { - trueCounterpart = null; - } - return new Message(cursor.getString(cursor.getColumnIndex(UUID)), - cursor.getString(cursor.getColumnIndex(CONVERSATION)), - jid, - trueCounterpart, - cursor.getString(cursor.getColumnIndex(BODY)), - cursor.getLong(cursor.getColumnIndex(TIME_SENT)), - cursor.getInt(cursor.getColumnIndex(ENCRYPTION)), - cursor.getInt(cursor.getColumnIndex(STATUS)), - cursor.getInt(cursor.getColumnIndex(TYPE)), - cursor.getInt(cursor.getColumnIndex(CARBON)) > 0, - cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)), - cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)), - cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)), - cursor.getString(cursor.getColumnIndex(FINGERPRINT)), - cursor.getInt(cursor.getColumnIndex(READ)) > 0, - cursor.getString(cursor.getColumnIndex(EDITED)), - cursor.getInt(cursor.getColumnIndex(OOB)) > 0); - } - - public static Message createStatusMessage(Conversation conversation, String body) { - final Message message = new Message(); - message.setType(Message.TYPE_STATUS); - message.setConversation(conversation); - message.setBody(body); - return message; - } - - @Override - public ContentValues getContentValues() { - ContentValues values = new ContentValues(); - values.put(UUID, uuid); - values.put(CONVERSATION, conversationUuid); - if (counterpart == null) { - values.putNull(COUNTERPART); - } else { - values.put(COUNTERPART, counterpart.toString()); - } - if (trueCounterpart == null) { - values.putNull(TRUE_COUNTERPART); - } else { - values.put(TRUE_COUNTERPART, trueCounterpart.toString()); - } - values.put(BODY, body); - values.put(TIME_SENT, timeSent); - values.put(ENCRYPTION, encryption); - values.put(STATUS, status); - values.put(TYPE, type); - values.put(CARBON, carbon ? 1 : 0); - values.put(REMOTE_MSG_ID, remoteMsgId); - values.put(RELATIVE_FILE_PATH, relativeFilePath); - values.put(SERVER_MSG_ID, serverMsgId); - values.put(FINGERPRINT, axolotlFingerprint); - values.put(READ,read ? 1 : 0); - values.put(EDITED, edited); - values.put(OOB, oob ? 1 : 0); - return values; - } - - public String getConversationUuid() { - return conversationUuid; - } - - public Conversation getConversation() { - return this.conversation; - } - - public void setConversation(Conversation conv) { - this.conversation = conv; - } - - public Jid getCounterpart() { - return counterpart; - } - - public void setCounterpart(final Jid counterpart) { - this.counterpart = counterpart; - } - - public Contact getContact() { - if (this.conversation.getMode() == Conversation.MODE_SINGLE) { - return this.conversation.getContact(); - } else { - if (this.trueCounterpart == null) { - return null; - } else { - return this.conversation.getAccount().getRoster() - .getContactFromRoster(this.trueCounterpart); - } - } - } - - public String getBody() { - return body; - } - - public void setBody(String body) { - this.body = body; - } - - public long getTimeSent() { - return timeSent; - } - - public int getEncryption() { - return encryption; - } - - public void setEncryption(int encryption) { - this.encryption = encryption; - } - - public int getStatus() { - return status; - } - - public void setStatus(int status) { - this.status = status; - } - - public String getRelativeFilePath() { - return this.relativeFilePath; - } - - public void setRelativeFilePath(String path) { - this.relativeFilePath = path; - } - - public String getRemoteMsgId() { - return this.remoteMsgId; - } - - public void setRemoteMsgId(String id) { - this.remoteMsgId = id; - } - - public String getServerMsgId() { - return this.serverMsgId; - } - - public void setServerMsgId(String id) { - this.serverMsgId = id; - } - - public boolean isRead() { - return this.read; - } - - public void markRead() { - this.read = true; - } - - public void markUnread() { - this.read = false; - } - - public void setTime(long time) { - this.timeSent = time; - } - - public String getEncryptedBody() { - return this.encryptedBody; - } - - public void setEncryptedBody(String body) { - this.encryptedBody = body; - } - - public int getType() { - return this.type; - } - - public void setType(int type) { - this.type = type; - } - - public boolean isCarbon() { - return carbon; - } - - public void setCarbon(boolean carbon) { - this.carbon = carbon; - } - - public boolean edited() { - return this.edited != null; - } - - public void setTrueCounterpart(Jid trueCounterpart) { - this.trueCounterpart = trueCounterpart; - } - - public Transferable getTransferable() { - return this.transferable; - } - - public void setTransferable(Transferable transferable) { - this.transferable = transferable; - } - - public boolean equals(Message message) { - if (this.getServerMsgId() != null && message.getServerMsgId() != null) { - return this.getServerMsgId().equals(message.getServerMsgId()); - } else if (this.getBody() == null || this.getCounterpart() == null - || message.getBody() == null || message.getCounterpart() == null) { - return false; - } else { - String body, otherBody; - if (this.hasFileOnRemoteHost()) { - body = this.getFileParams().url.toString(); - } else { - body = this.getBody(); - } - if (message.hasFileOnRemoteHost()) { - otherBody = message.getFileParams().url.toString(); - } else { - otherBody = message.getBody(); - } - - if (message.getRemoteMsgId() != null && this.getRemoteMsgId() != null) { - return (message.getRemoteMsgId().equals(this.getRemoteMsgId()) - || message.getRemoteMsgId().equals(this.getUuid()) - || message.getUuid().equals(this.getRemoteMsgId())) - && this.getCounterpart().equals(message.getCounterpart()) - && (body.equals(otherBody) - ||(message.getEncryption() == Message.ENCRYPTION_PGP - && message.getRemoteMsgId().matches("[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"))) ; - } else { - // existing (send) message with no remoteMsgId and MAM message with remoteMsgId - return ((this.getRemoteMsgId() == null && message.getRemoteMsgId() != null) - || (this.getRemoteMsgId() != null && message.getRemoteMsgId() == null) - // both null is also acceptable - || (this.getRemoteMsgId() == null && message.getRemoteMsgId() == null)) - && this.getCounterpart().equals(message.getCounterpart()) - && body.equals(otherBody); - } - } - } - - public Message next() { - synchronized (this.conversation.messages) { - if (this.mNextMessage == null) { - int index = this.conversation.messages.indexOf(this); - if (index < 0 || index >= this.conversation.messages.size() - 1) { - this.mNextMessage = null; - } else { - this.mNextMessage = this.conversation.messages.get(index + 1); - } - } - return this.mNextMessage; - } - } - - public Message prev() { - 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); - } - } - return this.mPreviousMessage; - } - } - - public boolean hasMeCommand() { - return getBody().startsWith(ME_COMMAND); - } - - public String getBodyReplacedMeCommand(String replaceString) { - try { - return getBody().replaceAll("^" + Message.ME_COMMAND, replaceString + " "); - } catch (ArrayIndexOutOfBoundsException e) { - return getBody(); - } - } - - public boolean trusted() { - Contact contact = this.getContact(); - return (status > STATUS_RECEIVED || (contact != null && contact.trusted())); - } - - 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; - } - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public String getEditedId() { - return edited; - } - - public void setOob(boolean isOob) { - this.oob = isOob; - } - - public enum Decision { - MUST, - SHOULD, - NEVER, - NOT_DECIDED, - } - - private String extractRelevantExtension(URL url) { - if (url == null) { - return null; - } - String path = url.getPath(); - return extractRelevantExtension(path); - } - - private String extractRelevantExtension(String path) { - if (path == null || path.isEmpty()) { - return null; - } - - String filename = path.substring(path.lastIndexOf('/') + 1).toLowerCase(); - - final String lastPart = FileUtils.getLastExtension(filename); - - if (!lastPart.isEmpty()) { - // we want the real file extension, not the crypto one - final String secondToLastPart = FileUtils.getSecondToLastExtension(filename); - if (!secondToLastPart.isEmpty() && Transferable.VALID_CRYPTO_EXTENSIONS.contains(lastPart)) { - return secondToLastPart; - } else { - return lastPart; - } - } - return null; - } - - public String getMimeType() { - if (relativeFilePath != null) { - int start = relativeFilePath.lastIndexOf('.') + 1; - if (start < relativeFilePath.length()) { - return MimeUtils.guessMimeTypeFromExtension(relativeFilePath.substring(start)); - } else { - return null; - } - } else { - try { - return MimeUtils.guessMimeTypeFromExtension(extractRelevantExtension(new URL(this.getBody()))); - } catch (MalformedURLException e) { - return null; - } - } - } - - /** - * in case of later found error with decision, set it to a value which does not affect anything, hopefully - */ - public void setNoDownloadable() { - mTreatAsDownloadAble = Decision.NEVER; - } - - public Decision treatAsDownloadable() { - // only test this ones, body will not change - if (mTreatAsDownloadAble != Decision.NOT_DECIDED) { - return mTreatAsDownloadAble; - } - /** - * there are a few cases where spaces result in an unwanted behavior, e.g. - * "http://example.com/image.jpg" text that will not be shown /abc.png" - * or more than one image link in one message. - */ - if (getBody().contains(" ")) { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - try { - URL url = new URL(body); - if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } else if (oob) { - mTreatAsDownloadAble = Decision.MUST; - return mTreatAsDownloadAble; - } - String extension = extractRelevantExtension(url); - if (extension == null) { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - String ref = url.getRef(); - boolean encrypted = ref != null && ref.matches("([A-Fa-f0-9]{2}){48}"); - - if (encrypted) { - if (MimeUtils.guessMimeTypeFromExtension(extension) != null) { - mTreatAsDownloadAble = Decision.MUST; - return mTreatAsDownloadAble; - } else { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - } else if (Transferable.VALID_IMAGE_EXTENSIONS.contains(extension) - || Transferable.WELL_KNOWN_EXTENSIONS.contains(extension)) { - mTreatAsDownloadAble = Decision.SHOULD; - return mTreatAsDownloadAble; - } else { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - - } catch (MalformedURLException e) { - mTreatAsDownloadAble = Decision.NEVER; - return mTreatAsDownloadAble; - } - } - - public FileParams getFileParams() { - FileParams params = getLegacyFileParams(); - if (params != null) { - return params; - } - params = new FileParams(); - if (this.transferable != null) { - params.size = this.transferable.getFileSize(); - } - if (this.getBody() == null) { - return params; - } - String parts[] = this.getBody().split("\\|"); - 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; - } - 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 FileParams getLegacyFileParams() { - FileParams params = new FileParams(); - if (this.getBody() == null) { - return params; - } - String parts[] = this.getBody().split(","); - if (parts.length == 3) { - try { - params.size = Long.parseLong(parts[0]); - } catch (NumberFormatException e) { - return null; - } - try { - params.width = Integer.parseInt(parts[1]); - } catch (NumberFormatException e) { - return null; - } - try { - params.height = Integer.parseInt(parts[2]); - } catch (NumberFormatException e) { - return null; - } - return params; - } else { - return null; - } - } - - public void untie() { - this.mNextMessage = null; - this.mPreviousMessage = null; - } - - public boolean isFileOrImage() { - return type == TYPE_FILE || type == TYPE_IMAGE; - } - - 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 void setAxolotlFingerprint(String fingerprint) { - this.axolotlFingerprint = fingerprint; - } - - public String getAxolotlFingerprint() { - return axolotlFingerprint; - } - - public boolean isTrusted() { - XmppAxolotlSession.Trust t = conversation.getAccount().getAxolotlService().getFingerprintTrust(axolotlFingerprint); - return t != null && t.trusted(); - } - - private int getPreviousEncryption() { - for (Message iterator = this.prev(); iterator != null; iterator = iterator.prev()){ - if( iterator.isCarbon() || iterator.getStatus() == STATUS_RECEIVED ) { - continue; - } - return iterator.getEncryption(); - } - return ENCRYPTION_NONE; - } - - private int getNextEncryption() { - for (Message iterator = this.next(); iterator != null; iterator = iterator.next()){ - if( iterator.isCarbon() || iterator.getStatus() == STATUS_RECEIVED ) { - continue; - } - return iterator.getEncryption(); - } - return conversation.getNextEncryption(); - } - - public boolean isValidInSession() { - int pastEncryption = getCleanedEncryption(this.getPreviousEncryption()); - int futureEncryption = getCleanedEncryption(this.getNextEncryption()); - - boolean inUnencryptedSession = pastEncryption == ENCRYPTION_NONE - || futureEncryption == ENCRYPTION_NONE - || pastEncryption != futureEncryption; - - return inUnencryptedSession || getCleanedEncryption(this.getEncryption()) == pastEncryption; - } - - private static int getCleanedEncryption(int encryption) { - if (encryption == ENCRYPTION_DECRYPTED || encryption == ENCRYPTION_DECRYPTION_FAILED) { - return ENCRYPTION_PGP; - } - return encryption; - } -} |