diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index b16da4517..d68981bf6 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -221,15 +221,7 @@ public class XmppConnectionService extends Service { }; private PresenceGenerator mPresenceGenerator = new PresenceGenerator(this); private List accounts; - private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager( - this); - private final OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() { - - @Override - public void onJinglePacketReceived(Account account, JinglePacket packet) { - mJingleConnectionManager.deliverPacket(account, packet); - } - }; + private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(this); private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(this); private AvatarService mAvatarService = new AvatarService(this); private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this); @@ -1327,7 +1319,7 @@ public class XmppConnectionService extends Service { connection.setOnStatusChangedListener(this.statusListener); connection.setOnPresencePacketReceivedListener(this.mPresenceParser); connection.setOnUnregisteredIqPacketReceivedListener(this.mIqParser); - connection.setOnJinglePacketReceivedListener(this.jingleListener); + connection.setOnJinglePacketReceivedListener(((a, jp) -> mJingleConnectionManager.deliverPacket(a, jp))); connection.setOnBindListener(this.mOnBindListener); connection.setOnMessageAcknowledgeListener(this.mOnMessageAcknowledgedListener); connection.addOnAdvancedStreamFeaturesAvailableListener(this.mMessageArchiveService); diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index 3f365642f..6d4447e38 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -33,6 +33,7 @@ public final class Namespace { public static final String PING = "urn:xmpp:ping"; public static final String PUSH = "urn:xmpp:push:0"; public static final String COMMANDS = "http://jabber.org/protocol/commands"; + public static final String JINGLE = "urn:xmpp:jingle:1"; public static final String JINGLE_ENCRYPTED_TRANSPORT = "urn:xmpp:jingle:jet:0"; public static final String JINGLE_ENCRYPTED_TRANSPORT_OMEMO = "urn:xmpp:jingle:jet-omemo:0"; public static final String MUC_USER = "http://jabber.org/protocol/muc#user"; diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index da0eb9656..97590e4d6 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -669,8 +669,8 @@ public class XmppConnection implements Runnable { } private @NonNull - Element processPacket(final Tag currentTag, final int packetType) throws XmlPullParserException, IOException { - Element element; + Element processPacket(final Tag currentTag, final int packetType) throws IOException { + final Element element; switch (packetType) { case PACKET_IQ: element = new IqPacket(); @@ -691,16 +691,7 @@ public class XmppConnection implements Runnable { } while (!nextTag.isEnd(element.getName())) { if (!nextTag.isNo()) { - final Element child = tagReader.readElement(nextTag); - final String type = currentTag.getAttribute("type"); - if (packetType == PACKET_IQ - && "jingle".equals(child.getName()) - && ("set".equalsIgnoreCase(type) || "get" - .equalsIgnoreCase(type))) { - element = new JinglePacket(); - element.setAttributes(currentTag.getAttributes()); - } - element.addChild(child); + element.addChild(tagReader.readElement(nextTag)); } nextTag = tagReader.readTag(); if (nextTag == null) { @@ -720,7 +711,11 @@ public class XmppConnection implements Runnable { if (Config.BACKGROUND_STANZA_LOGGING && mXmppConnectionService.checkListeners()) { Log.d(Config.LOGTAG, "[background stanza] " + element); } - return element; + if (element instanceof IqPacket && element.hasChild("jingle", Namespace.JINGLE)) { + return JinglePacket.upgrade((IqPacket) element); + } else { + return element; + } } private void processIq(final Tag currentTag) throws XmlPullParserException, IOException { 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 8c2139bb0..8ba989270 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -33,7 +33,7 @@ public class JingleConnectionManager extends AbstractConnectionManager { public void deliverPacket(final Account account, final JinglePacket packet) { final AbstractJingleConnection.Id id = AbstractJingleConnection.Id.of(account, packet); - if (packet.isAction("session-initiate")) { //TODO check that id doesn't exist yet + if (packet.getAction() == JinglePacket.Action.SESSION_INITIATE) { //TODO check that id doesn't exist yet JingleFileTransferConnection connection = new JingleFileTransferConnection(this, id); connection.init(account, packet); connections.put(id, connection); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java index 6586474da..65bc0d5ed 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleFileTransferConnection.java @@ -31,7 +31,6 @@ import eu.siacs.conversations.entities.TransferablePlaceholder; import eu.siacs.conversations.parser.IqParser; import eu.siacs.conversations.persistance.FileBackend; 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; @@ -70,7 +69,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private boolean proxyActivationFailed = false; private String contentName; - private String contentCreator; + private Content.Creator contentCreator; private Transport initialTransport; private boolean remoteSupportsOmemoJet; @@ -104,10 +103,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple @Override public void onFileTransmitted(DownloadableFile file) { if (responding()) { - if (expectedHash.length > 0 && !Arrays.equals(expectedHash, file.getSha1Sum())) { - Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": hashes did not match"); + if (expectedHash.length > 0) { + if (Arrays.equals(expectedHash, file.getSha1Sum())) { + Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": received file matched the expected hash"); + } else { + Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": hashes did not match"); + } + } else { + Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": other party did not include file hash in file transfer"); } - Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": file transmitted(). we are responding"); sendSuccess(); xmppConnectionService.getFileBackend().updateFileParams(message); xmppConnectionService.databaseBackend.createMessage(message); @@ -219,10 +223,10 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } final File parent = this.file.getParentFile(); if (parent != null && parent.mkdirs()) { - Log.d(Config.LOGTAG,"created parent directories for file "+file.getAbsolutePath()); + Log.d(Config.LOGTAG, "created parent directories for file " + file.getAbsolutePath()); } if (this.file.createNewFile()) { - Log.d(Config.LOGTAG,"created output file "+file.getAbsolutePath()); + Log.d(Config.LOGTAG, "created output file " + file.getAbsolutePath()); } this.mFileOutputStream = AbstractConnectionManager.createOutputStream(this.file, false, true); return this.mFileOutputStream; @@ -230,7 +234,9 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple @Override void deliverPacket(final JinglePacket packet) { - if (packet.isAction("session-terminate")) { + final JinglePacket.Action action = packet.getAction(); + //TODO switch case + if (action == JinglePacket.Action.SESSION_TERMINATE) { Reason reason = packet.getReason(); if (reason != null) { if (reason.hasChild("cancel")) { @@ -249,10 +255,10 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } else { this.fail(); } - } else if (packet.isAction("session-accept")) { + } else if (action == JinglePacket.Action.SESSION_ACCEPT) { receiveAccept(packet); - } else if (packet.isAction("session-info")) { - final Element checksum = packet.getChecksum(); + } else if (action == JinglePacket.Action.SESSION_INFO) { + final Element checksum = packet.getJingleChild("checksum"); final Element file = checksum == null ? null : checksum.findChild("file"); final Element hash = file == null ? null : file.findChild("hash", "urn:xmpp:hashes:2"); if (hash != null && "sha-1".equalsIgnoreCase(hash.getAttribute("algo"))) { @@ -263,16 +269,16 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } } respondToIq(packet, true); - } else if (packet.isAction("transport-info")) { + } else if (action == JinglePacket.Action.TRANSPORT_INFO) { receiveTransportInfo(packet); - } else if (packet.isAction("transport-replace")) { + } else if (action == JinglePacket.Action.TRANSPORT_REPLACE) { if (packet.getJingleContent().hasIbbTransport()) { receiveFallbackToIbb(packet); } else { Log.d(Config.LOGTAG, "trying to fallback to something unknown" + packet.toString()); respondToIq(packet, false); } - } else if (packet.isAction("transport-accept")) { + } else if (action == JinglePacket.Action.TRANSPORT_ACCEPT) { receiveTransportAccept(packet); } else { Log.d(Config.LOGTAG, "packet arrived in connection. action was " + packet.getAction()); @@ -317,7 +323,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void init(Message message, XmppAxolotlMessage xmppAxolotlMessage) { this.mXmppAxolotlMessage = xmppAxolotlMessage; - this.contentCreator = "initiator"; + this.contentCreator = Content.Creator.INITIATOR; this.contentName = JingleConnectionManager.nextRandomId(); this.message = message; final List remoteFeatures = getRemoteFeatures(); @@ -413,7 +419,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple this.initiator = this.id.counterPart; this.responder = this.id.account.getJid(); final Content content = packet.getJingleContent(); - this.contentCreator = content.getAttribute("creator"); + this.contentCreator = content.getCreator(); this.initialTransport = content.hasSocks5Transport() ? Transport.SOCKS : Transport.IBB; this.contentName = content.getAttribute("name"); this.transportId = content.getTransportId(); @@ -531,8 +537,8 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } private void sendInitRequest() { - JinglePacket packet = this.bootstrapPacket("session-initiate"); - Content content = new Content(this.contentCreator, this.contentName); + final JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.SESSION_INITIATE); + final Content content = new Content(this.contentCreator, this.contentName); if (message.isFileOrImage()) { content.setTransportId(this.transportId); this.file = this.xmppConnectionService.getFileBackend().getFile(message, false); @@ -574,7 +580,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple Log.d(Config.LOGTAG, String.format("%s: sending S5B offer with %d candidates", id.account.getJid().asBareJid(), candidates.size())); content.socks5transport().setChildren(candidates); } - packet.setContent(content); + packet.setJingleContent(content); this.sendJinglePacket(packet, (account, response) -> { if (response.getType() == IqPacket.TYPE.RESULT) { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": other party received offer"); @@ -593,8 +599,15 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } private void sendHash() { - JinglePacket packet = this.bootstrapPacket("session-info"); - packet.addChecksum(file.getSha1Sum(), ftVersion.getNamespace()); + + final Element checksum = new Element("checksum", ftVersion.getNamespace()); + checksum.setAttribute("creator", "initiator"); + checksum.setAttribute("name", "a-file-offer"); + Element hash = checksum.addChild("file").addChild("hash", "urn:xmpp:hashes:2"); + hash.setAttribute("algo", "sha-1").setContent(Base64.encodeToString(file.getSha1Sum(), Base64.NO_WRAP)); + + final JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.SESSION_INFO); + packet.setJingleChild(checksum); this.sendJinglePacket(packet); } @@ -622,7 +635,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendAcceptSocks() { gatherAndConnectDirectCandidates(); this.jingleConnectionManager.getPrimaryCandidate(this.id.account, initiating(), (success, candidate) -> { - final JinglePacket packet = bootstrapPacket("session-accept"); + final JinglePacket packet = bootstrapPacket(JinglePacket.Action.SESSION_ACCEPT); final Content content = new Content(contentCreator, contentName); content.setFileOffer(fileOffer, ftVersion); content.setTransportId(transportId); @@ -635,7 +648,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple public void failed() { Log.d(Config.LOGTAG, "connection to our own proxy65 candidate failed"); content.socks5transport().setChildren(getCandidatesAsElements()); - packet.setContent(content); + packet.setJingleContent(content); sendJinglePacket(packet); connectNextCandidate(); } @@ -645,7 +658,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple Log.d(Config.LOGTAG, "connected to proxy65 candidate"); mergeCandidate(candidate); content.socks5transport().setChildren(getCandidatesAsElements()); - packet.setContent(content); + packet.setJingleContent(content); sendJinglePacket(packet); connectNextCandidate(); } @@ -653,7 +666,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } else { Log.d(Config.LOGTAG, "did not find a proxy65 candidate for ourselves"); content.socks5transport().setChildren(getCandidatesAsElements()); - packet.setContent(content); + packet.setJingleContent(content); sendJinglePacket(packet); connectNextCandidate(); } @@ -662,23 +675,19 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendAcceptIbb() { this.transport = new JingleInBandTransport(this, this.transportId, this.ibbBlockSize); - final JinglePacket packet = bootstrapPacket("session-accept"); + final JinglePacket packet = bootstrapPacket(JinglePacket.Action.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); + packet.setJingleContent(content); this.transport.receive(file, onFileTransmissionStatusChanged); this.sendJinglePacket(packet); } - private JinglePacket bootstrapPacket(String action) { - JinglePacket packet = new JinglePacket(); - packet.setAction(action); - packet.setFrom(id.account.getJid()); + private JinglePacket bootstrapPacket(JinglePacket.Action action) { + final JinglePacket packet = new JinglePacket(action, this.id.sessionId); packet.setTo(id.counterPart); - packet.setSessionId(this.id.sessionId); - packet.setInitiator(this.initiator); return packet; } @@ -893,13 +902,13 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendFallbackToIbb() { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": sending fallback to ibb"); - JinglePacket packet = this.bootstrapPacket("transport-replace"); + JinglePacket packet = this.bootstrapPacket(JinglePacket.Action.TRANSPORT_REPLACE); Content content = new Content(this.contentCreator, this.contentName); - this.transportId = this.jingleConnectionManager.nextRandomId(); + this.transportId = JingleConnectionManager.nextRandomId(); content.setTransportId(this.transportId); content.ibbTransport().setAttribute("block-size", Integer.toString(this.ibbBlockSize)); - packet.setContent(content); + packet.setJingleContent(content); this.sendJinglePacket(packet); } @@ -932,12 +941,12 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple this.transportId = packet.getJingleContent().getTransportId(); this.transport = new JingleInBandTransport(this, this.transportId, this.ibbBlockSize); - final JinglePacket answer = bootstrapPacket("transport-accept"); + final JinglePacket answer = bootstrapPacket(JinglePacket.Action.TRANSPORT_ACCEPT); final Content content = new Content(contentCreator, contentName); content.ibbTransport().setAttribute("block-size", this.ibbBlockSize); content.ibbTransport().setAttribute("sid", this.transportId); - answer.setContent(content); + answer.setJingleContent(content); respondToIq(packet, true); @@ -1067,7 +1076,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } private void sendSessionTerminate(String reason) { - final JinglePacket packet = bootstrapPacket("session-terminate"); + final JinglePacket packet = bootstrapPacket(JinglePacket.Action.SESSION_TERMINATE); final Reason r = new Reason(); r.addChild(reason); packet.setReason(r); @@ -1120,29 +1129,29 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple } private void sendProxyActivated(String cid) { - final JinglePacket packet = bootstrapPacket("transport-info"); + final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); content.setTransportId(this.transportId); content.socks5transport().addChild("activated").setAttribute("cid", cid); - packet.setContent(content); + packet.setJingleContent(content); this.sendJinglePacket(packet); } private void sendProxyError() { - final JinglePacket packet = bootstrapPacket("transport-info"); + final JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); final Content content = new Content(this.contentCreator, this.contentName); content.setTransportId(this.transportId); content.socks5transport().addChild("proxy-error"); - packet.setContent(content); + packet.setJingleContent(content); this.sendJinglePacket(packet); } private void sendCandidateUsed(final String cid) { - JinglePacket packet = bootstrapPacket("transport-info"); + JinglePacket packet = bootstrapPacket(JinglePacket.Action.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); + packet.setJingleContent(content); this.sentCandidate = true; if ((receivedCandidate) && (mJingleStatus == JINGLE_STATUS_ACCEPTED)) { connect(); @@ -1152,11 +1161,11 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple private void sendCandidateError() { Log.d(Config.LOGTAG, id.account.getJid().asBareJid() + ": sending candidate error"); - JinglePacket packet = bootstrapPacket("transport-info"); + JinglePacket packet = bootstrapPacket(JinglePacket.Action.TRANSPORT_INFO); Content content = new Content(this.contentCreator, this.contentName); content.setTransportId(this.transportId); content.socks5transport().addChild("candidate-error"); - packet.setContent(content); + packet.setJingleContent(content); this.sentCandidate = true; this.sendJinglePacket(packet); if (receivedCandidate && mJingleStatus == JINGLE_STATUS_ACCEPTED) { @@ -1253,7 +1262,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple return this.mProgress; } - public AbstractConnectionManager getConnectionManager() { + AbstractConnectionManager getConnectionManager() { return this.jingleConnectionManager; } 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 e98a7e49e..5dbeef03d 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 @@ -1,44 +1,44 @@ package eu.siacs.conversations.xmpp.jingle.stanzas; +import android.support.annotation.NonNull; + +import com.google.common.base.Preconditions; + +import java.util.Locale; + import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; public class Content extends Element { + private String transportId; //refactor to getDescription and getTransport //return either FileTransferDescription or GenericDescription or RtpDescription (all extend Description interface) - 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; - - Version(String namespace) { - this.namespace = namespace; - } - - public String getNamespace() { - return namespace; - } - } - - private String transportId; - - public Content() { - super("content"); - } - - public Content(String creator, String name) { - super("content"); - this.setAttribute("creator", creator); - this.setAttribute("senders", creator); + public Content(final Creator creator, final String name) { + super("content", Namespace.JINGLE); + this.setAttribute("creator", creator.toString()); this.setAttribute("name", name); } + private Content() { + super("content", Namespace.JINGLE); + } + + public static Content upgrade(final Element element) { + Preconditions.checkArgument("content".equals(element.getName())); + final Content content = new Content(); + content.setAttributes(element.getAttributes()); + content.setChildren(element.getChildren()); + return content; + } + + public Creator getCreator() { + return Creator.of(getAttribute("creator")); + } + public Version getVersion() { if (hasChild("description", Version.FT_3.namespace)) { return Version.FT_3; @@ -50,10 +50,6 @@ public class Content extends Element { return null; } - 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; @@ -106,6 +102,10 @@ public class Content extends Element { return this.transportId; } + public void setTransportId(String sid) { + this.transportId = sid; + } + public Element socks5transport() { Element transport = this.findChild("transport", Namespace.JINGLE_TRANSPORTS_S5B); if (transport == null) { @@ -131,4 +131,48 @@ public class Content extends Element { public boolean hasIbbTransport() { return this.hasChild("transport", Namespace.JINGLE_TRANSPORTS_IBB); } + + 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; + + Version(String namespace) { + this.namespace = namespace; + } + + public String getNamespace() { + return namespace; + } + } + + public enum Creator { + INITIATOR, RESPONDER; + + public static Creator of(final String value) { + return Creator.valueOf(value.toUpperCase(Locale.ROOT)); + } + + @Override + @NonNull + public String toString() { + return super.toString().toLowerCase(Locale.ROOT); + } + } + + public enum Senders { + BOTH, INITIATOR, NONE, RESPONDER; + + public static Senders of(final String value) { + return Senders.valueOf(value.toUpperCase(Locale.ROOT)); + } + + @Override + @NonNull + public String toString() { + return super.toString().toLowerCase(Locale.ROOT); + } + } } 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 fe9a2ab56..b59ece9c2 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,121 +1,98 @@ package eu.siacs.conversations.xmpp.jingle.stanzas; -import android.util.Base64; +import android.support.annotation.NonNull; + +import com.google.common.base.CaseFormat; +import com.google.common.base.Preconditions; import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -import rocks.xmpp.addr.Jid; public class JinglePacket extends IqPacket { - - //get rid of that BS and set/get directly - Content content = null; - Reason reason = null; - Element checksum = null; - Element jingle = new Element("jingle"); - - //get rid of what ever that is; maybe throw illegal state to ensure we are only calling setContent etc - @Override - public Element addChild(Element child) { - if ("jingle".equals(child.getName())) { - Element contentElement = child.findChild("content"); - if (contentElement != null) { - this.content = new Content(); - this.content.setChildren(contentElement.getChildren()); - this.content.setAttributes(contentElement.getAttributes()); - } - Element reasonElement = child.findChild("reason"); - if (reasonElement != null) { - this.reason = new Reason(); - this.reason.setChildren(reasonElement.getChildren()); - this.reason.setAttributes(reasonElement.getAttributes()); - } - this.checksum = child.findChild("checksum"); - this.jingle.setAttributes(child.getAttributes()); - } - return child; + private JinglePacket() { + super(); } - public JinglePacket setContent(Content content) { //take content interface - this.content = content; - return this; + public JinglePacket(final Action action, final String sessionId) { + super(TYPE.SET); + final Element jingle = addChild("jingle", Namespace.JINGLE); + jingle.setAttribute("sid", sessionId); + jingle.setAttribute("action", action.toString()); + } + + public static JinglePacket upgrade(final IqPacket iqPacket) { + Preconditions.checkArgument(iqPacket.hasChild("jingle", Namespace.JINGLE)); + final JinglePacket jinglePacket = new JinglePacket(); + jinglePacket.setAttributes(iqPacket.getAttributes()); + jinglePacket.setChildren(iqPacket.getChildren()); + return jinglePacket; } public Content getJingleContent() { - if (this.content == null) { - this.content = new Content(); - } - return this.content; + final Element content = getJingleChild("content"); + return content == null ? null : Content.upgrade(content); + } + + public void setJingleContent(final Content content) { //take content interface + setJingleChild(content); } public Reason getReason() { - return this.reason; + final Element reason = getJingleChild("reason"); + return reason == null ? null : Reason.upgrade(reason); } - public JinglePacket setReason(Reason reason) { - this.reason = reason; - return this; + public void setReason(final Reason reason) { + final Element jingle = findChild("jingle", Namespace.JINGLE); + jingle.addChild(reason); } - public Element getChecksum() { - return this.checksum; + public Element getJingleChild(final String name) { + final Element jingle = findChild("jingle", Namespace.JINGLE); + return jingle == null ? null : jingle.findChild(name); } - //should be unnecessary if we set and get directly - private void build() { - this.children.clear(); - this.jingle.clearChildren(); - this.jingle.setAttribute("xmlns", "urn:xmpp:jingle:1"); - if (this.content != null) { - jingle.addChild(this.content); - } - if (this.reason != null) { - jingle.addChild(this.reason); - } - if (this.checksum != null) { - jingle.addChild(checksum); - } - this.children.add(jingle); - this.setAttribute("type", "set"); + public void setJingleChild(final Element child) { + final Element jingle = findChild("jingle", Namespace.JINGLE); + jingle.addChild(child); } public String getSessionId() { - return this.jingle.getAttribute("sid"); + return findChild("jingle", Namespace.JINGLE).getAttribute("sid"); } - public void setSessionId(String sid) { - this.jingle.setAttribute("sid", sid); + public Action getAction() { + return Action.of(findChild("jingle", Namespace.JINGLE).getAttribute("action")); } - @Override - public String toString() { - this.build(); - return super.toString(); - } + public enum Action { + CONTENT_ACCEPT, + CONTENT_ADD, + CONTENT_MODIFY, + CONTENT_REJECT, + CONTENT_REMOVE, + DESCRIPTION_INFO, + SECURITY_INFO, + SESSION_ACCEPT, + SESSION_INFO, + SESSION_INITIATE, + SESSION_TERMINATE, + TRANSPORT_ACCEPT, + TRANSPORT_INFO, + TRANSPORT_REJECT, + TRANSPORT_REPLACE; - //use enum for action - public String getAction() { - return this.jingle.getAttribute("action"); - } + public static Action of(final String value) { + //TODO handle invalid + return Action.valueOf(CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, value)); + } - public void setAction(String action) { - this.jingle.setAttribute("action", action); - } - - public void setInitiator(final Jid initiator) { - this.jingle.setAttribute("initiator", initiator.toString()); - } - - public boolean isAction(String action) { - return action.equalsIgnoreCase(this.getAction()); - } - - public void addChecksum(byte[] sha1Sum, String namespace) { - this.checksum = new Element("checksum", namespace); - checksum.setAttribute("creator", "initiator"); - checksum.setAttribute("name", "a-file-offer"); - Element hash = checksum.addChild("file").addChild("hash", "urn:xmpp:hashes:2"); - hash.setAttribute("algo", "sha-1").setContent(Base64.encodeToString(sha1Sum, Base64.NO_WRAP)); + @Override + @NonNull + public String toString() { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, super.toString()); + } } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java index 610d5e760..1eae65c5b 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/stanzas/Reason.java @@ -1,13 +1,20 @@ package eu.siacs.conversations.xmpp.jingle.stanzas; +import com.google.common.base.Preconditions; + import eu.siacs.conversations.xml.Element; public class Reason extends Element { - private Reason(String name) { - super(name); - } public Reason() { super("reason"); } + + public static Reason upgrade(final Element element) { + Preconditions.checkArgument("reason".equals(element.getName())); + final Reason reason = new Reason(); + reason.setAttributes(element.getAttributes()); + reason.setChildren(element.getChildren()); + return reason; + } }