From 132b27adeef3ab4d305facda7dd035015b00766f Mon Sep 17 00:00:00 2001 From: steckbrief Date: Sat, 5 May 2018 20:28:04 +0200 Subject: introduces new message state model --- .../conversationsplus/utils/MessageUtil.java | 255 ++++++++++----------- 1 file changed, 121 insertions(+), 134 deletions(-) (limited to 'src/main/java/de/thedevstack/conversationsplus/utils/MessageUtil.java') diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/MessageUtil.java b/src/main/java/de/thedevstack/conversationsplus/utils/MessageUtil.java index 2e346486..0be1461b 100644 --- a/src/main/java/de/thedevstack/conversationsplus/utils/MessageUtil.java +++ b/src/main/java/de/thedevstack/conversationsplus/utils/MessageUtil.java @@ -3,138 +3,35 @@ package de.thedevstack.conversationsplus.utils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import java.net.MalformedURLException; import java.net.URL; import java.util.regex.Matcher; import java.util.regex.Pattern; +import de.thedevstack.android.logcat.Logging; import de.thedevstack.conversationsplus.ConversationsPlusApplication; import de.thedevstack.conversationsplus.ConversationsPlusPreferences; +import de.thedevstack.conversationsplus.entities.Account; import de.thedevstack.conversationsplus.entities.Conversation; import de.thedevstack.conversationsplus.entities.DownloadableFile; import de.thedevstack.conversationsplus.entities.FileParams; import de.thedevstack.conversationsplus.entities.Message; import de.thedevstack.conversationsplus.entities.Transferable; +import de.thedevstack.conversationsplus.entities.TransferablePlaceholder; import de.thedevstack.conversationsplus.enums.FileStatus; +import de.thedevstack.conversationsplus.enums.MessageConfirmation; +import de.thedevstack.conversationsplus.enums.MessageDirection; +import de.thedevstack.conversationsplus.enums.MessageStatus; import de.thedevstack.conversationsplus.persistance.DatabaseBackend; import de.thedevstack.conversationsplus.persistance.FileBackend; +import de.thedevstack.conversationsplus.utils.messaging.MessageReceiptUtil; +import de.thedevstack.conversationsplus.xmpp.jid.Jid; +import de.tzur.conversations.Settings; /** * Utility class to work with messages. */ public final class MessageUtil { - public static void extractFileParamsFromBody(Message message) { - if (null == message) { - return; - } - - // Ensure that for every message the fileParams are set after calling this method - FileParams fileParams = message.getFileParams(); - if (null == fileParams) { - fileParams = new FileParams(); - message.setFileParams(fileParams); - } - - String body = message.getBody(); - /** - * 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 (null == body || body.isEmpty() || body.contains(" ")) { - return; - } - - try { - URL url = new URL(body); - if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) { - message.setTreatAsDownloadable(Message.Decision.NEVER); - fileParams.setFileStatus(FileStatus.UNDEFINED); - return; - } - String extension = FileUtils.getRelevantExtension(url); - if (message.isHttpUploaded()) { - fileParams.setUrl(url.toString()); - if (null != extension - && (Transferable.WELL_KNOWN_EXTENSIONS.contains(extension.toLowerCase()) || Transferable.VALID_IMAGE_EXTENSIONS.contains(extension.toLowerCase()))) { - message.setTreatAsDownloadable(Message.Decision.MUST); - } else { - message.setTreatAsDownloadable(Message.Decision.NEVER); - fileParams.setFileStatus(FileStatus.UNDEFINED); - } - - extractFilename(message, url.toString()); - return; - } - - if (extension == null) { - message.setTreatAsDownloadable(Message.Decision.NEVER); - fileParams.setFileStatus(FileStatus.UNDEFINED); - return; - } - byte[] ivAndKey = UrlUtil.getIvAndKeyFromURL(url); - - if (null != ivAndKey) { - if (MimeUtils.guessMimeTypeFromExtension(extension) != null) { - message.setTreatAsDownloadable(Message.Decision.MUST); - fileParams.setKeyAndIv(ivAndKey); - } else { - message.setTreatAsDownloadable(Message.Decision.NEVER); - fileParams.setFileStatus(FileStatus.UNDEFINED); - } - } else if (Transferable.VALID_IMAGE_EXTENSIONS.contains(extension) - || Transferable.WELL_KNOWN_EXTENSIONS.contains(extension)) { - message.setTreatAsDownloadable(Message.Decision.SHOULD); - } else { - message.setTreatAsDownloadable(Message.Decision.NEVER); - fileParams.setFileStatus(FileStatus.UNDEFINED); - } - - if (message.treatAsDownloadable() == Message.Decision.MUST - || message.treatAsDownloadable() == Message.Decision.SHOULD) { - fileParams.setUrl(url.toString()); - extractFilename(message, url.toString()); - } - } catch (MalformedURLException e) { - message.setTreatAsDownloadable(Message.Decision.NEVER); - fileParams.setFileStatus(FileStatus.UNDEFINED); - } - } - - private static void extractFilename(Message message, String url) { - String originalFilename = FileUtils.getFilenameFromPath(url); - final String lowerCaseFilename = originalFilename.toLowerCase(); - final String lastPart = FileUtils.getLastExtension(lowerCaseFilename); - - detectAndSetEncryption(lastPart, message); - - String filenameExtension; - if (!lastPart.isEmpty() && Transferable.VALID_CRYPTO_EXTENSIONS.contains(lastPart)) { - filenameExtension = FileUtils.getSecondToLastExtension(lowerCaseFilename); - originalFilename = originalFilename.replace("." + lastPart, ""); - } else { - filenameExtension = lastPart; - } - message.setRelativeFilePath(message.getUuid() + "." + filenameExtension); - - message.getFileParams().setOriginalFilename(originalFilename); - } - - private static void detectAndSetEncryption(String lastPart, Message message) { - if (!lastPart.isEmpty() && ("pgp".equals(lastPart) || "gpg".equals(lastPart))) { - message.setEncryption(Message.ENCRYPTION_PGP); - } else if (message.getEncryption() != Message.ENCRYPTION_OTR - && message.getEncryption() != Message.ENCRYPTION_AXOLOTL) { - message.setEncryption(Message.ENCRYPTION_NONE); - } else if ((message.getEncryption() == Message.ENCRYPTION_OTR - || message.getEncryption() == Message.ENCRYPTION_AXOLOTL) - && message.getFileParams() != null && message.getFileParams().getKey() == null) { - // If an encryption is set for the message, but no key given -> decryption not possible - message.setEncryption(Message.ENCRYPTION_NONE); - } - } - /** * Checks if an attached file is an image or not. * Prerequisite for calling this method: The check if a file is attached is done before. @@ -179,8 +76,8 @@ public final class MessageUtil { public static boolean needsDownload(Message message) { FileStatus fileStatus = (null != message.getFileParams()) ? message.getFileParams().getFileStatus() : null; return (message.hasFileAttached() || MessageUtil.hasDownloadableLink(message)) - &&(null == fileStatus - || (null != fileStatus && (fileStatus == FileStatus.NEEDS_DOWNLOAD || fileStatus == FileStatus.UNDEFINED))) + && (null == fileStatus + || (fileStatus == FileStatus.NEEDS_DOWNLOAD || fileStatus == FileStatus.UNDEFINED)) && message.treatAsDownloadable() != Message.Decision.NEVER; } @@ -190,31 +87,75 @@ public final class MessageUtil { && null != url; } + public static boolean isOutgoingMessage(Message message) { + return MessageDirection.OUT == message.getDirection(); + } + + public static boolean isIncomingMessage(Message message) { + return MessageDirection.IN == message.getDirection(); + } + public static boolean isMessageSent(Message message) { - switch (message.getStatus()) { - case Message.STATUS_SEND: - case Message.STATUS_SEND_DISPLAYED: - case Message.STATUS_SEND_FAILED: - case Message.STATUS_SEND_RECEIVED: - return true; - default: - return false; + return MessageUtil.isOutgoingMessage(message) + && MessageStatus.TRANSMITTED == message.getMessageStatus(); + } + + public static boolean isMessageReceived(Message message) { + return MessageUtil.isIncomingMessage(message) + && MessageStatus.TRANSMITTED == message.getMessageStatus(); + } + + public static boolean isMessageTransmittedOrDisplayedOrReceived(Message message) { + MessageStatus status = message.getMessageStatus(); + return MessageStatus.TRANSMITTED == status + || MessageStatus.RECEIVED == status + || MessageStatus.DISPLAYED == status; + } + + public static void setAndSaveStatusForFileDeleted(Message message) { + message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); + //FIXME: File Status needs to be changed + MessageStatus msgStatus = message.getMessageStatus(); + if (MessageUtil.isOutgoingMessage(message) + && (MessageStatus.TRANSMITTING == msgStatus || MessageStatus.WAITING == msgStatus)) { + MessageUtil.setAndSaveMessageStatus(message, MessageStatus.FAILED); // FIXME: add some information why this is failed } } public static void setAndSaveFileStatus(Message message, FileStatus fileStatus) { + if (setFileStatus(message, fileStatus)) { + DatabaseBackend.getInstance().updateMessage(message); + UiUpdateHelper.updateConversationUi(); + } + } + + public static boolean setFileStatus(Message message, FileStatus fileStatus) { message.getFileParams().setFileStatus(fileStatus); - DatabaseBackend.getInstance().updateMessage(message); - UiUpdateHelper.updateConversationUi(); + if (FileStatus.DOWNLOAD_FAILED == fileStatus + || FileStatus.UPLOAD_FAILED == fileStatus) { + setMessageStatus(message, MessageStatus.FAILED); + } else if (FileStatus.DOWNLOADED == fileStatus) { + setMessageStatus(message, MessageStatus.TRANSMITTED); + } + return true; + } + + public static boolean markMessageAsReceived(Account account, Jid from, String id) { + Message message = XmppConnectionServiceAccessor.xmppConnectionService.getMessage(account, from, id); + if (null != message) { + MessageUtil.setAndSaveMessageStatus(message, MessageStatus.RECEIVED); + return true; + } + return false; } - public static boolean markMessage(Conversation conversation, String uuid, int status) { + public static boolean setAndSaveMessageStatus(Conversation conversation, String uuid, MessageStatus newStatus) { if (uuid == null) { return false; } else { Message message = conversation.findSentMessageWithUuid(uuid); if (message != null) { - markMessage(message, status); + setAndSaveMessageStatus(message, newStatus); return true; } else { return false; @@ -222,15 +163,38 @@ public final class MessageUtil { } } - public static void markMessage(Message message, int status) { - if (status == Message.STATUS_SEND_FAILED - && (message.getStatus() == Message.STATUS_SEND_RECEIVED || message - .getStatus() == Message.STATUS_SEND_DISPLAYED)) { - return; + public static void setAndSaveMessageStatus(Message message, MessageStatus newStatus) { + if (setMessageStatus(message, newStatus)) { + DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateMessage(message); + UiUpdateHelper.updateConversationUi(); + } + } + + private static boolean sendReceipt(Message message) { + return Settings.CONFIRM_MESSAGE_RECEIVED // Only if user allows to send message confirmations + && isIncomingMessage(message) // Only if a message is incoming + && MessageConfirmation.NONE != message.getConfirmation() // Only if message contained an confirmation request + && message.getRemoteMsgId() != null // Only if there is an remote id + && !message.isMamReceived() // Only if it is not received using MAM + && !message.isCarbon() // Only if it is not received with carbons + && !message.isRead(); // Only if the message is not read yet + } + + public static boolean setMessageStatus(Message message, MessageStatus newStatus) { + MessageStatus currentStatus = message.getMessageStatus(); + if ((MessageStatus.FAILED == newStatus && (MessageStatus.RECEIVED == currentStatus || MessageStatus.DISPLAYED == currentStatus))) { + return false; + } + message.setMessageStatus(newStatus); + if (MessageStatus.TRANSMITTED == newStatus) { + if (sendReceipt(message)) { + Logging.d("message-util", "Send message receipt from setMessageStatus"); + MessageReceiptUtil.sendMessageReceipts(message); + } + Logging.d("message-util", "Push notification for message"); + XmppConnectionServiceAccessor.xmppConnectionService.getNotificationService().push(message); } - message.setStatus(status); - DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateMessage(message); - UiUpdateHelper.updateConversationUi(); + return true; } public static boolean wasHighlightedOrPrivate(final Message message) { @@ -302,6 +266,29 @@ public final class MessageUtil { } } + 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; + } + + public static Message createOutgoingMessage(Conversation conversation, String body) { + int encryption = conversation.getNextEncryption(); + if (encryption == Message.ENCRYPTION_PGP) { + encryption = Message.ENCRYPTION_DECRYPTED; + } + Message message = new Message(conversation, body, encryption); + message.setMessageStatus(MessageStatus.WAITING); + message.setDirection(MessageDirection.OUT); + if (conversation.getNextCounterpart() != null) { + message.setCounterpart(conversation.getNextCounterpart()); + } + + return message; + } + private MessageUtil() { // Static helper class } -- cgit v1.2.3