aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/eu/siacs/conversations
diff options
context:
space:
mode:
authorChristian S <christian@pix-art.de>2015-08-12 12:41:13 +0200
committerChristian S <christian@pix-art.de>2015-08-12 12:41:13 +0200
commita0145e779d3caf58b0bfdb6a76587c61b345bf55 (patch)
tree619423e3139836b9ad78dc472e7a6592b0d015ba /src/main/java/eu/siacs/conversations
parent6ef1f090840eec062f23c3433eaeef77df75f874 (diff)
parent81b7e27a468edb37994225fa7ad3581e26f73c9d (diff)
version 1.6.0 beta 3
Diffstat (limited to 'src/main/java/eu/siacs/conversations')
-rw-r--r--src/main/java/eu/siacs/conversations/Config.java2
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java99
-rw-r--r--src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java13
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/FileBackend.java37
-rw-r--r--src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java24
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java21
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationFragment.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java4
-rw-r--r--src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java2
-rw-r--r--src/main/java/eu/siacs/conversations/ui/XmppActivity.java6
-rw-r--r--src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java8
-rw-r--r--src/main/java/eu/siacs/conversations/utils/FileUtils.java144
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java10
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java67
-rw-r--r--src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java37
15 files changed, 331 insertions, 145 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java
index f0eb96832..a92b1024a 100644
--- a/src/main/java/eu/siacs/conversations/Config.java
+++ b/src/main/java/eu/siacs/conversations/Config.java
@@ -43,6 +43,8 @@ public final class Config {
public static final boolean ENCRYPT_ON_HTTP_UPLOADED = false;
+ public static final boolean REPORT_WRONG_FILESIZE_IN_OTR_JINGLE = true;
+
public static final boolean SHOW_REGENERATE_AXOLOTL_KEYS_BUTTON = false;
public static final long MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
index 79e4654be..0d202bb92 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java
@@ -2,10 +2,12 @@ package eu.siacs.conversations.http;
import android.content.Intent;
import android.net.Uri;
+import android.os.PowerManager;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
@@ -125,6 +127,17 @@ public class HttpDownloadConnection implements Transferable {
mXmppConnectionService.updateConversationUi();
}
+ private void showToastForException(Exception e) {
+ e.printStackTrace();
+ if (e instanceof java.net.UnknownHostException) {
+ mXmppConnectionService.showErrorToastInUi(R.string.download_failed_server_not_found);
+ } else if (e instanceof java.net.ConnectException) {
+ mXmppConnectionService.showErrorToastInUi(R.string.download_failed_could_not_connect);
+ } else {
+ mXmppConnectionService.showErrorToastInUi(R.string.download_failed_file_not_found);
+ }
+ }
+
private class FileSizeChecker implements Runnable {
private boolean interactive = false;
@@ -146,7 +159,7 @@ public class HttpDownloadConnection implements Transferable {
} catch (IOException e) {
Log.d(Config.LOGTAG, "io exception in http file size checker: " + e.getMessage());
if (interactive) {
- mXmppConnectionService.showErrorToastInUi(R.string.file_not_found_on_remote_host);
+ showToastForException(e);
}
cancel();
return;
@@ -163,20 +176,23 @@ public class HttpDownloadConnection implements Transferable {
}
private long retrieveFileSize() throws IOException {
- Log.d(Config.LOGTAG,"retrieve file size. interactive:"+String.valueOf(interactive));
- changeStatus(STATUS_CHECKING);
- HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
- connection.setRequestMethod("HEAD");
- if (connection instanceof HttpsURLConnection) {
- mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
- }
- connection.connect();
- String contentLength = connection.getHeaderField("Content-Length");
- if (contentLength == null) {
- throw new IOException();
- }
try {
+ Log.d(Config.LOGTAG, "retrieve file size. interactive:" + String.valueOf(interactive));
+ changeStatus(STATUS_CHECKING);
+ HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
+ connection.setRequestMethod("HEAD");
+ if (connection instanceof HttpsURLConnection) {
+ mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
+ }
+ connection.connect();
+ String contentLength = connection.getHeaderField("Content-Length");
+ connection.disconnect();
+ if (contentLength == null) {
+ throw new IOException();
+ }
return Long.parseLong(contentLength, 10);
+ } catch (IOException e) {
+ throw e;
} catch (NumberFormatException e) {
throw new IOException();
}
@@ -202,37 +218,46 @@ public class HttpDownloadConnection implements Transferable {
updateImageBounds();
finish();
} catch (SSLHandshakeException e) {
- FileBackend.close(os);
changeStatus(STATUS_OFFER);
} catch (IOException e) {
- FileBackend.close(os);
- mXmppConnectionService.showErrorToastInUi(R.string.file_not_found_on_remote_host);
+ if (interactive) {
+ showToastForException(e);
+ }
cancel();
}
}
- private void download() throws IOException {
- HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
- if (connection instanceof HttpsURLConnection) {
- mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
- }
- connection.connect();
- BufferedInputStream is = new BufferedInputStream(connection.getInputStream());
- file.getParentFile().mkdirs();
- file.createNewFile();
- os = AbstractConnectionManager.createOutputStream(file,true);
- long transmitted = 0;
- long expected = file.getExpectedSize();
- int count = -1;
- byte[] buffer = new byte[1024];
- while ((count = is.read(buffer)) != -1) {
- transmitted += count;
- os.write(buffer, 0, count);
- updateProgress((int) ((((double) transmitted) / expected) * 100));
+ private void download() throws IOException {
+ InputStream is = null;
+ PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_download_"+message.getUuid());
+ try {
+ wakeLock.acquire();
+ HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection();
+ if (connection instanceof HttpsURLConnection) {
+ mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
+ }
+ connection.connect();
+ is = new BufferedInputStream(connection.getInputStream());
+ file.getParentFile().mkdirs();
+ file.createNewFile();
+ os = AbstractConnectionManager.createOutputStream(file, true);
+ long transmitted = 0;
+ long expected = file.getExpectedSize();
+ int count = -1;
+ byte[] buffer = new byte[1024];
+ while ((count = is.read(buffer)) != -1) {
+ transmitted += count;
+ os.write(buffer, 0, count);
+ updateProgress((int) ((((double) transmitted) / expected) * 100));
+ }
+ os.flush();
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ FileBackend.close(os);
+ FileBackend.close(is);
+ wakeLock.release();
}
- os.flush();
- os.close();
- is.close();
}
private void updateImageBounds() {
diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
index 768915a94..2e5458423 100644
--- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
+++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java
@@ -3,9 +3,11 @@ package eu.siacs.conversations.http;
import android.app.PendingIntent;
import android.content.Intent;
import android.net.Uri;
+import android.os.PowerManager;
import android.util.Log;
import android.util.Pair;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -103,7 +105,13 @@ public class HttpUploadConnection implements Transferable {
mXmppConnectionService.getRNG().nextBytes(this.key);
this.file.setKeyAndIv(this.key);
}
- Pair<InputStream,Integer> pair = AbstractConnectionManager.createInputStream(file,true);
+ Pair<InputStream,Integer> pair;
+ try {
+ pair = AbstractConnectionManager.createInputStream(file, true);
+ } catch (FileNotFoundException e) {
+ fail();
+ return;
+ }
this.file.setExpectedSize(pair.second);
this.mFileInputStream = pair.first;
Jid host = account.getXmppConnection().findDiscoItemByFeature(Xmlns.HTTP_UPLOAD);
@@ -143,7 +151,9 @@ public class HttpUploadConnection implements Transferable {
private void upload() {
OutputStream os = null;
HttpURLConnection connection = null;
+ PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_upload_"+message.getUuid());
try {
+ wakeLock.acquire();
Log.d(Config.LOGTAG, "uploading to " + mPutUrl.toString());
connection = (HttpURLConnection) mPutUrl.openConnection();
if (connection instanceof HttpsURLConnection) {
@@ -211,6 +221,7 @@ public class HttpUploadConnection implements Transferable {
if (connection != null) {
connection.disconnect();
}
+ wakeLock.release();
}
}
}
diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
index 3a8248f16..7fd5d88b8 100644
--- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java
@@ -39,6 +39,7 @@ import eu.siacs.conversations.entities.Transferable;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExifHelper;
+import eu.siacs.conversations.utils.FileUtils;
import eu.siacs.conversations.xmpp.pep.Avatar;
public class FileBackend {
@@ -126,25 +127,25 @@ public class FileBackend {
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
- public String getOriginalPath(Uri uri) {
- String path = null;
- if (uri.getScheme().equals("file")) {
- return uri.getPath();
- } else if (uri.toString().startsWith("content://media/")) {
- String[] projection = {MediaStore.MediaColumns.DATA};
- Cursor metaCursor = mXmppConnectionService.getContentResolver().query(uri,
- projection, null, null, null);
- if (metaCursor != null) {
- try {
- if (metaCursor.moveToFirst()) {
- path = metaCursor.getString(0);
- }
- } finally {
- metaCursor.close();
- }
- }
+ public boolean useImageAsIs(Uri uri) {
+ String path = getOriginalPath(uri);
+ if (path == null) {
+ return false;
}
- return path;
+ Log.d(Config.LOGTAG,"using image as is. path: "+path);
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ try {
+ BitmapFactory.decodeStream(mXmppConnectionService.getContentResolver().openInputStream(uri), null, options);
+ return (options.outWidth <= Config.IMAGE_SIZE && options.outHeight <= Config.IMAGE_SIZE && options.outMimeType.contains(Config.IMAGE_FORMAT.name().toLowerCase()));
+ } catch (FileNotFoundException e) {
+ return false;
+ }
+ }
+
+ public String getOriginalPath(Uri uri) {
+ Log.d(Config.LOGTAG,"get original path for uri: "+uri.toString());
+ return FileUtils.getPath(mXmppConnectionService,uri);
}
public DownloadableFile copyFileToPrivateStorage(Message message, Uri uri) throws FileCopyException {
diff --git a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java
index b7e7c8d3a..5def05dd4 100644
--- a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java
+++ b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java
@@ -1,5 +1,7 @@
package eu.siacs.conversations.services;
+import android.content.Context;
+import android.os.PowerManager;
import android.util.Log;
import android.util.Pair;
@@ -49,17 +51,13 @@ public class AbstractConnectionManager {
}
}
- public static Pair<InputStream,Integer> createInputStream(DownloadableFile file, boolean gcm) {
+ public static Pair<InputStream,Integer> createInputStream(DownloadableFile file, boolean gcm) throws FileNotFoundException {
FileInputStream is;
int size;
- try {
- is = new FileInputStream(file);
- size = (int) file.getSize();
- if (file.getKey() == null) {
- return new Pair<InputStream,Integer>(is,size);
- }
- } catch (FileNotFoundException e) {
- return null;
+ is = new FileInputStream(file);
+ size = (int) file.getSize();
+ if (file.getKey() == null) {
+ return new Pair<InputStream,Integer>(is,size);
}
try {
if (gcm) {
@@ -72,7 +70,8 @@ public class AbstractConnectionManager {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(file.getKey(), "AES"), ips);
Log.d(Config.LOGTAG, "opening encrypted input stream");
- return new Pair<InputStream,Integer>(new CipherInputStream(is, cipher),(size / 16 + 1) * 16);
+ final int s = Config.REPORT_WRONG_FILESIZE_IN_OTR_JINGLE ? size : (size / 16 + 1) * 16;
+ return new Pair<InputStream,Integer>(new CipherInputStream(is, cipher),s);
}
} catch (InvalidKeyException e) {
return null;
@@ -117,4 +116,9 @@ 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/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index ffe587d69..ed3bb8792 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -404,8 +404,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
- public void attachImageToConversation(final Conversation conversation,
- final Uri uri, final UiCallback<Message> callback) {
+ public void attachImageToConversation(final Conversation conversation, final Uri uri, final UiCallback<Message> callback) {
+ if (getFileBackend().useImageAsIs(uri)) {
+ Log.d(Config.LOGTAG,"using image as is");
+ attachFileToConversation(conversation, uri, callback);
+ return;
+ }
final Message message;
if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) {
message = new Message(conversation, "", Message.ENCRYPTION_DECRYPTED);
@@ -855,7 +859,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
} else {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": fetching roster");
}
- iqPacket.query(Xmlns.ROSTER).setAttribute("ver",account.getRosterVersion());
+ iqPacket.query(Xmlns.ROSTER).setAttribute("ver", account.getRosterVersion());
sendIqPacket(account,iqPacket,mIqParser);
}
@@ -1000,6 +1004,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
public void onMessageFound(Message message) {
if (!getFileBackend().isFileAvailable(message)) {
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
+ final int s = message.getStatus();
+ if(s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
+ markMessage(message,Message.STATUS_SEND_FAILED);
+ }
}
}
});
@@ -1011,7 +1019,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
if (message != null) {
if (!getFileBackend().isFileAvailable(message)) {
message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED));
- updateConversationUi();
+ final int s = message.getStatus();
+ if(s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) {
+ markMessage(message,Message.STATUS_SEND_FAILED);
+ } else {
+ updateConversationUi();
+ }
}
return;
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
index 79cb006d1..49878463b 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java
@@ -333,7 +333,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa
mEditMessage.setHint(getString(R.string.send_otr_message));
break;
case Message.ENCRYPTION_AXOLOTL:
- mEditMessage.setHint(getString(R.string.send_axolotl_message));
+ mEditMessage.setHint(getString(R.string.send_omemo_message));
break;
case Message.ENCRYPTION_PGP:
mEditMessage.setHint(getString(R.string.send_pgp_message));
diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
index 7536ea753..f861e73df 100644
--- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java
@@ -577,10 +577,10 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
@Override
public void onClick(final View v) {
- if (copyTextToClipboard(axolotlFingerprint, R.string.axolotl_fingerprint)) {
+ if (copyTextToClipboard(axolotlFingerprint, R.string.omemo_fingerprint)) {
Toast.makeText(
EditAccountActivity.this,
- R.string.toast_message_axolotl_fingerprint,
+ R.string.toast_message_omemo_fingerprint,
Toast.LENGTH_SHORT).show();
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
index c55518579..cf22416fb 100644
--- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
@@ -111,7 +111,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate
}
private void populateView() {
- setTitle(getString(R.string.trust_keys));
+ setTitle(getString(R.string.trust_omemo_fingerprints));
ownKeys.removeAllViews();
foreignKeys.removeAllViews();
boolean hasOwnKeys = false;
diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
index 3a163ba45..7734dc116 100644
--- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java
@@ -696,15 +696,15 @@ public abstract class XmppActivity extends Activity {
}
if (showTag) {
- keyType.setText(getString(R.string.axolotl_fingerprint));
+ keyType.setText(getString(R.string.omemo_fingerprint));
} else {
keyType.setVisibility(View.GONE);
}
if (highlight) {
keyType.setTextColor(getResources().getColor(R.color.accent));
- keyType.setText(getString(R.string.axolotl_fingerprint_selected_message));
+ keyType.setText(getString(R.string.omemo_fingerprint_selected_message));
} else {
- keyType.setText(getString(R.string.axolotl_fingerprint));
+ keyType.setText(getString(R.string.omemo_fingerprint));
}
key.setText(CryptoHelper.prettifyFingerprint(identityKey.getFingerprint()));
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index 7b4abe48c..323c67d6b 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -303,8 +303,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
final Spannable span = new SpannableString(privateMarker + " "
+ formattedBody);
- span.setSpan(new ForegroundColorSpan(activity
- .getSecondaryTextColor()), 0, privateMarker
+ span.setSpan(new ForegroundColorSpan(getMessageTextColor(type,false)), 0, privateMarker
.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
span.setSpan(new StyleSpan(Typeface.BOLD), 0,
privateMarker.length(),
@@ -396,10 +395,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
@Override
public void onClick(View v) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setDataAndType(activity.xmppConnectionService
- .getFileBackend().getJingleFileUri(message), "image/*");
- getContext().startActivity(intent);
+ openDownloadable(message);
}
});
viewHolder.image.setOnLongClickListener(openContextMenu);
diff --git a/src/main/java/eu/siacs/conversations/utils/FileUtils.java b/src/main/java/eu/siacs/conversations/utils/FileUtils.java
new file mode 100644
index 000000000..a13300d43
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/utils/FileUtils.java
@@ -0,0 +1,144 @@
+package eu.siacs.conversations.utils;
+
+import android.annotation.SuppressLint;
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+
+public class FileUtils {
+
+ /**
+ * Get a file path from a Uri. This will get the the path for Storage Access
+ * Framework Documents, as well as the _data field for the MediaStore and
+ * other file-based ContentProviders.
+ *
+ * @param context The context.
+ * @param uri The Uri to query.
+ * @author paulburke
+ */
+ @SuppressLint("NewApi")
+ public static String getPath(final Context context, final Uri uri) {
+
+ final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+
+ // DocumentProvider
+ if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
+ // ExternalStorageProvider
+ if (isExternalStorageDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ if ("primary".equalsIgnoreCase(type)) {
+ return Environment.getExternalStorageDirectory() + "/" + split[1];
+ }
+
+ // TODO handle non-primary volumes
+ }
+ // DownloadsProvider
+ else if (isDownloadsDocument(uri)) {
+
+ final String id = DocumentsContract.getDocumentId(uri);
+ final Uri contentUri = ContentUris.withAppendedId(
+ Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
+
+ return getDataColumn(context, contentUri, null, null);
+ }
+ // MediaProvider
+ else if (isMediaDocument(uri)) {
+ final String docId = DocumentsContract.getDocumentId(uri);
+ final String[] split = docId.split(":");
+ final String type = split[0];
+
+ Uri contentUri = null;
+ if ("image".equals(type)) {
+ contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+ } else if ("video".equals(type)) {
+ contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+ } else if ("audio".equals(type)) {
+ contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ }
+
+ final String selection = "_id=?";
+ final String[] selectionArgs = new String[]{
+ split[1]
+ };
+
+ return getDataColumn(context, contentUri, selection, selectionArgs);
+ }
+ }
+ // MediaStore (and general)
+ else if ("content".equalsIgnoreCase(uri.getScheme())) {
+ return getDataColumn(context, uri, null, null);
+ }
+ // File
+ else if ("file".equalsIgnoreCase(uri.getScheme())) {
+ return uri.getPath();
+ }
+
+ return null;
+ }
+
+ /**
+ * Get the value of the data column for this Uri. This is useful for
+ * MediaStore Uris, and other file-based ContentProviders.
+ *
+ * @param context The context.
+ * @param uri The Uri to query.
+ * @param selection (Optional) Filter used in the query.
+ * @param selectionArgs (Optional) Selection arguments used in the query.
+ * @return The value of the _data column, which is typically a file path.
+ */
+ public static String getDataColumn(Context context, Uri uri, String selection,
+ String[] selectionArgs) {
+
+ Cursor cursor = null;
+ final String column = "_data";
+ final String[] projection = {
+ column
+ };
+
+ try {
+ cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
+ null);
+ if (cursor != null && cursor.moveToFirst()) {
+ final int column_index = cursor.getColumnIndexOrThrow(column);
+ return cursor.getString(column_index);
+ }
+ } finally {
+ if (cursor != null)
+ cursor.close();
+ }
+ return null;
+ }
+
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is ExternalStorageProvider.
+ */
+ public static boolean isExternalStorageDocument(Uri uri) {
+ return "com.android.externalstorage.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is DownloadsProvider.
+ */
+ public static boolean isDownloadsDocument(Uri uri) {
+ return "com.android.providers.downloads.documents".equals(uri.getAuthority());
+ }
+
+ /**
+ * @param uri The Uri to check.
+ * @return Whether the Uri authority is MediaProvider.
+ */
+ public static boolean isMediaDocument(Uri uri) {
+ return "com.android.providers.media.documents".equals(uri.getAuthority());
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
index bf89ba816..5ac089766 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java
@@ -81,7 +81,6 @@ public class XmppConnection implements Runnable {
private static final int PACKET_IQ = 0;
private static final int PACKET_MESSAGE = 1;
private static final int PACKET_PRESENCE = 2;
- private final Context applicationContext;
protected Account account;
private final WakeLock wakeLock;
private Socket socket;
@@ -123,7 +122,6 @@ public class XmppConnection implements Runnable {
PowerManager.PARTIAL_WAKE_LOCK, account.getJid().toBareJid().toString());
tagWriter = new TagWriter();
mXmppConnectionService = service;
- applicationContext = service.getApplicationContext();
}
protected void changeStatus(final Account.State nextStatus) {
@@ -531,14 +529,6 @@ public class XmppConnection implements Runnable {
tagWriter.writeTag(startTLS);
}
- private SharedPreferences getPreferences() {
- return PreferenceManager.getDefaultSharedPreferences(applicationContext);
- }
-
- private boolean enableLegacySSL() {
- return getPreferences().getBoolean("enable_legacy_ssl", false);
- }
-
private void switchOverToTls(final Tag currentTag) throws XmlPullParserException, IOException {
tagReader.readTag();
try {
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
index e9ca66b7c..7b140842a 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java
@@ -5,6 +5,7 @@ import android.net.Uri;
import android.util.Log;
import android.util.Pair;
+import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -28,7 +29,6 @@ import eu.siacs.conversations.entities.TransferablePlaceholder;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.AbstractConnectionManager;
import eu.siacs.conversations.services.XmppConnectionService;
-import eu.siacs.conversations.utils.Xmlns;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.jid.Jid;
@@ -97,15 +97,13 @@ public class JingleConnection implements Transferable {
public void onFileTransmitted(DownloadableFile file) {
if (responder.equals(account.getJid())) {
sendSuccess();
+ mXmppConnectionService.getFileBackend().updateFileParams(message);
+ mXmppConnectionService.databaseBackend.createMessage(message);
+ mXmppConnectionService.markMessage(message,Message.STATUS_RECEIVED);
if (acceptedAutomatically) {
message.markUnread();
- JingleConnection.this.mXmppConnectionService
- .getNotificationService().push(message);
+ JingleConnection.this.mXmppConnectionService.getNotificationService().push(message);
}
- mXmppConnectionService.getFileBackend().updateFileParams(message);
- mXmppConnectionService.databaseBackend.createMessage(message);
- mXmppConnectionService.markMessage(message,
- Message.STATUS_RECEIVED);
} else {
if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
file.delete();
@@ -274,7 +272,7 @@ public class JingleConnection implements Transferable {
});
mergeCandidate(candidate);
} else {
- Log.d(Config.LOGTAG,"no primary candidate of our own was found");
+ Log.d(Config.LOGTAG, "no primary candidate of our own was found");
sendInitRequest();
}
}
@@ -393,7 +391,11 @@ public class JingleConnection implements Transferable {
}
}
this.mFileOutputStream = AbstractConnectionManager.createOutputStream(this.file,message.getEncryption() == Message.ENCRYPTION_AXOLOTL);
- this.file.setExpectedSize(size);
+ if (message.getEncryption() == Message.ENCRYPTION_OTR && Config.REPORT_WRONG_FILESIZE_IN_OTR_JINGLE) {
+ this.file.setExpectedSize((size / 16 + 1) * 16);
+ } else {
+ this.file.setExpectedSize(size);
+ }
Log.d(Config.LOGTAG, "receiving file: expecting size of " + this.file.getExpectedSize());
} else {
this.sendCancel();
@@ -412,26 +414,31 @@ public class JingleConnection implements Transferable {
content.setTransportId(this.transportId);
this.file = this.mXmppConnectionService.getFileBackend().getFile(message, false);
Pair<InputStream,Integer> pair;
- if (message.getEncryption() == Message.ENCRYPTION_OTR) {
- Conversation conversation = this.message.getConversation();
- if (!this.mXmppConnectionService.renewSymmetricKey(conversation)) {
- Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not set symmetric key");
- cancel();
+ try {
+ if (message.getEncryption() == Message.ENCRYPTION_OTR) {
+ Conversation conversation = this.message.getConversation();
+ if (!this.mXmppConnectionService.renewSymmetricKey(conversation)) {
+ Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not set symmetric key");
+ cancel();
+ }
+ this.file.setKeyAndIv(conversation.getSymmetricKey());
+ pair = AbstractConnectionManager.createInputStream(this.file, false);
+ this.file.setExpectedSize(pair.second);
+ content.setFileOffer(this.file, true);
+ } else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
+ this.file.setKey(mXmppAxolotlMessage.getInnerKey());
+ this.file.setIv(mXmppAxolotlMessage.getIV());
+ pair = AbstractConnectionManager.createInputStream(this.file, true);
+ this.file.setExpectedSize(pair.second);
+ content.setFileOffer(this.file, false).addChild(mXmppAxolotlMessage.toElement());
+ } else {
+ pair = AbstractConnectionManager.createInputStream(this.file, false);
+ this.file.setExpectedSize(pair.second);
+ content.setFileOffer(this.file, false);
}
- this.file.setKeyAndIv(conversation.getSymmetricKey());
- pair = AbstractConnectionManager.createInputStream(this.file,false);
- this.file.setExpectedSize(pair.second);
- content.setFileOffer(this.file, true);
- } else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) {
- this.file.setKey(mXmppAxolotlMessage.getInnerKey());
- this.file.setIv(mXmppAxolotlMessage.getIV());
- pair = AbstractConnectionManager.createInputStream(this.file,true);
- this.file.setExpectedSize(pair.second);
- content.setFileOffer(this.file, false).addChild(mXmppAxolotlMessage.toElement());
- } else {
- pair = AbstractConnectionManager.createInputStream(this.file,false);
- this.file.setExpectedSize(pair.second);
- content.setFileOffer(this.file, false);
+ } catch (FileNotFoundException e) {
+ cancel();
+ return;
}
this.mFileInputStream = pair.first;
this.transportId = this.mJingleConnectionManager.nextRandomId();
@@ -1012,4 +1019,8 @@ public class JingleConnection implements Transferable {
public int getProgress() {
return this.mProgress;
}
+
+ public AbstractConnectionManager getConnectionManager() {
+ return this.mJingleConnectionManager;
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
index 7545dd646..556395aef 100644
--- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
+++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java
@@ -1,5 +1,6 @@
package eu.siacs.conversations.xmpp.jingle;
+import android.os.PowerManager;
import android.util.Log;
import java.io.FileNotFoundException;
@@ -96,14 +97,15 @@ public class JingleSocks5Transport extends JingleTransport {
}
- public void send(final DownloadableFile file,
- final OnFileTransmissionStatusChanged callback) {
+ public void send(final DownloadableFile file, final OnFileTransmissionStatusChanged callback) {
new Thread(new Runnable() {
@Override
public void run() {
InputStream fileInputStream = null;
+ final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_send_"+connection.getSessionId());
try {
+ wakeLock.acquire();
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
fileInputStream = connection.getFileInputStream();
@@ -138,6 +140,7 @@ public class JingleSocks5Transport extends JingleTransport {
callback.onFileTransferAborted();
} finally {
FileBackend.close(fileInputStream);
+ wakeLock.release();
}
}
}).start();
@@ -150,7 +153,9 @@ public class JingleSocks5Transport extends JingleTransport {
@Override
public void run() {
OutputStream fileOutputStream = null;
+ final PowerManager.WakeLock wakeLock = connection.getConnectionManager().createWakeLock("jingle_receive_"+connection.getSessionId());
try {
+ wakeLock.acquire();
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.reset();
inputStream.skip(45);
@@ -166,7 +171,7 @@ public class JingleSocks5Transport extends JingleTransport {
double size = file.getExpectedSize();
long remainingSize = file.getExpectedSize();
byte[] buffer = new byte[8192];
- int count = buffer.length;
+ int count;
while (remainingSize > 0) {
count = inputStream.read(buffer);
if (count == -1) {
@@ -194,7 +199,9 @@ public class JingleSocks5Transport extends JingleTransport {
Log.d(Config.LOGTAG, connection.getAccount().getJid().toBareJid() + ": "+e.getMessage());
callback.onFileTransferAborted();
} finally {
+ wakeLock.release();
FileBackend.close(fileOutputStream);
+ FileBackend.close(inputStream);
}
}
}).start();
@@ -209,27 +216,9 @@ public class JingleSocks5Transport extends JingleTransport {
}
public void disconnect() {
- if (this.outputStream != null) {
- try {
- this.outputStream.close();
- } catch (IOException e) {
-
- }
- }
- if (this.inputStream != null) {
- try {
- this.inputStream.close();
- } catch (IOException e) {
-
- }
- }
- if (this.socket != null) {
- try {
- this.socket.close();
- } catch (IOException e) {
-
- }
- }
+ FileBackend.close(inputStream);
+ FileBackend.close(outputStream);
+ FileBackend.close(socket);
}
public boolean isEstablished() {