A src/cheogram/java/com/cheogram/android/BobTransfer.java => src/cheogram/java/com/cheogram/android/BobTransfer.java +129 -0
@@ 0,0 1,129 @@
+package com.cheogram.android;
+
+import android.util.Base64;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.entities.DownloadableFile;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.entities.Transferable;
+import eu.siacs.conversations.http.AesGcmURL;
+import eu.siacs.conversations.services.AbstractConnectionManager;
+import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.utils.CryptoHelper;
+import eu.siacs.conversations.utils.MimeUtils;
+import eu.siacs.conversations.xml.Element;
+import eu.siacs.conversations.xmpp.stanzas.IqPacket;
+
+public class BobTransfer implements Transferable {
+ protected int status = Transferable.STATUS_OFFER;
+ protected Message message;
+ protected URI uri;
+ protected XmppConnectionService xmppConnectionService;
+ protected DownloadableFile file;
+
+ public BobTransfer(Message message, XmppConnectionService xmppConnectionService) throws URISyntaxException {
+ this.message = message;
+ this.xmppConnectionService = xmppConnectionService;
+ this.uri = new URI(message.getFileParams().url);
+ setupFile();
+ }
+
+ private void setupFile() {
+ final String reference = uri.getFragment();
+ if (reference != null && AesGcmURL.IV_KEY.matcher(reference).matches()) {
+ this.file = new DownloadableFile(xmppConnectionService.getCacheDir(), message.getUuid());
+ this.file.setKeyAndIv(CryptoHelper.hexToBytes(reference));
+ Log.d(Config.LOGTAG, "create temporary OMEMO encrypted file: " + this.file.getAbsolutePath() + "(" + message.getMimeType() + ")");
+ } else {
+ this.file = xmppConnectionService.getFileBackend().getFile(message, false);
+ }
+ }
+
+ @Override
+ public boolean start() {
+ if (status == Transferable.STATUS_DOWNLOADING) return true;
+
+ if (xmppConnectionService.hasInternetConnection()) {
+ changeStatus(Transferable.STATUS_DOWNLOADING);
+
+ IqPacket request = new IqPacket(IqPacket.TYPE.GET);
+ request.setTo(message.getCounterpart());
+ final Element dataq = request.addChild("data", "urn:xmpp:bob");
+ dataq.setAttribute("cid", uri.getSchemeSpecificPart());
+ xmppConnectionService.sendIqPacket(message.getConversation().getAccount(), request, (acct, packet) -> {
+ final Element data = packet.findChild("data", "urn:xmpp:bob");
+ if (packet.getType() == IqPacket.TYPE.ERROR || data == null) {
+ Log.d(Config.LOGTAG, "BobTransfer failed: " + packet);
+ xmppConnectionService.showErrorToastInUi(R.string.download_failed_file_not_found);
+ } else {
+ final String contentType = data.getAttribute("type");
+ if (contentType != null) {
+ final String fileExtension = MimeUtils.guessExtensionFromMimeType(contentType);
+ if (fileExtension != null) {
+ xmppConnectionService.getFileBackend().setupRelativeFilePath(message, String.format("%s.%s", message.getUuid(), fileExtension), contentType);
+ Log.d(Config.LOGTAG, "rewriting name for bob based on content type");
+ setupFile();
+ }
+ }
+
+ try {
+ file.getParentFile().mkdirs();
+ if (!file.exists() && !file.createNewFile()) {
+ throw new IOException(file.getAbsolutePath());
+ }
+ final OutputStream outputStream = AbstractConnectionManager.createOutputStream(file, false, false);
+ outputStream.write(Base64.decode(data.getContent(), Base64.DEFAULT));
+ outputStream.flush();
+ outputStream.close();
+
+ final boolean privateMessage = message.isPrivateMessage();
+ message.setType(privateMessage ? Message.TYPE_PRIVATE_FILE : Message.TYPE_FILE);
+ xmppConnectionService.getFileBackend().updateFileParams(message, uri.toString());
+ xmppConnectionService.updateMessage(message);
+ } catch (IOException e) {
+ xmppConnectionService.showErrorToastInUi(R.string.download_failed_could_not_write_file);
+ }
+ }
+ message.setTransferable(null);
+ xmppConnectionService.updateConversationUi();
+ });
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int getStatus() {
+ return status;
+ }
+
+ @Override
+ public int getProgress() {
+ return 0;
+ }
+
+ @Override
+ public Long getFileSize() {
+ return null;
+ }
+
+ @Override
+ public void cancel() {
+ // No real way to cancel an iq in process...
+ changeStatus(Transferable.STATUS_CANCELLED);
+ message.setTransferable(null);
+ }
+
+ protected void changeStatus(int newStatus) {
+ status = newStatus;
+ xmppConnectionService.updateConversationUi();
+ }
+}
M src/main/java/eu/siacs/conversations/entities/Message.java => src/main/java/eu/siacs/conversations/entities/Message.java +1 -1
@@ 930,7 930,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable
fileParams.size = this.transferable.getFileSize();
}
- if (oobUri != null && ("http".equalsIgnoreCase(oobUri.getScheme()) || "https".equalsIgnoreCase(oobUri.getScheme()))) {
+ if (oobUri != null && ("http".equalsIgnoreCase(oobUri.getScheme()) || "https".equalsIgnoreCase(oobUri.getScheme()) || "cid".equalsIgnoreCase(oobUri.getScheme()))) {
fileParams.url = oobUri.toString();
}
}
M src/main/java/eu/siacs/conversations/http/URL.java => src/main/java/eu/siacs/conversations/http/URL.java +1 -1
@@ 9,7 9,7 @@ import okhttp3.HttpUrl;
public class URL {
- public static final List<String> WELL_KNOWN_SCHEMES = Arrays.asList("http", "https", AesGcmURL.PROTOCOL_NAME);
+ public static final List<String> WELL_KNOWN_SCHEMES = Arrays.asList("http", "https", AesGcmURL.PROTOCOL_NAME, "cid");
public static String tryParse(String url) {
final URI uri;
M src/main/java/eu/siacs/conversations/parser/MessageParser.java => src/main/java/eu/siacs/conversations/parser/MessageParser.java +14 -1
@@ 3,6 3,9 @@ package eu.siacs.conversations.parser;
import android.util.Log;
import android.util.Pair;
+import com.cheogram.android.BobTransfer;
+
+import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ 746,7 749,17 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
mXmppConnectionService.databaseBackend.createMessage(message);
final HttpConnectionManager manager = this.mXmppConnectionService.getHttpConnectionManager();
if (message.trusted() && message.treatAsDownloadable() && manager.getAutoAcceptFileSize() > 0) {
- manager.createNewDownloadConnection(message);
+ if (message.getOob() != null && message.getOob().getScheme().equalsIgnoreCase("cid")) {
+ try {
+ BobTransfer transfer = new BobTransfer(message, mXmppConnectionService);
+ message.setTransferable(transfer);
+ transfer.start();
+ } catch (URISyntaxException e) {
+ Log.d(Config.LOGTAG, "BobTransfer failed to parse URI");
+ }
+ } else {
+ manager.createNewDownloadConnection(message);
+ }
} else if (notify) {
if (query != null && query.isCatchup()) {
mXmppConnectionService.getNotificationService().pushFromBacklog(message);
M src/main/java/eu/siacs/conversations/ui/ConversationFragment.java => src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +16 -3
@@ 64,11 64,14 @@ import androidx.databinding.DataBindingUtil;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
+import com.cheogram.android.BobTransfer;
+
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import org.jetbrains.annotations.NotNull;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ 1925,9 1928,19 @@ public class ConversationFragment extends XmppFragment
.show();
return;
}
- activity.xmppConnectionService
- .getHttpConnectionManager()
- .createNewDownloadConnection(message, true);
+ if (message.getOob() != null && message.getOob().getScheme().equalsIgnoreCase("cid")) {
+ try {
+ BobTransfer transfer = new BobTransfer(message, activity.xmppConnectionService);
+ message.setTransferable(transfer);
+ transfer.start();
+ } catch (URISyntaxException e) {
+ Log.d(Config.LOGTAG, "BobTransfer failed to parse URI");
+ }
+ } else {
+ activity.xmppConnectionService
+ .getHttpConnectionManager()
+ .createNewDownloadConnection(message, true);
+ }
}
@SuppressLint("InflateParams")
M src/main/java/eu/siacs/conversations/utils/MessageUtils.java => src/main/java/eu/siacs/conversations/utils/MessageUtils.java +2 -1
@@ 117,6 117,7 @@ public class MessageUtils {
}
public static boolean unInitiatedButKnownSize(Message message) {
- return message.getType() == Message.TYPE_TEXT && message.getTransferable() == null && message.isOOb() && message.getFileParams().size != null && message.getFileParams().url != null;
+ return message.getType() == Message.TYPE_TEXT && message.getTransferable() == null && message.isOOb() && message.getFileParams().url != null &&
+ (message.getFileParams().size != null || (message.getOob() != null && message.getOob().getScheme().equalsIgnoreCase("cid")));
}
}