aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java50
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java3
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/crypto/axolotl/AxolotlServiceImpl.java5
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java13
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/http/HttpConnectionManager.java39
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/http/HttpDownloadConnection.java5
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/http/HttpUploadConnection.java52
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java2
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/AbstractConnectionManager.java17
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/FileTransferService.java31
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/MessageArchiveService.java3
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java118
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/AbstractFileTransferService.java31
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferEntity.java108
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferManager.java127
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferStatusListener.java11
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpFileTransferEntity.java52
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpFileUploader.java120
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadFileTransferService.java84
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadSlotRequestReceived.java34
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadedFileEncryptionUiCallback.java33
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/filetransfer/jingle/JingleFileTransferService.java51
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java3
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java4
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java5
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/AbstractIqPacketParser.java43
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java17
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/MissingRequiredContentException.java26
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/MissingRequiredElementException.java26
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/UnexpectedIqPacketTypeException.java25
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/XmppException.java56
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUpload.java9
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUploadRequestSlotPacketGenerator.java46
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUploadSlot.java22
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/SlotPacketParser.java27
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/SlotRequestPacket.java53
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java4
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnectionManager.java4
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleSocks5Transport.java5
39 files changed, 1165 insertions, 199 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java b/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java
index a9f0c6ad..26854205 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ConversationsPlusApplication.java
@@ -3,12 +3,20 @@ package de.thedevstack.conversationsplus;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.PowerManager;
import android.preference.PreferenceManager;
import java.io.File;
+import java.security.SecureRandom;
+import de.duenndns.ssl.MemorizingTrustManager;
+import de.thedevstack.conversationsplus.http.HttpConnectionManager;
import de.thedevstack.conversationsplus.persistance.FileBackend;
+import de.thedevstack.conversationsplus.services.filetransfer.FileTransferManager;
+import de.thedevstack.conversationsplus.services.filetransfer.httpupload.HttpUploadFileTransferService;
+import de.thedevstack.conversationsplus.services.filetransfer.jingle.JingleFileTransferService;
import de.thedevstack.conversationsplus.utils.ImageUtil;
+import de.thedevstack.conversationsplus.utils.PRNGFixes;
import de.thedevstack.conversationsplus.utils.SerialSingleThreadExecutor;
/**
@@ -23,6 +31,9 @@ public class ConversationsPlusApplication extends Application {
private final SerialSingleThreadExecutor mFileAddingExecutor = new SerialSingleThreadExecutor();
private final SerialSingleThreadExecutor mDatabaseExecutor = new SerialSingleThreadExecutor();
+ private MemorizingTrustManager memorizingTrustManager;
+ private SecureRandom secureRandom;
+
/**
* Initializes the application and saves its instance.
*/
@@ -30,8 +41,20 @@ public class ConversationsPlusApplication extends Application {
super.onCreate();
ConversationsPlusApplication.instance = this;
ConversationsPlusPreferences.init(PreferenceManager.getDefaultSharedPreferences(getAppContext()));
+ this.initializeSecurity();
ImageUtil.initBitmapCache();
FileBackend.init();
+ FileTransferManager.init(new HttpUploadFileTransferService(), new JingleFileTransferService());
+ HttpConnectionManager.init();
+ }
+
+ /**
+ * Initializes security features.
+ */
+ private void initializeSecurity() {
+ PRNGFixes.apply();
+ this.secureRandom = new SecureRandom();
+ ConversationsPlusApplication.updateMemorizingTrustmanager();
}
/**
@@ -100,4 +123,31 @@ public class ConversationsPlusApplication extends Application {
public static String getNameAndVersion() {
return getName() + " " + getVersion();
}
+
+ public static PowerManager.WakeLock createPartialWakeLock(String name) {
+ PowerManager powerManager = (PowerManager) getAppContext().getSystemService(Context.POWER_SERVICE);
+ return powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
+ }
+
+ public static MemorizingTrustManager getMemorizingTrustManager() {
+ return getInstance().memorizingTrustManager;
+ }
+
+ public void setMemorizingTrustManager(MemorizingTrustManager trustManager) {
+ this.memorizingTrustManager = trustManager;
+ }
+
+ public static void updateMemorizingTrustmanager() {
+ final MemorizingTrustManager tm;
+ if (ConversationsPlusPreferences.dontTrustSystemCAs()) {
+ tm = new MemorizingTrustManager(getAppContext(), null);
+ } else {
+ tm = new MemorizingTrustManager(getAppContext());
+ }
+ getInstance().setMemorizingTrustManager(tm);
+ }
+
+ public static SecureRandom getSecureRandom() {
+ return getInstance().secureRandom;
+ }
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java b/src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java
index bba52954..d0b30d6d 100644
--- a/src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java
+++ b/src/main/java/de/thedevstack/conversationsplus/crypto/PgpEngine.java
@@ -65,12 +65,11 @@ public class PgpEngine {
&& message.getUuid().equals(uuid)) {
message.setBody(os.toString());
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
- final HttpConnectionManager manager = mXmppConnectionService.getHttpConnectionManager();
if (message.trusted()
&& message.treatAsDownloadable() != Message.Decision.NEVER
&& (message.isHttpUploaded() || ConversationsPlusPreferences.autoDownloadFileLink())
&& ConversationsPlusPreferences.autoAcceptFileSize() > 0) {
- manager.createNewDownloadConnection(message);
+ HttpConnectionManager.createNewDownloadConnection(message);
}
mXmppConnectionService.updateMessage(message);
callback.success(message);
diff --git a/src/main/java/de/thedevstack/conversationsplus/crypto/axolotl/AxolotlServiceImpl.java b/src/main/java/de/thedevstack/conversationsplus/crypto/axolotl/AxolotlServiceImpl.java
index 4bc27a7d..5e302011 100644
--- a/src/main/java/de/thedevstack/conversationsplus/crypto/axolotl/AxolotlServiceImpl.java
+++ b/src/main/java/de/thedevstack/conversationsplus/crypto/axolotl/AxolotlServiceImpl.java
@@ -34,6 +34,7 @@ import java.util.Random;
import java.util.Set;
import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.entities.Account;
import de.thedevstack.conversationsplus.entities.Contact;
import de.thedevstack.conversationsplus.entities.Conversation;
@@ -462,7 +463,7 @@ public class AxolotlServiceImpl implements OnAdvancedStreamFeaturesLoaded, Axolo
PrivateKey x509PrivateKey = KeyChain.getPrivateKey(mXmppConnectionService, account.getPrivateKeyAlias());
X509Certificate[] chain = KeyChain.getCertificateChain(mXmppConnectionService, account.getPrivateKeyAlias());
Signature verifier = Signature.getInstance("sha256WithRSA");
- verifier.initSign(x509PrivateKey,mXmppConnectionService.getRNG());
+ verifier.initSign(x509PrivateKey, ConversationsPlusApplication.getSecureRandom());
verifier.update(axolotlPublicKey.serialize());
byte[] signature = verifier.sign();
IqPacket packet = mXmppConnectionService.getIqGenerator().publishVerification(signature, chain, getOwnDeviceId());
@@ -669,7 +670,7 @@ public class AxolotlServiceImpl implements OnAdvancedStreamFeaturesLoaded, Axolo
verifier.update(identityKey.serialize());
if (verifier.verify(verification.second)) {
try {
- mXmppConnectionService.getMemorizingTrustManager().getNonInteractive().checkClientTrusted(verification.first, "RSA");
+ ConversationsPlusApplication.getMemorizingTrustManager().getNonInteractive().checkClientTrusted(verification.first, "RSA");
String fingerprint = session.getFingerprint();
Log.d(Config.LOGTAG, "verified session with x.509 signature. fingerprint was: "+fingerprint);
setFingerprintTrust(fingerprint, XmppAxolotlSession.Trust.TRUSTED_X509);
diff --git a/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java b/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java
index 9df0cc21..2d4c8f6a 100644
--- a/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java
+++ b/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java
@@ -20,7 +20,6 @@ import de.thedevstack.conversationsplus.Config;
import de.thedevstack.conversationsplus.crypto.axolotl.AxolotlService;
import de.thedevstack.conversationsplus.entities.Account;
import de.thedevstack.conversationsplus.entities.Conversation;
-import de.thedevstack.conversationsplus.entities.DownloadableFile;
import de.thedevstack.conversationsplus.services.MessageArchiveService;
import de.thedevstack.conversationsplus.utils.Xmlns;
import de.thedevstack.conversationsplus.xml.Element;
@@ -244,18 +243,6 @@ public class IqGenerator extends AbstractGenerator {
return packet;
}
- public IqPacket requestHttpUploadSlot(Jid host, DownloadableFile file, String mime) {
- IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
- packet.setTo(host);
- Element request = packet.addChild("request", Xmlns.HTTP_UPLOAD);
- request.addChild("filename").setContent(file.getName());
- request.addChild("size").setContent(String.valueOf(file.getExpectedSize()));
- if (mime != null) {
- request.addChild("content-type").setContent(mime);
- }
- return packet;
- }
-
public IqPacket generateCreateAccountWithCaptcha(Account account, String id, Data data) {
final IqPacket register = new IqPacket(IqPacket.TYPE.SET);
diff --git a/src/main/java/de/thedevstack/conversationsplus/http/HttpConnectionManager.java b/src/main/java/de/thedevstack/conversationsplus/http/HttpConnectionManager.java
index 59c54662..529d12c4 100644
--- a/src/main/java/de/thedevstack/conversationsplus/http/HttpConnectionManager.java
+++ b/src/main/java/de/thedevstack/conversationsplus/http/HttpConnectionManager.java
@@ -17,6 +17,7 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.X509TrustManager;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.entities.Message;
import de.thedevstack.conversationsplus.services.AbstractConnectionManager;
import de.thedevstack.conversationsplus.services.XmppConnectionService;
@@ -24,29 +25,23 @@ import de.thedevstack.conversationsplus.utils.CryptoHelper;
import de.thedevstack.conversationsplus.utils.SSLSocketHelper;
public class HttpConnectionManager extends AbstractConnectionManager {
+ private static HttpConnectionManager INSTANCE;
- public HttpConnectionManager(XmppConnectionService service) {
- super(service);
- }
+ public static void init() {
+ INSTANCE = new HttpConnectionManager();
+ }
private List<HttpDownloadConnection> downloadConnections = new CopyOnWriteArrayList<>();
private List<HttpUploadConnection> uploadConnections = new CopyOnWriteArrayList<>();
- public HttpDownloadConnection createNewDownloadConnection(Message message) {
- return this.createNewDownloadConnection(message, false);
+ public static HttpDownloadConnection createNewDownloadConnection(Message message) {
+ return createNewDownloadConnection(message, false);
}
- public HttpDownloadConnection createNewDownloadConnection(Message message, boolean interactive) {
- HttpDownloadConnection connection = new HttpDownloadConnection(this);
+ public static HttpDownloadConnection createNewDownloadConnection(Message message, boolean interactive) {
+ HttpDownloadConnection connection = new HttpDownloadConnection(INSTANCE);
connection.init(message,interactive);
- this.downloadConnections.add(connection);
- return connection;
- }
-
- public HttpUploadConnection createNewUploadConnection(Message message, boolean delay) {
- HttpUploadConnection connection = new HttpUploadConnection(this);
- connection.init(message,delay);
- this.uploadConnections.add(connection);
+ INSTANCE.downloadConnections.add(connection);
return connection;
}
@@ -58,26 +53,24 @@ public class HttpConnectionManager extends AbstractConnectionManager {
this.uploadConnections.remove(httpUploadConnection);
}
- public void setupTrustManager(final HttpsURLConnection connection, final boolean interactive) {
+ public static void setupTrustManager(final HttpsURLConnection connection, final boolean interactive) {
final X509TrustManager trustManager;
final HostnameVerifier hostnameVerifier;
if (interactive) {
- trustManager = mXmppConnectionService.getMemorizingTrustManager();
- hostnameVerifier = mXmppConnectionService
- .getMemorizingTrustManager().wrapHostnameVerifier(
+ trustManager = ConversationsPlusApplication.getMemorizingTrustManager();
+ hostnameVerifier = ConversationsPlusApplication.getMemorizingTrustManager().wrapHostnameVerifier(
new StrictHostnameVerifier());
} else {
- trustManager = mXmppConnectionService.getMemorizingTrustManager()
+ trustManager = ConversationsPlusApplication.getMemorizingTrustManager()
.getNonInteractive();
- hostnameVerifier = mXmppConnectionService
- .getMemorizingTrustManager()
+ hostnameVerifier = ConversationsPlusApplication.getMemorizingTrustManager()
.wrapHostnameVerifierNonInteractive(
new StrictHostnameVerifier());
}
try {
final SSLContext sc = SSLSocketHelper.getSSLContext();
sc.init(null, new X509TrustManager[]{trustManager},
- mXmppConnectionService.getRNG());
+ ConversationsPlusApplication.getSecureRandom());
final SSLSocketFactory sf = sc.getSocketFactory();
final String[] cipherSuites = CryptoHelper.getOrderedCipherSuites(
diff --git a/src/main/java/de/thedevstack/conversationsplus/http/HttpDownloadConnection.java b/src/main/java/de/thedevstack/conversationsplus/http/HttpDownloadConnection.java
index 424dc96a..3facc14a 100644
--- a/src/main/java/de/thedevstack/conversationsplus/http/HttpDownloadConnection.java
+++ b/src/main/java/de/thedevstack/conversationsplus/http/HttpDownloadConnection.java
@@ -32,6 +32,7 @@ import de.thedevstack.conversationsplus.services.AbstractConnectionManager;
import de.thedevstack.conversationsplus.services.XmppConnectionService;
import de.thedevstack.conversationsplus.utils.CryptoHelper;
import de.thedevstack.conversationsplus.utils.FileUtils;
+import de.thedevstack.conversationsplus.utils.XmppConnectionServiceAccessor;
public class HttpDownloadConnection implements Transferable {
@@ -48,7 +49,7 @@ public class HttpDownloadConnection implements Transferable {
public HttpDownloadConnection(HttpConnectionManager manager) {
this.mHttpConnectionManager = manager;
- this.mXmppConnectionService = manager.getXmppConnectionService();
+ this.mXmppConnectionService = XmppConnectionServiceAccessor.xmppConnectionService;
}
@Override
@@ -265,7 +266,7 @@ public class HttpDownloadConnection implements Transferable {
private void download() throws SSLHandshakeException, IOException {
InputStream is = null;
- PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_download_"+message.getUuid());
+ PowerManager.WakeLock wakeLock = ConversationsPlusApplication.createPartialWakeLock("http_download_"+message.getUuid());
try {
wakeLock.acquire();
HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
diff --git a/src/main/java/de/thedevstack/conversationsplus/http/HttpUploadConnection.java b/src/main/java/de/thedevstack/conversationsplus/http/HttpUploadConnection.java
index 231a6ca7..7c791e70 100644
--- a/src/main/java/de/thedevstack/conversationsplus/http/HttpUploadConnection.java
+++ b/src/main/java/de/thedevstack/conversationsplus/http/HttpUploadConnection.java
@@ -30,11 +30,21 @@ import de.thedevstack.conversationsplus.services.XmppConnectionService;
import de.thedevstack.conversationsplus.ui.UiCallback;
import de.thedevstack.conversationsplus.utils.CryptoHelper;
import de.thedevstack.conversationsplus.utils.Xmlns;
+import de.thedevstack.conversationsplus.utils.XmppConnectionServiceAccessor;
import de.thedevstack.conversationsplus.xml.Element;
import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived;
+import de.thedevstack.conversationsplus.xmpp.exceptions.MissingRequiredContentException;
+import de.thedevstack.conversationsplus.xmpp.exceptions.MissingRequiredElementException;
+import de.thedevstack.conversationsplus.xmpp.exceptions.XmppException;
+import de.thedevstack.conversationsplus.xmpp.httpupload.HttpUpload;
+import de.thedevstack.conversationsplus.xmpp.httpupload.HttpUploadRequestSlotPacketGenerator;
+import de.thedevstack.conversationsplus.xmpp.httpupload.HttpUploadSlot;
+import de.thedevstack.conversationsplus.xmpp.httpupload.SlotPacketParser;
+import de.thedevstack.conversationsplus.xmpp.httpupload.SlotRequestPacket;
import de.thedevstack.conversationsplus.xmpp.jid.Jid;
import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+@Deprecated
public class HttpUploadConnection implements Transferable {
private HttpConnectionManager mHttpConnectionManager;
@@ -57,7 +67,7 @@ public class HttpUploadConnection implements Transferable {
public HttpUploadConnection(HttpConnectionManager httpConnectionManager) {
this.mHttpConnectionManager = httpConnectionManager;
- this.mXmppConnectionService = httpConnectionManager.getXmppConnectionService();
+ this.mXmppConnectionService = XmppConnectionServiceAccessor.xmppConnectionService;
}
@Override
@@ -107,7 +117,7 @@ public class HttpUploadConnection implements Transferable {
|| message.getEncryption() == Message.ENCRYPTION_AXOLOTL
|| message.getEncryption() == Message.ENCRYPTION_OTR) {
this.key = new byte[48];
- mXmppConnectionService.getRNG().nextBytes(this.key);
+ ConversationsPlusApplication.getSecureRandom().nextBytes(this.key);
this.file.setKeyAndIv(this.key);
}
Pair<InputStream,Integer> pair;
@@ -119,29 +129,25 @@ public class HttpUploadConnection implements Transferable {
}
this.file.setExpectedSize(pair.second);
this.mFileInputStream = pair.first;
- Jid host = account.getXmppConnection().findDiscoItemByFeature(Xmlns.HTTP_UPLOAD);
- IqPacket request = mXmppConnectionService.getIqGenerator().requestHttpUploadSlot(host,file,mime);
+ Jid host = account.getXmppConnection().findDiscoItemByFeature(HttpUpload.NAMESPACE);
+ IqPacket request = HttpUploadRequestSlotPacketGenerator.generate(host, file.getName(), file.getSize(), mime);
mXmppConnectionService.sendIqPacket(account, request, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.getType() == IqPacket.TYPE.RESULT) {
- Element slot = packet.findChild("slot",Xmlns.HTTP_UPLOAD);
- if (slot != null) {
- try {
- mGetUrl = new URL(slot.findChildContent("get"));
- mPutUrl = new URL(slot.findChildContent("put"));
- if (!canceled) {
- new Thread(new FileUploader()).start();
- }
- } catch (MalformedURLException e) {
- fail();
- }
- } else {
- fail();
- }
- } else {
- fail();
- }
+ try {
+ HttpUploadSlot slot = SlotPacketParser.parseGetAndPutUrl(packet);
+ mGetUrl = new URL(slot.getGetUrl());
+ mPutUrl = new URL(slot.getPutUrl());
+ if (!canceled) {
+ new Thread(new FileUploader()).start();
+ }
+ } catch (XmppException e) {
+ Logging.e("httpupload", e.getMessage());
+ fail();
+ } catch (MalformedURLException e) {
+ Logging.e("httpupload", "malformed url retrieved from slot", e);
+ fail();
+ }
}
});
message.setTransferable(this);
@@ -159,7 +165,7 @@ public class HttpUploadConnection implements Transferable {
OutputStream os = null;
InputStream errorStream = null;
HttpURLConnection connection = null;
- PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_upload_"+message.getUuid());
+ PowerManager.WakeLock wakeLock = ConversationsPlusApplication.createPartialWakeLock("http_upload_"+message.getUuid());
try {
wakeLock.acquire();
Logging.d(Config.LOGTAG, "uploading to " + mPutUrl.toString());
diff --git a/src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java b/src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java
index a8e5929b..2f1701df 100644
--- a/src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java
+++ b/src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java
@@ -472,7 +472,7 @@ public class MessageParser extends AbstractParser implements
&& message.treatAsDownloadable() != Message.Decision.NEVER
&& ConversationsPlusPreferences.autoAcceptFileSize() > 0
&& (message.isHttpUploaded() || ConversationsPlusPreferences.autoDownloadFileLink())) {
- this.mXmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message);
+ HttpConnectionManager.createNewDownloadConnection(message);
} else {
if (query == null) {
mXmppConnectionService.getNotificationService().push(message);
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/AbstractConnectionManager.java b/src/main/java/de/thedevstack/conversationsplus/services/AbstractConnectionManager.java
index 7c937475..5456430a 100644
--- a/src/main/java/de/thedevstack/conversationsplus/services/AbstractConnectionManager.java
+++ b/src/main/java/de/thedevstack/conversationsplus/services/AbstractConnectionManager.java
@@ -31,22 +31,14 @@ import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.entities.DownloadableFile;
public class AbstractConnectionManager {
- protected XmppConnectionService mXmppConnectionService;
-
- public AbstractConnectionManager(XmppConnectionService service) {
- this.mXmppConnectionService = service;
- }
-
- public XmppConnectionService getXmppConnectionService() {
- return this.mXmppConnectionService;
- }
public boolean hasStoragePermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- return mXmppConnectionService.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
+ return ConversationsPlusApplication.getAppContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
} else {
return true;
}
@@ -125,9 +117,4 @@ public class AbstractConnectionManager {
return null;
}
}
-
- public PowerManager.WakeLock createWakeLock(String name) {
- PowerManager powerManager = (PowerManager) mXmppConnectionService.getSystemService(Context.POWER_SERVICE);
- return powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,name);
- }
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/FileTransferService.java b/src/main/java/de/thedevstack/conversationsplus/services/FileTransferService.java
new file mode 100644
index 00000000..d6ce4769
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/FileTransferService.java
@@ -0,0 +1,31 @@
+package de.thedevstack.conversationsplus.services;
+
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.entities.Transferable;
+
+/**
+ *
+ */
+public interface FileTransferService {
+ /**
+ * Transfers a file for the corresponding message.
+ * @param message the message containing the file to transfer
+ * @return <code>true</code> if the file transfer was successful, <code>false</code> otherwise
+ */
+ boolean transferFile(Message message);
+ /**
+ * Transfers a file for the corresponding message.
+ * @param message the message containing the file to transfer
+ * @param delay whether the message is delayed or not
+ * @return <code>true</code> if the file transfer was successful, <code>false</code> otherwise
+ */
+ boolean transferFile(Message message, boolean delay);
+
+ /**
+ * Checks whether a message can be sent using this service or not.
+ * @param message the message to be checked
+ * @return <code>true</code> if the message can be processed, <code>false</code> otherwise
+ */
+ boolean accept(Message message);
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/MessageArchiveService.java b/src/main/java/de/thedevstack/conversationsplus/services/MessageArchiveService.java
index cd55b42f..6402f4ed 100644
--- a/src/main/java/de/thedevstack/conversationsplus/services/MessageArchiveService.java
+++ b/src/main/java/de/thedevstack/conversationsplus/services/MessageArchiveService.java
@@ -10,6 +10,7 @@ import java.util.List;
import de.thedevstack.android.logcat.Logging;
import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.R;
import de.thedevstack.conversationsplus.entities.Account;
import de.thedevstack.conversationsplus.entities.Conversation;
@@ -290,7 +291,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded {
this.account = account;
this.start = start;
this.end = end;
- this.queryId = new BigInteger(50, mXmppConnectionService.getRNG()).toString(32);
+ this.queryId = new BigInteger(50, ConversationsPlusApplication.getSecureRandom()).toString(32);
}
private Query page(String reference) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java b/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java
index 9c0e55db..83cefc80 100644
--- a/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java
+++ b/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java
@@ -12,7 +12,6 @@ import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -58,8 +57,7 @@ import de.duenndns.ssl.MemorizingTrustManager;
import de.thedevstack.android.logcat.Logging;
import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
-import de.thedevstack.conversationsplus.exceptions.FileCopyException;
-import de.thedevstack.conversationsplus.utils.FileUtils;
+import de.thedevstack.conversationsplus.services.filetransfer.FileTransferManager;
import de.thedevstack.conversationsplus.utils.ImageUtil;
import de.thedevstack.conversationsplus.utils.MessageUtil;
import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
@@ -97,7 +95,6 @@ import de.thedevstack.conversationsplus.ui.UiCallback;
import de.thedevstack.conversationsplus.utils.CryptoHelper;
import de.thedevstack.conversationsplus.utils.ExceptionHelper;
import de.thedevstack.conversationsplus.utils.OnPhoneContactsLoadedListener;
-import de.thedevstack.conversationsplus.utils.PRNGFixes;
import de.thedevstack.conversationsplus.utils.PhoneHelper;
import de.thedevstack.conversationsplus.utils.Xmlns;
import de.thedevstack.conversationsplus.xml.Element;
@@ -148,7 +145,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
startService(intent);
}
};
- private MemorizingTrustManager mMemorizingTrustManager;
private NotificationService mNotificationService = new NotificationService(
this);
private OnMessagePacketReceived mMessageParser = new MessageParser(this);
@@ -169,8 +165,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
private MessageGenerator mMessageGenerator = new MessageGenerator();
private PresenceGenerator mPresenceGenerator = new PresenceGenerator();
private List<Account> accounts;
- private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
- this);
+ private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager();
public OnContactStatusChanged onContactStatusChanged = new OnContactStatusChanged() {
@Override
@@ -197,8 +192,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
};
- private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(
- this);
private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
private PushManagementService mPushManagementService = new PushManagementService(this);
private OnConversationUpdate mOnConversationUpdate = null;
@@ -239,7 +232,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
private int mucRosterChangedListenerCount = 0;
private OnKeyStatusUpdated mOnKeyStatusUpdated = null;
private int keyStatusUpdatedListenerCount = 0;
- private SecureRandom mRandom;
private LruCache<Pair<String,String>,ServiceDiscoveryResult> discoCache = new LruCache<>(20);
private final OnBindListener mOnBindListener = new OnBindListener() {
@@ -311,7 +303,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
&& checkListeners();
Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": push mode "+Boolean.toString(pushMode));
if (!disabled && !pushMode) {
- int timeToReconnect = mRandom.nextInt(20) + 10;
+ int timeToReconnect = ConversationsPlusApplication.getSecureRandom().nextInt(20) + 10;
scheduleWakeUpCall(timeToReconnect, account.getUuid().hashCode());
}
} else if (account.getStatus() == Account.State.REGISTRATION_SUCCESSFUL) {
@@ -334,8 +326,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
private OpenPgpServiceConnection pgpServiceConnection;
private PgpEngine mPgpEngine = null;
private WakeLock wakeLock;
- private PowerManager pm;
- private LruCache<String, Bitmap> mBitmapCache;
private Thread mPhoneContactMergerThread;
private EventReceiver mEventReceiver = new EventReceiver();
@@ -577,17 +567,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
@Override
public void onCreate() {
ExceptionHelper.init(getApplicationContext());
- PRNGFixes.apply();
- this.mRandom = new SecureRandom();
- updateMemorizingTrustmanager();
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 8;
- this.mBitmapCache = new LruCache<String, Bitmap>(cacheSize) {
- @Override
- protected int sizeOf(final String key, final Bitmap bitmap) {
- return bitmap.getByteCount() / 1024;
- }
- };
this.databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
this.accounts = databaseBackend.getAccounts();
@@ -614,8 +595,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
this.pgpServiceConnection.bindToService();
}
- this.pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "XmppConnectionService");
+ this.wakeLock = ConversationsPlusApplication.createPartialWakeLock("XmppConnectionService");
toggleForegroundService();
updateUnreadCountBadge();
UiUpdateHelper.initXmppConnectionService(this);
@@ -628,7 +608,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
super.onTrimMemory(level);
if (level >= TRIM_MEMORY_COMPLETE) {
Log.d(Config.LOGTAG, "clear cache due to low memory");
- getBitmapCache().evictAll();
+ ImageUtil.evictBitmapCache();
}
}
@@ -739,16 +719,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
- private void sendFileMessage(final Message message, final boolean delay) {
- Logging.d(Config.LOGTAG, "send file message");
- final Account account = message.getConversation().getAccount();
- if (account.httpUploadAvailable(FileBackend.getFile(message,false).getSize())) {
- mHttpConnectionManager.createNewUploadConnection(message, delay);
- } else {
- mJingleConnectionManager.createNewConnection(message);
- }
- }
-
public void sendMessage(final Message message) {
sendMessage(message, false, false);
}
@@ -776,28 +746,23 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
if (account.isOnlineAndConnected()) {
+ FileTransferManager fileTransferManager = FileTransferManager.getInstance();
switch (message.getEncryption()) {
case Message.ENCRYPTION_NONE:
- if (message.needsUploading()) {
- if (account.httpUploadAvailable(FileBackend.getFile(message,false).getSize())
- || message.fixCounterpart()) {
- this.sendFileMessage(message, delay);
- } else {
- break;
- }
+ if (fileTransferManager.accept(message)) {
+ if (!fileTransferManager.transferFile(message, delay)) {
+ break;
+ }
} else {
packet = mMessageGenerator.generateChat(message);
}
break;
case Message.ENCRYPTION_PGP:
case Message.ENCRYPTION_DECRYPTED:
- if (message.needsUploading()) {
- if (account.httpUploadAvailable(FileBackend.getFile(message,false).getSize())
- || message.fixCounterpart()) {
- this.sendFileMessage(message, delay);
- } else {
- break;
- }
+ if (fileTransferManager.accept(message)) {
+ if (!fileTransferManager.transferFile(message, delay)) {
+ break;
+ }
} else {
packet = mMessageGenerator.generatePgpChat(message);
}
@@ -810,7 +775,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} catch (InvalidJidException e) {
break;
}
- if (message.needsUploading()) {
+ if (message.needsUploading()) { //TODO: Use FileTransferManager with a preselection of filetransfer method
mJingleConnectionManager.createNewConnection(message);
} else {
packet = mMessageGenerator.generateOtrChat(message);
@@ -828,13 +793,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
break;
case Message.ENCRYPTION_AXOLOTL:
message.setFingerprint(account.getAxolotlService().getOwnFingerprint());
- if (message.needsUploading()) {
- if (account.httpUploadAvailable(FileBackend.getFile(message,false).getSize())
- || message.fixCounterpart()) {
- this.sendFileMessage(message, delay);
- } else {
- break;
- }
+ if (fileTransferManager.accept(message)) {
+ if (!fileTransferManager.transferFile(message, delay)) {
+ break;
+ }
} else {
XmppAxolotlMessage axolotlMessage = account.getAxolotlService().fetchAxolotlMessageFromCache(message);
if (axolotlMessage == null) {
@@ -1331,7 +1293,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
callback.onAccountCreated(account);
if (Config.X509_VERIFICATION) {
try {
- getMemorizingTrustManager().getNonInteractive().checkClientTrusted(chain, "RSA");
+ ConversationsPlusApplication.getMemorizingTrustManager().getNonInteractive().checkClientTrusted(chain, "RSA");
} catch (CertificateException e) {
callback.informUser(R.string.certificate_chain_is_not_trusted);
}
@@ -1359,7 +1321,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
databaseBackend.updateAccount(account);
if (Config.X509_VERIFICATION) {
try {
- getMemorizingTrustManager().getNonInteractive().checkClientTrusted(chain, "RSA");
+ ConversationsPlusApplication.getMemorizingTrustManager().getNonInteractive().checkClientTrusted(chain, "RSA");
} catch (CertificateException e) {
showErrorToastInUi(R.string.certificate_chain_is_not_trusted);
}
@@ -1901,7 +1863,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
return;
}
- String name = new BigInteger(75, getRNG()).toString(32);
+ String name = new BigInteger(75, ConversationsPlusApplication.getSecureRandom()).toString(32);
Jid jid = Jid.fromParts(name, server, null);
final Conversation conversation = findOrCreateConversation(account, jid, true);
joinMuc(conversation, new OnConferenceJoined() {
@@ -2170,7 +2132,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public boolean renewSymmetricKey(Conversation conversation) {
Account account = conversation.getAccount();
byte[] symmetricKey = new byte[32];
- this.mRandom.nextBytes(symmetricKey);
+ ConversationsPlusApplication.getSecureRandom().nextBytes(symmetricKey);
Session otrSession = conversation.getOtrSession();
if (otrSession != null) {
MessagePacket packet = new MessagePacket();
@@ -2440,36 +2402,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
- public SecureRandom getRNG() {
- return this.mRandom;
- }
-
- public MemorizingTrustManager getMemorizingTrustManager() {
- return this.mMemorizingTrustManager;
- }
-
- public void setMemorizingTrustManager(MemorizingTrustManager trustManager) {
- this.mMemorizingTrustManager = trustManager;
- }
-
- public void updateMemorizingTrustmanager() {
- final MemorizingTrustManager tm;
- if (ConversationsPlusPreferences.dontTrustSystemCAs()) {
- tm = new MemorizingTrustManager(getApplicationContext(), null);
- } else {
- tm = new MemorizingTrustManager(getApplicationContext());
- }
- setMemorizingTrustManager(tm);
- }
-
- public PowerManager getPowerManager() {
- return this.pm;
- }
-
- public LruCache<String, Bitmap> getBitmapCache() {
- return this.mBitmapCache;
- }
-
public void syncRosterToDisk(final Account account) {
Runnable runnable = new Runnable() {
@@ -2599,10 +2531,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
return this.mNotificationService;
}
- public HttpConnectionManager getHttpConnectionManager() {
- return this.mHttpConnectionManager;
- }
-
public void resendFailedMessages(final Message message) {
if (message.getStatus() == Message.STATUS_SEND_FAILED) {
message.setTime(System.currentTimeMillis());
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/AbstractFileTransferService.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/AbstractFileTransferService.java
new file mode 100644
index 00000000..02bd04b9
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/AbstractFileTransferService.java
@@ -0,0 +1,31 @@
+package de.thedevstack.conversationsplus.services.filetransfer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.services.FileTransferService;
+
+/**
+ *
+ */
+public abstract class AbstractFileTransferService implements FileTransferService, FileTransferStatusListener {
+ protected List<Message> failedMessages = new ArrayList<>();
+
+ @Override
+ public void onFailure(Message message, boolean delay) {
+ this.failedMessages.add(message);
+ }
+
+ @Override
+ public void onSuccess(Message message, boolean delay) {
+ if (this.failedMessages.contains(message)) {
+ this.failedMessages.remove(message);
+ }
+ }
+
+ @Override
+ public boolean accept(Message message) {
+ return !this.failedMessages.contains(message);
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferEntity.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferEntity.java
new file mode 100644
index 00000000..a44cf49d
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferEntity.java
@@ -0,0 +1,108 @@
+package de.thedevstack.conversationsplus.services.filetransfer;
+
+import java.io.InputStream;
+
+import de.thedevstack.conversationsplus.entities.DownloadableFile;
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.entities.Transferable;
+import de.thedevstack.conversationsplus.persistance.FileBackend;
+import de.thedevstack.conversationsplus.utils.MessageUtil;
+
+/**
+ *
+ */
+public class FileTransferEntity implements Transferable {
+ private final Message message;
+ private int tries = 0;
+ private boolean transferred = false;
+ private boolean canceled = false;
+ private boolean failed = false;
+ private long transmitted = 0;
+ private DownloadableFile file;
+ private InputStream fileInputStream;
+
+ public FileTransferEntity(Message message) {
+ this.message = message;
+ this.message.setTransferable(this);
+ this.file = FileBackend.getFile(message, false);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ FileTransferEntity other = (FileTransferEntity)o;
+ if ((this.message == null && other.message != null)
+ || (this.message != null && other.message == null)) {
+ return false;
+ } else if (this.message == null && other.message == null) {
+ return true;
+ }
+ return this.message.getUuid().equals(other.message.getUuid());
+ }
+
+ @Override
+ public boolean start() {
+ return false;
+ }
+
+ @Override
+ public int getStatus() {
+ int status = (failed) ? STATUS_FAILED : STATUS_UPLOADING;
+ return status;
+ }
+
+ @Override
+ public long getFileSize() {
+ return file == null ? 0 : file.getExpectedSize();
+ }
+
+ @Override
+ public int getProgress() {
+ if (file == null) {
+ return 0;
+ }
+ return (int) ((((double) transmitted) / file.getExpectedSize()) * 100);
+ }
+
+ @Override
+ public void cancel() {
+ this.canceled = true;
+ }
+
+ public void fail() {
+ this.failed = true;
+ this.getMessage().setTransferable(null);
+ MessageUtil.markMessage(this.getMessage(), Message.STATUS_SEND_FAILED);
+ }
+
+ public Message getMessage() {
+ return message;
+ }
+
+ public boolean isCanceled() {
+ return this.canceled;
+ }
+
+ public boolean isFailed() {
+ return failed;
+ }
+
+ public void updateProgress(long progress) {
+ this.transmitted += progress;
+ }
+
+ public DownloadableFile getFile() {
+ return file;
+ }
+
+ public void transferred() {
+ this.transferred = true;
+ }
+
+ public void setFileInputStream(InputStream fileInputStream) {
+ this.fileInputStream = fileInputStream;
+ }
+
+ public InputStream getFileInputStream() {
+ return fileInputStream;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferManager.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferManager.java
new file mode 100644
index 00000000..f7b3f4e2
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferManager.java
@@ -0,0 +1,127 @@
+package de.thedevstack.conversationsplus.services.filetransfer;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.services.FileTransferService;
+
+/**
+ *
+ */
+public class FileTransferManager implements FileTransferService {
+ private SortedSet<WeightedTransferService> transferServices;
+ private static final FileTransferManager INSTANCE = new FileTransferManager();
+
+ private FileTransferManager() {
+ this.transferServices = new TreeSet<>();
+ }
+
+ public static FileTransferManager getInstance() {
+ return INSTANCE;
+ }
+
+ public static void init(FileTransferService... fileTransferServices) {
+ if (null != fileTransferServices && fileTransferServices.length > 0) {
+ for (FileTransferService fts : fileTransferServices) {
+ addFileTransferService(fts);
+ }
+ }
+ }
+
+ public static void init(HashMap<Integer, FileTransferService> fileTransferServices) {
+ for (Map.Entry<Integer, FileTransferService> entry : fileTransferServices.entrySet()) {
+ addFileTransferService(entry.getKey(), entry.getValue());
+ }
+ }
+
+ public static void addFileTransferService(int weight, FileTransferService fts) {
+ INSTANCE.transferServices.add(new WeightedTransferService(weight, fts));
+ }
+
+ public static void addFileTransferService(FileTransferService fts) {
+ int weight = 1;
+ if (!INSTANCE.transferServices.isEmpty()) {
+ weight = INSTANCE.transferServices.last().weight + 1;
+ }
+ addFileTransferService(weight, fts);
+ }
+
+ /**
+ * Transfers a file for the corresponding message.
+ *
+ * @param message the message containing the file to transfer
+ * @return <code>true</code> if the file transfer was successful, <code>false</code> otherwise
+ */
+ public boolean transferFile(Message message) {
+ return this.transferFile(message, false);
+ }
+
+ /**
+ * Transfers a file for the corresponding message.
+ *
+ * @param message the message containing the file to transfer
+ * @param delay whether the message is delayed or not
+ * @return <code>true</code> if the file transfer was successful, <code>false</code> otherwise
+ */
+ @Override
+ public boolean transferFile(Message message, boolean delay) {
+ Logging.d(Config.LOGTAG, "send file message");
+ boolean transferSuccessfullyStarted = false;
+ for (WeightedTransferService wts : this.transferServices) {
+ try {
+ if (wts.fileTransferService.accept(message)) {
+ transferSuccessfullyStarted = wts.fileTransferService.transferFile(message, delay);
+ if (transferSuccessfullyStarted) {
+ break;
+ }
+ }
+ } catch (Exception e) {
+ //TODO Do real exception handling!!!!!
+ }
+ }
+ return transferSuccessfullyStarted;
+ }
+
+ /**
+ * Checks whether a message can be sent using this service or not.
+ *
+ * @param message the message to be checked
+ * @return <code>true</code> if the message can be processed, <code>false</code> otherwise
+ */
+ @Override
+ public boolean accept(Message message) {
+ return message.needsUploading();
+ }
+
+ static class WeightedTransferService implements Comparable<WeightedTransferService> {
+ int weight;
+ FileTransferService fileTransferService;
+
+ WeightedTransferService(int weight, FileTransferService service) {
+ this.weight = weight;
+ this.fileTransferService = service;
+ }
+
+ /**
+ * Compares this object to the specified object to determine their relative
+ * order.
+ *
+ * @param another the object to compare to this instance.
+ * @return a negative integer if this instance is less than {@code another};
+ * a positive integer if this instance is greater than
+ * {@code another}; 0 if this instance has the same order as
+ * {@code another}.
+ * @throws ClassCastException if {@code another} cannot be converted into something
+ * comparable to {@code this} instance.
+ */
+ @Override
+ public int compareTo(WeightedTransferService another) {
+ return this.weight - another.weight;
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferStatusListener.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferStatusListener.java
new file mode 100644
index 00000000..89af5b39
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/FileTransferStatusListener.java
@@ -0,0 +1,11 @@
+package de.thedevstack.conversationsplus.services.filetransfer;
+
+import de.thedevstack.conversationsplus.entities.Message;
+
+/**
+ *
+ */
+public interface FileTransferStatusListener {
+ void onFailure(Message message, boolean delay);
+ void onSuccess(Message message, boolean delay);
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpFileTransferEntity.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpFileTransferEntity.java
new file mode 100644
index 00000000..8efd498b
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpFileTransferEntity.java
@@ -0,0 +1,52 @@
+package de.thedevstack.conversationsplus.services.filetransfer.httpupload;
+
+import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.services.filetransfer.FileTransferEntity;
+import de.thedevstack.conversationsplus.xmpp.httpupload.HttpUploadSlot;
+
+/**
+ *
+ */
+public class HttpFileTransferEntity extends FileTransferEntity {
+ private HttpUploadSlot slot;
+ private final byte[] key;
+ private final boolean delayed;
+
+ public HttpFileTransferEntity(Message message, boolean delayed) {
+ super(message);
+ this.getMessage().setHttpUploaded(true);
+ this.getMessage().setNoDownloadable();
+ if (Config.ENCRYPT_ON_HTTP_UPLOADED
+ || message.getEncryption() == Message.ENCRYPTION_AXOLOTL
+ || message.getEncryption() == Message.ENCRYPTION_OTR) {
+ this.key = new byte[48];
+ ConversationsPlusApplication.getSecureRandom().nextBytes(this.key);
+ this.getFile().setKeyAndIv(this.key);
+ } else {
+ this.key = null;
+ }
+ this.delayed = delayed;
+ }
+
+ public void setSlot(HttpUploadSlot slot) {
+ this.slot = slot;
+ }
+
+ public String getGetUrl() {
+ return this.slot.getGetUrl();
+ }
+
+ public String getPutUrl() {
+ return this.slot.getPutUrl();
+ }
+
+ public byte[] getKey() {
+ return key;
+ }
+
+ public boolean isDelayed() {
+ return this.delayed;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpFileUploader.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpFileUploader.java
new file mode 100644
index 00000000..6352c7a7
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpFileUploader.java
@@ -0,0 +1,120 @@
+package de.thedevstack.conversationsplus.services.filetransfer.httpupload;
+
+import android.os.PowerManager;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Scanner;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.entities.DownloadableFile;
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.http.HttpConnectionManager;
+import de.thedevstack.conversationsplus.persistance.FileBackend;
+import de.thedevstack.conversationsplus.utils.CryptoHelper;
+import de.thedevstack.conversationsplus.utils.MessageUtil;
+import de.thedevstack.conversationsplus.utils.StreamUtil;
+import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
+import de.thedevstack.conversationsplus.utils.XmppConnectionServiceAccessor;
+import de.thedevstack.conversationsplus.xmpp.httpupload.HttpUpload;
+
+public class HttpFileUploader implements Runnable {
+ private static final String HTTP_METHOD = "PUT";
+ private static final String MIME_REQUEST_PROPERTY_NAME = "Content-Type";
+ private static final String USER_AGENT_REQUEST_PROPERTY_NAME = "User-Agent";
+ private static final int BUFFER_LENGTH = 4096;
+ private final HttpFileTransferEntity entity;
+
+ public HttpFileUploader(HttpFileTransferEntity entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public void run() {
+ this.upload();
+ }
+
+ private void upload() {
+ OutputStream os = null;
+ InputStream errorStream = null;
+ HttpURLConnection connection = null;
+ InputStream fileInputStream = null;
+ DownloadableFile file = this.entity.getFile();
+ PowerManager.WakeLock wakeLock = ConversationsPlusApplication.createPartialWakeLock("http_upload_" + entity.getMessage().getUuid());
+ try {
+ wakeLock.acquire();
+ Logging.d(Config.LOGTAG, "uploading to " + this.entity.getPutUrl());
+ URL putUrl = new URL(this.entity.getPutUrl());
+ fileInputStream = this.entity.getFileInputStream();
+ connection = (HttpURLConnection) putUrl.openConnection();
+
+ if (connection instanceof HttpsURLConnection) {
+ HttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, true);
+ }
+ connection.setRequestMethod(HTTP_METHOD);
+ connection.setFixedLengthStreamingMode((int) file.getExpectedSize());
+ String mime = this.entity.getFile().getMimeType();
+ connection.setRequestProperty(MIME_REQUEST_PROPERTY_NAME, mime == null ? HttpUpload.DEFAULT_MIME_TYPE : mime);
+ connection.setRequestProperty(USER_AGENT_REQUEST_PROPERTY_NAME, ConversationsPlusApplication.getNameAndVersion());
+ connection.setDoOutput(true);
+ connection.connect();
+ os = connection.getOutputStream();
+ int count = -1;
+ byte[] buffer = new byte[BUFFER_LENGTH];
+ while (((count = fileInputStream.read(buffer)) != -1) && !this.entity.isCanceled()) {
+ this.entity.updateProgress(count);
+ os.write(buffer, 0, count);
+ UiUpdateHelper.updateConversationUi();
+ }
+ os.flush();
+ os.close();
+ fileInputStream.close();
+ int code = connection.getResponseCode();
+ if (code == 200 || code == 201) {
+ Logging.d(Config.LOGTAG, "finished uploading file");
+ this.entity.transferred();
+ URL getUrl = new URL(this.entity.getGetUrl());
+ if (this.entity.getKey() != null) {
+ getUrl = new URL(getUrl.toString() + "#" + CryptoHelper.bytesToHex(this.entity.getKey()));
+ }
+ Message message = this.entity.getMessage();
+ MessageUtil.updateFileParams(message, getUrl);
+ FileBackend.updateMediaScanner(file, XmppConnectionServiceAccessor.xmppConnectionService);
+ message.setTransferable(null);
+ message.setCounterpart(message.getConversation().getJid().toBareJid());
+ if (message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
+ XmppConnectionServiceAccessor.xmppConnectionService.getPgpEngine().encrypt(message, new HttpUploadedFileEncryptionUiCallback(this.entity));
+ } else {
+ XmppConnectionServiceAccessor.xmppConnectionService.resendMessage(message, this.entity.isDelayed());
+ }
+ } else {
+ errorStream = connection.getErrorStream();
+ Logging.e("httpupload", "file upload failed: http code (" + code + ") " + new Scanner(errorStream).useDelimiter("\\A").next());
+ this.entity.fail();
+ }
+ } catch (IOException e) {
+ errorStream = (null != connection) ? connection.getErrorStream() : null;
+ String httpResponseMessage = null;
+ if (null != errorStream) {
+ httpResponseMessage = new Scanner(errorStream).useDelimiter("\\A").next();
+ }
+ Logging.e("httpupload", ((null != httpResponseMessage) ? ("http response: " + httpResponseMessage + ", ") : "") + "exception message: " + e.getMessage());
+ this.entity.fail();
+ } finally {
+ StreamUtil.close(os);
+ StreamUtil.close(errorStream);
+ StreamUtil.close(fileInputStream);
+ if (connection != null) {
+ connection.disconnect();
+ }
+ wakeLock.release();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadFileTransferService.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadFileTransferService.java
new file mode 100644
index 00000000..59957d1e
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadFileTransferService.java
@@ -0,0 +1,84 @@
+package de.thedevstack.conversationsplus.services.filetransfer.httpupload;
+
+import android.util.Pair;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.entities.DownloadableFile;
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.persistance.FileBackend;
+import de.thedevstack.conversationsplus.services.AbstractConnectionManager;
+import de.thedevstack.conversationsplus.services.FileTransferService;
+import de.thedevstack.conversationsplus.services.filetransfer.AbstractFileTransferService;
+import de.thedevstack.conversationsplus.utils.MessageUtil;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.thedevstack.conversationsplus.xmpp.httpupload.HttpUpload;
+import de.thedevstack.conversationsplus.xmpp.httpupload.HttpUploadRequestSlotPacketGenerator;
+import de.thedevstack.conversationsplus.xmpp.jid.Jid;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class HttpUploadFileTransferService extends AbstractFileTransferService implements FileTransferService {
+
+ public HttpUploadFileTransferService() {
+ }
+
+ /**
+ * Transfers a file for the corresponding message.
+ *
+ * @param message the message containing the file to transfer
+ * @return <code>true</code> if the file transfer was started successfully, <code>false</code> otherwise
+ */
+ @Override
+ public boolean transferFile(Message message) {
+ return this.transferFile(message, false);
+ }
+
+ /**
+ * Transfers a file for the corresponding message.
+ *
+ * @param message the message containing the file to transfer
+ * @param delay whether the message is delayed or not
+ * @return <code>true</code> if the file transfer was started successfully, <code>false</code> otherwise
+ */
+ @Override
+ public boolean transferFile(Message message, boolean delay) {
+ boolean started = false;
+ try {
+ final HttpFileTransferEntity entity = new HttpFileTransferEntity(message, delay);
+ Account account = message.getConversation().getAccount();
+ DownloadableFile file = entity.getFile();
+ Pair<InputStream, Integer> inputStreamAndExpectedSize = AbstractConnectionManager.createInputStream(file, true);
+
+ entity.setFileInputStream(inputStreamAndExpectedSize.first);
+ file.setExpectedSize(inputStreamAndExpectedSize.second);
+ Jid host = account.getXmppConnection().findDiscoItemByFeature(HttpUpload.NAMESPACE);
+ IqPacket request = HttpUploadRequestSlotPacketGenerator.generate(host, file.getName(), file.getSize(), file.getMimeType());
+ XmppSendUtil.sendIqPacket(account, request, new HttpUploadSlotRequestReceived(entity));
+ MessageUtil.markMessage(message, Message.STATUS_UNSEND);
+ started = true;
+ } catch (FileNotFoundException e) {
+ Logging.e("httpupload", "Could not find file, exception message: " + e.getMessage());
+ }
+ return started;
+ }
+
+ /**
+ * Checks whether a message can be sent using this service or not.
+ *
+ * @param message the message to be checked
+ * @return <code>true</code> if the message can be processed, <code>false</code> otherwise
+ */
+ @Override
+ public boolean accept(Message message) {
+ return null != message
+ && null != message.getConversation()
+ && null != message.getConversation().getAccount()
+ && message.getConversation().getAccount().httpUploadAvailable(FileBackend.getFile(message, false).getSize());
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadSlotRequestReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadSlotRequestReceived.java
new file mode 100644
index 00000000..e0b2332a
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadSlotRequestReceived.java
@@ -0,0 +1,34 @@
+package de.thedevstack.conversationsplus.services.filetransfer.httpupload;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived;
+import de.thedevstack.conversationsplus.xmpp.exceptions.XmppException;
+import de.thedevstack.conversationsplus.xmpp.httpupload.HttpUploadSlot;
+import de.thedevstack.conversationsplus.xmpp.httpupload.SlotPacketParser;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class HttpUploadSlotRequestReceived implements OnIqPacketReceived {
+ private final HttpFileTransferEntity entity;
+
+ public HttpUploadSlotRequestReceived(HttpFileTransferEntity entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ try {
+ HttpUploadSlot slot = SlotPacketParser.parseGetAndPutUrl(packet);
+ this.entity.setSlot(slot);
+ if (!this.entity.isCanceled()) {
+ new Thread(new HttpFileUploader(this.entity)).start();
+ }
+ } catch (XmppException e) {
+ Logging.e("httpupload", e.getMessage());
+ this.entity.fail();
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadedFileEncryptionUiCallback.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadedFileEncryptionUiCallback.java
new file mode 100644
index 00000000..25a16d78
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/httpupload/HttpUploadedFileEncryptionUiCallback.java
@@ -0,0 +1,33 @@
+package de.thedevstack.conversationsplus.services.filetransfer.httpupload;
+
+import android.app.PendingIntent;
+
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.ui.UiCallback;
+import de.thedevstack.conversationsplus.utils.XmppConnectionServiceAccessor;
+
+/**
+ *
+ */
+public class HttpUploadedFileEncryptionUiCallback implements UiCallback<Message> {
+ private final HttpFileTransferEntity entity;
+
+ public HttpUploadedFileEncryptionUiCallback(HttpFileTransferEntity entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public void success(Message message) {
+ XmppConnectionServiceAccessor.xmppConnectionService.resendMessage(message, this.entity.isDelayed());
+ }
+
+ @Override
+ public void error(int errorCode, Message object) {
+ this.entity.fail();
+ }
+
+ @Override
+ public void userInputRequried(PendingIntent pi, Message object) {
+ this.entity.fail();
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/jingle/JingleFileTransferService.java b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/jingle/JingleFileTransferService.java
new file mode 100644
index 00000000..46ee7ce5
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/filetransfer/jingle/JingleFileTransferService.java
@@ -0,0 +1,51 @@
+package de.thedevstack.conversationsplus.services.filetransfer.jingle;
+
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.services.FileTransferService;
+import de.thedevstack.conversationsplus.xmpp.jingle.JingleConnection;
+import de.thedevstack.conversationsplus.xmpp.jingle.JingleConnectionManager;
+
+/**
+ *
+ */
+public class JingleFileTransferService implements FileTransferService {
+ private final JingleConnectionManager jingleConnectionManager;
+
+ public JingleFileTransferService() {
+ this.jingleConnectionManager = new JingleConnectionManager();
+ }
+ /**
+ * Transfers a file for the corresponding message.
+ *
+ * @param message the message containing the file to transfer
+ * @return <code>true</code> if the file transfer was successful, <code>false</code> otherwise
+ */
+ @Override
+ public boolean transferFile(Message message) {
+ return this.transferFile(message, false);
+ }
+
+ /**
+ * Transfers a file for the corresponding message.
+ *
+ * @param message the message containing the file to transfer
+ * @param delay whether the message is delayed or not
+ * @return <code>true</code> if the file transfer was successful, <code>false</code> otherwise
+ */
+ @Override
+ public boolean transferFile(Message message, boolean delay) {
+ JingleConnection jingleConnection = this.jingleConnectionManager.createNewConnection(message);
+ return null != jingleConnection;
+ }
+
+ /**
+ * Checks whether a message can be sent using this service or not.
+ *
+ * @param message the message to be checked
+ * @return <code>true</code> if the message can be processed, <code>false</code> otherwise
+ */
+ @Override
+ public boolean accept(Message message) {
+ return message.fixCounterpart(); // No clue why - but this seems to be the check for jingle file transfer
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java
index de69c1e6..99d26b64 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationActivity.java
@@ -45,6 +45,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import de.thedevstack.android.logcat.Logging;
import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.http.HttpConnectionManager;
import de.thedevstack.conversationsplus.ui.dialogs.UserDecisionDialog;
import de.thedevstack.conversationsplus.ui.listeners.ResizePictureUserDecisionListener;
import de.thedevstack.conversationsplus.utils.ConversationUtil;
@@ -620,7 +621,7 @@ public class ConversationActivity extends XmppActivity
Toast.makeText(this, R.string.not_connected_try_again, Toast.LENGTH_SHORT).show();
}
} else if (message.treatAsDownloadable() != Message.Decision.NEVER) {
- xmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message, true);
+ HttpConnectionManager.createNewDownloadConnection(message, true);
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java
index f065a25b..d6e6f34c 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/ConversationFragment.java
@@ -46,6 +46,7 @@ import java.util.Collections;
import java.util.List;
import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.http.HttpConnectionManager;
import de.thedevstack.conversationsplus.http.HttpDownloadConnection;
import de.thedevstack.conversationsplus.ui.dialogs.MessageDetailsDialog;
import de.thedevstack.conversationsplus.Config;
@@ -685,8 +686,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
}
private void downloadFile(Message message) {
- activity.xmppConnectionService.getHttpConnectionManager()
- .createNewDownloadConnection(message,true);
+ HttpConnectionManager.createNewDownloadConnection(message,true);
}
private void cancelTransmission(Message message) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java
index 84eb7016..296f8f4f 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/SettingsActivity.java
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Locale;
import de.duenndns.ssl.MemorizingTrustManager;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.services.ExportLogsService;
import de.tzur.conversations.Settings;
import de.thedevstack.conversationsplus.R;
@@ -71,7 +72,7 @@ public class SettingsActivity extends XmppActivity implements
removeCertsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
- final MemorizingTrustManager mtm = xmppConnectionService.getMemorizingTrustManager();
+ final MemorizingTrustManager mtm = ConversationsPlusApplication.getMemorizingTrustManager();
final ArrayList<String> aliases = Collections.list(mtm.getCertificates());
if (aliases.size() == 0) {
displayToast(getString(R.string.toast_no_trusted_certs));
@@ -178,7 +179,7 @@ public class SettingsActivity extends XmppActivity implements
xmppConnectionService.refreshAllPresences();
}
} else if (name.equals("dont_trust_system_cas")) {
- xmppConnectionService.updateMemorizingTrustmanager();
+ ConversationsPlusApplication.updateMemorizingTrustmanager();
reconnectAccounts();
} else if ("parse_emoticons".equals(name)) {
EmojiconHandler.setParseEmoticons(Settings.PARSE_EMOTICONS);
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/AbstractIqPacketParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/AbstractIqPacketParser.java
new file mode 100644
index 00000000..d777cb64
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/AbstractIqPacketParser.java
@@ -0,0 +1,43 @@
+package de.thedevstack.conversationsplus.xmpp;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.exceptions.MissingRequiredContentException;
+import de.thedevstack.conversationsplus.xmpp.exceptions.MissingRequiredElementException;
+
+/**
+ *
+ */
+public abstract class AbstractIqPacketParser {
+ protected static Element findRequiredChild(Element element, String elementName, String namespace) throws MissingRequiredElementException {
+ if (null == element) {
+ return null;
+ }
+ Element child = element.findChild(elementName, namespace);
+ if (child == null) {
+ throw new MissingRequiredElementException(elementName, namespace, element);
+ }
+ return child;
+ }
+
+ protected static String findRequiredChildContent(Element element, String elementName) throws MissingRequiredContentException {
+ if (null == element) {
+ return null;
+ }
+ String childContent = element.findChildContent(elementName);
+ if (null == childContent) {
+ throw new MissingRequiredContentException(elementName, element);
+ }
+ return childContent;
+ }
+
+ protected static String findRequiredChildContent(Element element, String elementName, String namespace) throws MissingRequiredContentException {
+ if (null == element) {
+ return null;
+ }
+ String childContent = element.findChildContent(elementName, namespace);
+ if (null == childContent) {
+ throw new MissingRequiredContentException(elementName, namespace, element);
+ }
+ return childContent;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java
index a89f308f..c5a8fe3b 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java
@@ -2,7 +2,6 @@ package de.thedevstack.conversationsplus.xmpp;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.security.KeyChain;
@@ -50,6 +49,7 @@ import javax.net.ssl.X509TrustManager;
import de.duenndns.ssl.MemorizingTrustManager;
import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
import de.thedevstack.conversationsplus.dto.SrvRecord;
import de.thedevstack.conversationsplus.Config;
@@ -199,8 +199,7 @@ public class XmppConnection implements Runnable {
public XmppConnection(final Account account, final XmppConnectionService service) {
this.account = account;
- this.wakeLock = service.getPowerManager().newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, account.getJid().toBareJid().toString());
+ this.wakeLock = ConversationsPlusApplication.createPartialWakeLock(account.getJid().toBareJid().toString());
tagWriter = new TagWriter();
mXmppConnectionService = service;
}
@@ -382,14 +381,14 @@ public class XmppConnection implements Runnable {
private TlsFactoryVerifier getTlsFactoryVerifier() throws NoSuchAlgorithmException, KeyManagementException, IOException {
final SSLContext sc = SSLSocketHelper.getSSLContext();
- MemorizingTrustManager trustManager = this.mXmppConnectionService.getMemorizingTrustManager();
+ MemorizingTrustManager trustManager = ConversationsPlusApplication.getMemorizingTrustManager();
KeyManager[] keyManager;
if (account.getPrivateKeyAlias() != null && account.getPassword().isEmpty()) {
keyManager = new KeyManager[]{mKeyManager};
} else {
keyManager = null;
}
- sc.init(keyManager, new X509TrustManager[]{mInteractive ? trustManager : trustManager.getNonInteractive()}, mXmppConnectionService.getRNG());
+ sc.init(keyManager, new X509TrustManager[]{mInteractive ? trustManager : trustManager.getNonInteractive()}, ConversationsPlusApplication.getSecureRandom());
final SSLSocketFactory factory = sc.getSocketFactory();
final HostnameVerifier verifier;
if (mInteractive) {
@@ -737,13 +736,13 @@ public class XmppConnection implements Runnable {
final Element auth = new Element("auth");
auth.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
if (mechanisms.contains("EXTERNAL") && account.getPrivateKeyAlias() != null) {
- saslMechanism = new External(tagWriter, account, mXmppConnectionService.getRNG());
+ saslMechanism = new External(tagWriter, account, ConversationsPlusApplication.getSecureRandom());
} else if (mechanisms.contains("SCRAM-SHA-1")) {
- saslMechanism = new ScramSha1(tagWriter, account, mXmppConnectionService.getRNG());
+ saslMechanism = new ScramSha1(tagWriter, account, ConversationsPlusApplication.getSecureRandom());
} else if (mechanisms.contains("PLAIN")) {
saslMechanism = new Plain(tagWriter, account);
} else if (mechanisms.contains("DIGEST-MD5")) {
- saslMechanism = new DigestMd5(tagWriter, account, mXmppConnectionService.getRNG());
+ saslMechanism = new DigestMd5(tagWriter, account, ConversationsPlusApplication.getSecureRandom());
}
if (saslMechanism != null) {
final JSONObject keys = account.getKeys();
@@ -1171,7 +1170,7 @@ public class XmppConnection implements Runnable {
}
private String nextRandomId() {
- return new BigInteger(50, mXmppConnectionService.getRNG()).toString(32);
+ return new BigInteger(50, ConversationsPlusApplication.getSecureRandom()).toString(32);
}
public String sendIqPacket(final IqPacket packet, final OnIqPacketReceived callback) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/MissingRequiredContentException.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/MissingRequiredContentException.java
new file mode 100644
index 00000000..8b21cb9c
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/MissingRequiredContentException.java
@@ -0,0 +1,26 @@
+package de.thedevstack.conversationsplus.xmpp.exceptions;
+
+import de.thedevstack.conversationsplus.xml.Element;
+
+/**
+ *
+ */
+public class MissingRequiredContentException extends XmppException {
+ private String elementName;
+ private String namespace;
+
+ public MissingRequiredContentException(String elementName, Element context) {
+ super(context);
+ this.elementName = elementName;
+ }
+
+ public MissingRequiredContentException(String elementName, String namespace, Element context) {
+ this(elementName, context);
+ this.namespace = namespace;
+ }
+
+ @Override
+ public String getMessage() {
+ return "Missing required element content " + ((namespace != null) ? namespace + ":" : "") + elementName + " in context " + getContext();
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/MissingRequiredElementException.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/MissingRequiredElementException.java
new file mode 100644
index 00000000..8c8162ef
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/MissingRequiredElementException.java
@@ -0,0 +1,26 @@
+package de.thedevstack.conversationsplus.xmpp.exceptions;
+
+import de.thedevstack.conversationsplus.xml.Element;
+
+/**
+ *
+ */
+public class MissingRequiredElementException extends XmppException {
+ private String elementName;
+ private String namespace;
+
+ public MissingRequiredElementException(String elementName, Element context) {
+ super(context);
+ this.elementName = elementName;
+ }
+
+ public MissingRequiredElementException(String elementName, String namespace, Element context) {
+ this(elementName, context);
+ this.namespace = namespace;
+ }
+
+ @Override
+ public String getMessage() {
+ return "Missing required element " + ((namespace != null) ? namespace + ":" : "") + elementName + " in context " + getContext();
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/UnexpectedIqPacketTypeException.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/UnexpectedIqPacketTypeException.java
new file mode 100644
index 00000000..333f5dca
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/UnexpectedIqPacketTypeException.java
@@ -0,0 +1,25 @@
+package de.thedevstack.conversationsplus.xmpp.exceptions;
+
+import java.util.Arrays;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class UnexpectedIqPacketTypeException extends XmppException {
+ private final IqPacket.TYPE current;
+ private final IqPacket.TYPE[] expected;
+
+ public UnexpectedIqPacketTypeException(Element context, IqPacket.TYPE current, IqPacket.TYPE... expected) {
+ super(context);
+ this.expected = expected;
+ this.current = current;
+ }
+
+ @Override
+ public String getMessage() {
+ return "Unexpected IQ packet type '" + this.current + "' retrieved. One of " + Arrays.toString(expected) + " was expected.";
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/XmppException.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/XmppException.java
new file mode 100644
index 00000000..8c692f5b
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/XmppException.java
@@ -0,0 +1,56 @@
+package de.thedevstack.conversationsplus.xmpp.exceptions;
+
+import de.thedevstack.conversationsplus.xml.Element;
+
+/**
+ *
+ */
+public class XmppException extends Exception {
+ private Element context;
+ /**
+ * Constructs a new {@code Exception} that includes the current stack trace.
+ */
+ public XmppException() {
+ }
+
+ /**
+ * Constructs a new {@code Exception} that includes the current stack trace.
+ */
+ public XmppException(Element context) {
+ this.context = context;
+ }
+
+ /**
+ * Constructs a new {@code Exception} with the current stack trace and the
+ * specified cause.
+ *
+ * @param throwable the cause of this exception.
+ */
+ public XmppException(Throwable throwable) {
+ super(throwable);
+ }
+
+ /**
+ * Constructs a new {@code Exception} with the current stack trace and the
+ * specified cause.
+ *
+ * @param throwable the cause of this exception.
+ */
+ public XmppException(Element context, Throwable throwable) {
+ super(throwable);
+ this.context = context;
+ }
+
+ @Override
+ public String getMessage() {
+ if (null != context) {
+ return "Error in XMPP Element. XML element is: " + this.context.toString();
+ } else {
+ return super.getMessage();
+ }
+ }
+
+ public Element getContext() {
+ return context;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUpload.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUpload.java
new file mode 100644
index 00000000..28cba280
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUpload.java
@@ -0,0 +1,9 @@
+package de.thedevstack.conversationsplus.xmpp.httpupload;
+
+/**
+ *
+ */
+public interface HttpUpload {
+ String NAMESPACE = "urn:xmpp:http:upload";
+ String DEFAULT_MIME_TYPE = "application/octet-stream";
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUploadRequestSlotPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUploadRequestSlotPacketGenerator.java
new file mode 100644
index 00000000..59851417
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUploadRequestSlotPacketGenerator.java
@@ -0,0 +1,46 @@
+package de.thedevstack.conversationsplus.xmpp.httpupload;
+
+import de.thedevstack.conversationsplus.xmpp.jid.Jid;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ * Generates the IQ Packets for requesting a http upload slot
+ * as defined in XEP-0363.
+ * @see <a href="http://xmpp.org/extensions/xep-0363.html">http://xmpp.org/extensions/xep-0363.html</a>
+ */
+public final class HttpUploadRequestSlotPacketGenerator {
+ /**
+ * Generates the IqPacket to request a http upload slot.
+ * The attributes from and id are not set in here - this is added while sending the packet.
+ * <pre>
+ * <iq from='romeo@montague.tld/garden'
+ * id='step_03'
+ * to='upload.montague.tld'
+ * type='get'>
+ * <request xmlns='urn:xmpp:http:upload'>
+ * <filename>my_juliet.png</filename>
+ * <size>23456</size>
+ * <content-type>image/jpeg</content-type>
+ * </request>
+ * </iq>
+ * </pre>
+ * @param host the jid of the host to request a slot from
+ * @param filename the filename of the file which will be transferred
+ * @param filesize the filesize of the file which will be transferred
+ * @param mime the mime type of the file which will be transferred - <code>optional</code> and therefore nullable
+ * @return the IqPacket
+ */
+ public static IqPacket generate(Jid host, String filename, long filesize, String mime) {
+ SlotRequestPacket packet = new SlotRequestPacket(filename, filesize);
+ packet.setTo(host);
+ packet.setMime((mime == null) ? HttpUpload.DEFAULT_MIME_TYPE : mime);
+ return packet;
+ }
+
+ /**
+ * Utility class - avoid instantiation
+ */
+ private HttpUploadRequestSlotPacketGenerator() {
+ // Helper class - avoid instantiation
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUploadSlot.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUploadSlot.java
new file mode 100644
index 00000000..14fe5103
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/HttpUploadSlot.java
@@ -0,0 +1,22 @@
+package de.thedevstack.conversationsplus.xmpp.httpupload;
+
+/**
+ *
+ */
+public class HttpUploadSlot {
+ private final String getUrl;
+ private final String putUrl;
+
+ public HttpUploadSlot(String getUrl, String putUrl) {
+ this.getUrl = getUrl;
+ this.putUrl = putUrl;
+ }
+
+ public String getGetUrl() {
+ return this.getUrl;
+ }
+
+ public String getPutUrl() {
+ return this.putUrl;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/SlotPacketParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/SlotPacketParser.java
new file mode 100644
index 00000000..0630449a
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/SlotPacketParser.java
@@ -0,0 +1,27 @@
+package de.thedevstack.conversationsplus.xmpp.httpupload;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.AbstractIqPacketParser;
+import de.thedevstack.conversationsplus.xmpp.exceptions.UnexpectedIqPacketTypeException;
+import de.thedevstack.conversationsplus.xmpp.exceptions.XmppException;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public final class SlotPacketParser extends AbstractIqPacketParser {
+ public static HttpUploadSlot parseGetAndPutUrl(IqPacket packet) throws XmppException {
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ Element slot = findRequiredChild(packet, "slot", HttpUpload.NAMESPACE);
+
+ String getUrl = findRequiredChildContent(slot, "get");
+ String putUrl = findRequiredChildContent(slot, "put");
+
+ return new HttpUploadSlot(getUrl, putUrl);
+ } else if (packet.getType() == IqPacket.TYPE.ERROR) {
+ throw new XmppException(); // Do proper handling of error cases
+ } else {
+ throw new UnexpectedIqPacketTypeException(packet, packet.getType(), IqPacket.TYPE.RESULT, IqPacket.TYPE.ERROR);
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/SlotRequestPacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/SlotRequestPacket.java
new file mode 100644
index 00000000..d470d2f5
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/httpupload/SlotRequestPacket.java
@@ -0,0 +1,53 @@
+package de.thedevstack.conversationsplus.xmpp.httpupload;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class SlotRequestPacket extends IqPacket {
+ public static final String ELEMENT_NAME = "request";
+ public static final String FILENAME_ELEMENT_NAME = "filename";
+ public static final String FILESIZE_ELEMENT_NAME = "size";
+ public static final String MIME_ELEMENT_NAME = "content-type";
+ private Element requestElement;
+ private String filename;
+ private long filesize;
+ private String mime;
+
+ private SlotRequestPacket() {
+ super(TYPE.GET);
+ this.requestElement = super.addChild(SlotRequestPacket.ELEMENT_NAME, HttpUpload.NAMESPACE);
+ }
+
+ public SlotRequestPacket(String filename, long filesize) {
+ this();
+ this.setFilename(filename);
+ this.setFilesize(filesize);
+ }
+
+ public void setFilename(String filename) {
+ if (null == filename || filename.isEmpty()) {
+ throw new IllegalArgumentException("filename must not be null or empty.");
+ }
+ this.filename = filename;
+ this.requestElement.addChild(FILENAME_ELEMENT_NAME).setContent(filename);
+ }
+
+ public void setFilesize(long filesize) {
+ if (0 >= filesize) {
+ throw new IllegalArgumentException("filesize must not be null or empty.");
+ }
+ this.filesize = filesize;
+ this.requestElement.addChild(FILESIZE_ELEMENT_NAME).setContent(String.valueOf(filesize));
+ }
+
+ public void setMime(String mime) {
+ if (null == mime || mime.isEmpty()) {
+ throw new IllegalArgumentException("mime type must not be null or empty.");
+ }
+ this.mime = mime;
+ this.requestElement.addChild(MIME_ELEMENT_NAME).setContent(mime);
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java
index 422bdff0..ca823926 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnection.java
@@ -33,6 +33,7 @@ import de.thedevstack.conversationsplus.persistance.FileBackend;
import de.thedevstack.conversationsplus.services.AbstractConnectionManager;
import de.thedevstack.conversationsplus.services.XmppConnectionService;
import de.thedevstack.conversationsplus.utils.FileUtils;
+import de.thedevstack.conversationsplus.utils.XmppConnectionServiceAccessor;
import de.thedevstack.conversationsplus.xml.Element;
import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived;
import de.thedevstack.conversationsplus.xmpp.jid.Jid;
@@ -157,8 +158,7 @@ public class JingleConnection implements Transferable {
public JingleConnection(JingleConnectionManager mJingleConnectionManager) {
this.mJingleConnectionManager = mJingleConnectionManager;
- this.mXmppConnectionService = mJingleConnectionManager
- .getXmppConnectionService();
+ this.mXmppConnectionService = XmppConnectionServiceAccessor.xmppConnectionService;
}
public String getSessionId() {
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnectionManager.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnectionManager.java
index 2deb79c6..30ed9024 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnectionManager.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleConnectionManager.java
@@ -31,10 +31,6 @@ public class JingleConnectionManager extends AbstractConnectionManager {
@SuppressLint("TrulyRandom")
private SecureRandom random = new SecureRandom();
- public JingleConnectionManager(XmppConnectionService service) {
- super(service);
- }
-
public void deliverPacket(Account account, JinglePacket packet) {
if (packet.isAction("session-initiate")) {
JingleConnection connection = new JingleConnection(this);
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleSocks5Transport.java
index 9ea268d5..6480251f 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleSocks5Transport.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/jingle/JingleSocks5Transport.java
@@ -14,6 +14,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.utils.StreamUtil;
import de.thedevstack.conversationsplus.Config;
import de.thedevstack.conversationsplus.entities.DownloadableFile;
@@ -84,7 +85,7 @@ public class JingleSocks5Transport extends JingleTransport {
@Override
public void run() {
InputStream fileInputStream = null;
- final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_send_"+connection.getSessionId());
+ final PowerManager.WakeLock wakeLock = ConversationsPlusApplication.createPartialWakeLock("jingle_send_"+connection.getSessionId());
try {
wakeLock.acquire();
MessageDigest digest = MessageDigest.getInstance("SHA-1");
@@ -134,7 +135,7 @@ public class JingleSocks5Transport extends JingleTransport {
@Override
public void run() {
OutputStream fileOutputStream = null;
- final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_receive_"+connection.getSessionId());
+ final PowerManager.WakeLock wakeLock = ConversationsPlusApplication.createPartialWakeLock("jingle_receive_"+connection.getSessionId());
try {
wakeLock.acquire();
MessageDigest digest = MessageDigest.getInstance("SHA-1");