Compare commits

...

13 Commits

Author SHA1 Message Date
akwizgran
5a25d77d15 Add migration that drops offers table. 2020-11-03 17:31:22 +00:00
akwizgran
79142b2e97 Return early before allocating list. 2020-11-03 17:31:22 +00:00
akwizgran
0b2c84c53b Rename events. 2020-11-03 17:31:21 +00:00
akwizgran
8cbd27c011 Broadcast message IDs to request instead of storing them. 2020-11-03 17:31:19 +00:00
akwizgran
2962afa6f1 Restrict getMessage() method to small messages. 2020-11-03 17:19:39 +00:00
akwizgran
4490a2cd3f Add database methods for selecting small messages. 2020-11-03 16:57:50 +00:00
akwizgran
e2dbc92083 Log migration times. 2020-11-03 16:56:37 +00:00
akwizgran
4fd3970b4f Create blocks table. 2020-11-03 16:55:38 +00:00
akwizgran
46da4aa59e Close statements after running migrations. 2020-11-03 16:51:36 +00:00
Torsten Grote
64e1975cf1 Merge branch 'adaptive-icon' into 'master'
Add adaptive icon for API 26+ and Play Store icon

Closes #1456

See merge request briar/briar!1293
2020-11-03 11:55:12 +00:00
akwizgran
993502add0 Add adaptive icon for API 26+ and Play Store icon. 2020-11-03 11:35:53 +00:00
akwizgran
54893d2716 Bump version numbers for 1.2.12 release. 2020-11-02 14:51:34 +00:00
akwizgran
84657127b8 Update translations. 2020-11-02 14:50:06 +00:00
107 changed files with 893 additions and 679 deletions

View File

@@ -31,15 +31,6 @@
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value />
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
/**
* An item that can be consumed once.
*/
@NotNullByDefault
public class Consumable<T> {
private final AtomicReference<T> reference;
public Consumable(T item) {
reference = new AtomicReference<>(item);
}
@Nullable
public T consume() {
return reference.getAndSet(null);
}
}

View File

@@ -35,24 +35,24 @@ public interface ClientHelper {
Message createMessageForStoringMetadata(GroupId g);
Message getMessage(MessageId m) throws DbException;
Message getSmallMessage(MessageId m) throws DbException;
Message getMessage(Transaction txn, MessageId m) throws DbException;
Message getSmallMessage(Transaction txn, MessageId m) throws DbException;
BdfList getMessageAsList(MessageId m) throws DbException, FormatException;
BdfList getSmallMessageAsList(MessageId m)
throws DbException, FormatException;
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
FormatException;
BdfList getSmallMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException;
BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException,
FormatException;
BdfDictionary getGroupMetadataAsDictionary(GroupId g)
throws DbException, FormatException;
BdfDictionary getGroupMetadataAsDictionary(Transaction txn, GroupId g)
throws DbException, FormatException;
BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException,
FormatException;
throws DbException, FormatException;
BdfDictionary getMessageMetadataAsDictionary(Transaction txn, MessageId m)
throws DbException, FormatException;
@@ -67,8 +67,8 @@ public interface ClientHelper {
BdfDictionary query) throws DbException, FormatException;
Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
Transaction txn, GroupId g, BdfDictionary query) throws DbException,
FormatException;
Transaction txn, GroupId g, BdfDictionary query)
throws DbException, FormatException;
void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
throws DbException, FormatException;

View File

@@ -163,27 +163,23 @@ public interface DatabaseComponent extends TransactionManager {
* less than or equal to the given length, for transmission over a
* transport with the given maximum latency. Returns null if there are no
* sendable messages that fit in the given length.
*
* @param small True if only single-block messages should be sent
*/
@Nullable
Collection<Message> generateBatch(Transaction txn, ContactId c,
int maxLength, int maxLatency) throws DbException;
int maxLength, int maxLatency, boolean small) throws DbException;
/**
* Returns an offer for the given contact for transmission over a
* transport with the given maximum latency, or null if there are no
* messages to offer.
*
* @param small True if only single-block messages should be offered
*/
@Nullable
Offer generateOffer(Transaction txn, ContactId c, int maxMessages,
int maxLatency) throws DbException;
/**
* Returns a request for the given contact, or null if there are no
* messages to request.
*/
@Nullable
Request generateRequest(Transaction txn, ContactId c, int maxMessages)
throws DbException;
int maxLatency, boolean small) throws DbException;
/**
* Returns a batch of messages for the given contact, with a total length
@@ -272,13 +268,14 @@ public interface DatabaseComponent extends TransactionManager {
Collection<Identity> getIdentities(Transaction txn) throws DbException;
/**
* Returns the message with the given ID.
* Returns the single-block message with the given ID.
* <p/>
* Read-only.
*
* @throws MessageDeletedException if the message has been deleted
* @throws MessageTooLargeException if the message has more than one block
*/
Message getMessage(Transaction txn, MessageId m) throws DbException;
Message getSmallMessage(Transaction txn, MessageId m) throws DbException;
/**
* Returns the IDs of all delivered messages in the given group.

View File

@@ -0,0 +1,8 @@
package org.briarproject.bramble.api.db;
/**
* Thrown when a multi-block message is requested from the database via a
* method that is only suitable for requesting single-block messages.
*/
public class MessageTooLargeException extends DbException {
}

View File

@@ -29,10 +29,15 @@ public interface SyncConstants {
*/
int MESSAGE_HEADER_LENGTH = UniqueId.LENGTH + 8;
/**
* The maximum length of a block in bytes.
*/
int MAX_BLOCK_LENGTH = 32 * 1024; // 32 KiB
/**
* The maximum length of a message body in bytes.
*/
int MAX_MESSAGE_BODY_LENGTH = 32 * 1024; // 32 KiB
int MAX_MESSAGE_BODY_LENGTH = MAX_BLOCK_LENGTH;
/**
* The maximum length of a message in bytes.

View File

@@ -1,26 +0,0 @@
package org.briarproject.bramble.api.sync.event;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a message is offered by a contact and needs
* to be requested.
*/
@Immutable
@NotNullByDefault
public class MessageToRequestEvent extends Event {
private final ContactId contactId;
public MessageToRequestEvent(ContactId contactId) {
this.contactId = contactId;
}
public ContactId getContactId() {
return contactId;
}
}

View File

@@ -7,16 +7,16 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a message is received from, or offered by, a
* contact and needs to be acknowledged.
* An event that is broadcast when one or more messages are received from, or
* offered by, a contact and need to be acknowledged.
*/
@Immutable
@NotNullByDefault
public class MessageToAckEvent extends Event {
public class MessagesToAckEvent extends Event {
private final ContactId contactId;
public MessageToAckEvent(ContactId contactId) {
public MessagesToAckEvent(ContactId contactId) {
this.contactId = contactId;
}

View File

@@ -0,0 +1,39 @@
package org.briarproject.bramble.api.sync.event;
import org.briarproject.bramble.api.Consumable;
import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageId;
import java.util.Collection;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when one or more messages are offered by a
* contact and need to be requested.
*/
@Immutable
@NotNullByDefault
public class MessagesToRequestEvent extends Event {
private final ContactId contactId;
private final Consumable<Collection<MessageId>> ids;
public MessagesToRequestEvent(ContactId contactId,
Collection<MessageId> ids) {
this.contactId = contactId;
this.ids = new Consumable<>(ids);
}
public ContactId getContactId() {
return contactId;
}
@Nullable
public Collection<MessageId> consumeIds() {
return ids.consume();
}
}

View File

@@ -116,25 +116,27 @@ class ClientHelperImpl implements ClientHelper {
}
@Override
public Message getMessage(MessageId m) throws DbException {
return db.transactionWithResult(true, txn -> getMessage(txn, m));
public Message getSmallMessage(MessageId m) throws DbException {
return db.transactionWithResult(true, txn -> getSmallMessage(txn, m));
}
@Override
public Message getMessage(Transaction txn, MessageId m) throws DbException {
return db.getMessage(txn, m);
public Message getSmallMessage(Transaction txn, MessageId m)
throws DbException {
return db.getSmallMessage(txn, m);
}
@Override
public BdfList getMessageAsList(MessageId m) throws DbException,
FormatException {
return db.transactionWithResult(true, txn -> getMessageAsList(txn, m));
}
@Override
public BdfList getMessageAsList(Transaction txn, MessageId m)
public BdfList getSmallMessageAsList(MessageId m)
throws DbException, FormatException {
return toList(db.getMessage(txn, m).getBody());
return db.transactionWithResult(true, txn ->
getSmallMessageAsList(txn, m));
}
@Override
public BdfList getSmallMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException {
return toList(db.getSmallMessage(txn, m).getBody());
}
@Override

View File

@@ -12,6 +12,7 @@ import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.MessageTooLargeException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author;
@@ -125,11 +126,6 @@ interface Database<T> {
void addMessageDependency(T txn, Message dependent, MessageId dependency,
MessageState dependentState) throws DbException;
/**
* Records that a message has been offered by the given contact.
*/
void addOfferedMessage(T txn, ContactId c, MessageId m) throws DbException;
/**
* Stores a pending contact.
*/
@@ -218,13 +214,6 @@ interface Database<T> {
boolean containsVisibleMessage(T txn, ContactId c, MessageId m)
throws DbException;
/**
* Returns the number of messages offered by the given contact.
* <p/>
* Read-only.
*/
int countOfferedMessages(T txn, ContactId c) throws DbException;
/**
* Deletes the message with the given ID. Unlike
* {@link #removeMessage(Object, MessageId)}, the message ID and any other
@@ -332,13 +321,14 @@ interface Database<T> {
Collection<Identity> getIdentities(T txn) throws DbException;
/**
* Returns the message with the given ID.
* Returns the single-block message with the given ID.
* <p/>
* Read-only.
*
* @throws MessageDeletedException if the message has been deleted
* @throws MessageTooLargeException if the message has more than one block
*/
Message getMessage(T txn, MessageId m) throws DbException;
Message getSmallMessage(T txn, MessageId m) throws DbException;
/**
* Returns the IDs and states of all dependencies of the given message.
@@ -457,13 +447,13 @@ interface Database<T> {
int maxMessages, int maxLatency) throws DbException;
/**
* Returns the IDs of some messages that are eligible to be requested from
* the given contact, up to the given number of messages.
* Returns the IDs of some single-block messages that are eligible to be
* offered to the given contact, up to the given number of messages.
* <p/>
* Read-only.
*/
Collection<MessageId> getMessagesToRequest(T txn, ContactId c,
int maxMessages) throws DbException;
Collection<MessageId> getSmallMessagesToOffer(T txn, ContactId c,
int maxMessages, int maxLatency) throws DbException;
/**
* Returns the IDs of some messages that are eligible to be sent to the
@@ -474,6 +464,15 @@ interface Database<T> {
Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength,
int maxLatency) throws DbException;
/**
* Returns the IDs of some single-block messages that are eligible to be
* sent to the given contact, up to the given total length.
* <p/>
* Read-only.
*/
Collection<MessageId> getSmallMessagesToSend(T txn, ContactId c,
int maxLength, int maxLatency) throws DbException;
/**
* Returns the IDs of any messages that need to be validated.
* <p/>
@@ -636,13 +635,6 @@ interface Database<T> {
*/
void removeMessage(T txn, MessageId m) throws DbException;
/**
* Removes the given offered messages that were offered by the given
* contact.
*/
void removeOfferedMessages(T txn, ContactId c,
Collection<MessageId> requested) throws DbException;
/**
* Removes a pending contact (and all associated state) from the database.
*/

View File

@@ -61,10 +61,10 @@ import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
import org.briarproject.bramble.api.sync.event.MessageRequestedEvent;
import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent;
import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.sync.event.MessagesToAckEvent;
import org.briarproject.bramble.api.sync.event.MessagesToRequestEvent;
import org.briarproject.bramble.api.sync.event.SyncVersionsUpdatedEvent;
import org.briarproject.bramble.api.sync.validation.MessageState;
import org.briarproject.bramble.api.transport.KeySetId;
@@ -91,7 +91,6 @@ import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now;
@@ -406,19 +405,22 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable
@Override
public Collection<Message> generateBatch(Transaction transaction,
ContactId c, int maxLength, int maxLatency) throws DbException {
ContactId c, int maxLength, int maxLatency, boolean small)
throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<MessageId> ids =
db.getMessagesToSend(txn, c, maxLength, maxLatency);
Collection<MessageId> ids;
if (small)
ids = db.getSmallMessagesToSend(txn, c, maxLength, maxLatency);
else ids = db.getMessagesToSend(txn, c, maxLength, maxLatency);
if (ids.isEmpty()) return null;
List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) {
messages.add(db.getMessage(txn, m));
messages.add(db.getSmallMessage(txn, m));
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
}
if (ids.isEmpty()) return null;
db.lowerRequestedFlag(txn, c, ids);
transaction.attach(new MessagesSentEvent(c, ids));
return messages;
@@ -427,34 +429,21 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
@Nullable
@Override
public Offer generateOffer(Transaction transaction, ContactId c,
int maxMessages, int maxLatency) throws DbException {
int maxMessages, int maxLatency, boolean small) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<MessageId> ids =
db.getMessagesToOffer(txn, c, maxMessages, maxLatency);
Collection<MessageId> ids;
if (small)
ids = db.getSmallMessagesToOffer(txn, c, maxMessages, maxLatency);
else ids = db.getMessagesToOffer(txn, c, maxMessages, maxLatency);
if (ids.isEmpty()) return null;
for (MessageId m : ids)
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
return new Offer(ids);
}
@Nullable
@Override
public Request generateRequest(Transaction transaction, ContactId c,
int maxMessages) throws DbException {
if (transaction.isReadOnly()) throw new IllegalArgumentException();
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<MessageId> ids = db.getMessagesToRequest(txn, c,
maxMessages);
if (ids.isEmpty()) return null;
db.removeOfferedMessages(txn, c, ids);
return new Request(ids);
}
@Nullable
@Override
public Collection<Message> generateRequestedBatch(Transaction transaction,
@@ -465,12 +454,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
throw new NoSuchContactException();
Collection<MessageId> ids =
db.getRequestedMessagesToSend(txn, c, maxLength, maxLatency);
if (ids.isEmpty()) return null;
List<Message> messages = new ArrayList<>(ids.size());
for (MessageId m : ids) {
messages.add(db.getMessage(txn, m));
messages.add(db.getSmallMessage(txn, m));
db.updateExpiryTimeAndEta(txn, c, m, maxLatency);
}
if (ids.isEmpty()) return null;
db.lowerRequestedFlag(txn, c, ids);
transaction.attach(new MessagesSentEvent(c, ids));
return messages;
@@ -559,12 +548,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
}
@Override
public Message getMessage(Transaction transaction, MessageId m)
public Message getSmallMessage(Transaction transaction, MessageId m)
throws DbException {
T txn = unbox(transaction);
if (!db.containsMessage(txn, m))
throw new NoSuchMessageException();
return db.getMessage(txn, m);
return db.getSmallMessage(txn, m);
}
@Override
@@ -819,7 +808,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
db.addMessage(txn, m, UNKNOWN, false, false, c);
transaction.attach(new MessageAddedEvent(m, c));
}
transaction.attach(new MessageToAckEvent(c));
transaction.attach(new MessagesToAckEvent(c));
}
}
@@ -830,21 +819,20 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
T txn = unbox(transaction);
if (!db.containsContact(txn, c))
throw new NoSuchContactException();
boolean ack = false, request = false;
int count = db.countOfferedMessages(txn, c);
boolean ack = false;
List<MessageId> request = new ArrayList<>(o.getMessageIds().size());
for (MessageId m : o.getMessageIds()) {
if (db.containsVisibleMessage(txn, c, m)) {
db.raiseSeenFlag(txn, c, m);
db.raiseAckFlag(txn, c, m);
ack = true;
} else if (count < MAX_OFFERED_MESSAGES) {
db.addOfferedMessage(txn, c, m);
request = true;
count++;
} else {
request.add(m);
}
}
if (ack) transaction.attach(new MessageToAckEvent(c));
if (request) transaction.attach(new MessageToRequestEvent(c));
if (ack) transaction.attach(new MessagesToAckEvent(c));
if (!request.isEmpty())
transaction.attach(new MessagesToRequestEvent(c, request));
}
@Override

View File

@@ -6,13 +6,6 @@ import static java.util.concurrent.TimeUnit.DAYS;
interface DatabaseConstants {
/**
* The maximum number of offered messages from each contact that will be
* stored. If offers arrive more quickly than requests can be sent and this
* limit is reached, additional offers will not be stored.
*/
int MAX_OFFERED_MESSAGES = 1000;
/**
* The namespace of the {@link Settings} where the database schema version
* is stored.

View File

@@ -6,7 +6,6 @@ import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventExecutor;
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import java.sql.Connection;
@@ -22,9 +21,8 @@ public class DatabaseModule {
@Provides
@Singleton
Database<Connection> provideDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
Database<Connection> provideDatabase(DatabaseConfig config, Clock clock) {
return new H2Database(config, clock);
}
@Provides

View File

@@ -6,7 +6,6 @@ import org.briarproject.bramble.api.db.DbClosedException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils;
@@ -51,9 +50,8 @@ class H2Database extends JdbcDatabase {
private volatile SecretKey key = null;
@Inject
H2Database(DatabaseConfig config, MessageFactory messageFactory,
Clock clock) {
super(dbTypes, messageFactory, clock);
H2Database(DatabaseConfig config, Clock clock) {
super(dbTypes, clock);
this.config = config;
File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath();

View File

@@ -6,7 +6,6 @@ import org.briarproject.bramble.api.db.DbClosedException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.StringUtils;
@@ -51,9 +50,8 @@ class HyperSqlDatabase extends JdbcDatabase {
private volatile SecretKey key = null;
@Inject
HyperSqlDatabase(DatabaseConfig config, MessageFactory messageFactory,
Clock clock) {
super(dbTypes, messageFactory, clock);
HyperSqlDatabase(DatabaseConfig config, Clock clock) {
super(dbTypes, clock);
this.config = config;
File dir = config.getDatabaseDirectory();
String path = new File(dir, "db").getAbsolutePath();

View File

@@ -16,6 +16,7 @@ import org.briarproject.bramble.api.db.DataTooOldException;
import org.briarproject.bramble.api.db.DbClosedException;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.MessageDeletedException;
import org.briarproject.bramble.api.db.MessageTooLargeException;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.identity.Author;
@@ -30,7 +31,6 @@ import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.Group.Visibility;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.MessageStatus;
import org.briarproject.bramble.api.sync.validation.MessageState;
@@ -76,6 +76,7 @@ import static org.briarproject.bramble.api.db.Metadata.REMOVE;
import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED;
import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_BLOCK_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.PENDING;
@@ -98,7 +99,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing
static final int CODE_SCHEMA_VERSION = 47;
static final int CODE_SCHEMA_VERSION = 49;
// Time period offsets for incoming transport keys
private static final int OFFSET_PREV = -1;
@@ -180,8 +181,9 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " state INT NOT NULL,"
+ " shared BOOLEAN NOT NULL,"
+ " temporary BOOLEAN NOT NULL,"
+ " length INT NOT NULL,"
+ " raw BLOB," // Null if message has been deleted
+ " length INT NOT NULL," // Includes message header
+ " deleted BOOLEAN NOT NULL,"
+ " blockCount INT NOT NULL,"
+ " PRIMARY KEY (messageId),"
+ " FOREIGN KEY (groupId)"
+ " REFERENCES groups (groupId)"
@@ -218,13 +220,15 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " REFERENCES messages (messageId)"
+ " ON DELETE CASCADE)";
private static final String CREATE_OFFERS =
"CREATE TABLE offers"
+ " (messageId _HASH NOT NULL," // Not a foreign key
+ " contactId INT NOT NULL,"
+ " PRIMARY KEY (messageId, contactId),"
+ " FOREIGN KEY (contactId)"
+ " REFERENCES contacts (contactId)"
private static final String CREATE_BLOCKS =
"CREATE TABLE blocks"
+ " (messageId _HASH NOT NULL,"
+ " blockNumber INT NOT NULL,"
+ " blockLength INT NOT NULL," // Excludes block header
+ " data BLOB," // Null if message has been deleted
+ " PRIMARY KEY (messageId, blockNumber),"
+ " FOREIGN KEY (messageId)"
+ " REFERENCES messages (messageId)"
+ " ON DELETE CASCADE)";
private static final String CREATE_STATUSES =
@@ -339,7 +343,6 @@ abstract class JdbcDatabase implements Database<Connection> {
private static final Logger LOG =
getLogger(JdbcDatabase.class.getName());
private final MessageFactory messageFactory;
private final Clock clock;
private final DatabaseTypes dbTypes;
@@ -359,10 +362,8 @@ abstract class JdbcDatabase implements Database<Connection> {
protected abstract void compactAndClose() throws DbException;
JdbcDatabase(DatabaseTypes databaseTypes, MessageFactory messageFactory,
Clock clock) {
JdbcDatabase(DatabaseTypes databaseTypes, Clock clock) {
this.dbTypes = databaseTypes;
this.messageFactory = messageFactory;
this.clock = clock;
}
@@ -440,10 +441,12 @@ abstract class JdbcDatabase implements Database<Connection> {
if (LOG.isLoggable(INFO))
LOG.info("Migrating from schema " + start + " to " + end);
if (listener != null) listener.onDatabaseMigration();
long startTime = now();
// Apply the migration
m.migrate(txn);
// Store the new schema version
storeSchemaVersion(txn, end);
logDuration(LOG, "Migration", startTime);
dataSchemaVersion = end;
}
}
@@ -463,7 +466,9 @@ abstract class JdbcDatabase implements Database<Connection> {
new Migration43_44(dbTypes),
new Migration44_45(),
new Migration45_46(),
new Migration46_47(dbTypes)
new Migration46_47(dbTypes),
new Migration47_48(dbTypes),
new Migration48_49()
);
}
@@ -508,7 +513,7 @@ abstract class JdbcDatabase implements Database<Connection> {
s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGES));
s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_METADATA));
s.executeUpdate(dbTypes.replaceTypes(CREATE_MESSAGE_DEPENDENCIES));
s.executeUpdate(dbTypes.replaceTypes(CREATE_OFFERS));
s.executeUpdate(dbTypes.replaceTypes(CREATE_BLOCKS));
s.executeUpdate(dbTypes.replaceTypes(CREATE_STATUSES));
s.executeUpdate(dbTypes.replaceTypes(CREATE_TRANSPORTS));
s.executeUpdate(dbTypes.replaceTypes(CREATE_PENDING_CONTACTS));
@@ -726,7 +731,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ResultSet rs = null;
try {
String sql = "SELECT messageId, timestamp, state, shared,"
+ " length, raw IS NULL"
+ " length, deleted"
+ " FROM messages"
+ " WHERE groupId = ?";
ps = txn.prepareStatement(sql);
@@ -739,9 +744,8 @@ abstract class JdbcDatabase implements Database<Connection> {
boolean messageShared = rs.getBoolean(4);
int length = rs.getInt(5);
boolean deleted = rs.getBoolean(6);
boolean seen = removeOfferedMessage(txn, c, id);
addStatus(txn, id, c, g, timestamp, length, state, groupShared,
messageShared, deleted, seen);
messageShared, deleted, false);
}
rs.close();
ps.close();
@@ -788,8 +792,8 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null;
try {
String sql = "INSERT INTO messages (messageId, groupId, timestamp,"
+ " state, shared, temporary, length, raw)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+ " state, shared, temporary, length, deleted, blockCount)"
+ " VALUES (?, ?, ?, ?, ?, ?, ?, FALSE, 1)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getId().getBytes());
ps.setBytes(2, m.getGroupId().getBytes());
@@ -797,21 +801,29 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.setInt(4, state.getValue());
ps.setBoolean(5, shared);
ps.setBoolean(6, temporary);
byte[] raw = messageFactory.getRawMessage(m);
ps.setInt(7, raw.length);
ps.setBytes(8, raw);
ps.setInt(7, m.getRawLength());
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
sql = "INSERT INTO blocks (messageId, blockNumber, blockLength,"
+ " data)"
+ " VALUES (?, 0, ?, ?)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getId().getBytes());
ps.setInt(2, m.getBody().length);
ps.setBytes(3, m.getBody());
affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
// Create a status row for each contact that can see the group
Map<ContactId, Boolean> visibility =
getGroupVisibility(txn, m.getGroupId());
for (Entry<ContactId, Boolean> e : visibility.entrySet()) {
ContactId c = e.getKey();
boolean offered = removeOfferedMessage(txn, c, m.getId());
boolean seen = offered || c.equals(sender);
boolean seen = c.equals(sender);
addStatus(txn, m.getId(), c, m.getGroupId(), m.getTimestamp(),
raw.length, state, e.getValue(), shared, false, seen);
m.getRawLength(), state, e.getValue(), shared, false,
seen);
}
// Update denormalised column in messageDependencies if dependency
// is in same group as dependent
@@ -830,37 +842,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public void addOfferedMessage(Connection txn, ContactId c, MessageId m)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT NULL FROM offers"
+ " WHERE messageId = ? AND contactId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
ps.setInt(2, c.getInt());
rs = ps.executeQuery();
boolean found = rs.next();
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
if (found) return;
sql = "INSERT INTO offers (messageId, contactId) VALUES (?, ?)";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
ps.setInt(2, c.getInt());
int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
private void addStatus(Connection txn, MessageId m, ContactId c, GroupId g,
long timestamp, int length, MessageState state, boolean groupShared,
boolean messageShared, boolean deleted, boolean seen)
@@ -1262,40 +1243,22 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public int countOfferedMessages(Connection txn, ContactId c)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT COUNT (messageId) FROM offers "
+ " WHERE contactId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
rs = ps.executeQuery();
if (!rs.next()) throw new DbException();
int count = rs.getInt(1);
if (rs.next()) throw new DbException();
rs.close();
ps.close();
return count;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void deleteMessage(Connection txn, MessageId m) throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE messages SET raw = NULL WHERE messageId = ?";
String sql = "UPDATE messages SET deleted = TRUE"
+ " WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
sql = "UPDATE blocks SET data = NULL WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
affected = ps.executeUpdate();
if (affected < 0) throw new DbStateException();
if (affected > 1) throw new DbStateException();
ps.close();
// Update denormalised column in statuses
sql = "UPDATE statuses SET deleted = TRUE WHERE messageId = ?";
@@ -1688,11 +1651,13 @@ abstract class JdbcDatabase implements Database<Connection> {
}
@Override
public Message getMessage(Connection txn, MessageId m) throws DbException {
public Message getSmallMessage(Connection txn, MessageId m)
throws DbException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT groupId, timestamp, raw FROM messages"
String sql = "SELECT groupId, timestamp, deleted, blockCount"
+ " FROM messages"
+ " WHERE messageId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
@@ -1700,15 +1665,25 @@ abstract class JdbcDatabase implements Database<Connection> {
if (!rs.next()) throw new DbStateException();
GroupId g = new GroupId(rs.getBytes(1));
long timestamp = rs.getLong(2);
byte[] raw = rs.getBytes(3);
boolean deleted = rs.getBoolean(3);
int blockCount = rs.getInt(4);
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
if (raw == null) throw new MessageDeletedException();
if (raw.length <= MESSAGE_HEADER_LENGTH) throw new AssertionError();
byte[] body = new byte[raw.length - MESSAGE_HEADER_LENGTH];
System.arraycopy(raw, MESSAGE_HEADER_LENGTH, body, 0, body.length);
return new Message(m, g, timestamp, body);
if (deleted) throw new MessageDeletedException();
if (blockCount > 1) throw new MessageTooLargeException();
sql = "SELECT data FROM blocks"
+ " WHERE messageId = ? AND blockNumber = 0";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
rs = ps.executeQuery();
if (!rs.next()) throw new DbStateException();
byte[] data = rs.getBytes(1);
if (data == null) throw new DbStateException();
if (rs.next()) throw new DbStateException();
rs.close();
ps.close();
return new Message(m, g, timestamp, data);
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
@@ -2101,17 +2076,28 @@ abstract class JdbcDatabase implements Database<Connection> {
}
@Override
public Collection<MessageId> getMessagesToRequest(Connection txn,
ContactId c, int maxMessages) throws DbException {
public Collection<MessageId> getSmallMessagesToOffer(Connection txn,
ContactId c, int maxMessages, int maxLatency) throws DbException {
long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT messageId FROM offers"
+ " WHERE contactId = ?"
+ " LIMIT ?";
String sql = "SELECT messageId FROM statuses"
+ " WHERE contactId = ? AND state = ?"
+ " AND length <= ?"
+ " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE"
+ " AND seen = FALSE AND requested = FALSE"
+ " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp LIMIT ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setInt(2, maxMessages);
ps.setInt(2, DELIVERED.getValue());
ps.setInt(3, MESSAGE_HEADER_LENGTH + MAX_BLOCK_LENGTH);
ps.setLong(4, now);
ps.setLong(5, eta);
ps.setInt(6, maxMessages);
rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>();
while (rs.next()) ids.add(new MessageId(rs.getBytes(1)));
@@ -2164,6 +2150,47 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
@Override
public Collection<MessageId> getSmallMessagesToSend(Connection txn,
ContactId c, int maxLength, int maxLatency) throws DbException {
long now = clock.currentTimeMillis();
long eta = now + maxLatency;
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "SELECT length, messageId FROM statuses"
+ " WHERE contactId = ? AND state = ?"
+ " AND length <= ?"
+ " AND groupShared = TRUE AND messageShared = TRUE"
+ " AND deleted = FALSE"
+ " AND seen = FALSE"
+ " AND (expiry <= ? OR eta > ?)"
+ " ORDER BY timestamp";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setInt(2, DELIVERED.getValue());
ps.setInt(3, MESSAGE_HEADER_LENGTH + MAX_BLOCK_LENGTH);
ps.setLong(4, now);
ps.setLong(5, eta);
rs = ps.executeQuery();
List<MessageId> ids = new ArrayList<>();
int total = 0;
while (rs.next()) {
int length = rs.getInt(1);
if (total + length > maxLength) break;
ids.add(new MessageId(rs.getBytes(2)));
total += length;
}
rs.close();
ps.close();
return ids;
} catch (SQLException e) {
tryToClose(rs, LOG, WARNING);
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public Collection<MessageId> getMessagesToValidate(Connection txn)
throws DbException {
@@ -2182,7 +2209,7 @@ abstract class JdbcDatabase implements Database<Connection> {
ResultSet rs = null;
try {
String sql = "SELECT messageId FROM messages"
+ " WHERE state = ? AND raw IS NOT NULL";
+ " WHERE state = ? AND deleted = FALSE";
ps = txn.prepareStatement(sql);
ps.setInt(1, state.getValue());
rs = ps.executeQuery();
@@ -2887,50 +2914,6 @@ abstract class JdbcDatabase implements Database<Connection> {
}
}
private boolean removeOfferedMessage(Connection txn, ContactId c,
MessageId m) throws DbException {
PreparedStatement ps = null;
try {
String sql = "DELETE FROM offers"
+ " WHERE contactId = ? AND messageId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
ps.setBytes(2, m.getBytes());
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
return affected == 1;
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void removeOfferedMessages(Connection txn, ContactId c,
Collection<MessageId> requested) throws DbException {
PreparedStatement ps = null;
try {
String sql = "DELETE FROM offers"
+ " WHERE contactId = ? AND messageId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
for (MessageId m : requested) {
ps.setBytes(2, m.getBytes());
ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
if (batchAffected.length != requested.size())
throw new DbStateException();
for (int rows : batchAffected)
if (rows != 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override
public void removePendingContact(Connection txn, PendingContactId p)
throws DbException {

View File

@@ -37,6 +37,7 @@ class Migration38_39 implements Migration<Connection> {
s.execute("ALTER TABLE incomingKeys"
+ " ALTER COLUMN contactId"
+ " SET NOT NULL");
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);

View File

@@ -36,6 +36,7 @@ class Migration39_40 implements Migration<Connection> {
s.execute("ALTER TABLE statuses"
+ " ALTER COLUMN eta"
+ " SET NOT NULL");
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);

View File

@@ -38,6 +38,7 @@ class Migration40_41 implements Migration<Connection> {
s = txn.createStatement();
s.execute("ALTER TABLE contacts"
+ dbTypes.replaceTypes(" ADD alias _STRING"));
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);

View File

@@ -89,6 +89,7 @@ class Migration41_42 implements Migration<Connection> {
+ " FOREIGN KEY (keySetId)"
+ " REFERENCES outgoingHandshakeKeys (keySetId)"
+ " ON DELETE CASCADE)"));
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);

View File

@@ -44,6 +44,7 @@ class Migration42_43 implements Migration<Connection> {
+ " ADD COLUMN handshakePublicKey _BINARY"));
s.execute("ALTER TABLE contacts"
+ " DROP COLUMN active");
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);

View File

@@ -50,6 +50,7 @@ class Migration43_44 implements Migration<Connection> {
+ " ADD COLUMN rootKey _SECRET"));
s.execute("ALTER TABLE outgoingKeys"
+ " ADD COLUMN alice BOOLEAN");
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);

View File

@@ -31,6 +31,7 @@ class Migration44_45 implements Migration<Connection> {
try {
s = txn.createStatement();
s.execute("ALTER TABLE pendingContacts DROP COLUMN state");
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);

View File

@@ -32,6 +32,7 @@ class Migration45_46 implements Migration<Connection> {
s = txn.createStatement();
s.execute("ALTER TABLE messages"
+ " ADD COLUMN temporary BOOLEAN DEFAULT FALSE NOT NULL");
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);

View File

@@ -39,6 +39,7 @@ class Migration46_47 implements Migration<Connection> {
s.execute(dbTypes.replaceTypes("ALTER TABLE contacts"
+ " ADD COLUMN syncVersions"
+ " _BINARY DEFAULT '00' NOT NULL"));
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);

View File

@@ -0,0 +1,95 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import static java.lang.System.arraycopy;
import static java.sql.Types.BINARY;
import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration47_48 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration47_48.class.getName());
private final DatabaseTypes dbTypes;
Migration47_48(DatabaseTypes dbTypes) {
this.dbTypes = dbTypes;
}
@Override
public int getStartVersion() {
return 47;
}
@Override
public int getEndVersion() {
return 48;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
ResultSet rs = null;
PreparedStatement ps = null;
try {
s = txn.createStatement();
s.execute("ALTER TABLE messages"
+ " ADD COLUMN deleted BOOLEAN DEFAULT FALSE NOT NULL");
s.execute("UPDATE messages SET deleted = TRUE WHERE raw IS NULL");
s.execute("ALTER TABLE messages"
+ " ADD COLUMN blockCount INT DEFAULT 1 NOT NULL");
s.execute(dbTypes.replaceTypes("CREATE TABLE blocks"
+ " (messageId _HASH NOT NULL,"
+ " blockNumber INT NOT NULL,"
+ " blockLength INT NOT NULL," // Excludes block header
+ " data BLOB," // Null if message has been deleted
+ " PRIMARY KEY (messageId, blockNumber),"
+ " FOREIGN KEY (messageId)"
+ " REFERENCES messages (messageId)"
+ " ON DELETE CASCADE)"));
rs = s.executeQuery("SELECT messageId, length, raw FROM messages");
ps = txn.prepareStatement("INSERT INTO blocks"
+ " (messageId, blockNumber, blockLength, data)"
+ " VALUES (?, 0, ?, ?)");
int migrated = 0;
while (rs.next()) {
byte[] id = rs.getBytes(1);
int length = rs.getInt(2);
byte[] raw = rs.getBytes(3);
ps.setBytes(1, id);
ps.setInt(2, length - MESSAGE_HEADER_LENGTH);
if (raw == null) {
ps.setNull(3, BINARY);
} else {
byte[] data = new byte[raw.length - MESSAGE_HEADER_LENGTH];
arraycopy(raw, MESSAGE_HEADER_LENGTH, data, 0, data.length);
ps.setBytes(3, data);
}
if (ps.executeUpdate() != 1) throw new DbStateException();
migrated++;
}
ps.close();
rs.close();
s.execute("ALTER TABLE messages DROP COLUMN raw");
s.close();
if (LOG.isLoggable(INFO))
LOG.info("Migrated " + migrated + " messages");
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
tryToClose(rs, LOG, WARNING);
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
}

View File

@@ -0,0 +1,40 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration48_49 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration48_49.class.getName());
@Override
public int getStartVersion() {
return 48;
}
@Override
public int getEndVersion() {
return 49;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
s.execute("DROP TABLE offers");
s.close();
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
}

View File

@@ -199,7 +199,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
Map<TransportId, LatestUpdate> latest = findLatestLocal(txn);
// Retrieve and parse the latest local properties
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
BdfList message = clientHelper.getMessageAsList(txn,
BdfList message = clientHelper.getSmallMessageAsList(txn,
e.getValue().messageId);
local.put(e.getKey(), parseProperties(message));
}
@@ -220,7 +220,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
true);
if (latest != null) {
// Retrieve and parse the latest local properties
BdfList message = clientHelper.getMessageAsList(txn,
BdfList message = clientHelper.getSmallMessageAsList(txn,
latest.messageId);
p = parseProperties(message);
}
@@ -250,7 +250,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
if (latest == null) {
local = new TransportProperties();
} else {
BdfList message = clientHelper.getMessageAsList(txn,
BdfList message = clientHelper.getSmallMessageAsList(txn,
latest.messageId);
local = parseProperties(message);
}
@@ -271,8 +271,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
remote = new TransportProperties();
} else {
// Retrieve and parse the latest remote properties
BdfList message =
clientHelper.getMessageAsList(txn, latest.messageId);
BdfList message = clientHelper.getSmallMessageAsList(txn,
latest.messageId);
remote = parseProperties(message);
}
// Merge in any discovered properties
@@ -315,7 +315,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
}
changed = true;
} else {
BdfList message = clientHelper.getMessageAsList(txn,
BdfList message = clientHelper.getSmallMessageAsList(txn,
latest.messageId);
TransportProperties old = parseProperties(message);
merged = new TransportProperties(old);

View File

@@ -15,6 +15,7 @@ import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.plugin.event.TransportInactiveEvent;
import org.briarproject.bramble.api.sync.Ack;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Priority;
import org.briarproject.bramble.api.sync.Request;
@@ -25,8 +26,8 @@ import org.briarproject.bramble.api.sync.event.CloseSyncConnectionsEvent;
import org.briarproject.bramble.api.sync.event.GroupVisibilityUpdatedEvent;
import org.briarproject.bramble.api.sync.event.MessageRequestedEvent;
import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesToAckEvent;
import org.briarproject.bramble.api.sync.event.MessagesToRequestEvent;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.transport.StreamWriter;
@@ -87,8 +88,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
private final AtomicBoolean generateAckQueued = new AtomicBoolean(false);
private final AtomicBoolean generateBatchQueued = new AtomicBoolean(false);
private final AtomicBoolean generateOfferQueued = new AtomicBoolean(false);
private final AtomicBoolean generateRequestQueued =
new AtomicBoolean(false);
private final AtomicLong nextSendTime = new AtomicLong(Long.MAX_VALUE);
private volatile boolean interrupted = false;
@@ -125,7 +124,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
generateAck();
generateBatch();
generateOffer();
generateRequest();
long now = clock.currentTimeMillis();
long nextKeepalive = now + maxIdleTime;
boolean dataToFlush = true;
@@ -197,11 +195,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
dbExecutor.execute(new GenerateOffer());
}
private void generateRequest() {
if (generateRequestQueued.compareAndSet(false, true))
dbExecutor.execute(new GenerateRequest());
}
private void setNextSendTime(long time) {
long old = nextSendTime.getAndSet(time);
if (time < old) writerTasks.add(NEXT_SEND_TIME_DECREASED);
@@ -227,12 +220,16 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
} else if (e instanceof MessageRequestedEvent) {
if (((MessageRequestedEvent) e).getContactId().equals(contactId))
generateBatch();
} else if (e instanceof MessageToAckEvent) {
if (((MessageToAckEvent) e).getContactId().equals(contactId))
} else if (e instanceof MessagesToAckEvent) {
if (((MessagesToAckEvent) e).getContactId().equals(contactId))
generateAck();
} else if (e instanceof MessageToRequestEvent) {
if (((MessageToRequestEvent) e).getContactId().equals(contactId))
generateRequest();
} else if (e instanceof MessagesToRequestEvent) {
MessagesToRequestEvent m = (MessagesToRequestEvent) e;
if (m.getContactId().equals(contactId)) {
Collection<MessageId> ids = m.consumeIds();
if (ids != null)
writerTasks.add(new WriteRequest(new Request(ids)));
}
} else if (e instanceof LifecycleEvent) {
LifecycleEvent l = (LifecycleEvent) e;
if (l.getLifecycleState() == STOPPING) interrupt();
@@ -340,7 +337,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
try {
Offer o = db.transactionWithNullableResult(false, txn -> {
Offer offer = db.generateOffer(txn, contactId,
MAX_MESSAGE_IDS, maxLatency);
MAX_MESSAGE_IDS, maxLatency, true);
setNextSendTime(db.getNextSendTime(txn, contactId));
return offer;
});
@@ -372,27 +369,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
}
}
private class GenerateRequest implements Runnable {
@DatabaseExecutor
@Override
public void run() {
if (interrupted) return;
if (!generateRequestQueued.getAndSet(false))
throw new AssertionError();
try {
Request r = db.transactionWithNullableResult(false, txn ->
db.generateRequest(txn, contactId, MAX_MESSAGE_IDS));
if (LOG.isLoggable(INFO))
LOG.info("Generated request: " + (r != null));
if (r != null) writerTasks.add(new WriteRequest(r));
} catch (DbException e) {
logException(LOG, WARNING, e);
interrupt();
}
}
}
private class WriteRequest implements ThrowingRunnable<IOException> {
private final Request request;
@@ -407,7 +383,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
if (interrupted) return;
recordWriter.writeRequest(request);
LOG.info("Sent request");
generateRequest();
}
}
}

View File

@@ -186,7 +186,8 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
Collection<Message> b =
db.transactionWithNullableResult(false, txn ->
db.generateBatch(txn, contactId,
MAX_RECORD_PAYLOAD_BYTES, maxLatency));
MAX_RECORD_PAYLOAD_BYTES, maxLatency,
true));
if (LOG.isLoggable(INFO))
LOG.info("Generated batch: " + (b != null));
if (b == null) decrementOutstandingQueries();

View File

@@ -120,7 +120,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
Pair<Message, Group> mg = db.transactionWithResult(true, txn -> {
MessageId id = unvalidated.poll();
if (id == null) throw new AssertionError();
Message m = db.getMessage(txn, id);
Message m = db.getSmallMessage(txn, id);
Group g = db.getGroup(txn, m.getGroupId());
return new Pair<>(m, g);
});
@@ -179,7 +179,7 @@ class ValidationManagerImpl implements ValidationManager, Service,
invalidateMessage(txn, id);
addDependentsToInvalidate(txn, id, invalidate);
} else if (allDelivered) {
Message m = db.getMessage(txn, id);
Message m = db.getSmallMessage(txn, id);
Group g = db.getGroup(txn, m.getGroupId());
ClientId c = g.getClientId();
int majorVersion = g.getMajorVersion();

View File

@@ -298,7 +298,8 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
private List<ClientVersion> loadClientVersions(Transaction txn,
MessageId m) throws DbException {
try {
return parseClientVersions(clientHelper.getMessageAsList(txn, m));
return parseClientVersions(
clientHelper.getSmallMessageAsList(txn, m));
} catch (FormatException e) {
throw new DbException(e);
}
@@ -391,7 +392,7 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
private Update loadUpdate(Transaction txn, MessageId m) throws DbException {
try {
return parseUpdate(clientHelper.getMessageAsList(txn, m));
return parseUpdate(clientHelper.getSmallMessageAsList(txn, m));
} catch (FormatException e) {
throw new DbException(e);
}

View File

@@ -122,11 +122,11 @@ public class ClientHelperImplTest extends BrambleTestCase {
expectToList(true);
context.checking(new DbExpectations() {{
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessage(txn, messageId);
oneOf(db).getSmallMessage(txn, messageId);
will(returnValue(message));
}});
clientHelper.getMessageAsList(messageId);
clientHelper.getSmallMessageAsList(messageId);
context.assertIsSatisfied();
}

View File

@@ -44,10 +44,10 @@ import org.briarproject.bramble.api.sync.event.MessageAddedEvent;
import org.briarproject.bramble.api.sync.event.MessageRequestedEvent;
import org.briarproject.bramble.api.sync.event.MessageSharedEvent;
import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent;
import org.briarproject.bramble.api.sync.event.MessageToAckEvent;
import org.briarproject.bramble.api.sync.event.MessageToRequestEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
import org.briarproject.bramble.api.sync.event.MessagesSentEvent;
import org.briarproject.bramble.api.sync.event.MessagesToAckEvent;
import org.briarproject.bramble.api.sync.event.MessagesToRequestEvent;
import org.briarproject.bramble.api.transport.IncomingKeys;
import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.bramble.api.transport.OutgoingKeys;
@@ -76,7 +76,6 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH
import static org.briarproject.bramble.api.sync.validation.MessageState.DELIVERED;
import static org.briarproject.bramble.api.sync.validation.MessageState.UNKNOWN;
import static org.briarproject.bramble.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
import static org.briarproject.bramble.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
import static org.briarproject.bramble.test.TestUtils.getAgreementPrivateKey;
import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
import static org.briarproject.bramble.test.TestUtils.getAuthor;
@@ -295,11 +294,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
throws Exception {
context.checking(new Expectations() {{
// Check whether the contact is in the DB (which it's not)
exactly(18).of(database).startTransaction();
exactly(17).of(database).startTransaction();
will(returnValue(txn));
exactly(18).of(database).containsContact(txn, contactId);
exactly(17).of(database).containsContact(txn, contactId);
will(returnValue(false));
exactly(18).of(database).abortTransaction(txn);
exactly(17).of(database).abortTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager);
@@ -323,7 +322,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
try {
db.transaction(false, transaction ->
db.generateBatch(transaction, contactId, 123, 456));
db.generateBatch(transaction, contactId, 123, 456, true));
fail();
} catch (NoSuchContactException expected) {
// Expected
@@ -331,15 +330,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
try {
db.transaction(false, transaction ->
db.generateOffer(transaction, contactId, 123, 456));
fail();
} catch (NoSuchContactException expected) {
// Expected
}
try {
db.transaction(false, transaction ->
db.generateRequest(transaction, contactId, 123));
db.generateOffer(transaction, contactId, 123, 456, true));
fail();
} catch (NoSuchContactException expected) {
// Expected
@@ -624,7 +615,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
try {
db.transaction(false, transaction ->
db.getMessage(transaction, messageId));
db.getSmallMessage(transaction, messageId));
fail();
} catch (NoSuchMessageException expected) {
// Expected
@@ -865,14 +856,14 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getMessagesToSend(txn, contactId,
oneOf(database).getSmallMessagesToSend(txn, contactId,
MAX_MESSAGE_LENGTH * 2, maxLatency);
will(returnValue(ids));
oneOf(database).getMessage(txn, messageId);
oneOf(database).getSmallMessage(txn, messageId);
will(returnValue(message));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency);
oneOf(database).getMessage(txn, messageId1);
oneOf(database).getSmallMessage(txn, messageId1);
will(returnValue(message1));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency);
@@ -885,7 +876,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
db.transaction(false, transaction ->
assertEquals(messages, db.generateBatch(transaction, contactId,
MAX_MESSAGE_LENGTH * 2, maxLatency)));
MAX_MESSAGE_LENGTH * 2, maxLatency, true)));
}
@Test
@@ -897,7 +888,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getMessagesToOffer(txn, contactId, 123, maxLatency);
oneOf(database).getSmallMessagesToOffer(txn, contactId, 123,
maxLatency);
will(returnValue(ids));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency);
@@ -909,36 +901,13 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
eventExecutor, shutdownManager);
db.transaction(false, transaction -> {
Offer o = db.generateOffer(transaction, contactId, 123, maxLatency);
Offer o = db.generateOffer(transaction, contactId, 123, maxLatency,
true);
assertNotNull(o);
assertEquals(ids, o.getMessageIds());
});
}
@Test
public void testGenerateRequest() throws Exception {
MessageId messageId1 = new MessageId(getRandomId());
Collection<MessageId> ids = asList(messageId, messageId1);
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
oneOf(database).getMessagesToRequest(txn, contactId, 123);
will(returnValue(ids));
oneOf(database).removeOfferedMessages(txn, contactId, ids);
oneOf(database).commitTransaction(txn);
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager);
db.transaction(false, transaction -> {
Request r = db.generateRequest(transaction, contactId, 123);
assertNotNull(r);
assertEquals(ids, r.getMessageIds());
});
}
@Test
public void testGenerateRequestedBatch() throws Exception {
Collection<MessageId> ids = asList(messageId, messageId1);
@@ -951,11 +920,11 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
oneOf(database).getRequestedMessagesToSend(txn, contactId,
MAX_MESSAGE_LENGTH * 2, maxLatency);
will(returnValue(ids));
oneOf(database).getMessage(txn, messageId);
oneOf(database).getSmallMessage(txn, messageId);
will(returnValue(message));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId,
maxLatency);
oneOf(database).getMessage(txn, messageId1);
oneOf(database).getSmallMessage(txn, messageId1);
will(returnValue(message1));
oneOf(database).updateExpiryTimeAndEta(txn, contactId, messageId1,
maxLatency);
@@ -1018,10 +987,10 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
oneOf(database).raiseAckFlag(txn, contactId, messageId);
oneOf(database).commitTransaction(txn);
// First time: the message was received and added
oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
oneOf(eventBus).broadcast(with(any(MessagesToAckEvent.class)));
oneOf(eventBus).broadcast(with(any(MessageAddedEvent.class)));
// Second time: the message needs to be acked
oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
oneOf(eventBus).broadcast(with(any(MessagesToAckEvent.class)));
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager);
@@ -1049,7 +1018,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
oneOf(database).raiseAckFlag(txn, contactId, messageId);
oneOf(database).commitTransaction(txn);
// The message was received but not added
oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
oneOf(eventBus).broadcast(with(any(MessagesToAckEvent.class)));
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager);
@@ -1080,19 +1049,15 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
public void testReceiveOffer() throws Exception {
MessageId messageId1 = new MessageId(getRandomId());
MessageId messageId2 = new MessageId(getRandomId());
MessageId messageId3 = new MessageId(getRandomId());
context.checking(new Expectations() {{
oneOf(database).startTransaction();
will(returnValue(txn));
oneOf(database).containsContact(txn, contactId);
will(returnValue(true));
// There's room for two more offered messages
oneOf(database).countOfferedMessages(txn, contactId);
will(returnValue(MAX_OFFERED_MESSAGES - 2));
// The first message isn't visible - request it
oneOf(database).containsVisibleMessage(txn, contactId, messageId);
will(returnValue(false));
oneOf(database).addOfferedMessage(txn, contactId, messageId);
// The second message is visible - ack it
oneOf(database).containsVisibleMessage(txn, contactId, messageId1);
will(returnValue(true));
@@ -1101,19 +1066,14 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
// The third message isn't visible - request it
oneOf(database).containsVisibleMessage(txn, contactId, messageId2);
will(returnValue(false));
oneOf(database).addOfferedMessage(txn, contactId, messageId2);
// The fourth message isn't visible, but there's no room to store it
oneOf(database).containsVisibleMessage(txn, contactId, messageId3);
will(returnValue(false));
oneOf(database).commitTransaction(txn);
oneOf(eventBus).broadcast(with(any(MessageToAckEvent.class)));
oneOf(eventBus).broadcast(with(any(MessageToRequestEvent.class)));
oneOf(eventBus).broadcast(with(any(MessagesToAckEvent.class)));
oneOf(eventBus).broadcast(with(any(MessagesToRequestEvent.class)));
}});
DatabaseComponent db = createDatabaseComponent(database, eventBus,
eventExecutor, shutdownManager);
Offer o = new Offer(asList(messageId, messageId1,
messageId2, messageId3));
Offer o = new Offer(asList(messageId, messageId1, messageId2));
db.transaction(false, transaction ->
db.receiveOffer(transaction, contactId, o));
}

View File

@@ -3,11 +3,9 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.test.UTest;
import java.io.IOException;
@@ -32,8 +30,7 @@ public abstract class DatabasePerformanceComparisonTest
private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock);
DatabaseConfig databaseConfig, Clock clock);
@Override
protected void benchmark(String name,
@@ -76,8 +73,7 @@ public abstract class DatabasePerformanceComparisonTest
private Database<Connection> openDatabase(boolean conditionA)
throws DbException {
Database<Connection> db = createDatabase(conditionA,
new TestDatabaseConfig(testDir), new TestMessageFactory(),
new SystemClock());
new TestDatabaseConfig(testDir), new SystemClock());
db.open(databaseKey, null);
return db;
}

View File

@@ -41,7 +41,6 @@ import static org.briarproject.bramble.test.TestUtils.getGroup;
import static org.briarproject.bramble.test.TestUtils.getIdentity;
import static org.briarproject.bramble.test.TestUtils.getMessage;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
import static org.briarproject.bramble.test.UTest.Result.INCONCLUSIVE;
import static org.briarproject.bramble.test.UTest.Z_CRITICAL_0_1;
@@ -81,7 +80,6 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
private static final int METADATA_KEYS_PER_MESSAGE = 5;
private static final int METADATA_KEY_LENGTH = 10;
private static final int METADATA_VALUE_LENGTH = 100;
private static final int OFFERED_MESSAGES_PER_CONTACT = 100;
/**
* How many benchmark iterations to run in each block.
@@ -192,16 +190,6 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
});
}
@Test
public void testCountOfferedMessages() throws Exception {
String name = "countOfferedMessages(T, ContactId)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.countOfferedMessages(txn, pickRandom(contacts).getId());
db.commitTransaction(txn);
});
}
@Test
public void testGetContact() throws Exception {
String name = "getContact(T, ContactId)";
@@ -454,17 +442,6 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
});
}
@Test
public void testGetMessagesToRequest() throws Exception {
String name = "getMessagesToRequest(T, ContactId, int)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getMessagesToRequest(txn, pickRandom(contacts).getId(),
MAX_MESSAGE_IDS);
db.commitTransaction(txn);
});
}
@Test
public void testGetMessagesToSend() throws Exception {
String name = "getMessagesToSend(T, ContactId, int)";
@@ -507,11 +484,11 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
}
@Test
public void testGetMessage() throws Exception {
String name = "getMessage(T, MessageId)";
public void testGetSmallMessage() throws Exception {
String name = "getSmallMessage(T, MessageId)";
benchmark(name, db -> {
Connection txn = db.startTransaction();
db.getMessage(txn, pickRandom(messages).getId());
db.getSmallMessage(txn, pickRandom(messages).getId());
db.commitTransaction(txn);
});
}
@@ -583,9 +560,6 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
groupMessages.get(g.getId()).add(m.getId());
}
}
for (int j = 0; j < OFFERED_MESSAGES_PER_CONTACT; j++) {
db.addOfferedMessage(txn, c, new MessageId(getRandomId()));
}
}
for (int i = 0; i < LOCAL_GROUPS; i++) {
Group g = getGroup(clientIds.get(i % CLIENTS), 123);

View File

@@ -3,11 +3,9 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.system.SystemClock;
import org.briarproject.bramble.test.TestDatabaseConfig;
import org.briarproject.bramble.test.TestMessageFactory;
import org.briarproject.bramble.util.IoUtils;
import java.io.File;
@@ -26,7 +24,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private SecretKey databaseKey = getSecretKey();
abstract Database<Connection> createDatabase(DatabaseConfig databaseConfig,
MessageFactory messageFactory, Clock clock);
Clock clock);
@Nullable
protected abstract File getTraceFile();
@@ -48,8 +46,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
private Database<Connection> openDatabase() throws DbException {
Database<Connection> db = createDatabase(
new TestDatabaseConfig(testDir), new TestMessageFactory(),
new SystemClock());
new TestDatabaseConfig(testDir), new SystemClock());
db.open(databaseKey, null);
return db;
}

View File

@@ -16,6 +16,6 @@ public class H2DatabasePerformanceTest extends SingleDatabasePerformanceTest {
@Override
protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
return new H2Database(config, clock);
}
}

View File

@@ -9,6 +9,6 @@ public class H2DatabaseTest extends JdbcDatabaseTest {
@Override
protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new H2Database(config, messageFactory, clock);
return new H2Database(config, clock);
}
}

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -15,8 +14,8 @@ public class H2DatabaseTraceTest extends DatabaseTraceTest {
@Override
Database<Connection> createDatabase(DatabaseConfig databaseConfig,
MessageFactory messageFactory, Clock clock) {
return new H2Database(databaseConfig, messageFactory, clock) {
Clock clock) {
return new H2Database(databaseConfig, clock) {
@Override
@Nonnull
String getUrl() {

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -13,11 +12,11 @@ public class H2HyperSqlDatabasePerformanceComparisonTest
@Override
Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, MessageFactory messageFactory,
DatabaseConfig databaseConfig,
Clock clock) {
if (conditionA)
return new H2Database(databaseConfig, messageFactory, clock);
else return new HyperSqlDatabase(databaseConfig, messageFactory, clock);
return new H2Database(databaseConfig, clock);
else return new HyperSqlDatabase(databaseConfig, clock);
}
@Override

View File

@@ -11,7 +11,7 @@ public class H2MigrationTest extends DatabaseMigrationTest {
@Override
Database<Connection> createDatabase(
List<Migration<Connection>> migrations) {
return new H2Database(config, messageFactory, clock) {
return new H2Database(config, clock) {
@Override
List<Migration<Connection>> getMigrations() {
return migrations;

View File

@@ -1,7 +1,6 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -18,9 +17,9 @@ public class H2SelfDatabasePerformanceComparisonTest
@Override
Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, MessageFactory messageFactory,
DatabaseConfig databaseConfig,
Clock clock) {
return new H2Database(databaseConfig, messageFactory, clock);
return new H2Database(databaseConfig, clock);
}
@Override

View File

@@ -3,7 +3,6 @@ package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DatabaseConfig;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.MessageFactory;
import org.briarproject.bramble.api.system.Clock;
import org.junit.Ignore;
@@ -20,12 +19,11 @@ public class H2SleepDatabasePerformanceComparisonTest
@Override
Database<Connection> createDatabase(boolean conditionA,
DatabaseConfig databaseConfig, MessageFactory messageFactory,
Clock clock) {
DatabaseConfig databaseConfig, Clock clock) {
if (conditionA) {
return new H2Database(databaseConfig, messageFactory, clock);
return new H2Database(databaseConfig, clock);
} else {
return new H2Database(databaseConfig, messageFactory, clock) {
return new H2Database(databaseConfig, clock) {
@Override
@NotNullByDefault
public void commitTransaction(Connection txn)

View File

@@ -17,6 +17,6 @@ public class HyperSqlDatabasePerformanceTest
@Override
protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new HyperSqlDatabase(config, messageFactory, clock);
return new HyperSqlDatabase(config, clock);
}
}

View File

@@ -9,6 +9,6 @@ public class HyperSqlDatabaseTest extends JdbcDatabaseTest {
@Override
protected JdbcDatabase createDatabase(DatabaseConfig config,
MessageFactory messageFactory, Clock clock) {
return new HyperSqlDatabase(config, messageFactory ,clock);
return new HyperSqlDatabase(config, clock);
}
}

View File

@@ -11,7 +11,7 @@ public class HyperSqlMigrationTest extends DatabaseMigrationTest {
@Override
Database<Connection> createDatabase(
List<Migration<Connection>> migrations) {
return new HyperSqlDatabase(config, messageFactory, clock) {
return new HyperSqlDatabase(config, clock) {
@Override
List<Migration<Connection>> getMigrations() {
return migrations;

View File

@@ -41,7 +41,6 @@ import org.junit.Test;
import java.io.File;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -166,7 +165,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertTrue(db.containsGroup(txn, groupId));
assertTrue(db.containsMessage(txn, messageId));
assertArrayEquals(message.getBody(),
db.getMessage(txn, messageId).getBody());
db.getSmallMessage(txn, messageId).getBody());
// Delete the records
db.removeMessage(txn, messageId);
@@ -1187,35 +1186,6 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
db.close();
}
@Test
public void testOfferedMessages() throws Exception {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a contact - initially there should be no offered messages
db.addIdentity(txn, identity);
assertEquals(contactId,
db.addContact(txn, author, localAuthor.getId(), null, true));
assertEquals(0, db.countOfferedMessages(txn, contactId));
// Add some offered messages and count them
List<MessageId> ids = new ArrayList<>();
for (int i = 0; i < 10; i++) {
MessageId m = new MessageId(getRandomId());
db.addOfferedMessage(txn, contactId, m);
ids.add(m);
}
assertEquals(10, db.countOfferedMessages(txn, contactId));
// Remove some of the offered messages and count again
List<MessageId> half = ids.subList(0, 5);
db.removeOfferedMessages(txn, contactId, half);
assertEquals(5, db.countOfferedMessages(txn, contactId));
db.commitTransaction(txn);
db.close();
}
@Test
public void testGroupMetadata() throws Exception {
Database<Connection> db = open(false);
@@ -1929,7 +1899,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
assertEquals(singletonList(messageId), ids);
// The message should be available
Message m = db.getMessage(txn, messageId);
Message m = db.getSmallMessage(txn, messageId);
assertEquals(messageId, m.getId());
assertEquals(groupId, m.getGroupId());
assertEquals(message.getTimestamp(), m.getTimestamp());
@@ -1949,7 +1919,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
// Requesting the message should throw an exception
try {
db.getMessage(txn, messageId);
db.getSmallMessage(txn, messageId);
fail();
} catch (MessageDeletedException expected) {
// Expected
@@ -2087,7 +2057,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
Connection txn = db.startTransaction();
try {
// Ask for a nonexistent message - an exception should be thrown
db.getMessage(txn, messageId);
db.getSmallMessage(txn, messageId);
fail();
} catch (DbException expected) {
// It should be possible to abort the transaction without error

View File

@@ -402,7 +402,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, fooUpdateId);
will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict);
@@ -469,7 +469,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup2.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, fooUpdateId);
will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict);
@@ -524,7 +524,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, updateId);
oneOf(clientHelper).getSmallMessageAsList(txn, updateId);
will(returnValue(update));
oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict);
@@ -562,7 +562,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, updateId);
oneOf(clientHelper).getSmallMessageAsList(txn, updateId);
will(returnValue(update));
oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict);
@@ -693,7 +693,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
will(returnValue(localGroupMessageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, localGroupUpdateId);
will(returnValue(oldUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties(
oldPropertiesDict);
@@ -758,7 +758,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId());
will(returnValue(localGroupMessageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, localGroupUpdateId);
will(returnValue(oldUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties(
oldPropertiesDict);
@@ -817,12 +817,12 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
localGroup.getId());
will(returnValue(messageMetadata));
// Retrieve and parse the latest local properties
oneOf(clientHelper).getMessageAsList(txn, fooVersion999);
oneOf(clientHelper).getSmallMessageAsList(txn, fooVersion999);
will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict);
will(returnValue(fooProperties));
oneOf(clientHelper).getMessageAsList(txn, barVersion3);
oneOf(clientHelper).getSmallMessageAsList(txn, barVersion3);
will(returnValue(barUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties(
barPropertiesDict);

View File

@@ -64,7 +64,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(noMsgTxn));
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY));
with(any(int.class)), with(MAX_LATENCY), with(true));
will(returnValue(null));
// Send the end of stream marker
oneOf(streamWriter).sendEndOfStream();
@@ -101,7 +101,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(msgTxn));
oneOf(db).generateBatch(with(msgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY));
with(any(int.class)), with(MAX_LATENCY), with(true));
will(returnValue(singletonList(message)));
oneOf(recordWriter).writeMessage(message);
// No more acks
@@ -113,7 +113,7 @@ public class SimplexOutgoingSessionTest extends BrambleMockTestCase {
oneOf(db).transactionWithNullableResult(with(false),
withNullableDbCallable(noMsgTxn));
oneOf(db).generateBatch(with(noMsgTxn), with(contactId),
with(any(int.class)), with(MAX_LATENCY));
with(any(int.class)), with(MAX_LATENCY), with(true));
will(returnValue(null));
// Send the end of stream marker
oneOf(streamWriter).sendEndOfStream();

View File

@@ -99,7 +99,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
context.checking(new DbExpectations() {{
// Load the first raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessage(txn, messageId);
oneOf(db).getSmallMessage(txn, messageId);
will(returnValue(message));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
@@ -118,7 +118,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
will(returnValue(emptyMap()));
// Load the second raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn2));
oneOf(db).getMessage(txn2, messageId1);
oneOf(db).getSmallMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -159,7 +159,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn, messageId);
will(returnValue(singletonMap(messageId1, DELIVERED)));
// Get the message and its metadata to deliver
oneOf(db).getMessage(txn, messageId);
oneOf(db).getSmallMessage(txn, messageId);
will(returnValue(message));
oneOf(db).getGroup(txn, groupId);
will(returnValue(group));
@@ -179,7 +179,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn1, messageId2);
will(returnValue(singletonMap(messageId1, DELIVERED)));
// Get the dependent and its metadata to deliver
oneOf(db).getMessage(txn1, messageId2);
oneOf(db).getSmallMessage(txn1, messageId2);
will(returnValue(message2));
oneOf(db).getGroup(txn1, groupId);
will(returnValue(group));
@@ -276,11 +276,11 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
context.checking(new DbExpectations() {{
// Load the first raw message - *gasp* it's gone!
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessage(txn, messageId);
oneOf(db).getSmallMessage(txn, messageId);
will(throwException(new NoSuchMessageException()));
// Load the second raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getMessage(txn1, messageId1);
oneOf(db).getSmallMessage(txn1, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn1, groupId);
will(returnValue(group));
@@ -317,14 +317,14 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
context.checking(new DbExpectations() {{
// Load the first raw message
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
oneOf(db).getMessage(txn, messageId);
oneOf(db).getSmallMessage(txn, messageId);
will(returnValue(message));
// Load the group - *gasp* it's gone!
oneOf(db).getGroup(txn, groupId);
will(throwException(new NoSuchGroupException()));
// Load the second raw message and group
oneOf(db).transactionWithResult(with(true), withDbCallable(txn1));
oneOf(db).getMessage(txn1, messageId1);
oneOf(db).getSmallMessage(txn1, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn1, groupId);
will(returnValue(group));
@@ -614,7 +614,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn2, messageId1);
will(returnValue(singletonMap(messageId, DELIVERED)));
// Get message 1 and its metadata
oneOf(db).getMessage(txn2, messageId1);
oneOf(db).getSmallMessage(txn2, messageId1);
will(returnValue(message1));
oneOf(db).getGroup(txn2, groupId);
will(returnValue(group));
@@ -634,7 +634,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn3, messageId2);
will(returnValue(singletonMap(messageId, DELIVERED)));
// Get message 2 and its metadata
oneOf(db).getMessage(txn3, messageId2);
oneOf(db).getSmallMessage(txn3, messageId2);
will(returnValue(message2));
oneOf(db).getGroup(txn3, groupId);
will(returnValue(group));
@@ -654,7 +654,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn4, messageId3);
will(returnValue(twoDependencies));
// Get message 3 and its metadata
oneOf(db).getMessage(txn4, messageId3);
oneOf(db).getSmallMessage(txn4, messageId3);
will(returnValue(message3));
oneOf(db).getGroup(txn4, groupId);
will(returnValue(group));
@@ -677,7 +677,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
oneOf(db).getMessageDependencies(txn6, messageId4);
will(returnValue(singletonMap(messageId3, DELIVERED)));
// Get message 4 and its metadata
oneOf(db).getMessage(txn6, messageId4);
oneOf(db).getSmallMessage(txn6, messageId4);
will(returnValue(message4));
oneOf(db).getGroup(txn6, groupId);
will(returnValue(group));

View File

@@ -184,7 +184,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId());
will(returnValue(singletonMap(localUpdateId, localUpdateMeta)));
// Load the latest local update
oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody));
// Latest local update is up-to-date, no visibilities have changed
}});
@@ -206,7 +206,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
// Load the old client versions
oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(singletonList(localVersionsId)));
oneOf(clientHelper).getMessageAsList(txn, localVersionsId);
oneOf(clientHelper).getSmallMessageAsList(txn, localVersionsId);
will(returnValue(localVersionsBody));
// Client versions are up-to-date
}});
@@ -248,7 +248,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
// Load the old client versions
oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(singletonList(oldLocalVersionsId)));
oneOf(clientHelper).getMessageAsList(txn, oldLocalVersionsId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalVersionsId);
will(returnValue(oldLocalVersionsBody));
// Delete the old client versions
oneOf(db).removeMessage(txn, oldLocalVersionsId);
@@ -272,7 +272,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
will(returnValue(singletonMap(oldLocalUpdateId,
oldLocalUpdateMeta)));
// Load the latest local update
oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody));
// Delete the latest local update
oneOf(db).deleteMessage(txn, oldLocalUpdateId);
@@ -344,7 +344,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
// Load the old client versions
oneOf(db).getMessageIds(txn, localGroup.getId());
will(returnValue(singletonList(oldLocalVersionsId)));
oneOf(clientHelper).getMessageAsList(txn, oldLocalVersionsId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalVersionsId);
will(returnValue(oldLocalVersionsBody));
// Delete the old client versions
oneOf(db).removeMessage(txn, oldLocalVersionsId);
@@ -367,10 +367,10 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId());
will(returnValue(messageMetadata));
// Load the latest local update
oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody));
// Load the latest remote update
oneOf(clientHelper).getMessageAsList(txn, oldRemoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldRemoteUpdateId);
will(returnValue(oldRemoteUpdateBody));
// Delete the latest local update
oneOf(db).deleteMessage(txn, oldLocalUpdateId);
@@ -451,10 +451,10 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId());
will(returnValue(messageMetadata));
// Load the latest local update
oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody));
// Load the latest remote update
oneOf(clientHelper).getMessageAsList(txn, oldRemoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldRemoteUpdateId);
will(returnValue(oldRemoteUpdateBody));
// Delete the old remote update
oneOf(db).deleteMessage(txn, oldRemoteUpdateId);
@@ -490,7 +490,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
will(returnValue(singletonMap(oldLocalUpdateId,
oldLocalUpdateMeta)));
// Load the latest local update
oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody));
// Get client ID
oneOf(clientHelper).getGroupMetadataAsDictionary(txn,
@@ -557,10 +557,10 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId());
will(returnValue(messageMetadata));
// Load the latest local update
oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody));
// Load the latest remote update
oneOf(clientHelper).getMessageAsList(txn, oldRemoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldRemoteUpdateId);
will(returnValue(oldRemoteUpdateBody));
// Delete the old remote update
oneOf(db).deleteMessage(txn, oldRemoteUpdateId);
@@ -630,10 +630,10 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
contactGroup.getId());
will(returnValue(messageMetadata));
// Load the latest local update
oneOf(clientHelper).getMessageAsList(txn, oldLocalUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldLocalUpdateId);
will(returnValue(oldLocalUpdateBody));
// Load the latest remote update
oneOf(clientHelper).getMessageAsList(txn, oldRemoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, oldRemoteUpdateId);
will(returnValue(oldRemoteUpdateBody));
// Delete the old remote update
oneOf(db).deleteMessage(txn, oldRemoteUpdateId);
@@ -734,9 +734,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody));
oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody));
}});
@@ -769,9 +769,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody));
oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody));
}});
@@ -804,9 +804,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody));
oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody));
}});
@@ -839,9 +839,9 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, localUpdateId);
will(returnValue(localUpdateBody));
oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody));
}});
@@ -901,7 +901,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody));
}});
@@ -933,7 +933,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody));
}});
@@ -965,7 +965,7 @@ public class ClientVersioningManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId());
will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, remoteUpdateId);
oneOf(clientHelper).getSmallMessageAsList(txn, remoteUpdateId);
will(returnValue(remoteUpdateBody));
}});

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@@ -0,0 +1,43 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="0.20807062"
android:scaleY="0.20807062"
android:translateX="19.73077"
android:translateY="19.73077">
<path
android:pathData="M94,144.5V264c0,9.7 7.9,17.7 17.7,17.7h8.3c9.7,0 17.7,-8 17.7,-17.7V144.5Z"
android:fillColor="#87c214"
android:strokeColor="#00000000"/>
<path
android:pathData="M137.7,86.8V64.3c0,-9.7 -8,-17.7 -17.7,-17.7h-8.3C102,46.6 94,54.6 94,64.3v22.5z"
android:fillColor="#87c214"
android:strokeColor="#00000000"/>
<path
android:pathData="M234.7,183.8V64.3c0,-9.7 -7.9,-17.7 -17.7,-17.7h-8.3c-9.7,0 -17.7,8 -17.7,17.7v119.5z"
android:fillColor="#87c214"
android:strokeColor="#00000000"/>
<path
android:pathData="M191,241.5V264c0,9.7 8,17.7 17.7,17.7h8.3c9.7,0 17.7,-8 17.7,-17.7v-22.5z"
android:fillColor="#87c214"
android:strokeColor="#00000000"/>
<path
android:pathData="M87,190.8H64.5c-9.7,0 -17.7,7.9 -17.7,17.7v8.3c0,9.7 7.9,17.7 17.7,17.7H87Z"
android:fillColor="#95d220"
android:strokeColor="#00000000"/>
<path
android:pathData="M264.2,190.8H144.7v43.7h119.5c9.7,0 17.7,-8 17.7,-17.7v-8.3c-0.1,-9.7 -8,-17.7 -17.7,-17.7z"
android:fillColor="#95d220"
android:strokeColor="#00000000"/>
<path
android:pathData="M184,93.8H64.5c-9.7,0 -17.7,7.9 -17.7,17.7v8.3c0,9.7 7.9,17.7 17.7,17.7H184Z"
android:fillColor="#95d220"
android:strokeColor="#00000000"/>
<path
android:pathData="m264.2,93.8h-22.5v43.7h22.5c9.7,0 17.7,-7.9 17.7,-17.7v-8.3c-0.1,-9.7 -8,-17.7 -17.7,-17.7z"
android:fillColor="#95d220"
android:strokeColor="#00000000"/>
</group>
</vector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -215,7 +215,6 @@
<string name="connecting_to_device">يتم الإتصال بالجهاز\u2026</string>
<string name="authenticating_with_device">يتم التوثيق مع الجهاز\u2026</string>
<string name="connection_error_title">لم يمكن الإتصال بجهة إتصالك</string>
<string name="connection_error_explanation">رجاءًا التأكد أن كليكما متصل بنفس شبكة الواي فاي.</string>
<string name="connection_error_feedback">إذا إستمرت المشكلة، رجاءًا <a href="feedback">أرسل تقرير </a> لمساعدتنا على تحسين التطبيق.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">إضافة جهة اتصال عن بعد </string>

View File

@@ -162,7 +162,6 @@
<string name="connecting_to_device">Cihaza qoşulma /2026</string>
<string name="authenticating_with_device">Cihazla təsdiqlənir \u2026</string>
<string name="connection_error_title">Kontaktınıza qoşula bilmədi</string>
<string name="connection_error_explanation">Həmin Wi-Fi şəbəkəsinə qoşulduğunuzu yoxlayın.</string>
<string name="connection_error_feedback"><a href="feedback">Bu problem davam edərsə, tətbiqin təkmilləşdirilməsinə kömək etmək üçün rəy göndərin.</a></string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Məsafədə kontakt əlavə etmək </string>

View File

@@ -134,7 +134,6 @@
<string name="connecting_to_device">Povezujem se sa uređajem\u2026</string>
<string name="authenticating_with_device">Autentikacija sa uređajem\u2026</string>
<string name="connection_error_title">Nije moguće povezivanje sa vašim kontaktom</string>
<string name="connection_error_explanation">Provjerite jeste li oboje povezani na ist Wi-Fi mrežu.</string>
<string name="connection_error_feedback">Ako se problem ponavlja, Molimo vas <a href="feedback">pošaljite povratne informacije</a> kako bi pomogli poboljšanju aplikacije.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Dodaj udaljeni konktakt</string>

View File

@@ -27,7 +27,7 @@
<string name="enter_password">Contrasenya</string>
<string name="try_again">La contrasenya és incorrecta, torneu a escriure-la</string>
<string name="dialog_title_cannot_check_password">No es pot verificar la contrasenya</string>
<string name="dialog_message_cannot_check_password">El Briar no pot verificar la contrasenya. Proveu de reiniciar el vostre aparell per a solucionar aquest problema.</string>
<string name="dialog_message_cannot_check_password">Briar no pot verificar la contrasenya. Proveu de reiniciar el vostre aparell per a solucionar aquest problema.</string>
<string name="sign_in_button">Inicia la sessió</string>
<string name="forgotten_password">No recordo la contrasenya</string>
<string name="dialog_title_lost_password">Contrasenya perduda</string>
@@ -44,9 +44,9 @@
<item quantity="other">Aquesta és una versió de prova de Briar. El vostre compte caducarà en %d dies i no es podrà renovar.</item>
</plurals>
<string name="expiry_date_reached">Aquesta versió de Briar ha caducat.\nGràcies per haver-lo provat!</string>
<string name="download_briar">Per continuar utilitzant el Briar, baixeu la darrera versió.</string>
<string name="download_briar">Per continuar utilitzant Briar, baixeu la darrera versió.</string>
<string name="create_new_account">Haureu de crear un compte nou, però podeu utilitzar el mateix sobrenom.</string>
<string name="download_briar_button">Baixa l\'última versió</string>
<string name="download_briar_button">Descarrega la darrera versió</string>
<string name="startup_open_database">S\'està desxifrant la base de dades...</string>
<string name="startup_migrate_database">S\'està actualitzant la base de dades...</string>
<string name="startup_compact_database">S\'està compactant la base de dades...</string>
@@ -61,12 +61,36 @@
<string name="lock_button">Bloqueja l\'aplicació</string>
<string name="settings_button">Configuració</string>
<string name="sign_out_button">Tanca la sessió </string>
<string name="transports_onboarding_text">Toqueu per decidir com es connecta Briar als vostres contactes.</string>
<!--Transports: Tor-->
<string name="transport_tor">Internet</string>
<string name="tor_device_status_online_wifi">El mòbil té accés a Internet via WiFi</string>
<string name="tor_device_status_online_mobile">El mòbil té accés a Internet via dades</string>
<string name="tor_device_status_offline">El mòbil no té accés a Internet</string>
<string name="tor_plugin_status_enabling">Briar s\'està connectant a Internet</string>
<string name="tor_plugin_status_active">Briar està connectat a Internet</string>
<string name="tor_plugin_status_inactive">Briar no pot connectar-se a Internet</string>
<string name="tor_plugin_status_disabled">Briar està configurat per a no emprar Internet</string>
<string name="tor_plugin_status_disabled_mobile_data">Briar està configurat per a no emprar dades mòbils</string>
<string name="tor_plugin_status_disabled_battery">Briar està configurat per a no usar Internet mentre funciona amb bateria</string>
<string name="tor_plugin_status_disabled_country_blocked">Briar està configurat per a no emprar Internet en aquest país</string>
<!--Transports: Wi-Fi-->
<string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">La mateixa xarxa WiFi</string>
<string name="lan_device_status_on">El mòbil està connectat a WiFi</string>
<string name="lan_device_status_off">El mòbil no està connectat a WiFi</string>
<string name="lan_plugin_status_enabling">Briar s\'està connectant a la xarxa WiFi</string>
<string name="lan_plugin_status_active">Briar està connectat a la xarxa WiFi</string>
<string name="lan_plugin_status_inactive">Briar no pot connectar-se a la xarxa WiFi</string>
<string name="lan_plugin_status_disabled">Briar està configurat per a no emprar la xarxa WiFi</string>
<!--Transports: Bluetooth-->
<string name="transport_bt">Bluetooth</string>
<string name="bt_device_status_on">El Bluetooth del mòbil està apagat</string>
<string name="bt_device_status_off">El Bluetooth del mòbil està engegat</string>
<string name="bt_plugin_status_enabling">Briar s\'està connectant a Bluetooth</string>
<string name="bt_plugin_status_active">Briar està connectat a Bluetooth</string>
<string name="bt_plugin_status_inactive">Briar no pot connectar-se a Bluetooth</string>
<string name="bt_plugin_status_disabled">Briar està configurat per a no emprar Bluetooth</string>
<!--Notifications-->
<string name="reminder_notification_title">Heu sortit de Briar</string>
<string name="reminder_notification_text">Toqueu per a reiniciar la sessió.</string>
@@ -112,7 +136,7 @@
<string name="fix">Corregeix</string>
<string name="help">Ajuda</string>
<string name="sorry">Ens sap greu</string>
<string name="error_start_activity">No disponible al vostre sistema</string>
<string name="error_start_activity">No està disponible en el vostre sistema</string>
<string name="status_heading">Estat</string>
<!--Contacts and Private Conversations-->
<string name="no_contacts">No hi ha cap contacte per mostrar</string>
@@ -128,16 +152,16 @@
<string name="set_contact_alias">Canvia el nom del contacte</string>
<string name="set_contact_alias_hint">Nom del contacte</string>
<string name="set_alias_button">Canvia</string>
<string name="delete_all_messages">Suprimeix tots els missatges</string>
<string name="dialog_title_delete_all_messages">Confirmeu la supressió dels missatges</string>
<string name="dialog_message_delete_all_messages">Esteu segur que voleu suprimir tots els missatges?</string>
<string name="dialog_title_not_all_messages_deleted">No s\'ha pogut suprimir tots els missatges</string>
<string name="dialog_message_not_deleted_ongoing_both">Els missatges relacionats amb introduccions i invitacions pendents no es poden suprimir fins que es finalitzin.</string>
<string name="dialog_message_not_deleted_ongoing_introductions">Els missatges relacionats amb introduccions pendents no es poden suprimir fins que es finalitzin.</string>
<string name="dialog_message_not_deleted_ongoing_invitations">Els missatges relacionats amb invitacions pendents no es poden suprimir fins que es finalitzin.</string>
<string name="delete_all_messages">Esborra tots els missatges</string>
<string name="dialog_title_delete_all_messages">Confirmeu l\'esborrat dels missatges</string>
<string name="dialog_message_delete_all_messages">Segur que voleu esborrar tots els missatges?</string>
<string name="dialog_title_not_all_messages_deleted">No s\'han pogut esborrar tots els missatges</string>
<string name="dialog_message_not_deleted_ongoing_both">Els missatges relacionats amb presentacions i invitacions pendents no es poden suprimir fins que finalitzen.</string>
<string name="dialog_message_not_deleted_ongoing_introductions">Els missatges relacionats amb presentacions pendents no es poden suprimir fins que finalitzen.</string>
<string name="dialog_message_not_deleted_ongoing_invitations">Els missatges relacionats amb invitacions pendents no es poden suprimir fins que finalitzen.</string>
<string name="dialog_message_not_deleted_partly_downloaded">Els missatges baixats parcialment no es poden suprimir fins que s\'acabin de baixar.</string>
<string name="dialog_message_not_deleted_not_all_selected_both">Per a suprimir una invitació o una introducció, cal que seleccioneu la sol·licitdu i la resposta.</string>
<string name="dialog_message_not_deleted_not_all_selected_introductions">Per a suprimir una introducció, cal que seleccioneu la sol·licitud i la resposta.</string>
<string name="dialog_message_not_deleted_not_all_selected_both">Per a suprimir una invitació o una presentació, cal que seleccioneu la sol·licitud i la resposta.</string>
<string name="dialog_message_not_deleted_not_all_selected_introductions">Per a suprimir una presentació, cal que seleccioneu la sol·licitud i la resposta.</string>
<string name="dialog_message_not_deleted_not_all_selected_invitations">Per a suprimir una invitació, cal que seleccioneu la sol·licitud i la resposta.</string>
<string name="delete_contact">Suprimeix aquest contacte</string>
<string name="dialog_title_delete_contact">Confirmeu la supressió del contacte</string>
@@ -172,7 +196,6 @@ Així que l\'actualitzi li veureu una icona diferent .</string>
<string name="connecting_to_device">Connectant-se al dispositiu\u2026</string>
<string name="authenticating_with_device">Autenticant-se amb el dispositiu\u2026</string>
<string name="connection_error_title">No ha pogut connectar-se al vostre contacte</string>
<string name="connection_error_explanation">Comproveu que esteu connectats a la mateixa xarxa Wi-Fi.</string>
<string name="connection_error_feedback">Si aquest problema persisteix, <a href="feedback">envieu-nos un comentari</a> per ajudar-nos a millorar l\'aplicació.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Afegeix un contacte llunyà</string>
@@ -413,10 +436,20 @@ Així que l\'actualitzi li veureu una icona diferent .</string>
<string name="pref_theme_auto">Automàtic (segons l\'hora)</string>
<string name="pref_theme_system">Valor per defecte del sistema</string>
<!--Settings Connections-->
<string name="network_settings_title">Connexions</string>
<string name="bluetooth_setting">Connectat als contactes via Bluetooth</string>
<string name="wifi_setting">Connectat als contactes en la mateixa xarxa WiFi</string>
<string name="tor_enable_title">Connectat als contactes via Internet</string>
<string name="tor_enable_summary">Totes les connexions van via la xarxa Tor per augmentar privacitat</string>
<string name="tor_network_setting">Mètode de connexió per a la xarxa Tor</string>
<string name="tor_network_setting_automatic">Automàtic, basat en la posició</string>
<string name="tor_network_setting_without_bridges">Usa la xarxa Tor sense ponts</string>
<string name="tor_network_setting_with_bridges">Usa la xarxa Tor amb ponts</string>
<string name="tor_network_setting_never">No connectis a Internet</string>
<!--How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)"-->
<string name="tor_network_setting_summary">Automàtic: %1$s (a %2$s)</string>
<string name="tor_mobile_data_title">Usa dades mòbils</string>
<string name="tor_only_when_charging_title">Només connecta\'t a Internet mentre s\'està carregant </string>
<string name="tor_only_when_charging_summary">Desactiva la connexió a Internet quan el dispositiu estigui funcionant amb la bateria</string>
<!--Settings Security and Panic-->
<string name="security_settings_title">Seguretat</string>
@@ -527,6 +560,7 @@ Així que l\'actualitzi li veureu una icona diferent .</string>
<string name="lock_is_locked">Briar està bloquejat</string>
<string name="lock_tap_to_unlock">Toqueu per desbloquejar-lo</string>
<!--Connections Screen-->
<string name="transports_help_text">Briar pot contactar els vostres contactes via Internet, WiFi o Bluetooth.\n\nTotes les connexions d\'Internet van via la xarxa Tor per privacitat.\n\nSi es pot arribar a un contacte per diversos mètodes, Briar els usa tots simultàniament.</string>
<!--Screenshots-->
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_alice">Alba</string>

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Verbinde mit Gerät\u2026</string>
<string name="authenticating_with_device">Authentifiziere Gerät\u2026</string>
<string name="connection_error_title">Keine Verbindung zum Kontakt</string>
<string name="connection_error_explanation">Überprüfe, ob ihr beide mit demselben WLAN-Netzwerk verbunden seid.</string>
<string name="connection_error_feedback">Wenn das Problem weiterbesteht, hilf uns die App zu verbessern und <a href="feedback">schicke Feedback</a>.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Kontakt aus der Ferne hinzufügen</string>
@@ -550,6 +549,7 @@
<string name="permission_camera_location_title">Kamera und Standort</string>
<string name="permission_camera_location_request_body">Um den QR-Code zu scannen, braucht Briar Zugriff auf die Kamera.\n\nUm Bluetooth-Geräte zu finden, braucht Briar Zugriff auf deinen Standort.\n\nBriar speichert weder deinen Standort noch gibt es ihn an andere weiter.</string>
<string name="permission_camera_denied_body">Du hast den Zugriff auf die Kamera verweigert, aber das Hinzufügen von Kontakten erfordert die Verwendung der Kamera.\n\nBitte gewähre den Zugriff.</string>
<string name="permission_location_denied_body">Du hast den Zugriff auf deinen Standort verweigert, aber Briar benötigt diese Berechtigung, um Bluetooth-Geräte zu erkennen.\n\nBitte gewähre den Zugriff.</string>
<string name="qr_code">QR-Code</string>
<string name="show_qr_code_fullscreen">QR-Code im Vollbildmodus anzeigen</string>
<!--App Locking-->

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Conectando al dispositivo\u2026</string>
<string name="authenticating_with_device">Autentificándose con el dispositivo\u2026</string>
<string name="connection_error_title">No se pudo conectar a tu contacto</string>
<string name="connection_error_explanation">Por favor comprobar que ambos estén conectados a la misma red Wi-Fi.</string>
<string name="connection_error_feedback">Si este problema persiste, por favor <a href="feedback">envía tus comentarios</a> para ayudarnos a mejorar la aplicación.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Añadir un Contacto a Distancia</string>
@@ -550,6 +549,7 @@
<string name="permission_camera_location_title">Cámara y ubicación</string>
<string name="permission_camera_location_request_body">Para escanear el código QR, Briar necesita acceso a la cámara.\n\nPara descubrir dispositivos Bluetooth, Briar necesita permiso para acceder tu ubicación.\n\nBriar no la almacena o la comparte con nadie.</string>
<string name="permission_camera_denied_body">Has denegado el acceso a la cámara, pero para añadir contactos se requiere el uso de la cámara.\n\nPor favor considera la posibilidad de conceder el acceso.</string>
<string name="permission_location_denied_body">Has denegado el acceso a tu ubicación, pero Briar necesita este permiso para descubrir dispositivos Bluetooth.\n\nPor favor considera la posibilidad de conceder el acceso.</string>
<string name="qr_code">Código QR</string>
<string name="show_qr_code_fullscreen">Mostrar código QR a pantalla completa</string>
<!--App Locking-->

View File

@@ -171,7 +171,6 @@
<string name="connecting_to_device">Gailura konektatzen\u2026</string>
<string name="authenticating_with_device">Gailuarekin autentifikatzen\u2026</string>
<string name="connection_error_title">Ezin izan da zure kontaktuarekin konektatu</string>
<string name="connection_error_explanation">Egiaztatu biak Wi-Fi sare berera konektatuta zaudetela.</string>
<string name="connection_error_feedback">Arazoa mantentzen bada, mesedez <a href="feedback">bidali iruzkin bat</a> aplikazioa hobetzen laguntzeko.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Gehitu urruneko kontaktua</string>

View File

@@ -69,10 +69,21 @@
<string name="sign_out_button">خروج</string>
<!--Transports: Tor-->
<string name="transport_tor">اینترنت</string>
<string name="tor_plugin_status_enabling">Briar در حال اتصال به اینترنت می باشد</string>
<string name="tor_plugin_status_active">Briar به اینترنت متصل شد</string>
<string name="tor_plugin_status_inactive">Briar نمی تواند به اینترنت متصل شود</string>
<!--Transports: Wi-Fi-->
<string name="transport_lan">وای فای</string>
<string name="transport_lan_long">همان شبکه وای-فای</string>
<string name="lan_device_status_on">موبایل شما به وای-فای وصل می باشد</string>
<string name="lan_device_status_off">موبایل شما به وای-فای وصل نیست</string>
<string name="lan_plugin_status_enabling">Briar در حال اتصال به شبکه وای-فای می باشد</string>
<!--Transports: Bluetooth-->
<string name="transport_bt">بلوتوث</string>
<string name="bt_device_status_on">بلوتوث موبایل شما روشن می باشد</string>
<string name="bt_device_status_off">بلوتوث موبایل شما خاموش می باشد</string>
<string name="bt_plugin_status_inactive">Briar نمی تواند به بلوتوث وصل شود</string>
<string name="bt_plugin_status_disabled">Briar طوری پیکربندی شده که از بلوتوث استفاده نکند</string>
<!--Notifications-->
<string name="reminder_notification_title">از Briar (برایر) خارج شد</string>
<string name="reminder_notification_text">برای وارد شدن دوباره ضربه بزنید.</string>
@@ -185,7 +196,6 @@
<string name="connecting_to_device">اتصال به دستگاهu2026\</string>
<string name="authenticating_with_device">تصدیق سازی با دستگاه u2026\</string>
<string name="connection_error_title">اتصال به مخاطب شما برقرار نشد</string>
<string name="connection_error_explanation">لطفا مطمئن شوید که هر دو شما به شبکه وای فای یکسان متصل هستید.</string>
<string name="connection_error_feedback">اگر این مشکل ادامه پیدا کرد، لطفا <a href="feedback">بازخورد ارسال کنید</a> تا به ما در بهبود برنامه کمک کنید.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">افزودن مخاطب از دور</string>

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Connexion à lappareil\u2026</string>
<string name="authenticating_with_device">Autentification avec lappareil\u2026</string>
<string name="connection_error_title">Impossible de se connecter à votre contact</string>
<string name="connection_error_explanation">Veuillez vérifier que vous êtes connecté au même réseau Wi-Fi.</string>
<string name="connection_error_feedback">Si le problème persiste, veuillez nous <a href="feedback">envoyer une rétroaction</a> pour nous aider à améliorer l\'appli.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Ajouter un contact éloigné</string>
@@ -550,6 +549,7 @@
<string name="permission_camera_location_title">Appareil photo et position</string>
<string name="permission_camera_location_request_body">Afin de balayer le code QR, Briar doit accéder à lappareil photo.\n\nAfin de découvrir des périphériques Bluetooth, Briar doit accéder à votre position.\n\nBriar nenregistre pas votre position et ne la partage avec personne.</string>
<string name="permission_camera_denied_body">Vous avez refusé laccès à la caméra, mais lajout de contacts exige lutilisation de celle-ci.\n\nVeuillez envisager dy accorder laccès.</string>
<string name="permission_location_denied_body">Vous avez refusé laccès à votre position géographique, mais Briar en a besoin pour découvrir les appareils Bluetooth.\n\nVeuillez envisager dy accorder laccès.</string>
<string name="qr_code">Code QR</string>
<string name="show_qr_code_fullscreen">Afficher le code QR en plein écran</string>
<!--App Locking-->

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Conectando co dispositivo\u2026</string>
<string name="authenticating_with_device">Autenticándose co dispositivo\u2026</string>
<string name="connection_error_title">Non se puido conectar co contacto</string>
<string name="connection_error_explanation">Por favor, comprobe que ambas están conectadas a mesma rede Wi-Fi.</string>
<string name="connection_error_feedback">Si persiste o problema,<a href="feedback">envíe un informe</a> para axudarnos a mellorar a app.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Engadir contacto a distancia</string>
@@ -550,6 +549,7 @@
<string name="permission_camera_location_title">Cámara e localización</string>
<string name="permission_camera_location_request_body">Para escanear o código QR, Briar precisa acceso a cámara.\n\nPara descubrir dispositivos Bluetooth, Briar precisa permiso a súa localización.\n\nBriar non garda a súa localización nin a comparte con ninguén.</string>
<string name="permission_camera_denied_body">Denegou o permiso de acceso a cámara, pero é necesario para engadir contactos.\n\nPor favor, considere conceder o permiso.</string>
<string name="permission_location_denied_body">Denegache o acceso á localización, mais Briar precisa este permiso para descubrir dispositivos Bluetooth.\n\nConsidera conceder o permiso.</string>
<string name="qr_code">Código QR</string>
<string name="show_qr_code_fullscreen">Amosar o código QR a pantalla completa</string>
<!--App Locking-->

View File

@@ -63,12 +63,36 @@
<string name="lock_button">נעל יישום</string>
<string name="settings_button">הגדרות</string>
<string name="sign_out_button">התנתק</string>
<string name="transports_onboarding_text">הקש כאן כדי לשלוט איך Briar מתחבר אל אנשי הקשר שלך.</string>
<!--Transports: Tor-->
<string name="transport_tor">אינטרנט</string>
<string name="tor_device_status_online_wifi">לטלפון שלך יש גישת אינטרנט באמצעות Wi-Fi</string>
<string name="tor_device_status_online_mobile">לטלפון שלך יש חיבור אינטרנט באמצעות נתונים סלולריים</string>
<string name="tor_device_status_offline">לטלפון שלך אין גישת אינטרנט</string>
<string name="tor_plugin_status_enabling">Briar מתחבר אל האינטרנט</string>
<string name="tor_plugin_status_active">Briar מחובר אל האינטרנט</string>
<string name="tor_plugin_status_inactive">Briar אינו יכול להתחבר אל האינטרנט</string>
<string name="tor_plugin_status_disabled">Briar מתוצר לא להשתמש באינטרנט</string>
<string name="tor_plugin_status_disabled_mobile_data">Briar מתוצר לא להשתמש בנתונים סלולריים</string>
<string name="tor_plugin_status_disabled_battery">Briar מתוצר לא להשתמש באינטרנט בעת הרצה על סוללה</string>
<string name="tor_plugin_status_disabled_country_blocked">Briar מתוצר לא להשתמש באינטרנט במדינה זו</string>
<!--Transports: Wi-Fi-->
<string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">אותה רשת Wi-Fi</string>
<string name="lan_device_status_on">הטלפון שלך מחובר אל Wi-Fi</string>
<string name="lan_device_status_off">הטלפון שלך אינו מחובר אל Wi-Fi</string>
<string name="lan_plugin_status_enabling">Briar מתחבר אל רשת ה־Wi-Fi</string>
<string name="lan_plugin_status_active">Briar מחובר אל רשת ה־Wi-Fi</string>
<string name="lan_plugin_status_inactive">Briar אינו יכול להתחבר אל רשת ה־Wi-Fi</string>
<string name="lan_plugin_status_disabled">Briar מתוצר לא להשתמש ברשת ה־Wi-Fi</string>
<!--Transports: Bluetooth-->
<string name="transport_bt">שן כחולה</string>
<string name="transport_bt">Bluetooth</string>
<string name="bt_device_status_on">Bluetooth של הטלפון שלך מופעל</string>
<string name="bt_device_status_off">Bluetooth של הטלפון שלך מכובה</string>
<string name="bt_plugin_status_enabling">Briar מתחבר אל Bluetooth</string>
<string name="bt_plugin_status_active">Briar מחובר אל Bluetooth</string>
<string name="bt_plugin_status_inactive">Briar אינו יכול להתחבר אל Bluetooth</string>
<string name="bt_plugin_status_disabled">Briar מתוצר לא להשתמש ב־Bluetooth</string>
<!--Notifications-->
<string name="reminder_notification_title">נותקת מן Briar</string>
<string name="reminder_notification_text">הקש כדי להתחבר חזרה.</string>
@@ -181,7 +205,6 @@
<string name="connecting_to_device">מתחבר אל מכשיר\u2026</string>
<string name="authenticating_with_device">מזדהה מול המכשיר\u2026</string>
<string name="connection_error_title">לא היה ניתן להתחבר אל איש הקשר שלך</string>
<string name="connection_error_explanation">אנא בדוק ששניכם מחוברים אל אותה רשת Wi-Fi.</string>
<string name="connection_error_feedback">אם בעיה נמשכת, אנא <a href="feedback">שלח משוב</a> כדי לעזור לנו לשפר את היישום.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">הוסף איש קשר בקרבה</string>
@@ -436,10 +459,20 @@
<string name="pref_theme_auto">אוטומטי (שעות יום)</string>
<string name="pref_theme_system">ברירת מחדל</string>
<!--Settings Connections-->
<string name="network_settings_title">חיבורים</string>
<string name="bluetooth_setting">התחבר אל אנשי קשר באמצעות Bluetooth</string>
<string name="wifi_setting">התחבר אל אנשי קשר באותה רשת Wi-Fi</string>
<string name="tor_enable_title">התחבר אל אנשי קשר באמצעות האינטרנט</string>
<string name="tor_enable_summary">כל החיבורים עוברים דרך רשת Tor למען פרטיות</string>
<string name="tor_network_setting">שיטת חיבור עבור רשת Tor</string>
<string name="tor_network_setting_automatic">אוטומטי על סמך מיקום</string>
<string name="tor_network_setting_without_bridges">השתמש ברשת Tor בלי גשרים</string>
<string name="tor_network_setting_with_bridges">השתמש ברשת Tor עם גשרים</string>
<string name="tor_network_setting_never">אל תתחבר אל האינטרנט</string>
<!--How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)"-->
<string name="tor_network_setting_summary">אוטומטי: %1$s (תוך %2$s)</string>
<string name="tor_mobile_data_title">השתמש בנתונים סלולריים</string>
<string name="tor_only_when_charging_title">התחבר אל האינטרנט רק בעת טעינה</string>
<string name="tor_only_when_charging_summary">משבית חיבור אינטרנט כשהמכשיר עובד על סוללה</string>
<!--Settings Security and Panic-->
<string name="security_settings_title">אבטחה</string>
@@ -536,7 +569,7 @@
<string name="permission_camera_title">הרשאת מצלמה</string>
<string name="permission_camera_request_body">כדי לסרוק את קוד ה־QR, היישום Briar צריך גישה אל המצלמה.</string>
<string name="permission_location_title">הרשאת מיקום</string>
<string name="permission_location_request_body">כדי לגלות מכשירי שן־כחולה, Briar צריך הרשאה להשיג גישה אל מיקומך.\n\nBriar אינו מאחסן את מיקומך או משתף אותו עם אף אחד.</string>
<string name="permission_location_request_body">כדי לגלות מכשירי Bluetooth, היישום Briar צריך הרשאה להשיג גישה אל מיקומך.\n\nBriar אינו מאחסן את מיקומך או משתף אותו עם אף אחד.</string>
<string name="permission_camera_location_title">מצלמה ומיקום</string>
<string name="permission_camera_location_request_body">כדי לסרוק את קוד ה־QR, היישום Briar צריך הרשאה אל המצלמה.\n\nכדי לגלות מכשירי שן־כחולה, Briar צריך הרשאה להשיג גישה אל מיקומך.\n\nBriar אינו מאחסן את מיקומך או משתף אותו עם אף אחד.</string>
<string name="permission_camera_denied_body">דחית גישה אל המצלמה, אבל הוספת אנשי קשר דורשת שימוש במצלמה.\n\nאנא שקול הענקת גישה.</string>
@@ -550,6 +583,7 @@
<string name="lock_is_locked">Briar נעול</string>
<string name="lock_tap_to_unlock">הקש כדי לבטל נעילה</string>
<!--Connections Screen-->
<string name="transports_help_text">Briar יכול להתחבר אל אנשי הקשר שלך באמצעות האינטרנט, Wi-Fi או Bluetooth.\n\nכל חיבורי האינטרנט עוברים דרך רשת Tor למען פרטיות.\n\nאם איש קשר ניתן להשגה באמצעות שיטות רבות, Briar משתמש בהן במקביל.</string>
<!--Screenshots-->
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_alice">נועה</string>

View File

@@ -154,7 +154,6 @@
<string name="connecting_to_device">उपकरण \ u2026 से कनेक्ट हो रहा है</string>
<string name="authenticating_with_device">डिवाइस के साथ प्रमाणीकरण \ u2026</string>
<string name="connection_error_title">आपके संपर्क से कनेक्ट नहीं हो सका</string>
<string name="connection_error_explanation">कृपया जांचें कि आप दोनों एक ही वाई-फाई नेटवर्क से जुड़े हुए हैं।</string>
<string name="connection_error_feedback">यदि यह समस्या बनी रहती है, तो कृपया ऐप को बेहतर बनाने में हमारी सहायता के लिए <a href="feedback">फ़ीडबैक भेजें</a></string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">दूरी वाले संपर्क जोड़ें</string>

View File

@@ -197,7 +197,6 @@ Biztosan szeretné menteni?</string>
<string name="connecting_to_device">Csatlakozás az eszközhöz\u2026</string>
<string name="authenticating_with_device">Azonosítás az eszközzel\u2026</string>
<string name="connection_error_title">Nem sikerült csatlakozni a kapcsolatához</string>
<string name="connection_error_explanation">Ellenőrizzék, hogy mindketten ugyanahhoz a Wi-Fi hálózathoz vannak-e csatlakozva.</string>
<string name="connection_error_feedback">Ha ez a probléma tartósan fennáll, kérjük <a href="feedback">küldjön visszajelzést</a> nekünk, hogy segítsen fejleszteni az appot.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Távoli kapcsolat hozzá adása</string>

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Tengist við tæki\u2026</string>
<string name="authenticating_with_device">Auðkenni við tæki\u2026</string>
<string name="connection_error_title">Gat ekki tengst við tengiliðinn þinn</string>
<string name="connection_error_explanation">Athugaðu hvort þið séuð ekki báðir tengdir við sama þráðlausa Wi-Fi netið.</string>
<string name="connection_error_feedback">Ef þetta vandamál er viðvarandi, ættirðu að <a href="feedback">senda umsögn</a> til að hjálpa okkur að bæta forritið.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Bæta við fjarlægum tengilið</string>

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Connessione al dispositivo\u2026</string>
<string name="authenticating_with_device">Autenticazione con il dispositivo\u2026</string>
<string name="connection_error_title">Impossibile connettersi al tuo contatto</string>
<string name="connection_error_explanation">Verifica di essere entrambi connessi alla stessa rete Wi-Fi.</string>
<string name="connection_error_feedback">Se il problema persiste, <a href="feedback">invia un feedback</a> per aiutarci a migliorare l\'app.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Aggiungi contatto distante</string>

View File

@@ -149,7 +149,6 @@
<string name="connecting_to_device">デバイスに接続中\u2026</string>
<string name="authenticating_with_device">デバイス同士での認証中\u2026</string>
<string name="connection_error_title">連絡先に接続できませんでした</string>
<string name="connection_error_explanation">あなたと連絡相手、両方が同じWi-Fiネットワークに接続していることを確認してください。</string>
<string name="connection_error_feedback">この問題が解決しない場合、アプリを改善するために<a href="feedback">フィードバック</a>を送信してください。</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">離れた場所にいる相手を連絡先に追加</string>

View File

@@ -26,6 +26,8 @@
<!--Login-->
<string name="enter_password">비밀번호</string>
<string name="try_again">잘못된 비밀번호입니다. 다시 시도하세요.</string>
<string name="dialog_title_cannot_check_password">비밀번호를 확인할 수 없습니다</string>
<string name="dialog_message_cannot_check_password">비밀번호를 확인할 수 없었습니다. 이 문제를 해결하기 위해 기기를 재시작 해 보세요.</string>
<string name="sign_in_button">로그인</string>
<string name="forgotten_password">비밀번호를 잊어버렸습니다</string>
<string name="dialog_title_lost_password">비밀번호 분실</string>
@@ -41,7 +43,9 @@
<item quantity="other">이 Briar는 테스트용입니다. %d일 내에 계정이 만료되고 다시 되돌리지 못합니다.</item>
</plurals>
<string name="expiry_date_reached">이 소프트웨어는 만료되었습니다. \ n 테스트 해 주셔서 감사합니다!</string>
<string name="download_briar">Briar를 계속 이용하기 위해서는 최신 버전을 다운로드 해 주세요.</string>
<string name="create_new_account">새로운 계정을 만들어야 하지만, 같은 별명을 사용할 수 있습니다.</string>
<string name="download_briar_button">최신 버전 다운로드 받기</string>
<string name="startup_open_database">데이터베이스를 복호화하고 있습니다....</string>
<string name="startup_migrate_database">데이터베이스를 업그레이드 하고 있습니다...</string>
<string name="startup_compact_database">데이터베이스를 작게 만들고 있습니다...</string>
@@ -56,12 +60,36 @@
<string name="lock_button">앱 잠그기</string>
<string name="settings_button">설정</string>
<string name="sign_out_button">로그아웃</string>
<string name="transports_onboarding_text">여기를 눌러 Briar가 연락처와 연결하는 방법을 설정하세요.</string>
<!--Transports: Tor-->
<string name="transport_tor">인터넷</string>
<string name="tor_device_status_online_wifi">와이파이를 통해 인터넷에 연결하고 있습니다</string>
<string name="tor_device_status_online_mobile">모바일 데이터로 인터넷에 연결하고 있습니다</string>
<string name="tor_device_status_offline">인터넷에 연결돼 있지 않습니다</string>
<string name="tor_plugin_status_enabling">인터넷에 연결하고 있습니다</string>
<string name="tor_plugin_status_active">인터넷에 연결했습니다</string>
<string name="tor_plugin_status_inactive">인터넷에 연결하지 못했습니다</string>
<string name="tor_plugin_status_disabled">인터넷을 사용하지 않도록 설정돼 있습니다</string>
<string name="tor_plugin_status_disabled_mobile_data">모바일 데이터를 사용하지 않도록 설정돼 있습니다</string>
<string name="tor_plugin_status_disabled_battery">충전하지 않고 있을 때에는 인터넷을 사용하지 않도록 설정돼 있습니다</string>
<string name="tor_plugin_status_disabled_country_blocked">이 국가에서는 인터넷을 사용하지 않도록 설정돼 있습니다</string>
<!--Transports: Wi-Fi-->
<string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">동일한 와이파이 네트워크입니다</string>
<string name="lan_device_status_on">와이파이에 연결돼 있습니다</string>
<string name="lan_device_status_off">와이파이에 연결돼 있지 않습니다</string>
<string name="lan_plugin_status_enabling">와이파이에 연결 중입니다</string>
<string name="lan_plugin_status_active">와이파이에 연결됐습니다</string>
<string name="lan_plugin_status_inactive">와이파이에 연결하지 못했습니다</string>
<string name="lan_plugin_status_disabled">와이파이를 사용하지 않도록 설정돼 있습니다</string>
<!--Transports: Bluetooth-->
<string name="transport_bt">블루투스</string>
<string name="bt_device_status_on">블루투스가 켜져 있습니다</string>
<string name="bt_device_status_off">블루투스가 꺼져 있습니다</string>
<string name="bt_plugin_status_enabling">블루투스에 연결 중입니다</string>
<string name="bt_plugin_status_active">블루투스에 연결했습니다</string>
<string name="bt_plugin_status_inactive">블루투스에 연결하지 못했습니다</string>
<string name="bt_plugin_status_disabled">블루투스를 사용하지 않도록 설정돼 있습니다</string>
<!--Notifications-->
<string name="reminder_notification_title">Briar에서 로그아웃 됨</string>
<string name="reminder_notification_text">눌러서 다시 로그인하세요.</string>
@@ -103,6 +131,7 @@
<string name="fix">고치기</string>
<string name="help">도움</string>
<string name="sorry">죄송합니다</string>
<string name="error_start_activity">이 시스템에서는 지원되지 않습니다</string>
<string name="status_heading">상태</string>
<!--Contacts and Private Conversations-->
<string name="no_contacts">저장된 연락처가 없습니다</string>
@@ -118,6 +147,17 @@
<string name="set_contact_alias">연락처 이름 바꾸기</string>
<string name="set_contact_alias_hint">연락처 이름</string>
<string name="set_alias_button">바꾸기</string>
<string name="delete_all_messages">모든 메시지 지우기</string>
<string name="dialog_title_delete_all_messages">메시지 삭제 확인</string>
<string name="dialog_message_delete_all_messages">정말로 모든 메시지를 지우려고 하시나요?</string>
<string name="dialog_title_not_all_messages_deleted">모든 메시지를 지울 수는 없었습니다</string>
<string name="dialog_message_not_deleted_ongoing_both">진행 중인 초대와 소개와 관련된 메시지는 완료되기 전에는 지울 수 없습니다.</string>
<string name="dialog_message_not_deleted_ongoing_introductions">진행 중인 소개와 관련된 메시지는 완료되기 전에는 지울 수 없습니다.</string>
<string name="dialog_message_not_deleted_ongoing_invitations">진행 중인 초대와 관련된 메시지는 완료되기 전에는 지울 수 없습니다.</string>
<string name="dialog_message_not_deleted_partly_downloaded">부분적으로 다운로드 된 메시지는 다운로드가 완료되기 전까지는 지울 수 없습니다.</string>
<string name="dialog_message_not_deleted_not_all_selected_both">초대나 소개를 지우기 위해서는 요청을 선택하고 답을 주셔야 합니다.</string>
<string name="dialog_message_not_deleted_not_all_selected_introductions">소개를 지우기 위해서는 요청을 선택하고 답을 주셔야 합니다.</string>
<string name="dialog_message_not_deleted_not_all_selected_invitations">초대를 지우기 위해서는 요청을 선택하고 답을 주셔야 합니다.</string>
<string name="delete_contact">연락처 삭제하기</string>
<string name="dialog_title_delete_contact">연락처 삭제 확인</string>
<string name="dialog_message_delete_contact">정말로 이 연락처, 그리고 이 연락처와의 메시지를 모두 제거하시겠어요?</string>
@@ -133,8 +173,9 @@
<string name="dialog_message_no_image_support">지인 분의 Briar가 이미지 첨부를 지원하지 않습니다. 이 분이 업그레이드하면 다른 상징을 볼 수 있습니다.</string>
<string name="dialog_title_image_support">이제 이 분에게 이미지를 보낼 수 있습니다</string>
<string name="dialog_message_image_support">이 상징을 눌러 이미지를 첨부하세요.</string>
<string name="messaging_too_many_attachments_toast">첫 %d개의 이미지만 보내질 것입니다</string>
<!--Adding Contacts-->
<string name="add_contact_title">주위의 지인 추가하기</string>
<string name="add_contact_title">근처의 연락처 추가하기</string>
<string name="face_to_face">연락처를 추가하려는 사람과 먼저 만나야 합니다.\n\n나중에 누군가 당신인 척 하거나 메시지를 훔쳐보는 것을 방지할 수 있습니다.</string>
<string name="continue_button">계속하기</string>
<string name="try_again_button">다시 시도하기</string>
@@ -149,12 +190,11 @@
<string name="connecting_to_device">\u2026 기기에 연결하고 있습니다</string>
<string name="authenticating_with_device">\u2026 기기와 인증하고 있습니다</string>
<string name="connection_error_title">연락처에 연결하지 못했습니다</string>
<string name="connection_error_explanation">둘 다 같은 Wi-Fi 네트워크에 연결돼 있는지 확인해 보세요.</string>
<string name="connection_error_feedback">문제가 계속된다면, 부디 <a href="feedback">피드백을 남겨서</a> 앱이 좋아지게 도와주세요.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">멀리서 지인 추가하기</string>
<string name="add_contact_nearby_title">주위의 지인 추가하기</string>
<string name="add_contact_remotely_title">멀리서 지인 추가하기</string>
<string name="add_contact_remotely_title_case">원거리에서 연락처 추가하기</string>
<string name="add_contact_nearby_title">근처의 연락처 추가하기</string>
<string name="add_contact_remotely_title">원거리에서 연락처 추가하기</string>
<string name="contact_link_intro">지인 분에게서 받은 링크를 여기에 입력하세요</string>
<string name="contact_link_hint">지인 분의 링크</string>
<string name="paste_button">붙여 넣기</string>
@@ -194,8 +234,9 @@
<string name="offline_state">인터넷에 연결되지 않음</string>
<string name="duplicate_link_dialog_title">중복되는 링크입니다</string>
<string name="duplicate_link_dialog_text_1">%s: 이미 이 링크를 통한 연락 요청이 있습니다.</string>
<string name="duplicate_link_dialog_text_1_contact">%s: 이 링크의 연락처가 이미 있습니다.</string>
<!--This is a question asking whether two nicknames refer to the same person-->
<string name="duplicate_link_dialog_text_2">%s과(와) %s이(가) 같은 사람인가요?</string>
<string name="duplicate_link_dialog_text_2">%s 님과 %s 님이 같은 사람인가요?</string>
<!--This is a button for answering that two nicknames do indeed refer to the same person. This
string will be used in a dialog button, so if the translation of this string is longer than 20
characters, please use "Yes" instead, and use "No" for the "Different Person" button-->
@@ -204,7 +245,7 @@
will be used in a dialog button, so if the translation of this string longer than 20 characters,
please use "No" instead, and use "Yes" for the "Same Person" button-->
<string name="different_person_button">다른 사람</string>
<string name="duplicate_link_dialog_text_3">%s과(와) %s이(가) 같은 링크를 보냈습니다.\n\n둘 중 하나가 당신의 지인이 누군지 알아내려고 하는 것일 수도 있습니다.\n\n둘 중 누구에게라도 다른 사람에게서 같은 링크를 받았다고 알리지 마십시오.</string>
<string name="duplicate_link_dialog_text_3">%s 님과 %s 님이 동일한 링크를 보냈습니다.\n\n누군가 당신의 연락처를 찾으려고 하는 것일 수도 있습니다.\n\n둘 중 누구에게라도 다른 사람에게서 동일한 링크를 받았다고 알리지 마십시오.</string>
<string name="pending_contact_updated_toast">남은 연락 요청이 있는지 확인했습니다</string>
<!--Introductions-->
<string name="introduction_onboarding_title">지인 소개하기</string>
@@ -218,19 +259,19 @@
<string name="introduction_sent">소개시켰습니다.</string>
<string name="introduction_error">소개시키는 과정에서 문제가 있었습니다.</string>
<string name="introduction_request_sent">%2$s에게 %1$s을(를) 소개하고 싶다고 전했습니다.</string>
<string name="introduction_request_received">%1$s이(가) %2$s에게 소개하고 싶다고 합니다. %2$s을(를) 연락처 목록에 추가하고 싶으십니까?</string>
<string name="introduction_request_exists_received">%1$s이(가) %2$s에게 소개하고 싶다고 물었지만, %2$s은(는) 이미 연락처 목록에 있습니다. %1$s이(가) 아직 이 부분을 모르고 있을 수 있으니, 아직 응할 수 있습니다:</string>
<string name="introduction_request_answered_received">%1$s이(가) %2$s에게 소개시키고 싶다고 물었습니다.</string>
<string name="introduction_request_received">%1$s이 %2$s에게 소개하고 싶다고 합니다. %2$s을 연락처 목록에 추가하고 싶으십니까?</string>
<string name="introduction_request_exists_received">%1$s 님이 당신을 %2$s에게 소개하고 싶다고 지만, %2$s은 이미 연락처 목록에 있습니다. %1$s 님이 아직 모르고 있을 수 있으니, 아직 응할 수 있습니다:</string>
<string name="introduction_request_answered_received">%1$s 님이 당신을 %2$s에게 소개시키고 싶다고 니다.</string>
<string name="introduction_response_accepted_sent">%1$s에게 소개되고 싶다고 했습니다.</string>
<string name="introduction_response_accepted_sent_info">%1$s이(가) 당신의 연락처를 받기 전에, 그 쪽에서도 소개를 승락해야 합니다. 여기서 시간이 좀 걸릴 수 있습니다.</string>
<string name="introduction_response_accepted_sent_info">%1$s 님이 소개를 승락해야 연락처에 추가될 수 있습니다. 여기서 시간이 좀 걸릴 수 있습니다.</string>
<string name="introduction_response_declined_sent">%1$s에게 소개되고 싶지 않다고 했습니다.</string>
<string name="introduction_response_accepted_received">%1$s이(가) %2$s에게 소개해도 괜찮다고 했습니다.</string>
<string name="introduction_response_declined_received">%1$s이(가) %2$s에게 소개되고 싶지 않다고 했습니다.</string>
<string name="introduction_response_declined_received_by_introducee">%1$s이(가) %2$s이(가) 소개되고 싶지 않다고 합니다.</string>
<string name="introduction_response_accepted_received">%1$s이 %2$s 님과의 소개를 승락했습니다.</string>
<string name="introduction_response_declined_received">%1$s이 %2$s 님과의 소개를 거절했습니다.</string>
<string name="introduction_response_declined_received_by_introducee">%1$s 님은 %2$s 님이 소개를 거절했다고 합니다.</string>
<!--Private Groups-->
<string name="groups_list_empty">모임이 없습니다.</string>
<string name="groups_list_empty_action">+ 상징을 눌러 모임을 만들거나, 연락하는 분에게 모임을 공유해 달라고 물어보세요</string>
<string name="groups_created_by">%s이(가) 만듦</string>
<string name="groups_list_empty_action">+ 상징을 눌러 모임을 만들거나, 연락하는 분에게 모임을 공유해 달라고 여쭤보세요</string>
<string name="groups_created_by">%s이 만듦</string>
<plurals name="messages">
<item quantity="other">메시지 %d개</item>
</plurals>
@@ -245,9 +286,9 @@
<string name="groups_member_list">구성원 목록</string>
<string name="groups_invite_members">구성원 초대하기</string>
<string name="groups_member_created_you">모임을 만들었습니다</string>
<string name="groups_member_created">%s이(가) 모임을 만들었습니다</string>
<string name="groups_member_created">%s이 모임을 만들었습니다</string>
<string name="groups_member_joined_you">모임에 참가했습니다</string>
<string name="groups_member_joined">%s이(가) 모임에 참가했습니다</string>
<string name="groups_member_joined">%s이 모임에 참가했습니다</string>
<string name="groups_leave">모임 나가기</string>
<string name="groups_leave_dialog_title">모임 떠나기 확인</string>
<string name="groups_leave_dialog_message">정말로 이 모임을 나가고 싶으신가요?</string>
@@ -260,7 +301,7 @@
<!--Private Group Invitations-->
<string name="groups_invitations_title">모임 초대장</string>
<string name="groups_invitations_invitation_sent">%1$s을(를) \"%2$s\" 모임에 참가하도록 초대했습니다.</string>
<string name="groups_invitations_invitation_received">%1$s이(가) \"%2$s\" 모임에 참가하도록 초대했습니다.</string>
<string name="groups_invitations_invitation_received">%1$s이 \"%2$s\" 모임에 참가하도록 초대했습니다.</string>
<string name="groups_invitations_joined">모임에 참가했습니다</string>
<string name="groups_invitations_declined">모임 초대장 거절함</string>
<plurals name="groups_invitations_open">
@@ -268,19 +309,19 @@
</plurals>
<string name="groups_invitations_response_accepted_sent">%s(으)로부터 받은 초대장을 승락했습니다.</string>
<string name="groups_invitations_response_declined_sent">%s(으)로부터의 모임 초대장을 거절했습니다.</string>
<string name="groups_invitations_response_accepted_received">%s이(가) 모임 초대장을 승락했습니다.</string>
<string name="groups_invitations_response_declined_received">%s이(가) 모임 초대장을 거절했습니다.</string>
<string name="groups_invitations_response_accepted_received">%s이 모임 초대장을 승락했습니다.</string>
<string name="groups_invitations_response_declined_received">%s이 모임 초대장을 거절했습니다.</string>
<string name="sharing_status_groups">모임을 만든 분만 새로운 구성원을 초대할 수 있습니다. 다음은 모임의 모든 현재 구성원입니다.</string>
<!--Private Groups Revealing Contacts-->
<string name="groups_reveal_contacts">연락처 보이</string>
<string name="groups_reveal_contacts">연락처 공개하</string>
<string name="groups_reveal_dialog_message">이 모임의 지금과 앞으로 들어올 구성원에게 연락처를 공개할지를 정할 수 있습니다.\n\n연락처를 공개하면, 모임을 만든 사람이 오프라인이어도 공개된 연락처와 연결할 수 있기 때문에 모임에 더 빠르고 안정적으로 연결할 수 있습니다.</string>
<string name="groups_reveal_visible">연락처 관계가 모임에서 보입니다</string>
<string name="groups_reveal_visible_revealed_by_us">연락처 관계가 모임에서 보입니다(본인이 공개)</string>
<string name="groups_reveal_visible_revealed_by_contact">연락처 관계가 모임에서 보입니다(%s이(가) 공개)</string>
<string name="groups_reveal_invisible">연락처 관계가 모임에서 보이지 않습니다</string>
<string name="groups_reveal_visible_revealed_by_us">(당신이) 모임에게 지인 관계 공개합니다</string>
<string name="groups_reveal_visible_revealed_by_contact">(%s님이) 모임에게 지인 관계를 공개합니다</string>
<string name="groups_reveal_invisible">모임에게 지인 관계를 공개하지 않습니다</string>
<!--Forums-->
<string name="no_forums">보여드릴 포럼이 없습니다</string>
<string name="no_forums_action">+ 상징을 눌러 포럼을 만들거나, 연락하는 분에게 포럼을 공유해 달라고 물어보세요 </string>
<string name="no_forums_action">+ 상징을 눌러 포럼을 만들거나, 연락하는 분에게 포럼을 공유해 달라고 여쭤보세요</string>
<string name="create_forum_title">포럼 만들기</string>
<string name="choose_forum_hint">만드실 포럼 이름을 정해주세요</string>
<string name="create_forum_button">포럼 만들기</string>
@@ -295,7 +336,7 @@
<string name="btn_reply">답장</string>
<string name="forum_leave">포럼 떠나기</string>
<string name="dialog_title_leave_forum">포럼 떠나기 확인</string>
<string name="dialog_message_leave_forum">정말로 이 포럼을 떠나려고 하세요?\n\n이 포럼과 공유한 연락처에서 업데이트가 되지 않을 수 있습니다.</string>
<string name="dialog_message_leave_forum">정말로 이 포럼을 떠나려고 하세요?\n\n이 포럼과 공유한 지인이 업데이트를 받지 못할 수 있습니다.</string>
<string name="dialog_button_leave">떠나기</string>
<string name="forum_left_toast">포럼을 떠났습니다</string>
<!--Forum Sharing-->
@@ -303,11 +344,11 @@
<string name="contacts_selected">선택한 연락처</string>
<string name="activity_share_toolbar_header">연락처 선택하기</string>
<string name="no_contacts_selector">저장된 연락처가 없습니다</string>
<string name="no_contacts_selector_action">연락처를 추가한 후에 돌아오길 바랍니다</string>
<string name="forum_shared_snackbar">선택한 지인과 공유하는 포럼</string>
<string name="no_contacts_selector_action">연락처를 추가한 후에 돌아오세요</string>
<string name="forum_shared_snackbar">선택한 지인과 공유하는 포럼</string>
<string name="forum_share_message">메시지 추가하기(선택 사항)</string>
<string name="forum_share_error">포럼을 공유하는 과정에서 문제가 있었습니다</string>
<string name="forum_invitation_received">%1$s이(가) \"%2$s\" 포럼을 공유했습니다.</string>
<string name="forum_invitation_received">%1$s이 \"%2$s\" 포럼을 공유했습니다.</string>
<string name="forum_invitation_sent">\"%1$s\" 포럼을 %2$s과(와) 공유했습니다.</string>
<string name="forum_invitations_title">포럼 초대장</string>
<string name="forum_invitation_exists">이미 이 포럼에 초대를 승락했습니다.\n\n초대를 더 많이 승락할수록 더 빠르고 안정적으로 포럼에 연결할 수 있습니다.</string>
@@ -317,10 +358,10 @@
<string name="forum_invitation_already_sharing">이미 공유하고 있습니다</string>
<string name="forum_invitation_response_accepted_sent">%s(으)로부터의 포럼 초대를 승락했습니다.</string>
<string name="forum_invitation_response_declined_sent">%s(으)로부터의 포럼 초대를 거절했습니다.</string>
<string name="forum_invitation_response_accepted_received">%s이(가) 포럼 초대장을 승락했습니다.</string>
<string name="forum_invitation_response_declined_received">%s이(가) 포럼 초대장을 거절했습니다.</string>
<string name="forum_invitation_response_accepted_received">%s이 포럼 초대장을 승락했습니다.</string>
<string name="forum_invitation_response_declined_received">%s이 포럼 초대장을 거절했습니다.</string>
<string name="sharing_status">공유 상태</string>
<string name="sharing_status_forum">포럼은 참가한 누구나 지인과 공유할 수 있습니다. 다음 연락처와 포럼을 공유하고 있습니다. 이외 다른 구성원이 더 있을 수 있습니다.</string>
<string name="sharing_status_forum">포럼은 참가한 누구나 자신의 지인과 공유할 수 있습니다. 현재 다음 연락처와 포럼을 공유하고 있습니다. 이외 다른 구성원이 더 있을 수 있습니다.</string>
<string name="shared_with">와(과) 공유하고 있습니다.(%1$d %2$d명 온라인)</string>
<plurals name="forums_shared">
<item quantity="other">지인과 공유한 %d개의 포럼</item>
@@ -336,9 +377,9 @@
<string name="blogs_blog_post_received">새로운 블로그 게시물을 받았습니다</string>
<string name="blogs_blog_post_scroll_to">스크롤</string>
<string name="blogs_feed_empty_state">게시물이 없습니다</string>
<string name="blogs_feed_empty_state_action">연락처와 구독한 블로그의 게시물이 여기에 나타납니다.\n\n게시물을 려면 펜 상징을 누르세요</string>
<string name="blogs_feed_empty_state_action">지인이 올린 글과 구독한 블로그의 게시물이 여기에 올라옵니다.\n\n게시물을 작성하려면 펜 상징을 누르세요</string>
<string name="blogs_remove_blog">블로그 제거하기</string>
<string name="blogs_remove_blog_dialog_message">정말로 이 블로그를 제거하시겠어요?\n\n기기에서 게시물은 제거되지만 다른 사람의 기기에서는 제거되지 않습니다.\n\n이 블로그를 공유하던 연락처에서 업데이트가 되지 않을 수 있습니다. </string>
<string name="blogs_remove_blog_dialog_message">정말로 이 블로그를 제거하시겠어요?\n\n게시물이 이 기기에서는 제거되지만 다른 사람의 기기에서는 제거되지 않습니다.\n\n이 블로그를 공유하던 지인이 업데이트를 받지 못하게 될 수 있습니다. </string>
<string name="blogs_remove_blog_ok">제거하기</string>
<string name="blogs_blog_removed">블로그를 제거했습니다</string>
<string name="blogs_reblog_comment_hint">글 추가하기(선택 사항)</string>
@@ -347,17 +388,17 @@
<string name="blogs_sharing_share">블로그 공유하기</string>
<string name="blogs_sharing_error">블로그를 공유하는 과정에서 문제가 있었습니다.</string>
<string name="blogs_sharing_button">블로그 공유하기</string>
<string name="blogs_sharing_snackbar">선택한 지인과 블로그 공유함</string>
<string name="blogs_sharing_snackbar">선택한 지인과 블로그 공유함</string>
<string name="blogs_sharing_response_accepted_sent">%s(으)로부터 받은 블로그 초대장을 승락했습니다.</string>
<string name="blogs_sharing_response_declined_sent">%s(으)로부터의 블로그 초대장을 거절했습니다.</string>
<string name="blogs_sharing_response_accepted_received">%s이(가) 블로그 초대를 승락했습니다.</string>
<string name="blogs_sharing_response_declined_received">%s이(가) 블로그 초대장을 거절했습니다.</string>
<string name="blogs_sharing_invitation_received">%1$s이(가) \"%2$s\" 블로그를 공유했습니다.</string>
<string name="blogs_sharing_response_accepted_received">%s이 블로그 초대를 승락했습니다.</string>
<string name="blogs_sharing_response_declined_received">%s이 블로그 초대장을 거절했습니다.</string>
<string name="blogs_sharing_invitation_received">%1$s이 \"%2$s\" 블로그를 공유했습니다.</string>
<string name="blogs_sharing_invitation_sent">%2$s와(과) \"%1$s\" 블로그를 공유했습니다.</string>
<string name="blogs_sharing_invitations_title">블로그 초대장</string>
<string name="blogs_sharing_joined_toast">블로그에 구독함</string>
<string name="blogs_sharing_declined_toast">모임 초대장 거절함</string>
<string name="sharing_status_blog">블로그는 구독한 누구나 지인과 공유할 수 있습니다. 다음 지인 분과 이 블로그를 공유하고 있습니다. 이외 다른 구독자가 더 있을 수 있습니다.</string>
<string name="sharing_status_blog">블로그는 구독한 누구나 자신의 지인과 공유할 수 있습니다. 현재 다음 연락처와 이 블로그를 공유하고 있습니다. 이외 다른 구독자가 더 있을 수 있습니다.</string>
<!--RSS Feeds-->
<string name="blogs_rss_feeds_import">RSS 피드 불러오기</string>
<string name="blogs_rss_feeds_import_button">가져오기</string>
@@ -368,13 +409,13 @@
<string name="blogs_rss_feeds_manage_author">작성자:</string>
<string name="blogs_rss_feeds_manage_updated">최종 업데이트:</string>
<string name="blogs_rss_remove_feed">피드 제거하기</string>
<string name="blogs_rss_remove_feed_dialog_message">정말로 이 피드를 제거하시겠어요?\n\n기기에서 게시물은 제거되지만 다른 사람의 기기에서는 제거되지 않습니다.\n\n이 피드를 공유하던 연락처에서 업데이트가 되지 않을 수 있습니다. </string>
<string name="blogs_rss_remove_feed_dialog_message">정말로 이 피드를 제거하시겠어요?\n\n기기에서 게시물은 제거되지만 다른 사람의 기기에서는 제거되지 않습니다.\n\n이 피드를 공유하던 지인이 업데이트를 받지 못하게 될 수 있습니다. </string>
<string name="blogs_rss_remove_feed_ok">제거하기</string>
<string name="blogs_rss_feeds_manage_delete_error">피드를 삭제할 수 없었습니다!</string>
<string name="blogs_rss_feeds_manage_empty_state">보여드릴 RSS 피드가 없습니다\n\n+ 상징을 눌러 피드를 불러오세요</string>
<string name="blogs_rss_feeds_manage_error">피드를 불러오는 과정에서 문제가 있었습니다. 나중에 다시 시도해 주세요.</string>
<!--Settings Display-->
<string name="pref_language_title">언어 &amp; 지역</string>
<string name="pref_language_title">Language &amp; region</string>
<string name="pref_language_changed">Briar를 다시 시작한 후에 설정이 적용됩니다. 부디 로그아웃하고 Briar를 다시 시작해 주세요.</string>
<string name="pref_language_default">기본 설정</string>
<string name="display_settings_title">화면</string>
@@ -384,10 +425,20 @@
<string name="pref_theme_auto">자동(시간에 따라)</string>
<string name="pref_theme_system">기본 설정</string>
<!--Settings Connections-->
<string name="network_settings_title">연결</string>
<string name="bluetooth_setting">블루투스로 지인과 연결하기</string>
<string name="wifi_setting">같은 와이파이 네트워크에 연결된 지인과 연결하기</string>
<string name="tor_enable_title">인터넷을 통해 지인과 연결하기</string>
<string name="tor_enable_summary">프라이버시를 위해 모든 연결은 Tor 네트워크를 거칩니다</string>
<string name="tor_network_setting">Tor 네트워크 연결 방식</string>
<string name="tor_network_setting_automatic">장소에 따라 자동으로</string>
<string name="tor_network_setting_without_bridges">브리지 없이 Tor 네트워크 사용하기</string>
<string name="tor_network_setting_with_bridges">브지를 통해 Tor 네트워크 사용하기</string>
<string name="tor_network_setting_never">인터넷에 연결하지 않기</string>
<!--How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)"-->
<string name="tor_network_setting_summary">자동: %1$s(%2$s에서)</string>
<string name="tor_mobile_data_title">모바일 데이터 사용하기</string>
<string name="tor_only_when_charging_title">충전할 때만 인터넷에 연결하기</string>
<string name="tor_only_when_charging_summary">충전 중이지 않을 때에는 인터넷 연결을 비활성화</string>
<!--Settings Security and Panic-->
<string name="security_settings_title"> 보안</string>
@@ -422,12 +473,12 @@
<string name="panic_app_setting_summary">설정된 앱이 없습니다</string>
<string name="panic_app_setting_none">없음</string>
<string name="dialog_title_connect_panic_app">패닉 앱 확인</string>
<string name="dialog_message_connect_panic_app">%1$s이(가) 파기 권한을 지닌 패닉 버튼 동작을 작동시킬 수 있게 허용하시겠어요?</string>
<string name="dialog_message_connect_panic_app">%1$s이 파기 권한을 지닌 패닉 버튼 동작을 작동시킬 수 있게 허용하시겠어요?</string>
<string name="panic_setting_destructive_action">파기하기</string>
<string name="panic_setting_signout_title">로그아웃</string>
<string name="panic_setting_signout_summary">패닉 버튼이 눌리면 Briar에서 로그아웃하기</string>
<string name="purge_setting_title">계정 삭제하기</string>
<string name="purge_setting_summary">패닉 버튼이 눌리면 Briar 계정을 삭제하기 (주의: 계정, 연락처와 메시지가 영구적으로 지워집니다)</string>
<string name="purge_setting_summary">패닉 버튼이 눌리면 Briar 계정을 삭제하기. 주의: 계정, 연락처와 메시지가 영구적으로 지워집니다</string>
<!--Settings Notifications-->
<string name="notification_settings_title">알림</string>
<string name="notify_sign_in_title">로그인 알려주기</string>
@@ -498,6 +549,7 @@
<string name="lock_is_locked">Briar가 잠겼습니다</string>
<string name="lock_tap_to_unlock">눌러 잠금해제</string>
<!--Connections Screen-->
<string name="transports_help_text">Briar는 인터넷이나 Wi-Fi, 블루투스를 통해 지인과 연결할 수 있습니다.\n\n인터넷에 연결할 때는 프라이버시를 위해 언제나 Tor 네트워크를 거칩니다.\n\nBriar는 가능한 연락처에 닿을 수 있는 여러 방식을 병용합니다.</string>
<!--Screenshots-->
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_alice">영희</string>

View File

@@ -31,7 +31,7 @@
<string name="sign_in_button">Prisijungti</string>
<string name="forgotten_password">Aš pamiršau savo slaptažodį</string>
<string name="dialog_title_lost_password">Prarastas slaptažodis</string>
<string name="dialog_message_lost_password">Jūsų Briar paskyra yra saugoma šifruotu pavidalu jūsų įrenginyje, o ne debesijoje, taigi, negalime atstatyti jūsų slaptažodžio Ar norėtumėte ištrinti savo paskyrą ir pradėti iš naujo?\n\nDėmesio: Jūsų tapatybės, žinutės ir adresatai bus prarasti visiems laikams.</string>
<string name="dialog_message_lost_password">Jūsų Briar paskyra yra saugoma šifruotu pavidalu jūsų įrenginyje, o ne debesijoje, taigi, negalime atstatyti jūsų slaptažodžio. Ar norėtumėte ištrinti savo paskyrą ir pradėti iš naujo?\n\nDėmesio: Jūsų tapatybės, žinutės ir adresatai bus prarasti visiems laikams.</string>
<string name="startup_failed_notification_title">Nepavyko paleisti Briar</string>
<string name="startup_failed_notification_text">Bakstelėkite išsamesnei informacijai.</string>
<string name="startup_failed_activity_title">Briar paleidimo nesėkmė</string>
@@ -191,7 +191,7 @@
<string name="messaging_too_many_attachments_toast">Bus išsiųsti tik %d pirmi paveikslai</string>
<!--Adding Contacts-->
<string name="add_contact_title">Pridėti šalia esantį adresatą</string>
<string name="face_to_face">Jūs privalote susitikti gyvai su asmeniu, kurį norite pridėti kaip adresatą.\n\nTai neleis bet kam apsimetinėti jumis ar ateityje skaityti jūsų žinutes.</string>
<string name="face_to_face">Jūs privalote susitikti gyvai su asmeniu, kurį norite pridėti kaip adresatą.\n\nTai neleis bet kam apsimetinėti jumis ar ateityje skaityti jūsų žinučių.</string>
<string name="continue_button">Tęsti</string>
<string name="try_again_button">Bandyti dar kartą</string>
<string name="waiting_for_contact_to_scan">Laukiama, kol adresatas nuskenuos ir prisijungs\u2026</string>
@@ -205,7 +205,6 @@
<string name="connecting_to_device">Jungiamasi prie įrenginio\u2026</string>
<string name="authenticating_with_device">Tapatybės nustatymas su įrenginiu\u2026</string>
<string name="connection_error_title">Nepavyko prisijungti prie jūsų adresato</string>
<string name="connection_error_explanation">Įsitikinkite, kad abu esate prisijungę prie to paties belaidžio (Wi-Fi) tinklo.</string>
<string name="connection_error_feedback">Jei ši problema išlieka, <a href="feedback">atsiųskite mums atsiliepimą</a>, kad padėtumėte mums patobulinti programėlę.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Pridėti adresatą per atstumą</string>
@@ -570,6 +569,7 @@
<string name="permission_camera_location_title">Kamera ir įrenginio vietovė</string>
<string name="permission_camera_location_request_body">Tam, kad galėtų nuskenuoti QR kodą, Briar reikia gauti prieigą prie jūsų kameros.\n\nTam, kad galėtų atrasti Bluetooth įrenginius, Briar reikia gauti prieigą prie jūsų įrenginio vietovės.\n\nBriar nesaugo jūsų įrenginio vietovės ir su niekuo jos nebendrina.</string>
<string name="permission_camera_denied_body">Jūs uždraudėte prieigą prie kameros, tačiau norint pridėti adresatus, reikia naudoti kamerą.\n\nApsvarstykite galimybę sutekti prieigą prie kameros.</string>
<string name="permission_location_denied_body">Jūs uždraudėte prieigą prie įrenginio vietovės, tačiau norint atrasti Bluetooth įrenginius, Briar reikia šio leidimo.\n\nApsvarstykite galimybę sutekti prieigą prie įrenginio vietovės.</string>
<string name="qr_code">QR kodas</string>
<string name="show_qr_code_fullscreen">Rodyti QR kodą visame ekrane</string>
<!--App Locking-->

View File

@@ -61,12 +61,36 @@
<string name="lock_button">Заклучи ја апликацијата</string>
<string name="settings_button">Поставки</string>
<string name="sign_out_button">Одјави се</string>
<string name="transports_onboarding_text">Допрете овде за да контролирате како Briar се поврзува со вашите контакти.</string>
<!--Transports: Tor-->
<string name="transport_tor">Интернет</string>
<string name="tor_device_status_online_wifi">Вашиот телефон има интернет пристап преку Wi-Fi</string>
<string name="tor_device_status_online_mobile">Вашиот телефон има интернет пристап преку мобилни податоци</string>
<string name="tor_device_status_offline">Вашиот телефон нема интернет пристап</string>
<string name="tor_plugin_status_enabling">Briar се поврзува на Интернет</string>
<string name="tor_plugin_status_active">Briar е поврзан на Интернет</string>
<string name="tor_plugin_status_inactive">Briar не може да се поврзе на Интернет</string>
<string name="tor_plugin_status_disabled">Briar е конфигуриран да не користи Интернет</string>
<string name="tor_plugin_status_disabled_mobile_data">Briar е конфигуриран да не користи мобилни податоци</string>
<string name="tor_plugin_status_disabled_battery">Briar е конфигуриран да не користи Интернет додека е работи на батерија</string>
<string name="tor_plugin_status_disabled_country_blocked">Briar е конфигуриран да не користи Интернет во оваа држава</string>
<!--Transports: Wi-Fi-->
<string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">Иста Wi-Fi мрежа </string>
<string name="lan_device_status_on">Вашиот телефон е поврзан на Wi-Fi</string>
<string name="lan_device_status_off">Вашиот телефон не е поврзан на Wi-Fi</string>
<string name="lan_plugin_status_enabling">Briar се поврзува на Wi-Fi мрежа</string>
<string name="lan_plugin_status_active">Briar е поврзан на Wi-Fi мрежата</string>
<string name="lan_plugin_status_inactive">Briar сне може да се поврзе на Wi-Fi мрежата</string>
<string name="lan_plugin_status_disabled">Briar е конфигуриран да не ја користи Wi-Fi мрежата</string>
<!--Transports: Bluetooth-->
<string name="transport_bt">Bluetooth</string>
<string name="bt_device_status_on">Bluetooth-от на вашиот телефон е вклучен</string>
<string name="bt_device_status_off">Bluetooth-от на вашиот телефон е исклучен</string>
<string name="bt_plugin_status_enabling">Briar се поврзува со Bluetooth</string>
<string name="bt_plugin_status_active">Briar е поврзан со Bluetooth</string>
<string name="bt_plugin_status_inactive">Briar не може да се поврзе со Bluetooth</string>
<string name="bt_plugin_status_disabled">Briar е конфигуриран да не користи Bluetooth</string>
<!--Notifications-->
<string name="reminder_notification_title">Одјави се од Briar</string>
<string name="reminder_notification_text">Допрете за да се најавите.</string>
@@ -113,6 +137,7 @@
<string name="help">Помош</string>
<string name="sorry">Жал ни е</string>
<string name="error_start_activity">Недостапно на вашиот систем</string>
<string name="status_heading">Статус:</string>
<!--Contacts and Private Conversations-->
<string name="no_contacts">Нема контакти за прикажување</string>
<string name="no_contacts_action">Допрете ја + иконата за да додадете контакт</string>
@@ -170,7 +195,6 @@
<string name="connecting_to_device">Поврзување со уред\u2026</string>
<string name="authenticating_with_device">Автентикација со уред\u2026</string>
<string name="connection_error_title">Не може да се поврзе со твојот контакт</string>
<string name="connection_error_explanation">Ве молиме проверете дека и двајцата сте поврзани на истата Wi-Fi мрежа.</string>
<string name="connection_error_feedback">Ако овој проблем останува, ве молиме <a href="feedback">испратете повратна информација</a> за да ни помогнете да ја подобриме апликацијата.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Додај контакт НА РАСТОЈАНИЕ</string>
@@ -411,10 +435,20 @@
<string name="pref_theme_auto">Автоматски (Дневно)</string>
<string name="pref_theme_system">Систем стандардно поставен</string>
<!--Settings Connections-->
<string name="network_settings_title">Поврзувања</string>
<string name="bluetooth_setting">Поврзете се контактите преку Bluetooth</string>
<string name="wifi_setting">Поврзете се со контактите на истата Wi-Fi мрежа</string>
<string name="tor_enable_title">Поврзете се контактите преку Интернет</string>
<string name="tor_enable_summary">Сите поврзувања одат преку Tor мрежата поради приватност</string>
<string name="tor_network_setting">Метод на поврзување на Tor мрежата</string>
<string name="tor_network_setting_automatic">Автоматски базирано на локација</string>
<string name="tor_network_setting_without_bridges">Користете Tor мрежа без мостови</string>
<string name="tor_network_setting_with_bridges">Користете Tor мрежа со мостови</string>
<string name="tor_network_setting_never">Не се поврзувај на Интернет</string>
<!--How and when Briar will connect to Tor: E.g. "Don't connect to the Internet (in China)" or "Use Tor network with bridges (in Belarus)"-->
<string name="tor_network_setting_summary">Автоматски: %1$s (во %2$s)</string>
<string name="tor_mobile_data_title">Користи мобилни податоци</string>
<string name="tor_only_when_charging_title">Поврзи на Интернет само за време на полнење</string>
<string name="tor_only_when_charging_summary">Оневозможи го Интернет поврзувањето кога уредот не е приклучен на полнач</string>
<!--Settings Security and Panic-->
<string name="security_settings_title">Безбедност</string>
@@ -514,7 +548,8 @@
<string name="permission_location_request_body">За да открие Bluetooth уреди, на Briar му е потребна дозвола за пристап до вашата локација.\n\nBriar не ја зачувува вашата локација или не ја споделува со никого.</string>
<string name="permission_camera_location_title">Камера и локација</string>
<string name="permission_camera_location_request_body">За да го скенира QR кодот, на Briar му е потребен пристап до камерата.\n\nЗа да открие Bluetooth уреди, на Briar му е потребна дозвола за вашата локација.\n\nBriar не ја зачувува вашата локација или не ја споделува со никого.</string>
<string name="permission_camera_denied_body">Го одбивте пристапот до камерата, но за додавање на контакти потребно е користење на камерата.\n\nВе молиме размислете за давање дозвола.</string>
<string name="permission_camera_denied_body">Го одбивте пристапот до камерата, но за додавање на контакти потребно е користење на камерата.\n\nВе молиме размислете за давање пристап.</string>
<string name="permission_location_denied_body">Го одбивте пристапот до вашата локација, но на Briar му е потребна оваа дозвола за да ги открие Bluetooth уредите.\n\nВе молиме размислете за давање пристап.</string>
<string name="qr_code">QR код</string>
<string name="show_qr_code_fullscreen">Покажи го QR кодот на цел екран</string>
<!--App Locking-->
@@ -525,6 +560,7 @@
<string name="lock_is_locked">Briar е заклучен</string>
<string name="lock_tap_to_unlock">Допрете за отклучување</string>
<!--Connections Screen-->
<string name="transports_help_text">Briar може да се поврзе со вашите контакти преку Интернет, Wi-Fi или Bluetooth.\n\nСите Интернет поврзувања одат преку Tor Мрежата поради приватност.\n\nАко контактот може да биде достапен преку повеќе начини, Briar ќе ги користи паралелно. </string>
<!--Screenshots-->
<!--This is a name to be used in screenshots. Feel free to change it to a local name.-->
<string name="screenshot_alice">Жарко</string>

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Aan het verbinden met apparaat\u2026</string>
<string name="authenticating_with_device">Aan het authenticeren met apparaat\u2026</string>
<string name="connection_error_title">Kon geen verbinding maken met je contact</string>
<string name="connection_error_explanation">Controleer alsjeblieft dat jullie beiden met hetzelfde wifinetwerk zijn verbonden.</string>
<string name="connection_error_feedback">Als dit probleem aanhoudt, <a href="feedback">stuur feedback</a> alsjeblieft om ons te helpen de app te verbeteren.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Voeg een contact ver weg toe</string>

View File

@@ -169,7 +169,6 @@ Volètz suprimir vòstre compte e ne crear un nòu?\n
<string name="connecting_to_device">Connexion a laparelh\u2026</string>
<string name="authenticating_with_device">Autentificacion amb laparelh\u2026</string>
<string name="connection_error_title">Connexion impossibla al contacte</string>
<string name="connection_error_explanation">Verificatz que sètz los dos connectats al meteis ret wifi.</string>
<string name="connection_error_feedback">Saqueste problèma dura, mercés <a href="feedback"> denviar un comentari</a> per nos ajudar a melhorar laplicacion.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Ajustar un contacte a distància</string>

View File

@@ -165,7 +165,6 @@
<string name="connecting_to_device">Łączenie z urządzeniem\u2026</string>
<string name="authenticating_with_device">Autoryzowanie z urządzeniem\u2026</string>
<string name="connection_error_title">Nie udało się połączyć z kontaktem</string>
<string name="connection_error_explanation">Sprawdź czy obaj jesteście połączeni z tą samą siecią Wi-Fi.</string>
<string name="connection_error_feedback">Jeśli problem będzie występować dalej, proszę <a href="feedback">wysłać zgłoszenie</a> aby pomóc nam ulepszyć aplikację.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Dodaj Kontakt na odległość</string>

View File

@@ -172,7 +172,6 @@
<string name="connecting_to_device">Conectando a device\u2026</string>
<string name="authenticating_with_device">Autenticando com o dispositivo\u2026</string>
<string name="connection_error_title">Não foi possível conectar-se ao seu contato</string>
<string name="connection_error_explanation">Por favor, certifique se ambos estão conectados na mesma rede Wi-Fi.</string>
<string name="connection_error_feedback">Se o problema persistir, por favor <a href="feedback">envie um feedback</a> para nos ajudar a melhorar o app.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Adicionar contato à distância</string>

View File

@@ -200,7 +200,6 @@
<string name="connecting_to_device">Conectare la dispozitiv\u2026</string>
<string name="authenticating_with_device">Autentificare cu dispozitivul\u2026</string>
<string name="connection_error_title">Nu s-a putut face conexiunea la contactul dumneavoastră</string>
<string name="connection_error_explanation">Verificați să fiți conectați la aceeași rețea Wi-Fi.</string>
<string name="connection_error_feedback">Dacă problema persistă, vă rugăm să <a href="feedback">trimiteți feedback</a> pentru a ne ajuta să îmbunătățim aplicația.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Adaugă un contact la distanță</string>
@@ -560,6 +559,7 @@
<string name="permission_camera_location_title">Cameră foto și locație</string>
<string name="permission_camera_location_request_body">Pentru a scana codul QR, Briar are nevoie să acceseze camera foto.\n\nPentru a putea descoperi dispozitive Bluetooth, Briar are nevoie de permisiunea de a vă accesa locația.\n\nBriar nu vă stochează locația și nici nu o partajează cu nimeni. </string>
<string name="permission_camera_denied_body">Ați refuzat accesul la camera foto, dar pentru a adăuga contacte este necesară folosirea camerei foto.\n\nVă rugăm să luați în considerare acordarea accesului.</string>
<string name="permission_location_denied_body">Ați refuzat accesul la locație, dar Briar are nevoie de această permisiune pentru a descoperi dispozitive Bluetooth.\n\nVă rugăm să luați în considerare acordarea accesului.</string>
<string name="qr_code">Cod QR</string>
<string name="show_qr_code_fullscreen">Arată codul QR pe tot ecranul</string>
<!--App Locking-->

View File

@@ -207,7 +207,6 @@
<string name="connecting_to_device">Подключение к устройству\u2026</string>
<string name="authenticating_with_device">Аутентификация с устройством\u2026</string>
<string name="connection_error_title">Не удалось подключиться к контакту</string>
<string name="connection_error_explanation">Убедитесь, что вы оба подключены к той же сети Wi-Fi.</string>
<string name="connection_error_feedback">Если эта проблема сохраняется, пожалуйста <a href="feedback">отправьте отзыв</a>, чтобы помочь нам улучшить приложение.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Добавление контакта на расстоянии</string>

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Po lidhet me pajisjen\u2026</string>
<string name="authenticating_with_device">Po bëhet mirëfilltësimi me pajisjen\u2026</string>
<string name="connection_error_title">Su lidh dot te kontakti juaj</string>
<string name="connection_error_explanation">Ju lutemi, kontrolloni se jeni të dy të lidhur në të njëjtin rrjet Wi-Fi.</string>
<string name="connection_error_feedback">Nëse problemi vazhdon, ju lutemi, <a href="feedback">na njoftoni</a>, që të mund të përmirësojmë aplikacionin.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Shtoni Kontakt në Largësi</string>
@@ -550,6 +549,7 @@
<string name="permission_camera_location_title">Kamera dhe vend</string>
<string name="permission_camera_location_request_body">Që të skanojë kodin QR, Briar-it i duhet të përdorë kamerën.\n\nQë të pikasë pajisje Bluetooth, Briar-i lyp leje të njohë vendin tuaj.\n\nBriar-i nuk e depoziton vendin tuaj, as e ndan me dikë.</string>
<string name="permission_camera_denied_body">Keni mohuar hyrjen në kamera, por shtimi i kontakteve lyp përdorimin e kamerës.\n\nJu lutemi, shihni mundësinë e akordimit të hyrjes.</string>
<string name="permission_location_denied_body">Keni mohuar hyrje te vendndodhja juaj, por Briar-i ka nevojë për këtë leje, që të mund të zbulojë pajisje Bluetooth.\n\nJu lutemi, shihni mundësinë e akordimit të hyrjes.</string>
<string name="qr_code">Kod QR</string>
<string name="show_qr_code_fullscreen">Shfaqe kodin QR sa tërë ekrani</string>
<!--App Locking-->

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Ansluter till enhet\u2026</string>
<string name="authenticating_with_device">Autentiserar med enhet\u2026</string>
<string name="connection_error_title">Kunde ej ansluta till din kontakt</string>
<string name="connection_error_explanation">Kontrollera att ni båda är anslutna på samma Wi-Fi-nätverk.</string>
<string name="connection_error_feedback">Om det här problemet kvarstår, vänligen lämna <a href="feedback">synpunkter</a> så vi kan förbättra appen.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Lägg till en kontakt på avstånd</string>

View File

@@ -187,7 +187,6 @@ Umepoteza nenosiri.</string>
<string name="connecting_to_device">Unganisha kwenye kifaa\u2026</string>
<string name="authenticating_with_device">Uhalisishaji wa kifaa\u2026</string>
<string name="connection_error_title">Imeshindwa unganishwa kwenye mawasiliano </string>
<string name="connection_error_explanation">Tafathali Angalia kama wote Mmeunganishwa kwenye Mtandao wa WI-FI mmoja .</string>
<string name="connection_error_feedback">Kama hilo tatizo linaendela , Tafathali <a href="feedback"> tutumie maoni</a>ilituboreshe Programu .</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Ongeza mawasiliano kwambali </string>

View File

@@ -195,7 +195,6 @@
<string name="connecting_to_device">Aygıta bağlanıyor\u2026</string>
<string name="authenticating_with_device">Aygıtla kimlik doğrulama\u2026</string>
<string name="connection_error_title">Kişinizle bağlantı kurulamadı</string>
<string name="connection_error_explanation">Lütfen her ikinizin de aynı Wi-Fi ağına bağlı olup olmadığınızı kontrol edin.</string>
<string name="connection_error_feedback">Sorun devam ederse, uygulamayı geliştirmemize yardımcı olmak için <a href="feedback">geri bildirim gönderin</a>.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Uzaktaki Kişiyi Ekle</string>

View File

@@ -165,7 +165,6 @@
<string name="connecting_to_device">З\'єднання з пристроєм\u2026</string>
<string name="authenticating_with_device">Автентифікація з пристроєм\u2026</string>
<string name="connection_error_title">Неможливо з\'єднатися з вашим контактом</string>
<string name="connection_error_explanation">Будь ласка, впевніться, що ви обоє під\'єднані до однієї Wi-Fi-мережі.</string>
<string name="connection_error_feedback">Якщо ця проблема збережеться, будь ласка, <a href="feedback">надішліть відгук</a>, щоб допомогти нам вдосконалити цей додаток.</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Додати контакт віддалено</string>

View File

@@ -190,7 +190,6 @@
<string name="connecting_to_device">正在连接至设备\u2026</string>
<string name="authenticating_with_device">正在验证设备\u2026</string>
<string name="connection_error_title">无法连接到您的联系人</string>
<string name="connection_error_explanation">请确保你们连接到了同一个无线局域网中。</string>
<string name="connection_error_feedback">如果该问题仍存在,请 <a href="feedback">发送反馈</a> 帮助我们改善应用。</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">添加远处的联系人</string>
@@ -540,6 +539,7 @@
<string name="permission_camera_location_title">相机和位置</string>
<string name="permission_camera_location_request_body"> Briar 需要相机权限以扫描二维码。\n\nBriar 需要位置信息权限以发现蓝牙设备。\n\nBriar 不会存储您的位置或将它分享给任何人。</string>
<string name="permission_camera_denied_body">您已拒绝相机权限,而添加联系人需要使用相机。\n\n请考虑授予相机权限。</string>
<string name="permission_location_denied_body">您已拒绝访问您的位置但Briar需要此权限才能发现蓝牙设备。\n\n请考虑授予访问权限。</string>
<string name="qr_code">二维码</string>
<string name="show_qr_code_fullscreen">全屏显示二维码</string>
<!--App Locking-->

View File

@@ -149,7 +149,6 @@
<string name="connecting_to_device">正在連接至裝置\u2026</string>
<string name="authenticating_with_device">正在驗證裝置\u2026</string>
<string name="connection_error_title">無法連接到您的聯絡人</string>
<string name="connection_error_explanation">請確保您們連接到了同一個 Wi-Fi中。</string>
<string name="connection_error_feedback">如果該問題仍存在,請 <a href="feedback">發送反饋</a> 幫助我們改善程式。</string>
<!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">添加遠處的聯絡人</string>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFF</color>
</resources>

View File

@@ -317,7 +317,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
}
// Get body of message to be wrapped
BdfList body = clientHelper.getMessageAsList(txn, header.getId());
BdfList body = clientHelper.getSmallMessageAsList(txn, header.getId());
long timestamp = header.getTimestamp();
Message wrappedMessage;
@@ -465,7 +465,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
@Override
public String getPostText(MessageId m) throws DbException {
try {
return getPostText(clientHelper.getMessageAsList(m));
return getPostText(clientHelper.getSmallMessageAsList(m));
} catch (FormatException e) {
throw new DbException(e);
}

View File

@@ -179,7 +179,7 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
@Override
public String getPostText(MessageId m) throws DbException {
try {
return getPostText(clientHelper.getMessageAsList(m));
return getPostText(clientHelper.getSmallMessageAsList(m));
} catch (FormatException e) {
throw new DbException(e);
}

View File

@@ -448,7 +448,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
MessageStatus status, SessionId sessionId,
Map<AuthorId, AuthorInfo> authorInfos)
throws DbException, FormatException {
Message msg = clientHelper.getMessage(txn, m);
Message msg = clientHelper.getSmallMessage(txn, m);
BdfList body = clientHelper.toList(msg);
RequestMessage rm = messageParser.parseRequestMessage(msg, body);
String text = rm.getText();

View File

@@ -392,7 +392,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
@Override
public String getMessageText(MessageId m) throws DbException {
try {
BdfList body = clientHelper.getMessageAsList(m);
BdfList body = clientHelper.getSmallMessageAsList(m);
if (body.size() == 1) return body.getString(0); // Legacy format
else return body.getOptionalString(1);
} catch (FormatException e) {
@@ -404,7 +404,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
public Attachment getAttachment(AttachmentHeader h) throws DbException {
// TODO: Support large messages
MessageId m = h.getMessageId();
byte[] body = clientHelper.getMessage(m).getBody();
byte[] body = clientHelper.getSmallMessage(m).getBody();
try {
BdfDictionary meta = clientHelper.getMessageMetadataAsDictionary(m);
Long messageType = meta.getOptionalLong(MSG_KEY_MSG_TYPE);

View File

@@ -304,7 +304,7 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
@Override
public String getMessageText(MessageId m) throws DbException {
try {
return getMessageText(clientHelper.getMessageAsList(m));
return getMessageText(clientHelper.getSmallMessageAsList(m));
} catch (FormatException e) {
throw new DbException(e);
}

Some files were not shown because too many files have changed in this diff Show More