From 9fc1ead74f7dac214f6664c25f75db530a5016ff Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 16 Jun 2019 22:57:10 +0200 Subject: [PATCH] =?UTF-8?q?use=20ibb=20if=20other=20party=20doesn=E2=80=99?= =?UTF-8?q?t=20annouce=20s5b=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/eu/siacs/conversations/Config.java | 2 +- .../generator/AbstractGenerator.java | 4 +- .../eu/siacs/conversations/xml/Namespace.java | 2 + .../xmpp/jingle/JingleConnection.java | 2034 ++++++++--------- .../xmpp/jingle/JingleInbandTransport.java | 3 + .../xmpp/jingle/stanzas/Content.java | 215 +- 6 files changed, 1128 insertions(+), 1132 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 56615dc97..7cfb5f6e2 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -101,7 +101,7 @@ public final class Config { public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb - public static final boolean DISABLE_HTTP_UPLOAD = false; + public static final boolean DISABLE_HTTP_UPLOAD = true; public static final boolean EXTENDED_SM_LOGGING = false; // log stanza counts public static final boolean BACKGROUND_STANZA_LOGGING = false; //log all stanzas that were received while the app is in background public static final boolean RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE = true; //setting to true might increase power consumption diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java index d320168bb..dc47fc4ed 100644 --- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java @@ -27,8 +27,8 @@ public abstract class AbstractGenerator { Content.Version.FT_3.getNamespace(), Content.Version.FT_4.getNamespace(), Content.Version.FT_5.getNamespace(), - "urn:xmpp:jingle:transports:s5b:1", - "urn:xmpp:jingle:transports:ibb:1", + Namespace.JINGLE_TRANSPORTS_S5B, + Namespace.JINGLE_TRANSPORTS_IBB, "http://jabber.org/protocol/muc", "jabber:x:conference", Namespace.OOB, diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index f58f06373..0d478c586 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -25,4 +25,6 @@ public final class Namespace { public static final String BOOKMARKS = "storage:bookmarks"; public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0"; public static final String AVATAR_CONVERSION = "urn:xmpp:pep-vcard-conversion:0"; + public static final String JINGLE_TRANSPORTS_S5B = "urn:xmpp:jingle:transports:s5b:1"; + public static final String JINGLE_TRANSPORTS_IBB = "urn:xmpp:jingle:transports:ibb:1"; } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 75573acb4..3ec9b5359 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -10,6 +10,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -34,6 +35,7 @@ import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.OnIqPacketReceived; import eu.siacs.conversations.xmpp.jingle.stanzas.Content; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; @@ -43,1119 +45,1111 @@ import rocks.xmpp.addr.Jid; public class JingleConnection implements Transferable { - private JingleConnectionManager mJingleConnectionManager; - private XmppConnectionService mXmppConnectionService; + private static final int JINGLE_STATUS_INITIATED = 0; + private static final int JINGLE_STATUS_ACCEPTED = 1; + private static final int JINGLE_STATUS_FINISHED = 4; + static final int JINGLE_STATUS_TRANSMITTING = 5; + private static final int JINGLE_STATUS_FAILED = 99; + private static final int JINGLE_STATUS_OFFERED = -1; + private JingleConnectionManager mJingleConnectionManager; + private XmppConnectionService mXmppConnectionService; + private Content.Version ftVersion = Content.Version.FT_3; - private static final int JINGLE_STATUS_OFFERED = -1; - protected static final int JINGLE_STATUS_INITIATED = 0; - protected static final int JINGLE_STATUS_ACCEPTED = 1; - protected static final int JINGLE_STATUS_FINISHED = 4; - protected static final int JINGLE_STATUS_TRANSMITTING = 5; - protected static final int JINGLE_STATUS_FAILED = 99; + private int ibbBlockSize = 8192; - private Content.Version ftVersion = Content.Version.FT_3; + private int mJingleStatus = JINGLE_STATUS_OFFERED; + private int mStatus = Transferable.STATUS_UNKNOWN; + private Message message; + private String sessionId; + private Account account; + private Jid initiator; + private Jid responder; + private List candidates = new ArrayList<>(); + private ConcurrentHashMap connections = new ConcurrentHashMap<>(); - private int ibbBlockSize = 8192; + private String transportId; + private Element fileOffer; + private DownloadableFile file = null; - private int mJingleStatus = JINGLE_STATUS_OFFERED; - private int mStatus = Transferable.STATUS_UNKNOWN; - private Message message; - private String sessionId; - private Account account; - private Jid initiator; - private Jid responder; - private List candidates = new ArrayList<>(); - private ConcurrentHashMap connections = new ConcurrentHashMap<>(); + private String contentName; + private String contentCreator; + private Transport initialTransport; - private String transportId; - private Element fileOffer; - private DownloadableFile file = null; + private int mProgress = 0; - private String contentName; - private String contentCreator; - private Transport initialTransport; + private boolean receivedCandidate = false; + private boolean sentCandidate = false; - private int mProgress = 0; + private boolean acceptedAutomatically = false; + private boolean cancelled = false; - private boolean receivedCandidate = false; - private boolean sentCandidate = false; + private XmppAxolotlMessage mXmppAxolotlMessage; - private boolean acceptedAutomatically = false; - private boolean cancelled = false; + private JingleTransport transport = null; - private XmppAxolotlMessage mXmppAxolotlMessage; + private OutputStream mFileOutputStream; + private InputStream mFileInputStream; - private JingleTransport transport = null; + private OnIqPacketReceived responseListener = (account, packet) -> { + if (packet.getType() != IqPacket.TYPE.RESULT) { + fail(IqParser.extractErrorMessage(packet)); + } + }; + private byte[] expectedHash = new byte[0]; + private final OnFileTransmissionStatusChanged onFileTransmissionStatusChanged = new OnFileTransmissionStatusChanged() { - private OutputStream mFileOutputStream; - private InputStream mFileInputStream; + @Override + public void onFileTransmitted(DownloadableFile file) { + if (responding()) { + if (expectedHash.length > 0 && !Arrays.equals(expectedHash, file.getSha1Sum())) { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": hashes did not match"); + } + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": file transmitted(). we are responding"); + sendSuccess(); + mXmppConnectionService.getFileBackend().updateFileParams(message); + mXmppConnectionService.databaseBackend.createMessage(message); + mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVED); + if (acceptedAutomatically) { + message.markUnread(); + if (message.getEncryption() == Message.ENCRYPTION_PGP) { + account.getPgpDecryptionService().decrypt(message, true); + } else { + mXmppConnectionService.getFileBackend().updateMediaScanner(file, () -> JingleConnection.this.mXmppConnectionService.getNotificationService().push(message)); - private OnIqPacketReceived responseListener = (account, packet) -> { - if (packet.getType() != IqPacket.TYPE.RESULT) { - fail(IqParser.extractErrorMessage(packet)); - } - }; - private byte[] expectedHash = new byte[0]; + } + Log.d(Config.LOGTAG, "successfully transmitted file:" + file.getAbsolutePath() + " (" + CryptoHelper.bytesToHex(file.getSha1Sum()) + ")"); + return; + } + } else { + if (ftVersion == Content.Version.FT_5) { //older Conversations will break when receiving a session-info + sendHash(); + } + if (message.getEncryption() == Message.ENCRYPTION_PGP) { + account.getPgpDecryptionService().decrypt(message, false); + } + if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { + file.delete(); + } + } + Log.d(Config.LOGTAG, "successfully transmitted file:" + file.getAbsolutePath() + " (" + CryptoHelper.bytesToHex(file.getSha1Sum()) + ")"); + if (message.getEncryption() != Message.ENCRYPTION_PGP) { + mXmppConnectionService.getFileBackend().updateMediaScanner(file); + } + } - private boolean responding() { - return responder != null && responder.equals(account.getJid()); - } + @Override + public void onFileTransferAborted() { + JingleConnection.this.sendCancel(); + JingleConnection.this.fail(); + } + }; + private OnTransportConnected onIbbTransportConnected = new OnTransportConnected() { + @Override + public void failed() { + Log.d(Config.LOGTAG, "ibb open failed"); + } - private boolean initiating() { - return initiator.equals(account.getJid()); - } + @Override + public void established() { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": ibb transport connected. sending file"); + mJingleStatus = JINGLE_STATUS_TRANSMITTING; + JingleConnection.this.transport.send(file, onFileTransmissionStatusChanged); + } + }; + private OnProxyActivated onProxyActivated = new OnProxyActivated() { - final OnFileTransmissionStatusChanged onFileTransmissionStatusChanged = new OnFileTransmissionStatusChanged() { + @Override + public void success() { + if (initiator.equals(account.getJid())) { + Log.d(Config.LOGTAG, "we were initiating. sending file"); + transport.send(file, onFileTransmissionStatusChanged); + } else { + transport.receive(file, onFileTransmissionStatusChanged); + Log.d(Config.LOGTAG, "we were responding. receiving file"); + } + } - @Override - public void onFileTransmitted(DownloadableFile file) { - if (responding()) { - if (expectedHash.length > 0 && !Arrays.equals(expectedHash,file.getSha1Sum())) { - Log.d(Config.LOGTAG,account.getJid().asBareJid()+": hashes did not match"); - } - sendSuccess(); - mXmppConnectionService.getFileBackend().updateFileParams(message); - mXmppConnectionService.databaseBackend.createMessage(message); - mXmppConnectionService.markMessage(message,Message.STATUS_RECEIVED); - if (acceptedAutomatically) { - message.markUnread(); - if (message.getEncryption() == Message.ENCRYPTION_PGP) { - account.getPgpDecryptionService().decrypt(message, true); - } else { - mXmppConnectionService.getFileBackend().updateMediaScanner(file, () -> JingleConnection.this.mXmppConnectionService.getNotificationService().push(message)); + @Override + public void failed() { + Log.d(Config.LOGTAG, "proxy activation failed"); + } + }; - } - Log.d(Config.LOGTAG,"successfully transmitted file:" + file.getAbsolutePath()+" ("+ CryptoHelper.bytesToHex(file.getSha1Sum())+")"); - return; - } - } else { - if (ftVersion == Content.Version.FT_5) { //older Conversations will break when receiving a session-info - sendHash(); - } - if (message.getEncryption() == Message.ENCRYPTION_PGP) { - account.getPgpDecryptionService().decrypt(message, false); - } - if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { - file.delete(); - } - } - Log.d(Config.LOGTAG,"successfully transmitted file:" + file.getAbsolutePath()+" ("+ CryptoHelper.bytesToHex(file.getSha1Sum())+")"); - if (message.getEncryption() != Message.ENCRYPTION_PGP) { - mXmppConnectionService.getFileBackend().updateMediaScanner(file); - } - } + public JingleConnection(JingleConnectionManager mJingleConnectionManager) { + this.mJingleConnectionManager = mJingleConnectionManager; + this.mXmppConnectionService = mJingleConnectionManager + .getXmppConnectionService(); + } - @Override - public void onFileTransferAborted() { - JingleConnection.this.sendCancel(); - JingleConnection.this.fail(); - } - }; + private boolean responding() { + return responder != null && responder.equals(account.getJid()); + } - InputStream getFileInputStream() { - return this.mFileInputStream; - } + private boolean initiating() { + return initiator.equals(account.getJid()); + } - OutputStream getFileOutputStream() throws IOException { - if (this.file == null) { - Log.d(Config.LOGTAG,"file object was not assigned"); - return null; - } - this.file.getParentFile().mkdirs(); - this.file.createNewFile(); - this.mFileOutputStream = AbstractConnectionManager.createOutputStream(this.file); - return this.mFileOutputStream; - } + InputStream getFileInputStream() { + return this.mFileInputStream; + } - private OnTransportConnected onIbbTransportConnected = new OnTransportConnected() { - @Override - public void failed() { - Log.d(Config.LOGTAG, "ibb open failed"); - } + OutputStream getFileOutputStream() throws IOException { + if (this.file == null) { + Log.d(Config.LOGTAG, "file object was not assigned"); + return null; + } + this.file.getParentFile().mkdirs(); + this.file.createNewFile(); + this.mFileOutputStream = AbstractConnectionManager.createOutputStream(this.file); + return this.mFileOutputStream; + } - @Override - public void established() { - JingleConnection.this.transport.send(file, onFileTransmissionStatusChanged); - } - }; + public String getSessionId() { + return this.sessionId; + } - private OnProxyActivated onProxyActivated = new OnProxyActivated() { + public Account getAccount() { + return this.account; + } - @Override - public void success() { - if (initiator.equals(account.getJid())) { - Log.d(Config.LOGTAG, "we were initiating. sending file"); - transport.send(file, onFileTransmissionStatusChanged); - } else { - transport.receive(file, onFileTransmissionStatusChanged); - Log.d(Config.LOGTAG, "we were responding. receiving file"); - } - } + public Jid getCounterPart() { + return this.message.getCounterpart(); + } - @Override - public void failed() { - Log.d(Config.LOGTAG, "proxy activation failed"); - } - }; + public void deliverPacket(JinglePacket packet) { + boolean returnResult = true; + if (packet.isAction("session-terminate")) { + Reason reason = packet.getReason(); + if (reason != null) { + if (reason.hasChild("cancel")) { + this.fail(); + } else if (reason.hasChild("success")) { + this.receiveSuccess(); + } else { + this.fail(); + } + } else { + this.fail(); + } + } else if (packet.isAction("session-accept")) { + returnResult = receiveAccept(packet); + } else if (packet.isAction("session-info")) { + returnResult = true; + Element checksum = packet.getChecksum(); + Element file = checksum == null ? null : checksum.findChild("file"); + Element hash = file == null ? null : file.findChild("hash", "urn:xmpp:hashes:2"); + if (hash != null && "sha-1".equalsIgnoreCase(hash.getAttribute("algo"))) { + try { + this.expectedHash = Base64.decode(hash.getContent(), Base64.DEFAULT); + } catch (Exception e) { + this.expectedHash = new byte[0]; + } + } + } else if (packet.isAction("transport-info")) { + returnResult = receiveTransportInfo(packet); + } else if (packet.isAction("transport-replace")) { + if (packet.getJingleContent().hasIbbTransport()) { + returnResult = this.receiveFallbackToIbb(packet); + } else { + returnResult = false; + Log.d(Config.LOGTAG, "trying to fallback to something unknown" + + packet.toString()); + } + } else if (packet.isAction("transport-accept")) { + returnResult = this.receiveTransportAccept(packet); + } else { + Log.d(Config.LOGTAG, "packet arrived in connection. action was " + + packet.getAction()); + returnResult = false; + } + IqPacket response; + if (returnResult) { + response = packet.generateResponse(IqPacket.TYPE.RESULT); - public JingleConnection(JingleConnectionManager mJingleConnectionManager) { - this.mJingleConnectionManager = mJingleConnectionManager; - this.mXmppConnectionService = mJingleConnectionManager - .getXmppConnectionService(); - } + } else { + response = packet.generateResponse(IqPacket.TYPE.ERROR); + } + mXmppConnectionService.sendIqPacket(account, response, null); + } - public String getSessionId() { - return this.sessionId; - } + public void init(final Message message) { + if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { + Conversation conversation = (Conversation) message.getConversation(); + conversation.getAccount().getAxolotlService().prepareKeyTransportMessage(conversation, xmppAxolotlMessage -> { + if (xmppAxolotlMessage != null) { + init(message, xmppAxolotlMessage); + } else { + fail(); + } + }); + } else { + init(message, null); + } + } - public Account getAccount() { - return this.account; - } + private void init(Message message, XmppAxolotlMessage xmppAxolotlMessage) { + this.mXmppAxolotlMessage = xmppAxolotlMessage; + this.contentCreator = "initiator"; + this.contentName = this.mJingleConnectionManager.nextRandomId(); + this.message = message; + this.account = message.getConversation().getAccount(); + upgradeNamespace(); + this.initialTransport = getRemoteFeatures().contains(Namespace.JINGLE_TRANSPORTS_S5B) ? Transport.SOCKS : Transport.IBB; + this.message.setTransferable(this); + this.mStatus = Transferable.STATUS_UPLOADING; + this.initiator = this.account.getJid(); + this.responder = this.message.getCounterpart(); + this.sessionId = this.mJingleConnectionManager.nextRandomId(); + this.transportId = this.mJingleConnectionManager.nextRandomId(); + if (this.initialTransport == Transport.IBB) { + this.sendInitRequest(); + } else if (this.candidates.size() > 0) { + this.sendInitRequest(); + } else { + this.mJingleConnectionManager.getPrimaryCandidate(account, (success, candidate) -> { + if (success) { + final JingleSocks5Transport socksConnection = new JingleSocks5Transport(this, candidate); + connections.put(candidate.getCid(), socksConnection); + socksConnection.connect(new OnTransportConnected() { - public Jid getCounterPart() { - return this.message.getCounterpart(); - } + @Override + public void failed() { + Log.d(Config.LOGTAG, + "connection to our own primary candidete failed"); + sendInitRequest(); + } - public void deliverPacket(JinglePacket packet) { - boolean returnResult = true; - if (packet.isAction("session-terminate")) { - Reason reason = packet.getReason(); - if (reason != null) { - if (reason.hasChild("cancel")) { - this.fail(); - } else if (reason.hasChild("success")) { - this.receiveSuccess(); - } else { - this.fail(); - } - } else { - this.fail(); - } - } else if (packet.isAction("session-accept")) { - returnResult = receiveAccept(packet); - } else if (packet.isAction("session-info")) { - returnResult = true; - Element checksum = packet.getChecksum(); - Element file = checksum == null ? null : checksum.findChild("file"); - Element hash = file == null ? null : file.findChild("hash","urn:xmpp:hashes:2"); - if (hash != null && "sha-1".equalsIgnoreCase(hash.getAttribute("algo"))) { - try { - this.expectedHash = Base64.decode(hash.getContent(), Base64.DEFAULT); - } catch (Exception e) { - this.expectedHash = new byte[0]; - } - } - } else if (packet.isAction("transport-info")) { - returnResult = receiveTransportInfo(packet); - } else if (packet.isAction("transport-replace")) { - if (packet.getJingleContent().hasIbbTransport()) { - returnResult = this.receiveFallbackToIbb(packet); - } else { - returnResult = false; - Log.d(Config.LOGTAG, "trying to fallback to something unknown" - + packet.toString()); - } - } else if (packet.isAction("transport-accept")) { - returnResult = this.receiveTransportAccept(packet); - } else { - Log.d(Config.LOGTAG, "packet arrived in connection. action was " - + packet.getAction()); - returnResult = false; - } - IqPacket response; - if (returnResult) { - response = packet.generateResponse(IqPacket.TYPE.RESULT); + @Override + public void established() { + Log.d(Config.LOGTAG, + "successfully connected to our own primary candidate"); + mergeCandidate(candidate); + sendInitRequest(); + } + }); + mergeCandidate(candidate); + } else { + Log.d(Config.LOGTAG, "no primary candidate of our own was found"); + sendInitRequest(); + } + }); + } - } else { - response = packet.generateResponse(IqPacket.TYPE.ERROR); - } - mXmppConnectionService.sendIqPacket(account,response,null); - } + } - public void init(final Message message) { - if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { - Conversation conversation = (Conversation) message.getConversation(); - conversation.getAccount().getAxolotlService().prepareKeyTransportMessage(conversation, new OnMessageCreatedCallback() { - @Override - public void run(XmppAxolotlMessage xmppAxolotlMessage) { - if (xmppAxolotlMessage != null) { - init(message, xmppAxolotlMessage); - } else { - fail(); - } - } - }); - } else { - init(message, null); - } - } + private void upgradeNamespace() { + List features = getRemoteFeatures(); + if (features.contains(Content.Version.FT_5.getNamespace())) { + this.ftVersion = Content.Version.FT_5; + } else if (features.contains(Content.Version.FT_4.getNamespace())) { + this.ftVersion = Content.Version.FT_4; + } + } - private void init(Message message, XmppAxolotlMessage xmppAxolotlMessage) { - this.mXmppAxolotlMessage = xmppAxolotlMessage; - this.contentCreator = "initiator"; - this.contentName = this.mJingleConnectionManager.nextRandomId(); - this.message = message; - this.account = message.getConversation().getAccount(); - upgradeNamespace(); - this.message.setTransferable(this); - this.mStatus = Transferable.STATUS_UPLOADING; - this.initiator = this.account.getJid(); - this.responder = this.message.getCounterpart(); - this.sessionId = this.mJingleConnectionManager.nextRandomId(); - this.transportId = this.mJingleConnectionManager.nextRandomId(); - if (this.candidates.size() > 0) { - this.sendInitRequest(); - } else { - this.mJingleConnectionManager.getPrimaryCandidate(account, - new OnPrimaryCandidateFound() { + private List getRemoteFeatures() { + Jid jid = this.message.getCounterpart(); + String resource = jid != null ? jid.getResource() : null; + if (resource != null) { + Presence presence = this.account.getRoster().getContact(jid).getPresences().getPresences().get(resource); + ServiceDiscoveryResult result = presence != null ? presence.getServiceDiscoveryResult() : null; + return result == null ? Collections.emptyList() : result.getFeatures(); + } else { + return Collections.emptyList(); + } + } - @Override - public void onPrimaryCandidateFound(boolean success, - final JingleCandidate candidate) { - if (success) { - final JingleSocks5Transport socksConnection = new JingleSocks5Transport( - JingleConnection.this, candidate); - connections.put(candidate.getCid(), - socksConnection); - socksConnection - .connect(new OnTransportConnected() { - - @Override - public void failed() { - Log.d(Config.LOGTAG, - "connection to our own primary candidete failed"); - sendInitRequest(); - } - - @Override - public void established() { - Log.d(Config.LOGTAG, - "successfully connected to our own primary candidate"); - mergeCandidate(candidate); - sendInitRequest(); - } - }); - mergeCandidate(candidate); - } else { - Log.d(Config.LOGTAG, "no primary candidate of our own was found"); - sendInitRequest(); - } - } - }); - } - - } - - private void upgradeNamespace() { - Jid jid = this.message.getCounterpart(); - String resource = jid != null ?jid.getResource() : null; - if (resource != null) { - Presence presence = this.account.getRoster().getContact(jid).getPresences().getPresences().get(resource); - ServiceDiscoveryResult result = presence != null ? presence.getServiceDiscoveryResult() : null; - if (result != null) { - List features = result.getFeatures(); - if (features.contains(Content.Version.FT_5.getNamespace())) { - this.ftVersion = Content.Version.FT_5; - } else if (features.contains(Content.Version.FT_4.getNamespace())) { - this.ftVersion = Content.Version.FT_4; - } - } - } - } - - public void init(Account account, JinglePacket packet) { - this.mJingleStatus = JINGLE_STATUS_INITIATED; - Conversation conversation = this.mXmppConnectionService - .findOrCreateConversation(account, - packet.getFrom().asBareJid(), false, false); - this.message = new Message(conversation, "", Message.ENCRYPTION_NONE); - this.message.setStatus(Message.STATUS_RECEIVED); - this.mStatus = Transferable.STATUS_OFFER; - this.message.setTransferable(this); + public void init(Account account, JinglePacket packet) { + this.mJingleStatus = JINGLE_STATUS_INITIATED; + Conversation conversation = this.mXmppConnectionService + .findOrCreateConversation(account, + packet.getFrom().asBareJid(), false, false); + this.message = new Message(conversation, "", Message.ENCRYPTION_NONE); + this.message.setStatus(Message.STATUS_RECEIVED); + this.mStatus = Transferable.STATUS_OFFER; + this.message.setTransferable(this); final Jid from = packet.getFrom(); - this.message.setCounterpart(from); - this.account = account; - this.initiator = packet.getFrom(); - this.responder = this.account.getJid(); - this.sessionId = packet.getSessionId(); - Content content = packet.getJingleContent(); - this.contentCreator = content.getAttribute("creator"); - this.initialTransport = content.hasSocks5Transport() ? Transport.SOCKS : Transport.IBB; - this.contentName = content.getAttribute("name"); - this.transportId = content.getTransportId(); - if (this.initialTransport == Transport.SOCKS) { - this.mergeCandidates(JingleCandidate.parse(content.socks5transport().getChildren())); - } else if (this.initialTransport == Transport.IBB) { - final String receivedBlockSize = content.ibbTransport().getAttribute("block-size"); - if (receivedBlockSize != null) { - try { - this.ibbBlockSize = Math.min(Integer.parseInt(receivedBlockSize), this.ibbBlockSize); - } catch (NumberFormatException e) { - this.sendCancel(); - this.fail(); - return; - } - } else { - this.sendCancel(); - this.fail(); - return; - } - } - this.ftVersion = content.getVersion(); - if (ftVersion == null) { - this.sendCancel(); - this.fail(); - return; - } - this.fileOffer = content.getFileOffer(this.ftVersion); + this.message.setCounterpart(from); + this.account = account; + this.initiator = packet.getFrom(); + this.responder = this.account.getJid(); + this.sessionId = packet.getSessionId(); + Content content = packet.getJingleContent(); + this.contentCreator = content.getAttribute("creator"); + this.initialTransport = content.hasSocks5Transport() ? Transport.SOCKS : Transport.IBB; + this.contentName = content.getAttribute("name"); + this.transportId = content.getTransportId(); + if (this.initialTransport == Transport.SOCKS) { + this.mergeCandidates(JingleCandidate.parse(content.socks5transport().getChildren())); + } else if (this.initialTransport == Transport.IBB) { + final String receivedBlockSize = content.ibbTransport().getAttribute("block-size"); + if (receivedBlockSize != null) { + try { + this.ibbBlockSize = Math.min(Integer.parseInt(receivedBlockSize), this.ibbBlockSize); + } catch (NumberFormatException e) { + Log.d(Config.LOGTAG, "number format exception " + e.getMessage()); + this.sendCancel(); + this.fail(); + return; + } + } else { + Log.d(Config.LOGTAG, "received block size =" + receivedBlockSize); + this.sendCancel(); + this.fail(); + return; + } + } + this.ftVersion = content.getVersion(); + if (ftVersion == null) { + this.sendCancel(); + this.fail(); + return; + } + this.fileOffer = content.getFileOffer(this.ftVersion); - mXmppConnectionService.sendIqPacket(account,packet.generateResponse(IqPacket.TYPE.RESULT),null); + mXmppConnectionService.sendIqPacket(account, packet.generateResponse(IqPacket.TYPE.RESULT), null); - if (fileOffer != null) { - Element encrypted = fileOffer.findChild("encrypted", AxolotlService.PEP_PREFIX); - if (encrypted != null) { - this.mXmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, packet.getFrom().asBareJid()); - } - Element fileSize = fileOffer.findChild("size"); - Element fileNameElement = fileOffer.findChild("name"); - if (fileNameElement != null) { - String[] filename = fileNameElement.getContent() - .toLowerCase(Locale.US).toLowerCase().split("\\."); - String extension = filename[filename.length - 1]; - if (VALID_IMAGE_EXTENSIONS.contains(extension)) { - message.setType(Message.TYPE_IMAGE); - message.setRelativeFilePath(message.getUuid()+"."+extension); - } else if (VALID_CRYPTO_EXTENSIONS.contains( - filename[filename.length - 1])) { - if (filename.length == 3) { - extension = filename[filename.length - 2]; - if (VALID_IMAGE_EXTENSIONS.contains(extension)) { - message.setType(Message.TYPE_IMAGE); - message.setRelativeFilePath(message.getUuid()+"."+extension); - } else { - message.setType(Message.TYPE_FILE); - } - message.setEncryption(Message.ENCRYPTION_PGP); - } - } else { - message.setType(Message.TYPE_FILE); - } - if (message.getType() == Message.TYPE_FILE) { - String suffix = ""; - if (!fileNameElement.getContent().isEmpty()) { - String parts[] = fileNameElement.getContent().split("/"); - suffix = parts[parts.length - 1]; - if (message.getEncryption() == Message.ENCRYPTION_PGP && (suffix.endsWith(".pgp") || suffix.endsWith(".gpg"))) { - suffix = suffix.substring(0,suffix.length() - 4); - } - } - message.setRelativeFilePath(message.getUuid()+"_"+suffix); - } - long size = Long.parseLong(fileSize.getContent()); - message.setBody(Long.toString(size)); - conversation.add(message); - mJingleConnectionManager.updateConversationUi(true); - if (mJingleConnectionManager.hasStoragePermission() - && size < this.mJingleConnectionManager.getAutoAcceptFileSize() - && mXmppConnectionService.isDataSaverDisabled()) { - Log.d(Config.LOGTAG, "auto accepting file from "+ packet.getFrom()); - this.acceptedAutomatically = true; - this.sendAccept(); - } else { - message.markUnread(); - Log.d(Config.LOGTAG, - "not auto accepting new file offer with size: " - + size - + " allowed size:" - + this.mJingleConnectionManager - .getAutoAcceptFileSize()); - this.mXmppConnectionService.getNotificationService().push(message); - } - this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false); - if (mXmppAxolotlMessage != null) { - XmppAxolotlMessage.XmppAxolotlKeyTransportMessage transportMessage = account.getAxolotlService().processReceivingKeyTransportMessage(mXmppAxolotlMessage, false); - if (transportMessage != null) { - message.setEncryption(Message.ENCRYPTION_AXOLOTL); - this.file.setKey(transportMessage.getKey()); - this.file.setIv(transportMessage.getIv()); - message.setFingerprint(transportMessage.getFingerprint()); - } else { - Log.d(Config.LOGTAG,"could not process KeyTransportMessage"); - } - } - this.file.setExpectedSize(size); - message.resetFileParams(); - Log.d(Config.LOGTAG, "receiving file: expecting size of " + this.file.getExpectedSize()); - } else { - this.sendCancel(); - this.fail(); - } - } else { - this.sendCancel(); - this.fail(); - } - } + if (fileOffer != null) { + Element encrypted = fileOffer.findChild("encrypted", AxolotlService.PEP_PREFIX); + if (encrypted != null) { + this.mXmppAxolotlMessage = XmppAxolotlMessage.fromElement(encrypted, packet.getFrom().asBareJid()); + } + Element fileSize = fileOffer.findChild("size"); + Element fileNameElement = fileOffer.findChild("name"); + if (fileNameElement != null) { + String[] filename = fileNameElement.getContent() + .toLowerCase(Locale.US).toLowerCase().split("\\."); + String extension = filename[filename.length - 1]; + if (VALID_IMAGE_EXTENSIONS.contains(extension)) { + message.setType(Message.TYPE_IMAGE); + message.setRelativeFilePath(message.getUuid() + "." + extension); + } else if (VALID_CRYPTO_EXTENSIONS.contains( + filename[filename.length - 1])) { + if (filename.length == 3) { + extension = filename[filename.length - 2]; + if (VALID_IMAGE_EXTENSIONS.contains(extension)) { + message.setType(Message.TYPE_IMAGE); + message.setRelativeFilePath(message.getUuid() + "." + extension); + } else { + message.setType(Message.TYPE_FILE); + } + message.setEncryption(Message.ENCRYPTION_PGP); + } + } else { + message.setType(Message.TYPE_FILE); + } + if (message.getType() == Message.TYPE_FILE) { + String suffix = ""; + if (!fileNameElement.getContent().isEmpty()) { + String parts[] = fileNameElement.getContent().split("/"); + suffix = parts[parts.length - 1]; + if (message.getEncryption() == Message.ENCRYPTION_PGP && (suffix.endsWith(".pgp") || suffix.endsWith(".gpg"))) { + suffix = suffix.substring(0, suffix.length() - 4); + } + } + message.setRelativeFilePath(message.getUuid() + "_" + suffix); + } + long size = Long.parseLong(fileSize.getContent()); + message.setBody(Long.toString(size)); + conversation.add(message); + mJingleConnectionManager.updateConversationUi(true); + this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false); + if (mXmppAxolotlMessage != null) { + XmppAxolotlMessage.XmppAxolotlKeyTransportMessage transportMessage = account.getAxolotlService().processReceivingKeyTransportMessage(mXmppAxolotlMessage, false); + if (transportMessage != null) { + message.setEncryption(Message.ENCRYPTION_AXOLOTL); + this.file.setKey(transportMessage.getKey()); + this.file.setIv(transportMessage.getIv()); + message.setFingerprint(transportMessage.getFingerprint()); + } else { + Log.d(Config.LOGTAG, "could not process KeyTransportMessage"); + } + } + message.resetFileParams(); + this.file.setExpectedSize(size); + if (mJingleConnectionManager.hasStoragePermission() + && size < this.mJingleConnectionManager.getAutoAcceptFileSize() + && mXmppConnectionService.isDataSaverDisabled()) { + Log.d(Config.LOGTAG, "auto accepting file from " + packet.getFrom()); + this.acceptedAutomatically = true; + this.sendAccept(); + } else { + message.markUnread(); + Log.d(Config.LOGTAG, + "not auto accepting new file offer with size: " + + size + + " allowed size:" + + this.mJingleConnectionManager + .getAutoAcceptFileSize()); + this.mXmppConnectionService.getNotificationService().push(message); + } + Log.d(Config.LOGTAG, "receiving file: expecting size of " + this.file.getExpectedSize()); + } else { + this.sendCancel(); + this.fail(); + } + } else { + this.sendCancel(); + this.fail(); + } + } - private void sendInitRequest() { - JinglePacket packet = this.bootstrapPacket("session-initiate"); - Content content = new Content(this.contentCreator, this.contentName); - if (message.isFileOrImage()) { - content.setTransportId(this.transportId); - this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false); - if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { - this.file.setKey(mXmppAxolotlMessage.getInnerKey()); - this.file.setIv(mXmppAxolotlMessage.getIV()); - this.file.setExpectedSize(file.getSize() + 16); - content.setFileOffer(this.file, false, this.ftVersion).addChild(mXmppAxolotlMessage.toElement()); - } else { - this.file.setExpectedSize(file.getSize()); - content.setFileOffer(this.file, false, this.ftVersion); - } - message.resetFileParams(); - try { - this.mFileInputStream = new FileInputStream(file); - } catch (FileNotFoundException e) { - abort(); - return; - } - content.setTransportId(this.transportId); - content.socks5transport().setChildren(getCandidatesAsElements()); - packet.setContent(content); - this.sendJinglePacket(packet,new OnIqPacketReceived() { + private void sendInitRequest() { + JinglePacket packet = this.bootstrapPacket("session-initiate"); + Content content = new Content(this.contentCreator, this.contentName); + if (message.isFileOrImage()) { + content.setTransportId(this.transportId); + this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false); + if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { + this.file.setKey(mXmppAxolotlMessage.getInnerKey()); + this.file.setIv(mXmppAxolotlMessage.getIV()); + this.file.setExpectedSize(file.getSize() + 16); + content.setFileOffer(this.file, false, this.ftVersion).addChild(mXmppAxolotlMessage.toElement()); + } else { + this.file.setExpectedSize(file.getSize()); + content.setFileOffer(this.file, false, this.ftVersion); + } + message.resetFileParams(); + try { + this.mFileInputStream = new FileInputStream(file); + } catch (FileNotFoundException e) { + abort(); + return; + } + content.setTransportId(this.transportId); + if (this.initialTransport == Transport.IBB) { + content.ibbTransport().setAttribute("block-size", Integer.toString(this.ibbBlockSize)); + } else { + content.socks5transport().setChildren(getCandidatesAsElements()); + } + packet.setContent(content); + this.sendJinglePacket(packet, (account, response) -> { + if (response.getType() == IqPacket.TYPE.RESULT) { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": other party received offer"); + if (mJingleStatus == JINGLE_STATUS_OFFERED) { + mJingleStatus = JINGLE_STATUS_INITIATED; + mXmppConnectionService.markMessage(message, Message.STATUS_OFFERED); + } else { + Log.d(Config.LOGTAG, "received ack for offer when status was " + mJingleStatus); + } + } else { + fail(IqParser.extractErrorMessage(response)); + } + }); - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() == IqPacket.TYPE.RESULT) { - Log.d(Config.LOGTAG,account.getJid().asBareJid()+": other party received offer"); - if (mJingleStatus == JINGLE_STATUS_OFFERED) { - mJingleStatus = JINGLE_STATUS_INITIATED; - mXmppConnectionService.markMessage(message, Message.STATUS_OFFERED); - } else { - Log.d(Config.LOGTAG,"received ack for offer when status was "+mJingleStatus); - } - } else { - fail(IqParser.extractErrorMessage(packet)); - } - } - }); + } + } - } - } + private void sendHash() { + JinglePacket packet = this.bootstrapPacket("session-info"); + packet.addChecksum(file.getSha1Sum(), ftVersion.getNamespace()); + this.sendJinglePacket(packet); + } - private void sendHash() { - JinglePacket packet = this.bootstrapPacket("session-info"); - packet.addChecksum(file.getSha1Sum(),ftVersion.getNamespace()); - this.sendJinglePacket(packet); - } + private List getCandidatesAsElements() { + List elements = new ArrayList<>(); + for (JingleCandidate c : this.candidates) { + if (c.isOurs()) { + elements.add(c.toElement()); + } + } + return elements; + } - private List getCandidatesAsElements() { - List elements = new ArrayList<>(); - for (JingleCandidate c : this.candidates) { - if (c.isOurs()) { - elements.add(c.toElement()); - } - } - return elements; - } + private void sendAccept() { + mJingleStatus = JINGLE_STATUS_ACCEPTED; + this.mStatus = Transferable.STATUS_DOWNLOADING; + this.mJingleConnectionManager.updateConversationUi(true); + if (initialTransport == Transport.SOCKS) { + sendAcceptSocks(); + } else { + sendAcceptIbb(); + } + } - private void sendAccept() { - mJingleStatus = JINGLE_STATUS_ACCEPTED; - this.mStatus = Transferable.STATUS_DOWNLOADING; - this.mJingleConnectionManager.updateConversationUi(true); - if (initialTransport == Transport.SOCKS) { - sendAcceptSocks(); - } else { - sendAcceptIbb(); - } - } + private void sendAcceptSocks() { + this.mJingleConnectionManager.getPrimaryCandidate(this.account, (success, candidate) -> { + final JinglePacket packet = bootstrapPacket("session-accept"); + final Content content = new Content(contentCreator, contentName); + content.setFileOffer(fileOffer, ftVersion); + content.setTransportId(transportId); + if (success && candidate != null && !equalCandidateExists(candidate)) { + final JingleSocks5Transport socksConnection = new JingleSocks5Transport(this, candidate); + connections.put(candidate.getCid(), socksConnection); + socksConnection.connect(new OnTransportConnected() { - private void sendAcceptSocks() { - this.mJingleConnectionManager.getPrimaryCandidate(this.account, new OnPrimaryCandidateFound() { - @Override - public void onPrimaryCandidateFound(boolean success, final JingleCandidate candidate) { - final JinglePacket packet = bootstrapPacket("session-accept"); - final Content content = new Content(contentCreator,contentName); - content.setFileOffer(fileOffer, ftVersion); - content.setTransportId(transportId); - if (success && candidate != null && !equalCandidateExists(candidate)) { - final JingleSocks5Transport socksConnection = new JingleSocks5Transport( - JingleConnection.this, - candidate); - connections.put(candidate.getCid(), socksConnection); - socksConnection.connect(new OnTransportConnected() { + @Override + public void failed() { + Log.d(Config.LOGTAG, "connection to our own primary candidate failed"); + content.socks5transport().setChildren(getCandidatesAsElements()); + packet.setContent(content); + sendJinglePacket(packet); + connectNextCandidate(); + } - @Override - public void failed() { - Log.d(Config.LOGTAG,"connection to our own primary candidate failed"); - content.socks5transport().setChildren(getCandidatesAsElements()); - packet.setContent(content); - sendJinglePacket(packet); - connectNextCandidate(); - } + @Override + public void established() { + Log.d(Config.LOGTAG, "connected to primary candidate"); + mergeCandidate(candidate); + content.socks5transport().setChildren(getCandidatesAsElements()); + packet.setContent(content); + sendJinglePacket(packet); + connectNextCandidate(); + } + }); + } else { + Log.d(Config.LOGTAG, "did not find a primary candidate for ourself"); + content.socks5transport().setChildren(getCandidatesAsElements()); + packet.setContent(content); + sendJinglePacket(packet); + connectNextCandidate(); + } + }); + } - @Override - public void established() { - Log.d(Config.LOGTAG, "connected to primary candidate"); - mergeCandidate(candidate); - content.socks5transport().setChildren(getCandidatesAsElements()); - packet.setContent(content); - sendJinglePacket(packet); - connectNextCandidate(); - } - }); - } else { - Log.d(Config.LOGTAG,"did not find a primary candidate for ourself"); - content.socks5transport().setChildren(getCandidatesAsElements()); - packet.setContent(content); - sendJinglePacket(packet); - connectNextCandidate(); - } - } - }); - } + private void sendAcceptIbb() { + this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); + final JinglePacket packet = bootstrapPacket("session-accept"); + final Content content = new Content(contentCreator, contentName); + content.setFileOffer(fileOffer, ftVersion); + content.setTransportId(transportId); + content.ibbTransport().setAttribute("block-size", this.ibbBlockSize); + packet.setContent(content); + this.transport.receive(file, onFileTransmissionStatusChanged); + this.sendJinglePacket(packet); + } - private void sendAcceptIbb() { - this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); - final JinglePacket packet = bootstrapPacket("session-accept"); - final Content content = new Content(contentCreator,contentName); - content.setFileOffer(fileOffer, ftVersion); - content.setTransportId(transportId); - content.ibbTransport().setAttribute("block-size",this.ibbBlockSize); - packet.setContent(content); - this.sendJinglePacket(packet); - } + private JinglePacket bootstrapPacket(String action) { + JinglePacket packet = new JinglePacket(); + packet.setAction(action); + packet.setFrom(account.getJid()); + packet.setTo(this.message.getCounterpart()); + packet.setSessionId(this.sessionId); + packet.setInitiator(this.initiator); + return packet; + } - private JinglePacket bootstrapPacket(String action) { - JinglePacket packet = new JinglePacket(); - packet.setAction(action); - packet.setFrom(account.getJid()); - packet.setTo(this.message.getCounterpart()); - packet.setSessionId(this.sessionId); - packet.setInitiator(this.initiator); - return packet; - } + private void sendJinglePacket(JinglePacket packet) { + mXmppConnectionService.sendIqPacket(account, packet, responseListener); + } - private void sendJinglePacket(JinglePacket packet) { - mXmppConnectionService.sendIqPacket(account,packet,responseListener); - } + private void sendJinglePacket(JinglePacket packet, OnIqPacketReceived callback) { + mXmppConnectionService.sendIqPacket(account, packet, callback); + } - private void sendJinglePacket(JinglePacket packet, OnIqPacketReceived callback) { - mXmppConnectionService.sendIqPacket(account,packet,callback); - } + private boolean receiveAccept(JinglePacket packet) { + this.mJingleStatus = JINGLE_STATUS_ACCEPTED; + mXmppConnectionService.markMessage(message, Message.STATUS_UNSEND); + Content content = packet.getJingleContent(); + if (content.hasSocks5Transport()) { + mergeCandidates(JingleCandidate.parse(content.socks5transport().getChildren())); + this.connectNextCandidate(); + } else if (content.hasIbbTransport()) { + String receivedBlockSize = packet.getJingleContent().ibbTransport().getAttribute("block-size"); + if (receivedBlockSize != null) { + int bs = Integer.parseInt(receivedBlockSize); + if (bs > this.ibbBlockSize) { + this.ibbBlockSize = bs; + } + } + this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); + this.transport.connect(onIbbTransportConnected); + } + return true; + } - private boolean receiveAccept(JinglePacket packet) { - Content content = packet.getJingleContent(); - mergeCandidates(JingleCandidate.parse(content.socks5transport() - .getChildren())); - this.mJingleStatus = JINGLE_STATUS_ACCEPTED; - mXmppConnectionService.markMessage(message, Message.STATUS_UNSEND); - this.connectNextCandidate(); - return true; - } + private boolean receiveTransportInfo(JinglePacket packet) { + Content content = packet.getJingleContent(); + if (content.hasSocks5Transport()) { + if (content.socks5transport().hasChild("activated")) { + if ((this.transport != null) && (this.transport instanceof JingleSocks5Transport)) { + onProxyActivated.success(); + } else { + String cid = content.socks5transport().findChild("activated").getAttribute("cid"); + Log.d(Config.LOGTAG, "received proxy activated (" + cid + + ")prior to choosing our own transport"); + JingleSocks5Transport connection = this.connections.get(cid); + if (connection != null) { + connection.setActivated(true); + } else { + Log.d(Config.LOGTAG, "activated connection not found"); + this.sendCancel(); + this.fail(); + } + } + return true; + } else if (content.socks5transport().hasChild("proxy-error")) { + onProxyActivated.failed(); + return true; + } else if (content.socks5transport().hasChild("candidate-error")) { + Log.d(Config.LOGTAG, "received candidate error"); + this.receivedCandidate = true; + if (mJingleStatus == JINGLE_STATUS_ACCEPTED && this.sentCandidate) { + this.connect(); + } + return true; + } else if (content.socks5transport().hasChild("candidate-used")) { + String cid = content.socks5transport().findChild("candidate-used").getAttribute("cid"); + if (cid != null) { + Log.d(Config.LOGTAG, "candidate used by counterpart:" + cid); + JingleCandidate candidate = getCandidate(cid); + if (candidate == null) { + Log.d(Config.LOGTAG, "could not find candidate with cid=" + cid); + return false; + } + candidate.flagAsUsedByCounterpart(); + this.receivedCandidate = true; + if (mJingleStatus == JINGLE_STATUS_ACCEPTED && this.sentCandidate) { + this.connect(); + } else { + Log.d(Config.LOGTAG, "ignoring because file is already in transmission or we haven't sent our candidate yet status=" + mJingleStatus + " sentCandidate=" + sentCandidate); + } + return true; + } else { + return false; + } + } else { + return false; + } + } else { + return true; + } + } - private boolean receiveTransportInfo(JinglePacket packet) { - Content content = packet.getJingleContent(); - if (content.hasSocks5Transport()) { - if (content.socks5transport().hasChild("activated")) { - if ((this.transport != null) && (this.transport instanceof JingleSocks5Transport)) { - onProxyActivated.success(); - } else { - String cid = content.socks5transport().findChild("activated").getAttribute("cid"); - Log.d(Config.LOGTAG, "received proxy activated (" + cid - + ")prior to choosing our own transport"); - JingleSocks5Transport connection = this.connections.get(cid); - if (connection != null) { - connection.setActivated(true); - } else { - Log.d(Config.LOGTAG, "activated connection not found"); - this.sendCancel(); - this.fail(); - } - } - return true; - } else if (content.socks5transport().hasChild("proxy-error")) { - onProxyActivated.failed(); - return true; - } else if (content.socks5transport().hasChild("candidate-error")) { - Log.d(Config.LOGTAG, "received candidate error"); - this.receivedCandidate = true; - if (mJingleStatus == JINGLE_STATUS_ACCEPTED && this.sentCandidate) { - this.connect(); - } - return true; - } else if (content.socks5transport().hasChild("candidate-used")) { - String cid = content.socks5transport() - .findChild("candidate-used").getAttribute("cid"); - if (cid != null) { - Log.d(Config.LOGTAG, "candidate used by counterpart:" + cid); - JingleCandidate candidate = getCandidate(cid); - if (candidate == null) { - Log.d(Config.LOGTAG,"could not find candidate with cid="+cid); - return false; - } - candidate.flagAsUsedByCounterpart(); - this.receivedCandidate = true; - if (mJingleStatus == JINGLE_STATUS_ACCEPTED && this.sentCandidate) { - this.connect(); - } else { - Log.d(Config.LOGTAG, "ignoring because file is already in transmission or we haven't sent our candidate yet status="+mJingleStatus+" sentCandidate="+Boolean.toString(sentCandidate)); - } - return true; - } else { - return false; - } - } else { - return false; - } - } else { - return true; - } - } + private void connect() { + final JingleSocks5Transport connection = chooseConnection(); + this.transport = connection; + if (connection == null) { + Log.d(Config.LOGTAG, "could not find suitable candidate"); + this.disconnectSocks5Connections(); + if (initiating()) { + this.sendFallbackToIbb(); + } + } else { + this.mJingleStatus = JINGLE_STATUS_TRANSMITTING; + if (connection.needsActivation()) { + if (connection.getCandidate().isOurs()) { + final String sid; + if (ftVersion == Content.Version.FT_3) { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": use session ID instead of transport ID to activate proxy"); + sid = getSessionId(); + } else { + sid = getTransportId(); + } + Log.d(Config.LOGTAG, "candidate " + + connection.getCandidate().getCid() + + " was our proxy. going to activate"); + IqPacket activation = new IqPacket(IqPacket.TYPE.SET); + activation.setTo(connection.getCandidate().getJid()); + activation.query("http://jabber.org/protocol/bytestreams") + .setAttribute("sid", sid); + activation.query().addChild("activate") + .setContent(this.getCounterPart().toString()); + mXmppConnectionService.sendIqPacket(account, activation, (account, response) -> { + if (response.getType() != IqPacket.TYPE.RESULT) { + onProxyActivated.failed(); + } else { + onProxyActivated.success(); + sendProxyActivated(connection.getCandidate().getCid()); + } + }); + } else { + Log.d(Config.LOGTAG, + "candidate " + + connection.getCandidate().getCid() + + " was a proxy. waiting for other party to activate"); + } + } else { + if (initiating()) { + Log.d(Config.LOGTAG, "we were initiating. sending file"); + connection.send(file, onFileTransmissionStatusChanged); + } else { + Log.d(Config.LOGTAG, "we were responding. receiving file"); + connection.receive(file, onFileTransmissionStatusChanged); + } + } + } + } - private void connect() { - final JingleSocks5Transport connection = chooseConnection(); - this.transport = connection; - if (connection == null) { - Log.d(Config.LOGTAG, "could not find suitable candidate"); - this.disconnectSocks5Connections(); - if (initiating()) { - this.sendFallbackToIbb(); - } - } else { - this.mJingleStatus = JINGLE_STATUS_TRANSMITTING; - if (connection.needsActivation()) { - if (connection.getCandidate().isOurs()) { - final String sid; - if (ftVersion == Content.Version.FT_3) { - Log.d(Config.LOGTAG,account.getJid().asBareJid()+": use session ID instead of transport ID to activate proxy"); - sid = getSessionId(); - } else { - sid = getTransportId(); - } - Log.d(Config.LOGTAG, "candidate " - + connection.getCandidate().getCid() - + " was our proxy. going to activate"); - IqPacket activation = new IqPacket(IqPacket.TYPE.SET); - activation.setTo(connection.getCandidate().getJid()); - activation.query("http://jabber.org/protocol/bytestreams") - .setAttribute("sid", sid); - activation.query().addChild("activate") - .setContent(this.getCounterPart().toString()); - mXmppConnectionService.sendIqPacket(account,activation, - new OnIqPacketReceived() { + private JingleSocks5Transport chooseConnection() { + JingleSocks5Transport connection = null; + for (Entry cursor : connections + .entrySet()) { + JingleSocks5Transport currentConnection = cursor.getValue(); + // Log.d(Config.LOGTAG,"comparing candidate: "+currentConnection.getCandidate().toString()); + if (currentConnection.isEstablished() + && (currentConnection.getCandidate().isUsedByCounterpart() || (!currentConnection + .getCandidate().isOurs()))) { + // Log.d(Config.LOGTAG,"is usable"); + if (connection == null) { + connection = currentConnection; + } else { + if (connection.getCandidate().getPriority() < currentConnection + .getCandidate().getPriority()) { + connection = currentConnection; + } else if (connection.getCandidate().getPriority() == currentConnection + .getCandidate().getPriority()) { + // Log.d(Config.LOGTAG,"found two candidates with same priority"); + if (initiating()) { + if (currentConnection.getCandidate().isOurs()) { + connection = currentConnection; + } + } else { + if (!currentConnection.getCandidate().isOurs()) { + connection = currentConnection; + } + } + } + } + } + } + return connection; + } - @Override - public void onIqPacketReceived(Account account, - IqPacket packet) { - if (packet.getType() != IqPacket.TYPE.RESULT) { - onProxyActivated.failed(); - } else { - onProxyActivated.success(); - sendProxyActivated(connection.getCandidate().getCid()); - } - } - }); - } else { - Log.d(Config.LOGTAG, - "candidate " - + connection.getCandidate().getCid() - + " was a proxy. waiting for other party to activate"); - } - } else { - if (initiating()) { - Log.d(Config.LOGTAG, "we were initiating. sending file"); - connection.send(file, onFileTransmissionStatusChanged); - } else { - Log.d(Config.LOGTAG, "we were responding. receiving file"); - connection.receive(file, onFileTransmissionStatusChanged); - } - } - } - } + private void sendSuccess() { + JinglePacket packet = bootstrapPacket("session-terminate"); + Reason reason = new Reason(); + reason.addChild("success"); + packet.setReason(reason); + this.sendJinglePacket(packet); + this.disconnectSocks5Connections(); + this.mJingleStatus = JINGLE_STATUS_FINISHED; + this.message.setStatus(Message.STATUS_RECEIVED); + this.message.setTransferable(null); + this.mXmppConnectionService.updateMessage(message, false); + this.mJingleConnectionManager.finishConnection(this); + } - private JingleSocks5Transport chooseConnection() { - JingleSocks5Transport connection = null; - for (Entry cursor : connections - .entrySet()) { - JingleSocks5Transport currentConnection = cursor.getValue(); - // Log.d(Config.LOGTAG,"comparing candidate: "+currentConnection.getCandidate().toString()); - if (currentConnection.isEstablished() - && (currentConnection.getCandidate().isUsedByCounterpart() || (!currentConnection - .getCandidate().isOurs()))) { - // Log.d(Config.LOGTAG,"is usable"); - if (connection == null) { - connection = currentConnection; - } else { - if (connection.getCandidate().getPriority() < currentConnection - .getCandidate().getPriority()) { - connection = currentConnection; - } else if (connection.getCandidate().getPriority() == currentConnection - .getCandidate().getPriority()) { - // Log.d(Config.LOGTAG,"found two candidates with same priority"); - if (initiating()) { - if (currentConnection.getCandidate().isOurs()) { - connection = currentConnection; - } - } else { - if (!currentConnection.getCandidate().isOurs()) { - connection = currentConnection; - } - } - } - } - } - } - return connection; - } - - private void sendSuccess() { - JinglePacket packet = bootstrapPacket("session-terminate"); - Reason reason = new Reason(); - reason.addChild("success"); - packet.setReason(reason); - this.sendJinglePacket(packet); - this.disconnectSocks5Connections(); - this.mJingleStatus = JINGLE_STATUS_FINISHED; - this.message.setStatus(Message.STATUS_RECEIVED); - this.message.setTransferable(null); - this.mXmppConnectionService.updateMessage(message, false); - this.mJingleConnectionManager.finishConnection(this); - } - - private void sendFallbackToIbb() { - Log.d(Config.LOGTAG, account.getJid().asBareJid()+": sending fallback to ibb"); - JinglePacket packet = this.bootstrapPacket("transport-replace"); - Content content = new Content(this.contentCreator, this.contentName); - this.transportId = this.mJingleConnectionManager.nextRandomId(); - content.setTransportId(this.transportId); - content.ibbTransport().setAttribute("block-size", - Integer.toString(this.ibbBlockSize)); - packet.setContent(content); - this.sendJinglePacket(packet); - } + private void sendFallbackToIbb() { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": sending fallback to ibb"); + JinglePacket packet = this.bootstrapPacket("transport-replace"); + Content content = new Content(this.contentCreator, this.contentName); + this.transportId = this.mJingleConnectionManager.nextRandomId(); + content.setTransportId(this.transportId); + content.ibbTransport().setAttribute("block-size", + Integer.toString(this.ibbBlockSize)); + packet.setContent(content); + this.sendJinglePacket(packet); + } - private boolean receiveFallbackToIbb(JinglePacket packet) { - Log.d(Config.LOGTAG, "receiving fallack to ibb"); - String receivedBlockSize = packet.getJingleContent().ibbTransport() - .getAttribute("block-size"); - if (receivedBlockSize != null) { - int bs = Integer.parseInt(receivedBlockSize); - if (bs > this.ibbBlockSize) { - this.ibbBlockSize = bs; - } - } - this.transportId = packet.getJingleContent().getTransportId(); - this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); + private boolean receiveFallbackToIbb(JinglePacket packet) { + Log.d(Config.LOGTAG, "receiving fallack to ibb"); + String receivedBlockSize = packet.getJingleContent().ibbTransport() + .getAttribute("block-size"); + if (receivedBlockSize != null) { + int bs = Integer.parseInt(receivedBlockSize); + if (bs > this.ibbBlockSize) { + this.ibbBlockSize = bs; + } + } + this.transportId = packet.getJingleContent().getTransportId(); + this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); - JinglePacket answer = bootstrapPacket("transport-accept"); + JinglePacket answer = bootstrapPacket("transport-accept"); - final Content content = new Content(contentCreator,contentName); - content.setFileOffer(fileOffer, ftVersion); - content.ibbTransport().setAttribute("block-size",this.ibbBlockSize); - answer.setContent(content); + final Content content = new Content(contentCreator, contentName); + content.setFileOffer(fileOffer, ftVersion); + content.ibbTransport().setAttribute("block-size", this.ibbBlockSize); + answer.setContent(content); - if (initiating()) { - this.sendJinglePacket(answer, new OnIqPacketReceived() { - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() == IqPacket.TYPE.RESULT) { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + " recipient ACKed our transport-accept. creating ibb"); - transport.connect(onIbbTransportConnected); - } - } - }); - } else { - this.transport.receive(file, onFileTransmissionStatusChanged); - this.sendJinglePacket(answer); - } - return true; - } + if (initiating()) { + this.sendJinglePacket(answer, (account, response) -> { + if (response.getType() == IqPacket.TYPE.RESULT) { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + " recipient ACKed our transport-accept. creating ibb"); + transport.connect(onIbbTransportConnected); + } + }); + } else { + this.transport.receive(file, onFileTransmissionStatusChanged); + this.sendJinglePacket(answer); + } + return true; + } - private boolean receiveTransportAccept(JinglePacket packet) { - if (packet.getJingleContent().hasIbbTransport()) { - String receivedBlockSize = packet.getJingleContent().ibbTransport() - .getAttribute("block-size"); - if (receivedBlockSize != null) { - int bs = Integer.parseInt(receivedBlockSize); - if (bs > this.ibbBlockSize) { - this.ibbBlockSize = bs; - } - } - this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); + private boolean receiveTransportAccept(JinglePacket packet) { + if (packet.getJingleContent().hasIbbTransport()) { + String receivedBlockSize = packet.getJingleContent().ibbTransport() + .getAttribute("block-size"); + if (receivedBlockSize != null) { + int bs = Integer.parseInt(receivedBlockSize); + if (bs > this.ibbBlockSize) { + this.ibbBlockSize = bs; + } + } + this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); - //might be receive instead if we are not initiating - if (initiating()) { - this.transport.connect(onIbbTransportConnected); - } else { - this.transport.receive(file, onFileTransmissionStatusChanged); - } - return true; - } else { - return false; - } - } + //might be receive instead if we are not initiating + if (initiating()) { + this.transport.connect(onIbbTransportConnected); + } else { + this.transport.receive(file, onFileTransmissionStatusChanged); + } + return true; + } else { + return false; + } + } - private void receiveSuccess() { - if (initiating()) { - this.mJingleStatus = JINGLE_STATUS_FINISHED; - this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_RECEIVED); - this.disconnectSocks5Connections(); - if (this.transport instanceof JingleInbandTransport) { - this.transport.disconnect(); - } - this.message.setTransferable(null); - this.mJingleConnectionManager.finishConnection(this); - } else { - Log.d(Config.LOGTAG,account.getJid().asBareJid()+": received session-terminate/success while responding"); - } - } - @Override - public void cancel() { - this.cancelled = true; - abort(); - } + private void receiveSuccess() { + if (initiating()) { + this.mJingleStatus = JINGLE_STATUS_FINISHED; + this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_RECEIVED); + this.disconnectSocks5Connections(); + if (this.transport instanceof JingleInbandTransport) { + this.transport.disconnect(); + } + this.message.setTransferable(null); + this.mJingleConnectionManager.finishConnection(this); + } else { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received session-terminate/success while responding"); + } + } - public void abort() { - this.disconnectSocks5Connections(); - if (this.transport instanceof JingleInbandTransport) { - this.transport.disconnect(); - } - this.sendCancel(); - this.mJingleConnectionManager.finishConnection(this); - if (responding()) { - this.message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_FAILED)); - if (this.file!=null) { - file.delete(); - } - this.mJingleConnectionManager.updateConversationUi(true); - } else { - this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_FAILED, cancelled ? Message.ERROR_MESSAGE_CANCELLED : null); - this.message.setTransferable(null); - } - } + @Override + public void cancel() { + this.cancelled = true; + abort(); + } - private void fail() { - fail(null); - } + public void abort() { + this.disconnectSocks5Connections(); + if (this.transport instanceof JingleInbandTransport) { + this.transport.disconnect(); + } + this.sendCancel(); + this.mJingleConnectionManager.finishConnection(this); + if (responding()) { + this.message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_FAILED)); + if (this.file != null) { + file.delete(); + } + this.mJingleConnectionManager.updateConversationUi(true); + } else { + this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_FAILED, cancelled ? Message.ERROR_MESSAGE_CANCELLED : null); + this.message.setTransferable(null); + } + } - private void fail(String errorMessage) { - this.mJingleStatus = JINGLE_STATUS_FAILED; - this.disconnectSocks5Connections(); - if (this.transport instanceof JingleInbandTransport) { - this.transport.disconnect(); - } - FileBackend.close(mFileInputStream); - FileBackend.close(mFileOutputStream); - if (this.message != null) { - if (responding()) { - this.message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_FAILED)); - if (this.file!=null) { - file.delete(); - } - this.mJingleConnectionManager.updateConversationUi(true); - } else { - this.mXmppConnectionService.markMessage(this.message, - Message.STATUS_SEND_FAILED, - cancelled ? Message.ERROR_MESSAGE_CANCELLED : errorMessage); - this.message.setTransferable(null); - } - } - this.mJingleConnectionManager.finishConnection(this); - } + private void fail() { + fail(null); + } - private void sendCancel() { - JinglePacket packet = bootstrapPacket("session-terminate"); - Reason reason = new Reason(); - reason.addChild("cancel"); - packet.setReason(reason); - this.sendJinglePacket(packet); - } + private void fail(String errorMessage) { + this.mJingleStatus = JINGLE_STATUS_FAILED; + this.disconnectSocks5Connections(); + if (this.transport instanceof JingleInbandTransport) { + this.transport.disconnect(); + } + FileBackend.close(mFileInputStream); + FileBackend.close(mFileOutputStream); + if (this.message != null) { + if (responding()) { + this.message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_FAILED)); + if (this.file != null) { + file.delete(); + } + this.mJingleConnectionManager.updateConversationUi(true); + } else { + this.mXmppConnectionService.markMessage(this.message, + Message.STATUS_SEND_FAILED, + cancelled ? Message.ERROR_MESSAGE_CANCELLED : errorMessage); + this.message.setTransferable(null); + } + } + this.mJingleConnectionManager.finishConnection(this); + } - private void connectNextCandidate() { - for (JingleCandidate candidate : this.candidates) { - if ((!connections.containsKey(candidate.getCid()) && (!candidate - .isOurs()))) { - this.connectWithCandidate(candidate); - return; - } - } - this.sendCandidateError(); - } + private void sendCancel() { + JinglePacket packet = bootstrapPacket("session-terminate"); + Reason reason = new Reason(); + reason.addChild("cancel"); + packet.setReason(reason); + this.sendJinglePacket(packet); + } - private void connectWithCandidate(final JingleCandidate candidate) { - final JingleSocks5Transport socksConnection = new JingleSocks5Transport( - this, candidate); - connections.put(candidate.getCid(), socksConnection); - socksConnection.connect(new OnTransportConnected() { + private void connectNextCandidate() { + for (JingleCandidate candidate : this.candidates) { + if ((!connections.containsKey(candidate.getCid()) && (!candidate + .isOurs()))) { + this.connectWithCandidate(candidate); + return; + } + } + this.sendCandidateError(); + } - @Override - public void failed() { - Log.d(Config.LOGTAG, - "connection failed with " + candidate.getHost() + ":" - + candidate.getPort()); - connectNextCandidate(); - } + private void connectWithCandidate(final JingleCandidate candidate) { + final JingleSocks5Transport socksConnection = new JingleSocks5Transport( + this, candidate); + connections.put(candidate.getCid(), socksConnection); + socksConnection.connect(new OnTransportConnected() { - @Override - public void established() { - Log.d(Config.LOGTAG, - "established connection with " + candidate.getHost() - + ":" + candidate.getPort()); - sendCandidateUsed(candidate.getCid()); - } - }); - } + @Override + public void failed() { + Log.d(Config.LOGTAG, + "connection failed with " + candidate.getHost() + ":" + + candidate.getPort()); + connectNextCandidate(); + } - private void disconnectSocks5Connections() { - Iterator> it = this.connections - .entrySet().iterator(); - while (it.hasNext()) { - Entry pairs = it.next(); - pairs.getValue().disconnect(); - it.remove(); - } - } + @Override + public void established() { + Log.d(Config.LOGTAG, + "established connection with " + candidate.getHost() + + ":" + candidate.getPort()); + sendCandidateUsed(candidate.getCid()); + } + }); + } - private void sendProxyActivated(String cid) { - JinglePacket packet = bootstrapPacket("transport-info"); - Content content = new Content(this.contentCreator, this.contentName); - content.setTransportId(this.transportId); - content.socks5transport().addChild("activated") - .setAttribute("cid", cid); - packet.setContent(content); - this.sendJinglePacket(packet); - } + private void disconnectSocks5Connections() { + Iterator> it = this.connections + .entrySet().iterator(); + while (it.hasNext()) { + Entry pairs = it.next(); + pairs.getValue().disconnect(); + it.remove(); + } + } - private void sendCandidateUsed(final String cid) { - JinglePacket packet = bootstrapPacket("transport-info"); - Content content = new Content(this.contentCreator, this.contentName); - content.setTransportId(this.transportId); - content.socks5transport().addChild("candidate-used").setAttribute("cid", cid); - packet.setContent(content); - this.sentCandidate = true; - if ((receivedCandidate) && (mJingleStatus == JINGLE_STATUS_ACCEPTED)) { - connect(); - } - this.sendJinglePacket(packet); - } + private void sendProxyActivated(String cid) { + JinglePacket packet = bootstrapPacket("transport-info"); + Content content = new Content(this.contentCreator, this.contentName); + content.setTransportId(this.transportId); + content.socks5transport().addChild("activated").setAttribute("cid", cid); + packet.setContent(content); + this.sendJinglePacket(packet); + } - private void sendCandidateError() { - Log.d(Config.LOGTAG,"sending canditate error"); - JinglePacket packet = bootstrapPacket("transport-info"); - Content content = new Content(this.contentCreator, this.contentName); - content.setTransportId(this.transportId); - content.socks5transport().addChild("candidate-error"); - packet.setContent(content); - this.sentCandidate = true; - this.sendJinglePacket(packet); - if (receivedCandidate && mJingleStatus == JINGLE_STATUS_ACCEPTED) { - connect(); - } - } + private void sendCandidateUsed(final String cid) { + JinglePacket packet = bootstrapPacket("transport-info"); + Content content = new Content(this.contentCreator, this.contentName); + content.setTransportId(this.transportId); + content.socks5transport().addChild("candidate-used").setAttribute("cid", cid); + packet.setContent(content); + this.sentCandidate = true; + if ((receivedCandidate) && (mJingleStatus == JINGLE_STATUS_ACCEPTED)) { + connect(); + } + this.sendJinglePacket(packet); + } - public int getJingleStatus() { - return this.mJingleStatus; - } + private void sendCandidateError() { + Log.d(Config.LOGTAG, "sending candidate error"); + JinglePacket packet = bootstrapPacket("transport-info"); + Content content = new Content(this.contentCreator, this.contentName); + content.setTransportId(this.transportId); + content.socks5transport().addChild("candidate-error"); + packet.setContent(content); + this.sentCandidate = true; + this.sendJinglePacket(packet); + if (receivedCandidate && mJingleStatus == JINGLE_STATUS_ACCEPTED) { + connect(); + } + } - private boolean equalCandidateExists(JingleCandidate candidate) { - for (JingleCandidate c : this.candidates) { - if (c.equalValues(candidate)) { - return true; - } - } - return false; - } + public int getJingleStatus() { + return this.mJingleStatus; + } - private void mergeCandidate(JingleCandidate candidate) { - for (JingleCandidate c : this.candidates) { - if (c.equals(candidate)) { - return; - } - } - this.candidates.add(candidate); - } + private boolean equalCandidateExists(JingleCandidate candidate) { + for (JingleCandidate c : this.candidates) { + if (c.equalValues(candidate)) { + return true; + } + } + return false; + } - private void mergeCandidates(List candidates) { - for (JingleCandidate c : candidates) { - mergeCandidate(c); - } - } + private void mergeCandidate(JingleCandidate candidate) { + for (JingleCandidate c : this.candidates) { + if (c.equals(candidate)) { + return; + } + } + this.candidates.add(candidate); + } - private JingleCandidate getCandidate(String cid) { - for (JingleCandidate c : this.candidates) { - if (c.getCid().equals(cid)) { - return c; - } - } - return null; - } + private void mergeCandidates(List candidates) { + for (JingleCandidate c : candidates) { + mergeCandidate(c); + } + } - public void updateProgress(int i) { - this.mProgress = i; - mJingleConnectionManager.updateConversationUi(false); - } + private JingleCandidate getCandidate(String cid) { + for (JingleCandidate c : this.candidates) { + if (c.getCid().equals(cid)) { + return c; + } + } + return null; + } - public String getTransportId() { - return this.transportId; - } + void updateProgress(int i) { + this.mProgress = i; + mJingleConnectionManager.updateConversationUi(false); + } - public Content.Version getFtVersion() { - return this.ftVersion; - } + public String getTransportId() { + return this.transportId; + } - interface OnProxyActivated { - void success(); + public Content.Version getFtVersion() { + return this.ftVersion; + } - void failed(); - } + public boolean hasTransportId(String sid) { + return sid.equals(this.transportId); + } - public boolean hasTransportId(String sid) { - return sid.equals(this.transportId); - } + public JingleTransport getTransport() { + return this.transport; + } - public JingleTransport getTransport() { - return this.transport; - } + public boolean start() { + if (account.getStatus() == Account.State.ONLINE) { + if (mJingleStatus == JINGLE_STATUS_INITIATED) { + new Thread(new Runnable() { - public boolean start() { - if (account.getStatus() == Account.State.ONLINE) { - if (mJingleStatus == JINGLE_STATUS_INITIATED) { - new Thread(new Runnable() { + @Override + public void run() { + sendAccept(); + } + }).start(); + } + return true; + } else { + return false; + } + } - @Override - public void run() { - sendAccept(); - } - }).start(); - } - return true; - } else { - return false; - } - } + @Override + public int getStatus() { + return this.mStatus; + } - @Override - public int getStatus() { - return this.mStatus; - } + @Override + public long getFileSize() { + if (this.file != null) { + return this.file.getExpectedSize(); + } else { + return 0; + } + } - @Override - public long getFileSize() { - if (this.file != null) { - return this.file.getExpectedSize(); - } else { - return 0; - } - } + @Override + public int getProgress() { + return this.mProgress; + } - @Override - public int getProgress() { - return this.mProgress; - } + public AbstractConnectionManager getConnectionManager() { + return this.mJingleConnectionManager; + } - public AbstractConnectionManager getConnectionManager() { - return this.mJingleConnectionManager; - } + interface OnProxyActivated { + void success(); + + void failed(); + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index 54679631f..34bf5412e 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -154,6 +154,7 @@ public class JingleInbandTransport extends JingleTransport { if (count == -1) { sendClose(); file.setSha1Sum(digest.digest()); + Log.d(Config.LOGTAG,account.getJid().asBareJid()+": sendNextBlock() count was -1"); this.onFileTransmissionStatusChanged.onFileTransmitted(file); fileInputStream.close(); return; @@ -181,6 +182,7 @@ public class JingleInbandTransport extends JingleTransport { } else { sendClose(); file.setSha1Sum(digest.digest()); + Log.d(Config.LOGTAG,account.getJid().asBareJid()+": sendNextBlock() remaining size"); this.onFileTransmissionStatusChanged.onFileTransmitted(file); fileInputStream.close(); } @@ -204,6 +206,7 @@ public class JingleInbandTransport extends JingleTransport { file.setSha1Sum(digest.digest()); fileOutputStream.flush(); fileOutputStream.close(); + Log.d(Config.LOGTAG,account.getJid().asBareJid()+": receive next block nothing remaining"); this.onFileTransmissionStatusChanged.onFileTransmitted(file); } else { connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java index 1b01cf0b3..3696756cf 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java @@ -2,132 +2,129 @@ package eu.siacs.conversations.xmpp.jingle.stanzas; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xml.Namespace; public class Content extends Element { - public enum Version { - FT_3("urn:xmpp:jingle:apps:file-transfer:3"), - FT_4("urn:xmpp:jingle:apps:file-transfer:4"), - FT_5("urn:xmpp:jingle:apps:file-transfer:5"); + public enum Version { + FT_3("urn:xmpp:jingle:apps:file-transfer:3"), + FT_4("urn:xmpp:jingle:apps:file-transfer:4"), + FT_5("urn:xmpp:jingle:apps:file-transfer:5"); - private final String namespace; + private final String namespace; - Version(String namespace) { - this.namespace = namespace; - } + Version(String namespace) { + this.namespace = namespace; + } - public String getNamespace() { - return namespace; - } - } + public String getNamespace() { + return namespace; + } + } - private String transportId; + private String transportId; - public Content() { - super("content"); - } + public Content() { + super("content"); + } - public Content(String creator, String name) { - super("content"); - this.setAttribute("creator", creator); - this.setAttribute("senders", creator); - this.setAttribute("name", name); - } + public Content(String creator, String name) { + super("content"); + this.setAttribute("creator", creator); + this.setAttribute("senders", creator); + this.setAttribute("name", name); + } - public Version getVersion() { - if (hasChild("description", Version.FT_3.namespace)) { - return Version.FT_3; - } else if (hasChild("description" , Version.FT_4.namespace)) { - return Version.FT_4; - } else if (hasChild("description" , Version.FT_5.namespace)) { - return Version.FT_5; - } - return null; - } + public Version getVersion() { + if (hasChild("description", Version.FT_3.namespace)) { + return Version.FT_3; + } else if (hasChild("description", Version.FT_4.namespace)) { + return Version.FT_4; + } else if (hasChild("description", Version.FT_5.namespace)) { + return Version.FT_5; + } + return null; + } - public void setTransportId(String sid) { - this.transportId = sid; - } + public void setTransportId(String sid) { + this.transportId = sid; + } - public Element setFileOffer(DownloadableFile actualFile, boolean otr, Version version) { - Element description = this.addChild("description", version.namespace); - Element file; - if (version == Version.FT_3) { - Element offer = description.addChild("offer"); - file = offer.addChild("file"); - } else { - file = description.addChild("file"); - } - file.addChild("size").setContent(Long.toString(actualFile.getExpectedSize())); - if (otr) { - file.addChild("name").setContent(actualFile.getName() + ".otr"); - } else { - file.addChild("name").setContent(actualFile.getName()); - } - return file; - } + public Element setFileOffer(DownloadableFile actualFile, boolean otr, Version version) { + Element description = this.addChild("description", version.namespace); + Element file; + if (version == Version.FT_3) { + Element offer = description.addChild("offer"); + file = offer.addChild("file"); + } else { + file = description.addChild("file"); + } + file.addChild("size").setContent(Long.toString(actualFile.getExpectedSize())); + if (otr) { + file.addChild("name").setContent(actualFile.getName() + ".otr"); + } else { + file.addChild("name").setContent(actualFile.getName()); + } + return file; + } - public Element getFileOffer(Version version) { - Element description = this.findChild("description", version.namespace); - if (description == null) { - return null; - } - if (version == Version.FT_3) { - Element offer = description.findChild("offer"); - if (offer == null) { - return null; - } - return offer.findChild("file"); - } else { - return description.findChild("file"); - } - } + public Element getFileOffer(Version version) { + Element description = this.findChild("description", version.namespace); + if (description == null) { + return null; + } + if (version == Version.FT_3) { + Element offer = description.findChild("offer"); + if (offer == null) { + return null; + } + return offer.findChild("file"); + } else { + return description.findChild("file"); + } + } - public void setFileOffer(Element fileOffer, Version version) { - Element description = this.addChild("description", version.namespace); - if (version == Version.FT_3) { - description.addChild("offer").addChild(fileOffer); - } else { - description.addChild(fileOffer); - } - } + public void setFileOffer(Element fileOffer, Version version) { + Element description = this.addChild("description", version.namespace); + if (version == Version.FT_3) { + description.addChild("offer").addChild(fileOffer); + } else { + description.addChild(fileOffer); + } + } - public String getTransportId() { - if (hasSocks5Transport()) { - this.transportId = socks5transport().getAttribute("sid"); - } else if (hasIbbTransport()) { - this.transportId = ibbTransport().getAttribute("sid"); - } - return this.transportId; - } + public String getTransportId() { + if (hasSocks5Transport()) { + this.transportId = socks5transport().getAttribute("sid"); + } else if (hasIbbTransport()) { + this.transportId = ibbTransport().getAttribute("sid"); + } + return this.transportId; + } - public Element socks5transport() { - Element transport = this.findChild("transport", - "urn:xmpp:jingle:transports:s5b:1"); - if (transport == null) { - transport = this.addChild("transport", - "urn:xmpp:jingle:transports:s5b:1"); - transport.setAttribute("sid", this.transportId); - } - return transport; - } + public Element socks5transport() { + Element transport = this.findChild("transport", Namespace.JINGLE_TRANSPORTS_S5B); + if (transport == null) { + transport = this.addChild("transport", Namespace.JINGLE_TRANSPORTS_S5B); + transport.setAttribute("sid", this.transportId); + } + return transport; + } - public Element ibbTransport() { - Element transport = this.findChild("transport", - "urn:xmpp:jingle:transports:ibb:1"); - if (transport == null) { - transport = this.addChild("transport", - "urn:xmpp:jingle:transports:ibb:1"); - transport.setAttribute("sid", this.transportId); - } - return transport; - } + public Element ibbTransport() { + Element transport = this.findChild("transport", Namespace.JINGLE_TRANSPORTS_IBB); + if (transport == null) { + transport = this.addChild("transport", Namespace.JINGLE_TRANSPORTS_IBB); + transport.setAttribute("sid", this.transportId); + } + return transport; + } - public boolean hasSocks5Transport() { - return this.hasChild("transport", "urn:xmpp:jingle:transports:s5b:1"); - } + public boolean hasSocks5Transport() { + return this.hasChild("transport", Namespace.JINGLE_TRANSPORTS_S5B); + } - public boolean hasIbbTransport() { - return this.hasChild("transport", "urn:xmpp:jingle:transports:ibb:1"); - } + public boolean hasIbbTransport() { + return this.hasChild("transport", Namespace.JINGLE_TRANSPORTS_IBB); + } }