diff options
Diffstat (limited to 'src/main/java/eu/siacs/conversations/xmpp/jingle')
7 files changed, 291 insertions, 146 deletions
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java index 3e7c7b68..281ea3ca 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleCandidate.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.jid.Jid; public class JingleCandidate { @@ -17,7 +18,7 @@ public class JingleCandidate { private String host; private int port; private int type; - private String jid; + private Jid jid; private int priority; public JingleCandidate(String cid, boolean ours) { @@ -37,11 +38,11 @@ public class JingleCandidate { return this.host; } - public void setJid(String jid) { + public void setJid(final Jid jid) { this.jid = jid; } - public String getJid() { + public Jid getJid() { return this.jid; } @@ -58,13 +59,17 @@ public class JingleCandidate { } public void setType(String type) { - if ("proxy".equals(type)) { - this.type = TYPE_PROXY; - } else if ("direct".equals(type)) { - this.type = TYPE_DIRECT; - } else { - this.type = TYPE_UNKNOWN; - } + switch (type) { + case "proxy": + this.type = TYPE_PROXY; + break; + case "direct": + this.type = TYPE_DIRECT; + break; + default: + this.type = TYPE_UNKNOWN; + break; + } } public void setPriority(int i) { @@ -93,7 +98,7 @@ public class JingleCandidate { } public static List<JingleCandidate> parse(List<Element> canditates) { - List<JingleCandidate> parsedCandidates = new ArrayList<JingleCandidate>(); + List<JingleCandidate> parsedCandidates = new ArrayList<>(); for (Element c : canditates) { parsedCandidates.add(JingleCandidate.parse(c)); } @@ -104,7 +109,7 @@ public class JingleCandidate { JingleCandidate parsedCandidate = new JingleCandidate( candidate.getAttribute("cid"), false); parsedCandidate.setHost(candidate.getAttribute("host")); - parsedCandidate.setJid(candidate.getAttribute("jid")); + parsedCandidate.setJid(candidate.getAttributeAsJid("jid")); parsedCandidate.setType(candidate.getAttribute("type")); parsedCandidate.setPriority(Integer.parseInt(candidate .getAttribute("priority"))); @@ -118,7 +123,7 @@ public class JingleCandidate { element.setAttribute("cid", this.getCid()); element.setAttribute("host", this.getHost()); element.setAttribute("port", Integer.toString(this.getPort())); - element.setAttribute("jid", this.getJid()); + element.setAttribute("jid", this.getJid().toString()); element.setAttribute("priority", Integer.toString(this.getPriority())); if (this.getType() == TYPE_DIRECT) { element.setAttribute("type", "direct"); 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 6b9ca9aa..3a1ba778 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -1,5 +1,6 @@ package eu.siacs.conversations.xmpp.jingle; +import java.net.URLConnection; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; @@ -9,18 +10,20 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import android.content.Intent; -import android.graphics.BitmapFactory; import android.net.Uri; +import android.os.SystemClock; import android.util.Log; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.DownloadableFile; +import eu.siacs.conversations.entities.DownloadablePlaceholder; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnIqPacketReceived; +import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jingle.stanzas.Content; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; import eu.siacs.conversations.xmpp.jingle.stanzas.Reason; @@ -28,9 +31,6 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class JingleConnection implements Downloadable { - private final String[] extensions = { "webp", "jpeg", "jpg", "png" }; - private final String[] cryptoExtensions = { "pgp", "gpg", "otr" }; - private JingleConnectionManager mJingleConnectionManager; private XmppConnectionService mXmppConnectionService; @@ -45,14 +45,14 @@ public class JingleConnection implements Downloadable { private int ibbBlockSize = 4096; private int mJingleStatus = -1; - private int mStatus = -1; + private int mStatus = Downloadable.STATUS_UNKNOWN; private Message message; private String sessionId; private Account account; - private String initiator; - private String responder; - private List<JingleCandidate> candidates = new ArrayList<JingleCandidate>(); - private ConcurrentHashMap<String, JingleSocks5Transport> connections = new ConcurrentHashMap<String, JingleSocks5Transport>(); + private Jid initiator; + private Jid responder; + private List<JingleCandidate> candidates = new ArrayList<>(); + private ConcurrentHashMap<String, JingleSocks5Transport> connections = new ConcurrentHashMap<>(); private String transportId; private Element fileOffer; @@ -61,6 +61,9 @@ public class JingleConnection implements Downloadable { private String contentName; private String contentCreator; + private int mProgress = 0; + private long mLastGuiRefresh = 0; + private boolean receivedCandidate = false; private boolean sentCandidate = false; @@ -73,7 +76,7 @@ public class JingleConnection implements Downloadable { @Override public void onIqPacketReceived(Account account, IqPacket packet) { if (packet.getType() == IqPacket.TYPE_ERROR) { - cancel(); + fail(); } } }; @@ -82,23 +85,21 @@ public class JingleConnection implements Downloadable { @Override public void onFileTransmitted(DownloadableFile file) { - if (responder.equals(account.getFullJid())) { + if (responder.equals(account.getJid())) { sendSuccess(); if (acceptedAutomatically) { message.markUnread(); JingleConnection.this.mXmppConnectionService .getNotificationService().push(message); } - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(file.getAbsolutePath(), options); - int imageHeight = options.outHeight; - int imageWidth = options.outWidth; - message.setBody(Long.toString(file.getSize()) + '|' - + imageWidth + '|' + imageHeight); + mXmppConnectionService.getFileBackend().updateFileParams(message); mXmppConnectionService.databaseBackend.createMessage(message); mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVED); + } else { + if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) { + file.delete(); + } } Log.d(Config.LOGTAG, "sucessfully transmitted file:" + file.getAbsolutePath()); @@ -113,7 +114,7 @@ public class JingleConnection implements Downloadable { @Override public void onFileTransferAborted() { JingleConnection.this.sendCancel(); - JingleConnection.this.cancel(); + JingleConnection.this.fail(); } }; @@ -121,7 +122,7 @@ public class JingleConnection implements Downloadable { @Override public void success() { - if (initiator.equals(account.getFullJid())) { + if (initiator.equals(account.getJid())) { Log.d(Config.LOGTAG, "we were initiating. sending file"); transport.send(file, onFileTransmissionSatusChanged); } else { @@ -150,7 +151,7 @@ public class JingleConnection implements Downloadable { return this.account; } - public String getCounterPart() { + public Jid getCounterPart() { return this.message.getCounterpart(); } @@ -160,14 +161,14 @@ public class JingleConnection implements Downloadable { Reason reason = packet.getReason(); if (reason != null) { if (reason.hasChild("cancel")) { - this.cancel(); + this.fail(); } else if (reason.hasChild("success")) { this.receiveSuccess(); } else { - this.cancel(); + this.fail(); } } else { - this.cancel(); + this.fail(); } } else if (packet.isAction("session-accept")) { returnResult = receiveAccept(packet); @@ -202,8 +203,10 @@ public class JingleConnection implements Downloadable { this.contentCreator = "initiator"; this.contentName = this.mJingleConnectionManager.nextRandomId(); this.message = message; + this.message.setDownloadable(this); + this.mStatus = Downloadable.STATUS_UPLOADING; this.account = message.getConversation().getAccount(); - this.initiator = this.account.getFullJid(); + this.initiator = this.account.getJid(); this.responder = this.message.getCounterpart(); this.sessionId = this.mJingleConnectionManager.nextRandomId(); if (this.candidates.size() > 0) { @@ -254,17 +257,16 @@ public class JingleConnection implements Downloadable { this.mJingleStatus = JINGLE_STATUS_INITIATED; Conversation conversation = this.mXmppConnectionService .findOrCreateConversation(account, - packet.getFrom().split("/", 2)[0], false); + packet.getFrom().toBareJid(), false); this.message = new Message(conversation, "", Message.ENCRYPTION_NONE); this.message.setStatus(Message.STATUS_RECEIVED); - this.message.setType(Message.TYPE_IMAGE); this.mStatus = Downloadable.STATUS_OFFER; this.message.setDownloadable(this); - String[] fromParts = packet.getFrom().split("/", 2); - this.message.setPresence(fromParts[1]); + final Jid from = packet.getFrom(); + this.message.setCounterpart(from); this.account = account; this.initiator = packet.getFrom(); - this.responder = this.account.getFullJid(); + this.responder = this.account.getJid(); this.sessionId = packet.getSessionId(); Content content = packet.getJingleContent(); this.contentCreator = content.getAttribute("creator"); @@ -277,75 +279,83 @@ public class JingleConnection implements Downloadable { Element fileSize = fileOffer.findChild("size"); Element fileNameElement = fileOffer.findChild("name"); if (fileNameElement != null) { - boolean supportedFile = false; String[] filename = fileNameElement.getContent() .toLowerCase(Locale.US).split("\\."); - if (Arrays.asList(this.extensions).contains( + if (Arrays.asList(VALID_IMAGE_EXTENSIONS).contains( filename[filename.length - 1])) { - supportedFile = true; - } else if (Arrays.asList(this.cryptoExtensions).contains( + message.setType(Message.TYPE_IMAGE); + } else if (Arrays.asList(VALID_CRYPTO_EXTENSIONS).contains( filename[filename.length - 1])) { if (filename.length == 3) { - if (Arrays.asList(this.extensions).contains( + if (Arrays.asList(VALID_IMAGE_EXTENSIONS).contains( filename[filename.length - 2])) { - supportedFile = true; - if (filename[filename.length - 1].equals("otr")) { - Log.d(Config.LOGTAG, "receiving otr file"); - this.message - .setEncryption(Message.ENCRYPTION_OTR); - } else { - this.message - .setEncryption(Message.ENCRYPTION_PGP); - } + message.setType(Message.TYPE_IMAGE); + } else { + message.setType(Message.TYPE_FILE); + } + if (filename[filename.length - 1].equals("otr")) { + message.setEncryption(Message.ENCRYPTION_OTR); + } else { + message.setEncryption(Message.ENCRYPTION_PGP); } } + } else { + message.setType(Message.TYPE_FILE); } - if (supportedFile) { - long size = Long.parseLong(fileSize.getContent()); - message.setBody(Long.toString(size)); - conversation.add(message); - mXmppConnectionService.updateConversationUi(); - if (size <= this.mJingleConnectionManager - .getAutoAcceptFileSize()) { - 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 (message.getEncryption() == Message.ENCRYPTION_OTR) { - byte[] key = conversation.getSymmetricKey(); - if (key == null) { - this.sendCancel(); - this.cancel(); - return; - } else { - this.file.setKey(key); + 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_OTR && suffix.endsWith(".otr")) { + suffix = suffix.substring(0,suffix.length() - 4); + } else if (message.getEncryption() == Message.ENCRYPTION_PGP && (suffix.endsWith(".pgp") || suffix.endsWith(".gpg"))) { + suffix = suffix.substring(0,suffix.length() - 4); } } - this.file.setExpectedSize(size); + message.setRelativeFilePath(message.getUuid()+"_"+suffix); + } + long size = Long.parseLong(fileSize.getContent()); + message.setBody(Long.toString(size)); + conversation.add(message); + mXmppConnectionService.updateConversationUi(); + if (size <= this.mJingleConnectionManager + .getAutoAcceptFileSize()) { + Log.d(Config.LOGTAG, "auto accepting file from " + + packet.getFrom()); + this.acceptedAutomatically = true; + this.sendAccept(); } else { - this.sendCancel(); - this.cancel(); + 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 (message.getEncryption() == Message.ENCRYPTION_OTR) { + byte[] key = conversation.getSymmetricKey(); + if (key == null) { + this.sendCancel(); + this.fail(); + return; + } else { + this.file.setKey(key); + } + } + this.file.setExpectedSize(size); } else { this.sendCancel(); - this.cancel(); + this.fail(); } } else { this.sendCancel(); - this.cancel(); + this.fail(); } } @@ -353,7 +363,7 @@ public class JingleConnection implements Downloadable { this.mXmppConnectionService.markMessage(this.message, Message.STATUS_OFFERED); JinglePacket packet = this.bootstrapPacket("session-initiate"); Content content = new Content(this.contentCreator, this.contentName); - if (message.getType() == Message.TYPE_IMAGE) { + if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE) { content.setTransportId(this.transportId); this.file = this.mXmppConnectionService.getFileBackend().getFile( message, false); @@ -375,7 +385,7 @@ public class JingleConnection implements Downloadable { } private List<Element> getCandidatesAsElements() { - List<Element> elements = new ArrayList<Element>(); + List<Element> elements = new ArrayList<>(); for (JingleCandidate c : this.candidates) { elements.add(c.toElement()); } @@ -443,7 +453,7 @@ public class JingleConnection implements Downloadable { private JinglePacket bootstrapPacket(String action) { JinglePacket packet = new JinglePacket(); packet.setAction(action); - packet.setFrom(account.getFullJid()); + packet.setFrom(account.getJid()); packet.setTo(this.message.getCounterpart()); packet.setSessionId(this.sessionId); packet.setInitiator(this.initiator); @@ -484,7 +494,7 @@ public class JingleConnection implements Downloadable { } else { Log.d(Config.LOGTAG, "activated connection not found"); this.sendCancel(); - this.cancel(); + this.fail(); } } return true; @@ -531,8 +541,8 @@ public class JingleConnection implements Downloadable { this.transport = connection; if (connection == null) { Log.d(Config.LOGTAG, "could not find suitable candidate"); - this.disconnect(); - if (this.initiator.equals(account.getFullJid())) { + this.disconnectSocks5Connections(); + if (this.initiator.equals(account.getJid())) { this.sendFallbackToIbb(); } } else { @@ -547,7 +557,7 @@ public class JingleConnection implements Downloadable { activation.query("http://jabber.org/protocol/bytestreams") .setAttribute("sid", this.getSessionId()); activation.query().addChild("activate") - .setContent(this.getCounterPart()); + .setContent(this.getCounterPart().toString()); this.account.getXmppConnection().sendIqPacket(activation, new OnIqPacketReceived() { @@ -570,7 +580,7 @@ public class JingleConnection implements Downloadable { + " was a proxy. waiting for other party to activate"); } } else { - if (initiator.equals(account.getFullJid())) { + if (initiator.equals(account.getJid())) { Log.d(Config.LOGTAG, "we were initiating. sending file"); connection.send(file, onFileTransmissionSatusChanged); } else { @@ -600,7 +610,7 @@ public class JingleConnection implements Downloadable { } else if (connection.getCandidate().getPriority() == currentConnection .getCandidate().getPriority()) { // Log.d(Config.LOGTAG,"found two candidates with same priority"); - if (initiator.equals(account.getFullJid())) { + if (initiator.equals(account.getJid())) { if (currentConnection.getCandidate().isOurs()) { connection = currentConnection; } @@ -622,7 +632,7 @@ public class JingleConnection implements Downloadable { reason.addChild("success"); packet.setReason(reason); this.sendJinglePacket(packet); - this.disconnect(); + this.disconnectSocks5Connections(); this.mJingleStatus = JINGLE_STATUS_FINISHED; this.message.setStatus(Message.STATUS_RECEIVED); this.message.setDownloadable(null); @@ -653,8 +663,7 @@ public class JingleConnection implements Downloadable { } } this.transportId = packet.getJingleContent().getTransportId(); - this.transport = new JingleInbandTransport(this.account, - this.responder, this.transportId, this.ibbBlockSize); + this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); this.transport.receive(file, onFileTransmissionSatusChanged); JinglePacket answer = bootstrapPacket("transport-accept"); Content content = new Content("initiator", "a-file-offer"); @@ -676,8 +685,7 @@ public class JingleConnection implements Downloadable { this.ibbBlockSize = bs; } } - this.transport = new JingleInbandTransport(this.account, - this.responder, this.transportId, this.ibbBlockSize); + this.transport = new JingleInbandTransport(this, this.transportId, this.ibbBlockSize); this.transport.connect(new OnTransportConnected() { @Override @@ -701,20 +709,51 @@ public class JingleConnection implements Downloadable { this.mJingleStatus = JINGLE_STATUS_FINISHED; this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND); - this.disconnect(); + this.disconnectSocks5Connections(); + if (this.transport != null && this.transport instanceof JingleInbandTransport) { + this.transport.disconnect(); + } + this.message.setDownloadable(null); this.mJingleConnectionManager.finishConnection(this); } public void cancel() { - this.mJingleStatus = JINGLE_STATUS_CANCELED; - this.disconnect(); + this.disconnectSocks5Connections(); + if (this.transport != null && this.transport instanceof JingleInbandTransport) { + this.transport.disconnect(); + } + this.sendCancel(); + this.mJingleConnectionManager.finishConnection(this); + if (this.responder.equals(account.getJid())) { + this.message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_FAILED)); + if (this.file!=null) { + file.delete(); + } + this.mXmppConnectionService.updateConversationUi(); + } else { + this.mXmppConnectionService.markMessage(this.message, + Message.STATUS_SEND_FAILED); + this.message.setDownloadable(null); + } + } + + private void fail() { + this.mJingleStatus = JINGLE_STATUS_FAILED; + this.disconnectSocks5Connections(); + if (this.transport != null && this.transport instanceof JingleInbandTransport) { + this.transport.disconnect(); + } if (this.message != null) { - if (this.responder.equals(account.getFullJid())) { - this.mStatus = Downloadable.STATUS_FAILED; + if (this.responder.equals(account.getJid())) { + this.message.setDownloadable(new DownloadablePlaceholder(Downloadable.STATUS_FAILED)); + if (this.file!=null) { + file.delete(); + } this.mXmppConnectionService.updateConversationUi(); } else { this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND_FAILED); + this.message.setDownloadable(null); } } this.mJingleConnectionManager.finishConnection(this); @@ -763,7 +802,7 @@ public class JingleConnection implements Downloadable { }); } - private void disconnect() { + private void disconnectSocks5Connections() { Iterator<Entry<String, JingleSocks5Transport>> it = this.connections .entrySet().iterator(); while (it.hasNext()) { @@ -810,11 +849,11 @@ public class JingleConnection implements Downloadable { this.sendJinglePacket(packet); } - public String getInitiator() { + public Jid getInitiator() { return this.initiator; } - public String getResponder() { + public Jid getResponder() { return this.responder; } @@ -855,6 +894,14 @@ public class JingleConnection implements Downloadable { return null; } + public void updateProgress(int i) { + this.mProgress = i; + if (SystemClock.elapsedRealtime() - this.mLastGuiRefresh > Config.PROGRESS_UI_UPDATE_INTERVAL) { + this.mLastGuiRefresh = SystemClock.elapsedRealtime(); + mXmppConnectionService.updateConversationUi(); + } + } + interface OnProxyActivated { public void success(); @@ -870,7 +917,7 @@ public class JingleConnection implements Downloadable { } public boolean start() { - if (account.getStatus() == Account.STATUS_ONLINE) { + if (account.getStatus() == Account.State.ONLINE) { if (mJingleStatus == JINGLE_STATUS_INITIATED) { new Thread(new Runnable() { @@ -899,4 +946,29 @@ public class JingleConnection implements Downloadable { return 0; } } + + @Override + public int getProgress() { + return this.mProgress; + } + + @Override + public String getMimeType() { + if (this.message.getType() == Message.TYPE_FILE) { + String mime = null; + String path = this.message.getRelativeFilePath(); + if (path != null && !this.message.getRelativeFilePath().isEmpty()) { + mime = URLConnection.guessContentTypeFromName(this.message.getRelativeFilePath()); + if (mime!=null) { + return mime; + } else { + return ""; + } + } else { + return ""; + } + } else { + return "image/webp"; + } + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index d937146a..72c960d8 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -14,13 +14,15 @@ import eu.siacs.conversations.services.AbstractConnectionManager; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnIqPacketReceived; +import eu.siacs.conversations.xmpp.jid.InvalidJidException; +import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket; import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class JingleConnectionManager extends AbstractConnectionManager { - private List<JingleConnection> connections = new CopyOnWriteArrayList<JingleConnection>(); + private List<JingleConnection> connections = new CopyOnWriteArrayList<>(); - private HashMap<String, JingleCandidate> primaryCandidates = new HashMap<String, JingleCandidate>(); + private HashMap<Jid, JingleCandidate> primaryCandidates = new HashMap<>(); @SuppressLint("TrulyRandom") private SecureRandom random = new SecureRandom(); @@ -61,7 +63,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { return connection; } - public JingleConnection createNewConnection(JinglePacket packet) { + public JingleConnection createNewConnection(final JinglePacket packet) { JingleConnection connection = new JingleConnection(this); this.connections.add(connection); return connection; @@ -73,13 +75,17 @@ public class JingleConnectionManager extends AbstractConnectionManager { public void getPrimaryCandidate(Account account, final OnPrimaryCandidateFound listener) { - if (!this.primaryCandidates.containsKey(account.getJid())) { + if (Config.NO_PROXY_LOOKUP) { + listener.onPrimaryCandidateFound(false, null); + return; + } + if (!this.primaryCandidates.containsKey(account.getJid().toBareJid())) { String xmlns = "http://jabber.org/protocol/bytestreams"; final String proxy = account.getXmppConnection() .findDiscoItemByFeature(xmlns); if (proxy != null) { IqPacket iq = new IqPacket(IqPacket.TYPE_GET); - iq.setTo(proxy); + iq.setAttribute("to", proxy); iq.query(xmlns); account.getXmppConnection().sendIqPacket(iq, new OnIqPacketReceived() { @@ -101,9 +107,13 @@ public class JingleConnectionManager extends AbstractConnectionManager { .getAttribute("port"))); candidate .setType(JingleCandidate.TYPE_PROXY); - candidate.setJid(proxy); - candidate.setPriority(655360 + 65535); - primaryCandidates.put(account.getJid(), + try { + candidate.setJid(Jid.fromString(proxy)); + } catch (final InvalidJidException e) { + candidate.setJid(null); + } + candidate.setPriority(655360 + 65535); + primaryCandidates.put(account.getJid().toBareJid(), candidate); listener.onPrimaryCandidateFound(true, candidate); @@ -119,7 +129,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { } else { listener.onPrimaryCandidateFound(true, - this.primaryCandidates.get(account.getJid())); + this.primaryCandidates.get(account.getJid().toBareJid())); } } 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 cc1e92f6..04b225d0 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -8,17 +8,19 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import android.util.Base64; + import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnIqPacketReceived; +import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class JingleInbandTransport extends JingleTransport { private Account account; - private String counterpart; + private Jid counterpart; private int blockSize; private int bufferSize; private int seq = 0; @@ -26,11 +28,15 @@ public class JingleInbandTransport extends JingleTransport { private boolean established = false; + private boolean connected = true; + private DownloadableFile file; + private JingleConnection connection; private InputStream fileInputStream = null; - private OutputStream fileOutputStream; - private long remainingSize; + private OutputStream fileOutputStream = null; + private long remainingSize = 0; + private long fileSize = 0; private MessageDigest digest; private OnFileTransmissionStatusChanged onFileTransmissionStatusChanged; @@ -38,16 +44,16 @@ public class JingleInbandTransport extends JingleTransport { private OnIqPacketReceived onAckReceived = new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() == IqPacket.TYPE_RESULT) { + if (connected && packet.getType() == IqPacket.TYPE_RESULT) { sendNextBlock(); } } }; - public JingleInbandTransport(Account account, String counterpart, - String sid, int blocksize) { - this.account = account; - this.counterpart = counterpart; + public JingleInbandTransport(final JingleConnection connection, final String sid, final int blocksize) { + this.connection = connection; + this.account = connection.getAccount(); + this.counterpart = connection.getCounterPart(); this.blockSize = blocksize; this.bufferSize = blocksize / 4; this.sessionId = sid; @@ -60,7 +66,7 @@ public class JingleInbandTransport extends JingleTransport { open.setAttribute("sid", this.sessionId); open.setAttribute("stanza", "iq"); open.setAttribute("block-size", Integer.toString(this.blockSize)); - + this.connected = true; this.account.getXmppConnection().sendIqPacket(iq, new OnIqPacketReceived() { @@ -91,13 +97,11 @@ public class JingleInbandTransport extends JingleTransport { callback.onFileTransferAborted(); return; } - this.remainingSize = file.getExpectedSize(); - } catch (NoSuchAlgorithmException e) { - callback.onFileTransferAborted(); - } catch (IOException e) { + this.remainingSize = this.fileSize = file.getExpectedSize(); + } catch (final NoSuchAlgorithmException | IOException e) { callback.onFileTransferAborted(); } - } + } @Override public void send(DownloadableFile file, @@ -105,6 +109,8 @@ public class JingleInbandTransport extends JingleTransport { this.onFileTransmissionStatusChanged = callback; this.file = file; try { + this.remainingSize = this.file.getSize(); + this.fileSize = this.remainingSize; this.digest = MessageDigest.getInstance("SHA-1"); this.digest.reset(); fileInputStream = this.file.createInputStream(); @@ -112,12 +118,33 @@ public class JingleInbandTransport extends JingleTransport { callback.onFileTransferAborted(); return; } - this.sendNextBlock(); + if (this.connected) { + this.sendNextBlock(); + } } catch (NoSuchAlgorithmException e) { callback.onFileTransferAborted(); } } + @Override + public void disconnect() { + this.connected = false; + if (this.fileOutputStream != null) { + try { + this.fileOutputStream.close(); + } catch (IOException e) { + + } + } + if (this.fileInputStream != null) { + try { + this.fileInputStream.close(); + } catch (IOException e) { + + } + } + } + private void sendNextBlock() { byte[] buffer = new byte[this.bufferSize]; try { @@ -127,6 +154,7 @@ public class JingleInbandTransport extends JingleTransport { fileInputStream.close(); this.onFileTransmissionStatusChanged.onFileTransmitted(file); } else { + this.remainingSize -= count; this.digest.update(buffer); String base64 = Base64.encodeToString(buffer, Base64.NO_WRAP); IqPacket iq = new IqPacket(IqPacket.TYPE_SET); @@ -141,6 +169,7 @@ public class JingleInbandTransport extends JingleTransport { this.account.getXmppConnection().sendIqPacket(iq, this.onAckReceived); this.seq++; + connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); } } catch (IOException e) { this.onFileTransmissionStatusChanged.onFileTransferAborted(); @@ -156,6 +185,7 @@ public class JingleInbandTransport extends JingleTransport { } this.remainingSize -= buffer.length; + this.fileOutputStream.write(buffer); this.digest.update(buffer); @@ -164,6 +194,8 @@ public class JingleInbandTransport extends JingleTransport { fileOutputStream.flush(); fileOutputStream.close(); this.onFileTransmissionStatusChanged.onFileTransmitted(file); + } else { + connection.updateProgress((int) ((((double) (this.fileSize - this.remainingSize)) / this.fileSize) * 100)); } } catch (IOException e) { this.onFileTransmissionStatusChanged.onFileTransferAborted(); @@ -174,13 +206,14 @@ public class JingleInbandTransport extends JingleTransport { if (payload.getName().equals("open")) { if (!established) { established = true; + connected = true; this.account.getXmppConnection().sendIqPacket( packet.generateRespone(IqPacket.TYPE_RESULT), null); } else { this.account.getXmppConnection().sendIqPacket( packet.generateRespone(IqPacket.TYPE_ERROR), null); } - } else if (payload.getName().equals("data")) { + } else if (connected && payload.getName().equals("data")) { this.receiveNextBlock(payload.getContent()); this.account.getXmppConnection().sendIqPacket( packet.generateRespone(IqPacket.TYPE_RESULT), null); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 1da2f0cd..c3419580 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -15,6 +15,7 @@ import eu.siacs.conversations.utils.CryptoHelper; public class JingleSocks5Transport extends JingleTransport { private JingleCandidate candidate; + private JingleConnection connection; private String destination; private OutputStream outputStream; private InputStream inputStream; @@ -25,16 +26,17 @@ public class JingleSocks5Transport extends JingleTransport { public JingleSocks5Transport(JingleConnection jingleConnection, JingleCandidate candidate) { this.candidate = candidate; + this.connection = jingleConnection; try { MessageDigest mDigest = MessageDigest.getInstance("SHA-1"); StringBuilder destBuilder = new StringBuilder(); destBuilder.append(jingleConnection.getSessionId()); if (candidate.isOurs()) { - destBuilder.append(jingleConnection.getAccount().getFullJid()); + destBuilder.append(jingleConnection.getAccount().getJid()); destBuilder.append(jingleConnection.getCounterPart()); } else { destBuilder.append(jingleConnection.getCounterPart()); - destBuilder.append(jingleConnection.getAccount().getFullJid()); + destBuilder.append(jingleConnection.getAccount().getJid()); } mDigest.reset(); this.destination = CryptoHelper.bytesToHex(mDigest @@ -102,11 +104,15 @@ public class JingleSocks5Transport extends JingleTransport { callback.onFileTransferAborted(); return; } + long size = file.getSize(); + long transmitted = 0; int count; byte[] buffer = new byte[8192]; while ((count = fileInputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, count); digest.update(buffer, 0, count); + transmitted += count; + connection.updateProgress((int) ((((double) transmitted) / size) * 100)); } outputStream.flush(); file.setSha1Sum(CryptoHelper.bytesToHex(digest.digest())); @@ -151,6 +157,7 @@ public class JingleSocks5Transport extends JingleTransport { callback.onFileTransferAborted(); return; } + double size = file.getExpectedSize(); long remainingSize = file.getExpectedSize(); byte[] buffer = new byte[8192]; int count = buffer.length; @@ -164,6 +171,7 @@ public class JingleSocks5Transport extends JingleTransport { digest.update(buffer, 0, count); remainingSize -= count; } + connection.updateProgress((int) (((size - remainingSize) / size) * 100)); } fileOutputStream.flush(); fileOutputStream.close(); @@ -189,6 +197,20 @@ public class JingleSocks5Transport extends JingleTransport { } public void disconnect() { + if (this.outputStream != null) { + try { + this.outputStream.close(); + } catch (IOException e) { + + } + } + if (this.inputStream != null) { + try { + this.inputStream.close(); + } catch (IOException e) { + + } + } if (this.socket != null) { try { this.socket.close(); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java index 1374e61c..e832d3f5 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleTransport.java @@ -10,4 +10,6 @@ public abstract class JingleTransport { public abstract void send(final DownloadableFile file, final OnFileTransmissionStatusChanged callback); + + public abstract void disconnect(); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java index 77a73643..4f73a83a 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/JinglePacket.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.xmpp.jingle.stanzas; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class JinglePacket extends IqPacket { @@ -85,8 +86,8 @@ public class JinglePacket extends IqPacket { return this.jingle.getAttribute("action"); } - public void setInitiator(String initiator) { - this.jingle.setAttribute("initiator", initiator); + public void setInitiator(final Jid initiator) { + this.jingle.setAttribute("initiator", initiator.toString()); } public boolean isAction(String action) { |