From 97d9cb7dd53c127b170db41d2e3ed3b4da415e8f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 1 Jan 2023 12:05:49 +0100 Subject: [PATCH 01/43] remove work arounds for slack --- .../siacs/conversations/entities/Account.java | 8 ----- .../services/XmppConnectionService.java | 12 +++---- .../eu/siacs/conversations/xmpp/Patches.java | 3 -- .../conversations/xmpp/XmppConnection.java | 33 ------------------- 4 files changed, 4 insertions(+), 52 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 7c5f22b27a4af400c41dc28d643ddacc414fc166..bfbe817cb6d71f88a88a8434bc46f5373676c05c 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -222,14 +222,6 @@ public class Account extends AbstractEntity implements AvatarService.Avatarable this.displayName = displayName; } - public XmppConnection.Identity getServerIdentity() { - if (xmppConnection == null) { - return XmppConnection.Identity.UNKNOWN; - } else { - return xmppConnection.getServerIdentity(); - } - } - public Contact getSelfContact() { return getRoster().getContact(jid); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 483016364ef5ec8e2d56133be1b3f58f3533208a..4981f0473264deb9d06786e1e8d02d0eb308226a 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -61,7 +61,6 @@ import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpServiceConnection; import java.io.File; -import java.security.SecureRandom; import java.security.Security; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -154,7 +153,6 @@ import eu.siacs.conversations.xmpp.OnMessagePacketReceived; import eu.siacs.conversations.xmpp.OnPresencePacketReceived; import eu.siacs.conversations.xmpp.OnStatusChanged; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; -import eu.siacs.conversations.xmpp.Patches; import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.forms.Data; @@ -818,7 +816,7 @@ public class XmppConnectionService extends Service { case Intent.ACTION_SEND: Uri uri = intent.getData(); if (uri != null) { - Log.d(Config.LOGTAG, "received uri permission for " + uri.toString()); + Log.d(Config.LOGTAG, "received uri permission for " + uri); } return START_STICKY; } @@ -1520,9 +1518,7 @@ public class XmppConnectionService extends Service { } MessagePacket packet = null; - final boolean addToConversation = (conversation.getMode() != Conversation.MODE_MULTI - || !Patches.BAD_MUC_REFLECTION.contains(account.getServerIdentity())) - && !message.edited(); + final boolean addToConversation = !message.edited(); boolean saveInDb = addToConversation; message.setStatus(Message.STATUS_WAITING); @@ -3654,7 +3650,7 @@ public class XmppConnectionService extends Service { } }); } else { - Log.d(Config.LOGTAG, "failed to request vcard " + response.toString()); + Log.d(Config.LOGTAG, "failed to request vcard " + response); callback.onAvatarPublicationFailed(R.string.error_publish_avatar_no_server_support); } }); @@ -4680,7 +4676,7 @@ public class XmppConnectionService extends Service { mAvatarService.clear(account); sendIqPacket(account, request, (account1, packet) -> { if (packet.getType() == IqPacket.TYPE.ERROR) { - Log.d(Config.LOGTAG, account1.getJid().asBareJid() + ": unable to modify nick name " + packet.toString()); + Log.d(Config.LOGTAG, account1.getJid().asBareJid() + ": unable to modify nick name " + packet); } }); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/Patches.java b/src/main/java/eu/siacs/conversations/xmpp/Patches.java index a5b35e811c26a71a53a208aa58e22e3dfb596ec5..2332da1ca193551a4a5f8fadfa84081639d41a3b 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/Patches.java +++ b/src/main/java/eu/siacs/conversations/xmpp/Patches.java @@ -8,7 +8,4 @@ public class Patches { public static final List DISCO_EXCEPTIONS = Arrays.asList( "nimbuzz.com" ); - public static final List BAD_MUC_REFLECTION = Arrays.asList( - XmppConnection.Identity.SLACK - ); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 563868d2ab29dd41629840c312374a207d604c4d..abde8557f1d60e3631877b2769c80fbe97a629cb 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -2545,43 +2545,10 @@ public class XmppConnection implements Runnable { this.mInteractive = interactive; } - public Identity getServerIdentity() { - synchronized (this.disco) { - ServiceDiscoveryResult result = disco.get(account.getJid().getDomain()); - if (result == null) { - return Identity.UNKNOWN; - } - for (final ServiceDiscoveryResult.Identity id : result.getIdentities()) { - if (id.getType().equals("im") - && id.getCategory().equals("server") - && id.getName() != null) { - switch (id.getName()) { - case "Prosody": - return Identity.PROSODY; - case "ejabberd": - return Identity.EJABBERD; - case "Slack-XMPP": - return Identity.SLACK; - } - } - } - } - return Identity.UNKNOWN; - } - private IqGenerator getIqGenerator() { return mXmppConnectionService.getIqGenerator(); } - public enum Identity { - FACEBOOK, - SLACK, - EJABBERD, - PROSODY, - NIMBUZZ, - UNKNOWN - } - private class MyKeyManager implements X509KeyManager { @Override public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) { From 1000d927a79db8b96834fe8dc8da82924704797b Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 1 Jan 2023 12:20:10 +0100 Subject: [PATCH 02/43] remove work arounds for nimbuzz.com --- .../java/eu/siacs/conversations/xmpp/Patches.java | 11 ----------- .../eu/siacs/conversations/xmpp/XmppConnection.java | 11 +---------- 2 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 src/main/java/eu/siacs/conversations/xmpp/Patches.java diff --git a/src/main/java/eu/siacs/conversations/xmpp/Patches.java b/src/main/java/eu/siacs/conversations/xmpp/Patches.java deleted file mode 100644 index 2332da1ca193551a4a5f8fadfa84081639d41a3b..0000000000000000000000000000000000000000 --- a/src/main/java/eu/siacs/conversations/xmpp/Patches.java +++ /dev/null @@ -1,11 +0,0 @@ -package eu.siacs.conversations.xmpp; - - -import java.util.Arrays; -import java.util.List; - -public class Patches { - public static final List DISCO_EXCEPTIONS = Arrays.asList( - "nimbuzz.com" - ); -} diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index abde8557f1d60e3631877b2769c80fbe97a629cb..a4761389555752d57da9059dcd9ab531a340d033 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -1907,16 +1907,7 @@ public class XmppConnection implements Runnable { } Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": starting service discovery"); mPendingServiceDiscoveries.set(0); - if (!waitForDisco - || Patches.DISCO_EXCEPTIONS.contains( - account.getJid().getDomain().toEscapedString())) { - Log.d( - Config.LOGTAG, - account.getJid().asBareJid() + ": do not wait for service discovery"); - mWaitForDisco.set(false); - } else { - mWaitForDisco.set(true); - } + mWaitForDisco.set(waitForDisco); lastDiscoStarted = SystemClock.elapsedRealtime(); mXmppConnectionService.scheduleWakeUpCall( Config.CONNECT_DISCO_TIMEOUT, account.getUuid().hashCode()); From b1f95d2e39e64f3f066afa410c69d0704b1fdfb5 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 4 Jan 2023 10:23:20 +0100 Subject: [PATCH 03/43] integrate UnifiedPush distributor --- src/main/AndroidManifest.xml | 18 ++ .../conversations/parser/AbstractParser.java | 32 ++ .../siacs/conversations/parser/IqParser.java | 18 ++ .../persistance/UnifiedPushDatabase.java | 244 +++++++++++++++ .../services/UnifiedPushBroker.java | 277 ++++++++++++++++++ .../services/UnifiedPushDistributor.java | 152 ++++++++++ .../services/XmppConnectionService.java | 30 +- .../conversations/ui/SettingsActivity.java | 38 ++- .../eu/siacs/conversations/xml/Namespace.java | 1 + src/main/res/values/defaults.xml | 2 + src/main/res/values/strings.xml | 6 + src/main/res/xml/preferences.xml | 15 + 12 files changed, 831 insertions(+), 2 deletions(-) create mode 100644 src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java create mode 100644 src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java create mode 100644 src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 24265da618d211defb27384cb963fc236a4a3a0a..c18addf271067674e66a94d9ba2724dc3a566e8f 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -67,6 +67,9 @@ + + + @@ -102,6 +105,21 @@ + + + + + + + + + + + + diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java index f4b01b7d3199cf821732226b79cc1c998296ee89..5de637399fb571bfaff80675cee50a2275cc8d60 100644 --- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java @@ -4,6 +4,7 @@ package eu.siacs.conversations.parser; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Locale; @@ -86,6 +87,37 @@ public abstract class AbstractParser { return Math.min(dateFormat.parse(timestamp).getTime()+ms, System.currentTimeMillis()); } + public static long getTimestamp(final String input) throws ParseException { + if (input == null) { + throw new IllegalArgumentException("timestamp should not be null"); + } + final String timestamp = input.replace("Z", "+0000"); + final SimpleDateFormat simpleDateFormat = + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US); + final long milliseconds = getMilliseconds(timestamp); + final String formatted = + timestamp.substring(0, 19) + timestamp.substring(timestamp.length() - 5); + final Date date = simpleDateFormat.parse(formatted); + if (date == null) { + throw new IllegalArgumentException("Date was null"); + } + return date.getTime() + milliseconds; + } + + private static long getMilliseconds(final String timestamp) { + if (timestamp.length() >= 25 && timestamp.charAt(19) == '.') { + final String millis = timestamp.substring(19, timestamp.length() - 5); + try { + double fractions = Double.parseDouble("0" + millis); + return Math.round(1000 * fractions); + } catch (NumberFormatException e) { + return 0; + } + } else { + return 0; + } + } + protected void updateLastseen(final Account account, final Jid from) { final Contact contact = account.getRoster().getContact(from); contact.setLastResource(from.isBareJid() ? "" : from.getResource()); diff --git a/src/main/java/eu/siacs/conversations/parser/IqParser.java b/src/main/java/eu/siacs/conversations/parser/IqParser.java index d02d69ddca3e6fbba2086a12a03162102f6b1a62..0c08c557ebba9d8a052fad0cd33bb7079dcd8758 100644 --- a/src/main/java/eu/siacs/conversations/parser/IqParser.java +++ b/src/main/java/eu/siacs/conversations/parser/IqParser.java @@ -452,6 +452,24 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { response = mXmppConnectionService.getIqGenerator().entityTimeResponse(packet); } mXmppConnectionService.sendIqPacket(account, response, null); + } else if (packet.hasChild("push", Namespace.UNIFIED_PUSH) && packet.getType() == IqPacket.TYPE.SET) { + final Jid transport = packet.getFrom(); + final Element push = packet.findChild("push", Namespace.UNIFIED_PUSH); + final boolean success = + push != null + && mXmppConnectionService.processUnifiedPushMessage( + account, transport, push); + final IqPacket response; + if (success) { + response = packet.generateResponse(IqPacket.TYPE.RESULT); + } else { + response = packet.generateResponse(IqPacket.TYPE.ERROR); + final Element error = response.addChild("error"); + error.setAttribute("type", "cancel"); + error.setAttribute("code", "404"); + error.addChild("item-not-found", "urn:ietf:params:xml:ns:xmpp-stanzas"); + } + mXmppConnectionService.sendIqPacket(account, response, null); } else { if (packet.getType() == IqPacket.TYPE.GET || packet.getType() == IqPacket.TYPE.SET) { final IqPacket response = packet.generateResponse(IqPacket.TYPE.ERROR); diff --git a/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java new file mode 100644 index 0000000000000000000000000000000000000000..9b17406f7641ce5711c072d78ec79b7be5c4efcb --- /dev/null +++ b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java @@ -0,0 +1,244 @@ +package eu.siacs.conversations.persistance; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import androidx.annotation.Nullable; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +import eu.siacs.conversations.Config; + +public class UnifiedPushDatabase extends SQLiteOpenHelper { + private static final String DATABASE_NAME = "unified-push-distributor"; + private static final int DATABASE_VERSION = 1; + + private static UnifiedPushDatabase instance; + + public static UnifiedPushDatabase getInstance(final Context context) { + synchronized (UnifiedPushDatabase.class) { + if (instance == null) { + instance = new UnifiedPushDatabase(context.getApplicationContext()); + } + return instance; + } + } + + private UnifiedPushDatabase(@Nullable Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(final SQLiteDatabase sqLiteDatabase) { + sqLiteDatabase.execSQL( + "CREATE TABLE push (account TEXT, transport TEXT, application TEXT NOT NULL, instance TEXT NOT NULL UNIQUE, endpoint TEXT, expiration NUMBER DEFAULT 0)"); + } + + public boolean register(final String application, final String instance) { + final SQLiteDatabase sqLiteDatabase = getWritableDatabase(); + sqLiteDatabase.beginTransaction(); + final Optional existingApplication; + try (final Cursor cursor = + sqLiteDatabase.query( + "push", + new String[] {"application"}, + "instance=?", + new String[] {instance}, + null, + null, + null)) { + if (cursor != null && cursor.moveToFirst()) { + existingApplication = Optional.of(cursor.getString(0)); + } else { + existingApplication = Optional.absent(); + } + } + if (existingApplication.isPresent()) { + sqLiteDatabase.setTransactionSuccessful(); + sqLiteDatabase.endTransaction(); + return application.equals(existingApplication.get()); + } + final ContentValues contentValues = new ContentValues(); + contentValues.put("application", application); + contentValues.put("instance", instance); + contentValues.put("expiration", 0); + final long inserted = sqLiteDatabase.insert("push", null, contentValues); + if (inserted > 0) { + Log.d(Config.LOGTAG, "inserted new application/instance tuple into unified push db"); + } + sqLiteDatabase.setTransactionSuccessful(); + sqLiteDatabase.endTransaction(); + return true; + } + + public List getRenewals(final String account, final String transport) { + final ImmutableList.Builder renewalBuilder = ImmutableList.builder(); + final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); + try (final Cursor cursor = + sqLiteDatabase.query( + "push", + new String[] {"application", "instance"}, + "account <> ? OR transport <> ? OR expiration < " + + System.currentTimeMillis(), + new String[] {account, transport}, + null, + null, + null)) { + while (cursor != null && cursor.moveToNext()) { + renewalBuilder.add( + new PushTarget( + cursor.getString(cursor.getColumnIndexOrThrow("application")), + cursor.getString(cursor.getColumnIndexOrThrow("instance")))); + } + } + return renewalBuilder.build(); + } + + public ApplicationEndpoint getEndpoint( + final String account, final String transport, final String instance) { + final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); + try (final Cursor cursor = + sqLiteDatabase.query( + "push", + new String[] {"application", "endpoint"}, + "account = ? AND transport = ? AND instance = ? ", + new String[] {account, transport, instance}, + null, + null, + null)) { + if (cursor != null && cursor.moveToFirst()) { + return new ApplicationEndpoint( + cursor.getString(cursor.getColumnIndexOrThrow("application")), + cursor.getString(cursor.getColumnIndexOrThrow("endpoint"))); + } + } + return null; + } + + @Override + public void onUpgrade( + final SQLiteDatabase sqLiteDatabase, final int oldVersion, final int newVersion) {} + + public boolean updateEndpoint( + final String instance, + final String account, + final String transport, + final String endpoint, + final long expiration) { + final SQLiteDatabase sqLiteDatabase = getWritableDatabase(); + sqLiteDatabase.beginTransaction(); + final String existingEndpoint; + try (final Cursor cursor = + sqLiteDatabase.query( + "push", + new String[] {"endpoint"}, + "instance=?", + new String[] {instance}, + null, + null, + null)) { + if (cursor != null && cursor.moveToFirst()) { + existingEndpoint = cursor.getString(0); + } else { + existingEndpoint = null; + } + } + final ContentValues contentValues = new ContentValues(); + contentValues.put("account", account); + contentValues.put("transport", transport); + contentValues.put("endpoint", endpoint); + contentValues.put("expiration", expiration); + sqLiteDatabase.update("push", contentValues, "instance=?", new String[] {instance}); + sqLiteDatabase.setTransactionSuccessful(); + sqLiteDatabase.endTransaction(); + return !endpoint.equals(existingEndpoint); + } + + public List getPushTargets(final String account, final String transport) { + final ImmutableList.Builder renewalBuilder = ImmutableList.builder(); + final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); + try (final Cursor cursor = + sqLiteDatabase.query( + "push", + new String[] {"application", "instance"}, + "account = ?", + new String[] {account}, + null, + null, + null)) { + while (cursor != null && cursor.moveToNext()) { + renewalBuilder.add( + new PushTarget( + cursor.getString(cursor.getColumnIndexOrThrow("application")), + cursor.getString(cursor.getColumnIndexOrThrow("instance")))); + } + } + return renewalBuilder.build(); + } + + public boolean deleteInstance(final String instance) { + final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); + final int rows = sqLiteDatabase.delete("push", "instance=?", new String[] {instance}); + return rows >= 1; + } + + public boolean deleteApplication(final String application) { + final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); + final int rows = sqLiteDatabase.delete("push", "application=?", new String[] {application}); + return rows >= 1; + } + + public static class ApplicationEndpoint { + public final String application; + public final String endpoint; + + public ApplicationEndpoint(String application, String endpoint) { + this.application = application; + this.endpoint = endpoint; + } + } + + public static class PushTarget { + public final String application; + public final String instance; + + public PushTarget(final String application, final String instance) { + this.application = application; + this.instance = instance; + } + + @NotNull + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("application", application) + .add("instance", instance) + .toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PushTarget that = (PushTarget) o; + return Objects.equal(application, that.application) + && Objects.equal(instance, that.instance); + } + + @Override + public int hashCode() { + return Objects.hashCode(application, instance); + } + } +} diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java new file mode 100644 index 0000000000000000000000000000000000000000..101a09fc3542cdd5e002dac0bbab71f541de5429 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java @@ -0,0 +1,277 @@ +package eu.siacs.conversations.services; + +import android.content.ComponentName; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.preference.PreferenceManager; +import android.util.Log; + +import com.google.common.base.Optional; +import com.google.common.base.Strings; +import com.google.common.collect.Iterables; +import com.google.common.io.BaseEncoding; + +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.util.List; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.parser.AbstractParser; +import eu.siacs.conversations.persistance.UnifiedPushDatabase; +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xml.Namespace; +import eu.siacs.conversations.xmpp.Jid; +import eu.siacs.conversations.xmpp.stanzas.IqPacket; + +public class UnifiedPushBroker { + + private final XmppConnectionService service; + + public UnifiedPushBroker(final XmppConnectionService xmppConnectionService) { + this.service = xmppConnectionService; + } + + public Optional renewUnifiedPushEndpoints() { + final Optional transportOptional = getTransport(); + if (transportOptional.isPresent()) { + renewUnifiedEndpoint(transportOptional.get()); + } else { + Log.d(Config.LOGTAG, "skipping UnifiedPush endpoint renewal. No transport selected"); + } + return transportOptional; + } + + private void renewUnifiedEndpoint(final Transport transport) { + final Account account = transport.account; + final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(service); + final List renewals = + unifiedPushDatabase.getRenewals( + account.getUuid(), transport.transport.toEscapedString()); + for (final UnifiedPushDatabase.PushTarget renewal : renewals) { + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + ": try to renew UnifiedPush " + renewal); + final String hashedApplication = + UnifiedPushDistributor.hash(account.getUuid(), renewal.application); + final String hashedInstance = + UnifiedPushDistributor.hash(account.getUuid(), renewal.instance); + final IqPacket registration = new IqPacket(IqPacket.TYPE.SET); + registration.setTo(transport.transport); + final Element register = registration.addChild("register", Namespace.UNIFIED_PUSH); + register.setAttribute("application", hashedApplication); + register.setAttribute("instance", hashedInstance); + this.service.sendIqPacket( + account, + registration, + (a, response) -> processRegistration(transport, renewal, response)); + } + } + + private void processRegistration( + final Transport transport, + final UnifiedPushDatabase.PushTarget renewal, + final IqPacket response) { + if (response.getType() == IqPacket.TYPE.RESULT) { + final Element registered = response.findChild("registered", Namespace.UNIFIED_PUSH); + if (registered == null) { + return; + } + final String endpoint = registered.getAttribute("endpoint"); + if (Strings.isNullOrEmpty(endpoint)) { + Log.w(Config.LOGTAG, "endpoint was null in up registration"); + return; + } + final long expiration; + try { + expiration = AbstractParser.getTimestamp(registered.getAttribute("expiration")); + } catch (final IllegalArgumentException | ParseException e) { + Log.d(Config.LOGTAG, "could not parse expiration", e); + return; + } + renewUnifiedPushEndpoint(transport, renewal, endpoint, expiration); + } + } + + private void renewUnifiedPushEndpoint( + final Transport transport, + final UnifiedPushDatabase.PushTarget renewal, + final String endpoint, + final long expiration) { + Log.d(Config.LOGTAG, "registered endpoint " + endpoint + " expiration=" + expiration); + final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(service); + final boolean modified = + unifiedPushDatabase.updateEndpoint( + renewal.instance, + transport.account.getUuid(), + transport.transport.toEscapedString(), + endpoint, + expiration); + if (modified) { + Log.d( + Config.LOGTAG, + "endpoint for " + + renewal.application + + "/" + + renewal.instance + + " was updated to " + + endpoint); + broadcastEndpoint( + renewal.instance, + new UnifiedPushDatabase.ApplicationEndpoint(renewal.application, endpoint)); + } + } + + public boolean reconfigurePushDistributor() { + final boolean enabled = getTransport().isPresent(); + setUnifiedPushDistributorEnabled(enabled); + return enabled; + } + + private void setUnifiedPushDistributorEnabled(final boolean enabled) { + final PackageManager packageManager = service.getPackageManager(); + final ComponentName componentName = + new ComponentName(service, UnifiedPushDistributor.class); + if (enabled) { + packageManager.setComponentEnabledSetting( + componentName, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + Log.d(Config.LOGTAG, "UnifiedPushDistributor has been enabled"); + } else { + packageManager.setComponentEnabledSetting( + componentName, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + PackageManager.DONT_KILL_APP); + Log.d(Config.LOGTAG, "UnifiedPushDistributor has been disabled"); + } + } + + public boolean processPushMessage( + final Account account, final Jid transport, final Element push) { + final String instance = push.getAttribute("instance"); + final String application = push.getAttribute("application"); + if (Strings.isNullOrEmpty(instance) || Strings.isNullOrEmpty(application)) { + return false; + } + final String content = push.getContent(); + final byte[] payload; + if (Strings.isNullOrEmpty(content)) { + payload = new byte[0]; + } else if (BaseEncoding.base64().canDecode(content)) { + payload = BaseEncoding.base64().decode(content); + } else { + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + ": received invalid unified push payload"); + return false; + } + final Optional pushTarget = + getPushTarget(account, transport, application, instance); + if (pushTarget.isPresent()) { + final UnifiedPushDatabase.PushTarget target = pushTarget.get(); + // TODO check if app is still installed? + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": broadcasting a " + + payload.length + + " bytes push message to " + + target.application); + broadcastPushMessage(target, payload); + return true; + } else { + Log.d(Config.LOGTAG, "could not find application for push"); + return false; + } + } + + public Optional getTransport() { + final SharedPreferences sharedPreferences = + PreferenceManager.getDefaultSharedPreferences(service.getApplicationContext()); + final String accountPreference = + sharedPreferences.getString(UnifiedPushDistributor.PREFERENCE_ACCOUNT, "none"); + final String pushServerPreference = + sharedPreferences.getString( + UnifiedPushDistributor.PREFERENCE_PUSH_SERVER, + service.getString(R.string.default_push_server)); + if (Strings.isNullOrEmpty(accountPreference) + || "none".equalsIgnoreCase(accountPreference) + || Strings.nullToEmpty(pushServerPreference).trim().isEmpty()) { + return Optional.absent(); + } + final Jid transport; + final Jid jid; + try { + transport = Jid.ofEscaped(Strings.nullToEmpty(pushServerPreference).trim()); + jid = Jid.ofEscaped(Strings.nullToEmpty(accountPreference).trim()); + } catch (final IllegalArgumentException e) { + return Optional.absent(); + } + final Account account = service.findAccountByJid(jid); + if (account == null) { + return Optional.absent(); + } + return Optional.of(new Transport(account, transport)); + } + + private Optional getPushTarget( + final Account account, + final Jid transport, + final String application, + final String instance) { + final String uuid = account.getUuid(); + final List pushTargets = + UnifiedPushDatabase.getInstance(service) + .getPushTargets(uuid, transport.toEscapedString()); + return Iterables.tryFind( + pushTargets, + pt -> + UnifiedPushDistributor.hash(uuid, pt.application).equals(application) + && UnifiedPushDistributor.hash(uuid, pt.instance).equals(instance)); + } + + private void broadcastPushMessage( + final UnifiedPushDatabase.PushTarget target, final byte[] payload) { + final Intent updateIntent = new Intent(UnifiedPushDistributor.ACTION_MESSAGE); + updateIntent.setPackage(target.application); + updateIntent.putExtra("token", target.instance); + updateIntent.putExtra("bytesMessage", payload); + updateIntent.putExtra("message", new String(payload, StandardCharsets.UTF_8)); + service.sendBroadcast(updateIntent); + } + + private void broadcastEndpoint( + final String instance, final UnifiedPushDatabase.ApplicationEndpoint endpoint) { + Log.d(Config.LOGTAG, "broadcasting endpoint to " + endpoint.application); + final Intent updateIntent = new Intent(UnifiedPushDistributor.ACTION_NEW_ENDPOINT); + updateIntent.setPackage(endpoint.application); + updateIntent.putExtra("token", instance); + updateIntent.putExtra("endpoint", endpoint.endpoint); + service.sendBroadcast(updateIntent); + } + + public void rebroadcastEndpoint(final String instance, final Transport transport) { + final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(service); + final UnifiedPushDatabase.ApplicationEndpoint endpoint = + unifiedPushDatabase.getEndpoint( + transport.account.getUuid(), + transport.transport.toEscapedString(), + instance); + if (endpoint != null) { + broadcastEndpoint(instance, endpoint); + } + } + + public static class Transport { + public final Account account; + public final Jid transport; + + public Transport(Account account, Jid transport) { + this.account = account; + this.transport = transport; + } + } +} diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java new file mode 100644 index 0000000000000000000000000000000000000000..64c16dbcdf7ff804741282d8e4c66f94907ba2a6 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushDistributor.java @@ -0,0 +1,152 @@ +package eu.siacs.conversations.services; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.util.Log; + +import com.google.common.base.Charsets; +import com.google.common.base.Joiner; +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.hash.Hashing; +import com.google.common.io.BaseEncoding; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.persistance.UnifiedPushDatabase; +import eu.siacs.conversations.utils.Compatibility; + +public class UnifiedPushDistributor extends BroadcastReceiver { + + public static final String ACTION_REGISTER = "org.unifiedpush.android.distributor.REGISTER"; + public static final String ACTION_UNREGISTER = "org.unifiedpush.android.distributor.UNREGISTER"; + public static final String ACTION_BYTE_MESSAGE = + "org.unifiedpush.android.distributor.feature.BYTES_MESSAGE"; + public static final String ACTION_REGISTRATION_FAILED = + "org.unifiedpush.android.connector.REGISTRATION_FAILED"; + public static final String ACTION_MESSAGE = "org.unifiedpush.android.connector.MESSAGE"; + public static final String ACTION_NEW_ENDPOINT = + "org.unifiedpush.android.connector.NEW_ENDPOINT"; + + public static final String PREFERENCE_ACCOUNT = "up_push_account"; + public static final String PREFERENCE_PUSH_SERVER = "up_push_server"; + + public static final List PREFERENCES = + Arrays.asList(PREFERENCE_ACCOUNT, PREFERENCE_PUSH_SERVER); + + @Override + public void onReceive(final Context context, final Intent intent) { + if (intent == null) { + return; + } + final String action = intent.getAction(); + final String application = intent.getStringExtra("application"); + final String instance = intent.getStringExtra("token"); + final List features = intent.getStringArrayListExtra("features"); + switch (Strings.nullToEmpty(action)) { + case ACTION_REGISTER: + register(context, application, instance, features); + break; + case ACTION_UNREGISTER: + unregister(context, instance); + break; + case Intent.ACTION_PACKAGE_FULLY_REMOVED: + unregisterApplication(context, intent.getData()); + break; + default: + Log.d(Config.LOGTAG, "UnifiedPushDistributor received unknown action " + action); + break; + } + } + + private void register( + final Context context, + final String application, + final String instance, + final Collection features) { + if (Strings.isNullOrEmpty(application) || Strings.isNullOrEmpty(instance)) { + Log.w(Config.LOGTAG, "ignoring invalid UnifiedPush registration"); + return; + } + final List receivers = getBroadcastReceivers(context, application); + if (receivers.contains(application)) { + final boolean byteMessage = features != null && features.contains(ACTION_BYTE_MESSAGE); + Log.d( + Config.LOGTAG, + "received up registration from " + + application + + "/" + + instance + + " features: " + + features); + if (UnifiedPushDatabase.getInstance(context).register(application, instance)) { + Log.d( + Config.LOGTAG, + "successfully created UnifiedPush entry. waking up XmppConnectionService"); + final Intent serviceIntent = new Intent(context, XmppConnectionService.class); + serviceIntent.setAction(XmppConnectionService.ACTION_RENEW_UNIFIED_PUSH_ENDPOINTS); + serviceIntent.putExtra("instance", instance); + Compatibility.startService(context, serviceIntent); + } else { + Log.d(Config.LOGTAG, "not successful. sending error message back to application"); + final Intent registrationFailed = new Intent(ACTION_REGISTRATION_FAILED); + registrationFailed.setPackage(application); + registrationFailed.putExtra("token", instance); + context.sendBroadcast(registrationFailed); + } + } else { + Log.d( + Config.LOGTAG, + "ignoring invalid UnifiedPush registration. Unknown application " + + application); + } + } + + private List getBroadcastReceivers(final Context context, final String application) { + final Intent messageIntent = new Intent(ACTION_MESSAGE); + messageIntent.setPackage(application); + final List resolveInfo = + context.getPackageManager().queryBroadcastReceivers(messageIntent, 0); + return Lists.transform( + resolveInfo, ri -> ri.activityInfo == null ? null : ri.activityInfo.packageName); + } + + private void unregister(final Context context, final String instance) { + if (Strings.isNullOrEmpty(instance)) { + Log.w(Config.LOGTAG, "ignoring invalid UnifiedPush un-registration"); + return; + } + final UnifiedPushDatabase unifiedPushDatabase = UnifiedPushDatabase.getInstance(context); + if (unifiedPushDatabase.deleteInstance(instance)) { + Log.d(Config.LOGTAG, "successfully removed " + instance + " from UnifiedPush"); + } + } + + private void unregisterApplication(final Context context, final Uri uri) { + if (uri != null && "package".equalsIgnoreCase(uri.getScheme())) { + final String application = uri.getSchemeSpecificPart(); + if (Strings.isNullOrEmpty(application)) { + return; + } + Log.d(Config.LOGTAG, "app " + application + " has been removed from the system"); + final UnifiedPushDatabase database = UnifiedPushDatabase.getInstance(context); + if (database.deleteApplication(application)) { + Log.d(Config.LOGTAG, "successfully removed " + application + " from UnifiedPush"); + } + } + } + + public static String hash(String... components) { + return BaseEncoding.base64() + .encode( + Hashing.sha256() + .hashString(Joiner.on('\0').join(components), Charsets.UTF_8) + .asBytes()); + } +} diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 4981f0473264deb9d06786e1e8d02d0eb308226a..22e7b38e545b371620c45703cb876914d68935b6 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -53,6 +53,7 @@ import androidx.core.app.RemoteInput; import androidx.core.content.ContextCompat; import com.google.common.base.Objects; +import com.google.common.base.Optional; import com.google.common.base.Strings; import org.conscrypt.Conscrypt; @@ -64,6 +65,7 @@ import java.io.File; import java.security.Security; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -117,6 +119,7 @@ import eu.siacs.conversations.parser.MessageParser; import eu.siacs.conversations.parser.PresenceParser; import eu.siacs.conversations.persistance.DatabaseBackend; import eu.siacs.conversations.persistance.FileBackend; +import eu.siacs.conversations.persistance.UnifiedPushDatabase; import eu.siacs.conversations.ui.ChooseAccountForProfilePictureActivity; import eu.siacs.conversations.ui.RtpSessionActivity; import eu.siacs.conversations.ui.SettingsActivity; @@ -124,6 +127,7 @@ import eu.siacs.conversations.ui.UiCallback; import eu.siacs.conversations.ui.interfaces.OnAvatarPublication; import eu.siacs.conversations.ui.interfaces.OnMediaLoaded; import eu.siacs.conversations.ui.interfaces.OnSearchResultsAvailable; +import eu.siacs.conversations.utils.AccountUtils; import eu.siacs.conversations.utils.Compatibility; import eu.siacs.conversations.utils.ConversationsFileObserver; import eu.siacs.conversations.utils.CryptoHelper; @@ -185,6 +189,7 @@ public class XmppConnectionService extends Service { public static final String ACTION_END_CALL = "end_call"; public static final String ACTION_PROVISION_ACCOUNT = "provision_account"; private static final String ACTION_POST_CONNECTIVITY_CHANGE = "eu.siacs.conversations.POST_CONNECTIVITY_CHANGE"; + public static final String ACTION_RENEW_UNIFIED_PUSH_ENDPOINTS = "eu.siacs.conversations.UNIFIED_PUSH_RENEW"; private static final String SETTING_LAST_ACTIVITY_TS = "last_activity_timestamp"; @@ -217,6 +222,7 @@ public class XmppConnectionService extends Service { private final FileBackend fileBackend = new FileBackend(this); private MemorizingTrustManager mMemorizingTrustManager; private final NotificationService mNotificationService = new NotificationService(this); + private final UnifiedPushBroker unifiedPushBroker = new UnifiedPushBroker(this); private final ChannelDiscoveryService mChannelDiscoveryService = new ChannelDiscoveryService(this); private final ShortcutService mShortcutService = new ShortcutService(this); private final AtomicBoolean mInitialAddressbookSyncCompleted = new AtomicBoolean(false); @@ -804,6 +810,13 @@ public class XmppConnectionService extends Service { case ACTION_FCM_TOKEN_REFRESH: refreshAllFcmTokens(); break; + case ACTION_RENEW_UNIFIED_PUSH_ENDPOINTS: + final String instance = intent.getStringExtra("instance"); + final Optional transport = renewUnifiedPushEndpoints(); + if (instance != null && transport.isPresent()) { + unifiedPushBroker.rebroadcastEndpoint(instance, transport.get()); + } + break; case ACTION_IDLE_PING: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { scheduleNextIdlePing(); @@ -933,6 +946,10 @@ public class XmppConnectionService extends Service { return pingNow; } + public boolean processUnifiedPushMessage(final Account account, final Jid transport, final Element push) { + return unifiedPushBroker.processPushMessage(account, transport, push); + } + public void reinitializeMuclumbusService() { mChannelDiscoveryService.initializeMuclumbusService(); } @@ -1167,6 +1184,7 @@ public class XmppConnectionService extends Service { editor.putBoolean(EventReceiver.SETTING_ENABLED_ACCOUNTS, hasEnabledAccounts).apply(); editor.apply(); toggleSetProfilePictureActivity(hasEnabledAccounts); + reconfigurePushDistributor(); restoreFromDatabase(); @@ -2334,10 +2352,18 @@ public class XmppConnectionService extends Service { final int targetState = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED; getPackageManager().setComponentEnabledSetting(name, targetState, PackageManager.DONT_KILL_APP); } catch (IllegalStateException e) { - Log.d(Config.LOGTAG, "unable to toggle profile picture actvitiy"); + Log.d(Config.LOGTAG, "unable to toggle profile picture activity"); } } + public boolean reconfigurePushDistributor() { + return this.unifiedPushBroker.reconfigurePushDistributor(); + } + + public Optional renewUnifiedPushEndpoints() { + return this.unifiedPushBroker.renewUnifiedPushEndpoints(); + } + private void provisionAccount(final String address, final String password) { final Jid jid = Jid.ofEscaped(address); final Account account = new Account(jid, password); @@ -4499,6 +4525,8 @@ public class XmppConnectionService extends Service { } } + + private void sendOfflinePresence(final Account account) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": sending offline presence"); sendPresencePacket(account, mPresenceGenerator.sendOfflinePresence(account)); diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index 07c8a55db1b6bba085d94cb1909929b76fdc9d72..2b2f8110a9a96fdcd4c59fa731257261cce4ff75 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -24,6 +24,8 @@ import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import java.io.File; import java.security.KeyStoreException; @@ -40,6 +42,7 @@ import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.ExportBackupService; import eu.siacs.conversations.services.MemorizingTrustManager; import eu.siacs.conversations.services.QuickConversationsService; +import eu.siacs.conversations.services.UnifiedPushDistributor; import eu.siacs.conversations.ui.util.SettingsUtils; import eu.siacs.conversations.ui.util.StyledAttributes; import eu.siacs.conversations.utils.GeoHelper; @@ -88,7 +91,36 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference } @Override - void onBackendConnected() {} + void onBackendConnected() { + final Preference accountPreference = + mSettingsFragment.findPreference(UnifiedPushDistributor.PREFERENCE_ACCOUNT); + reconfigureUpAccountPreference(accountPreference); + } + + private void reconfigureUpAccountPreference(final Preference preference) { + final ListPreference listPreference; + if (preference instanceof ListPreference) { + listPreference = (ListPreference) preference; + } else { + return; + } + final List accounts = + ImmutableList.copyOf( + Lists.transform( + xmppConnectionService.getAccounts(), + a -> a.getJid().asBareJid().toEscapedString())); + final ImmutableList.Builder entries = new ImmutableList.Builder<>(); + final ImmutableList.Builder entryValues = new ImmutableList.Builder<>(); + entries.add(getString(R.string.no_account_deactivated)); + entryValues.add("none"); + entries.addAll(accounts); + entryValues.addAll(accounts); + listPreference.setEntries(entries.build().toArray(new CharSequence[0])); + listPreference.setEntryValues(entryValues.build().toArray(new CharSequence[0])); + if (!accounts.contains(listPreference.getValue())) { + listPreference.setValue("none"); + } + } @Override public void onStart() { @@ -472,6 +504,10 @@ public class SettingsActivity extends XmppActivity implements OnSharedPreference } } else if (name.equals(PREVENT_SCREENSHOTS)) { SettingsUtils.applyScreenshotPreventionSetting(this); + } else if (UnifiedPushDistributor.PREFERENCES.contains(name)) { + if (xmppConnectionService.reconfigurePushDistributor()) { + xmppConnectionService.renewUnifiedPushEndpoints(); + } } } diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index 55f45c6b552d2d20e2a94dde99023cd069f47e56..b614251bd8b2a1b0c2495da21018382af946eab2 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -65,4 +65,5 @@ public final class Namespace { public static final String PARS = "urn:xmpp:pars:0"; public static final String EASY_ONBOARDING_INVITE = "urn:xmpp:invite#invite"; public static final String OMEMO_DTLS_SRTP_VERIFICATION = "http://gultsch.de/xmpp/drafts/omemo/dlts-srtp-verification"; + public static final String UNIFIED_PUSH = "http://gultsch.de/xmpp/drafts/unified-push"; } diff --git a/src/main/res/values/defaults.xml b/src/main/res/values/defaults.xml index 60085d0f9bb0c32636d8d429f15c429c1b43464b..288e4ae74a600311822a3f23eac149e5de74ff1e 100644 --- a/src/main/res/values/defaults.xml +++ b/src/main/res/values/defaults.xml @@ -45,4 +45,6 @@ 360 JABBER_NETWORK false + up.conversations.im + none diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 3fc93601fdd4c04c5a910d609a905a2ccb3e04c8..e5399c15e3ee8f0a6d22d48a5d0399be08d915c7 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -999,5 +999,11 @@ Calls are disabled when using Tor Switch to video Reject switch to video request + UnifiedPush Distributor + XMPP Account + The account through which push messages will be received. + Push Server + A user-chosen push server to relay push messages via XMPP to your device. + None (deactivated) diff --git a/src/main/res/xml/preferences.xml b/src/main/res/xml/preferences.xml index b461558364e17a73999bce7a22008292f6275cc0..b9ea7e871ae6485fe60d06dcdb3ca8d7a80245a1 100644 --- a/src/main/res/xml/preferences.xml +++ b/src/main/res/xml/preferences.xml @@ -206,6 +206,21 @@ android:summary="@string/pref_create_backup_summary" android:title="@string/pref_create_backup" /> + + + + + From 4ee5c167bedd4e1105c4a7b52536c8ab0eb6e37d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 4 Jan 2023 20:59:08 +0100 Subject: [PATCH 04/43] do not attempt endpoint renewal when account is disabled. renew on bind --- .../persistance/UnifiedPushDatabase.java | 8 +++++--- .../services/UnifiedPushBroker.java | 20 ++++++++++++++++++- .../services/XmppConnectionService.java | 1 + 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java index 9b17406f7641ce5711c072d78ec79b7be5c4efcb..e49db54d310418195743261edac6a093d1545f54 100644 --- a/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java +++ b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java @@ -84,13 +84,14 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper { public List getRenewals(final String account, final String transport) { final ImmutableList.Builder renewalBuilder = ImmutableList.builder(); + // TODO use a date somewhat in the future to account for period renewal triggers + final long expiration = System.currentTimeMillis(); final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); try (final Cursor cursor = sqLiteDatabase.query( "push", new String[] {"application", "instance"}, - "account <> ? OR transport <> ? OR expiration < " - + System.currentTimeMillis(), + "account <> ? OR transport <> ? OR expiration < " + expiration, new String[] {account, transport}, null, null, @@ -112,7 +113,8 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper { sqLiteDatabase.query( "push", new String[] {"application", "endpoint"}, - "account = ? AND transport = ? AND instance = ? ", + "account = ? AND transport = ? AND instance = ? AND endpoint IS NOT NULL AND expiration >= " + + System.currentTimeMillis(), new String[] {account, transport, instance}, null, null, diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java index 101a09fc3542cdd5e002dac0bbab71f541de5429..6e675cc2764b2e2a01079a198bd316c8037af16d 100644 --- a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java @@ -34,10 +34,28 @@ public class UnifiedPushBroker { this.service = xmppConnectionService; } + public void renewUnifiedPushEndpointsOnBind(final Account account) { + final Optional transport = getTransport(); + if (transport.isPresent()) { + final Account transportAccount = transport.get().account; + if (transportAccount != null && transportAccount.getUuid().equals(account.getUuid())) { + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + ": trigger endpoint renewal on bind"); + renewUnifiedEndpoint(transport.get()); + } + } + } + public Optional renewUnifiedPushEndpoints() { final Optional transportOptional = getTransport(); if (transportOptional.isPresent()) { - renewUnifiedEndpoint(transportOptional.get()); + final Transport transport = transportOptional.get(); + if (transport.account.isEnabled()) { + renewUnifiedEndpoint(transportOptional.get()); + } else { + Log.d(Config.LOGTAG, "skipping UnifiedPush endpoint renewal. Account is disabled"); + } } else { Log.d(Config.LOGTAG, "skipping UnifiedPush endpoint renewal. No transport selected"); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 22e7b38e545b371620c45703cb876914d68935b6..d3722053f88f9cf4f736c6290fea3a7fdf4db273 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -381,6 +381,7 @@ public class XmppConnectionService extends Service { connectMultiModeConversations(account); syncDirtyContacts(account); + unifiedPushBroker.renewUnifiedPushEndpointsOnBind(account); } }; private final AtomicLong mLastExpiryRun = new AtomicLong(0); From 7af0dda5afa8dbf4f7561409504eee73ba86adcf Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 6 Jan 2023 12:40:51 +0100 Subject: [PATCH 05/43] make short store description shorter --- fastlane/metadata/android/en-US/short_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt index 4b41cb27b46faaf707be06a6c7a83b98cebae6dd..7a2205c2b6e6fd37bd8e87a489f9e10294376a94 100644 --- a/fastlane/metadata/android/en-US/short_description.txt +++ b/fastlane/metadata/android/en-US/short_description.txt @@ -1 +1 @@ -An encrypted, user friendly XMPP instant messaging client optimized for mobile \ No newline at end of file +Encrypted, easy-to-use XMPP instant messenger for your mobile device From 1e0904a48db4fd85c02381c07062042cba1a765a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 6 Jan 2023 12:41:26 +0100 Subject: [PATCH 06/43] use less entropy in SASL2 device id --- .../conversations/utils/AccountUtils.java | 18 ++++++++++++++++++ .../conversations/xmpp/XmppConnection.java | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/eu/siacs/conversations/utils/AccountUtils.java b/src/main/java/eu/siacs/conversations/utils/AccountUtils.java index 8f04532189c656830454aadc8f75898400365285..b8f4855d0eec8856a71c2b1f91797e665861ec4b 100644 --- a/src/main/java/eu/siacs/conversations/utils/AccountUtils.java +++ b/src/main/java/eu/siacs/conversations/utils/AccountUtils.java @@ -8,6 +8,7 @@ import android.widget.Toast; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -34,6 +35,23 @@ public class AccountUtils { return false; } + public static String publicDeviceId(final Account account) { + final UUID uuid; + try { + uuid = UUID.fromString(account.getUuid()); + } catch (final IllegalArgumentException e) { + return account.getUuid(); + } + final UUID publicDeviceId = getUuid(uuid.getLeastSignificantBits(), uuid.getLeastSignificantBits()); + return publicDeviceId.toString(); + } + + protected static UUID getUuid(final long msb, final long lsb) { + final long msb0 = (msb & 0xffffffffffff0fffL) | 4; // set version + final long lsb0 = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // set variant + return new UUID(msb0, lsb0); + } + public static List getEnabledAccounts(final XmppConnectionService service) { ArrayList accounts = new ArrayList<>(); for (Account account : service.getAccounts()) { diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index a4761389555752d57da9059dcd9ab531a340d033..010cb76c715da4c1d61585f3c42479d3ec355ea7 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -77,6 +77,7 @@ import eu.siacs.conversations.services.MemorizingTrustManager; import eu.siacs.conversations.services.MessageArchiveService; import eu.siacs.conversations.services.NotificationService; import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.utils.AccountUtils; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.Patterns; import eu.siacs.conversations.utils.PhoneHelper; @@ -1534,7 +1535,7 @@ public class XmppConnection implements Runnable { authenticate.addChild("initial-response").setContent(firstMessage); } final Element userAgent = authenticate.addChild("user-agent"); - userAgent.setAttribute("id", account.getUuid()); + userAgent.setAttribute("id", AccountUtils.publicDeviceId(account)); userAgent .addChild("software") .setContent(mXmppConnectionService.getString(R.string.app_name)); From 0e10ae387a775eca63c25b61474cfe99ad973d21 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 6 Jan 2023 15:44:39 +0100 Subject: [PATCH 07/43] periodically renew endpoints --- .../persistance/UnifiedPushDatabase.java | 7 ++--- .../services/UnifiedPushBroker.java | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java index e49db54d310418195743261edac6a093d1545f54..1b1adc92fa0ebb84f88b6b15b48743a6bd56ff74 100644 --- a/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java +++ b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java @@ -19,6 +19,7 @@ import org.jetbrains.annotations.NotNull; import java.util.List; import eu.siacs.conversations.Config; +import eu.siacs.conversations.services.UnifiedPushBroker; public class UnifiedPushDatabase extends SQLiteOpenHelper { private static final String DATABASE_NAME = "unified-push-distributor"; @@ -84,8 +85,7 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper { public List getRenewals(final String account, final String transport) { final ImmutableList.Builder renewalBuilder = ImmutableList.builder(); - // TODO use a date somewhat in the future to account for period renewal triggers - final long expiration = System.currentTimeMillis(); + final long expiration = System.currentTimeMillis() + UnifiedPushBroker.TIME_TO_RENEW; final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); try (final Cursor cursor = sqLiteDatabase.query( @@ -108,13 +108,14 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper { public ApplicationEndpoint getEndpoint( final String account, final String transport, final String instance) { + final long expiration = System.currentTimeMillis() + UnifiedPushBroker.TIME_TO_RENEW; final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); try (final Cursor cursor = sqLiteDatabase.query( "push", new String[] {"application", "endpoint"}, "account = ? AND transport = ? AND instance = ? AND endpoint IS NOT NULL AND expiration >= " - + System.currentTimeMillis(), + + expiration, new String[] {account, transport, instance}, null, null, diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java index 6e675cc2764b2e2a01079a198bd316c8037af16d..5c6f1bbc8115f6fa27ca2ab8f5818945f1d30aba 100644 --- a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java @@ -15,6 +15,9 @@ import com.google.common.io.BaseEncoding; import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -28,10 +31,24 @@ import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class UnifiedPushBroker { + // time to expiration before a renewal attempt is made (24 hours) + public static final long TIME_TO_RENEW = 86_400_000L; + + // interval for the 'cron tob' that attempts renewals for everything that expires is lass than + // `TIME_TO_RENEW` + public static final long RENEWAL_INTERVAL = 3_600_000L; + + private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1); + private final XmppConnectionService service; public UnifiedPushBroker(final XmppConnectionService xmppConnectionService) { this.service = xmppConnectionService; + SCHEDULER.scheduleAtFixedRate( + this::renewUnifiedPushEndpoints, + RENEWAL_INTERVAL, + RENEWAL_INTERVAL, + TimeUnit.MILLISECONDS); } public void renewUnifiedPushEndpointsOnBind(final Account account) { @@ -68,6 +85,13 @@ public class UnifiedPushBroker { final List renewals = unifiedPushDatabase.getRenewals( account.getUuid(), transport.transport.toEscapedString()); + Log.d( + Config.LOGTAG, + account.getJid().asBareJid() + + ": " + + renewals.size() + + " UnifiedPush endpoints scheduled for renewal on " + + transport.transport); for (final UnifiedPushDatabase.PushTarget renewal : renewals) { Log.d( Config.LOGTAG, @@ -110,6 +134,8 @@ public class UnifiedPushBroker { return; } renewUnifiedPushEndpoint(transport, renewal, endpoint, expiration); + } else { + Log.d(Config.LOGTAG, "could not register UP endpoint " + response.getErrorCondition()); } } From b7c7c40b946bc21086e55db65c8dceb17a1907cf Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 6 Jan 2023 17:04:15 +0100 Subject: [PATCH 08/43] send directed presence to transport if endpoints are configured --- .../persistance/UnifiedPushDatabase.java | 15 ++++++++++++++ .../services/UnifiedPushBroker.java | 20 +++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java index 1b1adc92fa0ebb84f88b6b15b48743a6bd56ff74..f36506bd1db43a27fff4ad2264f226cd92e35d66 100644 --- a/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java +++ b/src/main/java/eu/siacs/conversations/persistance/UnifiedPushDatabase.java @@ -129,6 +129,21 @@ public class UnifiedPushDatabase extends SQLiteOpenHelper { return null; } + public boolean hasEndpoints(final UnifiedPushBroker.Transport transport) { + final SQLiteDatabase sqLiteDatabase = getReadableDatabase(); + try (final Cursor cursor = + sqLiteDatabase.rawQuery( + "SELECT EXISTS(SELECT endpoint FROM push WHERE account = ? AND transport = ?)", + new String[] { + transport.account.getUuid(), transport.transport.toEscapedString() + })) { + if (cursor != null && cursor.moveToFirst()) { + return cursor.getInt(0) > 0; + } + } + return false; + } + @Override public void onUpgrade( final SQLiteDatabase sqLiteDatabase, final int oldVersion, final int newVersion) {} diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java index 5c6f1bbc8115f6fa27ca2ab8f5818945f1d30aba..8bfd018a784e6fb13c225f3c90d5f8568967a760 100644 --- a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java @@ -28,6 +28,7 @@ import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.stanzas.IqPacket; +import eu.siacs.conversations.xmpp.stanzas.PresencePacket; public class UnifiedPushBroker { @@ -52,18 +53,29 @@ public class UnifiedPushBroker { } public void renewUnifiedPushEndpointsOnBind(final Account account) { - final Optional transport = getTransport(); - if (transport.isPresent()) { - final Account transportAccount = transport.get().account; + final Optional transportOptional = getTransport(); + if (transportOptional.isPresent()) { + final Transport transport = transportOptional.get(); + final Account transportAccount = transport.account; if (transportAccount != null && transportAccount.getUuid().equals(account.getUuid())) { + final UnifiedPushDatabase database = UnifiedPushDatabase.getInstance(service); + if (database.hasEndpoints(transport)) { + sendDirectedPresence(transportAccount, transport.transport); + } Log.d( Config.LOGTAG, account.getJid().asBareJid() + ": trigger endpoint renewal on bind"); - renewUnifiedEndpoint(transport.get()); + renewUnifiedEndpoint(transportOptional.get()); } } } + private void sendDirectedPresence(final Account account, Jid to) { + final PresencePacket presence = new PresencePacket(); + presence.setTo(to); + service.sendPresencePacket(account, presence); + } + public Optional renewUnifiedPushEndpoints() { final Optional transportOptional = getTransport(); if (transportOptional.isPresent()) { From e99655585219fd52c509efad8d0f1e7ede237c72 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 6 Jan 2023 20:32:35 +0100 Subject: [PATCH 09/43] remove footnote in magic create text --- src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index e5399c15e3ee8f0a6d22d48a5d0399be08d915c7..4edf1ae7d7f5a37a30ce8f2dce308a599e244cb8 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -544,7 +544,7 @@ Have some Quick Conversations
You sign up with your phone number and Quicksy will automatically—based on the phone numbers in your address book—suggest possible contacts to you.

By signing up you agree to our privacy policy.]]>
Agree and continue - A guide is set up for account creation on conversations.im.¹\nWhen picking conversations.im as a provider you will be able to communicate with users of other providers by giving them your full XMPP address. + A guide is set up for account creation on conversations.im.\nWhen picking conversations.im as a provider you will be able to communicate with users of other providers by giving them your full XMPP address. Your full XMPP address will be: %s Create Account Use my own provider From 20eb80d34915ca1df70061444daef2bc96f58e01 Mon Sep 17 00:00:00 2001 From: licaon-kter Date: Sun, 1 Jan 2023 14:28:39 +0000 Subject: [PATCH 10/43] Translated using Weblate (Romanian) Currently translated at 100.0% (956 of 956 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/ro/ --- src/main/res/values-ro-rRO/strings.xml | 83 ++++++++++++++------------ 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index ad37ec02eb8e546329e2275055213bf2521b1665..41eed3c7e09d9c3f98e7097744d068678ceb9f17 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -31,16 +31,11 @@ acum %d minute %d conversație necitită - - %d conversații necitite - - %d de conversații necitite - - trimitere... - Decriptez mesaj. Te rog așteaptă... + trimitere… + Decriptez mesaj. Te rog așteaptă… Mesaj criptat cu OpenPGP Numele de utilizator este deja alocat Nume invalid @@ -59,7 +54,7 @@ Ați dori să ștergeți %s din semne de carte? Conversațiile asociate cu acest semn de carte nu vor fi șterse. Înregistrează un cont nou pe server Schimbă parola pe server - Partajează cu... + Partajează cu… Pornește o conversație Invită contact Invită @@ -87,12 +82,14 @@ trimitere eșuată Se pregătește trimiterea imaginii Se pregătește trimiterea imaginilor - Trimitere fișiere. Te rog asteaptă... + Trimitere fișiere. Vă rugăm așteptați… Șterge istoric Șterge istoricul conversației Doriți să ștergeți toate mesajele din această conversație?\n\nAtenție: Această acțiune nu va afecta mesajele aflate pe alte dispozitive sau servere. Șterge fișierul - Sigur doriți să ștergeți acest fișier?\n\nAtenție: Această acțiune nu va șterge copiile acestui fișier care sunt stocate pe alte dispozitive sau servere. + Sigur doriți să ștergeți acest fișier\? +\n +\nAtenție: Această acțiune nu va șterge copiile acestui fișier care sunt stocate pe alte dispozitive sau servere. Închide conversația după ștergere Alege dispozitiv Trimite mesaje necriptate @@ -105,19 +102,19 @@ Trimite necriptat Decriptarea a eșuat. Poate nu aveți cheia privată corectă. OpenKeychain - OpenKeychain pentru a cripta și decripta mesaje și a administra cheile publice.\n\nOpenKeychain este licențiat sub GPLv3+ și este disponibil în F-Droid și Google Play.\n\n(Vă rugăm să reporniți %1$s după instalare.)]]> + %1$s utilizează <b>OpenKeychain</b> pentru a cripta și decripta mesaje și a administra cheile publice.<br><br>OpenKeychain este licențiat sub GPLv3+ și este disponibil în F-Droid și Google Play.<br><br><small>(Vă rugăm să reporniți %1$s după instalare.)</small> Repornește Instalare Va rugăm să instalați OpenKeychain - transmit... - în așteptare... + transmit… + în așteptare… Nu am găsit cheia OpenPGP Nu s-au putut cripta mesajele deoarece contactul nu își anunță cheile publice.\n\nRugați-vă contactul să își configureze OpenPGP. Nu am găsit chei OpenPGP Nu s-au putut cripta mesajele deoarece contactele nu își anunță cheile publice.\n\nRugați-vă contactele să își configureze OpenPGP. General Acceptă fișiere - Mai mici decât... + Mai mici decât… Atașamente Notificare Vibrează @@ -154,7 +151,9 @@ Nu s-a putut face convertirea imaginii Fișierul nu a fost găsit Eroare I/O generala. Poate ați rămas fără spațiu liber? - Aplicația folosită pentru selecția acestei imagini nu a oferit destule permisiuni pentru a putea citii fișierul.\n\nFolosiți un alt manager de fișiere pentru a alege o imagine + Aplicația folosită pentru selecția acestei imagini nu a oferit destule permisiuni pentru a putea citii fișierul. +\n +\nFolosiți un alt manager de fișiere pentru a alege o imagine. Aplicația pe care ați folosit-o pentru a partaja acest fișier nu a furnizat suficiente permisiuni. Necunoscut Dezactivat temporar @@ -196,7 +195,7 @@ numeutilizator@exemplu.ro Parolă Aceasta nu este o adresă XMPP valabilă - Memorie epuizată. Imaginea este prea mare. + Memorie epuizată. Imaginea este prea mare Vreți să adăugați pe %s în lista de contacte? Informații server XEP-0313: MAM @@ -228,7 +227,7 @@ v\\Amprenta OMEMO (originea mesajului) Alte dispozitive Amprente OMEMO de încredere - Se preiau cheile... + Se preiau cheile… Gata Decriptează Semne de carte @@ -254,7 +253,7 @@ Nu s-a putut distruge canalul Editează subiectul discuției de grup Subiect discuție - Vă alăturați discuției de grup... + Vă alăturați discuției de grup… Paraseste Contactul v-a adăugat în lista de contacte Adaugă contact @@ -264,7 +263,7 @@ Toate persoanele au citit până aici Publică Atingeți avatarul pentru a selecta o poză din galerie - Se publică... + Se publică… Acest server v-a refuzat publicarea Nu s-a putut face convertirea pozei Nu s-a putut salva avatarul pe disc @@ -282,7 +281,9 @@ Activează Discuția de grup necesită o parolă Introduceți parola - Vă rugăm să cereți mai întâi actualizări de prezență de la acest contact.\n\nAcestea vor fi folosite pentru a determina ce aplicații folosește contactul dumneavoastră. + Vă rugăm să cereți mai întâi actualizări de prezență de la acest contact. +\n +\nAcestea vor fi folosite pentru a determina ce aplicații folosește contactul dumneavoastră.. Cere acum Ignora Atenție: Trimițând aceasta fără actualizări de prezență reciproce ar putea produce probleme neprevazute.\n\nMergeți la \"Detalii contact\" pentru a verifica abonările la actualizările de prezență. @@ -371,8 +372,8 @@ A apărut o problemă Descarc istoric de pe server Nu mai exista istoric pe server - Actualizare... - Parolă schimbată + Actualizare… + Parolă schimbată! Nu s-a putut schimba parola Schimbare parolă Parola curentă @@ -430,9 +431,9 @@ Trimit %s Ofer %s Ascunde deconectat - %s tastează... + %s tastează… %s s-a oprit din scris - %s tastează... + %s tastează… %s s-au oprit din scris Notificare tastare Contactele sunt anunțate atunci când le scrieți un nou mesaj @@ -470,7 +471,7 @@ Acesta nu este un nume de utilizator valabil Descărcare eșuată: Serverul nu a fost găsit Descărcare eșuată: Fișierul nu a fost găsit - Descărcare eșuată: Nu s-a putut realiza conexiunea cu gazda. + Descărcare eșuată: Nu s-a putut realiza conexiunea cu gazda Descărcare eșuată: Nu s-a putut scrie fișierul Descărcarea a eșuat: Fișier invalid Rețeaua Tor nu este disponibilă @@ -491,7 +492,7 @@ Nu s-a putut analiza certificatul Preferințe arhivare Preferințe arhivare pe server - Se descarcă preferințe arhivare. Vă rugăm să așteptați... + Se descarcă preferințe arhivare. Vă rugăm să așteptați… Nu s-au putut descărca preferințele de arhivare Text captcha de verificare necesar Introduceți textul din imaginea de mai sus @@ -499,7 +500,7 @@ Adresa XMPP nu corespunde cu certificatul Înnoiește certificatul Eroare la preluarea cheii OMEMO! - Verifica cheia OMEMO cu un certificat + Sa verificat cheia OMEMO cu un certificat! Dispozitivul nu permite selectia unui certificat pentru client! Opțiuni conexiune Conectare prin Tor @@ -523,7 +524,10 @@ Permiteți %1$s acces la stocarea externă Permiteți %1$s acces la camera foto Sincronizează cu contactele - %1$s dorește permisiunea de a vă accesa contactele pentru a putea potrivi lista de contacte XMPP cu cea din dispozitiv și a afișa numele lor complete și avatarele.\n\n%1$s va citi și potrivi local fără a fi încărcate pe serverul dumneavoastră. + %1$s dorește permisiunea de a vă accesa contactele pentru a putea potrivi lista de contacte XMPP cu cea din dispozitiv. +\nAșa v-a afișa numele lor complete și avatarele. +\n +\n%1$s va citi și potrivi local fără a fi încărcate pe serverul dumneavoastră.
Nu vom stoca o copie a acestor numere the telefon.\n\nPentru mai multe informații puteți citii politica noastră de confidențialitate.

Urmează să fiți întrebați dacă doriți să permiteți accesul la contacte.]]>
Notifică la toate mesajele Notifică doar atunci când cineva vă menționează numele @@ -535,7 +539,9 @@ Doar imaginile mari Optimizare baterie activată Dispozitivul dumneavoastră încearcă să optimizeze agresiv consumul bateriei pentru %1$s, aceasta poate duce la notificări întârziate sau chiar pierderea mesajelor.\nEste recomandat sa le dezactivați. - Dispozitivul dumneavoastră încearcă să optimizeze agresiv consumul bateriei pentru %1$s, aceasta poate duce la notificări întârziate sau chiar pierderea mesajelor.\nÎn continuare veți fi rugați să le dezactivați. + Dispozitivul dumneavoastră încearcă să optimizeze agresiv consumul bateriei pentru %1$s, aceasta poate duce la notificări întârziate sau chiar pierderea mesajelor. +\n +\nÎn continuare veți fi rugați să le dezactivați. Dezactivează Zona selectată este prea mare (Nici un cont activat) @@ -546,7 +552,7 @@ Ați dezactivat acest cont Eroare de securitate.: Acces fișier invalid! Nu s-a găsit nici o aplicație care să partajeze adresa - Partajează adresa cu... + Partajează adresa cu…
Vă înscrieți cu numărul de telefon și Quicksy—pe baza numerelor de telefon din agenda dumneavoastră—vă va sugera automat posibile contacte.

Înscriindu-vă sunteți de acord cu politica noastră de confidențialitate.]]>
Sunt de acord și continuă Ghidul va configura un cont pe conversations.im.¹\nCând alegeți conversations.im ca furnizor veți putea comunica cu utilizatorii altor furnizori oferindu-le adresa dumneavoastră completă XMPP. @@ -567,7 +573,7 @@ Înregistrare eșuată: Încercați din nou mai târziu Înregistrare eșuată: Parolă nesigură Alegeți participanți - Se creează discuția de grup... + Se creează discuția de grup… Trimite din nou invitația Dezactivată Scurtă @@ -747,7 +753,7 @@ Arată locația Partajare Nu s-a putut pornii înregistrarea - Vă rugăm să așteptați... + Vă rugăm să așteptați… Permiteți %1$s acces la microfon Caută mesaje GIF @@ -815,13 +821,13 @@ Retrimite SMS (%s) %s înapoi - S-a copiat automat un posibil cod din memorie + S-a copiat automat un posibil cod din memorie. Vă rugăm să vă introduceți codul de 6 cifre. Sigur doriți să anulați procedura de înregistrare? Da Nu - Verificare... - Se cere SMS... + Se verifică… + Se cere SMS… Codul introdus este incorect. Codul pe care vi l-am trimis a expirat. Eroare de rețea necunoscută. @@ -870,7 +876,7 @@ Vă rugăm să furnizați un nume pentru canal Vă rugăm să furnizați o adresă XMPP Aceasta este o adresă XMPP. Vă rugăm să furnizați un nume. - Se creează canalul public... + Se creează canalul public… Acest canal există deja V-ați alăturat unui canal existent Nu s-a putut salva configurația canalului @@ -907,7 +913,7 @@ Acest cont a fost deja configurat Va rugăm să introduceți parola pentru acest cont Nu s-a putut realiza această acțiune - Alătură-te unui canal public... + Alătură-te unui canal public… Aplicația care a partajat nu a permis accesul la acest fișier. jabber.network @@ -1015,5 +1021,4 @@ Apelurile sunt dezactivate atunci când utilizați Tor Comută la video Respinge solicitarea de comutare la video - - + \ No newline at end of file From c515d30c559ac07e16ca89bc1aa164eab2d2f8ad Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Mon, 2 Jan 2023 18:23:33 +0000 Subject: [PATCH 11/43] Translated using Weblate (Spanish) Currently translated at 100.0% (9 of 9 strings) Translation: Conversations/Android App (Quicksy) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-quicksy/es/ --- src/quicksy/res/values-es/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/quicksy/res/values-es/strings.xml b/src/quicksy/res/values-es/strings.xml index fb93a9971a8f1e3a31fca5597a4454a9c1550335..153e61b43d1c3444081f380eb50715d9573487f3 100644 --- a/src/quicksy/res/values-es/strings.xml +++ b/src/quicksy/res/values-es/strings.xml @@ -1,10 +1,10 @@ - Cuánto tiempo Quicksy permanece en silencio después de detectar una actividad en otro dispositivo - Si elige enviar un informe de error, estará ayudando al desarrollo de Quicksy + El tiempo que Quicksy permanece en silencio después de ver actividad en otro dispositivo + Al enviar seguimientos del registro, está ayudando al desarrollo de Quicksy Informar a tus contactos cuando usas Quicksy - Para continuar recibiendo notificaciones incluso cuando la pantalla está apagada, debe agregar Quicksy a la lista de aplicaciones protegidas. - Foto de perfil de Quicksy + Para seguir recibiendo notificaciones, aunque la pantalla esté apagada, tienes que añadir Quicksy a la lista de aplicaciones protegidas. + Imagen de perfil Quicksy Quicksy no está disponible en tu país. No se ha podido verificar la identidad del servidor. Error de seguridad desconocido. From 1d7abd86a7442a13f361deb621dcfae4668ea82d Mon Sep 17 00:00:00 2001 From: nautilusx Date: Mon, 2 Jan 2023 16:46:34 +0000 Subject: [PATCH 12/43] Translated using Weblate (German) Currently translated at 100.0% (43 of 43 strings) Translation: Conversations/App Store Metadata Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/de/ --- fastlane/metadata/android/de-DE/changelogs/42044.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 fastlane/metadata/android/de-DE/changelogs/42044.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/42044.txt b/fastlane/metadata/android/de-DE/changelogs/42044.txt new file mode 100644 index 0000000000000000000000000000000000000000..27548eeab8fbc55978368e700b3451a762413f87 --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/42044.txt @@ -0,0 +1,3 @@ +* Nachrichten werden bei Verwendung von SASL2 nicht mehr erneut gesendet +* Schwarzes Video zwischen einigen Geräten behoben +* Absturz bei leeren Passwörtern behoben From 88d82375a68af9419060724c43c1b73edf9228a0 Mon Sep 17 00:00:00 2001 From: mmbd Date: Wed, 4 Jan 2023 19:39:30 +0000 Subject: [PATCH 13/43] Translated using Weblate (Japanese) Currently translated at 99.4% (951 of 956 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/ja/ --- src/main/res/values-ja/strings.xml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml index d788c54a5f0562ad7bb13eefffad583fe789dbf2..54035ec75803fb502fd7aa4d53859fc18c333d3b 100644 --- a/src/main/res/values-ja/strings.xml +++ b/src/main/res/values-ja/strings.xml @@ -31,7 +31,6 @@ %d分前 %d件の未読の会話 - 送信中… メッセージを復号しています。しばらくお待ちください… @@ -170,7 +169,7 @@ 互換性のない端末 ストリーム エラー ストリームを開く際にエラー - 暗号化されていない + 暗号化しない OTR OpenPGP OMEMO @@ -682,7 +681,7 @@ 未知の証明書を受け入れますか? サーバー証明書が既知の認証局によって署名されていません。 不一致のサーバー名を受け入れますか? - サーバーは\"%s\"として認証できませんでした。証明書は次の場合にのみ有効です: + サーバーは\"%s\"として認証できませんでした。証明書は次の場合にのみ有効です: それでも接続を希望しますか? 証明書の詳細: 一度だけ @@ -902,7 +901,7 @@ 通話受入 通話終了 応答 - 解散 + 拒否 デバイス発見 鳴動 取込中 @@ -978,4 +977,4 @@ アバターを削除 Tor使用中のため通話できません ビデオ通話切替 - + \ No newline at end of file From abb5a732ac0d4fc36f3be6690b3bc6ce2b1999c4 Mon Sep 17 00:00:00 2001 From: licaon-kter Date: Tue, 3 Jan 2023 20:46:59 +0000 Subject: [PATCH 14/43] Translated using Weblate (Romanian) Currently translated at 100.0% (956 of 956 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/ro/ --- src/main/res/values-ro-rRO/strings.xml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index 41eed3c7e09d9c3f98e7097744d068678ceb9f17..3f44591edfa47ad70eaf87485a68cf561014d408 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -35,7 +35,7 @@ %d de conversații necitite trimitere… - Decriptez mesaj. Te rog așteaptă… + Decriptare mesaj. Vă rugăm să așteptați… Mesaj criptat cu OpenPGP Numele de utilizator este deja alocat Nume invalid @@ -82,7 +82,7 @@ trimitere eșuată Se pregătește trimiterea imaginii Se pregătește trimiterea imaginilor - Trimitere fișiere. Vă rugăm așteptați… + Trimitere fișiere. Vă rugăm să așteptați… Șterge istoric Șterge istoricul conversației Doriți să ștergeți toate mesajele din această conversație?\n\nAtenție: Această acțiune nu va afecta mesajele aflate pe alte dispozitive sau servere. @@ -500,7 +500,7 @@ Adresa XMPP nu corespunde cu certificatul Înnoiește certificatul Eroare la preluarea cheii OMEMO! - Sa verificat cheia OMEMO cu un certificat! + Cheia OMEMO s-a verificat cu un certificat! Dispozitivul nu permite selectia unui certificat pentru client! Opțiuni conexiune Conectare prin Tor @@ -538,10 +538,11 @@ Mereu Doar imaginile mari Optimizare baterie activată - Dispozitivul dumneavoastră încearcă să optimizeze agresiv consumul bateriei pentru %1$s, aceasta poate duce la notificări întârziate sau chiar pierderea mesajelor.\nEste recomandat sa le dezactivați. + Dispozitivul dumneavoastră încearcă să optimizeze agresiv consumul bateriei pentru %1$s, aceasta poate duce la notificări întârziate sau chiar pierderea mesajelor. +\nEste recomandat să dezactivați optimizarea. Dispozitivul dumneavoastră încearcă să optimizeze agresiv consumul bateriei pentru %1$s, aceasta poate duce la notificări întârziate sau chiar pierderea mesajelor. \n -\nÎn continuare veți fi rugați să le dezactivați. +\nÎn continuare veți fi rugați să dezactivați optimizarea.
Dezactivează Zona selectată este prea mare (Nici un cont activat) @@ -590,7 +591,7 @@ Fundal verde Pentru mesajele primite Nu s-a putut face conectarea la OpenKeychain - Acest dispozitiv nu mai este in uz + Acest dispozitiv nu mai este în uz PC Telefon mobil Tabletă @@ -622,7 +623,7 @@ Codul de bare nu conține amprente pentru această conversație. Amprente verificate Folosește camera pentru a scana codul de bare al contactului - Asteptati cat se preiau cheile + Vă rugăm să așteptați până se preiau cheile Partajează un cod de bare Partajează ca adresă XMPP Partajează ca legatură HTTP @@ -808,7 +809,7 @@ Alegeți o țară număr de telefon Verificare număr de telefon - Quicksy va trimite un mesaj SMS (pot exista costuri în funcție de furnizor) pentru a vă verifica numărul de telefon. Introduceți codul țării dumneavoastră si numărul de telefon: + Quicksy va trimite un mesaj SMS (pot exista costuri în funcție de furnizor) pentru a vă verifica numărul de telefon. Introduceți codul țării dumneavoastră și numărul de telefon:
%s

Este în regulă sau ați dori să editați numărul?]]>
%s nu este un număr de telefon valid. Vă rugăm să vă introduceți numărul de telefon. @@ -819,7 +820,7 @@ Vă rugăm să introduceți codul de 6 cifre mai jos. Retrimitere SMS Retrimite SMS (%s) - %s + Vă rugăm să așteptați (%s) înapoi S-a copiat automat un posibil cod din memorie. Vă rugăm să vă introduceți codul de 6 cifre. From 58a8cdd36872718480f682bca1505f2f271d7a0e Mon Sep 17 00:00:00 2001 From: wiktor Date: Thu, 5 Jan 2023 11:12:08 +0000 Subject: [PATCH 15/43] Translated using Weblate (Polish) Currently translated at 100.0% (13 of 13 strings) Translation: Conversations/Android App (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-conversations/pl/ --- src/conversations/res/values-pl/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/res/values-pl/strings.xml b/src/conversations/res/values-pl/strings.xml index ac746f8e6c875559a08be758cd39331fe7fbe4f3..ecc67da8cfcac14f74bc8e72ef8136765cadb900 100644 --- a/src/conversations/res/values-pl/strings.xml +++ b/src/conversations/res/values-pl/strings.xml @@ -2,7 +2,7 @@ Wybierz dostawcę XMPP Użyj conversations.im - Stwórz nowe konto + Utwórz nowe konto Czy masz już konto XMPP? Tak może być jeśli używasz już innego klienta XMPP lub używałeś już Conversations. Jeśli nie możesz stworzyć nowe konto XMPP teraz.\nPodpowiedź: Niektórzy dostawcy poczty oferują również konta XMPP. XMPP to niezależna od dostawcy sieć komunikacji błyskawicznej. Możesz użyć tego klienta z dowolnym serwerem XMPP.\nDla twojej wygody jednak ułatwiliśmy stworzenie konta na conversations.im; dostawcy specjalnie dostosowanego do pracy z Conversations. Zostałeś zaproszony do %1$s. Poprowadzimy ciebie przez proces tworzenia konta.\nWybierając %1$s jako dostawcę będziesz mógł komunikować się z innymi użytkownikami podając swój pełny adres XMPP. From 8ca882d4aabde0f5712f3480490250e5ae493dbc Mon Sep 17 00:00:00 2001 From: nautilusx Date: Thu, 5 Jan 2023 07:51:47 +0000 Subject: [PATCH 16/43] Translated using Weblate (German) Currently translated at 100.0% (43 of 43 strings) Translation: Conversations/App Store Metadata Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/de/ --- fastlane/metadata/android/de-DE/short_description.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastlane/metadata/android/de-DE/short_description.txt b/fastlane/metadata/android/de-DE/short_description.txt index 52910ff20bea60419be42556559fa32c07b6698f..5249bddf27ae25cd426374a4eeb656d5fe88a2c4 100644 --- a/fastlane/metadata/android/de-DE/short_description.txt +++ b/fastlane/metadata/android/de-DE/short_description.txt @@ -1 +1 @@ -Ein verschlüsselter, benutzerfreundlicher XMPP-Instant-Messaging-Client, der für Smartphones optimiert ist +Verschlüsselter, benutzerfreundlicher XMPP-Instant-Messenger für dein Smartphone From 50bb8ab67ace0a598ec9d24bb75f86694857502a Mon Sep 17 00:00:00 2001 From: wiktor Date: Thu, 5 Jan 2023 11:14:22 +0000 Subject: [PATCH 17/43] Translated using Weblate (Polish) Currently translated at 2.3% (1 of 43 strings) Translation: Conversations/App Store Metadata Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/pl/ --- fastlane/metadata/android/pl-PL/short_description.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 fastlane/metadata/android/pl-PL/short_description.txt diff --git a/fastlane/metadata/android/pl-PL/short_description.txt b/fastlane/metadata/android/pl-PL/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..b5e95870191c142a8785f603d460d541e21a2585 --- /dev/null +++ b/fastlane/metadata/android/pl-PL/short_description.txt @@ -0,0 +1 @@ +Szyfrowany, prosty w użyciu klient XMPP przystosowany do urządzeń mobilnych From 89d2009e2fe4f99ca050d52b1f8c1628158fab87 Mon Sep 17 00:00:00 2001 From: nautilusx Date: Thu, 5 Jan 2023 22:03:12 +0000 Subject: [PATCH 18/43] Translated using Weblate (German) Currently translated at 100.0% (962 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/de/ --- src/main/res/values-de/strings.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index a135a9e90b60d5bf9717eb7473643268130ef76c..401b6b3eed1589547bddcc22d621c7de5685f5ec 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -614,7 +614,7 @@ Nutze die Kamera, um Barcodes deiner Kontakte zu scannen Bitte warten, bis die Schlüssel abgerufen werden Als Barcode teilen - Als XMPP URI teilen + Als XMPP-URI teilen Als HTTP Link teilen Blind vertrauen vor der Überprüfung Neuen Geräten von nicht verifizierten Kontakten vertrauen, aber bei verifizierten Kontakten eine manuelle Bestätigung der neuen Geräte verlangen. @@ -1000,4 +1000,10 @@ Anrufe sind bei der Verwendung von Tor deaktiviert Umschalten auf Video Umschalten auf Video ablehnen + XMPP-Konto + Push-Server + Ein selbst gewählter Push-Server, der Push-Nachrichten über XMPP an dein Gerät weiterleitet. + Kein (deaktiviert) + UnifiedPush Verteiler + Das Konto, über das Push-Nachrichten empfangen werden sollen. \ No newline at end of file From bb298eebd0fd51bffc974d17659d67492eafb747 Mon Sep 17 00:00:00 2001 From: licaon-kter Date: Fri, 6 Jan 2023 10:25:44 +0000 Subject: [PATCH 19/43] Translated using Weblate (Romanian) Currently translated at 100.0% (962 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/ro/ --- src/main/res/values-ro-rRO/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index 3f44591edfa47ad70eaf87485a68cf561014d408..42a918606a0d56b5e5ec345e30e301c9c2dcb5b3 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -1022,4 +1022,10 @@ Apelurile sunt dezactivate atunci când utilizați Tor Comută la video Respinge solicitarea de comutare la video + Cont XMPP + Server Push + Un server ales de utilizator pentru a intermedia mesajele push către dispozitivul vostru prin XMPP. + Nici unul (dezactivat) + Distribuitor UnifiedPush + Contul prin care vor fi primite notificările push. \ No newline at end of file From c7541cdd37718d029ebbeb01b0e3d9db9459ba25 Mon Sep 17 00:00:00 2001 From: hamburger1024 Date: Fri, 6 Jan 2023 02:18:24 +0000 Subject: [PATCH 20/43] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (962 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/zh_Hans/ --- src/main/res/values-zh-rCN/strings.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index 827f47f6f9026e44d0ed1e495d9b7ecde70ddf4c..f5d2d2e04e858f8102db10fa8d2bbfa4c44865f1 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -991,4 +991,10 @@ 使用 Tor 时通话被禁用 切换到视频 拒绝切换到视频的请求 + XMPP 账户 + 推送服务器 + 无(未激活) + UnifiedPush 分发程序 + 将通过该账户接收推送消息。 + 用户选择的推送服务器,通过 XMPP 将推送消息传递到你的设备。 \ No newline at end of file From 2b8dad3006c96ee4c18ff91c67016807d9041220 Mon Sep 17 00:00:00 2001 From: nautilusx Date: Fri, 6 Jan 2023 22:08:16 +0000 Subject: [PATCH 21/43] Translated using Weblate (German) Currently translated at 100.0% (962 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/de/ --- src/main/res/values-de/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml index 401b6b3eed1589547bddcc22d621c7de5685f5ec..e51229cc2a22232938f53137f066dab37811c5a9 100644 --- a/src/main/res/values-de/strings.xml +++ b/src/main/res/values-de/strings.xml @@ -545,7 +545,8 @@ Teile URI mit…
Du registrierst dich mit deiner Telefonnummer und Quicksy wird automatisch auf der Grundlage der Telefonnummern in deinem Adressbuch mögliche Kontakte vorschlagen.

Mit der Anmeldung erklärst du dich mit unserer Datenschutzerklärung einverstanden.]]>
Zustimmen und fortfahren - Ein Guide hilft bei der Kontoerstellung auf conversations.im.¹\nWenn du conversations.im als Provider wählst, kannst du mit Nutzern anderer Anbieter kommunizieren, indem du ihnen deine vollständige XMPP-Adresse gibst. + Ein Guide hilft bei der Kontoerstellung auf conversations.im. +\nWenn du conversations.im als Provider wählst, kannst du mit Nutzern anderer Anbieter kommunizieren, indem du ihnen deine vollständige XMPP-Adresse gibst. Deine vollständige XMPP-Adresse lautet: %s Konto erstellen Nutze eigenen Provider From 20fb420a247a252511e9998b10db96bb9fcbaa34 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Fri, 6 Jan 2023 20:04:48 +0000 Subject: [PATCH 22/43] Translated using Weblate (Polish) Currently translated at 99.8% (961 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/pl/ --- src/main/res/values-pl/strings.xml | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index b4e03f700fe07d9269ec25910ae72938065b39f9..6ecbdbc3eeab596cd5780f16669b4b81452a02f0 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -31,16 +31,9 @@ %d minut temu %d nieprzeczytana konwersacja - - %d nieprzeczytane konwersacje - - %d nieprzeczytanych konwersacji - - %d nieprzeczytanych konwersacji - wysyłanie... Odszyfrowywanie wiadomości. To zajmie tylko chwilę... @@ -95,7 +88,9 @@ Wyczyść historię konwersacji Czy chcesz usunąć wszystkie wiadomości w tej rozmowie?\n\nOstrzeżenie: To nie ma wpływu na wiadomości składowane na innych urządzeniach lub serwerach. Usuń plik - Czy na pewno usunąć ten plik?\n\nUwaga: Działanie nie wpływa na kopie pliku przechowywane na innych urządzeniach lub serwerach. + Czy na pewno usunąć ten plik\? +\n +\nUwaga: Działanie nie wpływa na kopie pliku przechowywane na innych urządzeniach lub serwerach. Zamknij konwersację po zakończeniu Wybierz urządzenie Wyślij wiadomość bez szyfrowania @@ -156,7 +151,7 @@ Wybrany plik nie jest obrazem Błąd konwersji obrazu Nie odnaleziono pliku - Ogólny błąd wejścia/wyjścia + Ogólny błąd wejścia/wyjścia. Być może skończyło się miejsce w pamięci\? Aplikacja użyta do wyboru obrazu nie zezwoliła na odczyt pliku.\n\nWybierz obraz przy użyciu innego menedżera plików Aplikacja której użyłeś do udostępnienia pliku nie dostarczyła odpowiednich uprawnień. Nieznany @@ -409,7 +404,7 @@ Spraw aby adres XMPP był widoczny dla wszystkich Włącz moderację na kanale Nie bierzesz udziału - Ustawienia konferencji zostały zmodyfikowane + Ustawienia konferencji zostały zmodyfikowane! Nie można zmodyfikować ustawień konferencji Nigdy Ręcznie @@ -468,7 +463,7 @@ Przeszukuj kontakty Przeszukaj zakładki Wyślij wiadomość prywatną - %1$s opuścił konferencję! + %1$s opuścił konferencję Nazwa użytkownika Nazwa użytkownika Błędna nazwa użytkownika @@ -503,8 +498,8 @@ Adres XMPP nie pasuje do certyfikatu Odnów certyfikat Błąd pobierania klucza OMEMO! - Zweryfikowano klucz OMEMO z certyfikatem - Twoje urządzenie nie wspiera wyboru certyfikatów klienckich + Zweryfikowano klucz OMEMO z certyfikatem! + Twoje urządzenie nie wspiera wyboru certyfikatów klienckich! Połączenie Połącz przez sieć TOR Tuneluj wszystkie połączenia przez sieć TOR. Wymaga zainstalowania aplikacji \"Orbot\" @@ -814,7 +809,7 @@ Administrator twojego serwera będzie mógł czytać twoje wiadomości, ale moż Wybierz kraj numer telefonu Zweryfikuj swój numer telefonu - Quicksy wyśle SMS (operator może naliczyć koszty) aby zweryfikować numer telefonu. Wpisz kod kraju i numer telefonu. + Quicksy wyśle wiadomość SMS (operator może naliczyć opłatę) aby zweryfikować numer telefonu. Wpisz kod kraju i numer telefonu:
%s

Czy wszystko się zgadza czy też chciałbyś zmienić numer?]]>
%s nie jest prawidłowym numerem telefonu Proszę wpisać swój numer telefonu. @@ -1032,5 +1027,10 @@ Administrator twojego serwera będzie mógł czytać twoje wiadomości, ale moż Dzwonienie jest wyłączone podczas używania Tora Przełącz na wideo Odrzuć prośbę przełączenia na wideo - - + Dystrybutor UnifiedPush + Konto XMPP + Konto, poprzez które będą odbierane powiadomienia push. + Serwer push + Dowolnie wybrany serwer push do przekazywania wiadomości push przez XMPP na Twoje urządzenie. + Brak (nieaktywne) + \ No newline at end of file From a6eb12588db192d31353a31838fe0b443ce9ff19 Mon Sep 17 00:00:00 2001 From: hamburger1024 Date: Sat, 7 Jan 2023 04:27:06 +0000 Subject: [PATCH 23/43] Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (962 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/zh_Hans/ --- src/main/res/values-zh-rCN/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml index f5d2d2e04e858f8102db10fa8d2bbfa4c44865f1..3152cd7f784007b1607bb3566737133ac0ec1044 100644 --- a/src/main/res/values-zh-rCN/strings.xml +++ b/src/main/res/values-zh-rCN/strings.xml @@ -547,7 +547,8 @@ 分享链接……
您注册了电话号码,Quicksy就会根据您的通讯录中的电话号码自动为您建议可能的联系人

签署即表示您同意我们的隐私政策。]]>
同意并继续 - 此向导将为您在conversations.im¹上创建一个账户。\n您的联系人可以通过您的XMPP完整地址与您聊天。 + 此向导将为您在conversations.im 上创建一个账户。 +\n您的联系人可以通过您的XMPP完整地址与您聊天。 您的XMPP完整地址将是:%s 创建账户 使用我自己的服务器 From c9b1883c41364e6b5c3c74cbe6e3094c63e9bf8e Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Fri, 6 Jan 2023 20:01:33 +0000 Subject: [PATCH 24/43] Translated using Weblate (Polish) Currently translated at 4.6% (2 of 43 strings) Translation: Conversations/App Store Metadata Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/pl/ --- fastlane/metadata/android/pl-PL/changelogs/42044.txt | 3 +++ fastlane/metadata/android/pl-PL/short_description.txt | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/pl-PL/changelogs/42044.txt diff --git a/fastlane/metadata/android/pl-PL/changelogs/42044.txt b/fastlane/metadata/android/pl-PL/changelogs/42044.txt new file mode 100644 index 0000000000000000000000000000000000000000..5098380e3848407a60fd652f25184b793b3c89cb --- /dev/null +++ b/fastlane/metadata/android/pl-PL/changelogs/42044.txt @@ -0,0 +1,3 @@ +* Naprawiono ponowne wysyłanie wiadomości podczas używania SASL2 +* Naprawiono czarny obraz wideo pomiędzy niektórymi urządzeniami +* Naprawiono awarię przy użyciu pustych haseł diff --git a/fastlane/metadata/android/pl-PL/short_description.txt b/fastlane/metadata/android/pl-PL/short_description.txt index b5e95870191c142a8785f603d460d541e21a2585..7869c1ba5ac150dfb0dd6d7c2e32d3eb9dac4a0f 100644 --- a/fastlane/metadata/android/pl-PL/short_description.txt +++ b/fastlane/metadata/android/pl-PL/short_description.txt @@ -1 +1 @@ -Szyfrowany, prosty w użyciu klient XMPP przystosowany do urządzeń mobilnych +Szyfrowany, prosty w użyciu komunikator XMPP dla Twojego urządzenia mobilnego From 3f6ec7e7c111765f1903fe464b81189032a530d2 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sat, 7 Jan 2023 12:34:46 +0000 Subject: [PATCH 25/43] Translated using Weblate (Spanish) Currently translated at 99.6% (959 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/es/ --- src/main/res/values-es/strings.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index 559051cc984fd4c65138d7e266ec3a6e7af770e8..e6e9087c2f524a768da5c8ef29df68e425387041 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -548,7 +548,7 @@ Compartir URI con… Quicksy es un derivado del popular cliente XMPP Conversations con detección automática de contactos.<br><br>El registro se realiza con tu número de teléfono y Quicksy automáticamente—basado en los teléfonos de tu agenda de contactos—te sugerirá posibles contactos.<br><br>Registrándote en Quicksy aceptas nuestra <a href=https://quicksy.im/#privacy>política de privacidad</a>. Aceptar y continuar - Una guía te ayudará en el proceso de creación de la cuenta en conversations.im.¹ + Una guía te ayudará en el proceso de creación de la cuenta en conversations.im. \nCuando selecciones conversations.im como proveedor podrás comunicarte con usuarios de otros servidores proporcionándoles tu dirección XMPP completa. Tu dirección XMPP completa será: %s Crear cuenta @@ -1015,4 +1015,7 @@ Las llamadas están deshabilitadas cuando se usa Tor Cambiar a vídeo Rechazar petición de cambiar a vídeo + Distribuidor de UnifiedPush + Cuenta XMPP + La cuenta a través de la cual se recibirán los mensajes push. \ No newline at end of file From 60308753bef7113c90eca1e848711040501b1283 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sat, 7 Jan 2023 12:38:11 +0000 Subject: [PATCH 26/43] Translated using Weblate (Spanish) Currently translated at 100.0% (962 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/es/ --- src/main/res/values-es/strings.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml index e6e9087c2f524a768da5c8ef29df68e425387041..234c5410e65301ed8fa0eb3a910f6cec139180c6 100644 --- a/src/main/res/values-es/strings.xml +++ b/src/main/res/values-es/strings.xml @@ -1018,4 +1018,7 @@ Distribuidor de UnifiedPush Cuenta XMPP La cuenta a través de la cual se recibirán los mensajes push. + Servidor push + Un servidor push elegido por el usuario para transmitir mensajes push a través de XMPP a su dispositivo. + Ninguno (desactivado) \ No newline at end of file From 50f05cee1c043e61b2f6564609bb6a6c7da00f6e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 7 Jan 2023 15:17:11 +0100 Subject: [PATCH 27/43] version bump to 2.12.0-beta --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index cc35ecb564143d7f321e318e685494ccba98cf00..87980397c32e0a5a1ba01942176ea3c467a90cbf 100644 --- a/build.gradle +++ b/build.gradle @@ -91,8 +91,8 @@ android { defaultConfig { minSdkVersion 21 targetSdkVersion 32 - versionCode 42044 - versionName "2.11.3" + versionCode 42045 + versionName "2.12.0-beta" archivesBaseName += "-$versionName" applicationId "eu.siacs.conversations" resValue "string", "applicationId", applicationId From 4670f643f3b086524d6cb282b1179597088c426e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 9 Jan 2023 12:31:06 +0100 Subject: [PATCH 28/43] add changelog ahead of release to allow translation --- CHANGELOG.md | 4 ++++ fastlane/metadata/android/en-US/changelogs/42046.txt | 1 + 2 files changed, 5 insertions(+) create mode 100644 fastlane/metadata/android/en-US/changelogs/42046.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 44f9829f840eea5020472eb3b6238f70fbd7a58a..36d2bd996f1edc13c28ce482171be26480b9091e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### Version 2.12.0 + +* Integrate UnifiedPush Distributor to facilitate push messages to other UnifiedPush enabled apps like Tusky and Fedilab + ### Version 2.11.3 * Fix messages getting resend when using SASL2 diff --git a/fastlane/metadata/android/en-US/changelogs/42046.txt b/fastlane/metadata/android/en-US/changelogs/42046.txt new file mode 100644 index 0000000000000000000000000000000000000000..2ca538cfbeeb24c3b783909e19a9cb4f1af0b286 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/42046.txt @@ -0,0 +1 @@ +* Integrate UnifiedPush Distributor to facilitate push messages to other UnifiedPush enabled apps like Tusky and Fedilab From 0ee82f6135d0c1836a93126f9157d30d70e2ffce Mon Sep 17 00:00:00 2001 From: licaon-kter Date: Sun, 8 Jan 2023 15:26:42 +0000 Subject: [PATCH 29/43] Translated using Weblate (Romanian) Currently translated at 100.0% (962 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/ro/ --- src/main/res/values-ro-rRO/strings.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-ro-rRO/strings.xml b/src/main/res/values-ro-rRO/strings.xml index 42a918606a0d56b5e5ec345e30e301c9c2dcb5b3..b8bb104aeddaf06aae216bfcbf206dbfe1c38613 100644 --- a/src/main/res/values-ro-rRO/strings.xml +++ b/src/main/res/values-ro-rRO/strings.xml @@ -556,7 +556,8 @@ Partajează adresa cu…
Vă înscrieți cu numărul de telefon și Quicksy—pe baza numerelor de telefon din agenda dumneavoastră—vă va sugera automat posibile contacte.

Înscriindu-vă sunteți de acord cu politica noastră de confidențialitate.]]>
Sunt de acord și continuă - Ghidul va configura un cont pe conversations.im.¹\nCând alegeți conversations.im ca furnizor veți putea comunica cu utilizatorii altor furnizori oferindu-le adresa dumneavoastră completă XMPP. + Ghidul va configura un cont pe conversations.im. +\nCând alegeți conversations.im ca furnizor veți putea comunica cu utilizatorii altor furnizori oferindu-le adresa dumneavoastră completă XMPP. Adresa dumneavoastră XMPP completă va fi: %s Creează cont Folosește furnizorul meu From 528a73741cd97d1e06f3430bd8ae91fe0229b474 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Sat, 7 Jan 2023 19:33:34 +0000 Subject: [PATCH 30/43] Translated using Weblate (Polish) Currently translated at 100.0% (13 of 13 strings) Translation: Conversations/Android App (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-conversations/pl/ --- src/conversations/res/values-pl/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversations/res/values-pl/strings.xml b/src/conversations/res/values-pl/strings.xml index ecc67da8cfcac14f74bc8e72ef8136765cadb900..f3771aed2fe0f81499a51111cf16007fc668eab6 100644 --- a/src/conversations/res/values-pl/strings.xml +++ b/src/conversations/res/values-pl/strings.xml @@ -12,5 +12,5 @@ Użyj przycisku udostępniania aby wysłać swojemu kontaktowi zaproszenie do %1$s. Jeśli twój kontakt jest blisko może przeskanować kod poniżej aby zaakceptować twoje zaproszenie. Dołącz do %1$s aby porozmawiać ze mną: %2$s - Udostępnij zaproszenie... + Udostępnij zaproszenie… \ No newline at end of file From ffe0b9ff5056979b4f2c62229d44e4057e5ba125 Mon Sep 17 00:00:00 2001 From: esk0rner Date: Sat, 7 Jan 2023 15:16:18 +0000 Subject: [PATCH 31/43] Translated using Weblate (Russian) Currently translated at 100.0% (13 of 13 strings) Translation: Conversations/Android App (Conversations) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-conversations/ru/ --- src/conversations/res/values-ru/strings.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/conversations/res/values-ru/strings.xml b/src/conversations/res/values-ru/strings.xml index a8194508990ecf49fbc3fe203de2d5d039a92efb..20b99a7b306327037393c73f51860fbdbd9d18e4 100644 --- a/src/conversations/res/values-ru/strings.xml +++ b/src/conversations/res/values-ru/strings.xml @@ -3,10 +3,13 @@ Выберите своего XMPP-провайдера Использовать conversations.im Создать новый аккаунт - У вас есть аккаунт XMPP? Если вы использовали Conversations или другой XMPP-клиент в прошлом, то скорее всего, он у вас есть. Если у вас нет аккаунта, вы можете создать его прямо сейчас.\nНекоторые провайдеры электронной почты также регистрируют аккаунты XMPP. + У вас есть аккаунт XMPP\? Если вы использовали Conversations или другой XMPP-клиент в прошлом, то скорее всего, он у вас есть. Если у вас нет аккаунта, вы можете создать его прямо сейчас. +\nПодсказка: Некоторые провайдеры электронной почты также регистрируют аккаунты XMPP. XMPP - это независимая сеть обмена сообщениями. Conversations позволяет вам подключиться к любому XMPP-серверу на ваш выбор.\nЕсли у вас нет сервера, предлагаем вам зарегистрировать аккаунт на conversations.im, сервере, специально предназначенном для работы с Conversations. - Вас пригласили на %1$s. Мы проведём вас через процесс создания аккаунта. Аккаунт на %1$s позволит вам общаться с пользователями и на этом, и на других серверах, используя ваш полный XMPP-адрес. - Вас пригласили на %1$s. Вам уже назначили имя пользователя. Мы проведём вас через процесс создания аккаунта. Этот аккаунт позволит вам общаться с пользователями и на этом, и на других серверах, используя ваш полный XMPP-адрес. + Вас пригласили на %1$s. Мы проведём вас через процесс создания аккаунта. +\nАккаунт на %1$s позволит вам общаться с пользователями и на этом, и на других серверах, используя ваш полный XMPP-адрес. + Вас пригласили на %1$s. Вам уже назначили имя пользователя. Мы проведём вас через процесс создания аккаунта. +\nЭтот аккаунт позволит вам общаться с пользователями и на этом, и на других серверах, используя ваш полный XMPP-адрес. Ваше приглашение Неправильный формат кода Нажмите кнопку «Поделиться», чтобы отправить вашему контакту приглашение в %1$s. From d6c693786de705d3b9e2a927298bc1670a57a19e Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Sat, 7 Jan 2023 19:34:23 +0000 Subject: [PATCH 32/43] Translated using Weblate (Polish) Currently translated at 100.0% (9 of 9 strings) Translation: Conversations/Android App (Quicksy) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-quicksy/pl/ --- src/quicksy/res/values-pl/strings.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/quicksy/res/values-pl/strings.xml b/src/quicksy/res/values-pl/strings.xml index 4794987b4b7d4b114fda0e0f434219b62cefa66d..d94b0c7750eb36d77ecbb2162c694b42fe5ba038 100644 --- a/src/quicksy/res/values-pl/strings.xml +++ b/src/quicksy/res/values-pl/strings.xml @@ -1,12 +1,12 @@ - Ilość czasu kiedy Quicksy jest cicho po zobaczeniu aktywności na innym urządzeniu. + Czas, przez który Quicksy jest cicho po zobaczeniu aktywności na innym urządzeniu Wysyłając nam ślady stosu pomagasz w rozwoju Quicksy Powiadom kontakty o tym że używasz Quicksy Aby otrzymywać powiadomienia nawet kiedy ekran jest wyłączony musisz dodać Quicksy do listy chronionych aplikacji. Obrazek profilowy Quicksy - Quicksy nie jest dostępne w twoim kraju + Quicksy nie jest dostępne w Twoim kraju. Nie udało się sprawdzić tożsamości serwera. Nieznany błąd bezpieczeństwa. Błąd czasu oczekiwania na połączenie z serwerem. - + \ No newline at end of file From 5f4fd7f37d7b2912994f191ec82761fa1ed4cd9b Mon Sep 17 00:00:00 2001 From: licaon-kter Date: Sun, 8 Jan 2023 15:27:40 +0000 Subject: [PATCH 33/43] Translated using Weblate (Romanian) Currently translated at 2.3% (1 of 43 strings) Translation: Conversations/App Store Metadata Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/ro/ --- fastlane/metadata/android/ro/short_description.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 fastlane/metadata/android/ro/short_description.txt diff --git a/fastlane/metadata/android/ro/short_description.txt b/fastlane/metadata/android/ro/short_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..143f7cb553d45a0c8e6e071289da4fe779414e69 --- /dev/null +++ b/fastlane/metadata/android/ro/short_description.txt @@ -0,0 +1 @@ +Client de mesagerie XMPP ușor de folosit, criptat, și optimizat pentru mobile From a128f49472c7bb07e56d9cf4eab6325e6a760e21 Mon Sep 17 00:00:00 2001 From: Grzegorz Szymaszek Date: Sat, 7 Jan 2023 20:23:52 +0000 Subject: [PATCH 34/43] Translated using Weblate (Polish) Currently translated at 6.9% (3 of 43 strings) Translation: Conversations/App Store Metadata Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/pl/ --- .../android/pl-PL/changelogs/42044.txt | 6 +-- .../android/pl-PL/full_description.txt | 39 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 fastlane/metadata/android/pl-PL/full_description.txt diff --git a/fastlane/metadata/android/pl-PL/changelogs/42044.txt b/fastlane/metadata/android/pl-PL/changelogs/42044.txt index 5098380e3848407a60fd652f25184b793b3c89cb..9afce457432a1a8eadf074c936a1142311479810 100644 --- a/fastlane/metadata/android/pl-PL/changelogs/42044.txt +++ b/fastlane/metadata/android/pl-PL/changelogs/42044.txt @@ -1,3 +1,3 @@ -* Naprawiono ponowne wysyłanie wiadomości podczas używania SASL2 -* Naprawiono czarny obraz wideo pomiędzy niektórymi urządzeniami -* Naprawiono awarię przy użyciu pustych haseł +* Naprawiono ponowne wysyłanie wiadomości podczas używania SASL2. +* Naprawiono czarny obraz wideo pomiędzy niektórymi urządzeniami. +* Naprawiono awarię przy użyciu pustych haseł. diff --git a/fastlane/metadata/android/pl-PL/full_description.txt b/fastlane/metadata/android/pl-PL/full_description.txt new file mode 100644 index 0000000000000000000000000000000000000000..bb1ca39195b43c0bb87d4e9a88c72ee6f5e9c3b6 --- /dev/null +++ b/fastlane/metadata/android/pl-PL/full_description.txt @@ -0,0 +1,39 @@ +Łatwy w użyciu, godny zaufania, przyjazny dla baterii. Wbudowane wsparcie dla obrazków, rozmów grupowych i szyfrowania od nadawcy do odbiorcy. + +Zasady projektu: + +* ma być tak ładny i prosty w użyciu jak to możliwe bez uszczerbku na bezpieczeństwie lub prywatności; +* używa istniejących, dobrze znanych protokołów; +* nie wymaga Konta Google ani, w szczególności, Google Cloud Messaging (GCM); +* wymaga tylko naprawdę koniecznych uprawnień. + +Funkcjonalność: + +* szyfrowanie od nadawcy do odbiorcy (E2EE) z użyciem OMEMO lub OpenPGP; +* wysyłanie i odbieranie obrazków; +* szyfrowane rozmowy głosowe i wideo; +* intuicyjny interfejs użytkownika, zgodny z wytycznymi Android Design; +* obrazki/awatary dla Twoich kontaktów; +* synchronizacja z klientem desktopowym; +* konferencje (z obsługą zakładek); +* integracja z książką adresową; +* wiele kont, zintegrowana skrzynka odbiorcza; +* bardzo ograniczony wpływ na zużycie baterii. + +Conversations bardzo ułatwia rejestrację konta na darmowym serwerze conversations.im, jednak będzie działać również z każdym innym serwerem XMPP. Wiele serwerów jest uruchamianych przez wolontariuszy i są dostępne za bez opłat. + +Funkcjonalność XMPP: + +Conversations działa z każdym dostępnym serwerem XMPP, jednak XMPP to rozszerzalny protokół. Rozszerzenia są ustandaryzowane w tak zwanych XEP. Conversations obsługuje sporo z nich, dzięki czemu można go przyjemniej używać. Jest jednak możliwość, że Twój obecny serwer nie obsługuje tych rozszerzeń. Aby wyciągnąć jak najwięcej z Conversations rozważ przeniesienie się na taki serwer, który je obsługuje, lub — jeszcze lepiej — uruchom własny serwer dla Ciebie i Twoich przyjaciół. + +Obecnie są obsługiwane następujące rozszerzenia: + +* XEP-0065: SOCKS5 Bytestreams (lub mod_proxy65). Będzie używany do przesyłania plików jeżeli obie strony znajdują się za zaporą (NAT); +* XEP-0163: Personal Eventing Protocol dla awatarów; +* XEP-0191: Blocking Command umożliwia ochronę przed spamerami lub blokowanie bez usuwanie ich z rostera; +* XEP-0198: Stream Management pozwala na przetrwanie krótkich braków połączenia z siecią oraz zmian używanego połączenia TCP; +* XEP-0280: Message Carbons automatycznie synchronizuje wysyłane wiadomości z klientem desktopowym i w ten sposób pozwala na proste używanie zarówno klienta mobilnego, jak i desktopowego, w jednej konwersacji; +* XEP-0237: Roster Versioning, dzięki któremu można ograniczyć używanie sieci na słabych połączeniach komórkowych; +* XEP-0313: Message Archive Management synchronizuje historię wiadomości z serwerem. Bądź na bieżąco z wiadomości wysłanymi gdy Conversations był rozłączony; +* XEP-0352: Client State Indication informuje serwer o tym, czy Conversations działa w tle. Pozwala to na oszczędzanie łącza przez wstrzymywanie mniej ważnych komunikatów; +* XEP-0363: HTTP File Upload umożliwia udostępnianie plików w konferencjach oraz rozłączonym kontaktom. Wymaga dodatkowego komponentu na Twoim serwerze. From caa5c519f12f6e1b5baa1635981b176c144120b4 Mon Sep 17 00:00:00 2001 From: ewm Date: Sun, 8 Jan 2023 19:54:53 +0000 Subject: [PATCH 35/43] Translated using Weblate (Polish) Currently translated at 100.0% (962 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/pl/ --- src/main/res/values-pl/strings.xml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml index 6ecbdbc3eeab596cd5780f16669b4b81452a02f0..fc021fdc623519052abbd986e41782d5972b9a7e 100644 --- a/src/main/res/values-pl/strings.xml +++ b/src/main/res/values-pl/strings.xml @@ -35,8 +35,8 @@ %d nieprzeczytanych konwersacji %d nieprzeczytanych konwersacji - wysyłanie... - Odszyfrowywanie wiadomości. To zajmie tylko chwilę... + wysyłanie… + Odszyfrowywanie wiadomości. To zajmie tylko chwilę… Wiadomość zaszyfrowana OpenPGP Nazwa jest już w użyciu NIeprawidłowy pseudonim @@ -55,7 +55,7 @@ Czy chcesz usunąć zakładkę %s? Rozmowy z tą zakładką nie zostaną usunięte. Zarejestruj nowe konto na serwerze Zmień hasło na serwerze - Udostępnij... + Udostępnij… Rozpocznij rozmowę Zaproś kontakt Zaproś @@ -83,7 +83,7 @@ wysyłanie nie powiodło się Przygotowanie do wysłania obrazka Przygotowanie do wysłania obrazków - Udostępnianie plików. Proszę czekać... + Udostępnianie plików. Proszę czekać… Wyczyść historię Wyczyść historię konwersacji Czy chcesz usunąć wszystkie wiadomości w tej rozmowie?\n\nOstrzeżenie: To nie ma wpływu na wiadomości składowane na innych urządzeniach lub serwerach. @@ -107,8 +107,8 @@ Zrestartuj Zainstaluj Proszę zainstalować OpenKeychain - oferowanie... - oczekiwanie... + oferowanie… + oczekiwanie… Nie znaleziono klucza OpenPGP Nie można zaszyfrować twojej wiadomości bo ten kontakt nie ogłasza swojego publicznego klucza.\n\nPoproś kontakt aby ustawił OpenPGP. Nie znaleziono kluczy OpenPGP @@ -199,10 +199,10 @@ Informacje o serwerze XEP-0313: MAM XEP-0280: Kopie wiadomości - XEP-0352: Client State Indication - XEP-0191: Blocking Command + XEP-0352: Wskaźnik stanu klienta + XEP-0191: Polecenia Blokujące XEP-0237: Roster Versioning - XEP-0198: Stream Management + XEP-0198: Zarządzanie Strumieniem XEP-0215: Wykrywanie Zewnętrznych Usług XEP-0163: PEP (Awatary / OMEMO) XEP-0363: Przesyłanie plików przez HTTP @@ -549,7 +549,8 @@ Udostępnij URI za pomocą...
Zapisujesz się przy użyciu numeru telefonu i Quicksy automatycznie - na podstawie numerów telefonów w książce adresowej - zasugeruje potencjalne kontakty dla ciebie.

Zapisując się zgadzasz się na naszą politykę prywatności.]]>
Zgoda i kontynuuj - Poprowadzimy ciebie przez proces tworzenia konta na conversations.im.¹\nKiedy wybierzesz conversations.im jako dostawcę będziesz mógł komunikować się z innymi osobami jeśli podasz im swój pełen adres XMPP. + Poprowadzimy cię przez proces tworzenia konta na conversations.im. +\nKiedy wybierzesz conversations.im jako dostawcę będziesz mógł komunikować się z innymi osobami jeśli podasz im swój pełen adres XMPP. Twój pełen adres XMPP to: %s Utwórz konto Użyj innego serwera From 86394e3da73566ee086cd28589e3eb7288f0f4c5 Mon Sep 17 00:00:00 2001 From: nautilusx Date: Mon, 9 Jan 2023 12:05:23 +0000 Subject: [PATCH 36/43] Translated using Weblate (German) Currently translated at 100.0% (44 of 44 strings) Translation: Conversations/App Store Metadata Translate-URL: https://translate.codeberg.org/projects/conversations/app-store-metadata/de/ --- fastlane/metadata/android/de-DE/changelogs/42046.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 fastlane/metadata/android/de-DE/changelogs/42046.txt diff --git a/fastlane/metadata/android/de-DE/changelogs/42046.txt b/fastlane/metadata/android/de-DE/changelogs/42046.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed6e4bb38d9cb93ade5226bd92ec1c309e8d1354 --- /dev/null +++ b/fastlane/metadata/android/de-DE/changelogs/42046.txt @@ -0,0 +1 @@ +* Integration eines UnifiedPush-Verteilers, um Push-Nachrichten für andere UnifiedPush-fähige Apps wie Tusky und Fedilab zu ermöglichen From 0923440936155b771050ef97ead94a8dd48769f6 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 10 Jan 2023 09:02:32 +0100 Subject: [PATCH 37/43] version bump to 2.12.0 --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 87980397c32e0a5a1ba01942176ea3c467a90cbf..652f20262d421cfeff294fb6a9b8c886e61f5d2d 100644 --- a/build.gradle +++ b/build.gradle @@ -91,8 +91,8 @@ android { defaultConfig { minSdkVersion 21 targetSdkVersion 32 - versionCode 42045 - versionName "2.12.0-beta" + versionCode 42046 + versionName "2.12.0" archivesBaseName += "-$versionName" applicationId "eu.siacs.conversations" resValue "string", "applicationId", applicationId From 41cd96e37b9beeb7a4239ea4ea1ffac49cfc2b72 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 10 Jan 2023 17:22:48 +0100 Subject: [PATCH 38/43] UP: null check transport verification --- .../services/UnifiedPushBroker.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java index 8bfd018a784e6fb13c225f3c90d5f8568967a760..7d2d90dd5777b4aebc028f2366fe90b77cbf0f60 100644 --- a/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java +++ b/src/main/java/eu/siacs/conversations/services/UnifiedPushBroker.java @@ -6,19 +6,10 @@ import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.preference.PreferenceManager; import android.util.Log; - import com.google.common.base.Optional; import com.google.common.base.Strings; import com.google.common.collect.Iterables; import com.google.common.io.BaseEncoding; - -import java.nio.charset.StandardCharsets; -import java.text.ParseException; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; @@ -29,6 +20,12 @@ import eu.siacs.conversations.xml.Namespace; import eu.siacs.conversations.xmpp.Jid; import eu.siacs.conversations.xmpp.stanzas.IqPacket; import eu.siacs.conversations.xmpp.stanzas.PresencePacket; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; public class UnifiedPushBroker { @@ -278,6 +275,9 @@ public class UnifiedPushBroker { final Jid transport, final String application, final String instance) { + if (transport == null || application == null || instance == null) { + return Optional.absent(); + } final String uuid = account.getUuid(); final List pushTargets = UnifiedPushDatabase.getInstance(service) From a5e380a1af5534f1d68ef7d9819e8180a6ad141a Mon Sep 17 00:00:00 2001 From: Besnik_b Date: Tue, 10 Jan 2023 10:26:07 +0000 Subject: [PATCH 39/43] Added translation using Weblate (Albanian) --- src/conversations/res/values-sq/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/conversations/res/values-sq/strings.xml diff --git a/src/conversations/res/values-sq/strings.xml b/src/conversations/res/values-sq/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6b3daec9354f9ae75cdf8d94a67446c6227dd96 --- /dev/null +++ b/src/conversations/res/values-sq/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From d5e2b6ff6dd80061b9e388556d4997df4f219f47 Mon Sep 17 00:00:00 2001 From: Besnik_b Date: Tue, 10 Jan 2023 10:27:58 +0000 Subject: [PATCH 40/43] Added translation using Weblate (Albanian) --- src/quicksy/res/values-sq/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/quicksy/res/values-sq/strings.xml diff --git a/src/quicksy/res/values-sq/strings.xml b/src/quicksy/res/values-sq/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..a6b3daec9354f9ae75cdf8d94a67446c6227dd96 --- /dev/null +++ b/src/quicksy/res/values-sq/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 670fb0c2c013ba34675a864a5e822b4fbc5e53ec Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Tue, 10 Jan 2023 19:40:57 +0000 Subject: [PATCH 41/43] Translated using Weblate (Spanish) Currently translated at 100.0% (9 of 9 strings) Translation: Conversations/Android App (Quicksy) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-quicksy/es/ --- src/quicksy/res/values-es/strings.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/quicksy/res/values-es/strings.xml b/src/quicksy/res/values-es/strings.xml index 153e61b43d1c3444081f380eb50715d9573487f3..9b9f07ad18fa04307cbc3ae9031eb11f272b5686 100644 --- a/src/quicksy/res/values-es/strings.xml +++ b/src/quicksy/res/values-es/strings.xml @@ -1,10 +1,10 @@ - El tiempo que Quicksy permanece en silencio después de ver actividad en otro dispositivo - Al enviar seguimientos del registro, está ayudando al desarrollo de Quicksy + Cuánto tiempo Quicksy permanece en silencio después de ver actividad en otros dispositivos + Al enviar los seguimientos del registro, está ayudando al desarrollo de Quicksy Informar a tus contactos cuando usas Quicksy - Para seguir recibiendo notificaciones, aunque la pantalla esté apagada, tienes que añadir Quicksy a la lista de aplicaciones protegidas. - Imagen de perfil Quicksy + Para continuar recibiendo notificaciones incluso cuando la pantalla está apagada, debe agregar Quicksy a la lista de aplicaciones protegidas. + Imagen del perfil de Quicksy Quicksy no está disponible en tu país. No se ha podido verificar la identidad del servidor. Error de seguridad desconocido. From e4d79386c84be82bd46d832e7e7fdff894de4b92 Mon Sep 17 00:00:00 2001 From: ghose Date: Thu, 12 Jan 2023 05:04:01 +0000 Subject: [PATCH 42/43] Translated using Weblate (Galician) Currently translated at 100.0% (962 of 962 strings) Translation: Conversations/Android App (shared) Translate-URL: https://translate.codeberg.org/projects/conversations/android-app-shared/gl/ --- src/main/res/values-gl/strings.xml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/res/values-gl/strings.xml b/src/main/res/values-gl/strings.xml index 6a50166816322e4628e9e2633354f48be56aba5e..377b7da8b8e988da41ac97b1be00c98efeb889d5 100644 --- a/src/main/res/values-gl/strings.xml +++ b/src/main/res/values-gl/strings.xml @@ -547,7 +547,8 @@ Compartir URI con…
Podes rexistrarte co teu número de teléfono e Quicksy suxerirache automáticamente —tomando os números da túa libreta de enderezos como referencia— posibles contactos para ti.

Ao rexistrarte aceptas a nosa política de privacidade.]]>
Aceptar e continuar - Tes unha guía para crear unha conta en conversations.im¹\nAo escoller conversations.im como provedor poderás comunicarte con outras usuarias de outros provedores con só darlles o teu enderezo XMPP completo. + Tes unha guía para crear unha conta en conversations.im +\nAo escoller conversations.im como provedor poderás comunicarte con outras usuarias de outros provedores con só darlles o teu enderezo XMPP completo. O teu enderezo XMPP completo será: %s Crear conta Utilizar o meu propio proveedor @@ -1003,4 +1004,10 @@ As chamadas están desactivadas cando usas Tor Cambiar a vídeo Rexeitar a solicitude para cambiar a vídeo + Distribuidor UnifiedPush + Conta XMPP + A conta a través da cal se recibirán as mensaxes push. + Servidor Push + O servidor elexido pola usuaria para obter as mensaxes push a través de XMPP. + Ningún (desactivado)
\ No newline at end of file From e91b6ce37744bf508a1e0fe37cee88cdea339566 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 12 Jan 2023 09:41:10 +0100 Subject: [PATCH 43/43] version bump to 2.12.1 --- CHANGELOG.md | 4 ++++ build.gradle | 4 ++-- fastlane/metadata/android/en-US/changelogs/42047.txt | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/42047.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 36d2bd996f1edc13c28ce482171be26480b9091e..b5ef2e389ab0557028afff675640675948865bbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### Version 2.12.1 + +* Fix crash in UnifiedPush Distributor + ### Version 2.12.0 * Integrate UnifiedPush Distributor to facilitate push messages to other UnifiedPush enabled apps like Tusky and Fedilab diff --git a/build.gradle b/build.gradle index 652f20262d421cfeff294fb6a9b8c886e61f5d2d..37c0d856f57531cac32fa8e0cedecf3d67161ff5 100644 --- a/build.gradle +++ b/build.gradle @@ -91,8 +91,8 @@ android { defaultConfig { minSdkVersion 21 targetSdkVersion 32 - versionCode 42046 - versionName "2.12.0" + versionCode 42047 + versionName "2.12.1" archivesBaseName += "-$versionName" applicationId "eu.siacs.conversations" resValue "string", "applicationId", applicationId diff --git a/fastlane/metadata/android/en-US/changelogs/42047.txt b/fastlane/metadata/android/en-US/changelogs/42047.txt new file mode 100644 index 0000000000000000000000000000000000000000..c44467f526305cc8bda306bf3934d61675817367 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/42047.txt @@ -0,0 +1 @@ +* Fix crash in UnifiedPush Distributor