aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authoriNPUTmice <daniel@gultsch.de>2014-10-14 01:06:45 +0200
committeriNPUTmice <daniel@gultsch.de>2014-10-14 01:06:45 +0200
commitbbb0693f4a9a62a872b61b12a5118b01c7ca9450 (patch)
tree7db16c0083e42461921936344fba1f9af7c58f97 /src
parent7e373bc89fd11cf214fb435f25063d77cc2c48ae (diff)
basic image over http downloading
Diffstat (limited to 'src')
-rw-r--r--src/eu/siacs/conversations/AbstractConnectionManager.java25
-rw-r--r--src/eu/siacs/conversations/DownloadableFile.java148
-rw-r--r--src/eu/siacs/conversations/crypto/PgpEngine.java18
-rw-r--r--src/eu/siacs/conversations/entities/Contact.java4
-rw-r--r--src/eu/siacs/conversations/entities/Downloadable.java4
-rw-r--r--src/eu/siacs/conversations/entities/Message.java41
-rw-r--r--src/eu/siacs/conversations/entities/Roster.java2
-rw-r--r--src/eu/siacs/conversations/http/HttpConnection.java129
-rw-r--r--src/eu/siacs/conversations/http/HttpConnectionManager.java27
-rw-r--r--src/eu/siacs/conversations/parser/MessageParser.java3
-rw-r--r--src/eu/siacs/conversations/persistance/FileBackend.java22
-rw-r--r--src/eu/siacs/conversations/services/XmppConnectionService.java8
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java9
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java22
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleFile.java68
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleInbandTransport.java14
-rw-r--r--src/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java9
-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
20 files changed, 429 insertions, 213 deletions
diff --git a/src/eu/siacs/conversations/AbstractConnectionManager.java b/src/eu/siacs/conversations/AbstractConnectionManager.java
new file mode 100644
index 00000000..f2c937ab
--- /dev/null
+++ b/src/eu/siacs/conversations/AbstractConnectionManager.java
@@ -0,0 +1,25 @@
+package eu.siacs.conversations;
+
+import eu.siacs.conversations.services.XmppConnectionService;
+
+public class AbstractConnectionManager {
+ protected XmppConnectionService mXmppConnectionService;
+
+ public AbstractConnectionManager(XmppConnectionService service) {
+ this.mXmppConnectionService = service;
+ }
+
+ public XmppConnectionService getXmppConnectionService() {
+ return this.mXmppConnectionService;
+ }
+
+ public long getAutoAcceptFileSize() {
+ String config = this.mXmppConnectionService.getPreferences().getString(
+ "auto_accept_file_size", "524288");
+ try {
+ return Long.parseLong(config);
+ } catch (NumberFormatException e) {
+ return 524288;
+ }
+ }
+}
diff --git a/src/eu/siacs/conversations/DownloadableFile.java b/src/eu/siacs/conversations/DownloadableFile.java
new file mode 100644
index 00000000..c8097df8
--- /dev/null
+++ b/src/eu/siacs/conversations/DownloadableFile.java
@@ -0,0 +1,148 @@
+package eu.siacs.conversations;
+
+import java.io.File;
+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.Key;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import eu.siacs.conversations.utils.CryptoHelper;
+import android.util.Log;
+
+public class DownloadableFile extends File {
+
+ private static final long serialVersionUID = 2247012619505115863L;
+
+ private long expectedSize = 0;
+ private String sha1sum;
+ private Key aeskey;
+
+ private byte[] iv = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xf };
+
+ public DownloadableFile(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;
+ }
+
+ public InputStream createInputStream() {
+ if (this.getKey() == null) {
+ try {
+ return new FileInputStream(this);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ } else {
+ try {
+ IvParameterSpec ips = new IvParameterSpec(iv);
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, this.getKey(), ips);
+ Log.d(Config.LOGTAG, "opening encrypted input stream");
+ return new CipherInputStream(new FileInputStream(this), 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;
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+ }
+
+ public OutputStream createOutputStream() {
+ if (this.getKey() == null) {
+ try {
+ return new FileOutputStream(this);
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ } else {
+ try {
+ IvParameterSpec ips = new IvParameterSpec(iv);
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ cipher.init(Cipher.DECRYPT_MODE, this.getKey(), ips);
+ Log.d(Config.LOGTAG, "opening encrypted output stream");
+ return new CipherOutputStream(new FileOutputStream(this),
+ 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;
+ } catch (FileNotFoundException e) {
+ return null;
+ }
+ }
+ }
+}
diff --git a/src/eu/siacs/conversations/crypto/PgpEngine.java b/src/eu/siacs/conversations/crypto/PgpEngine.java
index e7058a68..d83a210d 100644
--- a/src/eu/siacs/conversations/crypto/PgpEngine.java
+++ b/src/eu/siacs/conversations/crypto/PgpEngine.java
@@ -15,6 +15,7 @@ import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
import eu.siacs.conversations.Config;
+import eu.siacs.conversations.DownloadableFile;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
@@ -22,7 +23,6 @@ import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.ui.UiCallback;
-import eu.siacs.conversations.xmpp.jingle.JingleFile;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.BitmapFactory;
@@ -86,10 +86,10 @@ public class PgpEngine {
});
} else if (message.getType() == Message.TYPE_IMAGE) {
try {
- final JingleFile inputFile = this.mXmppConnectionService
- .getFileBackend().getJingleFile(message, false);
- final JingleFile outputFile = this.mXmppConnectionService
- .getFileBackend().getJingleFile(message, true);
+ final DownloadableFile inputFile = this.mXmppConnectionService
+ .getFileBackend().getConversationsFile(message, false);
+ final DownloadableFile outputFile = this.mXmppConnectionService
+ .getFileBackend().getConversationsFile(message, true);
outputFile.createNewFile();
InputStream is = new FileInputStream(inputFile);
OutputStream os = new FileOutputStream(outputFile);
@@ -197,10 +197,10 @@ public class PgpEngine {
});
} else if (message.getType() == Message.TYPE_IMAGE) {
try {
- JingleFile inputFile = this.mXmppConnectionService
- .getFileBackend().getJingleFile(message, true);
- JingleFile outputFile = this.mXmppConnectionService
- .getFileBackend().getJingleFile(message, false);
+ DownloadableFile inputFile = this.mXmppConnectionService
+ .getFileBackend().getConversationsFile(message, true);
+ DownloadableFile outputFile = this.mXmppConnectionService
+ .getFileBackend().getConversationsFile(message, false);
outputFile.createNewFile();
InputStream is = new FileInputStream(inputFile);
OutputStream os = new FileOutputStream(outputFile);
diff --git a/src/eu/siacs/conversations/entities/Contact.java b/src/eu/siacs/conversations/entities/Contact.java
index b1ebe662..40eee73d 100644
--- a/src/eu/siacs/conversations/entities/Contact.java
+++ b/src/eu/siacs/conversations/entities/Contact.java
@@ -374,4 +374,8 @@ public class Contact implements ListItem {
return false;
}
}
+
+ public boolean trusted() {
+ return getOption(Options.FROM) && getOption(Options.TO);
+ }
}
diff --git a/src/eu/siacs/conversations/entities/Downloadable.java b/src/eu/siacs/conversations/entities/Downloadable.java
index 8fb4977e..c8ee357d 100644
--- a/src/eu/siacs/conversations/entities/Downloadable.java
+++ b/src/eu/siacs/conversations/entities/Downloadable.java
@@ -1,5 +1,9 @@
package eu.siacs.conversations.entities;
public interface Downloadable {
+
+ public final String[] VALID_EXTENSIONS = { "webp", "jpeg", "jpg", "png" };
+ public final String[] VALID_CRYPTO_EXTENSIONS = { "pgp", "gpg", "otr" };
+
public void start();
}
diff --git a/src/eu/siacs/conversations/entities/Message.java b/src/eu/siacs/conversations/entities/Message.java
index 49482bbc..b459510c 100644
--- a/src/eu/siacs/conversations/entities/Message.java
+++ b/src/eu/siacs/conversations/entities/Message.java
@@ -1,10 +1,15 @@
package eu.siacs.conversations.entities;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.text.InputFilter.LengthFilter;
public class Message extends AbstractEntity {
@@ -131,14 +136,8 @@ public class Message extends AbstractEntity {
if (this.trueCounterpart == null) {
return null;
} else {
- Account account = this.conversation.getAccount();
- Contact contact = account.getRoster().getContact(
+ return this.conversation.getAccount().getRoster().getContactFromRoster(
this.trueCounterpart);
- if (contact.showInRoster()) {
- return contact;
- } else {
- return null;
- }
}
}
}
@@ -369,4 +368,32 @@ public class Message extends AbstractEntity {
return prev.mergable(this);
}
}
+
+ public boolean bodyContainsDownloadable() {
+ Contact contact = this.getContact();
+ if (contact == null || !contact.trusted()) {
+ return false;
+ }
+ try {
+ URL url = new URL(this.getBody());
+ if (!url.getProtocol().equalsIgnoreCase("http") && !url.getProtocol().equalsIgnoreCase("https")) {
+ return false;
+ }
+ if (url.getPath()==null) {
+ return false;
+ }
+ String[] pathParts = url.getPath().split("/");
+ String filename = pathParts[pathParts.length - 1];
+ String[] extensionParts = filename.split("\\.");
+ if (extensionParts.length == 2 && Arrays.asList(Downloadable.VALID_EXTENSIONS).contains(extensionParts[extensionParts.length -1])) {
+ return true;
+ } else if (extensionParts.length == 3 && Arrays.asList(Downloadable.VALID_CRYPTO_EXTENSIONS).contains(extensionParts.length -1) && Arrays.asList(Downloadable.VALID_EXTENSIONS).contains(extensionParts[extensionParts.length -2])) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (MalformedURLException e) {
+ return false;
+ }
+ }
}
diff --git a/src/eu/siacs/conversations/entities/Roster.java b/src/eu/siacs/conversations/entities/Roster.java
index b6908793..ef47c577 100644
--- a/src/eu/siacs/conversations/entities/Roster.java
+++ b/src/eu/siacs/conversations/entities/Roster.java
@@ -14,7 +14,7 @@ public class Roster {
this.account = account;
}
- public Contact getContactAsShownInRoster(String jid) {
+ public Contact getContactFromRoster(String jid) {
String cleanJid = jid.split("/", 2)[0];
Contact contact = contacts.get(cleanJid);
if (contact != null && contact.showInRoster()) {
diff --git a/src/eu/siacs/conversations/http/HttpConnection.java b/src/eu/siacs/conversations/http/HttpConnection.java
new file mode 100644
index 00000000..d3b1700b
--- /dev/null
+++ b/src/eu/siacs/conversations/http/HttpConnection.java
@@ -0,0 +1,129 @@
+package eu.siacs.conversations.http;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import android.util.Log;
+
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.DownloadableFile;
+import eu.siacs.conversations.entities.Downloadable;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.XmppConnectionService;
+
+public class HttpConnection implements Downloadable {
+
+ private HttpConnectionManager mHttpConnectionManager;
+ private XmppConnectionService mXmppConnectionService;
+
+ private URL mUrl;
+ private Message message;
+ private DownloadableFile file;
+
+ public HttpConnection(HttpConnectionManager manager) {
+ this.mHttpConnectionManager = manager;
+ this.mXmppConnectionService = manager.getXmppConnectionService();
+ }
+
+ @Override
+ public void start() {
+ new Thread(new FileDownloader()).start();
+ }
+
+ public void init(Message message) {
+ this.message = message;
+ this.message.setDownloadable(this);
+ try {
+ mUrl = new URL(message.getBody());
+ this.file = mXmppConnectionService.getFileBackend().getConversationsFile(message,false);
+ message.setType(Message.TYPE_IMAGE);
+ mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVED_OFFER);
+ checkFileSize();
+ } catch (MalformedURLException e) {
+ this.cancel();
+ }
+ }
+
+ private void checkFileSize() {
+ new Thread(new FileSizeChecker()).start();
+ }
+
+ public void cancel() {
+ mXmppConnectionService.markMessage(message, Message.STATUS_RECEPTION_FAILED);
+ Log.d(Config.LOGTAG,"canceled download");
+ }
+
+ private class FileSizeChecker implements Runnable {
+
+ @Override
+ public void run() {
+ try {
+ long size = retrieveFileSize();
+ file.setExpectedSize(size);
+ if (size <= mHttpConnectionManager.getAutoAcceptFileSize()) {
+ start();
+ }
+ Log.d(Config.LOGTAG,"file size: "+size);
+ } catch (IOException e) {
+ cancel();
+ }
+ }
+
+ private long retrieveFileSize() throws IOException {
+ HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
+ connection.setRequestMethod("HEAD");
+ if (connection instanceof HttpsURLConnection) {
+
+ }
+ String contentLength = connection.getHeaderField("Content-Length");
+ if (contentLength == null) {
+ throw new IOException();
+ }
+ try {
+ return Long.parseLong(contentLength, 10);
+ } catch (NumberFormatException e) {
+ throw new IOException();
+ }
+ }
+
+ }
+
+ private class FileDownloader implements Runnable {
+
+ @Override
+ public void run() {
+ try {
+ mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVING);
+ download();
+ mXmppConnectionService.markMessage(message, Message.STATUS_RECEIVED);
+ } catch (IOException e) {
+ cancel();
+ }
+ }
+
+ private void download() throws IOException {
+ HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
+ if (connection instanceof HttpsURLConnection) {
+
+ }
+ BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
+ OutputStream os = file.createOutputStream();
+ int count = -1;
+ byte[] buffer = new byte[1024];
+ while ((count = is.read(buffer)) != -1) {
+ os.write(buffer, 0, count);
+ }
+ os.flush();
+ os.close();
+ is.close();
+ Log.d(Config.LOGTAG,"finished downloading "+file.getAbsolutePath().toString());
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/eu/siacs/conversations/http/HttpConnectionManager.java b/src/eu/siacs/conversations/http/HttpConnectionManager.java
new file mode 100644
index 00000000..ee50ef7e
--- /dev/null
+++ b/src/eu/siacs/conversations/http/HttpConnectionManager.java
@@ -0,0 +1,27 @@
+package eu.siacs.conversations.http;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import eu.siacs.conversations.AbstractConnectionManager;
+import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.services.XmppConnectionService;
+
+public class HttpConnectionManager extends AbstractConnectionManager {
+
+ public HttpConnectionManager(XmppConnectionService service) {
+ super(service);
+ }
+
+ private XmppConnectionService mXmppConnectionService;
+
+ private List<HttpConnection> connections = new CopyOnWriteArrayList<HttpConnection>();
+
+
+ public HttpConnection createNewConnection(Message message) {
+ HttpConnection connection = new HttpConnection(this);
+ connection.init(message);
+ this.connections.add(connection);
+ return connection;
+ }
+}
diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java
index f8329037..71346c7a 100644
--- a/src/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/eu/siacs/conversations/parser/MessageParser.java
@@ -478,6 +478,9 @@ public class MessageParser extends AbstractParser implements
mXmppConnectionService.databaseBackend.createMessage(message);
}
}
+ if (message.getStatus() == Message.STATUS_RECEIVED && message.bodyContainsDownloadable()) {
+ this.mXmppConnectionService.getHttpConnectionManager().createNewConnection(message);
+ }
notify = notify && !conversation.isMuted();
if (notify) {
mXmppConnectionService.getNotificationService().push(message);
diff --git a/src/eu/siacs/conversations/persistance/FileBackend.java b/src/eu/siacs/conversations/persistance/FileBackend.java
index d86c0ee1..8d5046ab 100644
--- a/src/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/eu/siacs/conversations/persistance/FileBackend.java
@@ -30,13 +30,13 @@ import android.util.Base64OutputStream;
import android.util.Log;
import android.util.LruCache;
import eu.siacs.conversations.Config;
+import eu.siacs.conversations.DownloadableFile;
import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.services.ImageProvider;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.UIHelper;
-import eu.siacs.conversations.xmpp.jingle.JingleFile;
import eu.siacs.conversations.xmpp.pep.Avatar;
public class FileBackend {
@@ -66,11 +66,11 @@ public class FileBackend {
return thumbnailCache;
}
- public JingleFile getJingleFileLegacy(Message message) {
+ public DownloadableFile getJingleFileLegacy(Message message) {
return getJingleFileLegacy(message, true);
}
- public JingleFile getJingleFileLegacy(Message message, boolean decrypted) {
+ public DownloadableFile getJingleFileLegacy(Message message, boolean decrypted) {
Conversation conversation = message.getConversation();
String prefix = context.getFilesDir().getAbsolutePath();
String path = prefix + "/" + conversation.getAccount().getJid() + "/"
@@ -85,14 +85,14 @@ public class FileBackend {
filename = message.getUuid() + ".webp.pgp";
}
}
- return new JingleFile(path + "/" + filename);
+ return new DownloadableFile(path + "/" + filename);
}
- public JingleFile getJingleFile(Message message) {
- return getJingleFile(message, true);
+ public DownloadableFile getJingleFile(Message message) {
+ return getConversationsFile(message, true);
}
- public JingleFile getJingleFile(Message message, boolean decrypted) {
+ public DownloadableFile getConversationsFile(Message message, boolean decrypted) {
StringBuilder filename = new StringBuilder();
filename.append(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES).getAbsolutePath());
@@ -107,7 +107,7 @@ public class FileBackend {
filename.append(".webp.pgp");
}
}
- return new JingleFile(filename.toString());
+ return new DownloadableFile(filename.toString());
}
public Bitmap resize(Bitmap originalBitmap, int size) {
@@ -139,17 +139,17 @@ public class FileBackend {
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
- public JingleFile copyImageToPrivateStorage(Message message, Uri image)
+ public DownloadableFile copyImageToPrivateStorage(Message message, Uri image)
throws ImageCopyException {
return this.copyImageToPrivateStorage(message, image, 0);
}
- private JingleFile copyImageToPrivateStorage(Message message, Uri image,
+ private DownloadableFile copyImageToPrivateStorage(Message message, Uri image,
int sampleSize) throws ImageCopyException {
try {
InputStream is = context.getContentResolver()
.openInputStream(image);
- JingleFile file = getJingleFile(message);
+ DownloadableFile file = getJingleFile(message);
file.getParentFile().mkdirs();
file.createNewFile();
Bitmap originalBitmap;
diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java
index e6297f4f..3549ce0a 100644
--- a/src/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/eu/siacs/conversations/services/XmppConnectionService.java
@@ -34,6 +34,7 @@ import eu.siacs.conversations.entities.Presences;
import eu.siacs.conversations.generator.IqGenerator;
import eu.siacs.conversations.generator.MessageGenerator;
import eu.siacs.conversations.generator.PresenceGenerator;
+import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.parser.IqParser;
import eu.siacs.conversations.parser.MessageParser;
import eu.siacs.conversations.parser.PresenceParser;
@@ -106,6 +107,7 @@ public class XmppConnectionService extends Service {
private CopyOnWriteArrayList<Conversation> conversations = null;
private JingleConnectionManager mJingleConnectionManager = new JingleConnectionManager(
this);
+ private HttpConnectionManager mHttpConnectionManager = new HttpConnectionManager(this);
private OnConversationUpdate mOnConversationUpdate = null;
private int convChangedListenerCount = 0;
@@ -1780,7 +1782,7 @@ public class XmppConnectionService extends Service {
for (Account account : getAccounts()) {
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
Contact contact = account.getRoster()
- .getContactAsShownInRoster(jid);
+ .getContactFromRoster(jid);
if (contact != null) {
contacts.add(contact);
}
@@ -1792,4 +1794,8 @@ public class XmppConnectionService extends Service {
public NotificationService getNotificationService() {
return this.mNotificationService;
}
+
+ public HttpConnectionManager getHttpConnectionManager() {
+ return this.mHttpConnectionManager;
+ }
}
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
index 92fdbe0b..4dac54f6 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
@@ -13,6 +13,7 @@ import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
import eu.siacs.conversations.Config;
+import eu.siacs.conversations.DownloadableFile;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Downloadable;
@@ -54,7 +55,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;
@@ -83,7 +84,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) {
@@ -323,7 +324,7 @@ public class JingleConnection implements Downloadable {
.push(message);
}
this.file = this.mXmppConnectionService.getFileBackend()
- .getJingleFile(message, false);
+ .getConversationsFile(message, false);
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
byte[] key = conversation.getSymmetricKey();
if (key == null) {
@@ -355,7 +356,7 @@ public class JingleConnection implements Downloadable {
if (message.getType() == Message.TYPE_IMAGE) {
content.setTransportId(this.transportId);
this.file = this.mXmppConnectionService.getFileBackend()
- .getJingleFile(message, false);
+ .getConversationsFile(message, false);
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
Conversation conversation = this.message.getConversation();
this.mXmppConnectionService.renewSymmetricKey(conversation);
diff --git a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
index 79090af6..93b03ff8 100644
--- a/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
+++ b/src/eu/siacs/conversations/xmpp/jingle/JingleConnectionManager.java
@@ -7,6 +7,7 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import android.annotation.SuppressLint;
import android.util.Log;
+import eu.siacs.conversations.AbstractConnectionManager;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Message;
@@ -16,10 +17,7 @@ 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) {
@@ -68,10 +66,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 +122,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;
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..ed64c24a 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;
@@ -9,6 +8,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import android.util.Base64;
+import eu.siacs.conversations.DownloadableFile;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.xml.Element;
@@ -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,18 @@ 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..ec6b2c24 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.DownloadableFile;
import eu.siacs.conversations.utils.CryptoHelper;
public class JingleSocks5Transport extends JingleTransport {
@@ -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..185018e6 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.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..a6df50a5 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.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..e74d8965 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.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");