From 06cadab7ccd315c35f1325b4d95f0bf7a24082ea Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 30 Nov 2015 16:03:04 +0100 Subject: changed method signature of calcSampleSize --- src/main/java/eu/siacs/conversations/persistance/FileBackend.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 349e18c70..35b836a7a 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -493,7 +493,7 @@ public class FileBackend { return calcSampleSize(options, size); } - private int calcSampleSize(BitmapFactory.Options options, int size) { + public static int calcSampleSize(BitmapFactory.Options options, int size) { int height = options.outHeight; int width = options.outWidth; int inSampleSize = 1; -- cgit v1.2.3 From f0b1761ec3826b72fe3b20032b532dc5b1adfc1c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 28 Nov 2015 20:11:38 +0100 Subject: initial tor support --- src/main/java/eu/siacs/conversations/Config.java | 4 + .../eu/siacs/conversations/entities/Account.java | 50 ++++- .../conversations/http/HttpConnectionManager.java | 14 ++ .../conversations/http/HttpDownloadConnection.java | 21 +- .../conversations/http/HttpUploadConnection.java | 11 +- .../conversations/persistance/DatabaseBackend.java | 222 +++++++++++---------- .../services/XmppConnectionService.java | 11 +- .../conversations/ui/EditAccountActivity.java | 43 +++- .../siacs/conversations/ui/SettingsActivity.java | 2 + .../siacs/conversations/xmpp/XmppConnection.java | 18 +- .../xmpp/jingle/JingleSocks5Transport.java | 6 +- src/main/res/layout/activity_edit_account.xml | 54 ++++- src/main/res/menu/editaccount.xml | 5 + src/main/res/values/strings.xml | 8 + src/main/res/xml/preferences.xml | 7 + 15 files changed, 346 insertions(+), 130 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 046dd0d54..ddeba6119 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -2,6 +2,10 @@ package eu.siacs.conversations; import android.graphics.Bitmap; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; + import eu.siacs.conversations.xmpp.chatstate.ChatState; public final class Config { diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index b02db812c..3aa1675fa 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -2,6 +2,8 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.database.Cursor; +import android.os.Bundle; +import android.os.Parcelable; import android.os.SystemClock; import eu.siacs.conversations.crypto.PgpDecryptionService; @@ -13,6 +15,7 @@ import org.json.JSONObject; import java.security.PublicKey; import java.security.interfaces.DSAPublicKey; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -39,6 +42,8 @@ public class Account extends AbstractEntity { public static final String KEYS = "keys"; public static final String AVATAR = "avatar"; public static final String DISPLAY_NAME = "display_name"; + public static final String HOSTNAME = "hostname"; + public static final String PORT = "port"; public static final String PINNED_MECHANISM_KEY = "pinned_mechanism"; @@ -67,7 +72,20 @@ public class Account extends AbstractEntity { } } - public static enum State { + public ArrayList getHostnamePortBundles() { + ArrayList values = new ArrayList<>(); + Bundle hostPort = new Bundle(); + if (hostname != null && !hostname.isEmpty()) { + hostPort.putString("name", hostname); + } else { + hostPort.putString("name", getServer().toString()); + } + hostPort.putInt("port", port); + values.add(hostPort); + return values; + } + + public enum State { DISABLED, OFFLINE, CONNECTING, @@ -147,6 +165,8 @@ public class Account extends AbstractEntity { protected JSONObject keys = new JSONObject(); protected String avatar; protected String displayName = null; + protected String hostname = null; + protected int port = 5222; protected boolean online = false; private OtrService mOtrService = null; private AxolotlService axolotlService = null; @@ -164,12 +184,12 @@ public class Account extends AbstractEntity { public Account(final Jid jid, final String password) { this(java.util.UUID.randomUUID().toString(), jid, - password, 0, null, "", null, null); + password, 0, null, "", null, null, null, 5222); } public Account(final String uuid, final Jid jid, final String password, final int options, final String rosterVersion, final String keys, - final String avatar, String displayName) { + final String avatar, String displayName, String hostname, int port) { this.uuid = uuid; this.jid = jid; if (jid.isBareJid()) { @@ -185,6 +205,8 @@ public class Account extends AbstractEntity { } this.avatar = avatar; this.displayName = displayName; + this.hostname = hostname; + this.port = port; } public static Account fromCursor(final Cursor cursor) { @@ -201,7 +223,9 @@ public class Account extends AbstractEntity { cursor.getString(cursor.getColumnIndex(ROSTERVERSION)), cursor.getString(cursor.getColumnIndex(KEYS)), cursor.getString(cursor.getColumnIndex(AVATAR)), - cursor.getString(cursor.getColumnIndex(DISPLAY_NAME))); + cursor.getString(cursor.getColumnIndex(DISPLAY_NAME)), + cursor.getString(cursor.getColumnIndex(HOSTNAME)), + cursor.getInt(cursor.getColumnIndex(PORT))); } public boolean isOptionSet(final int option) { @@ -236,6 +260,22 @@ public class Account extends AbstractEntity { this.password = password; } + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public String getHostname() { + return this.hostname == null ? "" : this.hostname; + } + + public void setPort(int port) { + this.port = port; + } + + public int getPort() { + return this.port; + } + public State getStatus() { if (isOptionSet(OPTION_DISABLED)) { return State.DISABLED; @@ -314,6 +354,8 @@ public class Account extends AbstractEntity { values.put(ROSTERVERSION, rosterVersion); values.put(AVATAR, avatar); values.put(DISPLAY_NAME, displayName); + values.put(HOSTNAME, hostname); + values.put(PORT, port); return values; } diff --git a/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java b/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java index 90fbadfe3..6435fd477 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java @@ -1,7 +1,13 @@ package eu.siacs.conversations.http; +import android.os.Build; + import org.apache.http.conn.ssl.StrictHostnameVerifier; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.List; @@ -87,4 +93,12 @@ public class HttpConnectionManager extends AbstractConnectionManager { } catch (final KeyManagementException | NoSuchAlgorithmException ignored) { } } + + public Proxy getProxy() throws IOException { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + return new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(InetAddress.getLocalHost(), 9050)); + } else { + return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(InetAddress.getLocalHost(), 8118)); + } + } } diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index 96dee62c7..f371a2551 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -10,7 +10,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.MalformedURLException; +import java.net.Proxy; import java.net.URL; import java.util.Arrays; @@ -39,10 +42,12 @@ public class HttpDownloadConnection implements Transferable { private int mStatus = Transferable.STATUS_UNKNOWN; private boolean acceptedAutomatically = false; private int mProgress = 0; + private boolean mUseTor = false; public HttpDownloadConnection(HttpConnectionManager manager) { this.mHttpConnectionManager = manager; this.mXmppConnectionService = manager.getXmppConnectionService(); + this.mUseTor = mXmppConnectionService.useTorToConnect(); } @Override @@ -191,8 +196,15 @@ public class HttpDownloadConnection implements Transferable { try { Log.d(Config.LOGTAG, "retrieve file size. interactive:" + String.valueOf(interactive)); changeStatus(STATUS_CHECKING); - HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection(); + HttpURLConnection connection; + if (mUseTor) { + connection = (HttpURLConnection) mUrl.openConnection(mHttpConnectionManager.getProxy()); + } else { + connection = (HttpURLConnection) mUrl.openConnection(); + } connection.setRequestMethod("HEAD"); + Log.d(Config.LOGTAG,"url: "+connection.getURL().toString()); + Log.d(Config.LOGTAG,"connection: "+connection.toString()); connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getIdentityName()); if (connection instanceof HttpsURLConnection) { mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive); @@ -245,7 +257,12 @@ public class HttpDownloadConnection implements Transferable { PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_download_"+message.getUuid()); try { wakeLock.acquire(); - HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection(); + HttpURLConnection connection; + if (mUseTor) { + connection = (HttpURLConnection) mUrl.openConnection(mHttpConnectionManager.getProxy()); + } else { + connection = (HttpURLConnection) mUrl.openConnection(); + } if (connection instanceof HttpsURLConnection) { mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive); } diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java index 3aa288813..1e4b91021 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java @@ -12,7 +12,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.MalformedURLException; +import java.net.Proxy; import java.net.URL; import javax.net.ssl.HttpsURLConnection; @@ -46,6 +49,7 @@ public class HttpUploadConnection implements Transferable { private String mime; private URL mGetUrl; private URL mPutUrl; + private boolean mUseTor = false; private byte[] key = null; @@ -56,6 +60,7 @@ public class HttpUploadConnection implements Transferable { public HttpUploadConnection(HttpConnectionManager httpConnectionManager) { this.mHttpConnectionManager = httpConnectionManager; this.mXmppConnectionService = httpConnectionManager.getXmppConnectionService(); + this.mUseTor = mXmppConnectionService.useTorToConnect(); } @Override @@ -158,7 +163,11 @@ public class HttpUploadConnection implements Transferable { try { wakeLock.acquire(); Log.d(Config.LOGTAG, "uploading to " + mPutUrl.toString()); - connection = (HttpURLConnection) mPutUrl.openConnection(); + if (mUseTor) { + connection = (HttpURLConnection) mPutUrl.openConnection(mHttpConnectionManager.getProxy()); + } else { + connection = (HttpURLConnection) mPutUrl.openConnection(); + } if (connection instanceof HttpsURLConnection) { mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, true); } diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 0e133d192..8b74581cc 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -43,7 +43,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 19; + private static final int DATABASE_VERSION = 20; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -59,41 +59,41 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static String CREATE_PREKEYS_STATEMENT = "CREATE TABLE " + SQLiteAxolotlStore.PREKEY_TABLENAME + "(" - + SQLiteAxolotlStore.ACCOUNT + " TEXT, " - + SQLiteAxolotlStore.ID + " INTEGER, " - + SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" - + SQLiteAxolotlStore.ACCOUNT - + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " - + "UNIQUE( " + SQLiteAxolotlStore.ACCOUNT + ", " - + SQLiteAxolotlStore.ID - + ") ON CONFLICT REPLACE" - +");"; + + SQLiteAxolotlStore.ACCOUNT + " TEXT, " + + SQLiteAxolotlStore.ID + " INTEGER, " + + SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" + + SQLiteAxolotlStore.ACCOUNT + + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " + + "UNIQUE( " + SQLiteAxolotlStore.ACCOUNT + ", " + + SQLiteAxolotlStore.ID + + ") ON CONFLICT REPLACE" + + ");"; private static String CREATE_SIGNED_PREKEYS_STATEMENT = "CREATE TABLE " + SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME + "(" - + SQLiteAxolotlStore.ACCOUNT + " TEXT, " - + SQLiteAxolotlStore.ID + " INTEGER, " - + SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" - + SQLiteAxolotlStore.ACCOUNT - + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " - + "UNIQUE( " + SQLiteAxolotlStore.ACCOUNT + ", " - + SQLiteAxolotlStore.ID - + ") ON CONFLICT REPLACE"+ + + SQLiteAxolotlStore.ACCOUNT + " TEXT, " + + SQLiteAxolotlStore.ID + " INTEGER, " + + SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" + + SQLiteAxolotlStore.ACCOUNT + + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " + + "UNIQUE( " + SQLiteAxolotlStore.ACCOUNT + ", " + + SQLiteAxolotlStore.ID + + ") ON CONFLICT REPLACE" + ");"; private static String CREATE_SESSIONS_STATEMENT = "CREATE TABLE " + SQLiteAxolotlStore.SESSION_TABLENAME + "(" - + SQLiteAxolotlStore.ACCOUNT + " TEXT, " - + SQLiteAxolotlStore.NAME + " TEXT, " - + SQLiteAxolotlStore.DEVICE_ID + " INTEGER, " - + SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" - + SQLiteAxolotlStore.ACCOUNT - + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " - + "UNIQUE( " + SQLiteAxolotlStore.ACCOUNT + ", " - + SQLiteAxolotlStore.NAME + ", " - + SQLiteAxolotlStore.DEVICE_ID - + ") ON CONFLICT REPLACE" - +");"; + + SQLiteAxolotlStore.ACCOUNT + " TEXT, " + + SQLiteAxolotlStore.NAME + " TEXT, " + + SQLiteAxolotlStore.DEVICE_ID + " INTEGER, " + + SQLiteAxolotlStore.KEY + " TEXT, FOREIGN KEY(" + + SQLiteAxolotlStore.ACCOUNT + + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " + + "UNIQUE( " + SQLiteAxolotlStore.ACCOUNT + ", " + + SQLiteAxolotlStore.NAME + ", " + + SQLiteAxolotlStore.DEVICE_ID + + ") ON CONFLICT REPLACE" + + ");"; private static String CREATE_IDENTITIES_STATEMENT = "CREATE TABLE " + SQLiteAxolotlStore.IDENTITIES_TABLENAME + "(" @@ -106,10 +106,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { + SQLiteAxolotlStore.ACCOUNT + ") REFERENCES " + Account.TABLENAME + "(" + Account.UUID + ") ON DELETE CASCADE, " + "UNIQUE( " + SQLiteAxolotlStore.ACCOUNT + ", " - + SQLiteAxolotlStore.NAME + ", " - + SQLiteAxolotlStore.FINGERPRINT + + SQLiteAxolotlStore.NAME + ", " + + SQLiteAxolotlStore.FINGERPRINT + ") ON CONFLICT IGNORE" - +");"; + + ");"; private DatabaseBackend(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); @@ -124,7 +124,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + Account.DISPLAY_NAME + " TEXT, " + Account.ROSTERVERSION + " TEXT," + Account.OPTIONS + " NUMBER, " + Account.AVATAR + " TEXT, " + Account.KEYS - + " TEXT)"); + + " TEXT, " + Account.HOSTNAME + " TEXT, " + Account.PORT + " NUMBER DEFAULT 5222)"); db.execSQL("create table " + Conversation.TABLENAME + " (" + Conversation.UUID + " TEXT PRIMARY KEY, " + Conversation.NAME + " TEXT, " + Conversation.CONTACT + " TEXT, " @@ -202,23 +202,23 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (oldVersion < 11 && newVersion >= 11) { db.execSQL("ALTER TABLE " + Contact.TABLENAME + " ADD COLUMN " + Contact.GROUPS + " TEXT"); - db.execSQL("delete from "+Contact.TABLENAME); - db.execSQL("update "+Account.TABLENAME+" set "+Account.ROSTERVERSION+" = NULL"); + db.execSQL("delete from " + Contact.TABLENAME); + db.execSQL("update " + Account.TABLENAME + " set " + Account.ROSTERVERSION + " = NULL"); } if (oldVersion < 12 && newVersion >= 12) { db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.SERVER_MSG_ID + " TEXT"); } if (oldVersion < 13 && newVersion >= 13) { - db.execSQL("delete from "+Contact.TABLENAME); - db.execSQL("update "+Account.TABLENAME+" set "+Account.ROSTERVERSION+" = NULL"); + db.execSQL("delete from " + Contact.TABLENAME); + db.execSQL("update " + Account.TABLENAME + " set " + Account.ROSTERVERSION + " = NULL"); } if (oldVersion < 14 && newVersion >= 14) { // migrate db to new, canonicalized JID domainpart representation // Conversation table Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME, new String[0]); - while(cursor.moveToNext()) { + while (cursor.moveToNext()) { String newJid; try { newJid = Jid.fromString( @@ -226,8 +226,8 @@ public class DatabaseBackend extends SQLiteOpenHelper { ).toString(); } catch (InvalidJidException ignored) { Log.e(Config.LOGTAG, "Failed to migrate Conversation CONTACTJID " - +cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) - +": " + ignored +". Skipping..."); + + cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID)) + + ": " + ignored + ". Skipping..."); continue; } @@ -236,14 +236,14 @@ public class DatabaseBackend extends SQLiteOpenHelper { cursor.getString(cursor.getColumnIndex(Conversation.UUID)), }; db.execSQL("update " + Conversation.TABLENAME - + " set " + Conversation.CONTACTJID + " = ? " + + " set " + Conversation.CONTACTJID + " = ? " + " where " + Conversation.UUID + " = ?", updateArgs); } cursor.close(); // Contact table cursor = db.rawQuery("select * from " + Contact.TABLENAME, new String[0]); - while(cursor.moveToNext()) { + while (cursor.moveToNext()) { String newJid; try { newJid = Jid.fromString( @@ -251,8 +251,8 @@ public class DatabaseBackend extends SQLiteOpenHelper { ).toString(); } catch (InvalidJidException ignored) { Log.e(Config.LOGTAG, "Failed to migrate Contact JID " - +cursor.getString(cursor.getColumnIndex(Contact.JID)) - +": " + ignored +". Skipping..."); + + cursor.getString(cursor.getColumnIndex(Contact.JID)) + + ": " + ignored + ". Skipping..."); continue; } @@ -270,7 +270,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { // Account table cursor = db.rawQuery("select * from " + Account.TABLENAME, new String[0]); - while(cursor.moveToNext()) { + while (cursor.moveToNext()) { String newServer; try { newServer = Jid.fromParts( @@ -280,8 +280,8 @@ public class DatabaseBackend extends SQLiteOpenHelper { ).getDomainpart(); } catch (InvalidJidException ignored) { Log.e(Config.LOGTAG, "Failed to migrate Account SERVER " - +cursor.getString(cursor.getColumnIndex(Account.SERVER)) - +": " + ignored +". Skipping..."); + + cursor.getString(cursor.getColumnIndex(Account.SERVER)) + + ": " + ignored + ". Skipping..."); continue; } @@ -295,7 +295,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { } cursor.close(); } - if (oldVersion < 15 && newVersion >= 15) { + if (oldVersion < 15 && newVersion >= 15) { recreateAxolotlDb(db); db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.FINGERPRINT + " TEXT"); @@ -305,7 +305,11 @@ public class DatabaseBackend extends SQLiteOpenHelper { + Message.CARBON + " INTEGER"); } if (oldVersion < 19 && newVersion >= 19) { - db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN "+ Account.DISPLAY_NAME+ " TEXT"); + db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.DISPLAY_NAME + " TEXT"); + } + if (oldVersion < 20 && newVersion >= 20) { + db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.HOSTNAME + " TEXT"); + db.execSQL("ALTER TABLE " + Account.TABLENAME + " ADD COLUMN " + Account.PORT + " NUMBER DEFAULT 5222"); } /* Any migrations that alter the Account table need to happen BEFORE this migration, as it * depends on account de-serialization. @@ -314,7 +318,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { List accounts = getAccounts(db); for (Account account : accounts) { String ownDeviceIdString = account.getKey(SQLiteAxolotlStore.JSONKEY_REGISTRATION_ID); - if ( ownDeviceIdString == null ) { + if (ownDeviceIdString == null) { continue; } int ownDeviceId = Integer.valueOf(ownDeviceIdString); @@ -324,12 +328,12 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (identityKeyPair != null) { setIdentityKeyTrust(db, account, identityKeyPair.getPublicKey().getFingerprint().replaceAll("\\s", ""), XmppAxolotlSession.Trust.TRUSTED); } else { - Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not load own identity key pair"); + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not load own identity key pair"); } } } if (oldVersion < 18 && newVersion >= 18) { - db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN "+ Message.READ+ " NUMBER DEFAULT 1"); + db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.READ + " NUMBER DEFAULT 1"); } } @@ -374,7 +378,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public CopyOnWriteArrayList getConversations(int status) { CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(); SQLiteDatabase db = this.getReadableDatabase(); - String[] selectionArgs = { Integer.toString(status) }; + String[] selectionArgs = {Integer.toString(status)}; Cursor cursor = db.rawQuery("select * from " + Conversation.TABLENAME + " where " + Conversation.STATUS + " = ? order by " + Conversation.CREATED + " desc", selectionArgs); @@ -390,20 +394,20 @@ public class DatabaseBackend extends SQLiteOpenHelper { } public ArrayList getMessages(Conversation conversation, int limit, - long timestamp) { + long timestamp) { ArrayList list = new ArrayList<>(); SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor; if (timestamp == -1) { - String[] selectionArgs = { conversation.getUuid() }; + String[] selectionArgs = {conversation.getUuid()}; cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION + "=?", selectionArgs, null, null, Message.TIME_SENT + " DESC", String.valueOf(limit)); } else { - String[] selectionArgs = { conversation.getUuid(), - Long.toString(timestamp) }; + String[] selectionArgs = {conversation.getUuid(), + Long.toString(timestamp)}; cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION - + "=? and " + Message.TIME_SENT + " getMessagesIterable(final Conversation conversation){ + public Iterable getMessagesIterable(final Conversation conversation) { return new Iterable() { @Override public Iterator iterator() { - class MessageIterator implements Iterator{ + class MessageIterator implements Iterator { SQLiteDatabase db = getReadableDatabase(); - String[] selectionArgs = { conversation.getUuid() }; + String[] selectionArgs = {conversation.getUuid()}; Cursor cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION + "=?", selectionArgs, null, null, Message.TIME_SENT + " ASC", null); @@ -458,10 +462,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { public Conversation findConversation(final Account account, final Jid contactJid) { SQLiteDatabase db = this.getReadableDatabase(); - String[] selectionArgs = { account.getUuid(), + String[] selectionArgs = {account.getUuid(), contactJid.toBareJid().toString() + "/%", contactJid.toBareJid().toString() - }; + }; Cursor cursor = db.query(Conversation.TABLENAME, null, Conversation.ACCOUNT + "=? AND (" + Conversation.CONTACTJID + " like ? OR " + Conversation.CONTACTJID + "=?)", selectionArgs, null, null, null); @@ -475,7 +479,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public void updateConversation(final Conversation conversation) { final SQLiteDatabase db = this.getWritableDatabase(); - final String[] args = { conversation.getUuid() }; + final String[] args = {conversation.getUuid()}; db.update(Conversation.TABLENAME, conversation.getContentValues(), Conversation.UUID + "=?", args); } @@ -498,14 +502,14 @@ public class DatabaseBackend extends SQLiteOpenHelper { public void updateAccount(Account account) { SQLiteDatabase db = this.getWritableDatabase(); - String[] args = { account.getUuid() }; + String[] args = {account.getUuid()}; db.update(Account.TABLENAME, account.getContentValues(), Account.UUID + "=?", args); } public void deleteAccount(Account account) { SQLiteDatabase db = this.getWritableDatabase(); - String[] args = { account.getUuid() }; + String[] args = {account.getUuid()}; db.delete(Account.TABLENAME, Account.UUID + "=?", args); } @@ -534,7 +538,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public void updateMessage(Message message) { SQLiteDatabase db = this.getWritableDatabase(); - String[] args = { message.getUuid() }; + String[] args = {message.getUuid()}; db.update(Message.TABLENAME, message.getContentValues(), Message.UUID + "=?", args); } @@ -542,7 +546,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public void readRoster(Roster roster) { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor; - String args[] = { roster.getAccount().getUuid() }; + String args[] = {roster.getAccount().getUuid()}; cursor = db.query(Contact.TABLENAME, null, Contact.ACCOUNT + "=?", args, null, null, null); while (cursor.moveToNext()) { roster.initContact(Contact.fromCursor(cursor)); @@ -558,7 +562,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.insert(Contact.TABLENAME, null, contact.getContentValues()); } else { String where = Contact.ACCOUNT + "=? AND " + Contact.JID + "=?"; - String[] whereArgs = { account.getUuid(), contact.getJid().toString() }; + String[] whereArgs = {account.getUuid(), contact.getJid().toString()}; db.delete(Contact.TABLENAME, where, whereArgs); } } @@ -568,19 +572,19 @@ public class DatabaseBackend extends SQLiteOpenHelper { public void deleteMessage(Message message) { SQLiteDatabase db = this.getWritableDatabase(); - String[] args = { message.getUuid() }; + String[] args = {message.getUuid()}; db.delete(Message.TABLENAME, Message.UUID + "=?", args); } public void deleteMessagesInConversation(Conversation conversation) { SQLiteDatabase db = this.getWritableDatabase(); - String[] args = { conversation.getUuid() }; + String[] args = {conversation.getUuid()}; db.delete(Message.TABLENAME, Message.CONVERSATION + "=?", args); } public Conversation findConversationByUuid(String conversationUuid) { SQLiteDatabase db = this.getReadableDatabase(); - String[] selectionArgs = { conversationUuid }; + String[] selectionArgs = {conversationUuid}; Cursor cursor = db.query(Conversation.TABLENAME, null, Conversation.UUID + "=?", selectionArgs, null, null, null); if (cursor.getCount() == 0) { @@ -594,7 +598,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public Message findMessageByUuid(String messageUuid) { SQLiteDatabase db = this.getReadableDatabase(); - String[] selectionArgs = { messageUuid }; + String[] selectionArgs = {messageUuid}; Cursor cursor = db.query(Message.TABLENAME, null, Message.UUID + "=?", selectionArgs, null, null, null); if (cursor.getCount() == 0) { @@ -608,7 +612,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { public Account findAccountByUuid(String accountUuid) { SQLiteDatabase db = this.getReadableDatabase(); - String[] selectionArgs = { accountUuid }; + String[] selectionArgs = {accountUuid}; Cursor cursor = db.query(Account.TABLENAME, null, Account.UUID + "=?", selectionArgs, null, null, null); if (cursor.getCount() == 0) { @@ -624,9 +628,9 @@ public class DatabaseBackend extends SQLiteOpenHelper { ArrayList list = new ArrayList<>(); SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor; - String[] selectionArgs = { conversation.getUuid(), String.valueOf(Message.TYPE_IMAGE) }; - cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION - + "=? AND "+Message.TYPE+"=?", selectionArgs, null, null,null); + String[] selectionArgs = {conversation.getUuid(), String.valueOf(Message.TYPE_IMAGE)}; + cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION + + "=? AND " + Message.TYPE + "=?", selectionArgs, null, null, null); if (cursor.getCount() > 0) { cursor.moveToLast(); do { @@ -659,10 +663,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { public SessionRecord loadSession(Account account, AxolotlAddress contact) { SessionRecord session = null; Cursor cursor = getCursorForSession(account, contact); - if(cursor.getCount() != 0) { + if (cursor.getCount() != 0) { cursor.moveToFirst(); try { - session = new SessionRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),Base64.DEFAULT)); + session = new SessionRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT)); } catch (IOException e) { cursor.close(); throw new AssertionError(e); @@ -689,7 +693,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { selectionArgs, null, null, null); - while(cursor.moveToNext()) { + while (cursor.moveToNext()) { devices.add(cursor.getInt( cursor.getColumnIndex(SQLiteAxolotlStore.DEVICE_ID))); } @@ -710,7 +714,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { ContentValues values = new ContentValues(); values.put(SQLiteAxolotlStore.NAME, contact.getName()); values.put(SQLiteAxolotlStore.DEVICE_ID, contact.getDeviceId()); - values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(session.serialize(),Base64.DEFAULT)); + values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(session.serialize(), Base64.DEFAULT)); values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid()); db.insert(SQLiteAxolotlStore.SESSION_TABLENAME, null, values); } @@ -757,11 +761,11 @@ public class DatabaseBackend extends SQLiteOpenHelper { public PreKeyRecord loadPreKey(Account account, int preKeyId) { PreKeyRecord record = null; Cursor cursor = getCursorForPreKey(account, preKeyId); - if(cursor.getCount() != 0) { + if (cursor.getCount() != 0) { cursor.moveToFirst(); try { - record = new PreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),Base64.DEFAULT)); - } catch (IOException e ) { + record = new PreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT)); + } catch (IOException e) { throw new AssertionError(e); } } @@ -780,7 +784,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(SQLiteAxolotlStore.ID, record.getId()); - values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(),Base64.DEFAULT)); + values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(), Base64.DEFAULT)); values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid()); db.insert(SQLiteAxolotlStore.PREKEY_TABLENAME, null, values); } @@ -810,11 +814,11 @@ public class DatabaseBackend extends SQLiteOpenHelper { public SignedPreKeyRecord loadSignedPreKey(Account account, int signedPreKeyId) { SignedPreKeyRecord record = null; Cursor cursor = getCursorForSignedPreKey(account, signedPreKeyId); - if(cursor.getCount() != 0) { + if (cursor.getCount() != 0) { cursor.moveToFirst(); try { - record = new SignedPreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),Base64.DEFAULT)); - } catch (IOException e ) { + record = new SignedPreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT)); + } catch (IOException e) { throw new AssertionError(e); } } @@ -833,7 +837,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { selectionArgs, null, null, null); - while(cursor.moveToNext()) { + while (cursor.moveToNext()) { try { prekeys.add(new SignedPreKeyRecord(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT))); } catch (IOException ignored) { @@ -854,7 +858,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { SQLiteDatabase db = this.getWritableDatabase(); ContentValues values = new ContentValues(); values.put(SQLiteAxolotlStore.ID, record.getId()); - values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(),Base64.DEFAULT)); + values.put(SQLiteAxolotlStore.KEY, Base64.encodeToString(record.serialize(), Base64.DEFAULT)); values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid()); db.insert(SQLiteAxolotlStore.SIGNED_PREKEY_TABLENAME, null, values); } @@ -874,7 +878,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { } private Cursor getIdentityKeyCursor(SQLiteDatabase db, Account account, String name, boolean own) { - return getIdentityKeyCursor(db, account, name, own, null); + return getIdentityKeyCursor(db, account, name, own, null); } private Cursor getIdentityKeyCursor(Account account, String fingerprint) { @@ -892,16 +896,16 @@ public class DatabaseBackend extends SQLiteOpenHelper { ArrayList selectionArgs = new ArrayList<>(4); selectionArgs.add(account.getUuid()); String selectionString = SQLiteAxolotlStore.ACCOUNT + " = ?"; - if (name != null){ + if (name != null) { selectionArgs.add(name); selectionString += " AND " + SQLiteAxolotlStore.NAME + " = ?"; } - if (fingerprint != null){ + if (fingerprint != null) { selectionArgs.add(fingerprint); selectionString += " AND " + SQLiteAxolotlStore.FINGERPRINT + " = ?"; } - if (own != null){ - selectionArgs.add(own?"1":"0"); + if (own != null) { + selectionArgs.add(own ? "1" : "0"); selectionString += " AND " + SQLiteAxolotlStore.OWN + " = ?"; } Cursor cursor = db.query(SQLiteAxolotlStore.IDENTITIES_TABLENAME, @@ -922,12 +926,12 @@ public class DatabaseBackend extends SQLiteOpenHelper { String name = account.getJid().toBareJid().toString(); IdentityKeyPair identityKeyPair = null; Cursor cursor = getIdentityKeyCursor(db, account, name, true); - if(cursor.getCount() != 0) { + if (cursor.getCount() != 0) { cursor.moveToFirst(); try { - identityKeyPair = new IdentityKeyPair(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),Base64.DEFAULT)); + identityKeyPair = new IdentityKeyPair(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT)); } catch (InvalidKeyException e) { - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Encountered invalid IdentityKey in database for account" + account.getJid().toBareJid() + ", address: " + name); + Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Encountered invalid IdentityKey in database for account" + account.getJid().toBareJid() + ", address: " + name); } } cursor.close(); @@ -943,16 +947,16 @@ public class DatabaseBackend extends SQLiteOpenHelper { Set identityKeys = new HashSet<>(); Cursor cursor = getIdentityKeyCursor(account, name, false); - while(cursor.moveToNext()) { - if ( trust != null && + while (cursor.moveToNext()) { + if (trust != null && cursor.getInt(cursor.getColumnIndex(SQLiteAxolotlStore.TRUSTED)) != trust.getCode()) { continue; } try { - identityKeys.add(new IdentityKey(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)),Base64.DEFAULT),0)); + identityKeys.add(new IdentityKey(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT), 0)); } catch (InvalidKeyException e) { - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+"Encountered invalid IdentityKey in database for account"+account.getJid().toBareJid()+", address: "+name); + Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Encountered invalid IdentityKey in database for account" + account.getJid().toBareJid() + ", address: " + name); } } cursor.close(); @@ -970,8 +974,8 @@ public class DatabaseBackend extends SQLiteOpenHelper { }; return DatabaseUtils.queryNumEntries(db, SQLiteAxolotlStore.IDENTITIES_TABLENAME, SQLiteAxolotlStore.ACCOUNT + " = ?" - + " AND " + SQLiteAxolotlStore.NAME + " = ?" - + " AND (" + SQLiteAxolotlStore.TRUSTED + " = ? OR "+SQLiteAxolotlStore.TRUSTED+ " = ?)", + + " AND " + SQLiteAxolotlStore.NAME + " = ?" + + " AND (" + SQLiteAxolotlStore.TRUSTED + " = ? OR " + SQLiteAxolotlStore.TRUSTED + " = ?)", args ); } @@ -1018,7 +1022,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { values.put(SQLiteAxolotlStore.TRUSTED, trust.getCode()); int rows = db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME, values, SQLiteAxolotlStore.ACCOUNT + " = ? AND " - + SQLiteAxolotlStore.FINGERPRINT + " = ? ", + + SQLiteAxolotlStore.FINGERPRINT + " = ? ", selectionArgs); return rows == 1; } @@ -1036,7 +1040,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { } public void recreateAxolotlDb(SQLiteDatabase db) { - Log.d(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+">>> (RE)CREATING AXOLOTL DATABASE <<<"); + Log.d(Config.LOGTAG, AxolotlService.LOGPREFIX + " : " + ">>> (RE)CREATING AXOLOTL DATABASE <<<"); db.execSQL("DROP TABLE IF EXISTS " + SQLiteAxolotlStore.SESSION_TABLENAME); db.execSQL(CREATE_SESSIONS_STATEMENT); db.execSQL("DROP TABLE IF EXISTS " + SQLiteAxolotlStore.PREKEY_TABLENAME); @@ -1046,12 +1050,12 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.execSQL("DROP TABLE IF EXISTS " + SQLiteAxolotlStore.IDENTITIES_TABLENAME); db.execSQL(CREATE_IDENTITIES_STATEMENT); } - + public void wipeAxolotlDb(Account account) { String accountName = account.getUuid(); - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account)+">>> WIPING AXOLOTL DATABASE FOR ACCOUNT " + accountName + " <<<"); + Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + ">>> WIPING AXOLOTL DATABASE FOR ACCOUNT " + accountName + " <<<"); SQLiteDatabase db = this.getWritableDatabase(); - String[] deleteArgs= { + String[] deleteArgs = { accountName }; db.delete(SQLiteAxolotlStore.SESSION_TABLENAME, diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 4bde7fb6c..30f8c687a 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2106,8 +2106,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public void createContact(Contact contact) { - SharedPreferences sharedPref = getPreferences(); - boolean autoGrant = sharedPref.getBoolean("grant_new_contacts", true); + boolean autoGrant = getPreferences().getBoolean("grant_new_contacts", true); if (autoGrant) { contact.setOption(Contact.Options.PREEMPTIVE_GRANT); contact.setOption(Contact.Options.ASKING); @@ -2534,10 +2533,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa .getDefaultSharedPreferences(getApplicationContext()); } - public boolean forceEncryption() { - return getPreferences().getBoolean("force_encryption", false); - } - public boolean confirmMessages() { return getPreferences().getBoolean("confirm_messages", true); } @@ -2554,6 +2549,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return getPreferences().getBoolean("indicate_received", false); } + public boolean useTorToConnect() { + return getPreferences().getBoolean("use_tor", false); + } + public int unreadCount() { int count = 0; for (Conversation conversation : getConversations()) { diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 5fe5848c0..bbdc75248 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -82,10 +82,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate private ImageButton mRegenerateAxolotlKeyButton; private LinearLayout keys; private LinearLayout keysCard; + private LinearLayout mNamePort; + private EditText mHostname; + private EditText mPort; private AlertDialog mCaptchaDialog = null; private Jid jidToEdit; private boolean mInitMode = false; + private boolean mUseTor = false; private Account mAccount; private String messageFingerprint; @@ -136,6 +140,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } final String password = mPassword.getText().toString(); final String passwordConfirm = mPasswordConfirm.getText().toString(); + final String hostname = mHostname.getText().toString(); + final String port = mPort.getText().toString(); if (registerNewAccount) { if (!password.equals(passwordConfirm)) { mPasswordConfirm.setError(getString(R.string.passwords_do_not_match)); @@ -149,6 +155,25 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate mPasswordConfirm.setError(null); mAccount.setPassword(password); mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); + if (hostname.contains(" ")) { + mHostname.setError(getString(R.string.not_valid_hostname)); + mHostname.requestFocus(); + return; + } + mAccount.setHostname(hostname); + try { + int numericPort = Integer.parseInt(port); + if (numericPort < 0 || numericPort > 65535) { + mPort.setError(getString(R.string.not_a_valid_port)); + mPort.requestFocus(); + return; + } + mAccount.setPort(numericPort); + } catch (NumberFormatException e) { + mPort.setError(getString(R.string.not_a_valid_port)); + mPort.requestFocus(); + return; + } xmppConnectionService.updateAccount(mAccount); } else { if (xmppConnectionService.findAccountByJid(jid) != null) { @@ -319,7 +344,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate unmodified = this.mAccount.getJid().toBareJid().toString(); } return !unmodified.equals(this.mAccountJid.getText().toString()) || - !this.mAccount.getPassword().equals(this.mPassword.getText().toString()); + !this.mAccount.getPassword().equals(this.mPassword.getText().toString()) || + !this.mAccount.getHostname().equals(this.mHostname.getText().toString()) || + !String.valueOf(this.mAccount.getPort()).equals(this.mPort.getText().toString()); } @Override @@ -368,6 +395,12 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mRegenerateAxolotlKeyButton = (ImageButton) findViewById(R.id.action_regenerate_axolotl_key); this.keysCard = (LinearLayout) findViewById(R.id.other_device_keys_card); this.keys = (LinearLayout) findViewById(R.id.other_device_keys); + this.mNamePort = (LinearLayout) findViewById(R.id.name_port); + this.mHostname = (EditText) findViewById(R.id.hostname); + this.mHostname.addTextChangedListener(mTextWatcher); + this.mPort = (EditText) findViewById(R.id.port); + this.mPort.setText("5222"); + this.mPort.addTextChangedListener(mTextWatcher); this.mSaveButton = (Button) findViewById(R.id.save_button); this.mCancelButton = (Button) findViewById(R.id.cancel_button); this.mSaveButton.setOnClickListener(this.mSaveButtonClickListener); @@ -448,6 +481,8 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } } } + this.mUseTor = getPreferences().getBoolean("use_tor", false); + this.mNamePort.setVisibility(mUseTor ? View.VISIBLE : View.GONE); } @Override @@ -529,6 +564,12 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mAccountJid.getEditableText().append(this.mAccount.getJid().toBareJid().toString()); } this.mPassword.setText(this.mAccount.getPassword()); + this.mHostname.setText(""); + this.mHostname.getEditableText().append(this.mAccount.getHostname()); + this.mPort.setText(""); + this.mPort.getEditableText().append(String.valueOf(this.mAccount.getPort())); + this.mNamePort.setVisibility(mUseTor ? View.VISIBLE : View.GONE); + } if (!mInitMode) { this.mAvatar.setVisibility(View.VISIBLE); diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index eca7c0c14..7118eb5a8 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -160,6 +160,8 @@ public class SettingsActivity extends XmppActivity implements } else if (name.equals("dont_trust_system_cas")) { xmppConnectionService.updateMemorizingTrustmanager(); reconnectAccounts(); + } else if (name.equals("use_tor")) { + reconnectAccounts(); } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 16b3f78b4..dec3cad6d 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -27,6 +27,7 @@ import java.net.ConnectException; import java.net.IDN; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.Proxy; import java.net.Socket; import java.net.UnknownHostException; import java.net.URL; @@ -233,16 +234,23 @@ public class XmppConnection implements Runnable { tagReader = new XmlReader(wakeLock); tagWriter = new TagWriter(); this.changeStatus(Account.State.CONNECTING); + final boolean useTor = mXmppConnectionService.useTorToConnect(); + final Proxy TOR_PROXY = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(InetAddress.getLocalHost(), 9050)); if (DNSHelper.isIp(account.getServer().toString())) { - socket = new Socket(); + socket = useTor ? new Socket(TOR_PROXY) : new Socket(); try { socket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000); } catch (IOException e) { throw new UnknownHostException(); } } else { - final Bundle result = DNSHelper.getSRVRecord(account.getServer(),mXmppConnectionService); - final ArrayList values = result.getParcelableArrayList("values"); + final ArrayList values; + if (useTor) { + values = account.getHostnamePortBundles(); + } else { + final Bundle result = DNSHelper.getSRVRecord(account.getServer(),mXmppConnectionService); + values = result.getParcelableArrayList("values"); + } int i = 0; boolean socketError = true; while (socketError && values.size() > i) { @@ -269,11 +277,11 @@ public class XmppConnection implements Runnable { + ": using values from dns " + srvRecordServer + ":" + srvRecordPort); } - socket = new Socket(); + socket = useTor ? new Socket(TOR_PROXY) : new Socket(); socket.connect(addr, Config.SOCKET_TIMEOUT * 1000); socketError = false; } catch (final Throwable e) { - Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); + Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage() +"("+e.getClass().getName()+")"); i++; } } 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 556395aef..74306ce3d 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -7,7 +7,9 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.Proxy; import java.net.Socket; import java.net.SocketAddress; import java.net.UnknownHostException; @@ -59,7 +61,9 @@ public class JingleSocks5Transport extends JingleTransport { @Override public void run() { try { - socket = new Socket(); + final boolean useTor = connection.getConnectionManager().getXmppConnectionService().useTorToConnect(); + final Proxy TOR_PROXY = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(InetAddress.getLocalHost(), 9050)); + socket = useTor ? new Socket(TOR_PROXY) : new Socket(); SocketAddress address = new InetSocketAddress(candidate.getHost(),candidate.getPort()); socket.connect(address,Config.SOCKET_TIMEOUT * 1000); inputStream = socket.getInputStream(); diff --git a/src/main/res/layout/activity_edit_account.xml b/src/main/res/layout/activity_edit_account.xml index 8d60f5f1c..73395bba9 100644 --- a/src/main/res/layout/activity_edit_account.xml +++ b/src/main/res/layout/activity_edit_account.xml @@ -78,7 +78,59 @@ android:textColorHint="@color/black54" android:textSize="?attr/TextSizeBody" /> - + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index fa484a825..eaff35341 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -540,4 +540,12 @@ Error fetching OMEMO key! Verified OMEMO key with certificate! Your device does not support the selection of client certificates! + Connection options + Connect via Tor + Tunnel all connections through the TOR network. Requires Orbot + Hostname + Port + Server- or .onion-Address + This is not a valid port number + This is not a valid hostname diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index f05738ac5..6ef3c0291 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -147,6 +147,13 @@ android:summary="@string/pref_remove_trusted_certificates_summary" android:title="@string/pref_remove_trusted_certificates_title"/> + + + Date: Sun, 29 Nov 2015 15:44:45 +0100 Subject: do socks5 connect manually --- .../eu/siacs/conversations/entities/Account.java | 20 ++------- .../conversations/ui/EditAccountActivity.java | 52 +++++++++++++--------- .../siacs/conversations/xmpp/XmppConnection.java | 48 ++++++++++++++------ 3 files changed, 69 insertions(+), 51 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 3aa1675fa..062c0d253 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -2,8 +2,6 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.database.Cursor; -import android.os.Bundle; -import android.os.Parcelable; import android.os.SystemClock; import eu.siacs.conversations.crypto.PgpDecryptionService; @@ -15,7 +13,6 @@ import org.json.JSONObject; import java.security.PublicKey; import java.security.interfaces.DSAPublicKey; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -72,19 +69,6 @@ public class Account extends AbstractEntity { } } - public ArrayList getHostnamePortBundles() { - ArrayList values = new ArrayList<>(); - Bundle hostPort = new Bundle(); - if (hostname != null && !hostname.isEmpty()) { - hostPort.putString("name", hostname); - } else { - hostPort.putString("name", getServer().toString()); - } - hostPort.putInt("port", port); - values.add(hostPort); - return values; - } - public enum State { DISABLED, OFFLINE, @@ -268,6 +252,10 @@ public class Account extends AbstractEntity { return this.hostname == null ? "" : this.hostname; } + public boolean isOnion() { + return getServer().toString().toLowerCase().endsWith(".onion"); + } + public void setPort(int port) { this.port = port; } diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index bbdc75248..961d2cd6e 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -129,6 +129,31 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate mAccountJid.requestFocus(); return; } + String hostname = null; + int numericPort = 5222; + if (mUseTor) { + hostname = mHostname.getText().toString(); + final String port = mPort.getText().toString(); + if (hostname.contains(" ")) { + mHostname.setError(getString(R.string.not_valid_hostname)); + mHostname.requestFocus(); + return; + } + try { + numericPort = Integer.parseInt(port); + if (numericPort < 0 || numericPort > 65535) { + mPort.setError(getString(R.string.not_a_valid_port)); + mPort.requestFocus(); + return; + } + + } catch (NumberFormatException e) { + mPort.setError(getString(R.string.not_a_valid_port)); + mPort.requestFocus(); + return; + } + } + if (jid.isDomainJid()) { if (Config.DOMAIN_LOCK != null) { mAccountJid.setError(getString(R.string.invalid_username)); @@ -140,8 +165,6 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } final String password = mPassword.getText().toString(); final String passwordConfirm = mPasswordConfirm.getText().toString(); - final String hostname = mHostname.getText().toString(); - final String port = mPort.getText().toString(); if (registerNewAccount) { if (!password.equals(passwordConfirm)) { mPasswordConfirm.setError(getString(R.string.passwords_do_not_match)); @@ -151,29 +174,12 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } if (mAccount != null) { mAccount.setJid(jid); + mAccount.setPort(numericPort); + mAccount.setHostname(hostname); mAccountJid.setError(null); mPasswordConfirm.setError(null); mAccount.setPassword(password); mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); - if (hostname.contains(" ")) { - mHostname.setError(getString(R.string.not_valid_hostname)); - mHostname.requestFocus(); - return; - } - mAccount.setHostname(hostname); - try { - int numericPort = Integer.parseInt(port); - if (numericPort < 0 || numericPort > 65535) { - mPort.setError(getString(R.string.not_a_valid_port)); - mPort.requestFocus(); - return; - } - mAccount.setPort(numericPort); - } catch (NumberFormatException e) { - mPort.setError(getString(R.string.not_a_valid_port)); - mPort.requestFocus(); - return; - } xmppConnectionService.updateAccount(mAccount); } else { if (xmppConnectionService.findAccountByJid(jid) != null) { @@ -182,11 +188,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate return; } mAccount = new Account(jid.toBareJid(), password); + mAccount.setPort(numericPort); + mAccount.setHostname(hostname); mAccount.setOption(Account.OPTION_USETLS, true); mAccount.setOption(Account.OPTION_USECOMPRESSION, true); mAccount.setOption(Account.OPTION_REGISTER, registerNewAccount); xmppConnectionService.createAccount(mAccount); } + mHostname.setError(null); + mPort.setError(null); if (!mAccount.isOptionSet(Account.OPTION_DISABLED) && !registerNewAccount && !mInitMode) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index dec3cad6d..f5f3860c2 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -13,7 +13,6 @@ import android.util.Log; import android.util.Pair; import android.util.SparseArray; -import org.apache.http.conn.ssl.StrictHostnameVerifier; import org.json.JSONException; import org.json.JSONObject; import org.xmlpull.v1.XmlPullParserException; @@ -27,10 +26,10 @@ import java.net.ConnectException; import java.net.IDN; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.Proxy; import java.net.Socket; import java.net.UnknownHostException; import java.net.URL; +import java.nio.ByteBuffer; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.Principal; @@ -234,23 +233,44 @@ public class XmppConnection implements Runnable { tagReader = new XmlReader(wakeLock); tagWriter = new TagWriter(); this.changeStatus(Account.State.CONNECTING); - final boolean useTor = mXmppConnectionService.useTorToConnect(); - final Proxy TOR_PROXY = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(InetAddress.getLocalHost(), 9050)); - if (DNSHelper.isIp(account.getServer().toString())) { - socket = useTor ? new Socket(TOR_PROXY) : new Socket(); + final boolean useTor = mXmppConnectionService.useTorToConnect() || account.isOnion(); + if (useTor) { + InetSocketAddress proxyAddress = new InetSocketAddress(InetAddress.getLocalHost(), 9050); + byte[] destination; + if (account.getHostname() == null || account.getHostname().isEmpty()) { + destination = account.getServer().toString().getBytes(); + } else { + destination = account.getHostname().getBytes(); + } + Log.d(Config.LOGTAG,"connecting via tor to "+new String(destination)); + socket = new Socket(); + socket.connect(proxyAddress, Config.CONNECT_TIMEOUT * 1000); + InputStream proxyIs = socket.getInputStream(); + OutputStream proxyOs = socket.getOutputStream(); + proxyOs.write(new byte[]{0x05, 0x01, 0x00}); + byte[] response = new byte[2]; + proxyIs.read(response); + ByteBuffer request = ByteBuffer.allocate(7 + destination.length); + request.put(new byte[]{0x05, 0x01, 0x00, 0x03}); + request.put((byte) destination.length); + request.put(destination); + request.putShort((short) account.getPort()); + proxyOs.write(request.array()); + response = new byte[7 + destination.length]; + proxyIs.read(response); + if (response[1] != 0x00) { + throw new UnknownHostException(); + } + } else if (DNSHelper.isIp(account.getServer().toString())) { + socket = new Socket(); try { socket.connect(new InetSocketAddress(account.getServer().toString(), 5222), Config.SOCKET_TIMEOUT * 1000); } catch (IOException e) { throw new UnknownHostException(); } } else { - final ArrayList values; - if (useTor) { - values = account.getHostnamePortBundles(); - } else { - final Bundle result = DNSHelper.getSRVRecord(account.getServer(),mXmppConnectionService); - values = result.getParcelableArrayList("values"); - } + final Bundle result = DNSHelper.getSRVRecord(account.getServer(),mXmppConnectionService); + final ArrayListvalues = result.getParcelableArrayList("values"); int i = 0; boolean socketError = true; while (socketError && values.size() > i) { @@ -277,7 +297,7 @@ public class XmppConnection implements Runnable { + ": using values from dns " + srvRecordServer + ":" + srvRecordPort); } - socket = useTor ? new Socket(TOR_PROXY) : new Socket(); + socket = new Socket(); socket.connect(addr, Config.SOCKET_TIMEOUT * 1000); socketError = false; } catch (final Throwable e) { -- cgit v1.2.3 From 8ffcc11f278994b5bd2cebe2ee50b78a9d14a985 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 29 Nov 2015 16:31:51 +0100 Subject: refactored socks5 connection code. make jingle transport use that new code --- src/main/java/eu/siacs/conversations/Config.java | 2 +- .../conversations/utils/SocksSocketFactory.java | 52 ++++++++++++++++++++++ .../siacs/conversations/xmpp/XmppConnection.java | 29 +++--------- .../xmpp/jingle/JingleSocks5Transport.java | 42 ++++++----------- 4 files changed, 72 insertions(+), 53 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index ddeba6119..8c0528455 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -42,7 +42,7 @@ public final class Config { public static final int REFRESH_UI_INTERVAL = 500; public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb - public static final boolean DISABLE_HTTP_UPLOAD = false; + public static final boolean DISABLE_HTTP_UPLOAD = true; public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance public static final boolean EXTENDED_SM_LOGGING = true; // log stanza counts public static final boolean RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE = true; //setting to true might increase power consumption diff --git a/src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java b/src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java new file mode 100644 index 000000000..6d9340ab0 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java @@ -0,0 +1,52 @@ +package eu.siacs.conversations.utils; + +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; + +import eu.siacs.conversations.Config; + +public class SocksSocketFactory { + + public static void createSocksConnection(Socket socket, String destination, int port) throws IOException { + InputStream proxyIs = socket.getInputStream(); + OutputStream proxyOs = socket.getOutputStream(); + proxyOs.write(new byte[]{0x05, 0x01, 0x00}); + byte[] response = new byte[2]; + proxyIs.read(response); + byte[] dest = destination.getBytes(); + ByteBuffer request = ByteBuffer.allocate(7 + dest.length); + request.put(new byte[]{0x05, 0x01, 0x00, 0x03}); + request.put((byte) dest.length); + request.put(dest); + request.putShort((short) port); + proxyOs.write(request.array()); + response = new byte[7 + dest.length]; + proxyIs.read(response); + if (response[1] != 0x00) { + throw new SocksConnectionException(); + } + } + + public static Socket createSocket(InetSocketAddress address, String destination, int port) throws IOException { + Socket socket = new Socket(); + socket.connect(address, Config.CONNECT_TIMEOUT * 1000); + createSocksConnection(socket, destination, port); + return socket; + } + + public static Socket createSocketOverTor(String destination, int port) throws IOException { + return createSocket(new InetSocketAddress(InetAddress.getLocalHost(), 9050), destination, port); + } + + static class SocksConnectionException extends IOException { + + } +} diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index f5f3860c2..388f65722 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -67,6 +67,7 @@ import eu.siacs.conversations.generator.IqGenerator; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.DNSHelper; +import eu.siacs.conversations.utils.SocksSocketFactory; import eu.siacs.conversations.utils.Xmlns; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Tag; @@ -235,32 +236,14 @@ public class XmppConnection implements Runnable { this.changeStatus(Account.State.CONNECTING); final boolean useTor = mXmppConnectionService.useTorToConnect() || account.isOnion(); if (useTor) { - InetSocketAddress proxyAddress = new InetSocketAddress(InetAddress.getLocalHost(), 9050); - byte[] destination; + String destination; if (account.getHostname() == null || account.getHostname().isEmpty()) { - destination = account.getServer().toString().getBytes(); + destination = account.getServer().toString(); } else { - destination = account.getHostname().getBytes(); - } - Log.d(Config.LOGTAG,"connecting via tor to "+new String(destination)); - socket = new Socket(); - socket.connect(proxyAddress, Config.CONNECT_TIMEOUT * 1000); - InputStream proxyIs = socket.getInputStream(); - OutputStream proxyOs = socket.getOutputStream(); - proxyOs.write(new byte[]{0x05, 0x01, 0x00}); - byte[] response = new byte[2]; - proxyIs.read(response); - ByteBuffer request = ByteBuffer.allocate(7 + destination.length); - request.put(new byte[]{0x05, 0x01, 0x00, 0x03}); - request.put((byte) destination.length); - request.put(destination); - request.putShort((short) account.getPort()); - proxyOs.write(request.array()); - response = new byte[7 + destination.length]; - proxyIs.read(response); - if (response[1] != 0x00) { - throw new UnknownHostException(); + destination = account.getHostname(); } + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": connect to "+destination+" via TOR"); + socket = SocksSocketFactory.createSocketOverTor(destination,account.getPort()); } else if (DNSHelper.isIp(account.getServer().toString())) { socket = new Socket(); try { 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 74306ce3d..9240bd2c6 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -21,6 +21,7 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.utils.CryptoHelper; +import eu.siacs.conversations.utils.SocksSocketFactory; public class JingleSocks5Transport extends JingleTransport { private JingleCandidate candidate; @@ -61,36 +62,19 @@ public class JingleSocks5Transport extends JingleTransport { @Override public void run() { try { - final boolean useTor = connection.getConnectionManager().getXmppConnectionService().useTorToConnect(); - final Proxy TOR_PROXY = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(InetAddress.getLocalHost(), 9050)); - socket = useTor ? new Socket(TOR_PROXY) : new Socket(); - SocketAddress address = new InetSocketAddress(candidate.getHost(),candidate.getPort()); - socket.connect(address,Config.SOCKET_TIMEOUT * 1000); - inputStream = socket.getInputStream(); - outputStream = socket.getOutputStream(); - byte[] login = { 0x05, 0x01, 0x00 }; - byte[] expectedReply = { 0x05, 0x00 }; - byte[] reply = new byte[2]; - outputStream.write(login); - inputStream.read(reply); - final String connect = Character.toString('\u0005') - + '\u0001' + '\u0000' + '\u0003' + '\u0028' - + destination + '\u0000' + '\u0000'; - if (Arrays.equals(reply, expectedReply)) { - outputStream.write(connect.getBytes()); - byte[] result = new byte[2]; - inputStream.read(result); - int status = result[1]; - if (status == 0) { - isEstablished = true; - callback.established(); - } else { - callback.failed(); - } + final boolean useTor = connection.getAccount().isOnion() || connection.getConnectionManager().getXmppConnectionService().useTorToConnect(); + if (useTor) { + socket = SocksSocketFactory.createSocketOverTor(candidate.getHost(),candidate.getPort()); } else { - socket.close(); - callback.failed(); + socket = new Socket(); + SocketAddress address = new InetSocketAddress(candidate.getHost(),candidate.getPort()); + socket.connect(address,Config.SOCKET_TIMEOUT * 1000); } + inputStream = socket.getInputStream(); + outputStream = socket.getOutputStream(); + SocksSocketFactory.createSocksConnection(socket,destination,0); + isEstablished = true; + callback.established(); } catch (UnknownHostException e) { callback.failed(); } catch (IOException e) { @@ -162,7 +146,7 @@ public class JingleSocks5Transport extends JingleTransport { wakeLock.acquire(); MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.reset(); - inputStream.skip(45); + //inputStream.skip(45); socket.setSoTimeout(30000); file.getParentFile().mkdirs(); file.createNewFile(); -- cgit v1.2.3 From b4a259837e56c81ce9e57fa6b37884b4a846713d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 30 Nov 2015 15:43:54 +0100 Subject: always use http proxy for http requests. (socks is leaking dns) --- .../java/eu/siacs/conversations/http/HttpConnectionManager.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java b/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java index 6435fd477..910c43f31 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java @@ -95,10 +95,6 @@ public class HttpConnectionManager extends AbstractConnectionManager { } public Proxy getProxy() throws IOException { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - return new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(InetAddress.getLocalHost(), 9050)); - } else { - return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(InetAddress.getLocalHost(), 8118)); - } + return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(InetAddress.getLocalHost(), 8118)); } } -- cgit v1.2.3 From 2225b0b6d5586d608b15d4e1ac13faa99b8971bf Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 30 Nov 2015 16:01:48 +0100 Subject: add error state for unavailable tor network --- src/main/java/eu/siacs/conversations/entities/Account.java | 6 +++--- .../eu/siacs/conversations/utils/SocksSocketFactory.java | 13 +++++++++---- .../java/eu/siacs/conversations/xmpp/XmppConnection.java | 8 ++------ src/main/res/values/strings.xml | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 062c0d253..75e6b2a00 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -83,7 +83,7 @@ public class Account extends AbstractEntity { REGISTRATION_NOT_SUPPORTED(true), SECURITY_ERROR(true), INCOMPATIBLE_SERVER(true), - DNS_TIMEOUT(true); + TOR_NOT_AVAILABLE(true); private final boolean isError; @@ -127,8 +127,8 @@ public class Account extends AbstractEntity { return R.string.account_status_security_error; case INCOMPATIBLE_SERVER: return R.string.account_status_incompatible_server; - case DNS_TIMEOUT: - return R.string.account_status_dns_timeout; + case TOR_NOT_AVAILABLE: + return R.string.account_status_tor_unavailable; default: return R.string.account_status_unknown; } diff --git a/src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java b/src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java index 6d9340ab0..768e9f17b 100644 --- a/src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java +++ b/src/main/java/eu/siacs/conversations/utils/SocksSocketFactory.java @@ -1,14 +1,11 @@ package eu.siacs.conversations.utils; -import android.util.Log; - import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; -import java.net.UnknownHostException; import java.nio.ByteBuffer; import eu.siacs.conversations.Config; @@ -37,7 +34,11 @@ public class SocksSocketFactory { public static Socket createSocket(InetSocketAddress address, String destination, int port) throws IOException { Socket socket = new Socket(); - socket.connect(address, Config.CONNECT_TIMEOUT * 1000); + try { + socket.connect(address, Config.CONNECT_TIMEOUT * 1000); + } catch (IOException e) { + throw new SocksProxyNotFoundException(); + } createSocksConnection(socket, destination, port); return socket; } @@ -49,4 +50,8 @@ public class SocksSocketFactory { static class SocksConnectionException extends IOException { } + + public static class SocksProxyNotFoundException extends IOException { + + } } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 388f65722..9ec4d9bbb 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -29,7 +29,6 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.net.URL; -import java.nio.ByteBuffer; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.Principal; @@ -318,8 +317,8 @@ public class XmppConnection implements Runnable { this.changeStatus(Account.State.UNAUTHORIZED); } catch (final UnknownHostException | ConnectException e) { this.changeStatus(Account.State.SERVER_NOT_FOUND); - } catch (final DnsTimeoutException e) { - this.changeStatus(Account.State.DNS_TIMEOUT); + } catch (final SocksSocketFactory.SocksProxyNotFoundException e) { + this.changeStatus(Account.State.TOR_NOT_AVAILABLE); } catch (final IOException | XmlPullParserException | NoSuchAlgorithmException e) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": " + e.getMessage()); this.changeStatus(Account.State.OFFLINE); @@ -1327,9 +1326,6 @@ public class XmppConnection implements Runnable { } - private class DnsTimeoutException extends IOException { - - } public enum Identity { FACEBOOK, SLACK, diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index eaff35341..9f2573637 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -521,7 +521,7 @@ Download failed: Could not connect to host Use white background Show received messages as black text on a white background - Timeout in DNS + TOR network unavailable Broken Presence settings Away when screen is off -- cgit v1.2.3 From d42c82abf21d92ae1e8c7d12510d376800a2b363 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 1 Dec 2015 12:22:47 +0100 Subject: combine multiple message receipts into single message --- .../eu/siacs/conversations/generator/MessageGenerator.java | 14 ++++++++------ .../java/eu/siacs/conversations/parser/MessageParser.java | 13 +++++++------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index 573049c79..9c847d0e0 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -4,6 +4,7 @@ import net.java.otr4j.OtrException; import net.java.otr4j.session.Session; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; import java.util.Locale; import java.util.TimeZone; @@ -72,9 +73,9 @@ public class MessageGenerator extends AbstractGenerator { Element html = packet.addChild("html","http://jabber.org/protocol/xhtml-im"); Element body = html.addChild("body","http://www.w3.org/1999/xhtml"); Element img = body.addChild("img"); - img.setAttribute("src",params.url.toString()); - img.setAttribute("height",params.height); - img.setAttribute("width",params.width); + img.setAttribute("src", params.url.toString()); + img.setAttribute("height", params.height); + img.setAttribute("width", params.width); } public static void addMessageHints(MessagePacket packet) { @@ -188,13 +189,14 @@ public class MessageGenerator extends AbstractGenerator { return packet; } - public MessagePacket received(Account account, MessagePacket originalMessage, String namespace, int type) { + public MessagePacket received(Account account, MessagePacket originalMessage, ArrayList namespaces, int type) { MessagePacket receivedPacket = new MessagePacket(); receivedPacket.setType(type); receivedPacket.setTo(originalMessage.getFrom()); receivedPacket.setFrom(account.getJid()); - Element received = receivedPacket.addChild("received", namespace); - received.setAttribute("id", originalMessage.getId()); + for(String namespace : namespaces) { + receivedPacket.addChild("received", namespace).setAttribute("id", originalMessage.getId()); + } return receivedPacket; } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 58ca51350..b4c648fe9 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -7,6 +7,7 @@ import eu.siacs.conversations.crypto.PgpDecryptionService; import net.java.otr4j.session.Session; import net.java.otr4j.session.SessionStatus; +import java.util.ArrayList; import java.util.Set; import eu.siacs.conversations.Config; @@ -393,17 +394,17 @@ public class MessageParser extends AbstractParser implements } if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) { + ArrayList receiptsNamespaces = new ArrayList<>(); if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) { - MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account, - packet, - "urn:xmpp:chat-markers:0", - MessagePacket.TYPE_CHAT); - mXmppConnectionService.sendMessagePacket(account, receipt); + receiptsNamespaces.add("urn:xmpp:chat-markers:0"); } if (packet.hasChild("request", "urn:xmpp:receipts")) { + receiptsNamespaces.add("urn:xmpp:receipts"); + } + if (receiptsNamespaces.size() > 0) { MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account, packet, - "urn:xmpp:receipts", + receiptsNamespaces, packet.getType()); mXmppConnectionService.sendMessagePacket(account, receipt); } -- cgit v1.2.3 From 2cd43f704215f963200249c0771362ce2bcf4768 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 1 Dec 2015 14:18:07 +0100 Subject: fixed crashes when activity got destroyed when selecting pgp key --- .../conversations/ui/ConversationActivity.java | 27 +++++- .../conversations/ui/ManageAccountActivity.java | 108 ++++++++++++++------- 2 files changed, 95 insertions(+), 40 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 5c7722200..5ac2b1b4e 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -17,6 +17,7 @@ import android.provider.MediaStore; import android.support.v4.widget.SlidingPaneLayout; import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener; import android.util.Log; +import android.util.Pair; import android.view.Gravity; import android.view.KeyEvent; import android.view.Menu; @@ -109,6 +110,7 @@ public class ConversationActivity extends XmppActivity private boolean mActivityPaused = false; private AtomicBoolean mRedirected = new AtomicBoolean(false); + private Pair mPostponedActivityResult; public Conversation getSelectedConversation() { return this.mSelectedConversation; @@ -1101,6 +1103,7 @@ public class ConversationActivity extends XmppActivity mPendingFileUris.clear(); mPendingGeoUri = null; setSelectedConversation(conversationList.get(0)); + mPostponedActivityResult = null; this.mConversationFragment.reInit(getSelectedConversation()); } else { this.mConversationFragment.messageListAdapter.updatePreferences(); @@ -1108,6 +1111,10 @@ public class ConversationActivity extends XmppActivity this.mConversationFragment.setupIme(); } + if (this.mPostponedActivityResult != null) { + this.onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second); + } + if(!forbidProcessingPendings) { for (Iterator i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) { Uri foo = i.next(); @@ -1208,14 +1215,24 @@ public class ConversationActivity extends XmppActivity if (requestCode == REQUEST_DECRYPT_PGP) { mConversationFragment.onActivityResult(requestCode, resultCode, data); } else if (requestCode == REQUEST_CHOOSE_PGP_ID) { - if (data.getExtras().containsKey(OpenPgpApi.EXTRA_SIGN_KEY_ID)) { - mSelectedConversation.getAccount().setPgpSignId(data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID)); - announcePgp(mSelectedConversation.getAccount(), null); + if (xmppConnectionServiceBound) { + if (data.getExtras().containsKey(OpenPgpApi.EXTRA_SIGN_KEY_ID)) { + mSelectedConversation.getAccount().setPgpSignId(data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID)); + announcePgp(mSelectedConversation.getAccount(), null); + } else { + choosePgpSignId(mSelectedConversation.getAccount()); + } + this.mPostponedActivityResult = null; } else { - choosePgpSignId(mSelectedConversation.getAccount()); + this.mPostponedActivityResult = new Pair<>(requestCode, data); } } else if (requestCode == REQUEST_ANNOUNCE_PGP) { - announcePgp(mSelectedConversation.getAccount(), null); + if (xmppConnectionServiceBound) { + announcePgp(mSelectedConversation.getAccount(), null); + this.mPostponedActivityResult = null; + } else { + this.mPostponedActivityResult = new Pair<>(requestCode, data); + } } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) { mPendingImageUris.clear(); mPendingImageUris.addAll(extractUriFromIntent(data)); diff --git a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java index 546be4d87..91b2a5615 100644 --- a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java @@ -9,6 +9,7 @@ import android.content.Intent; import android.os.Bundle; import android.security.KeyChain; import android.security.KeyChainAliasCallback; +import android.util.Pair; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; @@ -30,17 +31,25 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.ui.adapter.AccountAdapter; +import eu.siacs.conversations.xmpp.jid.InvalidJidException; +import eu.siacs.conversations.xmpp.jid.Jid; + import org.openintents.openpgp.util.OpenPgpApi; public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated { + private final String STATE_SELECTED_ACCOUNT = "selected_account"; + protected Account selectedAccount = null; + protected Jid selectedAccountJid = null; protected final List accountList = new ArrayList<>(); protected ListView accountListView; protected AccountAdapter mAccountAdapter; protected AtomicBoolean mInvokedAddAccount = new AtomicBoolean(false); + protected Pair mPostponedActivityResult = null; + @Override public void onAccountUpdate() { refreshUi(); @@ -68,6 +77,17 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda setContentView(R.layout.manage_accounts); + if (savedInstanceState != null) { + String jid = savedInstanceState.getString(STATE_SELECTED_ACCOUNT); + if (jid != null) { + try { + this.selectedAccountJid = Jid.fromString(jid); + } catch (InvalidJidException e) { + this.selectedAccountJid = null; + } + } + } + accountListView = (ListView) findViewById(R.id.account_list); this.mAccountAdapter = new AccountAdapter(this, accountList); accountListView.setAdapter(this.mAccountAdapter); @@ -83,12 +103,19 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda } @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + public void onSaveInstanceState(final Bundle savedInstanceState) { + if (selectedAccount != null) { + savedInstanceState.putString(STATE_SELECTED_ACCOUNT, selectedAccount.getJid().toBareJid().toString()); + } + super.onSaveInstanceState(savedInstanceState); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); ManageAccountActivity.this.getMenuInflater().inflate( R.menu.manageaccounts_context, menu); - AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; + AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; this.selectedAccount = accountList.get(acmi.position); if (this.selectedAccount.isOptionSet(Account.OPTION_DISABLED)) { menu.findItem(R.id.mgmt_account_disable).setVisible(false); @@ -103,9 +130,15 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda @Override void onBackendConnected() { + if (selectedAccountJid != null) { + this.selectedAccount = xmppConnectionService.findAccountByJid(selectedAccountJid); + } refreshUiReal(); + if (this.mPostponedActivityResult != null) { + this.onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second); + } if (Config.X509_VERIFICATION && this.accountList.size() == 0) { - if (mInvokedAddAccount.compareAndSet(false,true)) { + if (mInvokedAddAccount.compareAndSet(false, true)) { addAccountFromKey(); } } @@ -136,23 +169,23 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda @Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.mgmt_account_publish_avatar: - publishAvatar(selectedAccount); - return true; - case R.id.mgmt_account_disable: - disableAccount(selectedAccount); - return true; - case R.id.mgmt_account_enable: - enableAccount(selectedAccount); - return true; - case R.id.mgmt_account_delete: - deleteAccount(selectedAccount); - return true; - case R.id.mgmt_account_announce_pgp: - choosePgpSignId(selectedAccount); - return true; - default: - return super.onContextItemSelected(item); + case R.id.mgmt_account_publish_avatar: + publishAvatar(selectedAccount); + return true; + case R.id.mgmt_account_disable: + disableAccount(selectedAccount); + return true; + case R.id.mgmt_account_enable: + enableAccount(selectedAccount); + return true; + case R.id.mgmt_account_delete: + deleteAccount(selectedAccount); + return true; + case R.id.mgmt_account_announce_pgp: + publishOpenPGPPublicKey(selectedAccount); + return true; + default: + return super.onContextItemSelected(item); } } @@ -184,9 +217,9 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda Intent contactsIntent = new Intent(this, StartConversationActivity.class); contactsIntent.setFlags( - // if activity exists in stack, pop the stack and go back to it + // if activity exists in stack, pop the stack and go back to it Intent.FLAG_ACTIVITY_CLEAR_TOP | - // otherwise, make a new task for it + // otherwise, make a new task for it Intent.FLAG_ACTIVITY_NEW_TASK | // don't use the new activity animation; finish // animation runs instead @@ -211,7 +244,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda try { KeyChain.choosePrivateKeyAlias(this, this, null, null, null, -1, null); } catch (ActivityNotFoundException e) { - Toast.makeText(this,R.string.device_does_not_support_certificates,Toast.LENGTH_LONG).show(); + Toast.makeText(this, R.string.device_does_not_support_certificates, Toast.LENGTH_LONG).show(); } } @@ -231,7 +264,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda } } } - for(Account account : list) { + for (Account account : list) { disableAccount(account); } } @@ -267,7 +300,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda } } } - for(Account account : list) { + for (Account account : list) { enableAccount(account); } } @@ -284,7 +317,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda private void publishOpenPGPPublicKey(Account account) { if (ManageAccountActivity.this.hasPgp()) { - announcePgp(account, null); + choosePgpSignId(selectedAccount); } else { this.showInstallPgpDialog(); } @@ -312,15 +345,20 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == REQUEST_CHOOSE_PGP_ID) { - if (data.getExtras().containsKey(OpenPgpApi.EXTRA_SIGN_KEY_ID)) { - selectedAccount.setPgpSignId(data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID)); + if (xmppConnectionServiceBound) { + if (requestCode == REQUEST_CHOOSE_PGP_ID) { + if (data.getExtras().containsKey(OpenPgpApi.EXTRA_SIGN_KEY_ID)) { + selectedAccount.setPgpSignId(data.getExtras().getLong(OpenPgpApi.EXTRA_SIGN_KEY_ID)); + announcePgp(selectedAccount, null); + } else { + choosePgpSignId(selectedAccount); + } + } else if (requestCode == REQUEST_ANNOUNCE_PGP) { announcePgp(selectedAccount, null); - } else { - choosePgpSignId(selectedAccount); } - } else if (requestCode == REQUEST_ANNOUNCE_PGP) { - announcePgp(selectedAccount, null); + this.mPostponedActivityResult = null; + } else { + this.mPostponedActivityResult = new Pair<>(requestCode, data); } } } @@ -342,7 +380,7 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda runOnUiThread(new Runnable() { @Override public void run() { - Toast.makeText(ManageAccountActivity.this,r,Toast.LENGTH_LONG).show(); + Toast.makeText(ManageAccountActivity.this, r, Toast.LENGTH_LONG).show(); } }); } -- cgit v1.2.3 From 65b5504e68e36116234bd69126304d6d764b678b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 1 Dec 2015 17:15:36 +0100 Subject: introduce config.java variable to optionally show number of connected accounts in notification --- src/main/java/eu/siacs/conversations/Config.java | 2 + .../services/NotificationService.java | 92 +++++++++++++--------- src/main/res/values/strings.xml | 1 + 3 files changed, 58 insertions(+), 37 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 8c0528455..a53074687 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -16,6 +16,8 @@ public final class Config { public static final String DOMAIN_LOCK = null; //only allow account creation for this domain public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox public static final boolean HIDE_PGP_IN_UI = false; //some more consumer focused clients might want to disable OpenPGP + public static final boolean PARANOID_MODE = false; //disables ability to send unencrypted 1-on-1 chats and forces TOR + public static final boolean SHOW_CONNECTED_ACCOUNTS = true; //show number of connected accounts in foreground notification public static final boolean LEGACY_NAMESPACE_HTTP_UPLOAD = false; diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 125b1c268..abd42f4c4 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -60,12 +60,12 @@ public class NotificationService { public boolean notify(final Message message) { return (message.getStatus() == Message.STATUS_RECEIVED) - && notificationsEnabled() - && !message.getConversation().isMuted() - && (message.getConversation().isPnNA() - || conferenceNotificationsEnabled() - || wasHighlightedOrPrivate(message) - ); + && notificationsEnabled() + && !message.getConversation().isMuted() + && (message.getConversation().isPnNA() + || conferenceNotificationsEnabled() + || wasHighlightedOrPrivate(message) + ); } public void notifyPebble(final Message message) { @@ -179,7 +179,7 @@ public class NotificationService { public void updateNotification(final boolean notify) { final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService - .getSystemService(Context.NOTIFICATION_SERVICE); + .getSystemService(Context.NOTIFICATION_SERVICE); final SharedPreferences preferences = mXmppConnectionService.getPreferences(); final String ringtone = preferences.getString("notification_ringtone", null); @@ -235,7 +235,7 @@ public class NotificationService { conversation = messages.get(0).getConversation(); final String name = conversation.getName(); style.addLine(Html.fromHtml("" + name + " " - + UIHelper.getMessagePreview(mXmppConnectionService,messages.get(0)).first)); + + UIHelper.getMessagePreview(mXmppConnectionService, messages.get(0)).first)); names.append(name); names.append(", "); } @@ -275,9 +275,9 @@ public class NotificationService { Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? R.drawable.ic_file_download_white_24dp : R.drawable.ic_action_download, mXmppConnectionService.getResources().getString(R.string.download_x_file, - UIHelper.getFileDescriptionString(mXmppConnectionService, message)), + UIHelper.getFileDescriptionString(mXmppConnectionService, message)), createDownloadIntent(message) - ); + ); } if ((message = getFirstLocationMessage(messages)) != null) { mBuilder.addAction(R.drawable.ic_room_white_24dp, @@ -290,26 +290,26 @@ public class NotificationService { } private void modifyForImage(final Builder builder, final Message message, - final ArrayList messages, final boolean notify) { + final ArrayList messages, final boolean notify) { try { final Bitmap bitmap = mXmppConnectionService.getFileBackend() - .getThumbnail(message, getPixel(288), false); + .getThumbnail(message, getPixel(288), false); final ArrayList tmp = new ArrayList<>(); for (final Message msg : messages) { if (msg.getType() == Message.TYPE_TEXT && msg.getTransferable() == null) { tmp.add(msg); - } + } } final BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle(); bigPictureStyle.bigPicture(bitmap); if (tmp.size() > 0) { bigPictureStyle.setSummaryText(getMergedBodies(tmp)); - builder.setContentText(UIHelper.getMessagePreview(mXmppConnectionService,tmp.get(0)).first); + builder.setContentText(UIHelper.getMessagePreview(mXmppConnectionService, tmp.get(0)).first); } else { builder.setContentText(mXmppConnectionService.getString( R.string.received_x_file, - UIHelper.getFileDescriptionString(mXmppConnectionService,message))); + UIHelper.getFileDescriptionString(mXmppConnectionService, message))); } builder.setStyle(bigPictureStyle); } catch (final FileNotFoundException e) { @@ -318,11 +318,11 @@ public class NotificationService { } private void modifyForTextOnly(final Builder builder, - final ArrayList messages, final boolean notify) { + final ArrayList messages, final boolean notify) { builder.setStyle(new NotificationCompat.BigTextStyle().bigText(getMergedBodies(messages))); - builder.setContentText(UIHelper.getMessagePreview(mXmppConnectionService,messages.get(0)).first); + builder.setContentText(UIHelper.getMessagePreview(mXmppConnectionService, messages.get(0)).first); if (notify) { - builder.setTicker(UIHelper.getMessagePreview(mXmppConnectionService,messages.get(messages.size() - 1)).first); + builder.setTicker(UIHelper.getMessagePreview(mXmppConnectionService, messages.get(messages.size() - 1)).first); } } @@ -333,7 +333,7 @@ public class NotificationService { && message.getEncryption() != Message.ENCRYPTION_PGP && message.getFileParams().height > 0) { return message; - } + } } return null; } @@ -349,7 +349,7 @@ public class NotificationService { } private Message getFirstLocationMessage(final Iterable messages) { - for(final Message message : messages) { + for (final Message message : messages) { if (GeoHelper.isGeoUri(message.getBody())) { return message; } @@ -360,7 +360,7 @@ public class NotificationService { private CharSequence getMergedBodies(final ArrayList messages) { final StringBuilder text = new StringBuilder(); for (int i = 0; i < messages.size(); ++i) { - text.append(UIHelper.getMessagePreview(mXmppConnectionService,messages.get(i)).first); + text.append(UIHelper.getMessagePreview(mXmppConnectionService, messages.get(i)).first); if (i != messages.size() - 1) { text.append("\n"); } @@ -370,9 +370,9 @@ public class NotificationService { private PendingIntent createShowLocationIntent(final Message message) { Iterable intents = GeoHelper.createGeoIntentsFromMessage(message); - for(Intent intent : intents) { + for (Intent intent : intents) { if (intent.resolveActivity(mXmppConnectionService.getPackageManager()) != null) { - return PendingIntent.getActivity(mXmppConnectionService,18,intent,PendingIntent.FLAG_UPDATE_CURRENT); + return PendingIntent.getActivity(mXmppConnectionService, 18, intent, PendingIntent.FLAG_UPDATE_CURRENT); } } return createOpenConversationsIntent(); @@ -380,7 +380,7 @@ public class NotificationService { private PendingIntent createContentIntent(final String conversationUuid, final String downloadMessageUuid) { final TaskStackBuilder stackBuilder = TaskStackBuilder - .create(mXmppConnectionService); + .create(mXmppConnectionService); stackBuilder.addParentStack(ConversationActivity.class); final Intent viewConversationIntent = new Intent(mXmppConnectionService, @@ -432,10 +432,10 @@ public class NotificationService { } private PendingIntent createDisableAccountIntent(final Account account) { - final Intent intent = new Intent(mXmppConnectionService,XmppConnectionService.class); + final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class); intent.setAction(XmppConnectionService.ACTION_DISABLE_ACCOUNT); - intent.putExtra("account",account.getJid().toBareJid().toString()); - return PendingIntent.getService(mXmppConnectionService,0,intent,PendingIntent.FLAG_UPDATE_CURRENT); + intent.putExtra("account", account.getJid().toBareJid().toString()); + return PendingIntent.getService(mXmppConnectionService, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } private boolean wasHighlightedOrPrivate(final Message message) { @@ -468,7 +468,7 @@ public class NotificationService { private int getPixel(final int dp) { final DisplayMetrics metrics = mXmppConnectionService.getResources() - .getDisplayMetrics(); + .getDisplayMetrics(); return ((int) (dp * metrics.density)); } @@ -478,7 +478,7 @@ public class NotificationService { private boolean inMiniGracePeriod(final Account account) { final int miniGrace = account.getStatus() == Account.State.ONLINE ? Config.MINI_GRACE_PERIOD - : Config.MINI_GRACE_PERIOD * 2; + : Config.MINI_GRACE_PERIOD * 2; return SystemClock.elapsedRealtime() < (this.mLastNotification + miniGrace); } @@ -486,10 +486,25 @@ public class NotificationService { final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService); mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.conversations_foreground_service)); - mBuilder.setContentText(mXmppConnectionService.getString(R.string.touch_to_open_conversations)); + if (Config.SHOW_CONNECTED_ACCOUNTS) { + List accounts = mXmppConnectionService.getAccounts(); + int enabled = 0; + int connected = 0; + for (Account account : accounts) { + if (account.isOnlineAndConnected()) { + connected++; + enabled++; + } else if (!account.isOptionSet(Account.OPTION_DISABLED)) { + enabled++; + } + } + mBuilder.setContentText(mXmppConnectionService.getString(R.string.connected_accounts, connected, enabled)); + } else { + mBuilder.setContentText(mXmppConnectionService.getString(R.string.touch_to_open_conversations)); + } mBuilder.setContentIntent(createOpenConversationsIntent()); mBuilder.setWhen(0); - mBuilder.setPriority(NotificationCompat.PRIORITY_MIN); + mBuilder.setPriority(Config.SHOW_CONNECTED_ACCOUNTS ? NotificationCompat.PRIORITY_DEFAULT : NotificationCompat.PRIORITY_MIN); final int cancelIcon; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mBuilder.setCategory(Notification.CATEGORY_SERVICE); @@ -505,20 +520,23 @@ public class NotificationService { } private PendingIntent createOpenConversationsIntent() { - return PendingIntent.getActivity(mXmppConnectionService, 0, new Intent(mXmppConnectionService,ConversationActivity.class),0); + return PendingIntent.getActivity(mXmppConnectionService, 0, new Intent(mXmppConnectionService, ConversationActivity.class), 0); } public void updateErrorNotification() { - final NotificationManager mNotificationManager = (NotificationManager) mXmppConnectionService.getSystemService(Context.NOTIFICATION_SERVICE); + final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService.getSystemService(Context.NOTIFICATION_SERVICE); final List errors = new ArrayList<>(); for (final Account account : mXmppConnectionService.getAccounts()) { if (account.hasErrorStatus()) { errors.add(account); } } + if (mXmppConnectionService.getPreferences().getBoolean("keep_foreground_service", false)) { + notificationManager.notify(FOREGROUND_NOTIFICATION_ID, createForegroundNotification()); + } final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService); if (errors.size() == 0) { - mNotificationManager.cancel(ERROR_NOTIFICATION_ID); + notificationManager.cancel(ERROR_NOTIFICATION_ID); return; } else if (errors.size() == 1) { mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.problem_connecting_to_account)); @@ -545,12 +563,12 @@ public class NotificationService { final TaskStackBuilder stackBuilder = TaskStackBuilder.create(mXmppConnectionService); stackBuilder.addParentStack(ConversationActivity.class); - final Intent manageAccountsIntent = new Intent(mXmppConnectionService,ManageAccountActivity.class); + final Intent manageAccountsIntent = new Intent(mXmppConnectionService, ManageAccountActivity.class); stackBuilder.addNextIntent(manageAccountsIntent); - final PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT); + final PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); mBuilder.setContentIntent(resultPendingIntent); - mNotificationManager.notify(ERROR_NOTIFICATION_ID, mBuilder.build()); + notificationManager.notify(ERROR_NOTIFICATION_ID, mBuilder.build()); } } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 9f2573637..e312bd59d 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -548,4 +548,5 @@ Server- or .onion-Address This is not a valid port number This is not a valid hostname + %1$d of %2$d accounts connected -- cgit v1.2.3 From dc8967d8fc09a5b7e515bb5005726d677a08c86b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 1 Dec 2015 22:41:58 +0100 Subject: introduced build-time paranoia mode that disables unencrypted chats and forces TOR --- src/main/java/eu/siacs/conversations/Config.java | 2 +- .../java/eu/siacs/conversations/entities/Conversation.java | 11 +++++++++-- .../siacs/conversations/services/XmppConnectionService.java | 2 +- .../java/eu/siacs/conversations/ui/ConversationActivity.java | 1 + .../java/eu/siacs/conversations/ui/SettingsActivity.java | 12 ++++++++++++ src/main/res/xml/preferences.xml | 4 +++- 6 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index a53074687..0d51b4a19 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -17,7 +17,7 @@ public final class Config { public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox public static final boolean HIDE_PGP_IN_UI = false; //some more consumer focused clients might want to disable OpenPGP public static final boolean PARANOID_MODE = false; //disables ability to send unencrypted 1-on-1 chats and forces TOR - public static final boolean SHOW_CONNECTED_ACCOUNTS = true; //show number of connected accounts in foreground notification + public static final boolean SHOW_CONNECTED_ACCOUNTS = false; //show number of connected accounts in foreground notification public static final boolean LEGACY_NAMESPACE_HTTP_UPLOAD = false; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 473ef0fe0..e93d5564b 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -612,9 +612,16 @@ public class Conversation extends AbstractEntity implements Blockable { if (next == -1) { int outgoing = this.getMostRecentlyUsedOutgoingEncryption(); if (outgoing == Message.ENCRYPTION_NONE) { - return this.getMostRecentlyUsedIncomingEncryption(); + next = this.getMostRecentlyUsedIncomingEncryption(); } else { - return outgoing; + next = outgoing; + } + } + if (Config.PARANOID_MODE && mode == MODE_SINGLE && next <= 0) { + if (getAccount().getAxolotlService().isContactAxolotlCapable(getContact())) { + return Message.ENCRYPTION_AXOLOTL; + } else { + return Message.ENCRYPTION_OTR; } } return next; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 30f8c687a..fff8a9848 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2550,7 +2550,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public boolean useTorToConnect() { - return getPreferences().getBoolean("use_tor", false); + return Config.PARANOID_MODE || getPreferences().getBoolean("use_tor", false); } public int unreadCount() { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 5ac2b1b4e..1f6e57a0a 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -815,6 +815,7 @@ public class ConversationActivity extends XmppActivity MenuItem pgp = popup.getMenu().findItem(R.id.encryption_choice_pgp); MenuItem axolotl = popup.getMenu().findItem(R.id.encryption_choice_axolotl); pgp.setVisible(!Config.HIDE_PGP_IN_UI); + none.setVisible(!Config.PARANOID_MODE); if (conversation.getMode() == Conversation.MODE_MULTI) { otr.setVisible(false); axolotl.setVisible(false); diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index 7118eb5a8..da9738ab5 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -9,7 +9,10 @@ import android.os.Build; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; +import android.preference.PreferenceCategory; import android.preference.PreferenceManager; +import android.preference.PreferenceScreen; +import android.util.Log; import android.widget.Toast; import java.security.KeyStoreException; @@ -19,6 +22,7 @@ import java.util.Collections; import java.util.Locale; import de.duenndns.ssl.MemorizingTrustManager; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.xmpp.XmppConnection; @@ -57,6 +61,14 @@ public class SettingsActivity extends XmppActivity implements } } + if (Config.PARANOID_MODE) { + PreferenceCategory connectionOptions = (PreferenceCategory) mSettingsFragment.findPreference("connection_options"); + PreferenceScreen expert = (PreferenceScreen) mSettingsFragment.findPreference("expert"); + if (connectionOptions != null) { + expert.removePreference(connectionOptions); + } + } + final Preference removeCertsPreference = mSettingsFragment.findPreference("remove_trusted_certificates"); removeCertsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index 6ef3c0291..16dc5eb99 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -147,7 +147,9 @@ android:summary="@string/pref_remove_trusted_certificates_summary" android:title="@string/pref_remove_trusted_certificates_title"/> - + Date: Wed, 4 Nov 2015 21:08:06 -0600 Subject: =?UTF-8?q?s/.../=E2=80=A6/=20in=20default=20strings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index e312bd59d..5b3ef186f 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -218,7 +218,7 @@ Own OMEMO fingerprint Other devices Trust OMEMO Fingerprints - Fetching keys... + Fetching keys… Done Verify Decrypt @@ -478,7 +478,7 @@ Offering %s Hide offline Disable Account - %s is typing... + %s is typing… %s has stopped typing Typing notifications Let your contact know when you are writing a new message -- cgit v1.2.3 From 8455e5b5dd82371d58b2d5e7474779cd6ee5d5f3 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 2 Dec 2015 12:54:55 +0100 Subject: hide message content in notifications in paranoia mode --- .../services/NotificationService.java | 50 +++++++++++++--------- src/main/res/values/strings.xml | 4 ++ 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index abd42f4c4..b54e54826 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -234,8 +234,13 @@ public class NotificationService { if (messages.size() > 0) { conversation = messages.get(0).getConversation(); final String name = conversation.getName(); - style.addLine(Html.fromHtml("" + name + " " - + UIHelper.getMessagePreview(mXmppConnectionService, messages.get(0)).first)); + if (Config.PARANOID_MODE) { + int count = messages.size(); + style.addLine(Html.fromHtml(""+name+" "+mXmppConnectionService.getResources().getQuantityString(R.plurals.x_messages,count,count))); + } else { + style.addLine(Html.fromHtml("" + name + " " + + UIHelper.getMessagePreview(mXmppConnectionService, messages.get(0)).first)); + } names.append(name); names.append(", "); } @@ -264,25 +269,30 @@ public class NotificationService { mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService() .get(conversation, getPixel(64))); mBuilder.setContentTitle(conversation.getName()); - Message message; - if ((message = getImage(messages)) != null) { - modifyForImage(mBuilder, message, messages, notify); + if (Config.PARANOID_MODE) { + int count = messages.size(); + mBuilder.setContentText(mXmppConnectionService.getResources().getQuantityString(R.plurals.x_messages,count,count)); } else { - modifyForTextOnly(mBuilder, messages, notify); - } - if ((message = getFirstDownloadableMessage(messages)) != null) { - mBuilder.addAction( - Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? - R.drawable.ic_file_download_white_24dp : R.drawable.ic_action_download, - mXmppConnectionService.getResources().getString(R.string.download_x_file, - UIHelper.getFileDescriptionString(mXmppConnectionService, message)), - createDownloadIntent(message) - ); - } - if ((message = getFirstLocationMessage(messages)) != null) { - mBuilder.addAction(R.drawable.ic_room_white_24dp, - mXmppConnectionService.getString(R.string.show_location), - createShowLocationIntent(message)); + Message message; + if ((message = getImage(messages)) != null) { + modifyForImage(mBuilder, message, messages, notify); + } else { + modifyForTextOnly(mBuilder, messages, notify); + } + if ((message = getFirstDownloadableMessage(messages)) != null) { + mBuilder.addAction( + Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? + R.drawable.ic_file_download_white_24dp : R.drawable.ic_action_download, + mXmppConnectionService.getResources().getString(R.string.download_x_file, + UIHelper.getFileDescriptionString(mXmppConnectionService, message)), + createDownloadIntent(message) + ); + } + if ((message = getFirstLocationMessage(messages)) != null) { + mBuilder.addAction(R.drawable.ic_room_white_24dp, + mXmppConnectionService.getString(R.string.show_location), + createShowLocationIntent(message)); + } } mBuilder.setContentIntent(createContentIntent(conversation)); } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index e312bd59d..69f964d70 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -549,4 +549,8 @@ This is not a valid port number This is not a valid hostname %1$d of %2$d accounts connected + + %d message + %d messages + -- cgit v1.2.3 From 0329c9c7384b4518514555fca70a968241acb1be Mon Sep 17 00:00:00 2001 From: Philip Flohr Date: Fri, 6 Nov 2015 11:14:05 +0100 Subject: users are now able to crop their avatar pictures using the android-crop library --- build.gradle | 4 +++ src/main/AndroidManifest.xml | 2 +- .../conversations/persistance/FileBackend.java | 4 +-- .../ui/PublishProfilePictureActivity.java | 39 ++++++++++++++++++---- src/main/res/values/strings.xml | 1 + 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index d1f962282..077469146 100644 --- a/build.gradle +++ b/build.gradle @@ -14,6 +14,9 @@ allprojects { repositories { jcenter() mavenCentral() + maven { + url 'http://lorenzo.villani.me/android-cropimage/' + } } } @@ -27,6 +30,7 @@ repositories { dependencies { compile project(':libs:MemorizingTrustManager') compile 'org.sufficientlysecure:openpgp-api:9.0' + compile 'com.soundcloud.android:android-crop:1.0.1@aar' compile 'com.android.support:support-v13:23.0.1' compile 'org.bouncycastle:bcprov-jdk15on:1.52' compile 'org.bouncycastle:bcmail-jdk15on:1.52' diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index fb5df34d6..9f434a626 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -153,7 +153,7 @@ android:name="android.support.PARENT_ACTIVITY" android:value="eu.siacs.conversations.ui.SettingsActivity"/> - + diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 35b836a7a..36b745053 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -486,14 +486,14 @@ public class FileBackend { return calcSampleSize(options, size); } - private int calcSampleSize(File image, int size) { + public static int calcSampleSize(File image, int size) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(image.getAbsolutePath(), options); return calcSampleSize(options, size); } - public static int calcSampleSize(BitmapFactory.Options options, int size) { + private static int calcSampleSize(BitmapFactory.Options options, int size) { int height = options.outHeight; int width = options.outWidth; int inSampleSize = 1; diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java index e01490f90..59ca10693 100644 --- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -1,10 +1,14 @@ package eu.siacs.conversations.ui; import android.app.PendingIntent; +import android.content.ActivityNotFoundException; import android.content.Intent; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; +import android.os.Parcel; +import android.provider.MediaStore; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; @@ -13,9 +17,16 @@ import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; +import com.soundcloud.android.crop.Crop; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -32,6 +43,7 @@ public class PublishProfilePictureActivity extends XmppActivity { private Button cancelButton; private Button publishButton; + final static int REQUEST_CROP_PICTURE = 92374; private Uri avatarUri; private Uri defaultUri; private OnLongClickListener backToDefaultListener = new OnLongClickListener() { @@ -147,11 +159,14 @@ public class PublishProfilePictureActivity extends XmppActivity { if (resultCode == RESULT_OK) { if (requestCode == REQUEST_CHOOSE_FILE) { this.avatarUri = data.getData(); - if (xmppConnectionServiceBound) { - loadImageIntoPreview(this.avatarUri); - } + Uri destination = Uri.fromFile(new File(getCacheDir(), "croppedAvatar")); + Crop.of(this.avatarUri, destination).asSquare().start(PublishProfilePictureActivity.this); } } + if (requestCode == Crop.REQUEST_CROP) { + this.avatarUri = Uri.fromFile(new File(getCacheDir(), "croppedAvatar")); + loadImageIntoPreview(this.avatarUri); + } } @Override @@ -217,9 +232,22 @@ public class PublishProfilePictureActivity extends XmppActivity { } } + private Bitmap loadScaledBitmap(String filePath, int reqSize) { + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(filePath,options); + options.inSampleSize = FileBackend.calcSampleSize(new File(filePath), reqSize); + options.inJustDecodeBounds = false; + return BitmapFactory.decodeFile(filePath,options); + } protected void loadImageIntoPreview(Uri uri) { - Bitmap bm = xmppConnectionService.getFileBackend().cropCenterSquare( - uri, 384); + Bitmap bm = null; + try{ + bm = loadScaledBitmap(uri.getPath(), Config.AVATAR_SIZE); + } catch (Exception e) { + e.printStackTrace(); + } + if (bm == null) { disablePublishButton(); this.hintOrWarning.setTextColor(getWarningTextColor()); @@ -261,5 +289,4 @@ public class PublishProfilePictureActivity extends XmppActivity { public void refreshUiReal() { //nothing to do. This Activity doesn't implement any listeners } - } diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 69f964d70..59c5e1c0f 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -314,6 +314,7 @@ \n\nhttps://github.com/kyleduo/SwitchButton\n(Apache License, Version 2.0) \n\nhttps://github.com/WhisperSystems/libaxolotl-java\n(GPLv3) \n\nhttps://github.com/vinc3m1/RoundedImageView\n(Apache License, Version 2.0) + \n\nhttps://github.com/jdamcd/android-crop\n(Apache License, Version 2.0) Quiet Hours Start time -- cgit v1.2.3 From 02c6793ca9ae195494c7be86f7e0d7a6c08a04c0 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 2 Dec 2015 15:30:03 +0100 Subject: fixed avatar loading for non-file uris --- .../eu/siacs/conversations/persistance/FileBackend.java | 4 ++-- .../conversations/ui/PublishProfilePictureActivity.java | 14 +++++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 36b745053..febb09705 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -486,14 +486,14 @@ public class FileBackend { return calcSampleSize(options, size); } - public static int calcSampleSize(File image, int size) { + private static int calcSampleSize(File image, int size) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(image.getAbsolutePath(), options); return calcSampleSize(options, size); } - private static int calcSampleSize(BitmapFactory.Options options, int size) { + public static int calcSampleSize(BitmapFactory.Options options, int size) { int height = options.outHeight; int width = options.outWidth; int inSampleSize = 1; diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java index 59ca10693..542c27432 100644 --- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -1,14 +1,11 @@ package eu.siacs.conversations.ui; import android.app.PendingIntent; -import android.content.ActivityNotFoundException; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Bundle; -import android.os.Parcel; -import android.provider.MediaStore; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; @@ -21,7 +18,6 @@ import com.soundcloud.android.crop.Crop; import java.io.File; import java.io.FileNotFoundException; -import java.io.IOException; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -232,18 +228,18 @@ public class PublishProfilePictureActivity extends XmppActivity { } } - private Bitmap loadScaledBitmap(String filePath, int reqSize) { + private Bitmap loadScaledBitmap(Uri uri, int reqSize) throws FileNotFoundException { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(filePath,options); - options.inSampleSize = FileBackend.calcSampleSize(new File(filePath), reqSize); + BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); + options.inSampleSize = FileBackend.calcSampleSize(options, reqSize); options.inJustDecodeBounds = false; - return BitmapFactory.decodeFile(filePath,options); + return BitmapFactory.decodeStream(getContentResolver().openInputStream(uri)); } protected void loadImageIntoPreview(Uri uri) { Bitmap bm = null; try{ - bm = loadScaledBitmap(uri.getPath(), Config.AVATAR_SIZE); + bm = loadScaledBitmap(uri, Config.AVATAR_SIZE); } catch (Exception e) { e.printStackTrace(); } -- cgit v1.2.3 From 025cbf7d44f72544155e4074ef754d750bd86b2c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 2 Dec 2015 15:34:09 +0100 Subject: show tor config in paranoid mode --- src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 961d2cd6e..fc8b36fea 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -491,7 +491,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } } } - this.mUseTor = getPreferences().getBoolean("use_tor", false); + this.mUseTor = Config.PARANOID_MODE || getPreferences().getBoolean("use_tor", false); this.mNamePort.setVisibility(mUseTor ? View.VISIBLE : View.GONE); } -- cgit v1.2.3 From a3eb540f059f9123799c54d69201eba8a096e116 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Wed, 4 Nov 2015 20:56:45 -0600 Subject: Show status message when contact requests presence Remove presence when conversation closed --- .../java/eu/siacs/conversations/entities/Message.java | 2 +- .../eu/siacs/conversations/parser/PresenceParser.java | 16 ++++++++++++++-- .../conversations/services/XmppConnectionService.java | 7 +++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 1eafa45fa..b59b0b38c 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -171,7 +171,7 @@ public class Message extends AbstractEntity { } public static Message createStatusMessage(Conversation conversation, String body) { - Message message = new Message(); + final Message message = new Message(); message.setType(Message.TYPE_STATUS); message.setConversation(conversation); message.setBody(body); diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index d83347d82..59b94bc0c 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -6,6 +6,7 @@ import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.generator.PresenceGenerator; @@ -44,8 +45,8 @@ public class PresenceParser extends AbstractParser implements } } - public void parseContactPresence(PresencePacket packet, Account account) { - PresenceGenerator mPresenceGenerator = mXmppConnectionService.getPresenceGenerator(); + public void parseContactPresence(final PresencePacket packet, final Account account) { + final PresenceGenerator mPresenceGenerator = mXmppConnectionService.getPresenceGenerator(); final Jid from = packet.getFrom(); if (from == null) { return; @@ -93,6 +94,17 @@ public class PresenceParser extends AbstractParser implements mPresenceGenerator.sendPresenceUpdatesTo(contact)); } else { contact.setOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST); + final String statusMessage = packet.findChildContent("status"); + if (statusMessage != null && !statusMessage.isEmpty()) { + final Conversation conversation = mXmppConnectionService.findOrCreateConversation( + account, contact.getJid().toBareJid(), false); + conversation.add(new Message( + conversation, + statusMessage, + Message.ENCRYPTION_NONE, + Message.STATUS_RECEIVED + )); + } } } mXmppConnectionService.updateRosterUi(); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index fff8a9848..8e4c9c68c 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1322,6 +1322,13 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa leaveMuc(conversation); } else { conversation.endOtrIfNeeded(); + if (conversation.getContact().getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { + Log.d(Config.LOGTAG, "Canceling presence request from " + conversation.getJid().toString()); + sendPresencePacket( + conversation.getAccount(), + mPresenceGenerator.stopPresenceUpdatesTo(conversation.getContact()) + ); + } } this.databaseBackend.updateConversation(conversation); this.conversations.remove(conversation); -- cgit v1.2.3 From 3553b15c9f018471172bfce83c536baf2812b6d4 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 2 Dec 2015 17:24:56 +0100 Subject: renamed x509 verified omemo to v\OMEMO --- src/main/res/values/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 0726375d6..584b419f5 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -82,7 +82,7 @@ Send unencrypted message Send OTR encrypted message Send OMEMO encrypted message - Send OMEMO (X.509 verified) encrypted message + Send v\\OMEMO encrypted message Send OpenPGP encrypted message Your nickname has been changed Send unencrypted @@ -212,9 +212,9 @@ Your fingerprint OTR fingerprint OMEMO fingerprint - OMEMO fingerprint (X.509 verified) + v\\OMEMO fingerprint OMEMO fingerprint of message - OMEMO fingerprint (X.509 verified) of message + v\\OMEMO fingerprint of message Own OMEMO fingerprint Other devices Trust OMEMO Fingerprints -- cgit v1.2.3 From 6f8f35031f809b9bd71c50bf04e58b38457eb4ee Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 2 Dec 2015 17:25:22 +0100 Subject: version bump to 1.8.0-beta --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 077469146..48bf2ed38 100644 --- a/build.gradle +++ b/build.gradle @@ -53,8 +53,8 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 21 - versionCode 107 - versionName "1.7.3" + versionCode 108 + versionName "1.8.0-beta" project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName); } -- cgit v1.2.3 From b60c902810c813bbfa2bf5fcfe5db979b7f44bbf Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 2 Dec 2015 17:27:56 +0100 Subject: pulled new translations from transifex --- src/main/res/values-ar/strings.xml | 2 - src/main/res/values-bg/strings.xml | 6 - src/main/res/values-ca/strings.xml | 4 - src/main/res/values-cs/strings.xml | 24 +- src/main/res/values-de/strings.xml | 46 ++-- src/main/res/values-el/strings.xml | 4 - src/main/res/values-es/strings.xml | 8 +- src/main/res/values-eu/strings.xml | 24 +- src/main/res/values-fr/strings.xml | 110 ++++---- src/main/res/values-gl/strings.xml | 2 - src/main/res/values-id/strings.xml | 4 - src/main/res/values-it/strings.xml | 4 - src/main/res/values-iw/strings.xml | 43 ++-- src/main/res/values-ja/strings.xml | 24 +- src/main/res/values-ko/strings.xml | 4 - src/main/res/values-nb-rNO/strings.xml | 57 ++++- src/main/res/values-nl/strings.xml | 7 +- src/main/res/values-pl/strings.xml | 6 - src/main/res/values-pt/strings.xml | 3 - src/main/res/values-ro-rRO/strings.xml | 454 +++++++++++++++++++++++++++++++-- src/main/res/values-ru/strings.xml | 61 ++++- src/main/res/values-sk/strings.xml | 35 ++- src/main/res/values-sr/strings.xml | 112 ++++---- src/main/res/values-sv/strings.xml | 24 +- src/main/res/values-zh-rCN/strings.xml | 93 +++++-- src/main/res/values-zh-rTW/strings.xml | 3 - 26 files changed, 879 insertions(+), 285 deletions(-) diff --git a/src/main/res/values-ar/strings.xml b/src/main/res/values-ar/strings.xml index 586a58cf6..08d1dcbec 100644 --- a/src/main/res/values-ar/strings.xml +++ b/src/main/res/values-ar/strings.xml @@ -28,7 +28,6 @@ دقائق %d منذ محادثات غير مقروءة ارسال - رسالة مشفّرة .. الرجاء الإنتظار اللقب مستخدم من قبل مدير مالك @@ -90,7 +89,6 @@ Conversations::لا يستطيع تشفير الرساله\n\nمن فضلك أخبر صديقك بتنصيب تطبيق OpenPGP. OpenPGP-لايوجد مفاتيح Conversations::لا يستطيع تشفير الرساله\n\nمن فضلك أخبر صديقك بتنصيب تطبيق OpenPGP. - تلقيت رساله مشفّرة .. لمسه بأناملك لعرضها. عام الريسورس ضبط استقبال الملفات diff --git a/src/main/res/values-bg/strings.xml b/src/main/res/values-bg/strings.xml index 030432ad6..9988b9dee 100644 --- a/src/main/res/values-bg/strings.xml +++ b/src/main/res/values-bg/strings.xml @@ -28,7 +28,6 @@ преди %d минути непрочетени разговори изпращане... - Дешифроване на съобщението. Моля, изчакайте... Псевдонимът вече се използва Администратор Собственик @@ -93,7 +92,6 @@ Conversations не може да шифрова съобщенията Ви, тъй като Вашият контакт не обявява публичния си ключ.\n\nМоля, помолете го/я да инсталира и настрои OpenPGP. Не са открити OpenPGP ключове Conversations не може да шифрова съобщенията Ви, тъй като Вашите контакти не обявяват публичните си ключове.\n\nМоля, помолете го да инсталират и настроят OpenPGP. - Получено е шифровано съобщение. Докоснете, за да го прегледате и дешифровате. Общи XMPP ресурс Името, с което се определя този клиент @@ -172,7 +170,6 @@ Паролите са различни Това не е правилен Jabber идентификатор Няма достатъчно памет. Изображението е твърде голямо. - Искате ли да добавите %s в списъка си от телефонни контакти? на линия свободен за разговор отсъстващ @@ -212,7 +209,6 @@ Собствен отпечатък OMEMO Други устройства Доверяване на отпечатъци OMEMO - Изтегляне на ключовете... Готово Потвърждаване Дешифроване @@ -442,7 +438,6 @@ Предлагане на %s Скриване на тези извън линия Деактивиране на профила - %s пише... %s спря да пише Известия за писането Позволяване на контакта Ви да вижда, когато пишете ново съобщение @@ -485,7 +480,6 @@ Неуспешно сваляне: Неуспешна връзка със сървъра Използване на бял фон Показване на получените съобщения с черен текст на бял фон - Време на изчакване на DNS Повредено Настройки за присъствието Отсъстващ, когато екранът е изключен diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml index 806ed7a03..363eb20b1 100644 --- a/src/main/res/values-ca/strings.xml +++ b/src/main/res/values-ca/strings.xml @@ -28,7 +28,6 @@ %de minuts abans Converses sense llegir o no llegides enviant… - Desxifrant missatge. Espera si us plau… El sobrenom ja està en ús Administrador Propietari @@ -90,7 +89,6 @@ Conversations no ha pogut xifrar els teus missatges perquè el teu contacte no està anunciant la seva clau pública.\n\nSi us plau, demana al teu contacte que configuri OpenPGP. No hi ha claus OPENPGP trobades Coversations no és possible xifrar les teves converses perquè els teus contactes no han mostrat la seva clau pública.\n\n Si us plau, pregunti als seus contactes per configurar OpenPGP . - Missatge xifrat rebut. Prem per desxifrar i veure-ho. General Recursos XMPP El nom que identifica aquest client amb @@ -165,7 +163,6 @@ Contrasenyes no coincideixen Aquesta identificació de Jabber no és vàlida Fora de la capacitat de la mèmoria. L\'imatge és massa gran - Voleu afegir %s a la teva llista de contactes del telèfon? En línia Lliure per xatejar Fora @@ -406,7 +403,6 @@ Oferint %s Amaga el fora de línia Deshabilita el compte - %s està escrivint... %s ha deixat d\'escriure Notificacions d\'escriptura Permet el teu contacte saber quan estàs escrivint un missatge nou diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index 0c5dca552..eb80a2cec 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -28,7 +28,6 @@ před %d minutami nepřečtené konverzace odesílám… - Dešifruji zprávu. Chvíli strpení… Přezdívka se již používá Administrátor Vlastník @@ -74,6 +73,7 @@ Smaže historii konverzací Chcete smazat všechny zprávy v této konverzaci?\n\nVarování: Toto neovlivní zprávy uložené na jiných přístrojích nebo serverech. Smazat zprávy + Poté ukončit tuto konverzaci Vybrat aktualizaci stavu pro kontakt Odeslat nešifrovanou zprávu Poslat OTR šifrovanou zprávu @@ -92,7 +92,6 @@ Není možné zašifrovat zprávu v aplikaci Konverzace, protože druhá strana neoznamuje svůj veřejný klíč.\n\nPožádejte svůj kontakt ať si nastaví OpenPGP. Nebyly nalezeny žádné OpenPGP klíče Není možné zašifrovat zprávy v aplikaci Konverzace, protože kontakty neoznamují svůj veřejný klíč.\n\nPožádejte své kontakty ať si nastaví OpenPGP. - Byla přijata šifrovaná zpráva. Ťukni pro dešifrování a přečtení. Obecné XMPP zdroj Jméno se kterým se tento klient identifikuje @@ -171,7 +170,6 @@ Hesla nesouhlasí Toto není platné Jabber ID Nedostatek paměti. Obrázek je příliš velký - Chcete přidat %s do svého telefonního seznamu? online volný pro chat pryč @@ -211,7 +209,6 @@ Můj OMEMO otisk Ostatní přístroje Věřit OMEMO otiskům - Získávám klíče... Hotovo Ověřit Dešifrovat @@ -334,6 +331,9 @@ Conversations Ponechat službu v popředí Zamezit operačnímu systému v ukončení připojení + Exportovat logy + Zapsat logy na SD kartu + Zapisování logů na SD kartu Vybrat soubor Přijímám %1$s (%2$d%% dokončeno) Stáhnout %s @@ -438,7 +438,6 @@ Nabízím %s Skrýt offline Vypnout účet - %s píše... %s přestal(a) psát Upozornění při psaní Oznamovat kontaktům že píšete novou zprávu @@ -483,6 +482,19 @@ Stahování selhalo: Nelze se připojit k hostu Použít bílé pozadí Zobrazovat přijaté zprávy jako černý text na bílém pozadí - Vypršení v DNS Rozbité + Nastavení přítomnosti + Pryč při vypnuté obrazovce + Při vypnuté obrazovce označí váš stav jako pryč + Nedostupný při vypnutém zvuku + Při vypnutém zvuku označí váš stav jako nedostupný + Přidat účet s certifikátem + Nelze načíst certifikát + Nechat prázdné pro ověření s certifikátem + Captcha text + Captcha vyžadována + opište text z obrázku + Řetězec certifikátů není důvěryhodný + Jabber ID neodpovídá certifikátu + Obnovit certifikát diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index b7cc4440f..e457c46ca 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -28,7 +28,6 @@ vor %d Minuten ungelesene Unterhaltungen senden… - Nachricht wird entschlüsselt. Bitte warten … Nickname wird bereits verwendet Administrator Eigentümer @@ -42,9 +41,9 @@ Alle Kontakte von %s entsperren? Kontakt gesperrt Möchtest du %s von deiner Kontaktliste entfernen? Die Unterhaltung mit dieser Konferenz wird dabei nicht entfernt. - Neues Konto auf dem Server erstellen + Neues Konto auf Server erstellen Passwort ändern - Teile mit… + Teilen mit… Unterhaltung beginnen Kontakt einladen Kontakte @@ -69,7 +68,7 @@ Kontakt hinzufügen Zustellung fehlgeschlagen abgelehnt - Bereite Bild für die Übertragung vor + Bild wird für Übertragung vorbereitet Verlauf löschen Verlauf löschen Möchtest du alle Nachrichten in dieser Unterhaltung löschen?\n\nAchtung: Dies beeinflusst nicht Nachrichten, die auf anderen Geräten oder Servern gespeichert sind. @@ -93,7 +92,6 @@ Conversations ist nicht in der Lage, deine Nachrichten zu verschlüsseln, weil dein Kontakt seinen oder ihren Schlüssel nicht preisgibt.\n\nBitte sag deinem Kontakt, er oder sie möge OpenPGP einrichten. Keine OpenPGP-Schlüssel gefunden Conversations ist nicht in der Lage, deine Nachrichten zu verschlüsseln, weil deine Kontakte ihre Schlüssel nicht preisgeben.\n\nBitte sage deinen Kontakten, sie mögen OpenPGP einrichten. - Verschlüsselte Nachricht erhalten. Drücke hier, um sie zu entschlüsseln und anzuzeigen. Allgemeines XMPP-Ressource Der Name, mit dem sich der Client selbst identifiziert @@ -119,7 +117,7 @@ Fehler mit OpenKeychain Fehler beim Entschlüsseln der Datei Annehmen - Ein unbekannter Fehler ist aufgetreten + Ein Fehler ist aufgetreten Online-Status Erlaube neu hinzugefügten Kontakten meinen Online-Status zu sehen und frage um Erlaubnis, ihren sehen zu dürfen Abonnements @@ -172,7 +170,6 @@ Passwörter stimmen nicht überein Ungültige Jabber-ID Zu wenig Speicher vorhanden. Das Bild ist zu groß - Möchtest du %s zum Telefonbuch hinzufügen? online bereit abwesend @@ -212,7 +209,6 @@ Eigener OMEMO-Fingerabdruck Andere Geräte OMEMO-Fingerabdruck vertrauen - Schlüssel abrufen... Erledigt Überprüfen Entschlüsseln @@ -250,7 +246,7 @@ Dein Server unterstützt die Veröffentlichung von Avataren nicht. private Nachricht: privat an %s: - Sende private Nachricht an %s… + Private Nachricht an %s senden… Verbinden Das Konto existiert bereits Weiter @@ -285,7 +281,7 @@ Ruhige Stunden aktivieren Benachrichtigungen sind während der ruhigen Stunden stumm. Schrift vergrößern - Größere Schrift verwenden + Größere Schriften für die gesamte App verwenden \"Senden\"-Schaltfläche zeigt Online-Status an Empfangsbestätigungen anfragen Empfangene Nachrichten werden mit einem grünen Häkchen markiert. Bitte beachte, dass dies nicht in allen Fällen funktioniert. @@ -333,21 +329,21 @@ Kontakt fordert eine Überprüfung an Keine gültige OTR-Sitzung gefunden! Conversations - Den Dienst im Vordergrund ausführen. + Dienst im Vordergrund ausführen Verhindert, dass Android Conversations beendet und die Verbindung unterbricht Chats exportieren Chats auf SD-Karte schreiben - Chats auf SD-Karte schreiben + Chats werden auf SD-Karte geschrieben Datei auswählen - Empfange %1$s (%2$d%% abgeschlossen) - %s wird heruntergeladen + Empfange %1$s (%2$d%% abgeschlossen) + %s herunterladen Datei %s öffnen Senden (%1$d%% abgeschlossen) - Datei wird für den Versand vorbereitet + Datei wird für die Übertragung vorbereitet %s zum Herunterladen angeboten - Datei-Übertragung abbrechen - Datei-Übertragung fehlgeschlagen + Übertragung abbrechen + Übertragung fehlgeschlagen Datei wurde gelöscht Keine Anwendung zum Öffnen der Datei gefunden Fingerabdruck konnte nicht überprüft werden @@ -357,7 +353,7 @@ Schreibgeschütze Tags unterhalb der Kontakte anzeigen Benachrichtigungen aktivieren Konferenz erstellen mit… - Konferenz-Server kann nicht gefunden werden + Kein Konferenz-Server gefunden Erstellen der Konferenz fehlgeschlagen! Konferenz erstellt! Schlüssel akzeptiert! @@ -435,14 +431,13 @@ Android App Kontakt %s empfangen - Vordergrund-Dienst beenden + Vordergrund-Dienst deaktivieren Antippen, um Conversations zu öffnen Avatar wurde gespeichert %s wird gesendet %s wird angeboten Offline verstecken Konto abschalten - %s schreibt… %s schreibt nicht mehr Tipp-Benachrichtigung Informiere deine Kontakte, wenn du eine Nachricht eintippst. @@ -485,14 +480,13 @@ Download fehlgeschlagen: keine Verbindung zum Host Weißen Hintergrund benutzen Empfangene Nachrichten als schwarzen Text auf weißem Hintergrund anzeigen - Zeitüberschreitung bei der Namensauflösung Fehlerhaft Status Einstellungen - Abwesend - Setze deinen Status auf abwesend, wenn dein Bildschirm abgeschaltet ist - Nicht verfügbar - Setze deinen Status auf nicht verfügbar, wenn dein Gerät stumm geschaltet ist - Kontakt mit Zertifikat hinzufügen + Abwesend bei abgeschaltetem Bildschirm + Setzt deinen Status auf \"abwesend\", solange dein Bildschirm abgeschaltet ist + Nicht verfügbar bei Stummschaltung + Setzt deinen Status auf \"nicht verfügbar\", solange dein Gerät stummgeschaltet ist + Konto mit Zertifikat hinzufügen Zertifikat kann nicht gelesen werden Leer lassen, um mit Zertifikat anzumelden Captcha Text diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml index ed38d0c06..cd8f9e44e 100644 --- a/src/main/res/values-el/strings.xml +++ b/src/main/res/values-el/strings.xml @@ -28,7 +28,6 @@ πριν από %d λεπτά μη αναγνωσμένες Συζητήσεις αποστολή... - Αποκρυπτογράφηση μηνύματος. Παρακαλώ περιμένετε... Το ψευδώνυμο είναι ήδη σε χρήση Διαχειριστής Κάτοχος @@ -90,7 +89,6 @@ Το Conversations αδυνατεί να κρυπτογραφήσει τα μηνύματά σας γιατί η επαφή σας δεν ανακοινώνει το δημόσιο κλειδί της.\n\nΠαρακαλώ ζητήστε από την επαφή σας να εγκαταστήσει το OpenPGP. Δεν βρέθηκαν κλειδιά OpenPGP Το Conversations αδυνατεί να κρυπτογραφήσει τα μηνύματά σας γιατί οι επαφές σας δεν ανακοινώνουν το δημόσιο κλειδί τους.\n\nΠαρακαλώ ζητήστε από τις επαφές σας να εγκαταστήσουν το OpenPGP. - Λήψη κρυπτογραφημένου μηνύματος. Επιλέξτε για ανάγνωση και αποκρυπτογράφηση. Γενικά πόρος XMPP Το όνομα με το οποίο ταυτοποιείται αυτό το πρόγραμμα-πελάτης @@ -165,7 +163,6 @@ Τα συνθηματικά δεν ταιριάζουν Αυτή δεν είναι έγκυρη ταυτότητα Jabber Πλήρης μνήμη. Η εικόνα είναι πολύ μεγάλη - Θέλετε να προσθέσετε την επαφή %s στον τηλεφωνικό κατάλογο του τηλεφώνου σας; συνδεμένος ελεύθερος για συνομιλία λείπω @@ -406,7 +403,6 @@ Προσφορά του %s Απόκρυψη των εκτός σύνδεσης Απενεργοποίηση λογαριασμού - Ο χρήστης %s γράφει... Ο χρήστης %s σταμάτησε να γράφει Ειδοποιήσεις πληκτρολόγησης Επιτρέψτε στην επαφή σας να γνωρίζει πότε γράφετε ένα νέο μήνυμα diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index cdddfb164..41e0a6668 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -28,7 +28,6 @@ hace %d min conversaciones por leer enviando… - Descifrando mensaje. Espera por favor… El apodo ya está en uso Administrador Propietario @@ -74,7 +73,7 @@ Limpiar historial de conversación ¿Quieres borrar todos los mensajes de esta conversación?\n\nAviso: Esto no afectará a los mensajes guardados en otros dispositivos o servidores. Borrar mensajes - Terminar esta conversación después + Además, terminar esta conversación Selecciona recurso del contacto Enviar mensaje sin cifrar Enviar mensaje cifrado con OTR @@ -93,7 +92,6 @@ Conversations no ha podido cifrar tus mensajes porque tu contacto no está anunciando su clave publica.\n\nPor favor, pide a tu contacto que configure OpenPGP. Claves OpenPGP no encontradas Conversations no ha podido cifrar tus mensajes porque tus contactos no están anunciando su clave publica.\n\nPor favor, pide a tus contactos que configuren OpenPGP. - Mensaje cifrado recibido. Pulsa para ver. General Recurso El nombre que identifica el cliente que estás utilizando @@ -172,7 +170,6 @@ Las contraseñas no coinciden El identificador no es un identificador Jabber válido Sin memoria. La imagen es demasiado grande - ¿Quieres añadir a %s a tus contactos del teléfono? Disponible Hablador Ausente @@ -212,7 +209,6 @@ Tu huella digital OMEMO Otros dispositivos Huellas digitales OMEMO de confianza - Buscando claves... Hecho Verificar Descifrar @@ -442,7 +438,6 @@ Ofreciendo %s Ocultar desconectados Deshabilitar Cuenta - %s está escribiendo... %s ha dejado de escribir Notificación de escritura Permite a tus contactos saber cuando estás escribiendo un nuevo mensaje @@ -485,7 +480,6 @@ Error al descargar: No se ha podido conectar con el servidor Usar fondo blanco Mostrar mensajes recibidos en texto negro con fondo blanco - Timeout en DNS Error Opciones de presencia Ausente con pantalla apagada diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml index 86f39b0f6..28efc8d26 100644 --- a/src/main/res/values-eu/strings.xml +++ b/src/main/res/values-eu/strings.xml @@ -28,7 +28,6 @@ %d min lehenago irakurri gabeko elkarrizketak bidaltzen… - Mezua desenkriptatzen. Mesedez itxaron… Ezizena erabilita dagoeneko Administratzailea Jabea @@ -74,6 +73,7 @@ Elkarrizketa historia garbitu Elkarrizketa honetako mezu guztiak ezabatu nahi al dituzu?\n\nAbisua: Honek ez du beste gailu edo zerbitzarietan gordetako mezuetan eraginik izango. Mezuak ezabatu + Elkarrizketa hau jarraian amaitu Hautatu agerpena kontaktuarentzat Enkriptatu gabeko mezua bidali OTRz enkriptatutako mezua bidali @@ -92,7 +92,6 @@ Conversations ez da zure mezuak enkriptatzeko gai zure kontaktua bere gako publikoa jakinarazten ez dagoelako.\n\nMesedez eskatu ezaiozu zure kontaktuari openPGP konfigura dezan. Ez da OpenPGP gakorik aurkitu Conversations ez da zure mezuak enkriptatzeko gai zure kontaktuak haien gako publikoa jakinarazten ez daudelako.\n\nMesedez eskatu ezaiezu zure kontakuei OpenPGP konfigura dezaten. - Enkriptatutako mezua jaso da. Ukitu ikusi eta desenkriptatzeko. Orokorrak XMPP baliabidea Bezero honek bere burua aurkezteko erabiltzen duen izena @@ -171,7 +170,6 @@ Pasahitzak ez dute bat egiten Hau ez da Jabber ID baliodun bat Memoriarik gabe. Irudia handiegia da - %s zure telefono kontaktu zerrendara gehitu nahi al duzu? konektatuta hitzegiteko aske kanpoan @@ -211,7 +209,6 @@ Norberaren OMEMO hatz-marka Beste gailuak OMEMO hatz-marketaz fidatu - Gakoak eskuratzen... Eginda Egiaztatu Desenkriptatu @@ -334,6 +331,9 @@ Conversations Zerbitzua atzeko planoan mantendu Sistema eragileak zure konexioa hiltzea galarazten du + Erregistroak esportatu + Erregistroak SD txartelean gorde + Erregistroak SD txartelean gordetzen Fitxategia aukeratu %1$s jasotzen (%2$d%% osatua) %s deskargatu @@ -438,7 +438,6 @@ %s eskeintzen... Lineaz kanpokoak ezkutatu Kontua ezgaitu - %s idazten ari da... %s(e)k idazteari utzi dio Idazketa jakinarazpenak Zure kontaktuak mezu berri bat noiz idazten ari zaren jakin dezan baimendu @@ -481,6 +480,19 @@ Deskargak huts egin du: ezin izan da ostalarira konektatu Atzeko-planoan kolore zuria erabili Jasotako mezuak testu beltza atzeko-plano zuri baten gainean bezala erakutsi - DNSan denboraz kanpoko arazoa Hondatuta + Presentzia ezarpenak + Urrun pantaila itzalita dagoenean + Zure baliabidea urrun bezala markatzen du pantaila itzalita dagoenean + Ez eskuragarri modu isilean + Zure baliabidea ez eskuragarri bezala markatzen du mugikorra modu isilean dagoenean + Kontua ziurtagiriarekin gehitu + Ezin izan da ziurtagiria aztertu + Utzi hutsik ziurtagiririk gabe autentifikatzeko + Captcharen testua + Captcha beharrezkoa da + Sartu irudiaren testua + Ziurtagiriaren katea ez da fidagarria + Jabber IDa ez du ziurtagiriarekin bat egiten + Ziurtagiria berriztu diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml index b6c5f0daf..a5a2d5230 100644 --- a/src/main/res/values-fr/strings.xml +++ b/src/main/res/values-fr/strings.xml @@ -28,7 +28,6 @@ Il y a %d minutes Conversations non lues Envoi… - Déchiffrement du message. Veuillez patienter... Cet identifiant est déjà utilisé. Administrateur Propriétaire @@ -74,6 +73,7 @@ Vider l\'historique de la conversation Voulez-vous supprimer tous les messages de cette conversation ?\n\nAttention : Les messages seront supprimés uniquement sur cet appareil. Supprimer les messages + Fermer cette conversation ensuite Choisir le status de présence Envoyer un message non chiffré Envoyer un message chiffré avec OTR @@ -92,26 +92,25 @@ Conversations ne peut pas chiffrer vos messages car votre correspondant n\'a pas communiqué sa clef publique.\n\nDemandez-lui de configurer OpenPGP. Aucune clef OpenPGP n\'a été trouvée. Conversations ne peut pas chiffrer votre message car vos contacts ne communiquent pas leur clef publique.\n\nDemandez-leur de configurer OpenPGP. - Message chiffré reçu. Appuyez pour le déchiffrer. Général Ressource XMPP Nom utilisé par ce client pour s\'identifier Accepter les fichiers Accepter automatiquement les fichiers plus petits que… - Paramètres de notification + Options de notification Notifications - Notifier l\'arrivée d\'un message + Notifier de l\'arrivée d\'un message. Vibration - Vibrer lors de l\'arrivée d\'un message + Vibrer lors de l\'arrivée d\'un message. Sonore - Jouer une sonnerie pour notifier - Notifications dans les conférences publiques - Toujours notifier l\'arrivée d\'un message dans une conférence publique, même si votre nom n\'y apparaît pas + Jouer une sonnerie pour notifier. + Notifications et conf. publiques + Toujours notifier de l\'arrivée d\'un message dans une conférence publique, même si votre nom n\'y apparaît pas. Période sans notification Désactiver momentanément les notifications après l\'arrivée d\'une copie carbone. Options avancées - Ne jamais envoyer de rapports d\'erreurs - En envoyant des logs vous aidez au développement de Conversations. + Ne pas envoyer de rapports d\'erreurs + En envoyant des logs vous aidez le développement de Conversations. Confirmation de lecture Informer le contact lorsque vous avez reçu et lu un message. Options d\'interface @@ -119,14 +118,14 @@ Erreur d\'E/S lors du déchiffrement du fichier Accepter Une erreur s\'est produite - Accepter les mises à jour de présence - Demander et accepter par avance les mises à jour de présence des contacts créés. + Autoriser les màj de présence + Autoriser et demander par avance les mises à jour de présence des contacts ajoutés. Publications Votre compte Clefs - Envoyer les mises à jour de présence - Recevoir les mises à jour de présence - Demander les mises à jour de présence + Envoyer mes màj de présence + Recevoir ses màj de présence + Demander les màj de présence Choisir une image Prendre une photo Accepter par avance les demandes de publication. @@ -171,7 +170,6 @@ Les deux mots de passe ne correspondent pas. Cet identifiant n\'est pas valide. Plus de mémoire disponible. L\'image est trop volumineuse. - Voulez-vous ajouter %s aux contacts du téléphone ? En ligne Disponible Absent @@ -189,8 +187,8 @@ XEP-0198 : Gestion des flux XEP-0163 : PEP (Avatars / OMEMO) XEP-0363 : Envoi de fichiers via HTTP - disponible - indisponible + supporté + non supporté Aucune annonce de clef publique en ligne à l\'instant en ligne il y a 1 minute @@ -211,7 +209,6 @@ Votre empreinte OMEMO Autres appareils Faire confiance aux empreintes OMEMO - Récupération des clefs... Terminé Vérifier Déchiffrer @@ -269,35 +266,35 @@ Etes-vous sûr de vouloir supprimer l\'empreinte ? Ignorer Attention : peut poser problème si l\'un des deux correspondants n\'a pas activé les mises à jour de présence.\n\nVérifiez dans les détails du contact que vous y avez bien souscrit. - Paramètres de chiffrement + Options de chiffrement Forcer le chiffrement de bout en bout Toujours envoyer des messages chiffrés (sauf pour les conférences) - Ne pas sauvegarder les messages chiffrés - Attention : peut provoquer la perte de messages - Options avancées - À utiliser avec précaution + Messages chiffrés non sauvegardés + Attention : peut provoquer la perte de messages. + Paramètres expert + À utiliser avec précaution. À propos Informations sur la version et les licenses Heures tranquilles Heure de début Heure de fin Activer les heures tranquilles - Les notifications seront muettes pendant les heures tranquilles + Les notifications seront muettes pendant les heures tranquilles. Augmenter la taille du texte - Augmenter la taille du texte partout dans l\'application - Le bouton Envoyer permet d\'indiquer le statut - Demander des accusés de réception - Les messages reçus seront marqués d\'une coche verte (si supporté) - Changer la couleur du bouton Envoyer pour indiquer le statut du contact + Augmenter la taille du texte partout dans l\'application. + Statut sur le bouton Envoyer + Accusés de réception + Les messages reçus seront marqués d\'une coche verte (si supporté). + Le bouton Envoyer change de couleur pour indiquer le statut du contact. Autres Nom de la conférence - Identifier les conférences par leur nom plutôt que leur JID + Identifier les conférences par leur sujet plutôt que leur JID. Empreinte OTR copiée dans le presse-papier ! Empreinte OMEMO copiée dans le presse-papier ! Vous êtes banni de cette conférence Cette conférence est réservée aux membres Vous avez été éjecté de cette conférence - utiliser le compte %s + avec le compte %s Vérification de %s sur l\'hôte HTTP Vous n\'êtes pas connecté. Essayez plus tard. Vérification de la taille de %s @@ -317,7 +314,7 @@ Vérifier l\'OTR Supprimer l\'empreinte Scanner - (ou faites se toucher les combinés) + (ou faites se toucher les appareils) Socialist Millionaire Protocol Indice ou question Secret partagé @@ -332,9 +329,12 @@ Le contact requiert la vérification du SMP Aucune session OTR valide n\'a été trouvée ! Conversations - Garder le service au premier-plan - Évite que le système ne ferme votre connexion - Choix le fichier + Garder le service au 1er plan + Évite que le système ne ferme votre connexion. + Exporter les historiques + Sauvegarder les historiques sur la carte SD + Sauvegarde des historiques sur la carte SD en cours... + Choix du fichier Réception %1$s (%2$d%% complété) Télécharger %s fichier @@ -350,7 +350,7 @@ Vérifier manuellement Êtes-vous sûr de vouloir vérifier l\'empreinte OTR de vos contacts ? Afficher les tags dynamiques - Afficher les tags en lecture-seule sous les contacts + Afficher des tags en lecture seule en dessous des contacts. Activer les notifications Créer une conférence avec… Aucun serveur de conférence disponible @@ -420,10 +420,10 @@ 8 heures Jusqu\'à nouvel ordre Options de saisie - Entrée permet d\'envoyer - Utiliser la touche Entrée pour envoyer un message + Touche Entrée pour envoyer + Utiliser la touche Entrée pour envoyer un message. Afficher la touche Entrée - Remplacer le bouton Émoticônes par un bouton Entrée + Remplacer le bouton des Émoticônes par un bouton Entrée. audio vidéo image @@ -431,17 +431,16 @@ Application Android Contact %s reçu(e) - Ne plus garder le service au premier plan + Ne plus garder le service au 1er plan Cliquez pour ouvrir Conversations L\'avatar a été publié ! %s en cours d\'envoi En train de proposer un(e) %s Se cacher hors-ligne Désactiver le compte - %s écrit un message... %s a arrêté d\'écrire Notifications d\'écriture - Permettre à votre contact de savoir que vous écrivez un message + Informer votre contact lorsque vous êtes en train d\'écrire un message. Envoyer la position Afficher la position Aucune application trouvée pour afficher la position @@ -449,10 +448,10 @@ Position reçue Conversation fermée Conférence quittée - Ne pas faire confiance aux CAs système - Tous les certificats doivent être approuvés manuellement + Ne pas utiliser les CAs système + Tous les certificats doivent être approuvés manuellement. Retirer les certificats - Supprimer les certificats approuvés manuellement + Supprimer les certificats approuvés manuellement. Aucun certificat approuvé manuellement Retirer les certificats Supprimer la sélection @@ -465,7 +464,7 @@ %d contact séléctionné %d contacts séléctionnés - Remplacer le bouton envoyer avec une action rapide + Remplacer le bouton Envoyer par une action rapide. Action Rapide Aucune Dernière utilisée @@ -480,7 +479,20 @@ Échec du téléchargement : impossible de trouver le fichier Échec du téléchargement : impossible de se connecter à l\'hôte Utiliser un fond blanc - Afficher les messages reçus en texte noir sur fond blanc - Expiration dans le DNS + Afficher les messages reçus en texte noir sur fond blanc. Détraqué + Options de présence + Absent quand l\'écran est éteint + Marquer cette ressource comme absente quand l\'écran est éteint. + Indisponible en mode silencieux + Marque cette ressource comme indisponible quand l\'appareil est en mode silencieux + Ajouter un compte avec un certificat + Impossible d\'analyser le certificat + Laisser vide pour s\'identifier avec un certificat + Texte du captcha + Captcha obligatoire + Saisissez le texte dans l\'image + La chaîne de certificats n\'est pas digne de confiance + L\'identifiant ne correspond pas au certificat + Renouveler le certificat diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml index 019d4677f..c0e0b9aa2 100644 --- a/src/main/res/values-gl/strings.xml +++ b/src/main/res/values-gl/strings.xml @@ -14,7 +14,6 @@ min conversas sen ler enviando… - Descifrando mensaxe. Agarda uns intres… O apodo xa está en uso Moderador Participante @@ -55,7 +54,6 @@ ofrecendo… Clave OpenPGP non atopada Conversations non foi quen de cifrar as túas mensaxes porque o teu contactos non está anunciando a súa clave pública.\n\nPor favor, pídelle ao teu contacto que configure OpenPGP. - Mensaxe cifrado recibido. Pulsa para ver. Recurso O nome que identifica o cliente que estás a empregar Aceptar arquivos diff --git a/src/main/res/values-id/strings.xml b/src/main/res/values-id/strings.xml index 894c18a71..47918d3c4 100644 --- a/src/main/res/values-id/strings.xml +++ b/src/main/res/values-id/strings.xml @@ -28,7 +28,6 @@ %d min lalu Percakapan belum dibaca mengirim... - Menerjemahkan pesan. Tunggu sebentar... Nick ini sudah digunakan Administrator Pemilik @@ -90,7 +89,6 @@ Conversations tidak dapat mengenkripsi pesan Anda karena kontak tidak mengumumkan kunci publiknya.\n\nSilakan meminta kontak Anda untuk menyetel OpenPGP Tidak ada kunci OpenPGP ditemukan Percakapan tidak dapat mengenkripsi pesan Anda karena kontak tidak mengumumkan kunci publik mereka.\n\nSilakan meminta kontak Anda untuk setup OpenPGP. - Pesan terenkripsi diterima. Sentuh untuk membongkar dan melihatnya. Umum XMPP resource Identifikasi nama klien ini dengan @@ -165,7 +163,6 @@ Password tidak sama Jabber ID tidak valid Memori habis. Gambar terlalu besar - Apakah anda ingin menambahkan %s ke daftar kontak anda? online bebas untuk chatting pergi @@ -411,7 +408,6 @@ Menawarkan %s Sembunyikan Offline Nonaktifkan Akun - %s sedang mengetik... %s telah berhenti mengetik Notifikasi ketik pesan Biarkan kontak Anda tahu ketika Anda sedang menulis pesan baru diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml index 97311427c..f291db592 100644 --- a/src/main/res/values-it/strings.xml +++ b/src/main/res/values-it/strings.xml @@ -28,7 +28,6 @@ %d min fa Conversazioni non lette invio… - Decifrazione del messaggio. Attendere prego… Nome utente già in uso Amministratore Proprietario @@ -90,7 +89,6 @@ Conversations non è in grado di cifrare i tuoi messaggi perché il contatto non sta annunciando la sua chiave pubblica.\n\nPer favore chiedi al tuo contatto di configurare OpenPGP. Nessuna chiave OpenPGP trovata Conversations non è in grado di cifrare i tuoi messaggi perché i contatti non stanno annunciando la propria chiave pubblica.\n\nPer favore chiedi ai tuoi contatti di configurare OpenPGP. - Messaggio cifrato ricevuto. Tocca per decifrare. Generale Risorsa XMPP Il nome con il quale questo client si identifica @@ -165,7 +163,6 @@ Le Password non corrispondono Questo non è un ID Jabber valido Memoria esaurita. L’immagine è tropppo grande - Vuoi aggiungere %s alla rubrica del telefono? online vuole chattare assente @@ -407,7 +404,6 @@ Inviando %s Nascondi i contatti offline Disabilita l\'account - %s sta digitando... %s ha smesso di digitare Permetti al tuo contatto di vedere quando stai digitando Invia la posizione diff --git a/src/main/res/values-iw/strings.xml b/src/main/res/values-iw/strings.xml index d5fda1c23..fe25a42c0 100644 --- a/src/main/res/values-iw/strings.xml +++ b/src/main/res/values-iw/strings.xml @@ -9,7 +9,7 @@ דיון מאובטח הוסף חשבון ערוך שם - הוסף אל פנקס טלפונים + הוסף לפנקס הטלפונים מחק מרשימת אנשי הקשר חסום איש קשר בטל חסימת איש קשר @@ -28,7 +28,6 @@ לפני %d דקות שיחות שלא נקראו שולח... - מפענח הודעה. אנא המתן… שם כינוי כבר בשימוש מנהל בעלים @@ -36,10 +35,10 @@ משתתף מבקר האם ברצונך להסיר את %s מתוך רשימת אנשי הקשר? השיחה המשוייכת עם איש קשר זה לא תוסר. - האם ברצונך לחסום קבלת הודעות מ- %s? - האם ברצונך לבטל את החסימה ולאפשר קבלת הודעות מ- %s? - לחסום את כל האנשים מ- %s? - לבטל את חסימת כל האנשים מ- %s? + האם ברצונך לחסום קבלת הודעות מאת %s? + האם ברצונך לבטל את החסימה ולאפשר קבלת הודעות מאת %s? + לחסום את כל האנשים מתוך %s? + לבטל את חסימת כל האנשים מתוך %s? איש קשר נחסם האם ברצונך להסיר את %s בתור סימנייה? הדיונים אשר משוייכים עם סימנייה זו לא יוסרו. צור חשבון חדש בשרת @@ -49,6 +48,7 @@ הזמן איש קשר אנשי קשר ביטול + הגדר הוסף ערוך מחק @@ -57,7 +57,7 @@ שמור אישור Conversations קרסה - על ידי שליחת Stacktraces אתה עוזר להתקדמות הפיתוח של Conversations\nאזהרה: פעולה זו תעשה שימוש בחשבון ה- XMPP שלך כדי לשלוח עקבות מחסנית אל המפתח. + על ידי שליחת Stacktraces אתה עוזר להתקדמות הפיתוח של Conversations\nאזהרה: פעולה זו תעשה שימוש בחשבון XMPP שלך כדי לשלוח עקבות מחסנית אל המפתח. שלח עכשיו לעולם אל תשאל שוב התחברות לחשבון נכשלה @@ -73,6 +73,7 @@ נקה היסטוריית שיחה האם ברצונך למחוק את כל ההודעות בשיחה זאת?\n\nאזהרה: פעולה זו לא תשפיע על הודעות מאוחסנות על מכשירים או שרתים אחרים. מחק הודעות + סיים את השיחה לאחר מכן בחר נוכחות לאיש קשר שלח הודעה בלתי מוצפנת שלח הודעה בהצפנת OTR @@ -91,10 +92,9 @@ Conversations אינה מסוגלת להצפין את הודעותיך משום שאיש הקשר שלך אינו מכריז על המפתח הפומבי שלו או שלה.\n\nאנא בקש מאיש הקשר שלך להגדיר את OpenPGP. לא נמצאו מפתחות OpenPGP Conversations אינה מסוגלת להצפין את הודעותיך משום שאנשי הקשר שלך אינם מכריזים על המפתח הפומבי שלהם.\n\nאנא בקש מאנשי הקשר שלך לארגן OpenPGP. - הודעה מוצפנת התקבלה. לחץ כדי לצפות ולפענח. כללי - XMPP resource - השם שאפליקציה זו שולחת לשרת + משאב XMPP + השם שבעזרתו לקוח זה מזהה את עצמו קבל קבצים קבל אוטומטית קבצים שגודלם קטן מ… הגדרות התראות @@ -170,7 +170,6 @@ סיסמאות לא תואמות מזהה ה Jabber אינו תקין חסר זיכרון. תצלום גדול מדי - האם ברצונך להוסיף את %s אל רשימת קשר טלפונית? מקוון חופשי לשיחה נעדר @@ -210,7 +209,6 @@ טביעת אצבע OMEMO שלי מכשירים אחרים סמוך על טביעות אצבע OMEMO - משיג מפתחות... בוצע אמת פענח @@ -330,6 +328,9 @@ לא נמצא OTR Session תקין השאר שירות ב Foreground מונע ממערכת ההפעלה לנתק את החיבור לשרת + ייצא Logs + יצוא logs לכרטיס הזיכרון + מייצא logs לכרטיס זיכרון בחר קובץ מקבל %1$s ( הושלם %2$d%% ) הורד %s @@ -433,7 +434,6 @@ מציע %s הסתר בלתי מקוונים השבת חשבון - %s מקליד... %s הפסיק/ה להקליד התראות הקלדה אפשר לאנשי הקשר שלך לדעת כאשר אתה מקליד הודעה חדשה @@ -448,7 +448,7 @@ כל החתימות הדיגטליות יצטרכו לעבור אימות ידני מחק חתימות דיגטליות מחק חתימות דיגטליות שאומתו באופן ידני - אין חתימת דיגטליות שאושרו ידנית + אין חתימות דיגטליות שאושרו ידנית מחק חתימות דיגטליות מחק פריטים שנבחרו ביטול @@ -476,6 +476,19 @@ ההורדה נכשלה: נכשל ביצוע חיבור לשרת השתמש ברקע לבן הראה הודעות שהתקבלו בטקסט שחור על גבי רקע לבען - Timeout in DNS לא עובד + הגדרות נוכחות Presence + העבר למצב \"לא נמצא\" כאשר המסך כבוי + מעביר את המכשיר לסטטוס \"לא נמצא\" כאשר המסך כבוי + העבר למצב \"לא זמין\" כאשר במצב שקט + מעביר את המכשיר לסטטוס \"לא זמין\" כאשר הפלאפון נמצא במצב שקט. + הוסף חשבון עם certificate + תקלה בקריאת ה- certificate + השאר ריק כדי להזדהות ללא certificate + טקסט Captcha + דרוש טקסט Captcha + נא להזין את הטקסט שבתמונה + שרשרת תעודה אינה מהימנה + אין התאמה בין ה- JID לבין ה- certificate + חידוש certificate diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml index 45c67940e..4679c6b32 100644 --- a/src/main/res/values-ja/strings.xml +++ b/src/main/res/values-ja/strings.xml @@ -28,7 +28,6 @@ %d 分前 未読の会話 送信中… - メッセージを復号しています。しばらくお待ちください… ニックネームは既に使用されています 管理者 オーナー @@ -74,6 +73,7 @@ 会話履歴をクリア この会話のすべてのメッセージを削除しますか?\n\n警告: これは、他のデバイスやサーバーに保存されているメッセージには影響しません。 メッセージを削除 + その後、この会話を終了 連絡する参加を選択 暗号化されていないメッセージを送信 OTR 暗号化メッセージを送信 @@ -92,7 +92,6 @@ 連絡先が公開鍵を通知しないため、Conversations はあなたのメッセージを暗号化することができません。\n\n連絡先に OpenPGP をセットアップするように依頼してください。 OpenPGP の鍵はありません 連絡先が公開鍵を通知しないため、Conversations はあなたのメッセージを暗号化することができません。\n\n連絡先に OpenPGP をセットアップするように依頼してください。 - 暗号化されたメッセージを受信しました。タッチすると、表示および復号化します。 全般 XMPP リソース 自分自身を識別するこのクライアントの名前 @@ -171,7 +170,6 @@ パスワードが一致しません これは有効な Jabber ID ではありません メモリ不足です。画像が大きすぎます - 電話の連絡先リストに %s を追加しますか? オンライン 自由にチャットできます 離席中 @@ -211,7 +209,6 @@ 自分の OMEMO フィンガープリント 他のデバイス OMEMO フィンガープリントを信頼 - 鍵の取得中... 完了 検証 復号化 @@ -334,6 +331,9 @@ Conversations サービスをフォアグラウンドに保持 オペレーティングシステムが接続を切断するのを防止します + ログをエクスポート + ログを SD カードに書き込みます + ログを SD カードに書き込み中 ファイルの選択 %1$s 受信中 (%2$d%% 完了) %s のダウンロード @@ -438,7 +438,6 @@ %s の依頼中 オフラインを非表示にする アカウントを無効にする - %s は入力中... %s は入力を停止しました 入力中通知 あなたが新しいメッセージを書いている時に、連絡先に知らせます @@ -479,6 +478,19 @@ ダウンロードに失敗しました: ホストに接続できませんでした 白い背景を使用する 白地に黒の文字で、受け取ったメッセージを表示します - DNS でタイムアウト 壊れています + 参加設定 + 画面がオフのときは離席 + 画面がオフになっているとき、リソースを離席としてマークします + サイレントモード時は利用不可 + サイレントモードのとき、リソースを利用不可としてマークします + アカウントに証明書を追加 + 証明書を解析できません + 空にすると、証明書で認証します + キャプチャ テキスト + キャプチャが必要です + 画像からテキストを入力してください + 証明書チェーンは信頼済ではありません + Jabber ID が証明書と一致しません + 証明書を更新 diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml index 6f654dcf7..d8c28b709 100644 --- a/src/main/res/values-ko/strings.xml +++ b/src/main/res/values-ko/strings.xml @@ -28,7 +28,6 @@ %d 분 전 읽지 않은 대화 보내는중... - 메세지 복호화중입니다. 기다리세요... 사용중인 별명입니다 관리자 소유자 @@ -90,7 +89,6 @@ 당신의 연락처가 그들의 공개 키를 선언하지 않고 있기 때문에 Conversations는 당신의 메세지를 암호화할 수 없습니다. OpenPGP를 설정하도록 당신의 연락처에게 물어보세요. OpenPGP 키가 발견되지 않음 당신의 연락처가 그들의 공개 키를 선언하지 않고 있기 때문에 Conversations는 당신의 메세지를 암호화할 수 없습니다. OpenPGP를 설정하도록 당신의 연락처에게 물어보세요. - 암호화된 메세지 수신됨. 터치해서 복호화 및 열람하세요. 일반 XMPP 자원 이 클라이언트가 자신을 알아보는 이름 @@ -165,7 +163,6 @@ 암호가 일치하지 않습니다 올바른 Jabber ID가 아닙니다 메모리 부족. 이미지 용량이 너무 큽니다 - %s를 기기의 연락처 목록에 추가하시겠습니까? 접속중 대화 가능 자리 비움 @@ -406,7 +403,6 @@ %s 제공중 오프라인 숨기기 계정 해제 - %s 이(가) 입력중입니다... %s 이(가) 입력을 중단했습니다 입력 알림 새 메세지를 작성할 때 이를 연락처에게 알립니다 diff --git a/src/main/res/values-nb-rNO/strings.xml b/src/main/res/values-nb-rNO/strings.xml index dee41b7b4..0b4d13c2f 100644 --- a/src/main/res/values-nb-rNO/strings.xml +++ b/src/main/res/values-nb-rNO/strings.xml @@ -5,17 +5,21 @@ Kontobehandling Avslutt denne samtalen Kontaktdetaljer + Konferansedetaljer Sikret samtale Legg til samtale Rediger navn Legg til i telefonbok + Fjern fra kontaktliste Blokker kontakt Avblokker kontakt Blokker domene Avblokker domene Kontobehandling Innstillinger + Konferansedetaljer Kontaktdetaljer + Del med Conversation Start samtale Velg kontakt Blokkeringsliste @@ -24,13 +28,13 @@ %d minutter siden uleste samtaler sender... - Dekrypterer melding. Vent... Kallenavn allerede i bruk Admin Eier Moderator Deltager Besøkende + Bekreft fjerning av %s fra din kontaktliste. Samtalen med denne kontakten vil ikke bli fjernet. Vil du forhindre %s fra å sende deg meldinger? Ønsker du å avblokkere %s og tillate dem å sende deg meldinger? Blokker alle kontakter fra %s? @@ -62,6 +66,7 @@ Forbereder bilde for forsendelse Tøm historikk Tøm samtalehistorikk + Slett meldinger Send ukryptert melding Send OTR-kryptert melding Send OMEMO-kryptert melding @@ -75,7 +80,6 @@ venter... Ingen OpenPGP-nøkkel funnet Ingen OpenPGP-nøkler funnet - Kryptert melding mottatt. Trykk for å se og dekrypterte. XMPP-ressurs Godta filer Automatisk godkjenning av filer mindre enn... @@ -98,6 +102,8 @@ Nøkler Velg bilde Ta bilde + Finner ikke filen + Generell I/O-feil. Har du sluppet opp for lagringsplass? Ukjent Midlertidig avskrudd Pålogget @@ -107,6 +113,8 @@ Registrering feilet Brukernavn allerede i bruk Registrering fullført + Sikkerhetsfeil + Ukompatibel tjener Ukryptert OTR OpenPGP @@ -122,13 +130,13 @@ Ta opp stemme Jabber-ID Passord + brukernavn@eksempel.no Bekreft passord Passord Bekreft passord Passordene samsvarer ikke Dette er ikke en gyldig Jabber-ID Slapp opp for minne, bildet er for stort - Ønsker du å legge til %s til din telefons kontaktliste? pålogget tilgjengelig for sludring fraværende @@ -150,9 +158,11 @@ aldri sett Kryptert melding. Installer OpenKeychain for å dekryptere. Ukjent OTR-fingeravtrykk + Mottak mislyktes OTR-fingeravtrykk - Henter nøkler... + Andre enheter Ferdig + Bekreft Dekrypter Konferanser Søk @@ -162,7 +172,9 @@ Vis kontaktdetaljer Blokker kontakt Avblokker kontakt + Lag Kontakten finnes allerede + Ta del i Konferanse-adresse rom@konferanse.eksempel.no Lagre som bokmerke @@ -171,6 +183,43 @@ Deg Rediger temaet for konferansen Fant ikke konferansen + Forlat + Kontakt la deg til i sin liste + Gjengjeld tjenesten + hvisket + til %s + Send privat melding til %s + Koble til + Denne kontoen finnes allerede + Neste + Ytterligere informasjon + Hopp over + Skru av varslinger + Skru av varslinger for denne samtalen + Varslinger avskrudd + Skru på + Konferansen krever passord + Skriv inn passord + Mangler tilgjengelighetsoppdateringer fra kontakt + Slett fingeravtrykk + Bekreft fjerning av fingeravtrykk. + Ignorer + Krypteringsinnstillinger + Krev ende-til-ende-kryptering + Advarsel: Dette kan føre til at meldinger går tapt + Ekspertinnstillinger + Vær forsiktig med disse + Om Conversations + Utgave og lisensinformasjon + Stille tidsavgrensning + Oppstart + Avslutning + Aktiver stille tidsavgrensning + Varslinger blir ikke spilt under stilletid + Øk tekststørrelse + Bruk større tekststørrelser i hele programmet + Forsendelsesknappen indikerer status + Forespørr meldingskvitteringer lyd film stillbilde diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml index 61d57b260..c56471596 100644 --- a/src/main/res/values-nl/strings.xml +++ b/src/main/res/values-nl/strings.xml @@ -28,7 +28,6 @@ %d min. geleden ongelezen gesprekken versturen… - Bericht aan het ontsleutelen. Even geduld… Naam is al in gebruik Beheerder Eigenaar @@ -92,7 +91,6 @@ Conversations kan je berichten niet versleutelen omdat je contact geen publieke sleutel heeft ingesteld.\n\nVraag je contact om OpenPGP te configureren. Geen OpenPGP-sleutels gevonden Conversations kan je berichten niet versleutelen omdat je contacten geen publieke sleutel hebben ingesteld.\n\nVraag je contacten om OpenPGP te configureren. - Versleuteld bericht ontvangen. Raak aan om te bekijken en te ontsleutelen. Algemeen XMPP-bron De naam waarmee deze cliënt zich identificeert @@ -171,7 +169,6 @@ Wachtwoorden komen niet overeen Dit is geen geldige Jabber-ID Geen geheugen beschikbaar. Afbeelding is te groot - Wil je %s toevoegen aan de contactenlijst op je telefoon? online beschikbaar weg @@ -211,7 +208,6 @@ Eigen OMEMO-vingerafdruk Andere apparaten Vertrouw OMEMO-vingerafdrukken - Ophalen van de sleutels... Klaar Bevestigen Ontsleutelen @@ -438,7 +434,6 @@ Bezig met aanbieden van %s Offline contacten verbergen Account uitschakelen - %s is aan het typen... %s is gestopt met typen Aan-het-typen-meldingen Laat je contacten weten wanneer je een nieuw bericht aan het schrijven bent @@ -481,6 +476,6 @@ Downloaden mislukt: kon geen verbinding maken met host Gebruik witte achtergrond Toon ontvangen berichten als zwarte tekst op een witte achtergrond - Time-out in DNS Gebroken + Jabber-ID komt niet overeen met certificaat diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index 408672ca1..6fc57f304 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -28,7 +28,6 @@ %d minut temu nieprzeczytanych konwersacji wysyłanie... - Deszyfrowanie wiadomości. Proszę czekać... Nazwa jest już w użyciu Admin Właściciel @@ -92,7 +91,6 @@ Conversations nie może zaszyfrować wiadomości, ponieważ kontakt nie udostępnia klucza publicznego.\n\nZasugeruj rozmówcy instalację OpenPGP. Nie znaleziono kluczy OpenPGP Conversations nie może zaszyfrować wiadomości, ponieważ kontakty nie udostępniają kluczy publicznych.\n\nZasugeruj rozmówcom instalację OpenPGP. - Otrzymano zaszyfrowaną wiadomość. Dotknij, aby odszyfrować i wyświetlić. Główne Zasób XMPP Nazwa identyfikująca urządzenie @@ -171,7 +169,6 @@ Hasła są niezgodne Wprowadzono niepoprawny Jabber ID Brak pamięci, obraz jest za duży - Czy chcesz dodać kontakt %s do książki telefonicznej? dostępny chętny do rozmowy zaraz wracam @@ -211,7 +208,6 @@ Własny odcisk OMEMO Pozostałe urządzenia Zaufane odciski OMEMO - Pobieranie kluczy... Ukończono Weryfikuj Odszyfruj @@ -438,7 +434,6 @@ Oferowanie %s Ukryj niedostępnych Wyłącz konto - %s pisze... %s przestał(a) pisać Powiadomienia pisania Powiadamiaj rozmówcę, kiedy rozpoczynasz nową wiadomość @@ -483,6 +478,5 @@ Pobieranie nieudane: Nie można połączyć z hostem Białe tło Pokazuj otrzymane wiadomości jako czarny tekst na białym tle - DNS timeout Zepsute diff --git a/src/main/res/values-pt/strings.xml b/src/main/res/values-pt/strings.xml index 57f9d7c6e..917958f1f 100644 --- a/src/main/res/values-pt/strings.xml +++ b/src/main/res/values-pt/strings.xml @@ -27,7 +27,6 @@ %d minutos atrás Conversas não lidas enviando... - Descriptografando mensagem. Por favor aguarde... O apelido já está em uso Administrador Dono @@ -154,7 +153,6 @@ As senhas não combina Esse não é um ID Jabber válido Memória insuficiente. A imagem é muito grande - Você tem certeza que deseja adicionar %s à sua lista de contato do telefone? online disponível para conversa fora @@ -281,7 +279,6 @@ Contato Enviando %s Oferecendo %s - %s está digitando... %s parou de digitar Notificações de digitação Enviar localização diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index 991201e54..33e456710 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -1,6 +1,6 @@ - Configuratie + Setari Conversatie noua Configureaza conturi Termina conversatie @@ -19,18 +19,17 @@ Configuratie Detalii conferinta Detalii contact - Distribuie catre Conversatie - Porneste Conversatie + Distribuie catre Conversations + Porneste conversatie Alege contact Blocheaza lista in acest moment - acuma 1 minut - acuma %d minute - Conversatii necitite + acum un minut + acum %d minute + conversatii necitite trimitere... - Decriptez mesaj. Te rog asteapta... Nume utilizator este deja folosit. - Admin + Administrator Proprietar Moderator Participant @@ -41,11 +40,12 @@ Blocheaza toate contactele de la %s? Deblocheaza toate contactele de la %s? Contact blocat - Ai dori sa stergi pe %s ca semn de carte? Conversatia asociata cu acest semn de carte nu va fi stearsa. + Ai dori sa stergi pe %s din semne de carte? Conversatia asociata cu acest semn de carte nu va fi stearsa. Inregistreaza un cont nou pe server Schimba parola pe server - Porneste Conversatie - Invita Contact + Partajeaza cu... + Porneste conversatie + Invita contact Contacte Anuleaza Seteaza @@ -56,35 +56,445 @@ Deblocheaza Salveaza DA - Conversatii s-a oprit neasteptat - Trimitand date ajuti la dezvoltarea aplicatiei Conversatii\nAtentie: Se va utiliza contul XMPP pentru a trimite informatii catre programatori. - Trimie acum - Nu mai intreba in viitor + Conversations s-a oprit neasteptat + Trimitand date ajuti la dezvoltarea aplicatiei Conversations\nAtentie: Se va utiliza contul XMPP pentru a trimite informatii catre programatori. + Trimite acum + Nu ma mai intreba Nu ma pot conecta la cont Nu ma pot conecta la conturi multiple Apasa aici pentru a configura conturile tale Ataseaza fisier Contactul nu este in lista ta. Ai vrea sa il adaugi? Adauga contact - Trimitere esuata - rejectat + trimitere esuata + respins Pregatesc imaginea pentru transmisie Sterge istoria Sterge istoria conversatiei - Doresti sa stergi toate mesajele din Conversatii?\n\nAtentie: Aceasta actiune nu va influenta mesajele aflate pe alte telefoane/tabelete/servere. + Doresti sa stergi toate mesajele din aceasta conversatie?\n\nAtentie: Aceasta actiune nu va influenta mesajele aflate pe alte telefoane/tabelete/servere. Sterge mesajele + Dupa, incheie conversatia Alege prezenta pentru a contacta + Trimite mesaje necriptate Trimite mesaj criptat cu OTR + Trimite mesaj criptat cu OMEMO Trimite mesaj criptat cu OpenPGP Numele tau a fost schimbat Trimite necriptat Decriptia a esuat. Poate nu ai cheia privata corecta. OpenKeychain - Coonversatii utilizeaza o aplicatia externa OpenKeychain pentru a cripta si decripta mesaje si a administra cheile publice.\n\nOpenKeychain este licentiat sub GPLv3 si se gaseste pentru copiere pe F-Droid si Google Play.\n\n(Te rog sa repornesti Conversatii dupa.) + Conversations utilizeaza o aplicatia externa OpenKeychain pentru a cripta si decripta mesaje si a administra cheile publice.\n\nOpenKeychain este licentiat sub GPLv3 si se gaseste pentru copiere pe F-Droid si Google Play.\n\n(Te rog sa repornesti Conversations dupa) Reporneste Instaleaza - Transmit... - In asteptare... + transmit... + in asteptare... Nu am gasit cheie OpenPGP - Conversatii nu a putut sa cirpteze mesajele tale din cauza contactului care nu isi anunta cheia publica.\n\nRoaga contactul sa isi configureze OpenPGP. + Conversations nu a putut sa cripteze mesajele tale din cauza contactului care nu isi anunta cheia publica.\n\nRoaga contactul sa isi configureze OpenPGP. + Nu am gasit chei OpenPGP + Conversations nu poate cripta mesajele tale pentru contactele tale care nu isi anunta cheia publica.\n\nTe rog cere contactelor sa configureze OpenPGP. + General + resursa XMPP + Numele cu care acest client se identifica + Accepta fisiere + Accepta automat fisiere mai mici decat... + Setari notificari + Notificari + Notifica cand un nou mesaj este primit + Vibreaza + Vibreaza cand un nou mesaj este primit + Sunet + Ton de apel cu notificare + Notificari in Conferintele Publice + Notifica cand un mesaj apare in conferintele publice in loc doar sa fie evidentiat + Perioada de gratie notificari + Opreste notificari pentru o scurta perioada dupa ce o copie a mesajului a fost primita + Optiuni avansate + Nu trimite rapoarte de errori + Trimitand date ajuti la dezvoltarea aplicatiei Conversations\nAtentie: Se va utiliza contul XMPP pentru a trimite informatii catre programatori. + Confirma mesaje + Notifica contactul cand ai primit un mesaj si l-ai citit + Optiuni interfata + OpenKeychain a raportat o eroare + Eroare I/O la decriptarea fisierului + Accepta + A aparut o eroare + Trimite actualizari de prezenta + Acorda si cere anticipat abonarea la actualizarile de prezenta pentru contactele create de tine + Abonari + Contul tau + Chei + Trimite actualizari de prezenta + Primeste actualizari de prezenta + Cere actualizari de prezenta + Alege imagine + Fa o poza + Acorda anticipat cererea de abonare + Fisierul selectat nu este o imagine + Eroare la conversia fisierului de imagine + Fisierul nu a fost gasit + Eroare I/O gemerala. Poate ai ramas fara spatiu liber? + Aplicatia folosita pentru selectia acestei imagini nu a oferit destule permisiuni pentru a putea citi fisierul.\n\nFoloseste un alt manager de fisiere pentru a alege o imagine + Necunoscut + Dezactivat temporar + Conectat + In curs de conectare\u2026 + Deconectat + Neautorizat + Serverul nu a fost gasit + Fara conexiune + Inregistrare esuata + Nume de utilizator deja alocat + Inregistrare completa + Acest server nu permite inregistrarea + Eroare de securitate + Server incompatibil + Ne criptat + OTR + OpenGPG + OMEMO + Editare cont + Sterge cont + Dezactivare temporara + Publica avatar + Publica cheia publica OpenPGP + Activeaza cont + Esti sigur? + Daca iti stergi contul intregul istoric de conversatii va fi pierdut + Inregistrare voce + ID-ul Jabber + Parola + username@example.com + Confirma parola + Parola + Confirma parola + Parolele nu sunt identice + Acesta nu este un ID Jabber valabil + Memorie epuizata. Imaginea este prea mare. + conectat + disponibil pentru conversatie + plecat + plecat departe + nu deranja + deconectat + Conferinta + Alti membri + Informatii server + XEP-0313: MAM + XEP-0280: Copii indigo mesaje + XEP-0352: Indicator stare client + XEP-0191: Comanda blocare + XEP-0237: Creare de versiuni lista + XEP-0198: Management flux + XEP-0163: PEP (Avatare / OMEMO) + XEP-0363: Incarcare fisiere prin HTTP + disponibil + indisponibil + Cheile publice ce nu au fost anuntate + vazut ultima data adineauri + vazut ultima data acum un minut + vazut ultima data acum %d minute + vazut ultima data acum o ora + vazut ultima data acum %d ore + vazut ultima data acum o zi + vazut ultima data acum %d zile + niciodata vazut + Mesaj criptat. Te rog instaleaza OpenKeychain pentru a-l putea decripta. + Amprenta OTR necunoscuta + A fost gasit un mesaj criptat cu OpenPGP + Receptie esuata + Amprenta ta + Amprenta OTR + Amprenta OMEMO + Amprenta OMEMO a mesajului + Amprenta OMEMO proprie + Alte dispozitive + Amprente OMEMO de incredere + Gata + Verifica + Decripteaza + Conferinte + Cauta + Adauga contact + Alatura-te conferintei + Sterge contact + Arata detalii contact + Blocheaza contact + Deblocheaza contact + Creeaza + Contactul exista deja + Alatura-te + Adresa conferinta + room@conference.example.com + Salveaza semn de carte + Sterge semn de carte + Acest semn de carte exista + Tu + Editeaza titlul conferintei + Conferinta nu a fost gasita + Paraseste + Contactul a fost adaugat in lista + Adauga inapoi + %s a citit pana in acest loc + Publica + Atinge avatarul pentru a selecta o poza din galerie + Tine minte: Toti cei abonati la actualizarile tale de prezenta vor putea sa vada aceasta poza + Se publica... + Acest server v-a refuzat publicarea + Ceva nu a mers bine in timpul conversiei imaginii + Nu s-a putut salva avatarul pe disc + (Sau apasa indelung pentru a reseta la implicit) + Acest server nu permite publicarea de avatare + sopteste + catre %s + Trimite mesaj privat catre %s + Conectare + Acest cont exista deja + Urmatoarea + Sesiune curenta stabilita + Informatii aditionale + Sari + Dezactiveaza notificari + Dezactiveaza notificarile pentru aceasta conversatie + Notificari dezactivate + Activeaza + Conferinta necesita parola + Introdu parola + Au lipsit actualizarile de prezenta de la contact + Te rog mai intai cere actualizari de prezente de la contact.\n\nAsta va fi folosita pentru a determina ce aplicatii client foloseste contactul tau + Cere acum + Sterge amprenta + Sigur vrei sa stergi amprenta + Ignora + Atentie: Trimitand aceasta fara actualizari de prezenta reciproce, ar putea produce probleme neprevazute.\n\nMergi la lista de contacte, la detalii, sa iti verifici abonarile la actualizarile de prezenta. + Setari criptare + Forteaza criptarea conexiunii de la un capat la altul + Trimite mereu mesajele criptate (exceptand conferintele) + Nu salva mesaje criptate + Atentie: Asta poate duce la pierderea de mesaje + Optiuni expert + Te rog sa fi atent cu astea + Despre Conversations + Informatii despre versiune si licenta + Ore de liniste + Ora de pornire + Ora de inchidere + Activeaza orar de liniste + Notificarile vor fi reduse la tacere in timpul orelor de liniste + Mareste marimea literelor + Foloseste marimea mai mare de text in toata aplicatia + Butonul de trimitere indica startea + Cere raport de primire + Mesajele primite vor fi marcate cu un semn verde daca este suportat + Coloreaza butonul de trimitere pentru a indica starea contactului + Altele + Titlu conferinta + Foloseste subiectul camerei in locul JID pentru a identifica conferinta + Amprenta OTR copiata in memorie + Amprenta OMEMO copiata in memorie! + Ti-a fost interzis accesul la aceasta conferinta + Aceasta conferinta este rezervata membrilor + Ai fost dat afara din conferinta + folosind cont %s + Verifica %s pe gazda HTTP + Nu esti conectat. Incearca din nou mai tarziu. + Verifica marimea %s + Optiuni mesaje + Copiaza text + Copiaza URL original + Trimite din nou + URL fisier + Mesaj text + URL copiat in memorie + Mesaj copiat in memorie + Transmisia imaginii a esuat + Scaneaza cod QR + Arata codul QR + Arata lista blocata + Detalii cont + Verifica OTR + Amprenta la distanta + scaneaza + (sau dispozitive touch) + Socialist Millionaire Protocol + Indiciu sau Intrebare + Secret impartasit + Confirma + In desfasurare + Raspunde + Esuat + Secretele nu se potrivesc + Incearca din nou + Incheie + Verificat! + Contactul a cerut verificare SMP + Nu s-a gasit nici o sesiune OTR valida + Conversations + Pastreaza serviciul activ in prim plan + Previne inchiderea conexiunii de catre sistemul de operare. + Exporta jurnale + Scrie jurnal pe card SD + Se scrie jurnal pe card SD + Alege un fisier + Primesc %1$s (%2$d%% complet) + Descarca %s + fisier + Deschide %s + trimit (%1$d%% complet) + Pregatire fisier pentru transmisie + %s oferit spre descarcare + Anuleaza transmisiunea + transmisie fisier esuata + Fisierul a fost sters + Nu s-a gasi nici o aplicatie care sa deschida fisierul + Nu s-a putut verifica amprenta + Verifica manual + Sigur vrei sa verifici amprenta OTR a persoanei de contact? + Arata etichetele dinamice + Arata etichete doar pentru citire sub contacte + Activeaza notificari + Creeaza conferinta cu... + Serverul conferintei nu a fost gasita + Conferinta nu a putut fi creata! + Conferinta a fost creata! + Secret acceptat! + Reseteaza + Avatar cont + Copiaza amprenta OTR in memorie + Copiaza amprenta OMEMO in memorie + Genereaza din nou cheia OMEMO + Sterge alte dispozitive din PEP + Curata lista dispozitive + Sigur vrei sa inlaturi toate celelalte dispozitive din mesajul de anunt OMEMO? Data viitoare cand dispozitivele se vor conecta, se vor anunta din nou, dar se poate ca ele sa nu fi primit mesajele trimise intre timp. + Sterge cheia + Sigur vrei sa stergi aceasta cheie? + Va fi considera compromisa ireversibil si nu vei mai putea crea o sesiune cu ea niciodata. + Nu exista chei disponibile si utilizabile pentru acest contact. Daca ai sters vreuna din cheile contactului, trebuie sa generezi o alta noua. + Eroare + Descarc istoric de pe server + Nu mai exista istoric pe server + Actualizez... + Parola schimbata + Nu s-a putut schimba parola + Trimite un mesaj pentru a pornii o discutie criptata + Intreaba + Tu si contactul tau aveti un secret in comun pe care nimeni altcineva nu il stie (cum ar fi o gluma sau ce ati mancat ultima data cand v-ati vazut) poti folosi acel secret ca sa va verificati amprenta fiecaruia.\n\nTu pui la dispozitie un indiciu sau o intrebare contactului iar el/ea va raspunde cu un mesaj sensibil la majuscule. + Contactul tau doreste sa iti verifice amprenta provocandu-te cu un secret partajat. Contactul tau a furnizat urmatorul indiciu sau intrebare legat de acel secret. + Indiciul tau nu ar trebui sa fie gol + Secretul tau impartasit nu poate fi gol + Compara cu grija amprenta afisata mai jos cu amprenta contactului.\nPoti folosi orice forma de comunicare de incredere precum un e-mail criptat sau o convorbire telefonica pentru a face schimb de amprente. + Schimba parola + Parola curenta + Parola noua + Parola nu trebuie sa fie goala + Activeaza toate conturile + Dezactiveaza toate conturile + Efectuaza actiune cu + Fara afiliere + Fara rol + proscris + Membru + Mod avansat + Acorda calitatea de membru + Abroga calitatea de membru + Acorda privilegii de administrator + Abroga privilegii de administrator + Inlatura din conferinta + Nu s-a putut schimba afilierea lui %s + Interzice accesul la conferinta + Incerci sa il inlaturi pe %s dintr-o conferinta publica. Singurul mod in care poti face asta este sa in blochezi pentru totdeauna. + Interzice accesul acum + Nu s-a putut schimba rolul lui %s + Conferinta accesibila public + Conferinta privata, accesibila numai membrilor + Optiuni conferinta + Privat, numai pentru membri + Ne anonim + Monitorizata + Tu nu participi + Optiuni conferinta modificate! + Nu s-au putut modifca optiunile conferintei + Niciodata + 30 minute + O ora + 2 ore + 8 ore + Pana la noi ordine + Optiuni introducere + ENTER trimite + Apasa tasta ENTER pentru a trimite mesajul + Arata tasta ENTER + Preschimba tasta de zambilici in ENTER + audio + video + imagine + document PDF + Aplicatie Android + Contact + Primit %s + Dezactiveaza serviciul in prim plan + Atinge pentru a deschide Conversations + Avatarul a fost publicat! + Trimit %s + Ofer %s + Ascunde deconectat + Dezactiveaza cont + %s s-a oprit din scris + Notificari cand cineva scrie + Anunta contactul cand scrii un mou mesa + Trimite locatia + Arata locatia + Nu s-a gasit nici o aplicatie care sa afiseze locatia + Locatie + Locatie primita + Conversatie inchisa + A parasit conferinta + Nu ai incredere in CA din sistem + Toate certificatele trebuie aprobate manual + Inlatura certificatele + Sterge certificate aprobate manual + Nici un certificat aprobat manual + Inlatura certificatele + Sterge selectia + Anuleaza + + %d certificat sters + %d certificate sterse + %d certificate sterse + + + Selecteaza %d contact + Selecteaza %d contacte + Selecteaza %d contacte + + Inlocuieste butonul de trimitere cu actiune rapida + Actiune rapida + Nimic + Folosit recent + Alege actiune rapida + Cauta contacte sau grupuri + trimite mesaj privat + %s a parasit conferinta! + Nume utilizator + Nume utilizator + Acesta nu este un nume de utilizator valabil + Descarcarea a esuat: Serverul nu a fost gasit + Descarcare esuata: Fisierul nu a fost gasit + Descarcarea a esuat. Nu s-a putut realiza conexiunea cu gazda. + Foloseste un fundal alb + Arata mesajele primite cu negru pe fond alb + Deteriorat + Setari de prezenta + Plecat cand ecranul este oprit + Marcheaza resursa drept plecata cand ecranul este oprit + Indisponibil in mod silentios + Marcheaza resursa drept indisponibila cand dispozitivul este in mod silentios + Adauga un cont cu certificat + Nu se poate analiza certificatul + Lasa gol pentru a autentifica cu un certificat + Text captcha de verificare + Text captcha de verificare necesar + introdu textul din imagine + Seria de certificate nu este de incredere + ID-ul Jabber nu corespunde cu certificatul + Innoieste certificatul diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index 4c5c205fe..968d4f045 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -28,7 +28,6 @@ %d мин. назад непрочитанных сообщений отправка… - Расшифровка сообщения. Пожалуйста, подождите… Имя уже используется Администратор Владелец @@ -74,9 +73,11 @@ Очистить историю Вы хотите удалить все сообщения в этой беседе?\n\nПредупреждение: Данная операция не повлияет на сообщения, хранящиеся на других устройствах. Удалить сообщения + Закончить эту беседу впоследствии Укажите статус для контакта Отправить незащифрованное сообщение Отправить OTR защифрованное сообщение + Отправить OMEMO защифрованное сообщение Отправить OpenPGP защифрованное сообщение Ваш псевдоним был изменен Отправить в незашифрованном виде @@ -91,7 +92,6 @@ Conversations не может зашифровать сообщение, потому что удаленный пользователь не анонсирует свой открытый ключ.\n\nПожалуйста, попросите удаленного пользователя тоже установить OpenPGP. Нет OpenPGP ключей Conversations не может зашифровать сообщения, потому что удаленные пользователи не анонсируют свои открытые ключи.\n\nПожалуйста, попросите удаленных пользователей тоже установить OpenPGP. - Зашифрованное сообщение получено. Нажмите здесь, чтобы расшифровать и посмотреть сообщение. Общие Название ресурса Имя которым Conversations идентифицирует себя @@ -104,6 +104,8 @@ Использовать вибрацию когда приходят новые сообщения Звуковой сигнал Выберите звуковой сигнал для сообщений + Уведомления в публичных конференциях + Всегда уведомлять, когда сообщение появляется в публичной конференции вместо простого подсвечивания Отсрочка уведомлений Не использовать уведомления, если вы прочитали сообщение на другом устройстве Дополнительные параметры @@ -149,6 +151,7 @@ Без шифра OTR OpenPGP + OMEMO Редактировать аккаунт Удалить Отключить @@ -167,7 +170,6 @@ Пароли не совпадают Недопустимый JID (Джаббер ID) Недостаточно памяти. Изображение слишком большое - Вы хотите добавить %s в свою телефонную книгу? в сети свободен для общения скоро буду @@ -183,6 +185,8 @@ XEP-0191: Команда Блокирования XEP-0237: Управление версиями списков XEP-0198: Управление потоками + XEP-0163: PEP (Аватары / OMEMO) + XEP-0363: Загрузка файлов по HTTP доступен недоступен Отсутствие анонсирования открытых ключей @@ -200,12 +204,11 @@ Прием не удался Контрольная сумма OTR контрольная сумма - OMEMO контрольная сумма - OMEMO контрольная сумма сообщения - Собственная OMEMO контрольная сумма + OMEMO отпечаток + OMEMO отпечаток сообщения + Собственный OMEMO отпечаток Другие устройства - Доверенные контрольные суммы OMEMO - Получение ключей... + Доверенные отпечатки OMEMO Готово Подтвердить Дешифровать @@ -287,15 +290,19 @@ Название конференции Использовать тему беседы заместо JID для отображения конференций OTR-отпечаток скопирован в буфер обмена! + OMEMO отпечаток скопирован в буфер обмена! Вы заблокированы в этой конференции Эта конференция требует членства Вы были удалены из конференции использовать учётную запись %s + Проверка %s на сервере HTTP Вы неподключены. Попробуйте позже + Проверьте размер %s Опции сообщения Копировать текст Копировать адрес ссылки Отправить ещё раз + URL файла Текст сообщения Ссылка скопирована в буфер обмена Сообщение скопировано в буфер обмена @@ -324,6 +331,9 @@ Диалоги Оставить службу на переднем плане Не позволяет операционной системе закрыть ваше соединение + Экспорт истории + Записать историю на SD карту + Запись истории на SD карту Выберите файл Получение %1$s (%2$d%% выполнено) Загружено %s @@ -355,6 +365,11 @@ Стереть другие устройства из PEP Очистить устройства Вы уверены, что хотите очистить все остальные устройства из анонса ключей OMEMO? При соединении устройств в следующий раз новые ключи анонсируются автоматически, но устройства могут не получить сообщения, посланные до этого. + Очистить ключ + Вы уверены, что хотите удалить этот ключ? + Он будет необратимо считаться скомпрометированным, и вы никогда не сможете создать сессию с ним снова. + Для этого контакта не существует доступных ключей. Если вы очистили все его ключи, ему необходимо создать новые. + Ошибка Получение истории с сервера На сервере больше нет истории Обновление... @@ -392,7 +407,10 @@ Публичная конференция Приватная конференция только для членов Настройки конференции + Частная, только для участников Не анонимно + Модерируемая + Вы не участвуете Настройки конференции изменены! Не удалось изменить настройки конференции Никогда @@ -420,7 +438,6 @@ Предложен %s Скрыть пользователей вне сети Отключить учётную запись - %s набирает сообщение... %s прекратил набор Оповещения о наборе Позволяет вашим контактам видеть когда вы пишете новое сообщение @@ -456,4 +473,30 @@ Нет Последнее выбранное Выбрать быстрое действие + Поиск контактов или групп + Отправить частное сообщение + %s покинул конференцию! + Имя пользователя + Имя пользователя + Недопустимое имя пользователя + Загрузка не удалась: сервер не найден + Загрузка не удалась: файл не найден + Загрузка не удалась: не удалось подключиться к серверу + Использовать белый фон + Показывать принятые сообщения черным текстом на белом фоне + Повреждено + Настройки присутствия + Вышел когда экран выключен + Отмечает ваш ресурс как \"вышел\" когда экран выключен + Не доступен в режиме без звука + Отмечает ваш ресурс как \"не доступен\" когда телефон в беззвучном режиме + Добавить аккаунт с сертификатом + Невозможно разобрать сертификат + Оставить пустым для входа с сертификатом + Проверочный текст + Необходима проверка + введите текст с картинки + Цепочка сертификата не доверена + Jabber ID не соответствует сертификату + Обновить сертификат diff --git a/src/main/res/values-sk/strings.xml b/src/main/res/values-sk/strings.xml index b0f982c20..c544d3b4e 100644 --- a/src/main/res/values-sk/strings.xml +++ b/src/main/res/values-sk/strings.xml @@ -27,8 +27,7 @@ pred 1 minútou pred %d minútami neprečítané konverzácie - odosielam… - Dešifrujem správu. Čakajte, prosím… + posielam... Prezývka už existuje Administrátor Vlastník @@ -74,8 +73,11 @@ Vymazať históriu konverzácií Chcete vymazať všetky správy v tejto konverzácii?\n\nVarovanie: Toto neovplyvní správy uložené v iných zariadeniach alebo serveroch. Vymazať správy + Neskôr ukončiť konverzáciu Vybrať aktualizáciu stavu pre kontakt + Poslať nezašifrovanú správu Poslať OTR šifrovanú správu + Poslať OMEMO šifrovanú správu Poslať OpenPGP šifrovanú správu Prezývka sa zmenila Poslať nešifrované @@ -90,7 +92,6 @@ Nie je možné zašifrovať správu v aplikácii Conversations, pretože druhá strana neoznamuje svoj verejný kľúč.\n\nPožiadajte svoj kontakt o nastavenie OpenPGP. Nenašli sa žiadne OpenPGP kľúče Nie je možné zašifrovať správy v aplikácii Conversations, pretože kontakty neoznamujú svoj verejný kľúč.\n\nPožiadajte svoje kontakty o nastavenie OpenPGP. - Bola prijatá šifrovaná správa. Kliknite pre dešifrovanie a prečítanie. Všeobecné XMPP zdroj Meno, ktorým sa tento klient identifikuje @@ -103,6 +104,8 @@ Vibrovať pri prijatí novej správy Zvuk Prehrať zvuk spolu s upozornením + Upozornenia vo verejných konverzáciách + Vždy upozorniť na prichádzajúcu správu vo verejnej konverzácii, nie len keď je zvýraznená Doba na prečítanie upozornenia Neupozorňovať krátko po obdržaní kópie správy Rozšírené možnosti @@ -145,8 +148,10 @@ Server nepodporuje registráciu Bezpečnostná chyba Nekompatibilný server + Nezašifrovaný OTR OpenPGP + OMEMO Upraviť účet Vymazať účet Dočasne vypnúť @@ -165,7 +170,6 @@ Heslá nezodpovedajú Toto nie je platné Jabber ID Nedostatok pamäti. Obrázok je príliš veľký - Chcete pridať %s do svojho telefónneho zoznamu? online dostupný pre chat preč @@ -181,6 +185,8 @@ XEP-0191: Blocking Command XEP-0237: Roster Versioning XEP-0198: Stream Management + XEP-0163: PEP (Avatars / OMEMO) + XEP-0363: HTTP File Upload dostupný nedostupný Chýba oznámenie o verejnom kľúči @@ -198,6 +204,12 @@ Príjem zlyhal Váš identifikátor OTR identifikátor + OMEMO identifikátor + OMEMO identifkátor správy + Vlastný OMEMO identifikátor + Ostatné zariadenia + Dôverovať OMEMO identifikátoru + Dokončený Overiť Dešifrovať Skupinové konverzácie @@ -282,6 +294,7 @@ Táto konverzácia je iba pre členov Vyčlenili vás z tejto konverzácie Používa sa účet %s + Overiť %s na HTTP host Nie ste pripojený. Skúste to neskôr Overiť %s veľkosť Možnosti správy @@ -343,6 +356,8 @@ Vymazať Avatar účtu Skopírovať OTR identifikátor do schránky + Skopírovať OMEMO identifikátor do schránky + Chyba Načítať históriu zo serveru Na serveri nie je žiadna ďalšia história Aktualizujem... @@ -381,6 +396,7 @@ Súkromná konverzácia iba pre členov Možnosti skupinovej konverzácie Neanonymný + Nezúčastňujete sa Možnosti skupinovej konverzácie nastavené! Nepodarilo sa nastaviť možnosti skupinovej konverzácie Nikdy @@ -408,7 +424,6 @@ Ponúkam %s Skryť neprihlásených Vypnúť účet - %s píše... %s prestal písať Upozornenia pri písaní Upozorniť kontakt, keď píšete novú správu @@ -445,4 +460,14 @@ Hľadať kontakty alebo skupiny Poslať súkromnú správu %s opustil skupinovú konverzáciu! + Užívateľské meno + Užívateľské meno + Toto nie je platné užívateľské meno + Nedostupný v tichom režime + Pridať účet s certifikátom + Neschopný analyzovať certifikát + Text CAPTCHA + Potrebný CAPTCHA + vložiť text z obrázku + Obnoviť certifikát diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml index 5cf49475f..9858950a4 100644 --- a/src/main/res/values-sr/strings.xml +++ b/src/main/res/values-sr/strings.xml @@ -5,7 +5,7 @@ Управљај налозима Окончај преписку Детаљи контакта - Детаљи конференције + Детаљи групног ћаскања Безбедна преписка Додај налог Уреди име @@ -17,7 +17,7 @@ Одблокирај домен Управљање налозима Поставке - Детаљи конференције + Детаљи групног ћаскања Детаљи контакта Подели са преписком Почни преписку @@ -28,7 +28,6 @@ пре %d минута непрочитане преписке шаљем… - Дешифрујем поруку, сачекајте… Надимак је већ у употреби Администратор Власник @@ -74,6 +73,7 @@ Брисање историјата преписки Желите ли да обришете све поруке ове преписке?\n\nУпозорење: Ово неће утицати на поруке складиштене на осталим уређајима или серверима. Обриши поруке + Окончај ову преписку након тога Избор присутности за контакта Пошаљи нешифровану поруку Пошаљи ОТР шифровану поруку @@ -92,7 +92,6 @@ Конверзација није могла да шифрује ваше поруке јер ваш контакт не објављује свој јавни кључ.\n\nЗамолите вашег контакта да постави ОпенПГП. Нема ОпенПГП кључева Конверзација није могла да шифрује ваше поруке јер ваши контакти не објављују свој јавни кључ.\n\nЗамолите ваше контакте да поставе ОпенПГП. - Примљена је шифрована порука. Додирните за дешифровање и приказ. Опште ИксМПП ресурс Име са којим се овај клијент идентификује @@ -105,10 +104,10 @@ Вибрирај кад стигне нова порука Звук Звуци обавештења - Обавештења у јавним конференцијама - Увек обавести кад стигне порука у конференцији уместо само кад је означена + Обавештења у групним ћаскањима + Увек обавештавај кад стигне порука у групном ћаскању уместо само кад је означена Период одгоде обавештења - Онемогући обавештења на кратко по примању карбон копије + Искључи обавештења на кратко по примању карбон копије Напредне поставке Никад не шаљи извештаје о паду Слањем контратрага помажете текући развој Конверзације @@ -136,7 +135,7 @@ Општа У/И грешка. Можда вам је нестало простора у складишту? Апликација којом сте изабрали ову слику није дала довољне дозволе за читање фајла.\n\nКористите други менаџер фајлова да изаберете слику Непознато - Привремено онемогућен + Привремено искључен На вези Повезивање\u2026 Ван везе @@ -155,10 +154,10 @@ ОМЕМО Уреди налог Обриши налог - Привремено онемогући + Привремено искључи Објави аватар Објави ОпенПГП јавни кључ - Омогући налог + Укључи налог Да ли сте сигурни? Ако обришете ваш налог изгубићете сав историјат преписке Сними глас @@ -171,14 +170,13 @@ Лозинке се не поклапају Ово није исправан Џабер ИД Нестало меморије. Слика је превелика - Желите ли да додате %s у именик вашег телефона? на вези слободан за ћаскање одсутан продужено одсутан не узнемиравај ван везе - Конференција + Групно ћаскање Остали чланови Подаци о серверу XEP-0313: МАМ @@ -211,14 +209,13 @@ Сопствени ОМЕМО отисак Остали уређаји Поуздај се у ОМЕМО отиске - Добављам кључеве... Готово Овери Дешифруј - Конференције + Групна ћаскања Тражи Направи контакт - Придружи се конференцији + Придружи се групном ћаскању Обриши контакт Прикажи детаље контакта Блокирај контакт @@ -226,14 +223,14 @@ Направи Контакт већ постоји Придружи се - Адреса конференције + Адреса групног ћаскања soba@konferencija.primer.com Сачувај као обележивач Обриши обележивач Овај обележивач већ постоји Ви - Уреди предмет конференције - Конференција није нађена + Уреди предмет групног ћаскања + Групно ћаскање није нађено Напусти Контакт вас је додао на списак контаката Додај га @@ -256,11 +253,11 @@ Текућа сесија успостављена Додатни подаци Прескочи - Онемогући обавештења - Онемогући обавештења за ову преписку - Обавештења су онемогућена - Омогући - Конференција захтева лозинку + Искључи обавештења + Искључи обавештења за ову преписку + Обавештења су искључена + Укључи + Групно ћаскање захтева лозинку Унесите лозинку Нема ажуриране присутности од контакта Најпре захтевајте ажурирање присутности од вашег контакта.\n\nОво ће омогућити да се одреди којег клијента ваш контакт користи. @@ -271,7 +268,7 @@ Упозорење: Слање овога без узајамних ажурирања присутности би могло да узрокује неочекиване проблеме.\n\nИдите на детаље контакта да бисте проверили претплате на присутности. Поставке шифровања Присили крај-на-крај шифровање - Увек шифруј поруке (осим за конференције) + Увек шифруј поруке (осим за групна ћаскања) Не успремај шифроване поруке Упозорење: Ово може да доведе до губитка порука Опције за стручњаке @@ -281,8 +278,8 @@ Тихи сати Време почетка Време завршетка - Омогући тихе сате - Обавештења ће бити утишана за време тихих сати + Укључи тихе сате + Обавештења ће бити ућуткана за време тихих сати Повећај величину фонта Користи веће величине фонта за читаву апликацију Дугме слања показује стање @@ -290,13 +287,13 @@ Означи примљене поруке зеленом квачицом, ако је подржано Боја дугмета за слање показује стање контакта Остало - Име конференције - Предмет собе уместо ЈИД-а идентификује конференцију + Назив групног ћаскања + Предмет собе уместо ЈИД-а идентификује групно ћаскање ОТР отисак копиран на клипборд! ОМЕМО отисак копиран на клипборд! - Забрањени сте на овој конференцији - Ова конференција је само за чланове - Шутнути сте из ове конференције + Забрањени сте на овом групном ћаскању + Ово групно ћаскање је само за чланове + Шутнути сте из овог групног ћаскања преко налога %s Проверавам %s на ХТТП домаћину Нисте повезани. Покушајте поново касније @@ -334,6 +331,9 @@ Конверзација Држи сервис у првом плану Спречава оперативни систем да прекине вашу везу + Извези записе + Упис записа на СД картицу + Уписујем записе на СД картицу Изабери фајл Примам %1$s (%2$d%% завршено) Преузми %s @@ -351,11 +351,11 @@ Желите ли заиста да оверите ОТР отисак вашег контакта? Прикажи динамичке ознаке Приказ ознака испод контаката - Омогући обавештења - Направи конференцију са… - Сервер конференције није нађен - Прављење конференције није успело! - Конференција направљена! + Укључи обавештења + Направи групно ћаскање са… + Сервер групног ћаскања није нађен + Прављење групног ћаскања није успело! + Групно ћаскање направљено! Тајна прихваћена! Ресетуј Аватар налога @@ -386,8 +386,8 @@ Текућа лозинка Нова лозинка Лозинка не може бити празна - Омогући све налоге - Онемогући све налоге + Укључи све налоге + Искључи све налоге Изврши радњу са Без припадности Без улоге @@ -398,21 +398,21 @@ Опозови чланство Одобри админ. привилегије Одобри админ. привилегије - Уклони из конференције + Уклони из групног ћаскања Не могу да изменим припадност за %s - Забрани са конференције - Покушавате да уклоните %s са јавне конференције. Једини начин да то урадите је да забраните тог корисника заувек. + Забрани на групном ћаскању + Покушавате да уклоните %s са групног ћаскања. Једини начин да то урадите је да забраните тог корисника заувек. Забрани одмах Не могу да изменим улогу за %s - Јавно доступна конференција - Лична, само за чланове конференција - Опције конференције + Јавно доступно групно ћаскање + Лично, само за чланове + Опције групног ћаскања Лична, само чланови Неанонимна Уређивана Не учествујете - Поставке конференције измењене! - Не могу да изменим поставке конференције + Поставке групног ћаскања измењене! + Не могу да изменим поставке групног ћаскања никад 30 минута 1 сат @@ -431,14 +431,13 @@ Апликација за Андроид Контакт Примљено %s - Онемогући сервис у првом плану + Искључи сервис у првом плану Додирните да отворите Конверзацију Аватар је објављен! Шаљем %s Нудим %s Сакриј неповезане - Онемогући налог - %s куца... + Искључи налог %s престаде да куца Обавештења о куцању Обзнаните контакту кад куцате нову поруку @@ -448,7 +447,7 @@ Локација Примљена локација Преписка затворена - Напусти конференцију + Напусти групно ћаскање Не поуздај се у системска сертификациона тела Сви сертификати морају ручно да се одобре Уклони сертификате @@ -474,7 +473,7 @@ Изаберите брзу радњу Тражите контакте или групе Пошаљи личну поруку - %s напусти конференцију! + %s напусти групно ћаскање! Корисничко име Корисничко име Ово није исправно корисничко име @@ -483,6 +482,15 @@ Преузимање није успело: не могу да се повежем са домаћином Користи белу позадину Приказ примљених порука црним текстом на белој позадини - Прековреме за ДНС Оштећен + Поставке присутности + Одсутан кад је екран искључен + Означава ваш ресурс одсутним кад је екран искључен + Недоступан у тихом режиму + Означава ваш ресурс недоступним кад је телефон у тихом режиму + Не могу да рашчланим сертификат + унесите текст са слике + Ланац сертификата није поуздан + Џабер ИД не одговара сертификату + Обнови сертификат diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml index 90a0248ed..33868fd4e 100644 --- a/src/main/res/values-sv/strings.xml +++ b/src/main/res/values-sv/strings.xml @@ -28,7 +28,6 @@ %d min sedan olästa konversationer skickar… - Avkrypterar meddelande. Vänta… Nick används redan Admin Ägare @@ -74,6 +73,7 @@ Rensa konversationshistorik Vill du ta bort alla meddelanden i denna konversation?\n\nVarning: Detta kommer inte påverka meddelanden lagrade på andra enheter eller servrar. Ta bort meddelanden + Avsluta denna konversation efteråt Välj tillgänglighet till kontakt Skicka okrypterat meddelande Skicka OTR-krypterat meddelande @@ -92,7 +92,6 @@ Conversations kan inte avkryptera ditt meddelande eftersom din kontakt inte annonserar sin publika nyckel.\n\nBe din kontakt att sätta upp OpenPGP. Inga OpenPGP-nycklar funna Conversations kan inte avkryptera ditt meddelande eftersom din kontakt inte annonserar sin publika nyckel.\n\nBe din kontakt att sätta upp OpenPGP. - Krypterat meddelande mottaget. Tryck för att se och avkryptera. Generellt XMPP resurs Namnet som klienten identifierar sig med @@ -171,7 +170,6 @@ Lösenorden är inte lika Detta är inte ett korrekt Jabber ID Slut på minne. Bilden är för stor - Vill du lägga till %s i din telefons kontaktlista? online tillgänglig borta @@ -211,7 +209,6 @@ Eget OMEMO-fingeravtryck Andra enheter Lita på OMEMO-fingeravtryck - Hämtar nycklar... Klar Verifiera Avkryptera @@ -334,6 +331,9 @@ Conversations Håll tjänst i förgrunden Förehindrar operativsystemet att ta ner uppkopplingen + Exportera loggar + Skriv loggar till SD-kort + Skriver loggar till SD-kort Välj fil Tar emot %1$s (%2$d%% klart) Ladda ner %s @@ -438,7 +438,6 @@ Erbjuder %s Dölj ej anslutna Deaktivera konton - %s skriver... %s har slutat skriva Skriv-notifieringar Låter dina kontakter veta när du skriver ett nytt meddelande @@ -481,6 +480,19 @@ Nerladdningen gick fel: Kunder inte ansluta till server Använd vit bakgrund Visa mottagna meddelanden som svart text på vit bakgrund - Timeout för DNS Sönder + Tillgänglighetsinställningar + Status borta när skärmen är av + Sätter din tillgänglighet till borta när skrämen är av + Status ej tillgänglig i tyst läge + Sätter din tillgänglighet till ej tillgänglig när enheten är i tyst läge + Lägg till konto med certifikat + Kan inte läsa certifikat + Lämna tom för att för att logga in med certifikat + Captcha text + Captcha krävs + skriv in texten från bilden + Certifikatskedjan är inte betrodd + Jabber ID matchar inte certifikat + Förnya certifikat diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index 455d13a8b..908394541 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -28,7 +28,6 @@ %d分钟前 未读会话 正在发送… - 解密信息中. 请稍候… 该名称已存在 管理员 所有者 @@ -75,22 +74,23 @@ 删除该会话中所有信息?\n\n注: 该操作不会影响其他设备或服务器保存的信息。 删除消息 添加在线用户至联系人 + 发送未加密的信息 发送 OTR 加密信息 + 发送 OMEMO 加密信息 发送 OpenPGP 加密信息 昵称修改成功 不加密发送 解密失败,可能是私钥不正确。 OpenKeychain - 会话运用了第三方app,名为 OpenKeychain 用来加密、解密信息以及管理您的密钥。\n\nOpenKeychain 遵循 GPLv3 并且可以在 F-Droid 和 Google Play 上获取。\n\n(之后请重启 conversations) + Conversations 使用了第三方app OpenKeychain 来加密、解密信息并管理您的密钥。\n\nOpenKeychain 遵循 GPLv3 并且可以在 F-Droid 和 Google Play 上获取。\n\n(之后请重启 Conversations) 重启 安装 输入… 等待… 未发现 OpenPGP 密钥 - 会话加密信息失败,因为联系人未提供他/她的公钥。\n\n请通知联系人设置 OpenPGP。 + Conversations 无法加密信息,因为联系人未提供他/她的公钥。\n\n请通知联系人设置 OpenPGP。 未找到 OpenPGP 密钥 因您的联系人未公布公钥,Conversations未能成功加密您的信息.\n\n请通知联系人设置OpenPGP. - 加密信息已接收。点击解密并查看。 常规 XMPP 资源 客户端标识名称 @@ -145,8 +145,10 @@ 服务器不支持注册 安全错误 服务器不兼容 + 未加密 OTR OpenPGP + OMEMO 编辑账号 删除账号 暂时不可用 @@ -165,7 +167,6 @@ 密码不一致 该 Jabber ID 无效 空间不足。图片过大 - 您将添加 %s 至手机联系人列表? 在线 自由畅聊 离开 @@ -176,21 +177,20 @@ 其他成员 服务器信息 XEP-0313: MAM - XEP-0280: 消息碳 XEP-0352: 客户端状态指示 XEP-0191: 屏蔽指令 - XEP-0237: 花名册版本 XEP-0198: 流管理 + XEP-0363: HTTP 文件上传 有效 无效 缺少公钥通知 - 最近一次查看为刚刚 - 最近一次查看为一分钟前 - 最近一次查看为 %d 分钟前 - 最近一次查看为一小时前 - 最近一次查看为 %d 小时前 - 最近一次查看为一天前 - 最近一次查看为 %d天前 + 刚刚查看过 + 1 分钟前查看过 + %d 分钟前查看过 + 1 小时前查看过 + %d 小时前查看过 + 1 天前查看过 + %d 天前查看过 未曾查看 加密信息. 请安装 OpenKeychain 以解密。 未知 OTR 指纹 @@ -198,6 +198,11 @@ 接收失败 你的指纹 OTR 指纹 + OMEMO 指纹 + 消息的 OMEMO 指纹 + 其他设备 + 信任的 OMEMO 指纹 + 完成 验证 解密 讨论组 @@ -232,7 +237,7 @@ 不能将头像保存至磁盘 (或长按按钮将返回默认头像) 您的服务器不支持发布头像 - 密谈 + 私聊 至 %s 发送私密消息到 %s 连接 @@ -240,7 +245,7 @@ 下一步 当前会话已建立 其他信息 - Skip略过 + 忽略 关闭通知 关闭该会话消息 通知已关闭 @@ -259,10 +264,10 @@ 总是发送加密信息(讨论组信息除外) 不保存加密信息 警告:此操作将会导致信息丢失 - 导出选项 + 专家选项 请谨慎使用 关于 Conversations - 构建及许可证信息 + 编译及许可证信息 静默时间段 开始时间 结束时间 @@ -278,15 +283,19 @@ 讨论组名称 用讨论组的主题来标示讨论组而不是 JID OTR 指纹已拷贝到剪贴板! + OMEMO 指纹已拷贝到剪贴板! 你被此讨论组屏蔽 此讨论组只允许成员加入 你被从此讨论组踢出 用账户 %s + 正在 HTTP 服务器中检查 %s 你没有连接。请稍后重试 + 检查 %s 大小 消息选项 拷贝文本 拷贝原始URL 再次发送 + 文件 消息文本 已经拷贝 URL 到剪贴板 消息已经拷贝到剪贴板 @@ -315,7 +324,10 @@ Conversations 保持前台服务 防止操作系统中断你的连接 - 关闭文件 + 导出日志 + 将日志写入 SD 卡 + 正在将日志写入 SD 卡 + 选择文件 接收中 %1$s (已完成 %2$d%%) 下载 %s 文件 @@ -330,7 +342,7 @@ 不能验证指纹 手工验证 你确认验证你的联系人的 OTR 指纹? - 现实动态标签 + 显示动态标签 在联系人下方显示只读标签 启用通知 与…创建讨论组 @@ -341,12 +353,20 @@ 重置 账户头像 拷贝 OTR 指纹到剪贴板 + 拷贝 OMEMO 指纹到剪贴板 + 重新生成 OMEMO 密钥 + 从 PEP 中清除其他设备 + 清除设备 + 清除密钥 + 是否确认清除该密钥? + 他们没有密钥可用于此次会话。如果你曾经清除过他们的密钥,那么他们需要生成新的密钥。 + 错误 从服务器获取历史记录 服务器上没有更多历史记录 更新中… 密码已修改! 不能修改密码 - 要启动加密聊天先发送一条消息 + 发送消息来开始加密聊天 提出问题 如果你和你的联系人有一个共知的秘密(比如一个内部笑话或者仅仅只是上次见面时吃的午餐) 你可以使用这个秘密来验证彼此的指纹。\n\n你的联系人将以大小写敏感的方式给出答案,你可以给出提示或问题。 你的联系人可以通过一个你们共知的秘密来验证指纹。你的联系人给出了如下的提示或问题。 @@ -359,7 +379,7 @@ 密码不能为空 启用所有账户 禁用所有账户 - 做一个动作和 + 选择一个操作 没有从属关系 没有角色 抛弃 @@ -378,7 +398,9 @@ 公开访问的讨论组 私密,只有成员可以加入的讨论组 讨论组选项 + 私密,只有成员可以加入 非匿名 + 您尚未参与 讨论组选项已修改! 不能修改讨论组选项 从不 @@ -399,14 +421,13 @@ Android App 联系人 已经收到 %s - 禁用前端服务 + 禁用前台服务 轻触打开 Conversations 头像已经发布! 发送中 %s 提供中 %s 隐藏离线联系人 禁用账户 - %s 正在输入… %s 已停止输入 键盘输入通知 让对方知道你正在输入新消息 @@ -436,4 +457,28 @@ 最近使用过的 选择快速动作 + 搜索联系人或群组 + 发送私密消息 + %s 已离开讨论组! + 用户名 + 用户名 + 该用户名无效 + 下载失败:未找到服务器 + 下载失败:未找到文件 + 下载失败:无法连接到服务器 + 使用白色背景 + 收到的消息将显示为白底黑字 + 损坏 + 关闭屏幕时离开 + 当屏幕关闭时将标记您的资源为离开状态 + 静音模式时不可用 + 当设备处于静音模式时将标记您的资源为不可用状态 + 使用证书添加账户 + 无法解析证书 + 验证码 + 需要验证码 + 输入图片中的文字 + 证书链不受信任 + Jabber ID 与证书不匹配 + 更新证书 diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml index 161d49db2..19252c90b 100644 --- a/src/main/res/values-zh-rTW/strings.xml +++ b/src/main/res/values-zh-rTW/strings.xml @@ -21,7 +21,6 @@ %d 分鐘前 未讀對話 正在發送… - 正在解密訊息中,請稍候… 該用戶名稱已被使用 管理員 擁有人 @@ -74,7 +73,6 @@ Conversations 不能將你的訊息加密,因為聯絡人沒有公佈他/她的公鑰。\n\n請通知聯絡人設定 OpenPGP。 找不到多條 OpenPGP 鑰匙 Conversations 不能將你的訊息加密,因為多位聯絡人沒有公佈他/她的公鑰。\n\n請通知聯絡人設定 OpenPGP。 - 已收到加密訊息,點擊進行解密和查看。 一般 XMPP 資源 客戶端標示名稱 @@ -147,7 +145,6 @@ 密碼不一致 該 Jabber ID 無效 空間不足,圖片過大 - 你確定要新增 %s 為聯絡人嗎? 線上 目前有空 離開 -- cgit v1.2.3 From e5f154316cbfa1d701947fae8bc31239df37531a Mon Sep 17 00:00:00 2001 From: fiaxh Date: Wed, 2 Dec 2015 15:43:55 +0000 Subject: Unset all PGP signatures once ... so they will be redone to match the changed status. --- .../eu/siacs/conversations/entities/Account.java | 17 ++- .../conversations/persistance/DatabaseBackend.java | 11 +- .../conversations/ui/ConversationFragment.java | 142 +++++++++++---------- 3 files changed, 96 insertions(+), 74 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 75e6b2a00..64bbaa2b0 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -413,13 +413,13 @@ public class Account extends AbstractEntity { } public String getPgpSignature() { - if (keys.has(KEY_PGP_SIGNATURE)) { - try { + try { + if (keys.has(KEY_PGP_SIGNATURE) && !"null".equals(keys.getString(KEY_PGP_SIGNATURE))) { return keys.getString(KEY_PGP_SIGNATURE); - } catch (final JSONException e) { + } else { return null; } - } else { + } catch (final JSONException e) { return null; } } @@ -433,6 +433,15 @@ public class Account extends AbstractEntity { return true; } + public boolean unsetPgpSignature() { + try { + keys.put(KEY_PGP_SIGNATURE, JSONObject.NULL); + } catch (JSONException e) { + return false; + } + return true; + } + public long getPgpId() { if (keys.has(KEY_PGP_ID)) { try { diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 8b74581cc..2347c3188 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -43,7 +43,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 20; + private static final int DATABASE_VERSION = 21; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -335,6 +335,15 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (oldVersion < 18 && newVersion >= 18) { db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.READ + " NUMBER DEFAULT 1"); } + + if (oldVersion < 21 && newVersion >= 21) { + List accounts = getAccounts(db); + for (Account account : accounts) { + account.unsetPgpSignature(); + db.update(Account.TABLENAME, account.getContentValues(), Account.UUID + + "=?", new String[]{account.getUuid()}); + } + } } public static synchronized DatabaseBackend getInstance(Context context) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index f7a0e2109..0397ad24c 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1062,81 +1062,85 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final ConversationActivity activity = (ConversationActivity) getActivity(); final XmppConnectionService xmppService = activity.xmppConnectionService; final Contact contact = message.getConversation().getContact(); - if (activity.hasPgp()) { - if (conversation.getMode() == Conversation.MODE_SINGLE) { - if (contact.getPgpKeyId() != 0) { - xmppService.getPgpEngine().hasKey(contact, - new UiCallback() { - - @Override - public void userInputRequried(PendingIntent pi, - Contact contact) { - activity.runIntent( - pi, - ConversationActivity.REQUEST_ENCRYPT_MESSAGE); - } - - @Override - public void success(Contact contact) { - messageSent(); - activity.encryptTextMessage(message); - } - - @Override - public void error(int error, Contact contact) { + if (!activity.hasPgp()) { + activity.showInstallPgpDialog(); + return; + } + if (conversation.getAccount().getPgpSignature() == null) { + activity.announcePgp(conversation.getAccount(), conversation); + return; + } + if (conversation.getMode() == Conversation.MODE_SINGLE) { + if (contact.getPgpKeyId() != 0) { + xmppService.getPgpEngine().hasKey(contact, + new UiCallback() { + + @Override + public void userInputRequried(PendingIntent pi, + Contact contact) { + activity.runIntent( + pi, + ConversationActivity.REQUEST_ENCRYPT_MESSAGE); + } - } - }); + @Override + public void success(Contact contact) { + messageSent(); + activity.encryptTextMessage(message); + } - } else { - showNoPGPKeyDialog(false, - new DialogInterface.OnClickListener() { + @Override + public void error(int error, Contact contact) { + System.out.println(); + } + }); - @Override - public void onClick(DialogInterface dialog, - int which) { - conversation - .setNextEncryption(Message.ENCRYPTION_NONE); - xmppService.databaseBackend - .updateConversation(conversation); - message.setEncryption(Message.ENCRYPTION_NONE); - xmppService.sendMessage(message); - messageSent(); - } - }); - } } else { - if (conversation.getMucOptions().pgpKeysInUse()) { - if (!conversation.getMucOptions().everybodyHasKeys()) { - Toast warning = Toast - .makeText(getActivity(), - R.string.missing_public_keys, - Toast.LENGTH_LONG); - warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0); - warning.show(); - } - activity.encryptTextMessage(message); - messageSent(); - } else { - showNoPGPKeyDialog(true, - new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, - int which) { - conversation - .setNextEncryption(Message.ENCRYPTION_NONE); - message.setEncryption(Message.ENCRYPTION_NONE); - xmppService.databaseBackend - .updateConversation(conversation); - xmppService.sendMessage(message); - messageSent(); - } - }); - } + showNoPGPKeyDialog(false, + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); + xmppService.databaseBackend + .updateConversation(conversation); + message.setEncryption(Message.ENCRYPTION_NONE); + xmppService.sendMessage(message); + messageSent(); + } + }); } } else { - activity.showInstallPgpDialog(); + if (conversation.getMucOptions().pgpKeysInUse()) { + if (!conversation.getMucOptions().everybodyHasKeys()) { + Toast warning = Toast + .makeText(getActivity(), + R.string.missing_public_keys, + Toast.LENGTH_LONG); + warning.setGravity(Gravity.CENTER_VERTICAL, 0, 0); + warning.show(); + } + activity.encryptTextMessage(message); + messageSent(); + } else { + showNoPGPKeyDialog(true, + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); + message.setEncryption(Message.ENCRYPTION_NONE); + xmppService.databaseBackend + .updateConversation(conversation); + xmppService.sendMessage(message); + messageSent(); + } + }); + } } } -- cgit v1.2.3 From f1c0b7372f3db7400f03dc238bf295f039450bbb Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 3 Dec 2015 12:45:12 +0100 Subject: enabled previously disabled http upload --- src/main/java/eu/siacs/conversations/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 0d51b4a19..c56767aff 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -44,7 +44,7 @@ public final class Config { public static final int REFRESH_UI_INTERVAL = 500; public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb - public static final boolean DISABLE_HTTP_UPLOAD = true; + public static final boolean DISABLE_HTTP_UPLOAD = false; public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance public static final boolean EXTENDED_SM_LOGGING = true; // log stanza counts public static final boolean RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE = true; //setting to true might increase power consumption -- cgit v1.2.3 From 6b592435cd7bc831f0aac1bb159229dae955fb9b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 3 Dec 2015 18:18:34 +0100 Subject: parse vcard avatars from muc presences --- .../siacs/conversations/entities/MucOptions.java | 277 +++++++++------------ .../siacs/conversations/parser/MessageParser.java | 2 +- .../siacs/conversations/parser/PresenceParser.java | 117 ++++++++- .../conversations/services/AvatarService.java | 50 +++- .../services/XmppConnectionService.java | 22 +- .../ui/ConferenceDetailsActivity.java | 8 +- 6 files changed, 295 insertions(+), 181 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 13a5bb9f3..412f984fa 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -4,20 +4,25 @@ import android.annotation.SuppressLint; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; import eu.siacs.conversations.R; -import eu.siacs.conversations.crypto.PgpEngine; -import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.forms.Field; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -import eu.siacs.conversations.xmpp.stanzas.PresencePacket; +import eu.siacs.conversations.xmpp.pep.Avatar; @SuppressLint("DefaultLocale") public class MucOptions { + public Account getAccount() { + return this.conversation.getAccount(); + } + + public void setSelf(User user) { + this.self = user; + } + public enum Affiliation { OWNER("owner", 4, R.string.owner), ADMIN("admin", 3, R.string.admin), @@ -100,28 +105,31 @@ public class MucOptions { public static final String STATUS_CODE_LOST_MEMBERSHIP = "321"; private interface OnEventListener { - public void onSuccess(); + void onSuccess(); - public void onFailure(); + void onFailure(); } public interface OnRenameListener extends OnEventListener { } - public class User { + public static class User { private Role role = Role.NONE; private Affiliation affiliation = Affiliation.NONE; - private String name; private Jid jid; + private Jid fullJid; private long pgpKeyId = 0; + private Avatar avatar; + private MucOptions options; - public String getName() { - return name; + public User(MucOptions options, Jid from) { + this.options = options; + this.fullJid = from; } - public void setName(String user) { - this.name = user; + public String getName() { + return this.fullJid.getResourcepart(); } public void setJid(Jid jid) { @@ -162,7 +170,7 @@ public class MucOptions { return false; } else { User o = (User) other; - return name != null && name.equals(o.name) + return getName() != null && getName().equals(o.getName()) && jid != null && jid.equals(o.jid) && affiliation == o.affiliation && role == o.role; @@ -202,26 +210,43 @@ public class MucOptions { } public Contact getContact() { - return account.getRoster().getContactFromRoster(getJid()); + return getAccount().getRoster().getContactFromRoster(getJid()); + } + + public void setAvatar(Avatar avatar) { + this.avatar = avatar; + } + + public String getAvatar() { + return avatar == null ? null : avatar.getFilename(); + } + + public Account getAccount() { + return options.getAccount(); + } + + public Jid getFullJid() { + return fullJid; } } private Account account; - private List users = new CopyOnWriteArrayList<>(); + private final List users = new ArrayList<>(); private List features = new ArrayList<>(); private Data form = new Data(); private Conversation conversation; private boolean isOnline = false; private int error = ERROR_UNKNOWN; - private OnRenameListener onRenameListener = null; - private User self = new User(); + public OnRenameListener onRenameListener = null; + private User self; private String subject = null; private String password = null; - private boolean mNickChangingInProgress = false; + public boolean mNickChangingInProgress = false; public MucOptions(Conversation conversation) { this.account = conversation.getAccount(); this.conversation = conversation; + this.self = new User(this,conversation.getJid()); } public void updateFeatures(ArrayList features) { @@ -273,135 +298,67 @@ public class MucOptions { } public void deleteUser(String name) { - for (int i = 0; i < users.size(); ++i) { - if (users.get(i).getName().equals(name)) { - users.remove(i); - return; + synchronized (this.users) { + for (int i = 0; i < users.size(); ++i) { + if (users.get(i).getName().equals(name)) { + users.remove(i); + return; + } } } } public void addUser(User user) { - for (int i = 0; i < users.size(); ++i) { - if (users.get(i).getName().equals(user.getName())) { - users.set(i, user); - return; + synchronized (this.users) { + for (int i = 0; i < users.size(); ++i) { + if (users.get(i).getName().equals(user.getName())) { + users.set(i, user); + return; + } } + users.add(user); } - users.add(user); } - public boolean isUserInRoom(String name) { - for (int i = 0; i < users.size(); ++i) { - if (users.get(i).getName().equals(name)) { - return true; - } + public User findUser(String name) { + if (name == null) { + return null; } - return false; - } - - public void processPacket(PresencePacket packet, PgpEngine pgp) { - final Jid from = packet.getFrom(); - if (!from.isBareJid()) { - final String name = from.getResourcepart(); - final String type = packet.getAttribute("type"); - final Element x = packet.findChild("x", "http://jabber.org/protocol/muc#user"); - final List codes = getStatusCodes(x); - if (type == null) { - User user = new User(); - if (x != null) { - Element item = x.findChild("item"); - if (item != null && name != null) { - user.setName(name); - user.setAffiliation(item.getAttribute("affiliation")); - user.setRole(item.getAttribute("role")); - user.setJid(item.getAttributeAsJid("jid")); - if (codes.contains(STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(this.conversation.getJid())) { - this.isOnline = true; - this.error = ERROR_NO_ERROR; - self = user; - if (mNickChangingInProgress) { - if (onRenameListener != null) { - onRenameListener.onSuccess(); - } - mNickChangingInProgress = false; - } - } else { - addUser(user); - } - if (pgp != null) { - Element signed = packet.findChild("x", "jabber:x:signed"); - if (signed != null) { - Element status = packet.findChild("status"); - String msg = status == null ? "" : status.getContent(); - long keyId = pgp.fetchKeyId(account, msg, signed.getContent()); - if (keyId != 0) { - user.setPgpKeyId(keyId); - } - } - } - } - } - } else if (type.equals("unavailable")) { - if (codes.contains(STATUS_CODE_SELF_PRESENCE) || - packet.getFrom().equals(this.conversation.getJid())) { - if (codes.contains(STATUS_CODE_CHANGED_NICK)) { - this.mNickChangingInProgress = true; - } else if (codes.contains(STATUS_CODE_KICKED)) { - setError(KICKED_FROM_ROOM); - } else if (codes.contains(STATUS_CODE_BANNED)) { - setError(ERROR_BANNED); - } else if (codes.contains(STATUS_CODE_LOST_MEMBERSHIP)) { - setError(ERROR_MEMBERS_ONLY); - } else { - setError(ERROR_UNKNOWN); - } - } else { - deleteUser(name); - } - } else if (type.equals("error")) { - Element error = packet.findChild("error"); - if (error != null && error.hasChild("conflict")) { - if (isOnline) { - if (onRenameListener != null) { - onRenameListener.onFailure(); - } - } else { - setError(ERROR_NICK_IN_USE); - } - } else if (error != null && error.hasChild("not-authorized")) { - setError(ERROR_PASSWORD_REQUIRED); - } else if (error != null && error.hasChild("forbidden")) { - setError(ERROR_BANNED); - } else if (error != null && error.hasChild("registration-required")) { - setError(ERROR_MEMBERS_ONLY); + synchronized (this.users) { + for (User user : users) { + if (user.getName().equals(name)) { + return user; } } } + return null; } - private void setError(int error) { - this.isOnline = false; + public boolean isUserInRoom(String name) { + return findUser(name) != null; + } + + public void setError(int error) { + this.isOnline = error == ERROR_NO_ERROR; this.error = error; } - private List getStatusCodes(Element x) { - List codes = new ArrayList<>(); - if (x != null) { - for (Element child : x.getChildren()) { - if (child.getName().equals("status")) { - String code = child.getAttribute("code"); - if (code != null) { - codes.add(code); - } - } - } + public ArrayList getUsers() { + synchronized (this.users) { + return new ArrayList(this.users); } - return codes; } - public List getUsers() { - return this.users; + public List getUsers(int max) { + synchronized (this.users) { + return new ArrayList<>(users.subList(0,Math.min(users.size(),5))); + } + } + + public int getUserCount() { + synchronized (this.users) { + return this.users.size(); + } } public String getProposedNick() { @@ -455,34 +412,38 @@ public class MucOptions { } public String createNameFromParticipants() { - if (users.size() >= 2) { - List names = new ArrayList(); - for (User user : users) { - Contact contact = user.getContact(); - if (contact != null && !contact.getDisplayName().isEmpty()) { - names.add(contact.getDisplayName().split("\\s+")[0]); - } else { - names.add(user.getName()); + synchronized (this.users) { + if (users.size() >= 2) { + List names = new ArrayList(); + for (User user : users) { + Contact contact = user.getContact(); + if (contact != null && !contact.getDisplayName().isEmpty()) { + names.add(contact.getDisplayName().split("\\s+")[0]); + } else { + names.add(user.getName()); + } } - } - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < names.size(); ++i) { - builder.append(names.get(i)); - if (i != names.size() - 1) { - builder.append(", "); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < names.size(); ++i) { + builder.append(names.get(i)); + if (i != names.size() - 1) { + builder.append(", "); + } } + return builder.toString(); + } else { + return null; } - return builder.toString(); - } else { - return null; } } public long[] getPgpKeyIds() { List ids = new ArrayList<>(); - for (User user : getUsers()) { - if (user.getPgpKeyId() != 0) { - ids.add(user.getPgpKeyId()); + synchronized (this.users) { + for (User user : this.users) { + if (user.getPgpKeyId() != 0) { + ids.add(user.getPgpKeyId()); + } } } ids.add(account.getPgpId()); @@ -494,18 +455,22 @@ public class MucOptions { } public boolean pgpKeysInUse() { - for (User user : getUsers()) { - if (user.getPgpKeyId() != 0) { - return true; + synchronized (this.users) { + for (User user : this.users) { + if (user.getPgpKeyId() != 0) { + return true; + } } } return false; } public boolean everybodyHasKeys() { - for (User user : getUsers()) { - if (user.getPgpKeyId() == 0) { - return false; + synchronized (this.users) { + for (User user : this.users) { + if (user.getPgpKeyId() == 0) { + return false; + } } } return true; @@ -520,9 +485,11 @@ public class MucOptions { } public Jid getTrueCounterpart(String counterpart) { - for (User user : this.getUsers()) { - if (user.getName().equals(counterpart)) { - return user.getJid(); + synchronized (this.users) { + for (User user : this.users) { + if (user.getName().equals(counterpart)) { + return user.getJid(); + } } } return null; diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index b4c648fe9..3e923af1c 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -169,7 +169,7 @@ public class MessageParser extends AbstractParser implements if ("urn:xmpp:avatar:metadata".equals(node)) { Avatar avatar = Avatar.parseMetadata(items); if (avatar != null) { - avatar.owner = from; + avatar.owner = from.toBareJid(); if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) { if (account.getJid().toBareJid().equals(from)) { if (account.setAvatar(avatar.getFilename())) { diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 59b94bc0c..f94485280 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -1,7 +1,11 @@ package eu.siacs.conversations.parser; +import android.util.Log; + import java.util.ArrayList; +import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; @@ -25,19 +29,18 @@ public class PresenceParser extends AbstractParser implements } public void parseConferencePresence(PresencePacket packet, Account account) { - PgpEngine mPgpEngine = mXmppConnectionService.getPgpEngine(); final Conversation conversation = packet.getFrom() == null ? null : mXmppConnectionService.find(account, packet.getFrom().toBareJid()); if (conversation != null) { final MucOptions mucOptions = conversation.getMucOptions(); boolean before = mucOptions.online(); - int count = mucOptions.getUsers().size(); - final ArrayList tileUserBefore = new ArrayList<>(mucOptions.getUsers().subList(0,Math.min(mucOptions.getUsers().size(),5))); - mucOptions.processPacket(packet, mPgpEngine); - final ArrayList tileUserAfter = new ArrayList<>(mucOptions.getUsers().subList(0,Math.min(mucOptions.getUsers().size(),5))); + int count = mucOptions.getUserCount(); + final List tileUserBefore = mucOptions.getUsers(5); + processConferencePresence(packet, mucOptions); + final List tileUserAfter = mucOptions.getUsers(5); if (!tileUserAfter.equals(tileUserBefore)) { mXmppConnectionService.getAvatarService().clear(conversation); } - if (before != mucOptions.online() || (mucOptions.online() && count != mucOptions.getUsers().size())) { + if (before != mucOptions.online() || (mucOptions.online() && count != mucOptions.getUserCount())) { mXmppConnectionService.updateConversationUi(); } else if (mucOptions.online()) { mXmppConnectionService.updateMucRosterUi(); @@ -45,6 +48,108 @@ public class PresenceParser extends AbstractParser implements } } + private void processConferencePresence(PresencePacket packet, MucOptions mucOptions) { + final Jid from = packet.getFrom(); + if (!from.isBareJid()) { + final String type = packet.getAttribute("type"); + final Element x = packet.findChild("x", "http://jabber.org/protocol/muc#user"); + Avatar avatar = Avatar.parsePresence(packet.findChild("x", "vcard-temp:x:update")); + final List codes = getStatusCodes(x); + if (type == null) { + if (x != null) { + Element item = x.findChild("item"); + if (item != null && !from.isBareJid()) { + MucOptions.User user = new MucOptions.User(mucOptions,from); + user.setAffiliation(item.getAttribute("affiliation")); + user.setRole(item.getAttribute("role")); + user.setJid(item.getAttributeAsJid("jid")); + if (codes.contains(MucOptions.STATUS_CODE_SELF_PRESENCE) || packet.getFrom().equals(mucOptions.getConversation().getJid())) { + mucOptions.setError(MucOptions.ERROR_NO_ERROR); + mucOptions.setSelf(user); + if (mucOptions.mNickChangingInProgress) { + if (mucOptions.onRenameListener != null) { + mucOptions.onRenameListener.onSuccess(); + } + mucOptions.mNickChangingInProgress = false; + } + } else { + mucOptions.addUser(user); + } + if (mXmppConnectionService.getPgpEngine() != null) { + Element signed = packet.findChild("x", "jabber:x:signed"); + if (signed != null) { + Element status = packet.findChild("status"); + String msg = status == null ? "" : status.getContent(); + long keyId = mXmppConnectionService.getPgpEngine().fetchKeyId(mucOptions.getAccount(), msg, signed.getContent()); + if (keyId != 0) { + user.setPgpKeyId(keyId); + } + } + } + if (avatar != null) { + avatar.owner = from; + if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) { + user.setAvatar(avatar); + } else { + mXmppConnectionService.fetchAvatar(mucOptions.getAccount(), avatar); + } + Log.d(Config.LOGTAG, "user " + avatar.owner + " has avatar"); + } + } + } + } else if (type.equals("unavailable")) { + if (codes.contains(MucOptions.STATUS_CODE_SELF_PRESENCE) || + packet.getFrom().equals(mucOptions.getConversation().getJid())) { + if (codes.contains(MucOptions.STATUS_CODE_CHANGED_NICK)) { + mucOptions.mNickChangingInProgress = true; + } else if (codes.contains(MucOptions.STATUS_CODE_KICKED)) { + mucOptions.setError(MucOptions.KICKED_FROM_ROOM); + } else if (codes.contains(MucOptions.STATUS_CODE_BANNED)) { + mucOptions.setError(MucOptions.ERROR_BANNED); + } else if (codes.contains(MucOptions.STATUS_CODE_LOST_MEMBERSHIP)) { + mucOptions.setError(MucOptions.ERROR_MEMBERS_ONLY); + } else { + mucOptions.setError(MucOptions.ERROR_UNKNOWN); + } + } else if (!from.isBareJid()){ + mucOptions.deleteUser(from.getResourcepart()); + } + } else if (type.equals("error")) { + Element error = packet.findChild("error"); + if (error != null && error.hasChild("conflict")) { + if (mucOptions.online()) { + if (mucOptions.onRenameListener != null) { + mucOptions.onRenameListener.onFailure(); + } + } else { + mucOptions.setError(MucOptions.ERROR_NICK_IN_USE); + } + } else if (error != null && error.hasChild("not-authorized")) { + mucOptions.setError(MucOptions.ERROR_PASSWORD_REQUIRED); + } else if (error != null && error.hasChild("forbidden")) { + mucOptions.setError(MucOptions.ERROR_BANNED); + } else if (error != null && error.hasChild("registration-required")) { + mucOptions.setError(MucOptions.ERROR_MEMBERS_ONLY); + } + } + } + } + + private static List getStatusCodes(Element x) { + List codes = new ArrayList<>(); + if (x != null) { + for (Element child : x.getChildren()) { + if (child.getName().equals("status")) { + String code = child.getAttribute("code"); + if (code != null) { + codes.add(code); + } + } + } + } + return codes; + } + public void parseContactPresence(final PresencePacket packet, final Account account) { final PresenceGenerator mPresenceGenerator = mXmppConnectionService.getPresenceGenerator(); final Jid from = packet.getFrom(); diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index 5db4abae1..31d625ccd 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -58,6 +58,22 @@ public class AvatarService { return avatar; } + public Bitmap get(final MucOptions.User user, final int size, boolean cachedOnly) { + final String KEY = key(user, size); + Bitmap avatar = this.mXmppConnectionService.getBitmapCache().get(KEY); + if (avatar != null || cachedOnly) { + return avatar; + } + if (user.getAvatar() != null) { + avatar = mXmppConnectionService.getFileBackend().getAvatar(user.getAvatar(), size); + } + if (avatar == null) { + avatar = get(user.getName(), size, cachedOnly); + } + this.mXmppConnectionService.getBitmapCache().put(KEY, avatar); + return avatar; + } + public void clear(Contact contact) { synchronized (this.sizes) { for (Integer size : sizes) { @@ -77,6 +93,16 @@ public class AvatarService { + contact.getJid() + "_" + String.valueOf(size); } + private String key(MucOptions.User user, int size) { + synchronized (this.sizes) { + if (!this.sizes.contains(size)) { + this.sizes.add(size); + } + } + return PREFIX_CONTACT + "_" + user.getAccount().getJid().toBareJid() + "_" + + user.getFullJid() + "_" + String.valueOf(size); + } + public Bitmap get(ListItem item, int size) { return get(item,size,false); } @@ -122,7 +148,7 @@ public class AvatarService { if (bitmap != null || cachedOnly) { return bitmap; } - final List users = new ArrayList<>(mucOptions.getUsers()); + final List users = mucOptions.getUsers(); int count = users.size(); bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); @@ -198,15 +224,20 @@ public class AvatarService { } public Bitmap get(Message message, int size, boolean cachedOnly) { + final Conversation conversation = message.getConversation(); if (message.getStatus() == Message.STATUS_RECEIVED) { - Contact contact = message.getContact(); - if (contact != null) { - return get(contact, size, cachedOnly); - } else { - return get(UIHelper.getMessageDisplayName(message), size, cachedOnly); + Contact c = message.getContact(); + if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null)) { + return get(c, size, cachedOnly); + } else if (message.getConversation().getMode() == Conversation.MODE_MULTI){ + MucOptions.User user = conversation.getMucOptions().findUser(message.getCounterpart().getResourcepart()); + if (user != null) { + return get(user,size,cachedOnly); + } } + return get(UIHelper.getMessageDisplayName(message), size, cachedOnly); } else { - return get(message.getConversation().getAccount(), size, cachedOnly); + return get(conversation.getAccount(), size, cachedOnly); } } @@ -290,6 +321,11 @@ public class AvatarService { if (drawTile(canvas, uri, left, top, right, bottom)) { return true; } + } else if (user.getAvatar() != null) { + Uri uri = mXmppConnectionService.getFileBackend().getAvatarUri(user.getAvatar()); + if (drawTile(canvas, uri, left, top, right, bottom)) { + return true; + } } String name = contact != null ? contact.getDisplayName() : user.getName(); drawTile(canvas, name, left, top, right, bottom); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 8e4c9c68c..2bafb03aa 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2358,12 +2358,22 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (getFileBackend().save(avatar)) { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": successfully fetched vCard avatar for " + avatar.owner); - Contact contact = account.getRoster() - .getContact(avatar.owner); - contact.setAvatar(avatar); - getAvatarService().clear(contact); - updateConversationUi(); - updateRosterUi(); + if (avatar.owner.isBareJid()) { + Contact contact = account.getRoster() + .getContact(avatar.owner); + contact.setAvatar(avatar); + getAvatarService().clear(contact); + updateConversationUi(); + updateRosterUi(); + } else { + Conversation conversation = find(account,avatar.owner.toBareJid()); + if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) { + MucOptions.User user = conversation.getMucOptions().findUser(avatar.owner.getResourcepart()); + if (user != null) { + user.setAvatar(avatar); + } + } + } } } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index a2abbf527..adae79168 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -494,8 +494,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); membersView.removeAllViews(); - final ArrayList users = new ArrayList<>(); - users.addAll(mConversation.getMucOptions().getUsers()); + final ArrayList users = mucOptions.getUsers(); Collections.sort(users,new Comparator() { @Override public int compare(User lhs, User rhs) { @@ -527,20 +526,17 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers }); tvKey.setText(OpenPgpUtils.convertKeyIdToHex(user.getPgpKeyId())); } - Bitmap bm; Contact contact = user.getContact(); if (contact != null) { - bm = avatarService().get(contact, getPixel(48)); tvDisplayName.setText(contact.getDisplayName()); tvStatus.setText(user.getName() + " \u2022 " + getStatus(user)); } else { - bm = avatarService().get(user.getName(), getPixel(48)); tvDisplayName.setText(user.getName()); tvStatus.setText(getStatus(user)); } ImageView iv = (ImageView) view.findViewById(R.id.contact_photo); - iv.setImageBitmap(bm); + iv.setImageBitmap(avatarService().get(user, getPixel(48), false)); membersView.addView(view); if (mConversation.getMucOptions().canInvite()) { mInviteButton.setVisibility(View.VISIBLE); -- cgit v1.2.3 From 242887447c09846f8b4eaeb8a29406e5135ec906 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 4 Dec 2015 14:07:16 +0100 Subject: use proposed nick as default nick in mucoptions --- src/main/java/eu/siacs/conversations/entities/MucOptions.java | 2 +- src/main/java/eu/siacs/conversations/parser/PresenceParser.java | 4 ---- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 3 --- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 412f984fa..92254b906 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -246,7 +246,7 @@ public class MucOptions { public MucOptions(Conversation conversation) { this.account = conversation.getAccount(); this.conversation = conversation; - this.self = new User(this,conversation.getJid()); + this.self = new User(this,createJoinJid(getProposedNick())); } public void updateFeatures(ArrayList features) { diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index f94485280..12ffd33fd 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -1,11 +1,8 @@ package eu.siacs.conversations.parser; -import android.util.Log; - import java.util.ArrayList; import java.util.List; -import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; @@ -93,7 +90,6 @@ public class PresenceParser extends AbstractParser implements } else { mXmppConnectionService.fetchAvatar(mucOptions.getAccount(), avatar); } - Log.d(Config.LOGTAG, "user " + avatar.owner + " has avatar"); } } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 2bafb03aa..776069568 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1720,9 +1720,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa Account account = conversation.getAccount(); final String nick = conversation.getMucOptions().getProposedNick(); final Jid joinJid = conversation.getMucOptions().createJoinJid(nick); - if (joinJid == null) { - return; //safety net - } Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": joining conversation " + joinJid.toString()); PresencePacket packet = new PresencePacket(); packet.setFrom(conversation.getAccount().getJid()); -- cgit v1.2.3 From 3e3cb047be7f63233f766a022e9cf9ba8827094d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 4 Dec 2015 15:34:45 +0100 Subject: rely on message id if message id is uuid and pgp encryption was used to deduplicate messages. fixes #1357 --- src/main/java/eu/siacs/conversations/entities/Message.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index b59b0b38c..4a49d1b3c 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -361,7 +361,9 @@ public class Message extends AbstractEntity { if (message.getRemoteMsgId() != null) { return (message.getRemoteMsgId().equals(this.remoteMsgId) || message.getRemoteMsgId().equals(this.uuid)) && this.counterpart.equals(message.getCounterpart()) - && body.equals(otherBody); + && (body.equals(otherBody) + ||(message.getEncryption() == Message.ENCRYPTION_PGP + && message.getRemoteMsgId().matches("[0-9a-f]{8}-[0-9a-f]{4}-4[0-9]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"))) ; } else { return this.remoteMsgId == null && this.counterpart.equals(message.getCounterpart()) -- cgit v1.2.3 From 0664d6ac7b8d0cefac8fa92df625fe653d606b1a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 4 Dec 2015 15:35:22 +0100 Subject: avoid some NPEs --- src/main/java/eu/siacs/conversations/ui/ConversationFragment.java | 2 +- src/main/java/eu/siacs/conversations/utils/DNSHelper.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index f7a0e2109..ab1319ef8 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -365,7 +365,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa break; case Message.ENCRYPTION_AXOLOTL: AxolotlService axolotlService = conversation.getAccount().getAxolotlService(); - if (axolotlService.trustedSessionVerified(conversation)) { + if (axolotlService != null && axolotlService.trustedSessionVerified(conversation)) { mEditMessage.setHint(getString(R.string.send_omemo_x509_message)); } else { mEditMessage.setHint(getString(R.string.send_omemo_message)); diff --git a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java index f3c4f79a2..e07df627e 100644 --- a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java @@ -227,10 +227,11 @@ public class DNSHelper { } public static boolean isIp(final String server) { - return PATTERN_IPV4.matcher(server).matches() + return server != null && ( + PATTERN_IPV4.matcher(server).matches() || PATTERN_IPV6.matcher(server).matches() || PATTERN_IPV6_6HEX4DEC.matcher(server).matches() || PATTERN_IPV6_HEX4DECCOMPRESSED.matcher(server).matches() - || PATTERN_IPV6_HEXCOMPRESSED.matcher(server).matches(); + || PATTERN_IPV6_HEXCOMPRESSED.matcher(server).matches()); } } -- cgit v1.2.3 From 9d1e8a34b2397abe3d21c91f05df19f43eada2bd Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 4 Dec 2015 18:39:09 +0100 Subject: fixed showing avatars for contacts in muc --- .../java/eu/siacs/conversations/services/AvatarService.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index 31d625ccd..8c113ab00 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -59,6 +59,15 @@ public class AvatarService { } public Bitmap get(final MucOptions.User user, final int size, boolean cachedOnly) { + Contact c = user.getContact(); + if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null)) { + return get(c, size, cachedOnly); + } else { + return getImpl(user, size, cachedOnly); + } + } + + private Bitmap getImpl(final MucOptions.User user, final int size, boolean cachedOnly) { final String KEY = key(user, size); Bitmap avatar = this.mXmppConnectionService.getBitmapCache().get(KEY); if (avatar != null || cachedOnly) { @@ -232,7 +241,7 @@ public class AvatarService { } else if (message.getConversation().getMode() == Conversation.MODE_MULTI){ MucOptions.User user = conversation.getMucOptions().findUser(message.getCounterpart().getResourcepart()); if (user != null) { - return get(user,size,cachedOnly); + return getImpl(user,size,cachedOnly); } } return get(UIHelper.getMessageDisplayName(message), size, cachedOnly); -- cgit v1.2.3 From cd9a29718bcf961cdae2bb88ad65066e7347bfb5 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 4 Dec 2015 21:36:48 +0100 Subject: properly clear muc user avatar caches --- .../siacs/conversations/entities/MucOptions.java | 9 +++++++-- .../siacs/conversations/parser/PresenceParser.java | 6 ++++-- .../conversations/services/AvatarService.java | 22 ++++++++++++++-------- .../services/XmppConnectionService.java | 6 +++++- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 92254b906..853a8408f 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -213,8 +213,13 @@ public class MucOptions { return getAccount().getRoster().getContactFromRoster(getJid()); } - public void setAvatar(Avatar avatar) { - this.avatar = avatar; + public boolean setAvatar(Avatar avatar) { + if (this.avatar != null && this.avatar.equals(avatar)) { + return false; + } else { + this.avatar = avatar; + return true; + } } public String getAvatar() { diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 12ffd33fd..b8a2a7e96 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -35,7 +35,7 @@ public class PresenceParser extends AbstractParser implements processConferencePresence(packet, mucOptions); final List tileUserAfter = mucOptions.getUsers(5); if (!tileUserAfter.equals(tileUserBefore)) { - mXmppConnectionService.getAvatarService().clear(conversation); + mXmppConnectionService.getAvatarService().clear(mucOptions); } if (before != mucOptions.online() || (mucOptions.online() && count != mucOptions.getUserCount())) { mXmppConnectionService.updateConversationUi(); @@ -86,7 +86,9 @@ public class PresenceParser extends AbstractParser implements if (avatar != null) { avatar.owner = from; if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) { - user.setAvatar(avatar); + if (user.setAvatar(avatar)) { + mXmppConnectionService.getAvatarService().clear(user); + } } else { mXmppConnectionService.fetchAvatar(mucOptions.getAccount(), avatar); } diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index 8c113ab00..be320b6b1 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -197,8 +197,7 @@ public class AvatarService { public void clear(MucOptions options) { synchronized (this.sizes) { for (Integer size : sizes) { - this.mXmppConnectionService.getBitmapCache().remove( - key(options, size)); + this.mXmppConnectionService.getBitmapCache().remove(key(options, size)); } } } @@ -253,8 +252,15 @@ public class AvatarService { public void clear(Account account) { synchronized (this.sizes) { for (Integer size : sizes) { - this.mXmppConnectionService.getBitmapCache().remove( - key(account, size)); + this.mXmppConnectionService.getBitmapCache().remove(key(account, size)); + } + } + } + + public void clear(MucOptions.User user) { + synchronized (this.sizes) { + for (Integer size : sizes) { + this.mXmppConnectionService.getBitmapCache().remove(key(user, size)); } } } @@ -346,12 +352,12 @@ public class AvatarService { if (avatar != null) { Uri uri = mXmppConnectionService.getFileBackend().getAvatarUri(avatar); if (uri != null) { - drawTile(canvas, uri, left, top, right, bottom); + if (drawTile(canvas, uri, left, top, right, bottom)) { + return true; + } } - } else { - drawTile(canvas, account.getJid().toBareJid().toString(), left, top, right, bottom); } - return true; + return drawTile(canvas, account.getJid().toBareJid().toString(), left, top, right, bottom); } private boolean drawTile(Canvas canvas, String name, int left, int top, int right, int bottom) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 776069568..dbc4825c9 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2367,7 +2367,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) { MucOptions.User user = conversation.getMucOptions().findUser(avatar.owner.getResourcepart()); if (user != null) { - user.setAvatar(avatar); + if (user.setAvatar(avatar)) { + getAvatarService().clear(user); + updateConversationUi(); + updateMucRosterUi(); + } } } } -- cgit v1.2.3 From 41dcd8005b07cf7a2362dc349ba281defef514dc Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 4 Dec 2015 22:03:46 +0100 Subject: parse stanza-id from messages --- .../siacs/conversations/parser/MessageParser.java | 22 +++++++++++++++++++--- .../java/eu/siacs/conversations/xml/Element.java | 4 ++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 3e923af1c..137cd4561 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -163,6 +163,17 @@ public class MessageParser extends AbstractParser implements return null; } + private static String extractStanzaId(Element packet, Jid by) { + for(Element child : packet.getChildren()) { + if (child.getName().equals("stanza-id") + && "urn:xmpp:sid:0".equals(child.getNamespace()) + && by.equals(child.getAttributeAsJid("by"))) { + return child.getAttribute("id"); + } + } + return null; + } + private void parseEvent(final Element event, final Jid from, final Account account) { Element items = event.findChild("items"); String node = items == null ? null : items.getAttribute("node"); @@ -355,6 +366,11 @@ public class MessageParser extends AbstractParser implements } else { message = new Message(conversation, body, Message.ENCRYPTION_NONE, status); } + + if (serverMsgId == null) { + serverMsgId = extractStanzaId(packet, isTypeGroupChat ? conversation.getJid().toBareJid() : account.getServer()); + } + message.setCounterpart(counterpart); message.setRemoteMsgId(remoteMsgId); message.setServerMsgId(serverMsgId); @@ -379,11 +395,11 @@ public class MessageParser extends AbstractParser implements Log.d(Config.LOGTAG,"skipping duplicate message from "+message.getCounterpart().toString()+" "+message.getBody()); return; } + + conversation.add(message); if (query != null) { query.incrementMessageCount(); - } - conversation.add(message); - if (serverMsgId == null) { + } else { if (status == Message.STATUS_SEND || status == Message.STATUS_SEND_RECEIVED) { mXmppConnectionService.markRead(conversation); account.activateGracePeriod(); diff --git a/src/main/java/eu/siacs/conversations/xml/Element.java b/src/main/java/eu/siacs/conversations/xml/Element.java index e82c446bd..34794be1b 100644 --- a/src/main/java/eu/siacs/conversations/xml/Element.java +++ b/src/main/java/eu/siacs/conversations/xml/Element.java @@ -182,4 +182,8 @@ public class Element { String attr = getAttribute(name); return (attr != null && (attr.equalsIgnoreCase("true") || attr.equalsIgnoreCase("1"))); } + + public String getNamespace() { + return getAttribute("xmlns"); + } } -- cgit v1.2.3 From 72b781b845925ff02fe76ae39f9a84876422a1ed Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 5 Dec 2015 16:29:38 +0100 Subject: updated changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cde6a625a..65f06ce4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ ###Changelog +####Version 1.8.0 +* TOR/ORBOT support in advanced settings +* show vcard avatars of participants in a conference + +####Version 1.7.3 +* fixed PGP encrypted file transfer +* fixed repeating messages in slack conferences + +####Version 1.7.2 +* decode PGP messages in background + + ####Versrion 1.7.1 * performance improvements when opening a conversation -- cgit v1.2.3 From 6358f641e7acbc5b02a3b7a46289dd4baed63fcf Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 5 Dec 2015 18:41:38 +0100 Subject: check for query object as condition to trigger deduplication instead of serverId --- src/main/java/eu/siacs/conversations/parser/MessageParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 137cd4561..6baefac54 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -388,7 +388,7 @@ public class MessageParser extends AbstractParser implements } } updateLastseen(packet,account,true); - boolean checkForDuplicates = serverMsgId != null + boolean checkForDuplicates = query != null || (isTypeGroupChat && packet.hasChild("delay","urn:xmpp:delay")) || message.getType() == Message.TYPE_PRIVATE; if (checkForDuplicates && conversation.hasDuplicateMessage(message)) { -- cgit v1.2.3 From b7f326372d6ea2aceb40e36f18d9eaaba23fa97e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 5 Dec 2015 19:02:57 +0100 Subject: be more carefull with pending uris --- .../conversations/ui/ConversationActivity.java | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 1f6e57a0a..969838bd8 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -998,6 +998,7 @@ public class ConversationActivity extends XmppActivity if (xmppConnectionServiceBound) { if (intent != null && VIEW_CONVERSATION.equals(intent.getType())) { handleViewConversationIntent(intent); + setIntent(new Intent()); } } else { setIntent(intent); @@ -1049,17 +1050,26 @@ public class ConversationActivity extends XmppActivity public void onSaveInstanceState(final Bundle savedInstanceState) { Conversation conversation = getSelectedConversation(); if (conversation != null) { - savedInstanceState.putString(STATE_OPEN_CONVERSATION, - conversation.getUuid()); + savedInstanceState.putString(STATE_OPEN_CONVERSATION,conversation.getUuid()); + } else { + savedInstanceState.remove(STATE_OPEN_CONVERSATION); } - savedInstanceState.putBoolean(STATE_PANEL_OPEN, - isConversationsOverviewVisable()); + savedInstanceState.putBoolean(STATE_PANEL_OPEN,isConversationsOverviewVisable()); if (this.mPendingImageUris.size() >= 1) { savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUris.get(0).toString()); + } else { + savedInstanceState.remove(STATE_PENDING_URI); } super.onSaveInstanceState(savedInstanceState); } + private void clearPending() { + mPendingImageUris.clear(); + mPendingFileUris.clear(); + mPendingGeoUri = null; + mPostponedActivityResult = null; + } + @Override void onBackendConnected() { this.xmppConnectionService.getNotificationService().setIsInForeground(true); @@ -1087,6 +1097,7 @@ public class ConversationActivity extends XmppActivity finish(); } } else if (getIntent() != null && VIEW_CONVERSATION.equals(getIntent().getType())) { + clearPending(); handleViewConversationIntent(getIntent()); } else if (selectConversationByUuid(mOpenConverstaion)) { if (mPanelOpen) { @@ -1100,11 +1111,8 @@ public class ConversationActivity extends XmppActivity mOpenConverstaion = null; } else if (getSelectedConversation() == null) { showConversationsOverview(); - mPendingImageUris.clear(); - mPendingFileUris.clear(); - mPendingGeoUri = null; + clearPending(); setSelectedConversation(conversationList.get(0)); - mPostponedActivityResult = null; this.mConversationFragment.reInit(getSelectedConversation()); } else { this.mConversationFragment.messageListAdapter.updatePreferences(); -- cgit v1.2.3 From bd765c59cefc408d24240c93146ffaf03b74ae3a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 5 Dec 2015 19:03:17 +0100 Subject: check availabiltiy of pgp before sharing files --- src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index 8ec44f4e5..35f1ff359 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -192,6 +192,10 @@ public class ShareWithActivity extends XmppActivity { } private void share(final Conversation conversation) { + if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP && !hasPgp()) { + showInstallPgpDialog(); + return; + } if (share.uris.size() != 0) { OnPresenceSelected callback = new OnPresenceSelected() { @Override -- cgit v1.2.3 From 904edf5d59072058b324e7f80ab1201a1535f64e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 6 Dec 2015 11:57:11 +0100 Subject: hide prepare file toast after preparing the file --- src/main/java/eu/siacs/conversations/ui/ConversationActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 969838bd8..6b85410b9 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -1357,6 +1357,7 @@ public class ConversationActivity extends XmppActivity @Override public void success(Message message) { + hidePrepareFileToast(); xmppConnectionService.sendMessage(message); } -- cgit v1.2.3 From 164d341915137ec35f5d1eb681ee50d0b83c58bc Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 7 Dec 2015 13:20:00 +0100 Subject: version bump to 1.8.0 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 48bf2ed38..d92c161dd 100644 --- a/build.gradle +++ b/build.gradle @@ -53,8 +53,8 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 21 - versionCode 108 - versionName "1.8.0-beta" + versionCode 109 + versionName "1.8.0" project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName); } -- cgit v1.2.3 From 739a2d609d15be7472575adb937e9a0b164dd4a9 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 6 Dec 2015 11:55:37 +0100 Subject: implement direct sharing in android 6.0. fixes #1321 --- build.gradle | 4 +- src/main/AndroidManifest.xml | 9 +++ .../services/ContactChooserTargetService.java | 87 ++++++++++++++++++++++ .../siacs/conversations/ui/ShareWithActivity.java | 87 ++++++++++++++++------ src/main/res/values/strings.xml | 3 + 5 files changed, 165 insertions(+), 25 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java diff --git a/build.gradle b/build.gradle index d92c161dd..7a8ccfef3 100644 --- a/build.gradle +++ b/build.gradle @@ -48,11 +48,11 @@ dependencies { android { compileSdkVersion 23 - buildToolsVersion "23.0.1" + buildToolsVersion "23.0.2" defaultConfig { minSdkVersion 14 - targetSdkVersion 21 + targetSdkVersion 23 versionCode 109 versionName "1.8.0" project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName); diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 9f434a626..2f93480e3 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -136,6 +136,9 @@ + + + + + + diff --git a/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java b/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java new file mode 100644 index 000000000..c2a45bf28 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java @@ -0,0 +1,87 @@ +package eu.siacs.conversations.services; + +import android.annotation.TargetApi; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.graphics.drawable.Icon; +import android.os.Build; +import android.os.Bundle; +import android.os.IBinder; +import android.os.SystemClock; +import android.service.chooser.ChooserTarget; +import android.service.chooser.ChooserTargetService; +import android.util.DisplayMetrics; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.ui.ShareWithActivity; + +@TargetApi(Build.VERSION_CODES.M) +public class ContactChooserTargetService extends ChooserTargetService implements ServiceConnection { + + private final Object lock = new Object(); + + private XmppConnectionService mXmppConnectionService; + + private final int MAX_TARGETS = 5; + + @Override + public List onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) { + Intent intent = new Intent(this, XmppConnectionService.class); + intent.setAction("contact_chooser"); + startService(intent); + bindService(intent, this, Context.BIND_AUTO_CREATE); + ArrayList chooserTargets = new ArrayList<>(); + try { + waitForService(); + final ArrayList conversations = new ArrayList<>(); + if (!mXmppConnectionService.areMessagesInitialized()) { + return chooserTargets; + } + mXmppConnectionService.populateWithOrderedConversations(conversations, false); + final ComponentName componentName = new ComponentName(this, ShareWithActivity.class); + final int pixel = (int) (48 * getResources().getDisplayMetrics().density); + for(int i = 0; i < Math.min(conversations.size(),MAX_TARGETS); ++i) { + final Conversation conversation = conversations.get(i); + final String name = conversation.getName(); + final Icon icon = Icon.createWithBitmap(mXmppConnectionService.getAvatarService().get(conversation, pixel)); + final float score = (1.0f / MAX_TARGETS) * i; + final Bundle extras = new Bundle(); + extras.putString("uuid", conversation.getUuid()); + chooserTargets.add(new ChooserTarget(name, icon, score, componentName, extras)); + } + } catch (InterruptedException e) { + } + unbindService(this); + return chooserTargets; + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + XmppConnectionService.XmppConnectionBinder binder = (XmppConnectionService.XmppConnectionBinder) service; + mXmppConnectionService = binder.getService(); + synchronized (this.lock) { + lock.notifyAll(); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mXmppConnectionService = null; + } + + private void waitForService() throws InterruptedException { + if (mXmppConnectionService == null) { + synchronized (this.lock) { + lock.wait(); + } + } + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java index 35f1ff359..3cd2f384f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ShareWithActivity.java @@ -4,6 +4,7 @@ import android.app.PendingIntent; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -17,6 +18,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Conversation; @@ -33,6 +35,7 @@ public class ShareWithActivity extends XmppActivity { public String account; public String contact; public String text; + public String uuid; } private Share share; @@ -40,6 +43,7 @@ public class ShareWithActivity extends XmppActivity { private static final int REQUEST_START_NEW_CONVERSATION = 0x0501; private ListView mListView; private List mConversations = new ArrayList<>(); + private Toast mToast; private UiCallback attachFileCallback = new UiCallback() { @@ -50,8 +54,22 @@ public class ShareWithActivity extends XmppActivity { } @Override - public void success(Message message) { + public void success(final Message message) { xmppConnectionService.sendMessage(message); + runOnUiThread(new Runnable() { + @Override + public void run() { + if (mToast != null) { + mToast.cancel(); + } + if (share.uuid != null) { + mToast = Toast.makeText(getApplicationContext(), + getString(share.image ? R.string.shared_image_with_x : R.string.shared_file_with_x,message.getConversation().getName()), + Toast.LENGTH_SHORT); + mToast.show(); + } + } + }); } @Override @@ -128,6 +146,8 @@ public class ShareWithActivity extends XmppActivity { return; } final String type = intent.getType(); + Log.d(Config.LOGTAG, "action: "+intent.getAction()+ ", type:"+type); + share.uuid = intent.getStringExtra("uuid"); if (Intent.ACTION_SEND.equals(intent.getAction())) { final Uri uri = getIntent().getParcelableExtra(Intent.EXTRA_STREAM); if (type != null && uri != null && !type.equalsIgnoreCase("text/plain")) { @@ -146,7 +166,11 @@ public class ShareWithActivity extends XmppActivity { this.share.uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); } if (xmppConnectionServiceBound) { - xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0); + if (share.uuid != null) { + share(); + } else { + xmppConnectionService.populateWithOrderedConversations(mConversations, this.share.uris.size() == 0); + } } } @@ -163,7 +187,7 @@ public class ShareWithActivity extends XmppActivity { @Override void onBackendConnected() { if (xmppConnectionServiceBound && share != null - && share.contact != null && share.account != null) { + && ((share.contact != null && share.account != null) || share.uuid != null)) { share(); return; } @@ -172,28 +196,41 @@ public class ShareWithActivity extends XmppActivity { } private void share() { - Account account; - try { - account = xmppConnectionService.findAccountByJid(Jid.fromString(share.account)); - } catch (final InvalidJidException e) { - account = null; - } - if (account == null) { - return; - } final Conversation conversation; - try { - conversation = xmppConnectionService - .findOrCreateConversation(account, Jid.fromString(share.contact), false); - } catch (final InvalidJidException e) { - return; + if (share.uuid != null) { + conversation = xmppConnectionService.findConversationByUuid(share.uuid); + if (conversation == null) { + return; + } + }else{ + Account account; + try { + account = xmppConnectionService.findAccountByJid(Jid.fromString(share.account)); + } catch (final InvalidJidException e) { + account = null; + } + if (account == null) { + return; + } + + try { + conversation = xmppConnectionService + .findOrCreateConversation(account, Jid.fromString(share.contact), false); + } catch (final InvalidJidException e) { + return; + } } share(conversation); } private void share(final Conversation conversation) { if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP && !hasPgp()) { - showInstallPgpDialog(); + if (share.uuid == null) { + showInstallPgpDialog(); + } else { + Toast.makeText(this,R.string.openkeychain_not_installed,Toast.LENGTH_SHORT).show(); + finish(); + } return; } if (share.uris.size() != 0) { @@ -201,23 +238,27 @@ public class ShareWithActivity extends XmppActivity { @Override public void onPresenceSelected() { if (share.image) { - Toast.makeText(getApplicationContext(), + mToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_image), - Toast.LENGTH_LONG).show(); + Toast.LENGTH_LONG); + mToast.show(); for (Iterator i = share.uris.iterator(); i.hasNext(); i.remove()) { ShareWithActivity.this.xmppConnectionService .attachImageToConversation(conversation, i.next(), attachFileCallback); } } else { - Toast.makeText(getApplicationContext(), + mToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_file), - Toast.LENGTH_LONG).show(); + Toast.LENGTH_LONG); + mToast.show(); ShareWithActivity.this.xmppConnectionService .attachFileToConversation(conversation, share.uris.get(0), attachFileCallback); } - switchToConversation(conversation, null, true); + if (share.uuid == null) { + switchToConversation(conversation, null, true); + } finish(); } }; diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 584b419f5..ffbb69ce1 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -91,6 +91,7 @@ Conversations utilizes a third party app called OpenKeychain to encrypt and decrypt messages and to manage your public keys.\n\nOpenKeychain is licensed under GPLv3 and available on F-Droid and Google Play.\n\n(Please restart Conversations afterwards.) Restart Install + Please install OpenKeychain offering… waiting… No OpenPGP Key found @@ -554,4 +555,6 @@ %d message %d messages + Shared file with %s + Shared image with %s -- cgit v1.2.3 From c3e8fb3446237dee34bf49436076a10d07e2efdf Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 6 Dec 2015 18:23:59 +0100 Subject: request storage permission when needed on Android 6.0 --- .../conversations/http/HttpDownloadConnection.java | 2 +- .../services/AbstractConnectionManager.java | 11 +++++ .../conversations/ui/ConversationActivity.java | 56 +++++++++++++++++++++- .../conversations/ui/adapter/MessageAdapter.java | 14 +----- .../xmpp/jingle/JingleConnection.java | 3 +- src/main/res/values/strings.xml | 1 + 6 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index f371a2551..b7bea2e13 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -182,7 +182,7 @@ public class HttpDownloadConnection implements Transferable { return; } file.setExpectedSize(size); - if (size <= mHttpConnectionManager.getAutoAcceptFileSize()) { + if (mHttpConnectionManager.hasStoragePermission() && size <= mHttpConnectionManager.getAutoAcceptFileSize()) { HttpDownloadConnection.this.acceptedAutomatically = true; new Thread(new FileDownloader(interactive)).start(); } else { diff --git a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java index 5def05dd4..a12562503 100644 --- a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java @@ -1,6 +1,9 @@ package eu.siacs.conversations.services; +import android.Manifest; import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Build; import android.os.PowerManager; import android.util.Log; import android.util.Pair; @@ -51,6 +54,14 @@ public class AbstractConnectionManager { } } + public boolean hasStoragePermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + return mXmppConnectionService.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; + } else { + return true; + } + } + public static Pair createInputStream(DownloadableFile file, boolean gcm) throws FileNotFoundException { FileInputStream is; int size; diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 6b85410b9..7129da438 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -1,5 +1,6 @@ package eu.siacs.conversations.ui; +import android.Manifest; import android.annotation.SuppressLint; import android.app.ActionBar; import android.app.AlertDialog; @@ -10,6 +11,7 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.IntentSender.SendIntentException; +import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -49,6 +51,7 @@ import eu.siacs.conversations.entities.Blockable; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate; @@ -77,6 +80,7 @@ public class ConversationActivity extends XmppActivity public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207; public static final int REQUEST_TRUST_KEYS_TEXT = 0x0208; public static final int REQUEST_TRUST_KEYS_MENU = 0x0209; + public static final int REQUEST_START_DOWNLOAD = 0x0210; public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301; public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302; public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303; @@ -93,6 +97,7 @@ public class ConversationActivity extends XmppActivity final private List mPendingFileUris = new ArrayList<>(); private Uri mPendingGeoUri = null; private boolean forbidProcessingPendings = false; + private Message mPendingDownloadableMessage = null; private boolean conversationWasSelectedByKeyboard = false; @@ -497,6 +502,11 @@ public class ConversationActivity extends XmppActivity } public void attachFile(final int attachmentChoice) { + if (attachmentChoice != ATTACHMENT_CHOICE_LOCATION) { + if (!hasStoragePermission(attachmentChoice)) { + return; + } + } switch (attachmentChoice) { case ATTACHMENT_CHOICE_LOCATION: getPreferences().edit().putString("recently_used_quick_action","location").apply(); @@ -575,7 +585,51 @@ public class ConversationActivity extends XmppActivity } } + public boolean hasStoragePermission(int attachmentChoice) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, attachmentChoice); + return false; + } else { + return true; + } + } else { + return true; + } + } + @Override + public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { + if (grantResults.length > 0) + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (requestCode == REQUEST_START_DOWNLOAD) { + if (this.mPendingDownloadableMessage != null) { + startDownloadable(this.mPendingDownloadableMessage); + } + } else { + attachFile(requestCode); + } + } else { + Toast.makeText(this,R.string.no_storage_permission,Toast.LENGTH_SHORT).show(); + } + } + + public void startDownloadable(Message message) { + if (!hasStoragePermission(ConversationActivity.REQUEST_START_DOWNLOAD)) { + this.mPendingDownloadableMessage = message; + return; + } + Transferable transferable = message.getTransferable(); + if (transferable != null) { + if (!transferable.start()) { + 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); + } + } + + @Override public boolean onOptionsItemSelected(final MenuItem item) { if (item.getItemId() == android.R.id.home) { showConversationsOverview(); @@ -1176,7 +1230,7 @@ public class ConversationActivity extends XmppActivity if (downloadUuid != null) { final Message message = mSelectedConversation.findMessageWithFileAndUuid(downloadUuid); if (message != null) { - mConversationFragment.messageListAdapter.startDownloadable(message); + startDownloadable(message); } } } 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 f9f6e672b..1d906b294 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -352,7 +352,7 @@ public class MessageAdapter extends ArrayAdapter { @Override public void onClick(View v) { - startDownloadable(message); + activity.startDownloadable(message); } }); viewHolder.download_button.setOnLongClickListener(openContextMenu); @@ -602,18 +602,6 @@ public class MessageAdapter extends ArrayAdapter { return view; } - public void startDownloadable(Message message) { - Transferable transferable = message.getTransferable(); - if (transferable != null) { - if (!transferable.start()) { - Toast.makeText(activity, R.string.not_connected_try_again, - Toast.LENGTH_SHORT).show(); - } - } else if (message.treatAsDownloadable() != Message.Decision.NEVER) { - activity.xmppConnectionService.getHttpConnectionManager().createNewDownloadConnection(message, true); - } - } - public void openDownloadable(Message message) { DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); if (!file.exists()) { 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 59b660c8c..56582f974 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -361,7 +361,8 @@ public class JingleConnection implements Transferable { message.setBody(Long.toString(size)); conversation.add(message); mXmppConnectionService.updateConversationUi(); - if (size < this.mJingleConnectionManager.getAutoAcceptFileSize()) { + if (mJingleConnectionManager.hasStoragePermission() + && size < this.mJingleConnectionManager.getAutoAcceptFileSize()) { Log.d(Config.LOGTAG, "auto accepting file from "+ packet.getFrom()); this.acceptedAutomatically = true; this.sendAccept(); diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index ffbb69ce1..780460400 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -557,4 +557,5 @@ Shared file with %s Shared image with %s + Conversations need access to external storage -- cgit v1.2.3 From 739648e909446c83fe1474636b8465a7ef91cce2 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 7 Dec 2015 00:33:50 +0100 Subject: ask for contact permissions when first opening StartConversationActivity --- .../conversations/persistance/FileBackend.java | 8 ++- .../services/XmppConnectionService.java | 14 ++--- .../ui/StartConversationActivity.java | 63 +++++++++++++++++++--- .../eu/siacs/conversations/utils/PhoneHelper.java | 11 ++++ src/main/res/values/strings.xml | 3 ++ 5 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index febb09705..02b14c7df 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -410,6 +410,8 @@ public class FileBackend { } return cropCenterSquare(input, size); } + } catch (SecurityException e) { + return null; // happens for example on Android 6.0 if contacts permissions get revoked } catch (FileNotFoundException e) { return null; } finally { @@ -424,7 +426,7 @@ public class FileBackend { InputStream is = null; try { BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = calcSampleSize(image,Math.max(newHeight, newWidth)); + options.inSampleSize = calcSampleSize(image, Math.max(newHeight, newWidth)); is = mXmppConnectionService.getContentResolver().openInputStream(image); if (is == null) { return null; @@ -451,6 +453,8 @@ public class FileBackend { source.recycle(); } return dest; + } catch (SecurityException e) { + return null; //android 6.0 with revoked permissions for example } catch (FileNotFoundException e) { return null; } finally { @@ -479,7 +483,7 @@ public class FileBackend { return output; } - private int calcSampleSize(Uri image, int size) throws FileNotFoundException { + private int calcSampleSize(Uri image, int size) throws FileNotFoundException, SecurityException { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(mXmppConnectionService.getContentResolver().openInputStream(image), null, options); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index dbc4825c9..790e035c6 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -468,9 +468,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa break; case ACTION_MERGE_PHONE_CONTACTS: if (mRestoredFromDatabase) { - PhoneHelper.loadPhoneContacts(getApplicationContext(), - new CopyOnWriteArrayList(), - this); + loadPhoneContacts(); } return START_STICKY; case Intent.ACTION_SHUTDOWN: @@ -1097,9 +1095,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } getBitmapCache().evictAll(); Looper.prepare(); - PhoneHelper.loadPhoneContacts(getApplicationContext(), - new CopyOnWriteArrayList(), - XmppConnectionService.this); + loadPhoneContacts(); Log.d(Config.LOGTAG, "restoring messages"); for (Conversation conversation : conversations) { conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE)); @@ -1121,6 +1117,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } } + public void loadPhoneContacts() { + PhoneHelper.loadPhoneContacts(getApplicationContext(), + new CopyOnWriteArrayList(), + XmppConnectionService.this); + } + public List getConversations() { return this.conversations; } diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index df04567f1..f6a386478 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -1,5 +1,6 @@ package eu.siacs.conversations.ui; +import android.Manifest; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.ActionBar; @@ -13,6 +14,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; +import android.content.pm.PackageManager; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NdefRecord; @@ -51,6 +53,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -89,6 +92,9 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU private Invite mPendingInvite = null; private Menu mOptionsMenu; private EditText mSearchEditText; + private AtomicBoolean mRequestedContactsPermission = new AtomicBoolean(false); + private final int REQUEST_SYNC_CONTACTS = 0x3b28cf; + private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() { @Override @@ -245,6 +251,12 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } + @Override + public void onStart() { + super.onStart(); + askForContactsPermissions(); + } + protected void openConversationForContact(int position) { Contact contact = (Contact) contacts.get(position); Conversation conversation = xmppConnectionService @@ -369,7 +381,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU final Jid accountJid; try { if (Config.DOMAIN_LOCK != null) { - accountJid = Jid.fromParts((String) spinner.getSelectedItem(),Config.DOMAIN_LOCK,null); + accountJid = Jid.fromParts((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null); } else { accountJid = Jid.fromString((String) spinner.getSelectedItem()); } @@ -432,7 +444,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU final Jid accountJid; try { if (Config.DOMAIN_LOCK != null) { - accountJid = Jid.fromParts((String) spinner.getSelectedItem(),Config.DOMAIN_LOCK,null); + accountJid = Jid.fromParts((String) spinner.getSelectedItem(), Config.DOMAIN_LOCK, null); } else { accountJid = Jid.fromString((String) spinner.getSelectedItem()); } @@ -447,7 +459,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU return; } final Account account = xmppConnectionService - .findAccountByJid(accountJid); + .findAccountByJid(accountJid); if (account == null) { dialog.dismiss(); return; @@ -456,7 +468,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU if (account.hasBookmarkFor(conferenceJid)) { jid.setError(getString(R.string.bookmark_already_exists)); } else { - final Bookmark bookmark = new Bookmark(account,conferenceJid.toBareJid()); + final Bookmark bookmark = new Bookmark(account, conferenceJid.toBareJid()); bookmark.setAutojoin(true); String nick = conferenceJid.getResourcepart(); if (nick != null && !nick.isEmpty()) { @@ -465,8 +477,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU account.getBookmarks().add(bookmark); xmppConnectionService.pushBookmarks(account); final Conversation conversation = xmppConnectionService - .findOrCreateConversation(account, - conferenceJid, true); + .findOrCreateConversation(account, + conferenceJid, true); conversation.setBookmark(bookmark); if (!conversation.getMucOptions().online()) { xmppConnectionService.joinMuc(conversation); @@ -476,8 +488,8 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU } } else { final Conversation conversation = xmppConnectionService - .findOrCreateConversation(account, - conferenceJid, true); + .findOrCreateConversation(account, + conferenceJid, true); if (!conversation.getMucOptions().online()) { xmppConnectionService.joinMuc(conversation); } @@ -580,6 +592,41 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU super.onActivityResult(requestCode, requestCode, intent); } + private void askForContactsPermissions() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { + if (mRequestedContactsPermission.compareAndSet(false, true)) { + if (shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.sync_with_contacts); + builder.setMessage(R.string.sync_with_contacts_long); + builder.setPositiveButton(R.string.sync_now, new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, REQUEST_SYNC_CONTACTS); + } + } + }); + builder.create().show(); + } else { + requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, 0); + } + } + } + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { + if (grantResults.length > 0) + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (requestCode == REQUEST_SYNC_CONTACTS && xmppConnectionServiceBound) { + xmppConnectionService.loadPhoneContacts(); + } + } + } + @Override protected void onBackendConnected() { this.mActivatedAccounts.clear(); diff --git a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java index a37f60a0f..893f9eb89 100644 --- a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java @@ -1,5 +1,6 @@ package eu.siacs.conversations.utils; +import android.Manifest; import android.content.Context; import android.content.CursorLoader; import android.content.Loader; @@ -7,6 +8,7 @@ import android.content.Loader.OnLoadCompleteListener; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.provider.ContactsContract; import android.provider.ContactsContract.Profile; @@ -17,6 +19,11 @@ import java.util.concurrent.RejectedExecutionException; public class PhoneHelper { public static void loadPhoneContacts(Context context,final List phoneContacts, final OnPhoneContactsLoadedListener listener) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { + listener.onPhoneContactsLoaded(phoneContacts); + return; + } final String[] PROJECTION = new String[] { ContactsContract.Data._ID, ContactsContract.Data.DISPLAY_NAME, ContactsContract.Data.PHOTO_URI, @@ -74,6 +81,10 @@ public class PhoneHelper { } public static Uri getSefliUri(Context context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && context.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { + return null; + } String[] mProjection = new String[] { Profile._ID, Profile.PHOTO_URI }; Cursor mProfileCursor = context.getContentResolver().query( Profile.CONTENT_URI, mProjection, null, null, null); diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 780460400..25af5be12 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -558,4 +558,7 @@ Shared file with %s Shared image with %s Conversations need access to external storage + Synchronize with contacts + Conversations wants to match your XMPP roster with your contacts to show their full names and avatars.\n\nConversations will only read your contacts and match them locally without uploading them to your server. + Synchronize now -- cgit v1.2.3 From ac06cb2e4f8f4d2821265847376e651b08c38e31 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 7 Dec 2015 13:17:06 +0100 Subject: modified contact permission dialog --- src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java | 2 +- src/main/res/values/strings.xml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index f6a386478..caf3d3db8 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -600,7 +600,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(R.string.sync_with_contacts); builder.setMessage(R.string.sync_with_contacts_long); - builder.setPositiveButton(R.string.sync_now, new OnClickListener() { + builder.setPositiveButton(R.string.next, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 25af5be12..d3cda8668 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -559,6 +559,5 @@ Shared image with %s Conversations need access to external storage Synchronize with contacts - Conversations wants to match your XMPP roster with your contacts to show their full names and avatars.\n\nConversations will only read your contacts and match them locally without uploading them to your server. - Synchronize now + Conversations wants to match your XMPP roster with your contacts to show their full names and avatars.\n\nConversations will only read your contacts and match them locally without uploading them to your server.\n\nYou will now be asked to grant permission to access your contacts. -- cgit v1.2.3 From 312387d844e74d4d9dc1ba18121871d4ae16315d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 7 Dec 2015 13:26:01 +0100 Subject: add new build-tools version to travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4a2473ca0..2930c2509 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ android: components: - platform-tools - tools + - build-tools-23.0.2 - build-tools-23.0.1 - build-tools-23.0.0 - build-tools-22.0.1 -- cgit v1.2.3 From b9fc7ebe24eca92ec4d17e057e2643ab83b169fd Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 7 Dec 2015 13:54:59 +0100 Subject: pulled translations from transifex --- src/main/res/values-bg/strings.xml | 42 +++++++++++++++++++++++++++------- src/main/res/values-cs/strings.xml | 27 ++++++++++++++++++++++ src/main/res/values-de/strings.xml | 26 +++++++++++++++++++++ src/main/res/values-es/strings.xml | 32 ++++++++++++++++++++++++++ src/main/res/values-eu/strings.xml | 26 +++++++++++++++++++++ src/main/res/values-ro-rRO/strings.xml | 27 ++++++++++++++++++++++ src/main/res/values-sr/strings.xml | 33 +++++++++++++++++++++++--- src/main/res/values-sv/strings.xml | 32 ++++++++++++++++++++++++++ 8 files changed, 234 insertions(+), 11 deletions(-) diff --git a/src/main/res/values-bg/strings.xml b/src/main/res/values-bg/strings.xml index 9988b9dee..9ac857266 100644 --- a/src/main/res/values-bg/strings.xml +++ b/src/main/res/values-bg/strings.xml @@ -27,7 +27,9 @@ преди 1 минута преди %d минути непрочетени разговори - изпращане... + изпращане… + Дешифроване на съобщението. Моля, изчакайте… + Съобщение, шифр. чрез OpenPGP Псевдонимът вече се използва Администратор Собственик @@ -43,7 +45,7 @@ Искате ли да премахнете отметката за %s? Разговорът, свързан с тази отметка, няма да бъде премахнат. Регистриране на нов профил на сървъра Промяна на паролата в сървъра - Споделяне с... + Споделяне с… Започване на разговор Канене на контакт Контакти @@ -78,6 +80,7 @@ Изпр. на нешифр. съобщение Изпр. на съобщение, шифр. чрез OTP Изпр. на съобщение, шифр. чрез OMEMO + Изпр. на съобщение, шифр. чрез v\\OMEMO Изпр. на съобщение, шифр. чрез OpenPGP Псевдонимът Ви беше променен Изпращане нешифровано @@ -86,17 +89,18 @@ Conversations използва външно приложение с име OpenKeychain, за да шифрова и дешифрова съобщенията и да управлява публичните Ви ключове.\n\nOpenKeychain е лицензирано под условията на GPLv3 и е налично в F-Droid и Google Play.\n\n(Моля, рестартирайте Conversations след това.) Рестартиране Инсталиране - предлагане... - изчакване... + предлагане… + изчакване… Не е открит OpenPGP ключ Conversations не може да шифрова съобщенията Ви, тъй като Вашият контакт не обявява публичния си ключ.\n\nМоля, помолете го/я да инсталира и настрои OpenPGP. Не са открити OpenPGP ключове Conversations не може да шифрова съобщенията Ви, тъй като Вашите контакти не обявяват публичните си ключове.\n\nМоля, помолете го да инсталират и настроят OpenPGP. + Получено е шифровано съобщение. Докоснете, за да го дешифровате. Общи XMPP ресурс Името, с което се определя този клиент Приемане на файлове - Автоматично приемане на файлове с размер, по-малък от... + Автоматично приемане на файлове с размер, по-малък от… Настройки за известията Известия Известяване при получаване на ново съобщение @@ -170,6 +174,7 @@ Паролите са различни Това не е правилен Jabber идентификатор Няма достатъчно памет. Изображението е твърде голямо. + Искате ли да добавите %s към списъка си контакти на устройството си? на линия свободен за разговор отсъстващ @@ -205,10 +210,13 @@ Вашият отпечатък Отпечатък OTR Отпечатък OMEMO + Отпечатък v\\OMEMO Отпечатък OMEMO на съобщението + Отпечатък v\\OMEMO на съобщението Собствен отпечатък OMEMO Други устройства Доверяване на отпечатъци OMEMO + Изтегляне на ключове… Готово Потвърждаване Дешифроване @@ -238,7 +246,7 @@ Публикуване Докоснете аватара, за да изберете изображение от галерията Забележка: Всеки, абониран за актуализации на присъствието Ви, ще може да вижда тази снимка. - Публикуване... + Публикуване… Сървърът отказа Вашето публикуване Нещо се обърка при преобразуването на снимката Ви Неуспешно запазване на аватара на диска @@ -352,7 +360,7 @@ Динамични етикети Показване на етикети, предназначени само за четене под контактите Включване на известията - Започване на беседа с... + Започване на беседа с… Не е открит сървър за беседата Неуспешно създаване на беседа! Беседата беше създадена! @@ -372,7 +380,7 @@ Грешка Получаване на историята от сървъра Няма повече история на сървъра - Актуализиране... + Актуализиране… Паролата е променена! Неуспешна промяна на паролата Изпратете съобщение, за да започнете нешифрован разговор @@ -438,6 +446,7 @@ Предлагане на %s Скриване на тези извън линия Деактивиране на профила + %s пише… %s спря да пише Известия за писането Позволяване на контакта Ви да вижда, когато пишете ново съобщение @@ -480,6 +489,7 @@ Неуспешно сваляне: Неуспешна връзка със сървъра Използване на бял фон Показване на получените съобщения с черен текст на бял фон + Мрежата на TOR не е достъпна Повредено Настройки за присъствието Отсъстващ, когато екранът е изключен @@ -495,4 +505,20 @@ Сертификатът не е потвърден Jabber идентификатора не съответства на сертификата Подновяване на сертификата + Грешка при получаването на ключа за OMEMO! + Ключът за OMEMO беше потвърден със сертификат! + Устройството Ви не поддържа избраните клиентски сертификати! + Настройки за връзката + Свързване през Tor + Всички връзки да минават през мрежата на TOR. Изисква Orbot + Име на сървър + Порт + Адрес на сървър или .onion + Това не е правилен номер на порт + Това не е правилно име на сървър + %1$d от %2$d свързани профила + + %d съобщение + %d съобщения + diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml index eb80a2cec..9bf1c3b7c 100644 --- a/src/main/res/values-cs/strings.xml +++ b/src/main/res/values-cs/strings.xml @@ -28,6 +28,8 @@ před %d minutami nepřečtené konverzace odesílám… + Dešifrování zprávy. Chvíli strpení... + OpenPGP šifrovaná zpráva Přezdívka se již používá Administrátor Vlastník @@ -78,6 +80,7 @@ Odeslat nešifrovanou zprávu Poslat OTR šifrovanou zprávu Poslat OMEMO šifrovanou zprávu + Odeslat v\\OMEMO šifrovanou zprávu Poslat OpenPGP šifrovanou zprávu Přezdívka byla změněna Poslat nešifrované @@ -92,6 +95,7 @@ Není možné zašifrovat zprávu v aplikaci Konverzace, protože druhá strana neoznamuje svůj veřejný klíč.\n\nPožádejte svůj kontakt ať si nastaví OpenPGP. Nebyly nalezeny žádné OpenPGP klíče Není možné zašifrovat zprávy v aplikaci Konverzace, protože kontakty neoznamují svůj veřejný klíč.\n\nPožádejte své kontakty ať si nastaví OpenPGP. + Obdržena šifrovaná zpráva. Dešifrovat dotykem. Obecné XMPP zdroj Jméno se kterým se tento klient identifikuje @@ -170,6 +174,7 @@ Hesla nesouhlasí Toto není platné Jabber ID Nedostatek paměti. Obrázek je příliš velký + Chcete přidat %s do svého seznamu kontaktů v přístroji? online volný pro chat pryč @@ -205,10 +210,13 @@ Váš identifikátor OTR identifikátor OMEMO otisk + v\\OMEMO otisk OMEMO otisk zprávy + v\\OMEMO otisk zprávy Můj OMEMO otisk Ostatní přístroje Věřit OMEMO otiskům + Získávání klíčů... Hotovo Ověřit Dešifrovat @@ -438,6 +446,7 @@ Nabízím %s Skrýt offline Vypnout účet + %s píše... %s přestal(a) psát Upozornění při psaní Oznamovat kontaktům že píšete novou zprávu @@ -482,6 +491,7 @@ Stahování selhalo: Nelze se připojit k hostu Použít bílé pozadí Zobrazovat přijaté zprávy jako černý text na bílém pozadí + TOR síť nedostupná Rozbité Nastavení přítomnosti Pryč při vypnuté obrazovce @@ -497,4 +507,21 @@ Řetězec certifikátů není důvěryhodný Jabber ID neodpovídá certifikátu Obnovit certifikát + Chyba získání OMEMO klíče! + OMEMO klíč ověřen certifikátem! + Tento přístroj nepodporuje výběr klientského certifikátu! + Možnosti připojení + Připojit přes Tor + Posílat všechna spojení pomocí sítě TOR. Vyžaduje Orbot + Hostname + Port + Server- nebo .onion-adresa + Toto není platné číslo portu + Toto není platné hostname + %1$d z %2$d účtů připojeno + + %d zpráva + %d zprávy + %d zpráv + diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index e457c46ca..0ed90f750 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -28,6 +28,8 @@ vor %d Minuten ungelesene Unterhaltungen senden… + Nachricht wird entschlüsselt. Bitte warten … + OpenPGP-verschlüsselte Nachricht Nickname wird bereits verwendet Administrator Eigentümer @@ -78,6 +80,7 @@ Unverschlüsselt schreiben… OTR-verschlüsselt schreiben… OMEMO-verschlüsselt schreiben… + v\\OMEMO-verschlüsselte Nachricht senden OpenPGP-verschlüsselt schreiben… Dein Nickname wurde geändert Unverschlüsselt senden @@ -92,6 +95,7 @@ Conversations ist nicht in der Lage, deine Nachrichten zu verschlüsseln, weil dein Kontakt seinen oder ihren Schlüssel nicht preisgibt.\n\nBitte sag deinem Kontakt, er oder sie möge OpenPGP einrichten. Keine OpenPGP-Schlüssel gefunden Conversations ist nicht in der Lage, deine Nachrichten zu verschlüsseln, weil deine Kontakte ihre Schlüssel nicht preisgeben.\n\nBitte sage deinen Kontakten, sie mögen OpenPGP einrichten. + Verschlüsselte Nachricht erhalten. Drücke hier, um sie zu entschlüsseln. Allgemeines XMPP-Ressource Der Name, mit dem sich der Client selbst identifiziert @@ -170,6 +174,7 @@ Passwörter stimmen nicht überein Ungültige Jabber-ID Zu wenig Speicher vorhanden. Das Bild ist zu groß + Möchtest du %s zum Telefonbuch hinzufügen? online bereit abwesend @@ -205,10 +210,13 @@ Dein Fingerabdruck OTR-Fingerabdruck OMEMO-Fingerabdruck + v\\OMEMO-Fingerabdruck OMEMO-Fingerabdruck der Nachricht + v\\OMEMO-Fingerabdruck der Nachricht Eigener OMEMO-Fingerabdruck Andere Geräte OMEMO-Fingerabdruck vertrauen + Schlüssel empfangen… Erledigt Überprüfen Entschlüsseln @@ -438,6 +446,7 @@ %s wird angeboten Offline verstecken Konto abschalten + %s schreibt… %s schreibt nicht mehr Tipp-Benachrichtigung Informiere deine Kontakte, wenn du eine Nachricht eintippst. @@ -480,6 +489,7 @@ Download fehlgeschlagen: keine Verbindung zum Host Weißen Hintergrund benutzen Empfangene Nachrichten als schwarzen Text auf weißem Hintergrund anzeigen + TOR-Netzwerk nicht verfügbar Fehlerhaft Status Einstellungen Abwesend bei abgeschaltetem Bildschirm @@ -495,4 +505,20 @@ Zertifikat wird nicht vertraut Jabber-ID stimmt nicht dem Zertifikat überein Zertifikat erneuern + Kann OMEMO Schlüssel nicht empfangen! + OMEMO Schlüssel mit Zertifikat bestätigt! + Dein Gerät unterstützt das Auswählen von Client-Zertifikaten nicht! + Verbindungs-Optionen + Mit TOR verbinden + Alle Verbindungen über das TOR-Netzwerk tunneln. Benötigt Orbot + Hostname + Port + Server- oder .onion-Adresse + Dies ist keine gültige Port-Nummer + Dies ist kein gültiger Hostname + %1$d von %2$d Konten verbunden + + %d Nachricht + %d Nachrichten + diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 41e0a6668..598429395 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -28,6 +28,8 @@ hace %d min conversaciones por leer enviando… + Descifrando mensaje. Por favor, espera... + Mensaje cifrado con OpenPGP El apodo ya está en uso Administrador Propietario @@ -78,6 +80,7 @@ Enviar mensaje sin cifrar Enviar mensaje cifrado con OTR Enviar mensaje cifrado con OMEMO + Enviar mensaje cifrado v\\OMEMO Enviar mensaje cifrado con OpenPGP Tu apodo se ha modificado Enviar sin cifrar @@ -86,12 +89,14 @@ Conversations utiliza una aplicación de terceros llamada OpenKeychain para cifrar y descifrar mensajes y gestionar tus claves públicas.\n\nOpenKeychain está publicado bajo licencia GPLv3 y disponible on F-Droid y Google Play.\n\n(Por favor, reinicie Conversations después.) Reiniciar Instalar + Por favor, instala OpenKeyChain ofreciendo… esperando… Clave OpenPGP no encontrada Conversations no ha podido cifrar tus mensajes porque tu contacto no está anunciando su clave publica.\n\nPor favor, pide a tu contacto que configure OpenPGP. Claves OpenPGP no encontradas Conversations no ha podido cifrar tus mensajes porque tus contactos no están anunciando su clave publica.\n\nPor favor, pide a tus contactos que configuren OpenPGP. + Mensaje cifrado recibido. Pulsa para descifrar. General Recurso El nombre que identifica el cliente que estás utilizando @@ -170,6 +175,7 @@ Las contraseñas no coinciden El identificador no es un identificador Jabber válido Sin memoria. La imagen es demasiado grande + ¿Quieres añadir a %s a tu lista de dispositivos? Disponible Hablador Ausente @@ -205,10 +211,13 @@ Tu huella digital Huella digital OTR Huella digital OMEMO + Huella digital v\\OMEMO Huella digital OMEMO del mensaje + huella digital v\\OMEMO del mensaje Tu huella digital OMEMO Otros dispositivos Huellas digitales OMEMO de confianza + Buscando claves... Hecho Verificar Descifrar @@ -438,6 +447,7 @@ Ofreciendo %s Ocultar desconectados Deshabilitar Cuenta + %s está escribiendo... %s ha dejado de escribir Notificación de escritura Permite a tus contactos saber cuando estás escribiendo un nuevo mensaje @@ -480,6 +490,7 @@ Error al descargar: No se ha podido conectar con el servidor Usar fondo blanco Mostrar mensajes recibidos en texto negro con fondo blanco + Red Tor no disponible Error Opciones de presencia Ausente con pantalla apagada @@ -495,4 +506,25 @@ La cadena de certificados no es de confianza El identificador Jabber no coincide con el del certificado Renovar certificado + ¡Error buscando clave OMEMO! + ¡Clave OMEMO con certificado verificada! + ¡Tu dispositivo no soporta la elección de certificados de cliente! + Opciones de conexión + Conectar via Tor + Todas las conexiones se realizan a través de la red TOR. Requiere Orbot + Hostname + Puerto + Server- or .onion-Address + Éste no es un número de puerto válido + Éste no es un hostame válido + %1$d de %2$d cuentas conectadas + + %d mensaje + %d mensajes + + Archivo compartido con %s + Imagen compartida con %s + Conversations necesita acceder al almacenamiento externo + Sincronizar contactos + Conversations quiere cruzar tu lista de contactos de XMPP con tus contactos del móvil para mostrar sus nombres completos y sus fotos de perfil.\n\nConversations solo leerá tus contactos y los cruzará localmente sin subirlos a tu servidor.\n\nEl sistema te preguntará para conceder los permisos de acceso a tus contactos del móvil. diff --git a/src/main/res/values-eu/strings.xml b/src/main/res/values-eu/strings.xml index 28efc8d26..ed01ae56d 100644 --- a/src/main/res/values-eu/strings.xml +++ b/src/main/res/values-eu/strings.xml @@ -28,6 +28,8 @@ %d min lehenago irakurri gabeko elkarrizketak bidaltzen… + Mezua desenkriptatzen. Mesedez itxaron… + OpenPGPz enkriptatutako mezua Ezizena erabilita dagoeneko Administratzailea Jabea @@ -78,6 +80,7 @@ Enkriptatu gabeko mezua bidali OTRz enkriptatutako mezua bidali OMEMOz enkriptatutako mezua bidali + v\\OMEMOz enkriptatutako mezua bidali OpenPGPz enkriptatutako mezua bidali Zure ezizena aldatu da Enkriptatu gabe bidali @@ -92,6 +95,7 @@ Conversations ez da zure mezuak enkriptatzeko gai zure kontaktua bere gako publikoa jakinarazten ez dagoelako.\n\nMesedez eskatu ezaiozu zure kontaktuari openPGP konfigura dezan. Ez da OpenPGP gakorik aurkitu Conversations ez da zure mezuak enkriptatzeko gai zure kontaktuak haien gako publikoa jakinarazten ez daudelako.\n\nMesedez eskatu ezaiezu zure kontakuei OpenPGP konfigura dezaten. + Enkriptatutako mezua jaso da. Ukitu desenkriptatzeko. Orokorrak XMPP baliabidea Bezero honek bere burua aurkezteko erabiltzen duen izena @@ -170,6 +174,7 @@ Pasahitzak ez dute bat egiten Hau ez da Jabber ID baliodun bat Memoriarik gabe. Irudia handiegia da + %s zure gailuko kontaktu zerrendara gehitu nahi al duzu? konektatuta hitzegiteko aske kanpoan @@ -205,10 +210,13 @@ Zure hatz-marka OTR hatz-marka OMEMO hatz-marka + v\\OMEMO hatz-marka Mezuaren OMEMO hatz-marka + Mezuaren v\\OMEMO hatz-marka Norberaren OMEMO hatz-marka Beste gailuak OMEMO hatz-marketaz fidatu + Gakoak eskuratzen... Eginda Egiaztatu Desenkriptatu @@ -438,6 +446,7 @@ %s eskeintzen... Lineaz kanpokoak ezkutatu Kontua ezgaitu + %s idazten ari da... %s(e)k idazteari utzi dio Idazketa jakinarazpenak Zure kontaktuak mezu berri bat noiz idazten ari zaren jakin dezan baimendu @@ -480,6 +489,7 @@ Deskargak huts egin du: ezin izan da ostalarira konektatu Atzeko-planoan kolore zuria erabili Jasotako mezuak testu beltza atzeko-plano zuri baten gainean bezala erakutsi + TOR sarea ez dago eskuragarri Hondatuta Presentzia ezarpenak Urrun pantaila itzalita dagoenean @@ -495,4 +505,20 @@ Ziurtagiriaren katea ez da fidagarria Jabber IDa ez du ziurtagiriarekin bat egiten Ziurtagiria berriztu + Akatsa OMEMO gakoa eskuratzerakoan! + OMEMO gakoa ziurtagiriarekin egiaztatuta! + Zure gailuak ez du bezero ziurtagiriak aukeratzea onartzen! + Konexioaren aukerak + Tor bidez konektatu + Konexio guztiak TOR sarean zehar igaro. Orbot behar du + Ostalariaren izena + Ataka + Zerbitzari- edo .onion-helbidea + Hau ez da ataka zenbaki balioduna + Hau ez da ostalari izen balioduna + %2$dtik %1$d kontu konektatuta + + mezu %d + %d mezu + diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index 33e456710..58e7595dd 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -28,6 +28,8 @@ acum %d minute conversatii necitite trimitere... + Decriptez mesaj. Te rog asteapta... + Mesaj criptat cu OpenPGP Nume utilizator este deja folosit. Administrator Proprietar @@ -78,6 +80,7 @@ Trimite mesaje necriptate Trimite mesaj criptat cu OTR Trimite mesaj criptat cu OMEMO + Trimite mesaj criptat cu v\\OMEMO Trimite mesaj criptat cu OpenPGP Numele tau a fost schimbat Trimite necriptat @@ -92,6 +95,7 @@ Conversations nu a putut sa cripteze mesajele tale din cauza contactului care nu isi anunta cheia publica.\n\nRoaga contactul sa isi configureze OpenPGP. Nu am gasit chei OpenPGP Conversations nu poate cripta mesajele tale pentru contactele tale care nu isi anunta cheia publica.\n\nTe rog cere contactelor sa configureze OpenPGP. + Ai primit mesaj criptat. Apasa aici pentru a-l decripta. General resursa XMPP Numele cu care acest client se identifica @@ -170,6 +174,7 @@ Parolele nu sunt identice Acesta nu este un ID Jabber valabil Memorie epuizata. Imaginea este prea mare. + Vrei sa adaugi pe %s in lista de contacte a dispozitivului? conectat disponibil pentru conversatie plecat @@ -205,10 +210,13 @@ Amprenta ta Amprenta OTR Amprenta OMEMO + Amprenta v\\OMEMO Amprenta OMEMO a mesajului + Amprenta v\\OMEMO a mesajului Amprenta OMEMO proprie Alte dispozitive Amprente OMEMO de incredere + Se preiau cheile... Gata Verifica Decripteaza @@ -438,6 +446,7 @@ Ofer %s Ascunde deconectat Dezactiveaza cont + %s tasteaza... %s s-a oprit din scris Notificari cand cineva scrie Anunta contactul cand scrii un mou mesa @@ -482,6 +491,7 @@ Descarcarea a esuat. Nu s-a putut realiza conexiunea cu gazda. Foloseste un fundal alb Arata mesajele primite cu negru pe fond alb + Retea TOR indisponibila Deteriorat Setari de prezenta Plecat cand ecranul este oprit @@ -497,4 +507,21 @@ Seria de certificate nu este de incredere ID-ul Jabber nu corespunde cu certificatul Innoieste certificatul + Eroare la preluarea cheii OMEMO! + Verifica cheia OMEMO cu un certificat + Dispozitivul nu permite selectia unui certificat pentru client! + Optiuni conexiune + Conectare prin TOR + Toate conexiunile trec prin TOR. Necesita Orbot. + Nume gazda + Port + Adresa server- sau .onion + Acesta nu este un numar de port valabil + Acesta nu este un nume de gazda valabila + %1$d din %2$d conturi conectate + + %d mesaj + %d mesaje + %d mesaje + diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml index 9858950a4..b4d52b120 100644 --- a/src/main/res/values-sr/strings.xml +++ b/src/main/res/values-sr/strings.xml @@ -28,6 +28,8 @@ пре %d минута непрочитане преписке шаљем… + Дешифрујем поруку, сачекајте… + ОпенПГП шифрована порука Надимак је већ у употреби Администратор Власник @@ -62,7 +64,7 @@ Не питај више Не могу да се повежем са налогом Не могу да се повежем са више налога - Додирните овде да бисте управљали вашим налозима + Тапните овде да бисте управљали вашим налозима Приложи фајл Контакт није на вашем списку контаката. Желите ли да га додате? Додај контакт @@ -78,6 +80,7 @@ Пошаљи нешифровану поруку Пошаљи ОТР шифровану поруку Пошаљи ОМЕМО шифровану поруку + Пошаљи v\\ОМЕМО шифровану поруку Пошаљи ОпенПГП шифровану поруку Ваш надимак је промењен Пошаљи нешифровано @@ -92,6 +95,7 @@ Конверзација није могла да шифрује ваше поруке јер ваш контакт не објављује свој јавни кључ.\n\nЗамолите вашег контакта да постави ОпенПГП. Нема ОпенПГП кључева Конверзација није могла да шифрује ваше поруке јер ваши контакти не објављују свој јавни кључ.\n\nЗамолите ваше контакте да поставе ОпенПГП. + Примљена је шифрована порука. Тапните за дешифровање. Опште ИксМПП ресурс Име са којим се овај клијент идентификује @@ -170,6 +174,7 @@ Лозинке се не поклапају Ово није исправан Џабер ИД Нестало меморије. Слика је превелика + Желите ли да додате %s у именик вашег уређаја? на вези слободан за ћаскање одсутан @@ -205,10 +210,13 @@ Ваш отисак ОТР отисак ОМЕМО отисак + v\\ОМЕМО отисак ОМЕМО отисак поруке + v\\ОМЕМО отисак поруке Сопствени ОМЕМО отисак Остали уређаји Поуздај се у ОМЕМО отиске + Добављам кључеве… Готово Овери Дешифруј @@ -236,7 +244,7 @@ Додај га %s је прочитао довде Објави - Додирните аватар да изаберете слику из галерије + Тапните аватар да изаберете слику из галерије Имајте на уму: Свима који су претплаћени на ваше ажурирање присутности биће дозвољено да виде ову слику. Објављујем… Сервер је одбио вашу објаву @@ -432,12 +440,13 @@ Контакт Примљено %s Искључи сервис у првом плану - Додирните да отворите Конверзацију + Тапните да отворите Конверзацију Аватар је објављен! Шаљем %s Нудим %s Сакриј неповезане Искључи налог + %s куца… %s престаде да куца Обавештења о куцању Обзнаните контакту кад куцате нову поруку @@ -482,6 +491,7 @@ Преузимање није успело: не могу да се повежем са домаћином Користи белу позадину Приказ примљених порука црним текстом на белој позадини + Тор мрежа недоступна Оштећен Поставке присутности Одсутан кад је екран искључен @@ -493,4 +503,21 @@ Ланац сертификата није поуздан Џабер ИД не одговара сертификату Обнови сертификат + Грешка добављања ОМЕМО кључа! + Оверен ОМЕМО кључ помоћу сертификата! + Ваш уређај не подржава избор сертификата клијента! + Опције повезивања + Повежи се преко Тора + Тунеловање свих веза кроз Тор мрежу. Захтева Орбот + Име домаћина + Порт + Сервер или .onion адреса + Ово није исправан број порта + Ово није исправно име домаћина + %1$d од %2$d налога повезано + + %d порука + %d поруке + %d порука + diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml index 33868fd4e..725297e9c 100644 --- a/src/main/res/values-sv/strings.xml +++ b/src/main/res/values-sv/strings.xml @@ -28,6 +28,8 @@ %d min sedan olästa konversationer skickar… + Avkrypterar meddelande. Vänta… + OpenPGP-krypterat meddelande Nick används redan Admin Ägare @@ -78,6 +80,7 @@ Skicka okrypterat meddelande Skicka OTR-krypterat meddelande Skicka OMEMO-krypterat meddelande + Skicka v\\OMEMO-krypterat meddelande Skicka OpenPGP-krypterat meddelande Ditt nick har ändrats Skicka okrypterat @@ -86,12 +89,14 @@ Conversations använder en tredjeparts-applikation som heter OpenKeychain för att kryptera och avkryptera meddelanden och hantera dina publika nycklar.\n\nOpenKeychain är licensierad under GPLv3 och tillgänglig på F-Droid och Google Play.\n\n(Starta om Conversations efter installation.) Starta om Installera + Installera OpenKeychain erbjuder… väntar… Ingen OpenPGP-nyckel funnen Conversations kan inte avkryptera ditt meddelande eftersom din kontakt inte annonserar sin publika nyckel.\n\nBe din kontakt att sätta upp OpenPGP. Inga OpenPGP-nycklar funna Conversations kan inte avkryptera ditt meddelande eftersom din kontakt inte annonserar sin publika nyckel.\n\nBe din kontakt att sätta upp OpenPGP. + Krypterat meddelande mottaget. Tryck för att avkryptera. Generellt XMPP resurs Namnet som klienten identifierar sig med @@ -170,6 +175,7 @@ Lösenorden är inte lika Detta är inte ett korrekt Jabber ID Slut på minne. Bilden är för stor + Vill du lägga till %s i din enhets kontaktlista? online tillgänglig borta @@ -205,10 +211,13 @@ Ditt fingeravtryck OTR-fingeravtryck OMEMO-fingeravtryck + v\\OMEMO-fingeravtryck Meddelandets OMEMO-fingeravtryck + Meddelandets v\\OMEMO-fingeravtryck Eget OMEMO-fingeravtryck Andra enheter Lita på OMEMO-fingeravtryck + Hämtar nycklar... Klar Verifiera Avkryptera @@ -438,6 +447,7 @@ Erbjuder %s Dölj ej anslutna Deaktivera konton + %s skriver... %s har slutat skriva Skriv-notifieringar Låter dina kontakter veta när du skriver ett nytt meddelande @@ -480,6 +490,7 @@ Nerladdningen gick fel: Kunder inte ansluta till server Använd vit bakgrund Visa mottagna meddelanden som svart text på vit bakgrund + TOR-nätverk ej tillgängligt Sönder Tillgänglighetsinställningar Status borta när skärmen är av @@ -495,4 +506,25 @@ Certifikatskedjan är inte betrodd Jabber ID matchar inte certifikat Förnya certifikat + Misslyckades med att hämta OMEMO-nyckel! + Verifierade OMEMO-nyckel med certifikat! + Din enhet stödjer inte val av klientcertifikat! + Anslutningsalternativ + Ansluten via TOR + Tunnla alla anslutningar genom TOR-nätverket. Kräver Orbot + Servernamn + Port + Server- eller .onion-adress + Inte ett giltigt portnummer + Inte ett giltigt servernamn + %1$d av %2$d konton anslutna + + %d meddelande + %d meddelanden + + Delade fil med %s + Delade bild med %s + Conversations behöver access till extern lagring + Synkronisera med kontakter + Conversations vill matcha din XMPP-kontaktlista med dina kontakter för att visa deras namn och profilbild.\n\nConversations läser endast dina kontakter för att matcha dem lokalt utan att ladda upp dem till din server.\n\nDu kommer nu få frågan om tillåtelse för att använda kontakterna. -- cgit v1.2.3 From 1de74c2337a97c55180827ea8497f9efca12c24b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 8 Dec 2015 17:15:08 +0100 Subject: also verify sessions in CBE mode that got created by key transport messages --- .../conversations/crypto/axolotl/AxolotlService.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index 2aaadab71..a3dc1357e 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -924,7 +924,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } if (session.isFresh() && plaintextMessage != null) { - sessions.put(session); + putFreshSession(session); } return plaintextMessage; @@ -937,9 +937,21 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { keyTransportMessage = message.getParameters(session, getOwnDeviceId()); if (session.isFresh() && keyTransportMessage != null) { - sessions.put(session); + putFreshSession(session); } return keyTransportMessage; } + + private void putFreshSession(XmppAxolotlSession session) { + sessions.put(session); + if (Config.X509_VERIFICATION) { + IdentityKey identityKey = axolotlStore.loadSession(session.getRemoteAddress()).getSessionState().getRemoteIdentityKey(); + if (identityKey != null) { + verifySessionWithPEP(session, identityKey); + } else { + Log.e(Config.LOGTAG,account.getJid().toBareJid()+": identity key was empty after reloading for x509 verification"); + } + } + } } -- cgit v1.2.3 From aea664a0eca8c6f4c2c7113563d7bb5201787c61 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 9 Dec 2015 10:26:30 +0100 Subject: show sender name for notications in conferences. fixes #1581 --- .../conversations/services/NotificationService.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index b54e54826..03ab6f633 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -276,6 +276,8 @@ public class NotificationService { Message message; if ((message = getImage(messages)) != null) { modifyForImage(mBuilder, message, messages, notify); + } else if (conversation.getMode() == Conversation.MODE_MULTI) { + modifyForConference(mBuilder, conversation, messages, notify); } else { modifyForTextOnly(mBuilder, messages, notify); } @@ -336,6 +338,21 @@ public class NotificationService { } } + private void modifyForConference(Builder builder, Conversation conversation, List messages, boolean notify) { + final Message first = messages.get(0); + final Message last = messages.get(messages.size() - 1); + final NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle(); + style.setBigContentTitle(conversation.getName()); + for(Message message : messages) { + style.addLine(Html.fromHtml(""+UIHelper.getMessageDisplayName(message)+" "+UIHelper.getMessagePreview(mXmppConnectionService,message).first)); + } + builder.setContentText(UIHelper.getMessageDisplayName(first)+ ": " +UIHelper.getMessagePreview(mXmppConnectionService, messages.get(0)).first); + builder.setStyle(style); + if (notify) { + builder.setTicker(UIHelper.getMessageDisplayName(last) + ": " + UIHelper.getMessagePreview(mXmppConnectionService,last).first); + } + } + private Message getImage(final Iterable messages) { for (final Message message : messages) { if (message.getType() != Message.TYPE_TEXT -- cgit v1.2.3 From 11e58607c93f152aad82cfe7951355e03274bf47 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 9 Dec 2015 10:30:26 +0100 Subject: when no avatar found show avatar of contact and not the muc user in conferences --- src/main/java/eu/siacs/conversations/entities/MucOptions.java | 6 +++--- src/main/java/eu/siacs/conversations/parser/PresenceParser.java | 5 ++++- src/main/java/eu/siacs/conversations/services/AvatarService.java | 7 ++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index 853a8408f..014a4c985 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -302,15 +302,15 @@ public class MucOptions { return hasFeature("muc_moderated"); } - public void deleteUser(String name) { + public User deleteUser(String name) { synchronized (this.users) { for (int i = 0; i < users.size(); ++i) { if (users.get(i).getName().equals(name)) { - users.remove(i); - return; + return users.remove(i); } } } + return null; } public void addUser(User user) { diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index b8a2a7e96..d9806dfc7 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -110,7 +110,10 @@ public class PresenceParser extends AbstractParser implements mucOptions.setError(MucOptions.ERROR_UNKNOWN); } } else if (!from.isBareJid()){ - mucOptions.deleteUser(from.getResourcepart()); + MucOptions.User user = mucOptions.deleteUser(from.getResourcepart()); + if (user != null) { + mXmppConnectionService.getAvatarService().clear(user); + } } } else if (type.equals("error")) { Element error = packet.findChild("error"); diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index be320b6b1..276be10d1 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -77,7 +77,12 @@ public class AvatarService { avatar = mXmppConnectionService.getFileBackend().getAvatar(user.getAvatar(), size); } if (avatar == null) { - avatar = get(user.getName(), size, cachedOnly); + Contact contact = user.getContact(); + if (contact != null) { + avatar = get(contact, size, cachedOnly); + } else { + avatar = get(user.getName(), size, cachedOnly); + } } this.mXmppConnectionService.getBitmapCache().put(KEY, avatar); return avatar; -- cgit v1.2.3 From 5e151c7311bed98ce7eafa041735484c32bd7dda Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 9 Dec 2015 11:16:03 +0100 Subject: wait with status change to online after all disco queries have been made --- .../eu/siacs/conversations/xmpp/XmppConnection.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 9ec4d9bbb..7455ff8d3 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -116,6 +116,7 @@ public class XmppConnection implements Runnable { private long lastPingSent = 0; private long lastConnect = 0; private long lastSessionStarted = 0; + private int mPendingServiceDiscoveries = 0; private boolean mInteractive = false; private int attempt = 0; private final Hashtable> packetCallbacks = new Hashtable<>(); @@ -926,18 +927,16 @@ public class XmppConnection implements Runnable { synchronized (this.disco) { this.disco.clear(); } + mPendingServiceDiscoveries = 0; + sendServiceDiscoveryItems(account.getServer()); sendServiceDiscoveryInfo(account.getServer()); sendServiceDiscoveryInfo(account.getJid().toBareJid()); - sendServiceDiscoveryItems(account.getServer()); Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource()); this.lastSessionStarted = SystemClock.elapsedRealtime(); - changeStatus(Account.State.ONLINE); - if (bindListener != null) { - bindListener.onBind(account); - } } private void sendServiceDiscoveryInfo(final Jid jid) { + mPendingServiceDiscoveries++; final IqPacket iq = new IqPacket(IqPacket.TYPE.GET); iq.setTo(jid); iq.query("http://jabber.org/protocol/disco#info"); @@ -988,6 +987,16 @@ public class XmppConnection implements Runnable { } else { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not query disco info for " + jid.toString()); } + if (packet.getType() != IqPacket.TYPE.TIMEOUT) { + mPendingServiceDiscoveries--; + if (mPendingServiceDiscoveries <= 0) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": done with service discovery"); + changeStatus(Account.State.ONLINE); + if (bindListener != null) { + bindListener.onBind(account); + } + } + } } }); } -- cgit v1.2.3 From 5bd70cfee8d3a71cce5bfb0a1a3e3330091333a6 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 9 Dec 2015 12:18:06 +0100 Subject: always show conversations with pending subscription requests --- src/main/java/eu/siacs/conversations/parser/PresenceParser.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index d9806dfc7..d27182c19 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -200,10 +200,12 @@ public class PresenceParser extends AbstractParser implements mPresenceGenerator.sendPresenceUpdatesTo(contact)); } else { contact.setOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST); + final Conversation conversation = mXmppConnectionService.findOrCreateConversation( + account, contact.getJid().toBareJid(), false); final String statusMessage = packet.findChildContent("status"); - if (statusMessage != null && !statusMessage.isEmpty()) { - final Conversation conversation = mXmppConnectionService.findOrCreateConversation( - account, contact.getJid().toBareJid(), false); + if (statusMessage != null + && !statusMessage.isEmpty() + && conversation.countMessages() == 0) { conversation.add(new Message( conversation, statusMessage, -- cgit v1.2.3 From ede92235d79459dc2cb12e22f25dbca86f884193 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 10 Dec 2015 18:26:31 +0100 Subject: disable sm logging --- src/main/java/eu/siacs/conversations/Config.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index c56767aff..0b336ed39 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -2,10 +2,6 @@ package eu.siacs.conversations; import android.graphics.Bitmap; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Proxy; - import eu.siacs.conversations.xmpp.chatstate.ChatState; public final class Config { @@ -46,7 +42,7 @@ public final class Config { public static final boolean DISABLE_PROXY_LOOKUP = false; //useful to debug ibb public static final boolean DISABLE_HTTP_UPLOAD = false; public static final boolean DISABLE_STRING_PREP = false; // setting to true might increase startup performance - public static final boolean EXTENDED_SM_LOGGING = true; // log stanza counts + public static final boolean EXTENDED_SM_LOGGING = false; // log stanza counts public static final boolean RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE = true; //setting to true might increase power consumption public static final boolean ENCRYPT_ON_HTTP_UPLOADED = false; -- cgit v1.2.3 From 2262921ff41f3e1b2108c4ab075bfbda27fe090f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 10 Dec 2015 18:28:47 +0100 Subject: properly clean up timed out mam queries --- .../eu/siacs/conversations/parser/MessageParser.java | 2 +- .../conversations/services/MessageArchiveService.java | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 6baefac54..2c536f69d 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -425,7 +425,7 @@ public class MessageParser extends AbstractParser implements mXmppConnectionService.sendMessagePacket(account, receipt); } } - if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().advancedStreamFeaturesLoaded()) { + if (account.isOnlineAndConnected() && query == null) { if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) { mXmppConnectionService.updateConversation(conversation); } diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index ae81cc17f..f6d3a2fa3 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -35,7 +35,15 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.mXmppConnectionService = service; } - public void catchup(final Account account) { + private void catchup(final Account account) { + synchronized (this.queries) { + for(Iterator iterator = this.queries.iterator(); iterator.hasNext();) { + Query query = iterator.next(); + if (query.getAccount() == account) { + iterator.remove(); + } + } + } long startCatchup = getLastMessageTransmitted(account); long endCatchup = account.getXmppConnection().getLastSessionEstablished(); if (startCatchup == 0) { @@ -131,7 +139,14 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { this.mXmppConnectionService.sendIqPacket(account, packet, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { - if (packet.getType() != IqPacket.TYPE.RESULT) { + if (packet.getType() == IqPacket.TYPE.TIMEOUT) { + synchronized (MessageArchiveService.this.queries) { + MessageArchiveService.this.queries.remove(query); + if (query.hasCallback()) { + query.callback(); + } + } + } else if (packet.getType() != IqPacket.TYPE.RESULT) { Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": error executing mam: " + packet.toString()); finalizeQuery(query); } -- cgit v1.2.3 From 55c1129a651b1191273bbf8e49783a4798580375 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 10 Dec 2015 23:05:11 +0100 Subject: notify on mam catchup messages --- .../eu/siacs/conversations/parser/MessageParser.java | 20 +++++++++++++++----- .../services/MessageArchiveService.java | 3 +++ .../conversations/services/NotificationService.java | 4 ++-- .../services/XmppConnectionService.java | 2 +- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 2c536f69d..80886f7ff 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -397,15 +397,21 @@ public class MessageParser extends AbstractParser implements } conversation.add(message); - if (query != null) { - query.incrementMessageCount(); - } else { + + if (query == null || query.getWith() == null) { //either no mam or catchup if (status == Message.STATUS_SEND || status == Message.STATUS_SEND_RECEIVED) { mXmppConnectionService.markRead(conversation); - account.activateGracePeriod(); + if (query == null) { + account.activateGracePeriod(); + } } else { message.markUnread(); } + } + + if (query != null) { + query.incrementMessageCount(); + } else { mXmppConnectionService.updateConversationUi(); } @@ -445,7 +451,11 @@ public class MessageParser extends AbstractParser implements if (message.trusted() && message.treatAsDownloadable() != Message.Decision.NEVER && manager.getAutoAcceptFileSize() > 0) { manager.createNewDownloadConnection(message); } else if (!message.isRead()) { - mXmppConnectionService.getNotificationService().push(message); + if (query == null) { + mXmppConnectionService.getNotificationService().push(message); + } else if (query.getWith() == null) { // mam catchup + mXmppConnectionService.getNotificationService().pushFromBacklog(message); + } } } else { //no body if (isTypeGroupChat) { diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index f6d3a2fa3..8847cfcd5 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -218,6 +218,9 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { if (complete || relevant == null || abort) { this.finalizeQuery(query); Log.d(Config.LOGTAG,query.getAccount().getJid().toBareJid().toString()+": finished mam after "+query.getTotalCount()+" messages"); + if (query.getWith() == null && query.getTotalCount() > 0) { + mXmppConnectionService.getNotificationService().finishBacklog(true); + } } else { final Query nextQuery; if (query.getPagingOrder() == PagingOrder.NORMAL) { diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 03ab6f633..e8dec8154 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -119,10 +119,10 @@ public class NotificationService { } } - public void finishBacklog() { + public void finishBacklog(boolean notify) { synchronized (notifications) { mXmppConnectionService.updateUnreadCountBadge(); - updateNotification(false); + updateNotification(notify); } } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 790e035c6..1a0153e51 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -1107,7 +1107,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } }); } - mNotificationService.finishBacklog(); + mNotificationService.finishBacklog(false); mRestoredFromDatabase = true; Log.d(Config.LOGTAG, "restored all messages"); updateConversationUi(); -- cgit v1.2.3 From 15f220747f33b351d10e2b1c736f1e26601c7eeb Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 10 Dec 2015 23:16:33 +0100 Subject: some more NPE checks --- src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java index a3dc1357e..e22b05c00 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -72,7 +72,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { @Override public void onAdvancedStreamFeaturesAvailable(Account account) { - if (account.getXmppConnection().getFeatures().pep()) { + if (account.getXmppConnection() != null && account.getXmppConnection().getFeatures().pep()) { publishBundlesIfNeeded(true, false); } else { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": skipping OMEMO initialization"); -- cgit v1.2.3 From 4cae283cff3db1b8b49adaa2f21aa36226621a75 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 10 Dec 2015 23:17:11 +0100 Subject: version bump to 1.8.1 and changelog --- CHANGELOG.md | 6 ++++++ build.gradle | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65f06ce4d..bfd685fa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ ###Changelog +####Version 1.8.1 +* enabled direct share on Android 6.0 +* ask for permissions on Android 6.0 +* notify on MAM catchup messages +* bug fixes + ####Version 1.8.0 * TOR/ORBOT support in advanced settings * show vcard avatars of participants in a conference diff --git a/build.gradle b/build.gradle index 7a8ccfef3..8af500beb 100644 --- a/build.gradle +++ b/build.gradle @@ -53,8 +53,8 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 23 - versionCode 109 - versionName "1.8.0" + versionCode 110 + versionName "1.8.1" project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName); } -- cgit v1.2.3 From 5ffb87059ca1fc53769d8f489ff926d6a3f766f2 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 10 Dec 2015 23:37:38 +0100 Subject: renamed pretty-please-store message hint to store --- src/main/java/eu/siacs/conversations/generator/MessageGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index 9c847d0e0..b1a0d99d0 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -65,7 +65,7 @@ public class MessageGenerator extends AbstractGenerator { return null; } packet.setAxolotlMessage(axolotlMessage.toElement()); - packet.addChild("pretty-please-store", "urn:xmpp:hints"); + packet.addChild("store", "urn:xmpp:hints"); return packet; } -- cgit v1.2.3 From 61b068110983c279fa31b9a1062b76dd6ae38416 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 11 Dec 2015 13:27:33 +0100 Subject: pulled translations from transifex --- src/main/res/values-ru/strings.xml | 28 ++++++++++++++++++++++++++++ src/main/res/values-sr/strings.xml | 12 ++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml index 968d4f045..0cd253923 100644 --- a/src/main/res/values-ru/strings.xml +++ b/src/main/res/values-ru/strings.xml @@ -28,6 +28,8 @@ %d мин. назад непрочитанных сообщений отправка… + Расшифровка сообщения. Подождите... + OpenPGP зашифрованное сообщение Имя уже используется Администратор Владелец @@ -78,6 +80,7 @@ Отправить незащифрованное сообщение Отправить OTR защифрованное сообщение Отправить OMEMO защифрованное сообщение + Послать v\\OMEMO зашифрованное сообщение Отправить OpenPGP защифрованное сообщение Ваш псевдоним был изменен Отправить в незашифрованном виде @@ -86,12 +89,14 @@ Conversations использует стороннее приложение под названием OpenKeychain для шифрования и расшифрования сообщений и управления открытыми ключами.\nПрограмма OpenKeychain распространяется под лицензией GPLv3 и доступна для загрузки через F-Droid или Google Play.\n\n(Потребуется перезапуск Conversations после установки.) Перезапуск Установка + Установите OpenKeychain пожалуйста предложение… ожидание… Нет OpenPGP ключа Conversations не может зашифровать сообщение, потому что удаленный пользователь не анонсирует свой открытый ключ.\n\nПожалуйста, попросите удаленного пользователя тоже установить OpenPGP. Нет OpenPGP ключей Conversations не может зашифровать сообщения, потому что удаленные пользователи не анонсируют свои открытые ключи.\n\nПожалуйста, попросите удаленных пользователей тоже установить OpenPGP. + Получено зашифрованное сообщение. Нажмите, чтобы расшифровать. Общие Название ресурса Имя которым Conversations идентифицирует себя @@ -170,6 +175,7 @@ Пароли не совпадают Недопустимый JID (Джаббер ID) Недостаточно памяти. Изображение слишком большое + Вы хотите добавить %s в список контактов устройства? в сети свободен для общения скоро буду @@ -205,10 +211,13 @@ Контрольная сумма OTR контрольная сумма OMEMO отпечаток + v\\OMEMO отпечаток OMEMO отпечаток сообщения + v\\OMEMO отпечаток сообщения Собственный OMEMO отпечаток Другие устройства Доверенные отпечатки OMEMO + Получение ключей… Готово Подтвердить Дешифровать @@ -438,6 +447,7 @@ Предложен %s Скрыть пользователей вне сети Отключить учётную запись + %s печатает… %s прекратил набор Оповещения о наборе Позволяет вашим контактам видеть когда вы пишете новое сообщение @@ -484,6 +494,7 @@ Загрузка не удалась: не удалось подключиться к серверу Использовать белый фон Показывать принятые сообщения черным текстом на белом фоне + Сеть TOR недоступна Повреждено Настройки присутствия Вышел когда экран выключен @@ -499,4 +510,21 @@ Цепочка сертификата не доверена Jabber ID не соответствует сертификату Обновить сертификат + Ошибка при получении OMEMO ключа! + Проверен OMEMO ключ с сертификатом! + Ваше устройство не поддерживает выбор клиентских сертификатов! + Настройки соединения + Соединение через Tor + Направить все соединения через сеть TOR. Требуется Orbot + Имя сервера + Порт + Сервер- или .onion-Адрес + Это недопустимый номер порта + Это недопустимое имя сервера + %1$d из %2$d аккаунтов соединены + Общий файл с %s + Общее изображение с %s + Conversations требуется доступ к внешнему хранилищу + Синхронизировать с контактами + Conversations ожидает совпадения вашего XMPP ростера с вашими контактами для отображения их полных имен и аватаров.\n\nConversations только считает ваши контакты и сопоставит их локально без отправки их на ваш сервер.\n\nСейчас вы получите запрос на разрешение доступа к вашим контактам. diff --git a/src/main/res/values-sr/strings.xml b/src/main/res/values-sr/strings.xml index b4d52b120..3b64ea795 100644 --- a/src/main/res/values-sr/strings.xml +++ b/src/main/res/values-sr/strings.xml @@ -19,7 +19,7 @@ Поставке Детаљи групног ћаскања Детаљи контакта - Подели са преписком + Подели у преписци Почни преписку Изабери контакт Списак блокираних @@ -45,7 +45,7 @@ Желите ли да уклоните %s са обележивача? Преписка са овим контактом неће бити уклоњена. Региструј нови налог на серверу Промени лозинку на серверу - Подели са… + Подели помоћу… Почни преписку Позови контакта Контакти @@ -89,6 +89,7 @@ Конверзација користи апликацију Отворени кључарник за шифровање и дешифровање порука и управљање вашим јавним кључевима.\n\nОтворени кључарник је лиценциран под ГПЛв3 и доступан је на Ф-дроиду у Гугловој Плеј продавници.\n\n(Поново покрените Конверзацију након тога.) Поново покрени Инсталирај + Инсталирајте Отворени кључарник нудим… чекам… Нема ОпенПГП кључа @@ -499,6 +500,9 @@ Недоступан у тихом режиму Означава ваш ресурс недоступним кад је телефон у тихом режиму Не могу да рашчланим сертификат + Оставите празно за аутентификацију сертификатом + Текст стопке + Потребна стопка унесите текст са слике Ланац сертификата није поуздан Џабер ИД не одговара сертификату @@ -520,4 +524,8 @@ %d поруке %d порука + Подељен фајл са %s + Подељена слика са %s + Конверзацији је потребан приступ спољашњем складишту + Синхронизуј са контактима -- cgit v1.2.3 From 293e820a5857ffff5301babc43fc08120a35385c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 11 Dec 2015 13:52:04 +0100 Subject: get rid of lastMessageTransmitted in favor of db query --- .../siacs/conversations/entities/Conversation.java | 30 +++++----------------- .../siacs/conversations/parser/MessageParser.java | 7 +---- .../conversations/persistance/DatabaseBackend.java | 14 ++++++++++ .../services/MessageArchiveService.java | 29 ++++++--------------- .../services/XmppConnectionService.java | 4 --- 5 files changed, 29 insertions(+), 55 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index e93d5564b..8b7aa8949 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -46,7 +46,6 @@ public class Conversation extends AbstractEntity implements Blockable { public static final String ATTRIBUTE_NEXT_ENCRYPTION = "next_encryption"; public static final String ATTRIBUTE_MUC_PASSWORD = "muc_password"; public static final String ATTRIBUTE_MUTED_TILL = "muted_till"; - public static final String ATTRIBUTE_LAST_MESSAGE_TRANSMITTED = "last_message_transmitted"; private String name; private String contactUuid; @@ -693,33 +692,16 @@ public class Conversation extends AbstractEntity implements Blockable { } } - public void resetLastMessageTransmitted() { - this.setAttribute(ATTRIBUTE_LAST_MESSAGE_TRANSMITTED,String.valueOf(-1)); - } - - public boolean setLastMessageTransmitted(long value) { - long before = getLastMessageTransmitted(); - if (value - before > 1000) { - this.setAttribute(ATTRIBUTE_LAST_MESSAGE_TRANSMITTED, String.valueOf(value)); - return true; - } else { - return false; - } - } - public long getLastMessageTransmitted() { - long timestamp = getLongAttribute(ATTRIBUTE_LAST_MESSAGE_TRANSMITTED,0); - if (timestamp == 0) { - synchronized (this.messages) { - for(int i = this.messages.size() - 1; i >= 0; --i) { - Message message = this.messages.get(i); - if (message.getStatus() == Message.STATUS_RECEIVED) { - return message.getTimeSent(); - } + synchronized (this.messages) { + for(int i = this.messages.size() - 1; i >= 0; --i) { + Message message = this.messages.get(i); + if (message.getStatus() == Message.STATUS_RECEIVED || message.isCarbon()) { + return message.getTimeSent(); } } } - return timestamp; + return 0; } public void setMutedTill(long value) { diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 80886f7ff..49c3134cf 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -329,7 +329,7 @@ public class MessageParser extends AbstractParser implements } if ((body != null || pgpEncrypted != null || axolotlEncrypted != null) && !isMucStatusMessage) { - Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.toBareJid(), isTypeGroupChat); + Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.toBareJid(), isTypeGroupChat, query); if (isTypeGroupChat) { if (counterpart.getResourcepart().equals(conversation.getMucOptions().getActualNick())) { status = Message.STATUS_SEND_RECEIVED; @@ -431,11 +431,6 @@ public class MessageParser extends AbstractParser implements mXmppConnectionService.sendMessagePacket(account, receipt); } } - if (account.isOnlineAndConnected() && query == null) { - if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) { - mXmppConnectionService.updateConversation(conversation); - } - } if (message.getStatus() == Message.STATUS_RECEIVED && conversation.getOtrSession() != null diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 2347c3188..e482f0f85 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -9,6 +9,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Base64; import android.util.Log; +import android.util.Pair; import org.whispersystems.libaxolotl.AxolotlAddress; import org.whispersystems.libaxolotl.IdentityKey; @@ -591,6 +592,19 @@ public class DatabaseBackend extends SQLiteOpenHelper { db.delete(Message.TABLENAME, Message.CONVERSATION + "=?", args); } + public Pair getLastMessageReceived(Account account) { + SQLiteDatabase db = this.getReadableDatabase(); + String sql = "select messages.timeSent,messages.serverMsgId from accounts join conversations on accounts.uuid=conversations.accountUuid join messages on conversations.uuid=messages.conversationUuid where accounts.uuid=? and (messages.status=0 or messages.carbon=1 or messages.serverMsgId not null) order by messages.timesent desc limit 1"; + String[] args = {account.getUuid()}; + Cursor cursor = db.rawQuery(sql,args); + if (cursor.getCount() ==0) { + return null; + } else { + cursor.moveToFirst(); + return new Pair<>(cursor.getLong(0),cursor.getString(1)); + } + } + public Conversation findConversationByUuid(String conversationUuid) { SQLiteDatabase db = this.getReadableDatabase(); String[] selectionArgs = {conversationUuid}; diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 8847cfcd5..13261951b 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.services; import android.util.Log; +import android.util.Pair; import java.math.BigInteger; import java.util.ArrayList; @@ -75,16 +76,8 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { } private long getLastMessageTransmitted(final Account account) { - long timestamp = 0; - for(final Conversation conversation : mXmppConnectionService.getConversations()) { - if (conversation.getAccount() == account) { - long tmp = conversation.getLastMessageTransmitted(); - if (tmp > timestamp) { - timestamp = tmp; - } - } - } - return timestamp; + Pair pair = mXmppConnectionService.databaseBackend.getLastMessageReceived(account); + return pair == null ? 0 : pair.first; } public Query query(final Conversation conversation) { @@ -166,25 +159,19 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { final Conversation conversation = query.getConversation(); if (conversation != null) { conversation.sort(); - if (conversation.setLastMessageTransmitted(query.getEnd())) { - this.mXmppConnectionService.databaseBackend.updateConversation(conversation); - } conversation.setHasMessagesLeftOnServer(query.getMessageCount() > 0); - if (query.hasCallback()) { - query.callback(); - } else { - this.mXmppConnectionService.updateConversationUi(); - } } else { for(Conversation tmp : this.mXmppConnectionService.getConversations()) { if (tmp.getAccount() == query.getAccount()) { tmp.sort(); - if (tmp.setLastMessageTransmitted(query.getEnd())) { - this.mXmppConnectionService.databaseBackend.updateConversation(tmp); - } } } } + if (query.hasCallback()) { + query.callback(); + } else { + this.mXmppConnectionService.updateConversationUi(); + } } public boolean queryInProgress(Conversation conversation, XmppConnectionService.OnMoreMessagesLoaded callback) { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 1a0153e51..cb193167a 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -221,9 +221,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa Message message = conversation.findUnsentMessageWithUuid(uuid); if (message != null) { markMessage(message, Message.STATUS_SEND); - if (conversation.setLastMessageTransmitted(System.currentTimeMillis())) { - databaseBackend.updateConversation(conversation); - } } } } @@ -2883,7 +2880,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public void clearConversationHistory(final Conversation conversation) { conversation.clearMessages(); conversation.setHasMessagesLeftOnServer(false); //avoid messages getting loaded through mam - conversation.resetLastMessageTransmitted(); Runnable runnable = new Runnable() { @Override public void run() { -- cgit v1.2.3 From b2c278c91bc2a733dcb807d7eb7f0d3e7145d9c2 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 11 Dec 2015 19:28:44 +0100 Subject: set bookmark name to room subject if no subject has been set before --- src/main/java/eu/siacs/conversations/entities/Bookmark.java | 10 ++++++++++ .../java/eu/siacs/conversations/parser/MessageParser.java | 12 ++++++++++-- .../siacs/conversations/services/XmppConnectionService.java | 3 ++- .../eu/siacs/conversations/ui/ConferenceDetailsActivity.java | 1 + 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index 0210da245..acb4bf1a3 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -138,6 +138,16 @@ public class Bookmark extends Element implements ListItem { return this.getAttribute("name"); } + public boolean setBookmarkName(String name) { + String before = getBookmarkName(); + if (name != null && !name.equals(before)) { + this.setAttribute("name", name); + return true; + } else { + return false; + } + } + public void unregisterConversation() { if (this.mJoinedConversation != null) { this.mJoinedConversation.deregisterWithBookmark(); diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 49c3134cf..d8190b707 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -14,6 +14,7 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; @@ -387,7 +388,7 @@ public class MessageParser extends AbstractParser implements message.setType(Message.TYPE_PRIVATE); } } - updateLastseen(packet,account,true); + updateLastseen(packet, account, true); boolean checkForDuplicates = query != null || (isTypeGroupChat && packet.hasChild("delay","urn:xmpp:delay")) || message.getType() == Message.TYPE_PRIVATE; @@ -458,7 +459,14 @@ public class MessageParser extends AbstractParser implements if (packet.hasChild("subject")) { if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) { conversation.setHasMessagesLeftOnServer(conversation.countMessages() > 0); - conversation.getMucOptions().setSubject(packet.findChildContent("subject")); + String subject = packet.findChildContent("subject"); + conversation.getMucOptions().setSubject(subject); + final Bookmark bookmark = conversation.getBookmark(); + if (bookmark != null && bookmark.getBookmarkName() == null) { + if (bookmark.setBookmarkName(subject)) { + mXmppConnectionService.pushBookmarks(account); + } + } mXmppConnectionService.updateConversationUi(); return; } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index cb193167a..3be56b042 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -250,9 +250,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa account.getRoster().clearPresences(); fetchRosterFromServer(account); fetchBookmarks(account); + mMessageArchiveService.executePendingQueries(account); sendPresence(account); connectMultiModeConversations(account); - mMessageArchiveService.executePendingQueries(account); mJingleConnectionManager.cancelInTransmission(); syncDirtyContacts(account); } @@ -1015,6 +1015,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public void pushBookmarks(Account account) { + Log.d(Config.LOGTAG, account.getJid().toBareJid()+": pushing bookmarks"); IqPacket iqPacket = new IqPacket(IqPacket.TYPE.SET); Element query = iqPacket.query("jabber:iq:private"); Element storage = query.addChild("storage", "storage:bookmarks"); diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index adae79168..b3de28b38 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -420,6 +420,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers if (!mConversation.getJid().isBareJid()) { bookmark.setNick(mConversation.getJid().getResourcepart()); } + bookmark.setBookmarkName(mConversation.getMucOptions().getSubject()); bookmark.setAutojoin(true); account.getBookmarks().add(bookmark); xmppConnectionService.pushBookmarks(account); -- cgit v1.2.3 From a1ac4fd66594b8d79523819f427945f5b3f0c6da Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 11 Dec 2015 20:33:41 +0100 Subject: fix cancelation of http downloads and enable resume --- .../conversations/http/HttpDownloadConnection.java | 43 ++++++++++++++++++---- .../services/AbstractConnectionManager.java | 10 ++++- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index b7bea2e13..455a0b14b 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -16,6 +16,7 @@ import java.net.MalformedURLException; import java.net.Proxy; import java.net.URL; import java.util.Arrays; +import java.util.concurrent.CancellationException; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLHandshakeException; @@ -43,6 +44,7 @@ public class HttpDownloadConnection implements Transferable { private boolean acceptedAutomatically = false; private int mProgress = 0; private boolean mUseTor = false; + private boolean canceled = false; public HttpDownloadConnection(HttpConnectionManager manager) { this.mHttpConnectionManager = manager; @@ -114,7 +116,9 @@ public class HttpDownloadConnection implements Transferable { new Thread(new FileSizeChecker(interactive)).start(); } + @Override public void cancel() { + this.canceled = true; mHttpConnectionManager.finishConnection(this); if (message.isFileOrImage()) { message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); @@ -150,7 +154,7 @@ public class HttpDownloadConnection implements Transferable { 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 { + } else if (!(e instanceof CancellationException)) { mXmppConnectionService.showErrorToastInUi(R.string.download_failed_file_not_found); } } @@ -244,7 +248,7 @@ public class HttpDownloadConnection implements Transferable { finish(); } catch (SSLHandshakeException e) { changeStatus(STATUS_OFFER); - } catch (IOException e) { + } catch (Exception e) { if (interactive) { showToastForException(e); } @@ -252,7 +256,7 @@ public class HttpDownloadConnection implements Transferable { } } - private void download() throws IOException { + private void download() throws Exception { InputStream is = null; PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_download_"+message.getUuid()); try { @@ -267,24 +271,47 @@ public class HttpDownloadConnection implements Transferable { mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive); } connection.setRequestProperty("User-Agent",mXmppConnectionService.getIqGenerator().getIdentityName()); + final boolean tryResume = file.exists() && file.getKey() == null; + if (tryResume) { + Log.d(Config.LOGTAG,"http download trying resume"); + long size = file.getSize(); + connection.setRequestProperty("Range", "bytes="+size+"-"); + } connection.connect(); is = new BufferedInputStream(connection.getInputStream()); - file.getParentFile().mkdirs(); - file.createNewFile(); - os = AbstractConnectionManager.createOutputStream(file, true); + boolean serverResumed = "bytes".equals(connection.getHeaderField("Accept-Ranges")); long transmitted = 0; long expected = file.getExpectedSize(); + if (tryResume && serverResumed) { + Log.d(Config.LOGTAG,"server resumed"); + transmitted = file.getSize(); + updateProgress((int) ((((double) transmitted) / expected) * 100)); + os = AbstractConnectionManager.createAppendedOutputStream(file); + } else { + file.getParentFile().mkdirs(); + file.createNewFile(); + os = AbstractConnectionManager.createOutputStream(file, true); + } 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)); + if (canceled) { + throw new CancellationException(); + } } - os.flush(); - } catch (IOException e) { + } catch (CancellationException | IOException e) { throw e; } finally { + if (os != null) { + try { + os.flush(); + } catch (final IOException ignored) { + + } + } FileBackend.close(os); FileBackend.close(is); wakeLock.release(); diff --git a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java index a12562503..8d02f975a 100644 --- a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java @@ -95,10 +95,18 @@ public class AbstractConnectionManager { } } + public static OutputStream createAppendedOutputStream(DownloadableFile file) { + return createOutputStream(file, false, true); + } + public static OutputStream createOutputStream(DownloadableFile file, boolean gcm) { + return createOutputStream(file, gcm, false); + } + + private static OutputStream createOutputStream(DownloadableFile file, boolean gcm, boolean append) { FileOutputStream os; try { - os = new FileOutputStream(file); + os = new FileOutputStream(file, append); if (file.getKey() == null) { return os; } -- cgit v1.2.3 From 5e79e94e776026438e8dea56c19fb89aef84eb9d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 11 Dec 2015 20:37:52 +0100 Subject: bump version code --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 8af500beb..97c382818 100644 --- a/build.gradle +++ b/build.gradle @@ -53,7 +53,7 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 23 - versionCode 110 + versionCode 111 versionName "1.8.1" project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName); } -- cgit v1.2.3 From 5e4b55a0ff446431b5b5d5c4b3d70e8898815844 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 11 Dec 2015 20:43:50 +0100 Subject: notfiy after mam catchup only if message count > 0 --- .../java/eu/siacs/conversations/services/MessageArchiveService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java index 13261951b..4403f99cd 100644 --- a/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java +++ b/src/main/java/eu/siacs/conversations/services/MessageArchiveService.java @@ -205,7 +205,7 @@ public class MessageArchiveService implements OnAdvancedStreamFeaturesLoaded { if (complete || relevant == null || abort) { this.finalizeQuery(query); Log.d(Config.LOGTAG,query.getAccount().getJid().toBareJid().toString()+": finished mam after "+query.getTotalCount()+" messages"); - if (query.getWith() == null && query.getTotalCount() > 0) { + if (query.getWith() == null && query.getMessageCount() > 0) { mXmppConnectionService.getNotificationService().finishBacklog(true); } } else { -- cgit v1.2.3 From 88523bbb5073867be3faeed27d4b7def1263205b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 12 Dec 2015 15:58:22 +0100 Subject: more detailed logging --- src/main/java/eu/siacs/conversations/parser/IqParser.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index e26a493f5..1761e0df1 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -117,8 +117,7 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { Integer id = Integer.valueOf(device.getAttribute("id")); deviceIds.add(id); } catch (NumberFormatException e) { - Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Encountered nvalid node in PEP:" + device.toString() - + ", skipping..."); + Log.e(Config.LOGTAG, AxolotlService.LOGPREFIX+" : "+"Encountered invalid node in PEP ("+e.getMessage()+"):" + device.toString()+ ", skipping..."); continue; } } -- cgit v1.2.3 From 50817956c2c0c855cb75b97d6a0078a58bfd6d36 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 12 Dec 2015 16:01:33 +0100 Subject: changed order of send presence and execute mam queries --- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 3be56b042..9ecdf6ae8 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -248,12 +248,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa @Override public void onBind(final Account account) { account.getRoster().clearPresences(); + mJingleConnectionManager.cancelInTransmission(); fetchRosterFromServer(account); fetchBookmarks(account); - mMessageArchiveService.executePendingQueries(account); sendPresence(account); + mMessageArchiveService.executePendingQueries(account); connectMultiModeConversations(account); - mJingleConnectionManager.cancelInTransmission(); syncDirtyContacts(account); } }; -- cgit v1.2.3 From b0a314411f6e9c37ee602bc771f4a14b22335900 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 13 Dec 2015 11:06:56 +0100 Subject: version code bump and tagging 1.8.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 97c382818..3a6d19796 100644 --- a/build.gradle +++ b/build.gradle @@ -53,7 +53,7 @@ android { defaultConfig { minSdkVersion 14 targetSdkVersion 23 - versionCode 111 + versionCode 112 versionName "1.8.1" project.ext.set(archivesBaseName, archivesBaseName + "-" + versionName); } -- cgit v1.2.3 From aa472a0098ab1420d90376ca5fa2821bd1b5d15d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 13 Dec 2015 11:09:42 +0100 Subject: pulled translations from transifex --- src/main/res/values-iw/strings.xml | 39 ++++++++++++++++++++++++------ src/main/res/values-ja/strings.xml | 31 ++++++++++++++++++++++++ src/main/res/values-zh-rCN/strings.xml | 43 ++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 7 deletions(-) diff --git a/src/main/res/values-iw/strings.xml b/src/main/res/values-iw/strings.xml index fe25a42c0..83741ae34 100644 --- a/src/main/res/values-iw/strings.xml +++ b/src/main/res/values-iw/strings.xml @@ -28,6 +28,8 @@ לפני %d דקות שיחות שלא נקראו שולח... + כעת מפענח צופן הודעה. אנא המתן… + הודעה מוצפנת OpenPGP שם כינוי כבר בשימוש מנהל בעלים @@ -86,12 +88,14 @@ Conversations מסתמכת על אפליקציית צד-שלישי הקרויה OpenKeychain כדי להצפין ולפענח הודעות וגם כדי לנהל את המפתחות הפומביים שלך.\n\nOpenKeychain הינה רשויה תחת GPLv3 וזמינה ב F-Droid וגם ב Google Play.\n\n(אנא התחל מחדש את Conversations לאחר מכן.) התחל מחדש התקן + אנא התקן OpenKeychain מציע… ממתין… לא נמצא מפתח OpenPGP Conversations אינה מסוגלת להצפין את הודעותיך משום שאיש הקשר שלך אינו מכריז על המפתח הפומבי שלו או שלה.\n\nאנא בקש מאיש הקשר שלך להגדיר את OpenPGP. לא נמצאו מפתחות OpenPGP Conversations אינה מסוגלת להצפין את הודעותיך משום שאנשי הקשר שלך אינם מכריזים על המפתח הפומבי שלהם.\n\nאנא בקש מאנשי הקשר שלך לארגן OpenPGP. + הודעה מוצפנת תנקבלה. גע כדי לפענח צופן. כללי משאב XMPP השם שבעזרתו לקוח זה מזהה את עצמו @@ -128,7 +132,7 @@ בקש עדכוני נוכחות בחר תמונה צלם תמונה - הענק בקשת הרשמה מראש + הענק מראש בקשת הרשמה הקובץ שבחרת אינו תמונה שגיאה במהלך המרת תמונה קובץ לא נמצא @@ -170,6 +174,7 @@ סיסמאות לא תואמות מזהה ה Jabber אינו תקין חסר זיכרון. תצלום גדול מדי + האם ברצונך להוסיף את %s לתוך רשימת הקשר של המכשיר שלך? מקוון חופשי לשיחה נעדר @@ -434,6 +439,7 @@ מציע %s הסתר בלתי מקוונים השבת חשבון + %s מקליד/ה כעת… %s הפסיק/ה להקליד התראות הקלדה אפשר לאנשי הקשר שלך לדעת כאשר אתה מקליד הודעה חדשה @@ -476,19 +482,38 @@ ההורדה נכשלה: נכשל ביצוע חיבור לשרת השתמש ברקע לבן הראה הודעות שהתקבלו בטקסט שחור על גבי רקע לבען + רשת TOR לא זמינה לא עובד הגדרות נוכחות Presence העבר למצב \"לא נמצא\" כאשר המסך כבוי מעביר את המכשיר לסטטוס \"לא נמצא\" כאשר המסך כבוי העבר למצב \"לא זמין\" כאשר במצב שקט מעביר את המכשיר לסטטוס \"לא זמין\" כאשר הפלאפון נמצא במצב שקט. - הוסף חשבון עם certificate - תקלה בקריאת ה- certificate - השאר ריק כדי להזדהות ללא certificate + הוסף חשבון עם תעודה + תקלה בפענוח תעודה + השאר ריק כדי להזדהות בלי תעודה טקסט Captcha דרוש טקסט Captcha - נא להזין את הטקסט שבתמונה + אנא הזן את הטקסט מתוך התמונה שרשרת תעודה אינה מהימנה - אין התאמה בין ה- JID לבין ה- certificate - חידוש certificate + אין התאמה בין מזהה Jabber לבין תעודה + חידוש תעודה + שגיאה בתפיסת OMEMO! + אפשרוית חיבור + התחבר דרך Tor + שם מארח + פורט + שרת- או כתובת onion. + זהו אינו מספר פורט תקין + זהו אינו שם מארח תקין + %1$d מתוך %2$d חשבונות מחוברים + + הודעה %d + %d הודעות + + שתף קובץ בעזרת %s + שתף תמונה בעזרת %s + ‏Conversations זקוקה לגישה לאחסון חיצוני + סנכרן עם אנשי קשר + ‏Conversations מבקשת להתאים את רשימת XMPP שלך עם אנשי הקשר שלך כדי להציג את השמות המלאים שלהם כולל אווטארים.\n\nConversations רק תקרא את אנשי הקשר שלך ותתאים אותם באופן מקומי מבלי להעלות אותם לשרת שלך.\n\nכעת אתה תתבקש להעניק הרשאה כדי לגשת להתקן שלך. diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml index 4679c6b32..307d21d37 100644 --- a/src/main/res/values-ja/strings.xml +++ b/src/main/res/values-ja/strings.xml @@ -28,6 +28,8 @@ %d 分前 未読の会話 送信中… + メッセージを復号化しています。しばらくお待ちください… + OpenPGP 暗号化メッセージ ニックネームは既に使用されています 管理者 オーナー @@ -78,6 +80,7 @@ 暗号化されていないメッセージを送信 OTR 暗号化メッセージを送信 OMEMO 暗号化メッセージを送信 + v\\OMEMO 暗号化メッセージを送信 OpenPGP 暗号化メッセージを送信 あなたのニックネームが変更されました 暗号化されていない送信 @@ -86,12 +89,14 @@ Conversations は OpenKeychain と呼ばれるサードパーティのアプリを利用して、メッセージの暗号化および復号化、そしてあなたの公開鍵を管理します。\n\nOpenKeychain は GPLv3 ライセンスの下で、F-Droid および Google Play から利用可能です。\n\n(後で Conversations を再起動してください。) 再起動 インストール + OpenKeychain をインストールしてください 依頼中… 待機中… OpenPGP の鍵はありません 連絡先が公開鍵を通知しないため、Conversations はあなたのメッセージを暗号化することができません。\n\n連絡先に OpenPGP をセットアップするように依頼してください。 OpenPGP の鍵はありません 連絡先が公開鍵を通知しないため、Conversations はあなたのメッセージを暗号化することができません。\n\n連絡先に OpenPGP をセットアップするように依頼してください。 + 暗号化されたメッセージを受信しました。タッチすると復号化します。 全般 XMPP リソース 自分自身を識別するこのクライアントの名前 @@ -170,6 +175,7 @@ パスワードが一致しません これは有効な Jabber ID ではありません メモリ不足です。画像が大きすぎます + お使いのデバイスの連絡先リストに %s を追加しますか? オンライン 自由にチャットできます 離席中 @@ -205,10 +211,13 @@ あなたのフィンガープリント OTR フィンガープリント OMEMO フィンガープリント + v\\OMEMO フィンガープリント メッセージの OMEMO フィンガープリント + メッセージの v\\OMEMO フィンガープリント 自分の OMEMO フィンガープリント 他のデバイス OMEMO フィンガープリントを信頼 + 鍵の取得中… 完了 検証 復号化 @@ -438,6 +447,7 @@ %s の依頼中 オフラインを非表示にする アカウントを無効にする + %s は入力中… %s は入力を停止しました 入力中通知 あなたが新しいメッセージを書いている時に、連絡先に知らせます @@ -478,6 +488,7 @@ ダウンロードに失敗しました: ホストに接続できませんでした 白い背景を使用する 白地に黒の文字で、受け取ったメッセージを表示します + TOR ネットワークは利用できません 壊れています 参加設定 画面がオフのときは離席 @@ -493,4 +504,24 @@ 証明書チェーンは信頼済ではありません Jabber ID が証明書と一致しません 証明書を更新 + OMEMO 鍵の取得中にエラー! + OMEMO 鍵の取得中にエラー! + お使いのデバイスはクライアント証明書の選択をサポートしていません! + 接続オプション + Tor 経由で接続 + TOR ネットワークを介してすべての接続をトンネルします。 Orbot が必要です + ホスト名 + ポート + サーバーまたは .onion アドレス + これは有効なポート番号ではありません + これは有効なホスト名ではありません + %1$d / %2$d アカウントが接続しました + + %d メッセージ + + %s でファイルを共有 + %s で画像を共有 + Conversations は外部ストレージにアクセスが必要です + 連絡先と同期 + Conversations はフルネームやアバターを表示するために、連絡先と XMPP 名簿と一致するようにしたいです。\n\nConversations は、サーバーにアップロードすることはなく、ローカルで連絡先を読んで一致させるだけです。\n\n今、連絡先へのアクセス許可を付与するように求められます。 diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index 908394541..87a6e5d9b 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -28,6 +28,8 @@ %d分钟前 未读会话 正在发送… + 解密信息中. 请稍候… + OpenPGP 加密的信息 该名称已存在 管理员 所有者 @@ -73,10 +75,12 @@ 清除会话记录 删除该会话中所有信息?\n\n注: 该操作不会影响其他设备或服务器保存的信息。 删除消息 + 结束此会话以后 添加在线用户至联系人 发送未加密的信息 发送 OTR 加密信息 发送 OMEMO 加密信息 + 发送 v\\OMEMO 加密信息 发送 OpenPGP 加密信息 昵称修改成功 不加密发送 @@ -85,12 +89,14 @@ Conversations 使用了第三方app OpenKeychain 来加密、解密信息并管理您的密钥。\n\nOpenKeychain 遵循 GPLv3 并且可以在 F-Droid 和 Google Play 上获取。\n\n(之后请重启 Conversations) 重启 安装 + 请安装 OpenKeychain 以解密 输入… 等待… 未发现 OpenPGP 密钥 Conversations 无法加密信息,因为联系人未提供他/她的公钥。\n\n请通知联系人设置 OpenPGP。 未找到 OpenPGP 密钥 因您的联系人未公布公钥,Conversations未能成功加密您的信息.\n\n请通知联系人设置OpenPGP. + 接收到加密消息。轻触以解密。 常规 XMPP 资源 客户端标识名称 @@ -103,6 +109,8 @@ 收到新消息时震动 声音 收到新消息时的铃声 + 公共讨论组内通知 + 收到公共讨论组消息时总是通知,而不是仅在高亮时通知 通知限期 接收副本短时间内关闭通知 高级选项 @@ -167,6 +175,7 @@ 密码不一致 该 Jabber ID 无效 空间不足。图片过大 + 你想把 %s 加到你设备的联系人列表吗? 在线 自由畅聊 离开 @@ -177,9 +186,12 @@ 其他成员 服务器信息 XEP-0313: MAM + XEP-0280: 消息复写 XEP-0352: 客户端状态指示 XEP-0191: 屏蔽指令 + XEP-0237: 花名册版本控制 XEP-0198: 流管理 + XEP-0163: PEP (替身 / OMEMO) XEP-0363: HTTP 文件上传 有效 无效 @@ -199,9 +211,13 @@ 你的指纹 OTR 指纹 OMEMO 指纹 + v\\OMEMO 指纹 消息的 OMEMO 指纹 + 消息的 OMEMO 指纹 + 自己的 OMEMO 指纹 其他设备 信任的 OMEMO 指纹 + 获取密钥中 完成 验证 解密 @@ -357,8 +373,10 @@ 重新生成 OMEMO 密钥 从 PEP 中清除其他设备 清除设备 + 你想清除所有其他设备的 OMEMO 通告?下次你的设备连接,将会重新收到通告,但也许将不会收到当时你发送的消息。 清除密钥 是否确认清除该密钥? + 这是不可逆的损坏,你不能用此再建立一个会话了。 他们没有密钥可用于此次会话。如果你曾经清除过他们的密钥,那么他们需要生成新的密钥。 错误 从服务器获取历史记录 @@ -400,6 +418,7 @@ 讨论组选项 私密,只有成员可以加入 非匿名 + 版主 您尚未参与 讨论组选项已修改! 不能修改讨论组选项 @@ -428,6 +447,7 @@ 提供中 %s 隐藏离线联系人 禁用账户 + %s 正在输入 %s 已停止输入 键盘输入通知 让对方知道你正在输入新消息 @@ -468,17 +488,40 @@ 下载失败:无法连接到服务器 使用白色背景 收到的消息将显示为白底黑字 + TOR 网络不可用 损坏 + 上线设置 关闭屏幕时离开 当屏幕关闭时将标记您的资源为离开状态 静音模式时不可用 当设备处于静音模式时将标记您的资源为不可用状态 使用证书添加账户 无法解析证书 + 留空以认证 w/ 证书 验证码 需要验证码 输入图片中的文字 证书链不受信任 Jabber ID 与证书不匹配 更新证书 + 获取 OMEMO 密钥错误! + 请用证书验证 OMEMO 密钥! + 您的设备不支持设备证书选择! + 连接选项 + 通过 Tor 连接 + 所有连接使用 TOR 网络隧道。需要 Orbot + 主机名 + 端口 + 服务器 - 或者 .orion 地址 + 该端口号无效 + 该主机名无效 + %2$d 个中的 %1$d 个账户已连接 + + %d 条消息 + + 用 %s 分享文件 + 用 %s 分享图片 + Conversations 需要访问外部存储 + 与联系人同步 + Conversations 会匹配你的 XMPP 花名册与你的联系人,以显示他们的全名和头像。\n\nConversations 只会读取你的联系人并在本地匹配,不会上传到你的服务器。\n\n现在将要询问你是否给予访问你联系人的权限。 -- cgit v1.2.3 From 042939e44d2d98c669b1dc5414f7f8353e9cde27 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 14 Dec 2015 10:44:43 +0100 Subject: make message text non-selectable. fixes #1606 --- src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java | 3 --- 1 file changed, 3 deletions(-) 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 1d906b294..fd2e5751b 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -244,7 +244,6 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.messageBody.setText(text); viewHolder.messageBody.setTextColor(getMessageTextColor(darkBackground, false)); viewHolder.messageBody.setTypeface(null, Typeface.ITALIC); - viewHolder.messageBody.setTextIsSelectable(false); } private void displayDecryptionFailed(ViewHolder viewHolder, boolean darkBackground) { @@ -257,7 +256,6 @@ public class MessageAdapter extends ArrayAdapter { R.string.decryption_failed)); viewHolder.messageBody.setTextColor(getMessageTextColor(darkBackground, false)); viewHolder.messageBody.setTypeface(null, Typeface.NORMAL); - viewHolder.messageBody.setTextIsSelectable(false); } private void displayHeartMessage(final ViewHolder viewHolder, final String body) { @@ -339,7 +337,6 @@ public class MessageAdapter extends ArrayAdapter { viewHolder.messageBody.setLinkTextColor(this.getMessageTextColor(darkBackground, true)); viewHolder.messageBody.setHighlightColor(activity.getResources().getColor(darkBackground ? R.color.grey800 : R.color.grey500)); viewHolder.messageBody.setTypeface(null, Typeface.NORMAL); - viewHolder.messageBody.setTextIsSelectable(true); } private void displayDownloadableMessage(ViewHolder viewHolder, -- cgit v1.2.3 From f6b22dad2032453bd2e1157488b142af1a86d413 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 14 Dec 2015 10:54:55 +0100 Subject: splite PARANOIA_MODE into three different options --- src/main/java/eu/siacs/conversations/Config.java | 4 +++- src/main/java/eu/siacs/conversations/entities/Conversation.java | 2 +- .../java/eu/siacs/conversations/services/NotificationService.java | 4 ++-- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 2 +- src/main/java/eu/siacs/conversations/ui/ConversationActivity.java | 2 +- src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 2 +- src/main/java/eu/siacs/conversations/ui/SettingsActivity.java | 2 +- 7 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 0b336ed39..1bb8028af 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -12,7 +12,9 @@ public final class Config { public static final String DOMAIN_LOCK = null; //only allow account creation for this domain public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox public static final boolean HIDE_PGP_IN_UI = false; //some more consumer focused clients might want to disable OpenPGP - public static final boolean PARANOID_MODE = false; //disables ability to send unencrypted 1-on-1 chats and forces TOR + public static final boolean FORCE_ENCRYPTION = true; //disables ability to send unencrypted 1-on-1 + public static final boolean FORCE_ORBOT = false; // always use TOR + public static final boolean HIDE_MESSAGE_TEXT_IN_NOTIFICATION = false; public static final boolean SHOW_CONNECTED_ACCOUNTS = false; //show number of connected accounts in foreground notification public static final boolean LEGACY_NAMESPACE_HTTP_UPLOAD = false; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 8b7aa8949..a085f0c03 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -616,7 +616,7 @@ public class Conversation extends AbstractEntity implements Blockable { next = outgoing; } } - if (Config.PARANOID_MODE && mode == MODE_SINGLE && next <= 0) { + if (Config.FORCE_ENCRYPTION && mode == MODE_SINGLE && next <= 0) { if (getAccount().getAxolotlService().isContactAxolotlCapable(getContact())) { return Message.ENCRYPTION_AXOLOTL; } else { diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index e8dec8154..624c0a604 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -234,7 +234,7 @@ public class NotificationService { if (messages.size() > 0) { conversation = messages.get(0).getConversation(); final String name = conversation.getName(); - if (Config.PARANOID_MODE) { + if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) { int count = messages.size(); style.addLine(Html.fromHtml(""+name+" "+mXmppConnectionService.getResources().getQuantityString(R.plurals.x_messages,count,count))); } else { @@ -269,7 +269,7 @@ public class NotificationService { mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService() .get(conversation, getPixel(64))); mBuilder.setContentTitle(conversation.getName()); - if (Config.PARANOID_MODE) { + if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) { int count = messages.size(); mBuilder.setContentText(mXmppConnectionService.getResources().getQuantityString(R.plurals.x_messages,count,count)); } else { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 9ecdf6ae8..0addbfd43 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2568,7 +2568,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } public boolean useTorToConnect() { - return Config.PARANOID_MODE || getPreferences().getBoolean("use_tor", false); + return Config.FORCE_ORBOT || getPreferences().getBoolean("use_tor", false); } public int unreadCount() { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 7129da438..688ee95cc 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -869,7 +869,7 @@ public class ConversationActivity extends XmppActivity MenuItem pgp = popup.getMenu().findItem(R.id.encryption_choice_pgp); MenuItem axolotl = popup.getMenu().findItem(R.id.encryption_choice_axolotl); pgp.setVisible(!Config.HIDE_PGP_IN_UI); - none.setVisible(!Config.PARANOID_MODE); + none.setVisible(!Config.FORCE_ENCRYPTION); if (conversation.getMode() == Conversation.MODE_MULTI) { otr.setVisible(false); axolotl.setVisible(false); diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index fc8b36fea..a6c459968 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -491,7 +491,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } } } - this.mUseTor = Config.PARANOID_MODE || getPreferences().getBoolean("use_tor", false); + this.mUseTor = Config.FORCE_ORBOT || getPreferences().getBoolean("use_tor", false); this.mNamePort.setVisibility(mUseTor ? View.VISIBLE : View.GONE); } diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index da9738ab5..aa23e36db 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -61,7 +61,7 @@ public class SettingsActivity extends XmppActivity implements } } - if (Config.PARANOID_MODE) { + if (Config.FORCE_ORBOT) { PreferenceCategory connectionOptions = (PreferenceCategory) mSettingsFragment.findPreference("connection_options"); PreferenceScreen expert = (PreferenceScreen) mSettingsFragment.findPreference("expert"); if (connectionOptions != null) { -- cgit v1.2.3 From 85f36e9dbc416d0644bcc0e1f7d3790124786579 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 14 Dec 2015 10:58:55 +0100 Subject: default force encryption to false --- src/main/java/eu/siacs/conversations/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 1bb8028af..8b76ba90c 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -12,7 +12,7 @@ public final class Config { public static final String DOMAIN_LOCK = null; //only allow account creation for this domain public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox public static final boolean HIDE_PGP_IN_UI = false; //some more consumer focused clients might want to disable OpenPGP - public static final boolean FORCE_ENCRYPTION = true; //disables ability to send unencrypted 1-on-1 + public static final boolean FORCE_ENCRYPTION = false; //disables ability to send unencrypted 1-on-1 public static final boolean FORCE_ORBOT = false; // always use TOR public static final boolean HIDE_MESSAGE_TEXT_IN_NOTIFICATION = false; public static final boolean SHOW_CONNECTED_ACCOUNTS = false; //show number of connected accounts in foreground notification -- cgit v1.2.3 From 43dd681239ea5a287f5761597de5dcdc4daed3de Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 15 Dec 2015 19:14:38 +0100 Subject: timeout service discovery after 20s --- src/main/java/eu/siacs/conversations/Config.java | 1 + .../services/XmppConnectionService.java | 12 ++++-- .../siacs/conversations/xmpp/XmppConnection.java | 49 ++++++++++++++++++---- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 8b76ba90c..b1534a7ab 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -24,6 +24,7 @@ public final class Config { public static final int PING_TIMEOUT = 15; public static final int SOCKET_TIMEOUT = 15; public static final int CONNECT_TIMEOUT = 90; + public static final int CONNECT_DISCO_TIMEOUT = 20; public static final int CARBON_GRACE_PERIOD = 90; public static final int MINI_GRACE_PERIOD = 750; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 0addbfd43..649ddacd8 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -547,12 +547,18 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } else if (account.getStatus() == Account.State.OFFLINE) { reconnectAccount(account, true, interactive); } else if (account.getStatus() == Account.State.CONNECTING) { - long timeout = Config.CONNECT_TIMEOUT - ((SystemClock.elapsedRealtime() - account.getXmppConnection().getLastConnect()) / 1000); + long secondsSinceLastConnect = (SystemClock.elapsedRealtime() - account.getXmppConnection().getLastConnect()) / 1000; + long secondsSinceLastDisco = (SystemClock.elapsedRealtime() - account.getXmppConnection().getLastDiscoStarted()) / 1000; + long discoTimeout = Config.CONNECT_DISCO_TIMEOUT - secondsSinceLastDisco; + long timeout = Config.CONNECT_TIMEOUT - secondsSinceLastConnect; if (timeout < 0) { Log.d(Config.LOGTAG, account.getJid() + ": time out during connect reconnecting"); reconnectAccount(account, true, interactive); + } else if (discoTimeout < 0) { + account.getXmppConnection().sendDiscoTimeout(); + scheduleWakeUpCall((int) Math.min(timeout,discoTimeout), account.getUuid().hashCode()); } else { - scheduleWakeUpCall((int) timeout, account.getUuid().hashCode()); + scheduleWakeUpCall((int) Math.min(timeout,discoTimeout), account.getUuid().hashCode()); } } else { if (account.getXmppConnection().getTimeToNextAttempt() <= 0) { @@ -748,7 +754,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa stopSelf(); } - protected void scheduleWakeUpCall(int seconds, int requestCode) { + public void scheduleWakeUpCall(int seconds, int requestCode) { final long timeToWake = SystemClock.elapsedRealtime() + (seconds < 0 ? 1 : seconds + 1) * 1000; Context context = getApplicationContext(); diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 7455ff8d3..efb670726 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -116,7 +116,9 @@ public class XmppConnection implements Runnable { private long lastPingSent = 0; private long lastConnect = 0; private long lastSessionStarted = 0; + private long lastDiscoStarted = 0; private int mPendingServiceDiscoveries = 0; + private final ArrayList mPendingServiceDiscoveriesIds = new ArrayList<>(); private boolean mInteractive = false; private int attempt = 0; private final Hashtable> packetCallbacks = new Hashtable<>(); @@ -225,6 +227,7 @@ public class XmppConnection implements Runnable { features.encryptionEnabled = false; lastConnect = SystemClock.elapsedRealtime(); lastPingSent = SystemClock.elapsedRealtime(); + lastDiscoStarted = Long.MAX_VALUE; this.attempt++; if (account.getJid().getDomainpart().equals("chat.facebook.com")) { mServerIdentity = Identity.FACEBOOK; @@ -893,6 +896,29 @@ public class XmppConnection implements Runnable { Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": done clearing iq callbacks. " + this.packetCallbacks.size() + " left"); } + public void sendDiscoTimeout() { + final IqPacket failurePacket = new IqPacket(IqPacket.TYPE.ERROR); //don't use timeout + final ArrayList callbacks = new ArrayList<>(); + synchronized (this.mPendingServiceDiscoveriesIds) { + for(String id : mPendingServiceDiscoveriesIds) { + synchronized (this.packetCallbacks) { + Pair pair = this.packetCallbacks.remove(id); + if (pair != null) { + callbacks.add(pair.second); + } + } + } + this.mPendingServiceDiscoveriesIds.clear(); + } + if (callbacks.size() > 0) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": sending disco timeout"); + resetStreamId(); //we don't want to live with this for ever + } + for(OnIqPacketReceived callback : callbacks) { + callback.onIqPacketReceived(account,failurePacket); + } + } + private void sendStartSession() { final IqPacket startSession = new IqPacket(IqPacket.TYPE.SET); startSession.addChild("session", "urn:ietf:params:xml:ns:xmpp-session"); @@ -928,10 +954,12 @@ public class XmppConnection implements Runnable { this.disco.clear(); } mPendingServiceDiscoveries = 0; + lastDiscoStarted = SystemClock.elapsedRealtime(); + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": starting service discovery"); + mXmppConnectionService.scheduleWakeUpCall(Config.CONNECT_DISCO_TIMEOUT, account.getUuid().hashCode()); sendServiceDiscoveryItems(account.getServer()); sendServiceDiscoveryInfo(account.getServer()); sendServiceDiscoveryInfo(account.getJid().toBareJid()); - Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource()); this.lastSessionStarted = SystemClock.elapsedRealtime(); } @@ -940,7 +968,7 @@ public class XmppConnection implements Runnable { final IqPacket iq = new IqPacket(IqPacket.TYPE.GET); iq.setTo(jid); iq.query("http://jabber.org/protocol/disco#info"); - this.sendIqPacket(iq, new OnIqPacketReceived() { + String id = this.sendIqPacket(iq, new OnIqPacketReceived() { @Override public void onIqPacketReceived(final Account account, final IqPacket packet) { @@ -991,6 +1019,7 @@ public class XmppConnection implements Runnable { mPendingServiceDiscoveries--; if (mPendingServiceDiscoveries <= 0) { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": done with service discovery"); + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource()); changeStatus(Account.State.ONLINE); if (bindListener != null) { bindListener.onBind(account); @@ -999,6 +1028,9 @@ public class XmppConnection implements Runnable { } } }); + synchronized (this.mPendingServiceDiscoveriesIds) { + this.mPendingServiceDiscoveriesIds.add(id); + } } private void enableAdvancedStreamFeatures() { @@ -1033,7 +1065,7 @@ public class XmppConnection implements Runnable { } } } else { - Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not query disco items of "+server); + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": could not query disco items of " + server); } } }); @@ -1086,13 +1118,12 @@ public class XmppConnection implements Runnable { return new BigInteger(50, mXmppConnectionService.getRNG()).toString(32); } - public void sendIqPacket(final IqPacket packet, final OnIqPacketReceived callback) { + public String sendIqPacket(final IqPacket packet, final OnIqPacketReceived callback) { packet.setFrom(account.getJid()); - this.sendUnmodifiedIqPacket(packet, callback); - + return this.sendUnmodifiedIqPacket(packet, callback); } - private synchronized void sendUnmodifiedIqPacket(final IqPacket packet, final OnIqPacketReceived callback) { + private synchronized String sendUnmodifiedIqPacket(final IqPacket packet, final OnIqPacketReceived callback) { if (packet.getId() == null) { final String id = nextRandomId(); packet.setAttribute("id", id); @@ -1103,6 +1134,7 @@ public class XmppConnection implements Runnable { } } this.sendPacket(packet); + return packet.getId(); } public void sendMessagePacket(final MessagePacket packet) { @@ -1293,6 +1325,9 @@ public class XmppConnection implements Runnable { return this.lastPingSent; } + public long getLastDiscoStarted() { + return this.lastDiscoStarted; + } public long getLastPacketReceived() { return this.lastPacketReceived; } -- cgit v1.2.3 From 9522af539e80fdf24ce4e116d346294008826e0b Mon Sep 17 00:00:00 2001 From: Christian S Date: Wed, 16 Dec 2015 20:00:46 +0100 Subject: modified strings --- src/main/res/values-de/strings.xml | 32 +------------------------------- src/main/res/values/strings.xml | 21 +-------------------- 2 files changed, 2 insertions(+), 51 deletions(-) diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index fc8450259..7c4ac3036 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -28,11 +28,8 @@ vor %d Minuten ungelesene Unterhaltungen senden… -<<<<<<< HEAD -======= Nachricht wird entschlüsselt. Bitte warten … OpenPGP-verschlüsselte Nachricht ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de Nickname wird bereits verwendet Administrator Eigentümer @@ -97,13 +94,8 @@ Kein OpenPGP-Schlüssel gefunden Pix-Art Messenger ist nicht in der Lage, deine Nachrichten zu verschlüsseln, weil dein Kontakt seinen oder ihren Schlüssel nicht preisgibt.\n\nBitte sag deinem Kontakt, er oder sie möge OpenPGP einrichten. Keine OpenPGP-Schlüssel gefunden -<<<<<<< HEAD Pix-Art Messenger ist nicht in der Lage, deine Nachrichten zu verschlüsseln, weil deine Kontakte ihre Schlüssel nicht preisgeben.\n\nBitte sage deinen Kontakten, sie mögen OpenPGP einrichten. Verschlüsselte Nachricht erhalten. Drücke hier, um sie zu entschlüsseln und anzuzeigen. -======= - Conversations ist nicht in der Lage, deine Nachrichten zu verschlüsseln, weil deine Kontakte ihre Schlüssel nicht preisgeben.\n\nBitte sage deinen Kontakten, sie mögen OpenPGP einrichten. - Verschlüsselte Nachricht erhalten. Drücke hier, um sie zu entschlüsseln. ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de Allgemeines XMPP-Ressource Der Name, mit dem sich der Client selbst identifiziert @@ -224,11 +216,7 @@ Eigener OMEMO-Fingerabdruck Andere Geräte OMEMO-Fingerabdruck vertrauen -<<<<<<< HEAD - Schlüssel abrufen… -======= Schlüssel empfangen… ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de Erledigt Überprüfen Entschlüsseln @@ -348,18 +336,12 @@ Überprüft! Kontakt fordert eine Überprüfung an Keine gültige OTR-Sitzung gefunden! -<<<<<<< HEAD Pix-Art Messenger - Den Dienst im Vordergrund ausführen. + Dienst im Vordergrund ausführen. Verhindert, dass Android Pix-Art Messenger beendet und die Verbindung unterbricht -======= - Conversations - Dienst im Vordergrund ausführen - Verhindert, dass Android Conversations beendet und die Verbindung unterbricht Chats exportieren Chats auf SD-Karte schreiben Chats werden auf SD-Karte geschrieben ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de Datei auswählen Empfange %1$s (%2$d%% abgeschlossen) %s herunterladen @@ -457,13 +439,8 @@ Android App Kontakt %s empfangen -<<<<<<< HEAD - Vordergrund-Dienst beenden Antippen, um Pix-Art Messenger zu öffnen -======= Vordergrund-Dienst deaktivieren - Antippen, um Conversations zu öffnen ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de Avatar wurde gespeichert %s wird gesendet %s wird angeboten @@ -514,7 +491,6 @@ Download fehlgeschlagen: keine Verbindung zum Host Weißen Hintergrund benutzen Empfangene Nachrichten als schwarzen Text auf weißem Hintergrund anzeigen -<<<<<<< HEAD Auf Updates prüfen Installierte Version: Neue Version: @@ -526,9 +502,7 @@ Download gestartet Kein Update verfügbar Zeitüberschreitung bei der Namensauflösung -======= TOR-Netzwerk nicht verfügbar ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de Fehlerhaft Conversation prüft auf eine neuere Version. Wenn ein Update verfügbar ist, wirst du gefragt, ob du deine Version aktualisieren möchtest. Der Update Dienst lädt und installiert die neue Version automatisch. Schreibe Chats auf SD Karte @@ -548,7 +522,6 @@ Zertifikat wird nicht vertraut Jabber-ID stimmt nicht dem Zertifikat überein Zertifikat erneuern -<<<<<<< HEAD Bild speichern… Bitte warten… Keine Bildquellen verfügbar @@ -583,8 +556,6 @@ Mit %s geteiltes Bild Mit Kontakten synchronisieren Pix-Art Messenger möchte deine Chat-Kontaktliste mit deinem Telefon-Kontakten abgleichen, um vollständige Namen und Avatare anzuzeigen.\n\nPix-Art Messenger wird deine Kontakte nur lokal lesen und abgleichen und benötigt keinen Abgleich mit dem Server.\n\nDu wirst gefragt, ob du den Zugriff auf deine Kontakte erlauben möchtest. - -======= Kann OMEMO Schlüssel nicht empfangen! OMEMO Schlüssel mit Zertifikat bestätigt! Dein Gerät unterstützt das Auswählen von Client-Zertifikaten nicht! @@ -601,5 +572,4 @@ %d Nachricht %d Nachrichten ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 3053de724..e2d4e6a0c 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -316,12 +316,8 @@ \n\nhttps://github.com/kyleduo/SwitchButton\n(Apache License, Version 2.0) \n\nhttps://github.com/WhisperSystems/libaxolotl-java\n(GPLv3) \n\nhttps://github.com/vinc3m1/RoundedImageView\n(Apache License, Version 2.0) -<<<<<<< HEAD - \n\nhttps://github.com/jdamcd/android-crop\n(Apache License, Version 2.0) -======= \n\nhttps://github.com/jdamcd/android-crop\n(Apache License, Version 2.0) ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de Quiet Hours Start time End time @@ -486,10 +482,7 @@ Hide offline Disable Account %s is typing… -<<<<<<< HEAD is typing… -======= ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de %s has stopped typing Typing notifications Let your contact know when you are writing a new message @@ -533,7 +526,6 @@ undo Use white background Show received messages as black text on a white background -<<<<<<< HEAD Timeout in DNS Check for Updates Update Service @@ -545,8 +537,6 @@ installed version: No update available Download started -======= ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de TOR network unavailable Broken Presence settings @@ -567,7 +557,6 @@ Error fetching OMEMO key! Verified OMEMO key with certificate! Your device does not support the selection of client certificates! -<<<<<<< HEAD Changes Plugins Download plugins for Pix-Art Messenger @@ -575,10 +564,6 @@ Send and receive locations Connection options Connect via TOR -======= - Connection options - Connect via Tor ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de Tunnel all connections through the TOR network. Requires Orbot Hostname Port @@ -592,11 +577,7 @@ Shared file with %s Shared image with %s -<<<<<<< HEAD Pix-Art Messenger needs access to external storage -======= - Conversations need access to external storage ->>>>>>> 43dd681239ea5a287f5761597de5dcdc4daed3de Synchronize with contacts - Conversations wants to match your XMPP roster with your contacts to show their full names and avatars.\n\nConversations will only read your contacts and match them locally without uploading them to your server.\n\nYou will now be asked to grant permission to access your contacts. + Pix-Art Messenger wants to match your XMPP roster with your contacts to show their full names and avatars.\n\nPix-Art Messenger will only read your contacts and match them locally without uploading them to your server.\n\nYou will now be asked to grant permission to access your contacts. -- cgit v1.2.3