diff options
Diffstat (limited to '')
9 files changed, 201 insertions, 273 deletions
diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java index 54409be4..39dcb362 100644 --- a/src/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java @@ -4,14 +4,17 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; +import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Hashtable; +import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; @@ -22,14 +25,19 @@ import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509TrustManager; +import org.apache.http.conn.ssl.StrictHostnameVerifier; import org.xmlpull.v1.XmlPullParserException; import de.duenndns.ssl.MemorizingTrustManager; +import android.content.Context; +import android.content.SharedPreferences; import android.os.Bundle; +import android.os.Parcelable; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.SystemClock; +import android.preference.PreferenceManager; import android.util.Log; import android.util.SparseArray; import eu.siacs.conversations.Config; @@ -80,6 +88,7 @@ public class XmppConnection implements Runnable { private SparseArray<String> messageReceipts = new SparseArray<String>(); private boolean usingCompression = false; + private boolean usingEncryption = false; private int stanzasReceived = 0; private int stanzasSent = 0; @@ -104,6 +113,7 @@ public class XmppConnection implements Runnable { private OnBindListener bindListener = null; private OnMessageAcknowledged acknowledgedListener = null; private MemorizingTrustManager mMemorizingTrustManager; + private final Context applicationContext; public XmppConnection(Account account, XmppConnectionService service) { this.mRandom = service.getRNG(); @@ -112,6 +122,7 @@ public class XmppConnection implements Runnable { this.wakeLock = service.getPowerManager().newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, account.getJid()); tagWriter = new TagWriter(); + applicationContext = service.getApplicationContext(); } protected void changeStatus(int nextStatus) { @@ -135,6 +146,7 @@ public class XmppConnection implements Runnable { protected void connect() { Log.d(Config.LOGTAG, account.getJid() + ": connecting"); usingCompression = false; + usingEncryption = false; lastConnect = SystemClock.elapsedRealtime(); lastPingSent = SystemClock.elapsedRealtime(); this.attempt++; @@ -145,29 +157,47 @@ public class XmppConnection implements Runnable { tagWriter = new TagWriter(); packetCallbacks.clear(); this.changeStatus(Account.STATUS_CONNECTING); - Bundle namePort = DNSHelper.getSRVRecord(account.getServer()); - if ("timeout".equals(namePort.getString("error"))) { + Bundle result = DNSHelper.getSRVRecord(account.getServer()); + ArrayList<Parcelable> values = result.getParcelableArrayList("values"); + if ("timeout".equals(result.getString("error"))) { Log.d(Config.LOGTAG, account.getJid() + ": dns timeout"); this.changeStatus(Account.STATUS_OFFLINE); return; - } - String srvRecordServer = namePort.getString("name"); - String srvIpServer = namePort.getString("ipv4"); - int srvRecordPort = namePort.getInt("port"); - if (srvRecordServer != null) { - if (srvIpServer != null) { - Log.d(Config.LOGTAG, account.getJid() - + ": using values from dns " + srvRecordServer - + "[" + srvIpServer + "]:" + srvRecordPort); - socket = new Socket(srvIpServer, srvRecordPort); - } else { - Log.d(Config.LOGTAG, account.getJid() - + ": using values from dns " + srvRecordServer - + ":" + srvRecordPort); - socket = new Socket(srvRecordServer, srvRecordPort); - } - } else if (namePort.containsKey("error") - && "nosrv".equals(namePort.getString("error", null))) { + } else if (values != null) { + int i = 0; + boolean socketError = true; + while (socketError && values.size() > i) { + Bundle namePort = (Bundle) values.get(i); + try { + String srvRecordServer = namePort.getString("name"); + int srvRecordPort = namePort.getInt("port"); + String srvIpServer = namePort.getString("ipv4"); + InetSocketAddress addr; + if (srvIpServer!=null) { + addr = new InetSocketAddress(srvIpServer, srvRecordPort); + Log.d(Config.LOGTAG, account.getJid() + + ": using values from dns " + srvRecordServer + + "[" + srvIpServer + "]:" + srvRecordPort); + } else { + addr = new InetSocketAddress(srvRecordServer, srvRecordPort); + Log.d(Config.LOGTAG, account.getJid() + + ": using values from dns " + + srvRecordServer + ":" + srvRecordPort); + } + socket = new Socket(); + socket.connect(addr, 20000); + socketError = false; + } catch (UnknownHostException e) { + i++; + } catch (IOException e) { + i++; + } + } + if (socketError) { + throw new IOException(); + } + } else if (result.containsKey("error") + && "nosrv".equals(result.getString("error", null))) { socket = new Socket(account.getServer(), 5222); } else { Log.d(Config.LOGTAG, account.getJid() @@ -504,6 +534,15 @@ public class XmppConnection implements Runnable { tagWriter.writeTag(startTLS); } + private SharedPreferences getPreferences() { + return PreferenceManager + .getDefaultSharedPreferences(applicationContext); + } + + private boolean enableLegacySSL() { + return getPreferences().getBoolean("enable_legacy_ssl", false); + } + private void switchOverToTls(Tag currentTag) throws XmlPullParserException, IOException { tagReader.readTag(); @@ -515,11 +554,27 @@ public class XmppConnection implements Runnable { SSLSocketFactory factory = sc.getSocketFactory(); HostnameVerifier verifier = this.mMemorizingTrustManager - .wrapHostnameVerifier(new org.apache.http.conn.ssl.StrictHostnameVerifier()); + .wrapHostnameVerifier(new StrictHostnameVerifier()); SSLSocket sslSocket = (SSLSocket) factory.createSocket(socket, socket.getInetAddress().getHostAddress(), socket.getPort(), true); + // Support all protocols except legacy SSL. + // The min SDK version prevents us having to worry about SSLv2. In + // future, this may be + // true of SSLv3 as well. + final String[] supportProtocols; + if (enableLegacySSL()) { + supportProtocols = sslSocket.getSupportedProtocols(); + } else { + final List<String> supportedProtocols = new LinkedList<String>( + Arrays.asList(sslSocket.getSupportedProtocols())); + supportedProtocols.remove("SSLv3"); + supportProtocols = new String[supportedProtocols.size()]; + supportedProtocols.toArray(supportProtocols); + } + sslSocket.setEnabledProtocols(supportProtocols); + if (verifier != null && !verifier.verify(account.getServer(), sslSocket.getSession())) { @@ -533,6 +588,7 @@ public class XmppConnection implements Runnable { sendStartStream(); Log.d(Config.LOGTAG, account.getJid() + ": TLS connection established"); + usingEncryption = true; processStream(tagReader.readTag()); sslSocket.close(); } catch (NoSuchAlgorithmException e1) { @@ -562,20 +618,20 @@ public class XmppConnection implements Runnable { private void processStreamFeatures(Tag currentTag) throws XmlPullParserException, IOException { this.streamFeatures = tagReader.readElement(currentTag); - if (this.streamFeatures.hasChild("starttls") - && account.isOptionSet(Account.OPTION_USETLS)) { + if (this.streamFeatures.hasChild("starttls") && !usingEncryption) { sendStartTLS(); } else if (compressionAvailable()) { sendCompressionZlib(); } else if (this.streamFeatures.hasChild("register") - && (account.isOptionSet(Account.OPTION_REGISTER))) { + && account.isOptionSet(Account.OPTION_REGISTER) + && usingEncryption) { sendRegistryRequest(); } else if (!this.streamFeatures.hasChild("register") - && (account.isOptionSet(Account.OPTION_REGISTER))) { + && account.isOptionSet(Account.OPTION_REGISTER)) { changeStatus(Account.STATUS_REGISTRATION_NOT_SUPPORTED); disconnect(true); } else if (this.streamFeatures.hasChild("mechanisms") - && shouldAuthenticate) { + && shouldAuthenticate && usingEncryption) { List<String> mechanisms = extractMechanisms(streamFeatures .findChild("mechanisms")); if (mechanisms.contains("PLAIN")) { @@ -591,6 +647,10 @@ public class XmppConnection implements Runnable { this.tagWriter.writeStanzaAsync(resume); } else if (this.streamFeatures.hasChild("bind") && shouldBind) { sendBindRequest(); + } else { + Log.d(Config.LOGTAG, account.getJid() + + ": incompatible server. disconnecting"); + disconnect(true); } } @@ -910,7 +970,7 @@ public class XmppConnection implements Runnable { } public void disconnect(boolean force) { - Log.d(Config.LOGTAG, account.getJid()+": disconnecting"); + Log.d(Config.LOGTAG, account.getJid() + ": disconnecting"); try { if (force) { socket.close(); diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index 92fdbe0b..6b9ca9aa 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -16,6 +16,7 @@ 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.Message; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xml.Element; @@ -33,17 +34,18 @@ public class JingleConnection implements Downloadable { private JingleConnectionManager mJingleConnectionManager; private XmppConnectionService mXmppConnectionService; - public static final int STATUS_INITIATED = 0; - public static final int STATUS_ACCEPTED = 1; - public static final int STATUS_TERMINATED = 2; - public static final int STATUS_CANCELED = 3; - public static final int STATUS_FINISHED = 4; - public static final int STATUS_TRANSMITTING = 5; - public static final int STATUS_FAILED = 99; + protected static final int JINGLE_STATUS_INITIATED = 0; + protected static final int JINGLE_STATUS_ACCEPTED = 1; + protected static final int JINGLE_STATUS_TERMINATED = 2; + protected static final int JINGLE_STATUS_CANCELED = 3; + 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 = 4096; - private int status = -1; + private int mJingleStatus = -1; + private int mStatus = -1; private Message message; private String sessionId; private Account account; @@ -54,7 +56,7 @@ public class JingleConnection implements Downloadable { private String transportId; private Element fileOffer; - private JingleFile file = null; + private DownloadableFile file = null; private String contentName; private String contentCreator; @@ -71,11 +73,7 @@ public class JingleConnection implements Downloadable { @Override public void onIqPacketReceived(Account account, IqPacket packet) { if (packet.getType() == IqPacket.TYPE_ERROR) { - if (initiator.equals(account.getFullJid())) { - mXmppConnectionService.markMessage(message, - Message.STATUS_SEND_FAILED); - } - status = STATUS_FAILED; + cancel(); } } }; @@ -83,7 +81,7 @@ public class JingleConnection implements Downloadable { final OnFileTransmissionStatusChanged onFileTransmissionSatusChanged = new OnFileTransmissionStatusChanged() { @Override - public void onFileTransmitted(JingleFile file) { + public void onFileTransmitted(DownloadableFile file) { if (responder.equals(account.getFullJid())) { sendSuccess(); if (acceptedAutomatically) { @@ -96,8 +94,8 @@ public class JingleConnection implements Downloadable { BitmapFactory.decodeFile(file.getAbsolutePath(), options); int imageHeight = options.outHeight; int imageWidth = options.outWidth; - message.setBody(Long.toString(file.getSize()) + ',' - + imageWidth + ',' + imageHeight); + message.setBody(Long.toString(file.getSize()) + '|' + + imageWidth + '|' + imageHeight); mXmppConnectionService.databaseBackend.createMessage(message); mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVED); @@ -148,8 +146,8 @@ public class JingleConnection implements Downloadable { return this.sessionId; } - public String getAccountJid() { - return this.account.getFullJid(); + public Account getAccount() { + return this.account; } public String getCounterPart() { @@ -253,13 +251,14 @@ public class JingleConnection implements Downloadable { } public void init(Account account, JinglePacket packet) { - this.status = STATUS_INITIATED; + this.mJingleStatus = JINGLE_STATUS_INITIATED; Conversation conversation = this.mXmppConnectionService .findOrCreateConversation(account, packet.getFrom().split("/", 2)[0], false); this.message = new Message(conversation, "", Message.ENCRYPTION_NONE); + this.message.setStatus(Message.STATUS_RECEIVED); this.message.setType(Message.TYPE_IMAGE); - this.message.setStatus(Message.STATUS_RECEIVED_OFFER); + this.mStatus = Downloadable.STATUS_OFFER; this.message.setDownloadable(this); String[] fromParts = packet.getFrom().split("/", 2); this.message.setPresence(fromParts[1]); @@ -304,7 +303,8 @@ public class JingleConnection implements Downloadable { if (supportedFile) { long size = Long.parseLong(fileSize.getContent()); message.setBody(Long.toString(size)); - conversation.getMessages().add(message); + conversation.add(message); + mXmppConnectionService.updateConversationUi(); if (size <= this.mJingleConnectionManager .getAutoAcceptFileSize()) { Log.d(Config.LOGTAG, "auto accepting file from " @@ -323,7 +323,7 @@ public class JingleConnection implements Downloadable { .push(message); } this.file = this.mXmppConnectionService.getFileBackend() - .getJingleFile(message, false); + .getFile(message, false); if (message.getEncryption() == Message.ENCRYPTION_OTR) { byte[] key = conversation.getSymmetricKey(); if (key == null) { @@ -350,12 +350,13 @@ public class JingleConnection implements Downloadable { } private void sendInitRequest() { + 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) { content.setTransportId(this.transportId); - this.file = this.mXmppConnectionService.getFileBackend() - .getJingleFile(message, false); + this.file = this.mXmppConnectionService.getFileBackend().getFile( + message, false); if (message.getEncryption() == Message.ENCRYPTION_OTR) { Conversation conversation = this.message.getConversation(); this.mXmppConnectionService.renewSymmetricKey(conversation); @@ -369,7 +370,7 @@ public class JingleConnection implements Downloadable { content.socks5transport().setChildren(getCandidatesAsElements()); packet.setContent(content); this.sendJinglePacket(packet); - this.status = STATUS_INITIATED; + this.mJingleStatus = JINGLE_STATUS_INITIATED; } } @@ -382,8 +383,9 @@ public class JingleConnection implements Downloadable { } private void sendAccept() { - status = STATUS_ACCEPTED; - mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVING); + mJingleStatus = JINGLE_STATUS_ACCEPTED; + this.mStatus = Downloadable.STATUS_DOWNLOADING; + mXmppConnectionService.updateConversationUi(); this.mJingleConnectionManager.getPrimaryCandidate(this.account, new OnPrimaryCandidateFound() { @@ -457,7 +459,7 @@ public class JingleConnection implements Downloadable { Content content = packet.getJingleContent(); mergeCandidates(JingleCandidate.parse(content.socks5transport() .getChildren())); - this.status = STATUS_ACCEPTED; + this.mJingleStatus = JINGLE_STATUS_ACCEPTED; mXmppConnectionService.markMessage(message, Message.STATUS_UNSEND); this.connectNextCandidate(); return true; @@ -492,7 +494,8 @@ public class JingleConnection implements Downloadable { } else if (content.socks5transport().hasChild("candidate-error")) { Log.d(Config.LOGTAG, "received candidate error"); this.receivedCandidate = true; - if ((status == STATUS_ACCEPTED) && (this.sentCandidate)) { + if ((mJingleStatus == JINGLE_STATUS_ACCEPTED) + && (this.sentCandidate)) { this.connect(); } return true; @@ -504,7 +507,8 @@ public class JingleConnection implements Downloadable { JingleCandidate candidate = getCandidate(cid); candidate.flagAsUsedByCounterpart(); this.receivedCandidate = true; - if ((status == STATUS_ACCEPTED) && (this.sentCandidate)) { + if ((mJingleStatus == JINGLE_STATUS_ACCEPTED) + && (this.sentCandidate)) { this.connect(); } else { Log.d(Config.LOGTAG, @@ -532,7 +536,7 @@ public class JingleConnection implements Downloadable { this.sendFallbackToIbb(); } } else { - this.status = STATUS_TRANSMITTING; + this.mJingleStatus = JINGLE_STATUS_TRANSMITTING; if (connection.needsActivation()) { if (connection.getCandidate().isOurs()) { Log.d(Config.LOGTAG, "candidate " @@ -619,13 +623,15 @@ public class JingleConnection implements Downloadable { packet.setReason(reason); this.sendJinglePacket(packet); this.disconnect(); - this.status = STATUS_FINISHED; - this.mXmppConnectionService.markMessage(this.message, - Message.STATUS_RECEIVED); + this.mJingleStatus = JINGLE_STATUS_FINISHED; + this.message.setStatus(Message.STATUS_RECEIVED); + this.message.setDownloadable(null); + this.mXmppConnectionService.updateMessage(message); this.mJingleConnectionManager.finishConnection(this); } private void sendFallbackToIbb() { + Log.d(Config.LOGTAG, "sending fallback to ibb"); JinglePacket packet = this.bootstrapPacket("transport-replace"); Content content = new Content(this.contentCreator, this.contentName); this.transportId = this.mJingleConnectionManager.nextRandomId(); @@ -637,6 +643,7 @@ public class JingleConnection implements Downloadable { } private boolean receiveFallbackToIbb(JinglePacket packet) { + Log.d(Config.LOGTAG, "receiving fallack to ibb"); String receivedBlockSize = packet.getJingleContent().ibbTransport() .getAttribute("block-size"); if (receivedBlockSize != null) { @@ -691,7 +698,7 @@ public class JingleConnection implements Downloadable { } private void receiveSuccess() { - this.status = STATUS_FINISHED; + this.mJingleStatus = JINGLE_STATUS_FINISHED; this.mXmppConnectionService.markMessage(this.message, Message.STATUS_SEND); this.disconnect(); @@ -699,20 +706,15 @@ public class JingleConnection implements Downloadable { } public void cancel() { - this.status = STATUS_CANCELED; + this.mJingleStatus = JINGLE_STATUS_CANCELED; this.disconnect(); if (this.message != null) { if (this.responder.equals(account.getFullJid())) { - this.mXmppConnectionService.markMessage(this.message, - Message.STATUS_RECEPTION_FAILED); + this.mStatus = Downloadable.STATUS_FAILED; + this.mXmppConnectionService.updateConversationUi(); } else { - if (this.status == STATUS_INITIATED) { - this.mXmppConnectionService.markMessage(this.message, - Message.STATUS_SEND_REJECTED); - } else { - this.mXmppConnectionService.markMessage(this.message, - Message.STATUS_SEND_FAILED); - } + this.mXmppConnectionService.markMessage(this.message, + Message.STATUS_SEND_FAILED); } } this.mJingleConnectionManager.finishConnection(this); @@ -789,7 +791,7 @@ public class JingleConnection implements Downloadable { .setAttribute("cid", cid); packet.setContent(content); this.sentCandidate = true; - if ((receivedCandidate) && (status == STATUS_ACCEPTED)) { + if ((receivedCandidate) && (mJingleStatus == JINGLE_STATUS_ACCEPTED)) { connect(); } this.sendJinglePacket(packet); @@ -802,7 +804,7 @@ public class JingleConnection implements Downloadable { content.socks5transport().addChild("candidate-error"); packet.setContent(content); this.sentCandidate = true; - if ((receivedCandidate) && (status == STATUS_ACCEPTED)) { + if ((receivedCandidate) && (mJingleStatus == JINGLE_STATUS_ACCEPTED)) { connect(); } this.sendJinglePacket(packet); @@ -816,8 +818,8 @@ public class JingleConnection implements Downloadable { return this.responder; } - public int getStatus() { - return this.status; + public int getJingleStatus() { + return this.mJingleStatus; } private boolean equalCandidateExists(JingleCandidate candidate) { @@ -867,17 +869,34 @@ public class JingleConnection implements Downloadable { return this.transport; } - public void start() { - if (status == STATUS_INITIATED) { - new Thread(new Runnable() { + public boolean start() { + if (account.getStatus() == Account.STATUS_ONLINE) { + if (mJingleStatus == JINGLE_STATUS_INITIATED) { + new Thread(new Runnable() { - @Override - public void run() { - sendAccept(); - } - }).start(); + @Override + public void run() { + sendAccept(); + } + }).start(); + } + return true; + } else { + return false; + } + } + + @Override + public int getStatus() { + return this.mStatus; + } + + @Override + public long getFileSize() { + if (this.file != null) { + return this.file.getExpectedSize(); } else { - Log.d(Config.LOGTAG, "status (" + status + ") was not ok"); + return 0; } } } diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java index 79090af6..d937146a 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java @@ -10,16 +10,14 @@ import android.util.Log; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Message; +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.jingle.stanzas.JinglePacket; import eu.siacs.conversations.xmpp.stanzas.IqPacket; -public class JingleConnectionManager { - - private XmppConnectionService xmppConnectionService; - +public class JingleConnectionManager extends AbstractConnectionManager { private List<JingleConnection> connections = new CopyOnWriteArrayList<JingleConnection>(); private HashMap<String, JingleCandidate> primaryCandidates = new HashMap<String, JingleCandidate>(); @@ -28,7 +26,7 @@ public class JingleConnectionManager { private SecureRandom random = new SecureRandom(); public JingleConnectionManager(XmppConnectionService service) { - this.xmppConnectionService = service; + super(service); } public void deliverPacket(Account account, JinglePacket packet) { @@ -38,7 +36,7 @@ public class JingleConnectionManager { connections.add(connection); } else { for (JingleConnection connection : connections) { - if (connection.getAccountJid().equals(account.getFullJid()) + if (connection.getAccount() == account && connection.getSessionId().equals( packet.getSessionId()) && connection.getCounterPart().equals(packet.getFrom())) { @@ -46,8 +44,13 @@ public class JingleConnectionManager { return; } } - account.getXmppConnection().sendIqPacket( - packet.generateRespone(IqPacket.TYPE_ERROR), null); + IqPacket response = packet.generateRespone(IqPacket.TYPE_ERROR); + Element error = response.addChild("error"); + error.setAttribute("type", "cancel"); + error.addChild("item-not-found", + "urn:ietf:params:xml:ns:xmpp-stanzas"); + error.addChild("unknown-session", "urn:xmpp:jingle:errors:1"); + account.getXmppConnection().sendIqPacket(response, null); } } @@ -68,10 +71,6 @@ public class JingleConnectionManager { this.connections.remove(connection); } - public XmppConnectionService getXmppConnectionService() { - return this.xmppConnectionService; - } - public void getPrimaryCandidate(Account account, final OnPrimaryCandidateFound listener) { if (!this.primaryCandidates.containsKey(account.getJid())) { @@ -128,16 +127,6 @@ public class JingleConnectionManager { return new BigInteger(50, random).toString(32); } - public long getAutoAcceptFileSize() { - String config = this.xmppConnectionService.getPreferences().getString( - "auto_accept_file_size", "524288"); - try { - return Long.parseLong(config); - } catch (NumberFormatException e) { - return 524288; - } - } - public void deliverIbbPacket(Account account, IqPacket packet) { String sid = null; Element payload = null; @@ -152,7 +141,8 @@ public class JingleConnectionManager { } if (sid != null) { for (JingleConnection connection : connections) { - if (connection.hasTransportId(sid)) { + if (connection.getAccount() == account + && connection.hasTransportId(sid)) { JingleTransport transport = connection.getTransport(); if (transport instanceof JingleInbandTransport) { JingleInbandTransport inbandTransport = (JingleInbandTransport) transport; @@ -170,7 +160,7 @@ public class JingleConnectionManager { public void cancelInTransmission() { for (JingleConnection connection : this.connections) { - if (connection.getStatus() == JingleConnection.STATUS_TRANSMITTING) { + if (connection.getJingleStatus() == JingleConnection.JINGLE_STATUS_TRANSMITTING) { connection.cancel(); } } diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java b/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java deleted file mode 100644 index 9253814b..00000000 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleFile.java +++ /dev/null @@ -1,68 +0,0 @@ -package eu.siacs.conversations.xmpp.jingle; - -import java.io.File; -import java.security.Key; - -import javax.crypto.spec.SecretKeySpec; - -import eu.siacs.conversations.Config; -import eu.siacs.conversations.utils.CryptoHelper; -import android.util.Log; - -public class JingleFile extends File { - - private static final long serialVersionUID = 2247012619505115863L; - - private long expectedSize = 0; - private String sha1sum; - private Key aeskey; - - public JingleFile(String path) { - super(path); - } - - public long getSize() { - return super.length(); - } - - public long getExpectedSize() { - if (this.aeskey != null) { - return (this.expectedSize / 16 + 1) * 16; - } else { - return this.expectedSize; - } - } - - public void setExpectedSize(long size) { - this.expectedSize = size; - } - - public String getSha1Sum() { - return this.sha1sum; - } - - public void setSha1Sum(String sum) { - this.sha1sum = sum; - } - - public void setKey(byte[] key) { - if (key.length >= 32) { - byte[] secretKey = new byte[32]; - System.arraycopy(key, 0, secretKey, 0, 32); - this.aeskey = new SecretKeySpec(secretKey, "AES"); - } else if (key.length >= 16) { - byte[] secretKey = new byte[16]; - System.arraycopy(key, 0, secretKey, 0, 16); - this.aeskey = new SecretKeySpec(secretKey, "AES"); - } else { - Log.d(Config.LOGTAG, "weird key"); - } - Log.d(Config.LOGTAG, - "using aes key " - + CryptoHelper.bytesToHex(this.aeskey.getEncoded())); - } - - public Key getKey() { - return this.aeskey; - } -} diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java index c5498075..cc1e92f6 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java @@ -1,6 +1,5 @@ package eu.siacs.conversations.xmpp.jingle; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -10,6 +9,7 @@ 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; @@ -26,7 +26,7 @@ public class JingleInbandTransport extends JingleTransport { private boolean established = false; - private JingleFile file; + private DownloadableFile file; private InputStream fileInputStream = null; private OutputStream fileOutputStream; @@ -77,7 +77,7 @@ public class JingleInbandTransport extends JingleTransport { } @Override - public void receive(JingleFile file, + public void receive(DownloadableFile file, OnFileTransmissionStatusChanged callback) { this.onFileTransmissionStatusChanged = callback; this.file = file; @@ -86,7 +86,7 @@ public class JingleInbandTransport extends JingleTransport { digest.reset(); file.getParentFile().mkdirs(); file.createNewFile(); - this.fileOutputStream = getOutputStream(file); + this.fileOutputStream = file.createOutputStream(); if (this.fileOutputStream == null) { callback.onFileTransferAborted(); return; @@ -100,20 +100,19 @@ public class JingleInbandTransport extends JingleTransport { } @Override - public void send(JingleFile file, OnFileTransmissionStatusChanged callback) { + public void send(DownloadableFile file, + OnFileTransmissionStatusChanged callback) { this.onFileTransmissionStatusChanged = callback; this.file = file; try { this.digest = MessageDigest.getInstance("SHA-1"); this.digest.reset(); - fileInputStream = this.getInputStream(file); + fileInputStream = this.file.createInputStream(); if (fileInputStream == null) { callback.onFileTransferAborted(); return; } this.sendNextBlock(); - } catch (FileNotFoundException e) { - callback.onFileTransferAborted(); } catch (NoSuchAlgorithmException e) { callback.onFileTransferAborted(); } diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 63f5a507..1da2f0cd 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -10,6 +10,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.utils.CryptoHelper; public class JingleSocks5Transport extends JingleTransport { @@ -29,11 +30,11 @@ public class JingleSocks5Transport extends JingleTransport { StringBuilder destBuilder = new StringBuilder(); destBuilder.append(jingleConnection.getSessionId()); if (candidate.isOurs()) { - destBuilder.append(jingleConnection.getAccountJid()); + destBuilder.append(jingleConnection.getAccount().getFullJid()); destBuilder.append(jingleConnection.getCounterPart()); } else { destBuilder.append(jingleConnection.getCounterPart()); - destBuilder.append(jingleConnection.getAccountJid()); + destBuilder.append(jingleConnection.getAccount().getFullJid()); } mDigest.reset(); this.destination = CryptoHelper.bytesToHex(mDigest @@ -86,7 +87,7 @@ public class JingleSocks5Transport extends JingleTransport { } - public void send(final JingleFile file, + public void send(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) { new Thread(new Runnable() { @@ -96,7 +97,7 @@ public class JingleSocks5Transport extends JingleTransport { try { MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.reset(); - fileInputStream = getInputStream(file); + fileInputStream = file.createInputStream(); if (fileInputStream == null) { callback.onFileTransferAborted(); return; @@ -132,7 +133,7 @@ public class JingleSocks5Transport extends JingleTransport { } - public void receive(final JingleFile file, + public void receive(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) { new Thread(new Runnable() { @@ -145,7 +146,7 @@ public class JingleSocks5Transport extends JingleTransport { socket.setSoTimeout(30000); file.getParentFile().mkdirs(); file.createNewFile(); - OutputStream fileOutputStream = getOutputStream(file); + OutputStream fileOutputStream = file.createOutputStream(); if (fileOutputStream == null) { callback.onFileTransferAborted(); return; diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java b/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java index 07dc8ecc..1374e61c 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java +++ b/src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java @@ -1,88 +1,13 @@ package eu.siacs.conversations.xmpp.jingle; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import javax.crypto.Cipher; -import javax.crypto.CipherOutputStream; -import javax.crypto.CipherInputStream; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.spec.IvParameterSpec; - -import eu.siacs.conversations.Config; - -import android.util.Log; +import eu.siacs.conversations.entities.DownloadableFile; public abstract class JingleTransport { public abstract void connect(final OnTransportConnected callback); - public abstract void receive(final JingleFile file, + public abstract void receive(final DownloadableFile file, final OnFileTransmissionStatusChanged callback); - public abstract void send(final JingleFile file, + public abstract void send(final DownloadableFile file, final OnFileTransmissionStatusChanged callback); - - private byte[] iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xf }; - - protected InputStream getInputStream(JingleFile file) - throws FileNotFoundException { - if (file.getKey() == null) { - return new FileInputStream(file); - } else { - try { - IvParameterSpec ips = new IvParameterSpec(iv); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(Cipher.ENCRYPT_MODE, file.getKey(), ips); - Log.d(Config.LOGTAG, "opening encrypted input stream"); - return new CipherInputStream(new FileInputStream(file), cipher); - } catch (NoSuchAlgorithmException e) { - Log.d(Config.LOGTAG, "no such algo: " + e.getMessage()); - return null; - } catch (NoSuchPaddingException e) { - Log.d(Config.LOGTAG, "no such padding: " + e.getMessage()); - return null; - } catch (InvalidKeyException e) { - Log.d(Config.LOGTAG, "invalid key: " + e.getMessage()); - return null; - } catch (InvalidAlgorithmParameterException e) { - Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage()); - return null; - } - } - } - - protected OutputStream getOutputStream(JingleFile file) - throws FileNotFoundException { - if (file.getKey() == null) { - return new FileOutputStream(file); - } else { - try { - IvParameterSpec ips = new IvParameterSpec(iv); - Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - cipher.init(Cipher.DECRYPT_MODE, file.getKey(), ips); - Log.d(Config.LOGTAG, "opening encrypted output stream"); - return new CipherOutputStream(new FileOutputStream(file), - cipher); - } catch (NoSuchAlgorithmException e) { - Log.d(Config.LOGTAG, "no such algo: " + e.getMessage()); - return null; - } catch (NoSuchPaddingException e) { - Log.d(Config.LOGTAG, "no such padding: " + e.getMessage()); - return null; - } catch (InvalidKeyException e) { - Log.d(Config.LOGTAG, "invalid key: " + e.getMessage()); - return null; - } catch (InvalidAlgorithmParameterException e) { - Log.d(Config.LOGTAG, "invavid iv:" + e.getMessage()); - return null; - } - } - } } diff --git a/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java b/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java index 19fd4d97..e45e7441 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java +++ b/src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java @@ -1,7 +1,9 @@ package eu.siacs.conversations.xmpp.jingle; +import eu.siacs.conversations.entities.DownloadableFile; + public interface OnFileTransmissionStatusChanged { - public void onFileTransmitted(JingleFile file); + public void onFileTransmitted(DownloadableFile file); public void onFileTransferAborted(); } diff --git a/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java b/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java index d19e6dfd..bcadbe77 100644 --- a/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java +++ b/src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java @@ -1,7 +1,7 @@ package eu.siacs.conversations.xmpp.jingle.stanzas; +import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.xml.Element; -import eu.siacs.conversations.xmpp.jingle.JingleFile; public class Content extends Element { @@ -25,7 +25,7 @@ public class Content extends Element { this.transportId = sid; } - public void setFileOffer(JingleFile actualFile, boolean otr) { + public void setFileOffer(DownloadableFile actualFile, boolean otr) { Element description = this.addChild("description", "urn:xmpp:jingle:apps:file-transfer:3"); Element offer = description.addChild("offer"); |