diff options
Diffstat (limited to 'src')
23 files changed, 271 insertions, 200 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/enums/FileStatus.java b/src/main/java/de/thedevstack/conversationsplus/enums/FileStatus.java index e4254aeb..31b40512 100644 --- a/src/main/java/de/thedevstack/conversationsplus/enums/FileStatus.java +++ b/src/main/java/de/thedevstack/conversationsplus/enums/FileStatus.java @@ -16,5 +16,5 @@ public enum FileStatus { DELETING, NOT_FOUND, DOWNLOADING, - CHECKING_FILE_SIZE; + CHECKING_FILE_SIZE, UPLOAD_FAILED; } diff --git a/src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java b/src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java index 6643c276..d1da4a8e 100644 --- a/src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java +++ b/src/main/java/de/thedevstack/conversationsplus/persistance/FileBackend.java @@ -23,6 +23,7 @@ import de.thedevstack.conversationsplus.ConversationsPlusPreferences; import de.thedevstack.conversationsplus.entities.FileParams; import de.thedevstack.conversationsplus.exceptions.FileCopyException; import de.thedevstack.conversationsplus.persistance.observers.FileDeletionObserver; +import de.thedevstack.conversationsplus.utils.FileUtils; import de.thedevstack.conversationsplus.utils.StreamUtil; import de.thedevstack.conversationsplus.Config; import de.thedevstack.conversationsplus.R; @@ -44,10 +45,25 @@ public class FileBackend { if (null == INSTANCE) { INSTANCE = new FileBackend(); } + INSTANCE.checkIfDirectoriesExistAndCreateIfNot(); INSTANCE.initFileObservers(); INSTANCE.createNoMedia(); } + private void checkIfDirectoriesExistAndCreateIfNot() { + this.checkIfDirectoryExistsAndCreateIfNot(FileBackend.getPrivateFileDirectoryPath()); + this.checkIfDirectoryExistsAndCreateIfNot(FileBackend.getConversationsFileDirectory()); + this.checkIfDirectoryExistsAndCreateIfNot(FileBackend.getConversationsImageDirectory()); + this.checkIfDirectoryExistsAndCreateIfNot(FileBackend.getPrivateImageDirectoryPath()); + } + + private void checkIfDirectoryExistsAndCreateIfNot(String directoryPath) { + File directory = new File(directoryPath); + if (!directory.exists()) { + directory.mkdirs(); + } + } + private void initFileObservers() { this.privateFilesDirectoryObserver = new FileDeletionObserver(FileBackend.getPrivateFileDirectoryPath()); this.privateFilesImageDirectoryObserver = new FileDeletionObserver(FileBackend.getConversationsFileDirectory()); @@ -72,6 +88,7 @@ public class FileBackend { } public static void onFileTransferFolderChanged() { + INSTANCE.checkIfDirectoryExistsAndCreateIfNot(FileBackend.getConversationsFileDirectory()); INSTANCE.conversationsFilesDirectoryObserver.stopWatching(); INSTANCE.conversationsFilesDirectoryObserver = new FileDeletionObserver(FileBackend.getConversationsFileDirectory()); INSTANCE.conversationsFilesDirectoryObserver.startWatching(); @@ -79,6 +96,7 @@ public class FileBackend { } public static void onImageTransferFolderChanged() { + INSTANCE.checkIfDirectoryExistsAndCreateIfNot(FileBackend.getConversationsImageDirectory()); INSTANCE.conversationsImagesDirectoryObserver.stopWatching(); INSTANCE.conversationsImagesDirectoryObserver = new FileDeletionObserver(FileBackend.getConversationsImageDirectory()); INSTANCE.conversationsImagesDirectoryObserver.startWatching(); @@ -107,7 +125,7 @@ public class FileBackend { } public static DownloadableFile getFile(Message message, boolean decrypted) { - DownloadableFile downloadableFile = new DownloadableFile(getFilePath(message, decrypted)); + DownloadableFile downloadableFile = new DownloadableFile(getFilePath(message, decrypted, null)); FileParams fileParams = message.getFileParams(); if (null != fileParams) { if (null != fileParams.getKey()) { @@ -122,10 +140,7 @@ public class FileBackend { } protected static String getFilePath(Message message, String extension) { - String path = FileBackend.getFilePath(message, true); - if (!path.endsWith(extension)) { - path += "." + extension; - } + String path = FileBackend.getFilePath(message, true, extension); return path; } @@ -137,7 +152,7 @@ public class FileBackend { return getFilePath(message, extension); } - protected static String getFilePath(Message message, boolean decrypted) { + protected static String getFilePath(Message message, boolean decrypted, String fallbackExtension) { final boolean encrypted = !decrypted && (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED); @@ -157,7 +172,11 @@ public class FileBackend { path = getConversationsFileDirectory() + path; } String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mime); - path += "." + extension; + if (null != extension) { + path += "." + extension; + } else if (null != fallbackExtension) { + path += "." +fallbackExtension; + } fileParams.setPath(path); } @@ -218,9 +237,11 @@ public class FileBackend { } public static DownloadableFile compressImageAndCopyToPrivateStorage(Message message, Bitmap scaledBitmap) throws FileCopyException { - String path = getFilePath(message, "jpg"); - message.getFileParams().setPath(path); - message.setRelativeFilePath(path); // TODO: Remove + if (null == message.getFileParams() || null == message.getFileParams().getPath()) { + String path = getFilePath(message, "jpg"); + message.setRelativeFilePath(path); // TODO: Remove + } + DownloadableFile file = getFile(message); file.getParentFile().mkdirs(); OutputStream os = null; diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferManager.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferManager.java index 8d971bb2..b99f8d82 100644 --- a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferManager.java +++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferManager.java @@ -8,6 +8,7 @@ import java.util.TreeSet; import de.thedevstack.android.logcat.Logging; import de.thedevstack.conversationsplus.Config; import de.thedevstack.conversationsplus.entities.Message; +import de.thedevstack.conversationsplus.enums.FileStatus; import de.thedevstack.conversationsplus.services.FileTransferService; import de.thedevstack.conversationsplus.services.filetransfer.http.upload.HttpUploadFileTransferEntity; import de.thedevstack.conversationsplus.utils.MessageUtil; @@ -124,6 +125,7 @@ public class FileTransferManager implements FileTransferStatusListener { } } if (!retransferStarted) { + entity.getMessage().getFileParams().setFileStatus(FileStatus.UPLOAD_FAILED); MessageUtil.markMessage(entity.getMessage(), Message.STATUS_SEND_FAILED); } } diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteRemoteFileService.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteRemoteFileService.java index 2085cf4b..83f7e359 100644 --- a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteRemoteFileService.java +++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteRemoteFileService.java @@ -1,16 +1,13 @@ package de.thedevstack.conversationsplus.services.filetransfer.http.delete; -import de.thedevstack.conversationsplus.ConversationsPlusApplication; import de.thedevstack.conversationsplus.entities.Account; import de.thedevstack.conversationsplus.entities.Message; import de.thedevstack.conversationsplus.enums.FileStatus; -import de.thedevstack.conversationsplus.persistance.DatabaseBackend; import de.thedevstack.conversationsplus.ui.listeners.SimpleUserDecisionCallback; import de.thedevstack.conversationsplus.utils.MessageUtil; -import de.thedevstack.conversationsplus.utils.UiUpdateHelper; import de.thedevstack.conversationsplus.utils.XmppSendUtil; import de.thedevstack.conversationsplus.xmpp.filetransfer.http.FileTransferHttp; -import de.thedevstack.conversationsplus.xmpp.filetransfer.http.delete.FileTransferHttpDeleteSlotRequestPacketGenerator; +import de.thedevstack.conversationsplus.xmpp.filetransfer.http.delete.FileTransferHttpDeleteRequestPacketGenerator; import de.thedevstack.conversationsplus.xmpp.jid.Jid; import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; @@ -36,9 +33,9 @@ public class DeleteRemoteFileService implements SimpleUserDecisionCallback { Account account = this.message.getConversation().getAccount(); Jid host = account.getXmppConnection().findDiscoItemByFeature(FileTransferHttp.NAMESPACE); if (null != host) { - IqPacket request = FileTransferHttpDeleteSlotRequestPacketGenerator.generate(host, path); + IqPacket request = FileTransferHttpDeleteRequestPacketGenerator.generate(host, path); MessageUtil.setAndSaveFileStatus(this.message, FileStatus.DELETING); - XmppSendUtil.sendIqPacket(account, request, new DeleteTokenReceived(remoteFile)); + XmppSendUtil.sendIqPacket(account, request, new DeletedIqPacketReceived(remoteFile)); } } } diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteTokenReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteTokenReceived.java deleted file mode 100644 index d61a5c6a..00000000 --- a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeleteTokenReceived.java +++ /dev/null @@ -1,97 +0,0 @@ -package de.thedevstack.conversationsplus.services.filetransfer.http.delete; - -import android.widget.Toast; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.IOException; - -import de.thedevstack.android.logcat.Logging; -import de.thedevstack.conversationsplus.R; -import de.thedevstack.conversationsplus.entities.Account; -import de.thedevstack.conversationsplus.enums.FileStatus; -import de.thedevstack.conversationsplus.http.HttpClient; -import de.thedevstack.conversationsplus.utils.MessageUtil; -import de.thedevstack.conversationsplus.utils.ui.ConversationsPlusToast; -import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived; -import de.thedevstack.conversationsplus.xmpp.exceptions.ServiceUnavailableException; -import de.thedevstack.conversationsplus.xmpp.exceptions.XmppException; -import de.thedevstack.conversationsplus.xmpp.filetransfer.http.delete.DeleteSlotPacketParser; -import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; - -/** - * - */ -public class DeleteTokenReceived implements OnIqPacketReceived { - private static final String HEADER_NAME_DELETE_TOKEN = "X-FILETRANSFER-HTTP-DELETE-TOKEN"; - private final DeleteRemoteFile remoteFile; - - public DeleteTokenReceived(DeleteRemoteFile remoteFile) { - this.remoteFile = remoteFile; - } - - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - try { - String url = this.remoteFile.getPath(); - String deleteToken = DeleteSlotPacketParser.parseDeleteToken(packet); - Logging.d("filetransfer.http.delete", "Got delete token '" + deleteToken + "' for remote file '" + remoteFile.getPath() + "'"); - OkHttpClient client = HttpClient.getOkHttpClient(true); - Request request = new Request.Builder() - .url(url) - .addHeader(HEADER_NAME_DELETE_TOKEN, deleteToken) - .delete() - .build(); - client.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(Call call, IOException e) { - Logging.e("filetransfer.http.delete", "Error while connecting to '" + call.request().url() + "': " + e.getMessage()); - MessageUtil.setAndSaveFileStatus(remoteFile.getMessage(), FileStatus.DELETE_FAILED); - } - - @Override - public void onResponse(Call call, Response response) throws IOException { - if (response.isSuccessful()) { - MessageUtil.setAndSaveFileStatus(remoteFile.getMessage(), FileStatus.DELETED); - Logging.i("filetransfer.http.delete", "Remote file successfully deleted '" + remoteFile.getPath() + "'"); - } else { - String detailedMessage = response.body().string(); - FileStatus fileStatus = FileStatus.DELETE_FAILED; - switch (response.code()) { - case 403: - case 500: - try { - JSONObject jsonObject = new JSONObject(detailedMessage); - detailedMessage = jsonObject.getString("msg"); - } catch (JSONException e) { - Logging.e("filetransfer.http.delete", "Failed to get error message from expected json response: " + detailedMessage); - } - break; - case 404: - fileStatus = FileStatus.DELETED; - Logging.i("filetransfer.http.delete", "Failed to delete file - it was already deleted."); - break; - } - Logging.e("filetransfer.http.delete", "Could not delete remote file '" + remoteFile.getPath() + "'. Response Code: " + response.code() + ", details: " + detailedMessage); - MessageUtil.setAndSaveFileStatus(remoteFile.getMessage(), fileStatus); - } - } - }); - - } catch (XmppException e) { - Logging.e("filetransfer.http.delete", "Error while trying to get the delete token: " + e.getMessage()); - int messageResId = R.string.cplus_remote_file_delete_failed; - if (e instanceof ServiceUnavailableException) { - messageResId = R.string.cplus_remote_file_delete_service_unavailable; - } - ConversationsPlusToast.makeErrorToast(messageResId, Toast.LENGTH_LONG); - MessageUtil.setAndSaveFileStatus(remoteFile.getMessage(), FileStatus.DELETE_FAILED); - } - } -} diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeletedIqPacketReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeletedIqPacketReceived.java new file mode 100644 index 00000000..470a6010 --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/delete/DeletedIqPacketReceived.java @@ -0,0 +1,47 @@ +package de.thedevstack.conversationsplus.services.filetransfer.http.delete; + +import android.widget.Toast; + +import de.thedevstack.android.logcat.Logging; +import de.thedevstack.conversationsplus.R; +import de.thedevstack.conversationsplus.entities.Account; +import de.thedevstack.conversationsplus.enums.FileStatus; +import de.thedevstack.conversationsplus.utils.MessageUtil; +import de.thedevstack.conversationsplus.utils.ui.ConversationsPlusToast; +import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived; +import de.thedevstack.conversationsplus.xmpp.exceptions.ServiceUnavailableException; +import de.thedevstack.conversationsplus.xmpp.exceptions.XmppException; +import de.thedevstack.conversationsplus.xmpp.filetransfer.http.delete.DeletedPacketParser; +import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; + +/** + * + */ +public class DeletedIqPacketReceived implements OnIqPacketReceived { + private final DeleteRemoteFile remoteFile; + + public DeletedIqPacketReceived(DeleteRemoteFile remoteFile) { + this.remoteFile = remoteFile; + } + + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + try { + boolean fileIsDeleted = DeletedPacketParser.parseDeleteToken(packet); + if (fileIsDeleted) { + MessageUtil.setAndSaveFileStatus(remoteFile.getMessage(), FileStatus.DELETED); + Logging.i("filetransfer.http.delete", "Remote file successfully deleted '" + remoteFile.getPath() + "'"); + } else { + Logging.e("filetransfer.http.delete", "Unexpectedly failed to delete remote file."); + } + } catch (XmppException e) { + Logging.e("filetransfer.http.delete", "Error while trying to delete remote file: " + e.getMessage()); + int messageResId = R.string.cplus_remote_file_delete_failed; + if (e instanceof ServiceUnavailableException) { + messageResId = R.string.cplus_remote_file_delete_service_unavailable; + } + ConversationsPlusToast.makeErrorToast(messageResId, Toast.LENGTH_LONG); + MessageUtil.setAndSaveFileStatus(remoteFile.getMessage(), FileStatus.DELETE_FAILED); + } + } +} diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/upload/HttpUploadFileTransferService.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/upload/HttpUploadFileTransferService.java index c2e92a9e..28bb3a1c 100644 --- a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/upload/HttpUploadFileTransferService.java +++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/http/upload/HttpUploadFileTransferService.java @@ -15,10 +15,7 @@ import de.thedevstack.conversationsplus.services.filetransfer.AbstractFileTransf import de.thedevstack.conversationsplus.utils.AccountUtil; import de.thedevstack.conversationsplus.utils.MessageUtil; import de.thedevstack.conversationsplus.utils.XmppSendUtil; -import de.thedevstack.conversationsplus.xmpp.filetransfer.http.FileTransferHttp; -import de.thedevstack.conversationsplus.xmpp.filetransfer.http.upload.HttpUpload; import de.thedevstack.conversationsplus.xmpp.filetransfer.http.upload.HttpUploadRequestSlotPacketGenerator; -import de.thedevstack.conversationsplus.xmpp.jid.Jid; import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; /** @@ -63,29 +60,18 @@ public class HttpUploadFileTransferService extends AbstractFileTransferService i file.setExpectedSize(inputStreamAndExpectedSize.second); Logging.d("httpupload", "Requesting upload slot for file upload"); - Jid host = this.getHost(account); - if (null != host) { - IqPacket request = HttpUploadRequestSlotPacketGenerator.generate(host, file.getName(), file.getSize(), file.getMimeType()); - XmppSendUtil.sendIqPacket(account, request, new HttpUploadSlotRequestReceived(entity)); - MessageUtil.markMessage(message, Message.STATUS_UNSEND); + IqPacket request = HttpUploadRequestSlotPacketGenerator.generate(account, message.getContact().getJid(), file.getName(), file.getSize(), file.getMimeType()); + XmppSendUtil.sendIqPacket(account, request, new HttpUploadSlotRequestReceived(entity)); + MessageUtil.markMessage(message, Message.STATUS_UNSEND); - Logging.d("httpupload", "Upload slot for file upload requested"); - started = true; - } + Logging.d("httpupload", "Upload slot for file upload requested"); + started = true; } catch (FileNotFoundException e) { Logging.e("httpupload", "Could not find file, exception message: " + e.getMessage()); } return started; } - private Jid getHost(Account account) { - Jid host = account.getXmppConnection().findDiscoItemByFeature(FileTransferHttp.NAMESPACE); - if (null == host) { - host = account.getXmppConnection().findDiscoItemByFeature(HttpUpload.NAMESPACE); - } - return host; - } - /** * Checks whether a message can be sent using this service or not. * @@ -99,6 +85,7 @@ public class HttpUploadFileTransferService extends AbstractFileTransferService i && null != message.getConversation().getAccount() && null != message.getFileParams() && message.needsUploading() - && AccountUtil.isHttpUploadAvailable(message.getConversation().getAccount(), message.getFileParams().getSize()); + && (AccountUtil.isHttpUploadAvailable(message.getConversation().getAccount(), message.getFileParams().getSize()) + || AccountUtil.isFileTransferHttpAvailable(message.getConversation().getAccount())); } } diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java index df7fc922..9e550988 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java @@ -24,6 +24,7 @@ import de.thedevstack.conversationsplus.ConversationsPlusColors; import de.thedevstack.conversationsplus.ConversationsPlusPreferences; import de.thedevstack.conversationsplus.ui.listeners.ShowResourcesListDialogListener; import de.thedevstack.conversationsplus.utils.ImageUtil; +import de.thedevstack.conversationsplus.utils.MessageUtil; import de.tzur.conversations.Settings; import de.thedevstack.conversationsplus.R; import de.thedevstack.conversationsplus.entities.Account; @@ -108,10 +109,7 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { imagePreview.setVisibility(View.GONE); CharSequence msgText = preview.first; String msgPrefix = null; - if (message.getStatus() == Message.STATUS_SEND - || message.getStatus() == Message.STATUS_SEND_DISPLAYED - || message.getStatus() == Message.STATUS_SEND_FAILED - || message.getStatus() == Message.STATUS_SEND_RECEIVED) { + if (MessageUtil.isMessageSent(message)) { msgPrefix = activity.getString(R.string.cplus_me); } else if (conversation.getMode() == Conversation.MODE_MULTI) { msgPrefix = UIHelper.getMessageDisplayName(message); diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java index e49575f6..9a501b89 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java @@ -496,14 +496,31 @@ public class MessageAdapter extends ArrayAdapter<Message> { private void displayFileMessage(final Message message, ViewHolder viewHolder) { Transferable transferable = message.getTransferable(); - if (null != transferable) { + if (FileStatus.CHECKING_FILE_SIZE == message.getFileParams().getFileStatus()) { + displayInfoMessage(viewHolder, activity.getString(R.string.checking_remote_filesize)); + } else if (MessageUtil.isAttachedFileAnImage(message) + && (FileStatus.DOWNLOADED == message.getFileParams().getFileStatus()) + || FileStatus.DELETED == message.getFileParams().getFileStatus() + || FileStatus.DELETING == message.getFileParams().getFileStatus() + || FileStatus.DELETE_FAILED == message.getFileParams().getFileStatus() + || FileStatus.UPLOADED == message.getFileParams().getFileStatus()) { + displayImageMessage(viewHolder, message); + } else if ((MessageUtil.isTypeFileAndDecrypted(message) || FileStatus.DOWNLOADED == message.getFileParams().getFileStatus()) + && !MessageUtil.needsDownload(message)) { + displayOpenableMessage(viewHolder, message); + } else if (Message.Decision.NEVER == message.treatAsDownloadable() || !MessageUtil.mayFileRemoteAvailable(message)) { + displayTextMessage(viewHolder, message); + } else if (FileStatus.UPLOAD_FAILED == message.getFileParams().getFileStatus()) { + displayImageMessage(viewHolder, message); // TODO Show failed status + } else if (null != transferable) { switch (transferable.getStatus()) { case Transferable.STATUS_OFFER: case Transferable.STATUS_OFFER_CHECK_FILESIZE: displayDownloadableMessage(viewHolder, message); break; case Transferable.STATUS_UPLOADING: - displayFileMessage(message, viewHolder); + // Should not happen, since this is now covered by the other if-statements + // TODO Maybe in Jingle File Transfer?? Needs to be checked! break; case Transferable.STATUS_DELETED: case Transferable.STATUS_CHECKING: @@ -513,15 +530,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first); break; } - } else if (FileStatus.CHECKING_FILE_SIZE == message.getFileParams().getFileStatus()) { - displayInfoMessage(viewHolder, activity.getString(R.string.checking_remote_filesize)); - } else if (MessageUtil.isAttachedFileAnImage(message) && FileStatus.DOWNLOADED == message.getFileParams().getFileStatus()) { - displayImageMessage(viewHolder, message); - } else if ((MessageUtil.isTypeFileAndDecrypted(message) || FileStatus.DOWNLOADED == message.getFileParams().getFileStatus()) - && !MessageUtil.needsDownload(message)) { - displayOpenableMessage(viewHolder, message); - } else if (Message.Decision.NEVER == message.treatAsDownloadable() || !MessageUtil.mayFileRemoteAvailable(message)) { - displayTextMessage(viewHolder, message); } else { displayDownloadableMessage(viewHolder, message); } diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/MessageDetailsDialog.java b/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/MessageDetailsDialog.java index c640ce6d..b43384a4 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/MessageDetailsDialog.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/dialogs/MessageDetailsDialog.java @@ -56,7 +56,7 @@ public class MessageDetailsDialog extends AbstractAlertDialog { * @param message the message to display in dialog */ protected void displayFileInfo(View view, Message message) { - if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE || message.getTransferable() != null) { + if (message.isHttpUploaded() || message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE || message.getTransferable() != null) { Logging.d("messagedetailsfile", "File is stored in path: " + message.getRelativeFilePath()); view.findViewById(R.id.dlgMsgDetFileTable).setVisibility(View.VISIBLE); if (null != message.getFileParams()) { diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ResizePictureUserDecisionListener.java b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ResizePictureUserDecisionListener.java index 1574bb85..68d2e47c 100644 --- a/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ResizePictureUserDecisionListener.java +++ b/src/main/java/de/thedevstack/conversationsplus/ui/listeners/ResizePictureUserDecisionListener.java @@ -31,6 +31,7 @@ import de.thedevstack.conversationsplus.ui.UiCallback; import de.thedevstack.conversationsplus.ui.XmppActivity; import de.thedevstack.conversationsplus.utils.MimeUtils; import de.thedevstack.conversationsplus.utils.StreamUtil; +import de.thedevstack.conversationsplus.utils.UiUpdateHelper; /** * Listener to let the user decide whether to resize a picture before sending or not. @@ -57,6 +58,7 @@ public class ResizePictureUserDecisionListener implements UserDecisionListener { @Override public void success(Message message) { + UiUpdateHelper.updateConversationUi(); ResizePictureUserDecisionListener.this.xmppConnectionService.sendMessage(message); } diff --git a/src/main/java/de/thedevstack/conversationsplus/utils/MessageUtil.java b/src/main/java/de/thedevstack/conversationsplus/utils/MessageUtil.java index e0d627b9..5e629485 100644 --- a/src/main/java/de/thedevstack/conversationsplus/utils/MessageUtil.java +++ b/src/main/java/de/thedevstack/conversationsplus/utils/MessageUtil.java @@ -181,6 +181,7 @@ public final class MessageUtil { 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: @@ -283,7 +284,7 @@ public final class MessageUtil { fileParams.setHeight(imageHeight); } String relativeFilePathFromMessage = message.getRelativeFilePath(); - if (null != relativeFilePathFromMessage && relativeFilePathFromMessage.startsWith("/")) { + if (null != relativeFilePathFromMessage && relativeFilePathFromMessage.startsWith("/") && (null == fileParams.getPath() || !relativeFilePathFromMessage.equals(fileParams.getPath()))) { fileParams.setPath(relativeFilePathFromMessage); } } diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java index 1082e19f..b886bf65 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java @@ -1208,6 +1208,7 @@ public class XmppConnection implements Runnable { disconnect(true); return; } + Logging.d("SendIqPacket", "Outgoing stanza: " + packet.toString()); tagWriter.writeStanzaAsync(packet); if (packet instanceof AbstractAcknowledgeableStanza) { AbstractAcknowledgeableStanza stanza = (AbstractAcknowledgeableStanza) packet; diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/FileTransferHttp.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/FileTransferHttp.java index 28f4f870..1c6544b4 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/FileTransferHttp.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/FileTransferHttp.java @@ -1,8 +1,9 @@ package de.thedevstack.conversationsplus.xmpp.filetransfer.http; /** - * Created by steckbrief on 21.08.2016. + * */ public interface FileTransferHttp { String NAMESPACE = "urn:xmpp:filetransfer:http"; + String DEFAULT_MIME_TYPE = "application/octet-stream"; } diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeleteSlotRequestPacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeleteRequestPacket.java index e389d851..d358a266 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeleteSlotRequestPacket.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeleteRequestPacket.java @@ -7,19 +7,19 @@ import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; /** * Created by steckbrief on 21.08.2016. */ -public class DeleteSlotRequestPacket extends IqPacket { +public class DeleteRequestPacket extends IqPacket { public static final String ELEMENT_NAME = "request"; public static final String FILEURL_ELEMENT_NAME = "fileurl"; private Element requestElement; private String fileurl; - private DeleteSlotRequestPacket() { + private DeleteRequestPacket() { super(TYPE.GET); - this.requestElement = super.addChild(DeleteSlotRequestPacket.ELEMENT_NAME, FileTransferHttp.NAMESPACE); + this.requestElement = super.addChild(DeleteRequestPacket.ELEMENT_NAME, FileTransferHttp.NAMESPACE); this.requestElement.setAttribute("type", "delete"); } - public DeleteSlotRequestPacket(String fileurl) { + public DeleteRequestPacket(String fileurl) { this(); this.setFileURL(fileurl); } diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeleteSlotPacketParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeleteSlotPacketParser.java deleted file mode 100644 index 7c011449..00000000 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeleteSlotPacketParser.java +++ /dev/null @@ -1,29 +0,0 @@ -package de.thedevstack.conversationsplus.xmpp.filetransfer.http.delete; - -import de.thedevstack.conversationsplus.xml.Element; -import de.thedevstack.conversationsplus.xmpp.IqPacketParser; -import de.thedevstack.conversationsplus.xmpp.exceptions.UnexpectedIqPacketTypeException; -import de.thedevstack.conversationsplus.xmpp.exceptions.XmppException; -import de.thedevstack.conversationsplus.xmpp.filetransfer.http.FileTransferHttp; -import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; -import de.thedevstack.conversationsplus.xmpp.utils.ErrorIqPacketExceptionHelper; - -/** - * Created by steckbrief on 21.08.2016. - */ -public class DeleteSlotPacketParser extends IqPacketParser { - public static String parseDeleteToken(IqPacket packet) throws XmppException { - String deletetoken = null; - if (packet.getType() == IqPacket.TYPE.RESULT) { - Element slot = findRequiredChild(packet, "slot", FileTransferHttp.NAMESPACE); - - deletetoken = findRequiredChildContent(slot, "deletetoken"); - } else if (packet.getType() == IqPacket.TYPE.ERROR) { - ErrorIqPacketExceptionHelper.throwIqErrorException(packet); - } else { - throw new UnexpectedIqPacketTypeException(packet, packet.getType(), IqPacket.TYPE.RESULT, IqPacket.TYPE.ERROR); - } - - return deletetoken; - } -} diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeletedPacketParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeletedPacketParser.java new file mode 100644 index 00000000..df17a997 --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/DeletedPacketParser.java @@ -0,0 +1,43 @@ +package de.thedevstack.conversationsplus.xmpp.filetransfer.http.delete; + +import de.thedevstack.conversationsplus.xml.Element; +import de.thedevstack.conversationsplus.xmpp.IqPacketParser; +import de.thedevstack.conversationsplus.xmpp.exceptions.UnexpectedIqPacketTypeException; +import de.thedevstack.conversationsplus.xmpp.exceptions.XmppException; +import de.thedevstack.conversationsplus.xmpp.filetransfer.http.FileTransferHttp; +import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; +import de.thedevstack.conversationsplus.xmpp.utils.ErrorIqPacketExceptionHelper; + +/** + * IqPacketParser to parse the response of a remote file delete request. + * This parser parses a IqPacket according to the specification 'filetransfer for XMPP over http". + */ +public class DeletedPacketParser extends IqPacketParser { + /** + * Parses an IqPacket. + * <pre> + * <iq from='montague.tld' + * id='delete-file_002' + * to='romeo@montague.tld/garden' + * type='result'> + * <deleted xmlns='urn:xmpp:filetransfer:http'/> + * </iq> + * </pre> + * @param packet the packet to parse + * @return <code>true</code> if the result packet contains a deleted element of namespace <code>urn:xmpp:filetransfer:http</code> + * @throws XmppException in case of IqPacket type error or {@link UnexpectedIqPacketTypeException} in case of an unexpected IqPacket type. + */ + public static boolean parseDeleteToken(IqPacket packet) throws XmppException { + boolean successfullyDeleted = false; + if (packet.getType() == IqPacket.TYPE.RESULT) { + Element deletedElement = findRequiredChild(packet, "deleted", FileTransferHttp.NAMESPACE); + successfullyDeleted = null != deletedElement; + } else if (packet.getType() == IqPacket.TYPE.ERROR) { + ErrorIqPacketExceptionHelper.throwIqErrorException(packet); + } else { + throw new UnexpectedIqPacketTypeException(packet, packet.getType(), IqPacket.TYPE.RESULT, IqPacket.TYPE.ERROR); + } + + return successfullyDeleted; + } +} diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/FileTransferHttpDeleteSlotRequestPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/FileTransferHttpDeleteRequestPacketGenerator.java index ac7de74e..88ad5d5a 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/FileTransferHttpDeleteSlotRequestPacketGenerator.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/delete/FileTransferHttpDeleteRequestPacketGenerator.java @@ -6,7 +6,7 @@ import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; /** * Created by steckbrief on 21.08.2016. */ -public final class FileTransferHttpDeleteSlotRequestPacketGenerator { +public final class FileTransferHttpDeleteRequestPacketGenerator { /** * Generates the IqPacket to request a slot to delete a file previously uploaded via http upload. * The attributes from and id are not set in here - this is added while sending the packet. @@ -25,7 +25,7 @@ public final class FileTransferHttpDeleteSlotRequestPacketGenerator { * @return the IqPacket */ public static IqPacket generate(Jid host, String fileurl) { - DeleteSlotRequestPacket packet = new DeleteSlotRequestPacket(fileurl); + DeleteRequestPacket packet = new DeleteRequestPacket(fileurl); packet.setTo(host); return packet; } @@ -33,7 +33,7 @@ public final class FileTransferHttpDeleteSlotRequestPacketGenerator { /** * Utility class - avoid instantiation */ - private FileTransferHttpDeleteSlotRequestPacketGenerator() { + private FileTransferHttpDeleteRequestPacketGenerator() { // Helper class - avoid instantiation } } diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/FileTransferHttpUploadSlotRequestPacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/FileTransferHttpUploadSlotRequestPacket.java new file mode 100644 index 00000000..2d7ed1c7 --- /dev/null +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/FileTransferHttpUploadSlotRequestPacket.java @@ -0,0 +1,53 @@ +package de.thedevstack.conversationsplus.xmpp.filetransfer.http.upload; + +import de.thedevstack.conversationsplus.xml.Element; +import de.thedevstack.conversationsplus.xmpp.filetransfer.http.FileTransferHttp; +import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; + +/** + * + */ +public class FileTransferHttpUploadSlotRequestPacket extends IqPacket { + public static final String ELEMENT_NAME = "request"; + public static final String FILENAME_ELEMENT_NAME = "filename"; + public static final String FILESIZE_ELEMENT_NAME = "size"; + public static final String MIME_ELEMENT_NAME = "content-type"; + private static final String RECIPIENT_ATTRIBUTE_NAME = "recipient"; + private Element requestElement; + private String filename; + private long filesize; + private String mime; + + public FileTransferHttpUploadSlotRequestPacket(String recipient, String filename, long filesize, String mime) { + super(TYPE.GET); + this.requestElement = super.addChild(FileTransferHttpUploadSlotRequestPacket.ELEMENT_NAME, FileTransferHttp.NAMESPACE); + this.requestElement.setAttribute(RECIPIENT_ATTRIBUTE_NAME, recipient); + this.setFilename(filename); + this.setFilesize(filesize); + this.setMime(mime); + } + + public void setFilename(String filename) { + if (null == filename || filename.isEmpty()) { + throw new IllegalArgumentException("filename must not be null or empty."); + } + this.filename = filename; + this.requestElement.addChild(FILENAME_ELEMENT_NAME).setContent(filename); + } + + public void setFilesize(long filesize) { + if (0 >= filesize) { + throw new IllegalArgumentException("filesize must not be null or empty."); + } + this.filesize = filesize; + this.requestElement.addChild(FILESIZE_ELEMENT_NAME).setContent(String.valueOf(filesize)); + } + + public void setMime(String mime) { + if (null == mime || mime.isEmpty()) { + mime = FileTransferHttp.DEFAULT_MIME_TYPE; + } + this.mime = mime; + this.requestElement.addChild(MIME_ELEMENT_NAME).setContent(mime); + } +} diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/HttpUploadRequestSlotPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/HttpUploadRequestSlotPacketGenerator.java index 4b0a956c..db455b7a 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/HttpUploadRequestSlotPacketGenerator.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/HttpUploadRequestSlotPacketGenerator.java @@ -1,5 +1,7 @@ package de.thedevstack.conversationsplus.xmpp.filetransfer.http.upload; +import de.thedevstack.conversationsplus.entities.Account; +import de.thedevstack.conversationsplus.xmpp.filetransfer.http.FileTransferHttp; import de.thedevstack.conversationsplus.xmpp.jid.Jid; import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; @@ -24,17 +26,38 @@ public final class HttpUploadRequestSlotPacketGenerator { * </request> * </iq> * </pre> - * @param host the jid of the host to request a slot from + * @param account the account requesting a slot * @param filename the filename of the file which will be transferred * @param filesize the filesize of the file which will be transferred * @param mime the mime type of the file which will be transferred - <code>optional</code> and therefore nullable * @return the IqPacket */ - public static IqPacket generate(Jid host, String filename, long filesize, String mime) { - SlotRequestPacket packet = new SlotRequestPacket(filename, filesize); - packet.setTo(host); - packet.setMime((mime == null || mime.isEmpty()) ? HttpUpload.DEFAULT_MIME_TYPE : mime); - return packet; + public static IqPacket generate(Account account, Jid recipient, String filename, long filesize, String mime) { + String namespace = getNamespace(account); + Jid host = getHost(account, namespace); + IqPacket requestPacket; + switch (namespace) { + case HttpUpload.NAMESPACE: + requestPacket = new HttpUploadSlotRequestPacket(filename, filesize, mime); + break; + case FileTransferHttp.NAMESPACE: + default: + requestPacket = new FileTransferHttpUploadSlotRequestPacket(recipient.toString(), filename, filesize, mime); + } + requestPacket.setTo(host); + return requestPacket; + } + + private static String getNamespace(Account account) { + if (null != account.getXmppConnection().findDiscoItemByFeature(FileTransferHttp.NAMESPACE)) { + return FileTransferHttp.NAMESPACE; + } else { + return HttpUpload.NAMESPACE; + } + } + + private static Jid getHost(Account account, String namespace) { + return account.getXmppConnection().findDiscoItemByFeature(namespace); } /** diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/SlotRequestPacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/HttpUploadSlotRequestPacket.java index d0866508..93422d3f 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/SlotRequestPacket.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/HttpUploadSlotRequestPacket.java @@ -6,7 +6,7 @@ import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; /** * */ -public class SlotRequestPacket extends IqPacket { +public class HttpUploadSlotRequestPacket extends IqPacket { public static final String ELEMENT_NAME = "request"; public static final String FILENAME_ELEMENT_NAME = "filename"; public static final String FILESIZE_ELEMENT_NAME = "size"; @@ -16,15 +16,16 @@ public class SlotRequestPacket extends IqPacket { private long filesize; private String mime; - private SlotRequestPacket() { + private HttpUploadSlotRequestPacket() { super(TYPE.GET); - this.requestElement = super.addChild(SlotRequestPacket.ELEMENT_NAME, HttpUpload.NAMESPACE); + this.requestElement = super.addChild(HttpUploadSlotRequestPacket.ELEMENT_NAME, HttpUpload.NAMESPACE); } - public SlotRequestPacket(String filename, long filesize) { + public HttpUploadSlotRequestPacket(String filename, long filesize, String mime) { this(); this.setFilename(filename); this.setFilesize(filesize); + this.setMime(mime); } public void setFilename(String filename) { @@ -45,7 +46,7 @@ public class SlotRequestPacket extends IqPacket { public void setMime(String mime) { if (null == mime || mime.isEmpty()) { - throw new IllegalArgumentException("mime type must not be null or empty."); + mime = HttpUpload.DEFAULT_MIME_TYPE; } this.mime = mime; this.requestElement.addChild(MIME_ELEMENT_NAME).setContent(mime); diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/SlotPacketParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/SlotPacketParser.java index 85d11b6b..e2d629e4 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/SlotPacketParser.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/filetransfer/http/upload/SlotPacketParser.java @@ -2,8 +2,10 @@ package de.thedevstack.conversationsplus.xmpp.filetransfer.http.upload; import de.thedevstack.conversationsplus.xml.Element; import de.thedevstack.conversationsplus.xmpp.IqPacketParser; +import de.thedevstack.conversationsplus.xmpp.exceptions.MissingRequiredElementException; import de.thedevstack.conversationsplus.xmpp.exceptions.UnexpectedIqPacketTypeException; import de.thedevstack.conversationsplus.xmpp.exceptions.XmppException; +import de.thedevstack.conversationsplus.xmpp.filetransfer.http.FileTransferHttp; import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket; import de.thedevstack.conversationsplus.xmpp.utils.ErrorIqPacketExceptionHelper; @@ -11,10 +13,18 @@ import de.thedevstack.conversationsplus.xmpp.utils.ErrorIqPacketExceptionHelper; * */ public final class SlotPacketParser extends IqPacketParser { + private static final String SLOT_ELEMENT_NAME = "slot"; + public static HttpUploadSlot parseGetAndPutUrl(IqPacket packet) throws XmppException { HttpUploadSlot httpUploadSlot = null; if (packet.getType() == IqPacket.TYPE.RESULT) { - Element slot = findRequiredChild(packet, "slot", HttpUpload.NAMESPACE); + Element slot = findChild(packet, SLOT_ELEMENT_NAME, FileTransferHttp.NAMESPACE); + if (null == slot) { + slot = findChild(packet, SLOT_ELEMENT_NAME, HttpUpload.NAMESPACE); + } + if (null == slot) { + throw new MissingRequiredElementException(SLOT_ELEMENT_NAME, "neither " + FileTransferHttp.NAMESPACE + " nor " + HttpUpload.NAMESPACE, packet); + } String getUrl = findRequiredChildContent(slot, "get"); String putUrl = findRequiredChildContent(slot, "put"); diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java index aa85430b..ea93fdb8 100644 --- a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java +++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java @@ -464,6 +464,8 @@ public class JingleConnection implements Transferable { } }); + } else { + fail(); } } |