aboutsummaryrefslogtreecommitdiffstats
path: root/src/eu/siacs/conversations/xmpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/eu/siacs/conversations/xmpp/XmppConnection.java114
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java137
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java38
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleFile.java68
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java15
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java13
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleTransport.java81
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/OnFileTransmissionStatusChanged.java4
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/stanzas/Content.java4
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");