Compare commits

...

27 Commits

Author SHA1 Message Date
akwizgran
0dd4d86f4a Bump version numbers for 1.4.21 release. 2023-02-20 16:00:45 +00:00
akwizgran
17e0829f42 Update translations. 2023-02-20 16:00:05 +00:00
Torsten Grote
938d8b71a0 Merge branch 'bdf-cleanup' into 'master'
Clean up some BDF quirks

See merge request briar/briar!1772
2023-02-20 14:15:47 +00:00
akwizgran
1b808584b6 Replace some more longs with ints. 2023-02-20 13:53:40 +00:00
akwizgran
36db5b48ef Remove methods for manually reading lists and dictionaries. 2023-02-20 13:05:38 +00:00
akwizgran
ccd6ed9ff0 Add fast path for writing BdfDictionaries. 2023-02-20 11:56:13 +00:00
akwizgran
0ced10b3a9 Use getInt() in a couple more places. 2023-02-20 11:33:48 +00:00
akwizgran
98064e9efe Remove BdfWriter methods for manually constructing lists and dicts. 2023-02-18 17:36:02 +00:00
akwizgran
63172ef2e4 Add 32-bit int methods to BdfList and BdfDictionary.
We use these a lot so it's useful to have built-in support.

Also refactor BdfList and BdfDictionary so the getters that take default values behave like the other getters. This simplifies the semantics and allows duplicated code to be removed.

Add comprehensive tests for BdfList and BdfDictionary.
2023-02-18 17:36:02 +00:00
akwizgran
7a854e70cb Add BdfReader methods for 32-bit ints.
We use these a lot so it's convenient to have built-in support.

Also make BdfReaderImpl and BdfWriterImpl final to enable compiler optimisations.
2023-02-18 17:36:02 +00:00
akwizgran
ac8a4db457 Add support for reading and writing BDF in canonical form.
Existing transport property updates may not be in canonical form, so we need to parse them leniently.
2023-02-18 17:36:02 +00:00
akwizgran
5a09530670 Reject invalid UTF-8 instead of ignoring it. 2023-02-18 17:10:57 +00:00
akwizgran
4fe91bacc6 Merge branch 'sync-record-reader-tests' into 'master'
Add some tests for sync record reader

See merge request briar/briar!1771
2023-02-17 17:38:04 +00:00
akwizgran
7f70a1519b Make message fields local. 2023-02-17 17:28:10 +00:00
akwizgran
c92ee0458e Add some tests for sync record reader. 2023-02-17 17:19:59 +00:00
akwizgran
10b1fe756d Merge branch 'reproduce-headless' into 'master'
Check reproducibility of headless releases

See merge request briar/briar!1769
2023-02-13 16:21:50 +00:00
Torsten Grote
1a2a250be0 Check reproducibility of headless releases 2023-02-10 16:43:01 -03:00
akwizgran
a621b8077e Merge branch 'update-reproducer-release-tag' into 'master'
Update briar-reproducer release tag

See merge request briar/briar!1768
2023-02-10 14:17:15 +00:00
akwizgran
19084d4060 Merge branch 'mailbox-version-mismatch' into 'master'
Show mailbox version issues before connection failures

See merge request briar/briar!1767
2023-02-10 13:57:36 +00:00
akwizgran
2f73ee1b57 Update briar-reproducer release tag. 2023-02-10 13:54:44 +00:00
Torsten Grote
45fa12c0b3 Show mailbox version issues before connection failures 2023-02-09 13:10:02 -03:00
akwizgran
4253bbaaf5 Update translations. 2023-02-06 12:40:04 +00:00
akwizgran
8c2e58796b Merge branch 'mailbox-convert-qr' into 'master'
Add convenience method for converting mailbox pairing text into QR code payload

See merge request briar/briar!1766
2023-02-03 14:34:04 +00:00
Torsten Grote
3f13e7e9c3 Add convenience method for converting mailbox pairing text into QR code payload 2023-02-03 11:18:25 -03:00
akwizgran
421a93b9a6 Merge branch 'rss-from-file' into 'master'
Allow to import RSS feeds from a file

See merge request briar/briar!1765
2023-01-31 13:17:21 +00:00
Torsten Grote
8a088638db Don't show success fragment for RSS file import 2023-01-31 09:57:51 -03:00
Torsten Grote
a888c5f632 Allow to import RSS feeds from a file 2023-01-30 15:31:25 -03:00
98 changed files with 1804 additions and 687 deletions

View File

@@ -83,7 +83,8 @@ android test:
test_reproducible: test_reproducible:
stage: check_reproducibility stage: check_reproducibility
script: script:
- "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]=${CI_COMMIT_REF_NAME} https://code.briarproject.org/api/v4/projects/61/trigger/pipeline" - "curl -X POST -F token=${RELEASE_CHECK_TOKEN} -F ref=master -F variables[RELEASE_TAG]='briar ${CI_COMMIT_REF_NAME}' https://code.briarproject.org/api/v4/projects/61/trigger/pipeline"
- "curl -X POST -F token=${RELEASE_JAR_CHECK_TOKEN} -F ref=main -F variables[RELEASE_TAG]='briar-headless ${CI_COMMIT_REF_NAME}' https://code.briarproject.org/api/v4/projects/307/trigger/pipeline"
only: only:
- tags - tags

View File

@@ -13,8 +13,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 31 targetSdkVersion 31
versionCode 10420 versionCode 10421
versionName "1.4.20" versionName "1.4.21"
consumerProguardFiles 'proguard-rules.txt' consumerProguardFiles 'proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

View File

@@ -16,6 +16,7 @@ import java.util.logging.Logger;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE; import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
@Immutable @Immutable
@@ -23,17 +24,24 @@ import static org.briarproject.bramble.api.transport.TransportConstants.MAX_CLOC
public abstract class BdfMessageValidator implements MessageValidator { public abstract class BdfMessageValidator implements MessageValidator {
protected static final Logger LOG = protected static final Logger LOG =
Logger.getLogger(BdfMessageValidator.class.getName()); getLogger(BdfMessageValidator.class.getName());
protected final ClientHelper clientHelper; protected final ClientHelper clientHelper;
protected final MetadataEncoder metadataEncoder; protected final MetadataEncoder metadataEncoder;
protected final Clock clock; protected final Clock clock;
protected final boolean canonical;
protected BdfMessageValidator(ClientHelper clientHelper, protected BdfMessageValidator(ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock) { MetadataEncoder metadataEncoder, Clock clock, boolean canonical) {
this.clientHelper = clientHelper; this.clientHelper = clientHelper;
this.metadataEncoder = metadataEncoder; this.metadataEncoder = metadataEncoder;
this.clock = clock; this.clock = clock;
this.canonical = canonical;
}
protected BdfMessageValidator(ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock) {
this(clientHelper, metadataEncoder, clock, true);
} }
protected abstract BdfMessageContext validateMessage(Message m, Group g, protected abstract BdfMessageContext validateMessage(Message m, Group g,
@@ -49,7 +57,7 @@ public abstract class BdfMessageValidator implements MessageValidator {
"Timestamp is too far in the future"); "Timestamp is too far in the future");
} }
try { try {
BdfList bodyList = clientHelper.toList(m.getBody()); BdfList bodyList = clientHelper.toList(m, canonical);
BdfMessageContext result = validateMessage(m, g, bodyList); BdfMessageContext result = validateMessage(m, g, bodyList);
Metadata meta = metadataEncoder.encode(result.getDictionary()); Metadata meta = metadataEncoder.encode(result.getDictionary());
return new MessageContext(meta, result.getDependencies()); return new MessageContext(meta, result.getDependencies());

View File

@@ -49,6 +49,9 @@ public interface ClientHelper {
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException, BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
FormatException; FormatException;
BdfList getMessageAsList(Transaction txn, MessageId m, boolean canonical)
throws DbException, FormatException;
BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException, BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException,
FormatException; FormatException;
@@ -106,6 +109,8 @@ public interface ClientHelper {
BdfList toList(Message m) throws FormatException; BdfList toList(Message m) throws FormatException;
BdfList toList(Message m, boolean canonical) throws FormatException;
BdfList toList(Author a); BdfList toList(Author a);
byte[] sign(String label, BdfList toSign, PrivateKey privateKey) byte[] sign(String label, BdfList toSign, PrivateKey privateKey)

View File

@@ -11,7 +11,7 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
@NotThreadSafe @NotThreadSafe
public class BdfDictionary extends TreeMap<String, Object> { public final class BdfDictionary extends TreeMap<String, Object> {
public static final Object NULL_VALUE = new Object(); public static final Object NULL_VALUE = new Object();
@@ -39,9 +39,9 @@ public class BdfDictionary extends TreeMap<String, Object> {
} }
public Boolean getBoolean(String key) throws FormatException { public Boolean getBoolean(String key) throws FormatException {
Object o = get(key); Boolean value = getOptionalBoolean(key);
if (o instanceof Boolean) return (Boolean) o; if (value == null) throw new FormatException();
throw new FormatException(); return value;
} }
@Nullable @Nullable
@@ -52,19 +52,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public Boolean getBoolean(String key, Boolean defaultValue) { public Boolean getBoolean(String key, Boolean defaultValue)
Object o = get(key); throws FormatException {
if (o instanceof Boolean) return (Boolean) o; Boolean value = getOptionalBoolean(key);
return defaultValue; return value == null ? defaultValue : value;
} }
public Long getLong(String key) throws FormatException { public Long getLong(String key) throws FormatException {
Object o = get(key); Long value = getOptionalLong(key);
if (o instanceof Long) return (Long) o; if (value == null) throw new FormatException();
if (o instanceof Integer) return ((Integer) o).longValue(); return value;
if (o instanceof Short) return ((Short) o).longValue();
if (o instanceof Byte) return ((Byte) o).longValue();
throw new FormatException();
} }
@Nullable @Nullable
@@ -78,20 +75,37 @@ public class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public Long getLong(String key, Long defaultValue) { public Long getLong(String key, Long defaultValue) throws FormatException {
Object o = get(key); Long value = getOptionalLong(key);
if (o instanceof Long) return (Long) o; return value == null ? defaultValue : value;
if (o instanceof Integer) return ((Integer) o).longValue(); }
if (o instanceof Short) return ((Short) o).longValue();
if (o instanceof Byte) return ((Byte) o).longValue(); public Integer getInt(String key) throws FormatException {
return defaultValue; Integer value = getOptionalInt(key);
if (value == null) throw new FormatException();
return value;
}
@Nullable
public Integer getOptionalInt(String key) throws FormatException {
Long value = getOptionalLong(key);
if (value == null) return null;
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new FormatException();
}
return value.intValue();
}
public Integer getInt(String key, Integer defaultValue)
throws FormatException {
Integer value = getOptionalInt(key);
return value == null ? defaultValue : value;
} }
public Double getDouble(String key) throws FormatException { public Double getDouble(String key) throws FormatException {
Object o = get(key); Double value = getOptionalDouble(key);
if (o instanceof Double) return (Double) o; if (value == null) throw new FormatException();
if (o instanceof Float) return ((Float) o).doubleValue(); return value;
throw new FormatException();
} }
@Nullable @Nullable
@@ -103,17 +117,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public Double getDouble(String key, Double defaultValue) { public Double getDouble(String key, Double defaultValue)
Object o = get(key); throws FormatException {
if (o instanceof Double) return (Double) o; Double value = getOptionalDouble(key);
if (o instanceof Float) return ((Float) o).doubleValue(); return value == null ? defaultValue : value;
return defaultValue;
} }
public String getString(String key) throws FormatException { public String getString(String key) throws FormatException {
Object o = get(key); String value = getOptionalString(key);
if (o instanceof String) return (String) o; if (value == null) throw new FormatException();
throw new FormatException(); return value;
} }
@Nullable @Nullable
@@ -124,17 +137,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public String getString(String key, String defaultValue) { public String getString(String key, String defaultValue)
Object o = get(key); throws FormatException {
if (o instanceof String) return (String) o; String value = getOptionalString(key);
return defaultValue; return value == null ? defaultValue : value;
} }
public byte[] getRaw(String key) throws FormatException { public byte[] getRaw(String key) throws FormatException {
Object o = get(key); byte[] value = getOptionalRaw(key);
if (o instanceof byte[]) return (byte[]) o; if (value == null) throw new FormatException();
if (o instanceof Bytes) return ((Bytes) o).getBytes(); return value;
throw new FormatException();
} }
@Nullable @Nullable
@@ -146,17 +158,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public byte[] getRaw(String key, byte[] defaultValue) { public byte[] getRaw(String key, byte[] defaultValue)
Object o = get(key); throws FormatException {
if (o instanceof byte[]) return (byte[]) o; byte[] value = getOptionalRaw(key);
if (o instanceof Bytes) return ((Bytes) o).getBytes(); return value == null ? defaultValue : value;
return defaultValue;
} }
public BdfList getList(String key) throws FormatException { public BdfList getList(String key) throws FormatException {
Object o = get(key); BdfList value = getOptionalList(key);
if (o instanceof BdfList) return (BdfList) o; if (value == null) throw new FormatException();
throw new FormatException(); return value;
} }
@Nullable @Nullable
@@ -167,16 +178,16 @@ public class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public BdfList getList(String key, BdfList defaultValue) { public BdfList getList(String key, BdfList defaultValue)
Object o = get(key); throws FormatException {
if (o instanceof BdfList) return (BdfList) o; BdfList value = getOptionalList(key);
return defaultValue; return value == null ? defaultValue : value;
} }
public BdfDictionary getDictionary(String key) throws FormatException { public BdfDictionary getDictionary(String key) throws FormatException {
Object o = get(key); BdfDictionary value = getOptionalDictionary(key);
if (o instanceof BdfDictionary) return (BdfDictionary) o; if (value == null) throw new FormatException();
throw new FormatException(); return value;
} }
@Nullable @Nullable
@@ -188,9 +199,9 @@ public class BdfDictionary extends TreeMap<String, Object> {
throw new FormatException(); throw new FormatException();
} }
public BdfDictionary getDictionary(String key, BdfDictionary defaultValue) { public BdfDictionary getDictionary(String key, BdfDictionary defaultValue)
Object o = get(key); throws FormatException {
if (o instanceof BdfDictionary) return (BdfDictionary) o; BdfDictionary value = getOptionalDictionary(key);
return defaultValue; return value == null ? defaultValue : value;
} }
} }

View File

@@ -13,7 +13,7 @@ import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
@NotThreadSafe @NotThreadSafe
public class BdfList extends ArrayList<Object> { public final class BdfList extends ArrayList<Object> {
/** /**
* Factory method for constructing lists inline. * Factory method for constructing lists inline.
@@ -33,15 +33,15 @@ public class BdfList extends ArrayList<Object> {
super(items); super(items);
} }
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isInRange(int index) { private boolean isInRange(int index) {
return index >= 0 && index < size(); return index >= 0 && index < size();
} }
public Boolean getBoolean(int index) throws FormatException { public Boolean getBoolean(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); Boolean value = getOptionalBoolean(index);
Object o = get(index); if (value == null) throw new FormatException();
if (o instanceof Boolean) return (Boolean) o; return value;
throw new FormatException();
} }
@Nullable @Nullable
@@ -53,21 +53,16 @@ public class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public Boolean getBoolean(int index, Boolean defaultValue) { public Boolean getBoolean(int index, Boolean defaultValue)
if (!isInRange(index)) return defaultValue; throws FormatException {
Object o = get(index); Boolean value = getOptionalBoolean(index);
if (o instanceof Boolean) return (Boolean) o; return value == null ? defaultValue : value;
return defaultValue;
} }
public Long getLong(int index) throws FormatException { public Long getLong(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); Long value = getOptionalLong(index);
Object o = get(index); if (value == null) throw new FormatException();
if (o instanceof Long) return (Long) o; return value;
if (o instanceof Integer) return ((Integer) o).longValue();
if (o instanceof Short) return ((Short) o).longValue();
if (o instanceof Byte) return ((Byte) o).longValue();
throw new FormatException();
} }
@Nullable @Nullable
@@ -82,22 +77,37 @@ public class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public Long getLong(int index, Long defaultValue) { public Long getLong(int index, Long defaultValue) throws FormatException {
if (!isInRange(index)) return defaultValue; Long value = getOptionalLong(index);
Object o = get(index); return value == null ? defaultValue : value;
if (o instanceof Long) return (Long) o; }
if (o instanceof Integer) return ((Integer) o).longValue();
if (o instanceof Short) return ((Short) o).longValue(); public Integer getInt(int index) throws FormatException {
if (o instanceof Byte) return ((Byte) o).longValue(); Integer value = getOptionalInt(index);
return defaultValue; if (value == null) throw new FormatException();
return value;
}
@Nullable
public Integer getOptionalInt(int index) throws FormatException {
Long value = getOptionalLong(index);
if (value == null) return null;
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new FormatException();
}
return value.intValue();
}
public Integer getInt(int index, Integer defaultValue)
throws FormatException {
Integer value = getOptionalInt(index);
return value == null ? defaultValue : value;
} }
public Double getDouble(int index) throws FormatException { public Double getDouble(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); Double value = getOptionalDouble(index);
Object o = get(index); if (value == null) throw new FormatException();
if (o instanceof Double) return (Double) o; return value;
if (o instanceof Float) return ((Float) o).doubleValue();
throw new FormatException();
} }
@Nullable @Nullable
@@ -110,19 +120,16 @@ public class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public Double getDouble(int index, Double defaultValue) { public Double getDouble(int index, Double defaultValue)
if (!isInRange(index)) return defaultValue; throws FormatException {
Object o = get(index); Double value = getOptionalDouble(index);
if (o instanceof Double) return (Double) o; return value == null ? defaultValue : value;
if (o instanceof Float) return ((Float) o).doubleValue();
return defaultValue;
} }
public String getString(int index) throws FormatException { public String getString(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); String value = getOptionalString(index);
Object o = get(index); if (value == null) throw new FormatException();
if (o instanceof String) return (String) o; return value;
throw new FormatException();
} }
@Nullable @Nullable
@@ -134,19 +141,16 @@ public class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public String getString(int index, String defaultValue) { public String getString(int index, String defaultValue)
if (!isInRange(index)) return defaultValue; throws FormatException {
Object o = get(index); String value = getOptionalString(index);
if (o instanceof String) return (String) o; return value == null ? defaultValue : value;
return defaultValue;
} }
public byte[] getRaw(int index) throws FormatException { public byte[] getRaw(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); byte[] value = getOptionalRaw(index);
Object o = get(index); if (value == null) throw new FormatException();
if (o instanceof byte[]) return (byte[]) o; return value;
if (o instanceof Bytes) return ((Bytes) o).getBytes();
throw new FormatException();
} }
@Nullable @Nullable
@@ -159,19 +163,16 @@ public class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public byte[] getRaw(int index, byte[] defaultValue) { public byte[] getRaw(int index, byte[] defaultValue)
if (!isInRange(index)) return defaultValue; throws FormatException {
Object o = get(index); byte[] value = getOptionalRaw(index);
if (o instanceof byte[]) return (byte[]) o; return value == null ? defaultValue : value;
if (o instanceof Bytes) return ((Bytes) o).getBytes();
return defaultValue;
} }
public BdfList getList(int index) throws FormatException { public BdfList getList(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); BdfList value = getOptionalList(index);
Object o = get(index); if (value == null) throw new FormatException();
if (o instanceof BdfList) return (BdfList) o; return value;
throw new FormatException();
} }
@Nullable @Nullable
@@ -183,18 +184,16 @@ public class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public BdfList getList(int index, BdfList defaultValue) { public BdfList getList(int index, BdfList defaultValue)
if (!isInRange(index)) return defaultValue; throws FormatException {
Object o = get(index); BdfList value = getOptionalList(index);
if (o instanceof BdfList) return (BdfList) o; return value == null ? defaultValue : value;
return defaultValue;
} }
public BdfDictionary getDictionary(int index) throws FormatException { public BdfDictionary getDictionary(int index) throws FormatException {
if (!isInRange(index)) throw new FormatException(); BdfDictionary value = getOptionalDictionary(index);
Object o = get(index); if (value == null) throw new FormatException();
if (o instanceof BdfDictionary) return (BdfDictionary) o; return value;
throw new FormatException();
} }
@Nullable @Nullable
@@ -207,10 +206,9 @@ public class BdfList extends ArrayList<Object> {
throw new FormatException(); throw new FormatException();
} }
public BdfDictionary getDictionary(int index, BdfDictionary defaultValue) { public BdfDictionary getDictionary(int index, BdfDictionary defaultValue)
if (!isInRange(index)) return defaultValue; throws FormatException {
Object o = get(index); BdfDictionary value = getOptionalDictionary(index);
if (o instanceof BdfDictionary) return (BdfDictionary) o; return value == null ? defaultValue : value;
return defaultValue;
} }
} }

View File

@@ -32,6 +32,12 @@ public interface BdfReader {
void skipLong() throws IOException; void skipLong() throws IOException;
boolean hasInt() throws IOException;
int readInt() throws IOException;
void skipInt() throws IOException;
boolean hasDouble() throws IOException; boolean hasDouble() throws IOException;
double readDouble() throws IOException; double readDouble() throws IOException;
@@ -54,23 +60,11 @@ public interface BdfReader {
BdfList readList() throws IOException; BdfList readList() throws IOException;
void readListStart() throws IOException;
boolean hasListEnd() throws IOException;
void readListEnd() throws IOException;
void skipList() throws IOException; void skipList() throws IOException;
boolean hasDictionary() throws IOException; boolean hasDictionary() throws IOException;
BdfDictionary readDictionary() throws IOException; BdfDictionary readDictionary() throws IOException;
void readDictionaryStart() throws IOException;
boolean hasDictionaryEnd() throws IOException;
void readDictionaryEnd() throws IOException;
void skipDictionary() throws IOException; void skipDictionary() throws IOException;
} }

View File

@@ -9,6 +9,8 @@ public interface BdfReaderFactory {
BdfReader createReader(InputStream in); BdfReader createReader(InputStream in);
BdfReader createReader(InputStream in, boolean canonical);
BdfReader createReader(InputStream in, int nestedLimit, BdfReader createReader(InputStream in, int nestedLimit,
int maxBufferSize); int maxBufferSize, boolean canonical);
} }

View File

@@ -24,13 +24,5 @@ public interface BdfWriter {
void writeList(Collection<?> c) throws IOException; void writeList(Collection<?> c) throws IOException;
void writeListStart() throws IOException;
void writeListEnd() throws IOException;
void writeDictionary(Map<?, ?> m) throws IOException; void writeDictionary(Map<?, ?> m) throws IOException;
void writeDictionaryStart() throws IOException;
void writeDictionaryEnd() throws IOException;
} }

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.api.mailbox; package org.briarproject.bramble.api.mailbox;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.lifecycle.IoExecutor; import org.briarproject.bramble.api.lifecycle.IoExecutor;
@@ -34,6 +35,16 @@ public interface MailboxManager {
*/ */
MailboxPairingTask startPairingTask(String qrCodePayload); MailboxPairingTask startPairingTask(String qrCodePayload);
/**
* Takes a textual QR code representation in
* {@link org.briarproject.bramble.util.Base32} format and converts it
* into a qrCodePayload as expected by {@link #startPairingTask(String)}.
*
* @throws FormatException when the provided payload did not include a
* proper briar-mailbox:// link.
*/
String convertBase32Payload(String base32Payload) throws FormatException;
/** /**
* Can be used by the UI to test the mailbox connection. * Can be used by the UI to test the mailbox connection.
* *

View File

@@ -14,6 +14,7 @@ import java.util.regex.Pattern;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static java.nio.charset.CodingErrorAction.IGNORE; import static java.nio.charset.CodingErrorAction.IGNORE;
import static java.nio.charset.CodingErrorAction.REPORT;
import static java.util.regex.Pattern.CASE_INSENSITIVE; import static java.util.regex.Pattern.CASE_INSENSITIVE;
@SuppressWarnings("CharsetObjectCanBeUsed") @SuppressWarnings("CharsetObjectCanBeUsed")
@@ -52,26 +53,38 @@ public class StringUtils {
return s.getBytes(UTF_8); return s.getBytes(UTF_8);
} }
public static String fromUtf8(byte[] bytes) { public static String fromUtf8(byte[] bytes) throws FormatException {
return fromUtf8(bytes, 0, bytes.length); return fromUtf8(bytes, 0, bytes.length, true);
} }
public static String fromUtf8(byte[] bytes, int off, int len) { public static String fromUtf8(byte[] bytes, int off, int len)
throws FormatException {
return fromUtf8(bytes, off, len, true);
}
private static String fromUtf8(byte[] bytes, int off, int len,
boolean strict) throws FormatException {
CharsetDecoder decoder = UTF_8.newDecoder(); CharsetDecoder decoder = UTF_8.newDecoder();
decoder.onMalformedInput(IGNORE); decoder.onMalformedInput(strict ? REPORT : IGNORE);
decoder.onUnmappableCharacter(IGNORE); decoder.onUnmappableCharacter(strict ? REPORT : IGNORE);
ByteBuffer buffer = ByteBuffer.wrap(bytes, off, len); ByteBuffer buffer = ByteBuffer.wrap(bytes, off, len);
try { try {
return decoder.decode(buffer).toString(); return decoder.decode(buffer).toString();
} catch (CharacterCodingException e) { } catch (CharacterCodingException e) {
throw new AssertionError(e); throw new FormatException();
} }
} }
public static String truncateUtf8(String s, int maxUtf8Length) { public static String truncateUtf8(String s, int maxUtf8Length) {
byte[] utf8 = toUtf8(s); byte[] utf8 = toUtf8(s);
if (utf8.length <= maxUtf8Length) return s; if (utf8.length <= maxUtf8Length) return s;
return fromUtf8(utf8, 0, maxUtf8Length); // Don't be strict when converting back, so that if we truncate a
// multi-byte character the whole character gets dropped
try {
return fromUtf8(utf8, 0, maxUtf8Length, false);
} catch (FormatException e) {
throw new AssertionError(e);
}
} }
/** /**

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api.data; package org.briarproject.bramble.api.data;
import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test; import org.junit.Test;
@@ -8,9 +9,12 @@ import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map.Entry; import java.util.Map.Entry;
import static java.lang.Boolean.TRUE;
import static java.util.Collections.singletonMap;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
public class BdfDictionaryTest extends BrambleTestCase { public class BdfDictionaryTest extends BrambleTestCase {
@@ -19,20 +23,20 @@ public class BdfDictionaryTest extends BrambleTestCase {
public void testConstructors() { public void testConstructors() {
assertEquals(Collections.<String, Object>emptyMap(), assertEquals(Collections.<String, Object>emptyMap(),
new BdfDictionary()); new BdfDictionary());
assertEquals(Collections.singletonMap("foo", NULL_VALUE), assertEquals(singletonMap("foo", NULL_VALUE),
new BdfDictionary(Collections.singletonMap("foo", NULL_VALUE))); new BdfDictionary(singletonMap("foo", NULL_VALUE)));
} }
@Test @Test
public void testFactoryMethod() { public void testFactoryMethod() {
assertEquals(Collections.<String, Object>emptyMap(), assertEquals(Collections.<String, Object>emptyMap(),
BdfDictionary.of()); BdfDictionary.of());
assertEquals(Collections.singletonMap("foo", NULL_VALUE), assertEquals(singletonMap("foo", NULL_VALUE),
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE))); BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)));
} }
@Test @Test
public void testIntegerPromotion() throws Exception { public void testLongPromotion() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("foo", (byte) 1); d.put("foo", (byte) 1);
d.put("bar", (short) 2); d.put("bar", (short) 2);
@@ -44,6 +48,33 @@ public class BdfDictionaryTest extends BrambleTestCase {
assertEquals(Long.valueOf(4), d.getLong("bam")); assertEquals(Long.valueOf(4), d.getLong("bam"));
} }
@Test
public void testIntPromotionAndDemotion() throws Exception {
BdfDictionary d = new BdfDictionary();
d.put("foo", (byte) 1);
d.put("bar", (short) 2);
d.put("baz", 3);
d.put("bam", 4L);
assertEquals(Integer.valueOf(1), d.getInt("foo"));
assertEquals(Integer.valueOf(2), d.getInt("bar"));
assertEquals(Integer.valueOf(3), d.getInt("baz"));
assertEquals(Integer.valueOf(4), d.getInt("bam"));
}
@Test(expected = FormatException.class)
public void testIntUnderflow() throws Exception {
BdfDictionary d =
BdfDictionary.of(new BdfEntry("foo", Integer.MIN_VALUE - 1L));
d.getInt("foo");
}
@Test(expected = FormatException.class)
public void testIntOverflow() throws Exception {
BdfDictionary d =
BdfDictionary.of(new BdfEntry("foo", Integer.MAX_VALUE + 1L));
d.getInt("foo");
}
@Test @Test
public void testFloatPromotion() throws Exception { public void testFloatPromotion() throws Exception {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
@@ -67,7 +98,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testKeySetIteratorIsOrderedByKeys() throws Exception { public void testKeySetIteratorIsOrderedByKeys() {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -86,7 +117,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testValuesIteratorIsOrderedByKeys() throws Exception { public void testValuesIteratorIsOrderedByKeys() {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -105,7 +136,7 @@ public class BdfDictionaryTest extends BrambleTestCase {
} }
@Test @Test
public void testEntrySetIteratorIsOrderedByKeys() throws Exception { public void testEntrySetIteratorIsOrderedByKeys() {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put("a", 1); d.put("a", 1);
d.put("d", 4); d.put("d", 4);
@@ -130,4 +161,284 @@ public class BdfDictionaryTest extends BrambleTestCase {
assertEquals("d", e.getKey()); assertEquals("d", e.getKey());
assertEquals(4, e.getValue()); assertEquals(4, e.getValue());
} }
@Test(expected = FormatException.class)
public void testMissingValueForBooleanThrowsFormatException()
throws Exception {
new BdfDictionary().getBoolean("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForLongThrowsFormatException()
throws Exception {
new BdfDictionary().getLong("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForIntThrowsFormatException() throws Exception {
new BdfDictionary().getInt("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForDoubleThrowsFormatException()
throws Exception {
new BdfDictionary().getDouble("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForStringThrowsFormatException()
throws Exception {
new BdfDictionary().getString("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForRawThrowsFormatException() throws Exception {
new BdfDictionary().getRaw("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForListThrowsFormatException()
throws Exception {
new BdfDictionary().getList("foo");
}
@Test(expected = FormatException.class)
public void testMissingValueForDictionaryThrowsFormatException()
throws Exception {
new BdfDictionary().getDictionary("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForBooleanThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getBoolean("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForLongThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getLong("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForIntThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getInt("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForDoubleThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getDouble("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForStringThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getString("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForRawThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getRaw("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForListThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getList("foo");
}
@Test(expected = FormatException.class)
public void testNullValueForDictionaryThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", NULL_VALUE)).getDictionary("foo");
}
@Test
public void testOptionalMethodsReturnNullForMissingValue()
throws Exception {
testOptionalMethodsReturnNull(new BdfDictionary());
}
@Test
public void testOptionalMethodsReturnNullForNullValue() throws Exception {
BdfDictionary d = BdfDictionary.of(new BdfEntry("foo", NULL_VALUE));
testOptionalMethodsReturnNull(d);
}
private void testOptionalMethodsReturnNull(BdfDictionary d)
throws Exception {
assertNull(d.getOptionalBoolean("foo"));
assertNull(d.getOptionalLong("foo"));
assertNull(d.getOptionalInt("foo"));
assertNull(d.getOptionalDouble("foo"));
assertNull(d.getOptionalString("foo"));
assertNull(d.getOptionalRaw("foo"));
assertNull(d.getOptionalList("foo"));
assertNull(d.getOptionalDictionary("foo"));
}
@Test
public void testDefaultMethodsReturnDefaultForMissingValue()
throws Exception {
testDefaultMethodsReturnDefault(new BdfDictionary());
}
@Test
public void testDefaultMethodsReturnDefaultForNullValue() throws Exception {
BdfDictionary d = BdfDictionary.of(new BdfEntry("foo", NULL_VALUE));
testDefaultMethodsReturnDefault(d);
}
private void testDefaultMethodsReturnDefault(BdfDictionary d)
throws Exception {
assertEquals(TRUE, d.getBoolean("foo", TRUE));
assertEquals(Long.valueOf(123L), d.getLong("foo", 123L));
assertEquals(Integer.valueOf(123), d.getInt("foo", 123));
assertEquals(Double.valueOf(123D), d.getDouble("foo", 123D));
assertEquals("123", d.getString("foo", "123"));
byte[] defaultRaw = {1, 2, 3};
assertArrayEquals(defaultRaw, d.getRaw("foo", defaultRaw));
BdfList defaultList = BdfList.of(1, 2, 3);
assertEquals(defaultList, d.getList("foo", defaultList));
BdfDictionary defaultDict = BdfDictionary.of(new BdfEntry("123", 123));
assertEquals(defaultDict, d.getDictionary("foo", defaultDict));
}
@Test(expected = FormatException.class)
public void testWrongTypeForBooleanThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getBoolean("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalBooleanThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalBoolean("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultBooleanThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getBoolean("foo", true);
}
@Test(expected = FormatException.class)
public void testWrongTypeForLongThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getLong("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalLongThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getOptionalLong("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultLongThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getLong("foo", 1L);
}
@Test(expected = FormatException.class)
public void testWrongTypeForIntThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getInt("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalIntThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getOptionalInt("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultIntThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 1.23)).getInt("foo", 1);
}
@Test(expected = FormatException.class)
public void testWrongTypeForDoubleThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getDouble("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalDoubleThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalDouble("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultDoubleThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getDouble("foo", 1D);
}
@Test(expected = FormatException.class)
public void testWrongTypeForStringThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getString("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalStringThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalString("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultStringThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getString("foo", "");
}
@Test(expected = FormatException.class)
public void testWrongTypeForRawThrowsFormatException() throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getRaw("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalRawThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalRaw("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultRawThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getRaw("foo", new byte[0]);
}
@Test(expected = FormatException.class)
public void testWrongTypeForListThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getList("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalListThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalList("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultListThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getList("foo",
new BdfList());
}
@Test(expected = FormatException.class)
public void testWrongTypeForDictionaryThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getDictionary("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalDictionaryThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getOptionalDictionary("foo");
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultDictionaryThrowsFormatException()
throws Exception {
BdfDictionary.of(new BdfEntry("foo", 123)).getDictionary("foo",
new BdfDictionary());
}
} }

View File

@@ -5,31 +5,31 @@ import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test; import org.junit.Test;
import java.util.Arrays; import static java.lang.Boolean.TRUE;
import java.util.Collections; import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public class BdfListTest extends BrambleTestCase { public class BdfListTest extends BrambleTestCase {
@Test @Test
public void testConstructors() { public void testConstructors() {
assertEquals(Collections.emptyList(), new BdfList()); assertEquals(emptyList(), new BdfList());
assertEquals(Arrays.asList(1, 2, NULL_VALUE), assertEquals(asList(1, 2, NULL_VALUE),
new BdfList(Arrays.asList(1, 2, NULL_VALUE))); new BdfList(asList(1, 2, NULL_VALUE)));
} }
@Test @Test
public void testFactoryMethod() { public void testFactoryMethod() {
assertEquals(Collections.emptyList(), BdfList.of()); assertEquals(emptyList(), BdfList.of());
assertEquals(Arrays.asList(1, 2, NULL_VALUE), assertEquals(asList(1, 2, NULL_VALUE), BdfList.of(1, 2, NULL_VALUE));
BdfList.of(1, 2, NULL_VALUE));
} }
@Test @Test
public void testIntegerPromotion() throws Exception { public void testLongPromotion() throws Exception {
BdfList list = new BdfList(); BdfList list = new BdfList();
list.add((byte) 1); list.add((byte) 1);
list.add((short) 2); list.add((short) 2);
@@ -41,6 +41,31 @@ public class BdfListTest extends BrambleTestCase {
assertEquals(Long.valueOf(4), list.getLong(3)); assertEquals(Long.valueOf(4), list.getLong(3));
} }
@Test
public void testIntPromotionAndDemotion() throws Exception {
BdfList list = new BdfList();
list.add((byte) 1);
list.add((short) 2);
list.add(3);
list.add(4L);
assertEquals(Integer.valueOf(1), list.getInt(0));
assertEquals(Integer.valueOf(2), list.getInt(1));
assertEquals(Integer.valueOf(3), list.getInt(2));
assertEquals(Integer.valueOf(4), list.getInt(3));
}
@Test(expected = FormatException.class)
public void testIntUnderflow() throws Exception {
BdfList list = BdfList.of(Integer.MIN_VALUE - 1L);
list.getInt(0);
}
@Test(expected = FormatException.class)
public void testIntOverflow() throws Exception {
BdfList list = BdfList.of(Integer.MAX_VALUE + 1L);
list.getInt(0);
}
@Test @Test
public void testFloatPromotion() throws Exception { public void testFloatPromotion() throws Exception {
BdfList list = new BdfList(); BdfList list = new BdfList();
@@ -63,61 +88,6 @@ public class BdfListTest extends BrambleTestCase {
assertArrayEquals(new byte[123], second); assertArrayEquals(new byte[123], second);
} }
@Test
@SuppressWarnings("ConstantConditions")
public void testIndexOutOfBoundsReturnsDefaultValue() throws Exception {
BdfList list = BdfList.of(1, 2, 3);
boolean defaultBoolean = true;
assertEquals(defaultBoolean, list.getBoolean(-1, defaultBoolean));
assertEquals(defaultBoolean, list.getBoolean(3, defaultBoolean));
Long defaultLong = 123L;
assertEquals(defaultLong, list.getLong(-1, defaultLong));
assertEquals(defaultLong, list.getLong(3, defaultLong));
Double defaultDouble = 1.23;
assertEquals(defaultDouble, list.getDouble(-1, defaultDouble));
assertEquals(defaultDouble, list.getDouble(3, defaultDouble));
String defaultString = "123";
assertEquals(defaultString, list.getString(-1, defaultString));
assertEquals(defaultString, list.getString(3, defaultString));
byte[] defaultBytes = new byte[] {1, 2, 3};
assertArrayEquals(defaultBytes, list.getRaw(-1, defaultBytes));
assertArrayEquals(defaultBytes, list.getRaw(3, defaultBytes));
BdfList defaultList = BdfList.of(1, 2, 3);
assertEquals(defaultList, list.getList(-1, defaultList));
assertEquals(defaultList, list.getList(3, defaultList));
BdfDictionary defaultDict = BdfDictionary.of(
new BdfEntry("1", 1),
new BdfEntry("2", 2),
new BdfEntry("3", 3)
);
assertEquals(defaultDict, list.getDictionary(-1, defaultDict));
assertEquals(defaultDict, list.getDictionary(3, defaultDict));
}
@Test
@SuppressWarnings("ConstantConditions")
public void testWrongTypeReturnsDefaultValue() throws Exception {
BdfList list = BdfList.of(1, 2, 3, true);
boolean defaultBoolean = true;
assertEquals(defaultBoolean, list.getBoolean(0, defaultBoolean));
Long defaultLong = 123L;
assertEquals(defaultLong, list.getLong(3, defaultLong));
Double defaultDouble = 1.23;
assertEquals(defaultDouble, list.getDouble(0, defaultDouble));
String defaultString = "123";
assertEquals(defaultString, list.getString(0, defaultString));
byte[] defaultBytes = new byte[] {1, 2, 3};
assertArrayEquals(defaultBytes, list.getRaw(0, defaultBytes));
BdfList defaultList = BdfList.of(1, 2, 3);
assertEquals(defaultList, list.getList(0, defaultList));
BdfDictionary defaultDict = BdfDictionary.of(
new BdfEntry("1", 1),
new BdfEntry("2", 2),
new BdfEntry("3", 3)
);
assertEquals(defaultDict, list.getDictionary(0, defaultDict));
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForBooleanThrowsFormatException() public void testNegativeIndexForBooleanThrowsFormatException()
throws Exception { throws Exception {
@@ -130,6 +100,12 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalBoolean(-1); new BdfList().getOptionalBoolean(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultBooleanThrowsFormatException()
throws Exception {
new BdfList().getBoolean(-1, true);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForLongThrowsFormatException() public void testNegativeIndexForLongThrowsFormatException()
throws Exception { throws Exception {
@@ -142,6 +118,30 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalLong(-1); new BdfList().getOptionalLong(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultLongThrowsFormatException()
throws Exception {
new BdfList().getLong(-1, 1L);
}
@Test(expected = FormatException.class)
public void testNegativeIndexForIntThrowsFormatException()
throws Exception {
new BdfList().getInt(-1);
}
@Test(expected = FormatException.class)
public void testNegativeIndexForOptionalIntThrowsFormatException()
throws Exception {
new BdfList().getOptionalInt(-1);
}
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultIntThrowsFormatException()
throws Exception {
new BdfList().getInt(-1, 1);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForDoubleThrowsFormatException() public void testNegativeIndexForDoubleThrowsFormatException()
throws Exception { throws Exception {
@@ -154,6 +154,12 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalDouble(-1); new BdfList().getOptionalDouble(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultDoubleThrowsFormatException()
throws Exception {
new BdfList().getDouble(-1, 1D);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForStringThrowsFormatException() public void testNegativeIndexForStringThrowsFormatException()
throws Exception { throws Exception {
@@ -166,6 +172,12 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalString(-1); new BdfList().getOptionalString(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultStringThrowsFormatException()
throws Exception {
new BdfList().getString(-1, "");
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForRawThrowsFormatException() public void testNegativeIndexForRawThrowsFormatException()
throws Exception { throws Exception {
@@ -178,6 +190,12 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalRaw(-1); new BdfList().getOptionalRaw(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultRawThrowsFormatException()
throws Exception {
new BdfList().getRaw(-1, new byte[0]);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForListThrowsFormatException() public void testNegativeIndexForListThrowsFormatException()
throws Exception { throws Exception {
@@ -190,6 +208,11 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalList(-1); new BdfList().getOptionalList(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultListThrowsFormatException()
throws Exception {
new BdfList().getList(-1, new BdfList());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNegativeIndexForDictionaryThrowsFormatException() public void testNegativeIndexForDictionaryThrowsFormatException()
@@ -203,6 +226,12 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalDictionary(-1); new BdfList().getOptionalDictionary(-1);
} }
@Test(expected = FormatException.class)
public void testNegativeIndexForDefaultDictionaryThrowsFormatException()
throws Exception {
new BdfList().getDictionary(-1, new BdfDictionary());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForBooleanThrowsFormatException() public void testTooLargeIndexForBooleanThrowsFormatException()
throws Exception { throws Exception {
@@ -215,6 +244,12 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalBoolean(0); new BdfList().getOptionalBoolean(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultBooleanThrowsFormatException()
throws Exception {
new BdfList().getBoolean(0, true);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForLongThrowsFormatException() public void testTooLargeIndexForLongThrowsFormatException()
throws Exception { throws Exception {
@@ -227,6 +262,30 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalLong(0); new BdfList().getOptionalLong(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultLongThrowsFormatException()
throws Exception {
new BdfList().getLong(0, 1L);
}
@Test(expected = FormatException.class)
public void testTooLargeIndexForIntThrowsFormatException()
throws Exception {
new BdfList().getInt(0);
}
@Test(expected = FormatException.class)
public void testTooLargeIndexForOptionalIntThrowsFormatException()
throws Exception {
new BdfList().getOptionalInt(0);
}
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultIntThrowsFormatException()
throws Exception {
new BdfList().getInt(0, 1);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForDoubleThrowsFormatException() public void testTooLargeIndexForDoubleThrowsFormatException()
throws Exception { throws Exception {
@@ -239,6 +298,12 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalDouble(0); new BdfList().getOptionalDouble(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultDoubleThrowsFormatException()
throws Exception {
new BdfList().getDouble(0, 1D);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForStringThrowsFormatException() public void testTooLargeIndexForStringThrowsFormatException()
throws Exception { throws Exception {
@@ -251,6 +316,12 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalString(0); new BdfList().getOptionalString(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultStringThrowsFormatException()
throws Exception {
new BdfList().getString(0, "");
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForRawThrowsFormatException() public void testTooLargeIndexForRawThrowsFormatException()
throws Exception { throws Exception {
@@ -263,6 +334,12 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalRaw(0); new BdfList().getOptionalRaw(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultRawThrowsFormatException()
throws Exception {
new BdfList().getRaw(0, new byte[0]);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForListThrowsFormatException() public void testTooLargeIndexForListThrowsFormatException()
throws Exception { throws Exception {
@@ -275,6 +352,11 @@ public class BdfListTest extends BrambleTestCase {
new BdfList().getOptionalList(0); new BdfList().getOptionalList(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultListThrowsFormatException()
throws Exception {
new BdfList().getList(0, new BdfList());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testTooLargeIndexForDictionaryThrowsFormatException() public void testTooLargeIndexForDictionaryThrowsFormatException()
@@ -287,6 +369,13 @@ public class BdfListTest extends BrambleTestCase {
throws Exception { throws Exception {
new BdfList().getOptionalDictionary(0); new BdfList().getOptionalDictionary(0);
} }
@Test(expected = FormatException.class)
public void testTooLargeIndexForDefaultDictionaryThrowsFormatException()
throws Exception {
new BdfList().getDictionary(0, new BdfDictionary());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForBooleanThrowsFormatException() public void testWrongTypeForBooleanThrowsFormatException()
throws Exception { throws Exception {
@@ -299,6 +388,12 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalBoolean(0); BdfList.of(123).getOptionalBoolean(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultBooleanThrowsFormatException()
throws Exception {
BdfList.of(123).getBoolean(0, true);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForLongThrowsFormatException() throws Exception { public void testWrongTypeForLongThrowsFormatException() throws Exception {
BdfList.of(1.23).getLong(0); BdfList.of(1.23).getLong(0);
@@ -310,6 +405,29 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(1.23).getOptionalLong(0); BdfList.of(1.23).getOptionalLong(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultLongThrowsFormatException()
throws Exception {
BdfList.of(1.23).getLong(0, 1L);
}
@Test(expected = FormatException.class)
public void testWrongTypeForIntThrowsFormatException() throws Exception {
BdfList.of(1.23).getInt(0);
}
@Test(expected = FormatException.class)
public void testWrongTypeForOptionalIntThrowsFormatException()
throws Exception {
BdfList.of(1.23).getOptionalInt(0);
}
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultIntThrowsFormatException()
throws Exception {
BdfList.of(1.23).getInt(0, 1);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForDoubleThrowsFormatException() throws Exception { public void testWrongTypeForDoubleThrowsFormatException() throws Exception {
BdfList.of(123).getDouble(0); BdfList.of(123).getDouble(0);
@@ -321,6 +439,12 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalDouble(0); BdfList.of(123).getOptionalDouble(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultDoubleThrowsFormatException()
throws Exception {
BdfList.of(123).getDouble(0, 1D);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForStringThrowsFormatException() throws Exception { public void testWrongTypeForStringThrowsFormatException() throws Exception {
BdfList.of(123).getString(0); BdfList.of(123).getString(0);
@@ -332,6 +456,12 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalString(0); BdfList.of(123).getOptionalString(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultStringThrowsFormatException()
throws Exception {
BdfList.of(123).getString(0, "");
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForRawThrowsFormatException() throws Exception { public void testWrongTypeForRawThrowsFormatException() throws Exception {
BdfList.of(123).getRaw(0); BdfList.of(123).getRaw(0);
@@ -343,6 +473,12 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalRaw(0); BdfList.of(123).getOptionalRaw(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultRawThrowsFormatException()
throws Exception {
BdfList.of(123).getRaw(0, new byte[0]);
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForListThrowsFormatException() throws Exception { public void testWrongTypeForListThrowsFormatException() throws Exception {
BdfList.of(123).getList(0); BdfList.of(123).getList(0);
@@ -354,6 +490,11 @@ public class BdfListTest extends BrambleTestCase {
BdfList.of(123).getOptionalList(0); BdfList.of(123).getOptionalList(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultListThrowsFormatException()
throws Exception {
BdfList.of(123).getList(0, new BdfList());
}
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testWrongTypeForDictionaryThrowsFormatException() public void testWrongTypeForDictionaryThrowsFormatException()
@@ -366,4 +507,81 @@ public class BdfListTest extends BrambleTestCase {
throws Exception { throws Exception {
BdfList.of(123).getOptionalDictionary(0); BdfList.of(123).getOptionalDictionary(0);
} }
@Test(expected = FormatException.class)
public void testWrongTypeForDefaultDictionaryThrowsFormatException()
throws Exception {
BdfList.of(123).getDictionary(0, new BdfDictionary());
}
@Test(expected = FormatException.class)
public void testNullValueForBooleanThrowsFormatException()
throws Exception {
BdfList.of(NULL_VALUE).getBoolean(0);
}
@Test(expected = FormatException.class)
public void testNullValueForLongThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getLong(0);
}
@Test(expected = FormatException.class)
public void testNullValueForIntThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getInt(0);
}
@Test(expected = FormatException.class)
public void testNullValueForDoubleThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getDouble(0);
}
@Test(expected = FormatException.class)
public void testNullValueForStringThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getString(0);
}
@Test(expected = FormatException.class)
public void testNullValueForRawThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getRaw(0);
}
@Test(expected = FormatException.class)
public void testNullValueForListThrowsFormatException() throws Exception {
BdfList.of(NULL_VALUE).getList(0);
}
@Test(expected = FormatException.class)
public void testNullValueForDictionaryThrowsFormatException()
throws Exception {
BdfList.of(NULL_VALUE).getDictionary(0);
}
@Test
public void testOptionalMethodsReturnNullForNullValue() throws Exception {
BdfList list = BdfList.of(NULL_VALUE);
assertNull(list.getOptionalBoolean(0));
assertNull(list.getOptionalLong(0));
assertNull(list.getOptionalInt(0));
assertNull(list.getOptionalDouble(0));
assertNull(list.getOptionalString(0));
assertNull(list.getOptionalRaw(0));
assertNull(list.getOptionalList(0));
assertNull(list.getOptionalDictionary(0));
}
@Test
public void testDefaultMethodsReturnDefaultForNullValue() throws Exception {
BdfList list = BdfList.of(NULL_VALUE);
assertEquals(TRUE, list.getBoolean(0, TRUE));
assertEquals(Long.valueOf(123L), list.getLong(0, 123L));
assertEquals(Integer.valueOf(123), list.getInt(0, 123));
assertEquals(Double.valueOf(123D), list.getDouble(0, 123D));
assertEquals("123", list.getString(0, "123"));
byte[] defaultRaw = {1, 2, 3};
assertArrayEquals(defaultRaw, list.getRaw(0, defaultRaw));
BdfList defaultList = BdfList.of(1, 2, 3);
assertEquals(defaultList, list.getList(0, defaultList));
BdfDictionary defaultDict = BdfDictionary.of(new BdfEntry("123", 123));
assertEquals(defaultDict, list.getDictionary(0, defaultDict));
}
} }

View File

@@ -155,7 +155,13 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList getMessageAsList(Transaction txn, MessageId m) public BdfList getMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException { throws DbException, FormatException {
return toList(db.getMessage(txn, m).getBody()); return getMessageAsList(txn, m, true);
}
@Override
public BdfList getMessageAsList(Transaction txn, MessageId m,
boolean canonical) throws DbException, FormatException {
return toList(db.getMessage(txn, m), canonical);
} }
@Override @Override
@@ -313,8 +319,13 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList toList(byte[] b, int off, int len) throws FormatException { public BdfList toList(byte[] b, int off, int len) throws FormatException {
return toList(b, off, len, true);
}
private BdfList toList(byte[] b, int off, int len, boolean canonical)
throws FormatException {
ByteArrayInputStream in = new ByteArrayInputStream(b, off, len); ByteArrayInputStream in = new ByteArrayInputStream(b, off, len);
BdfReader reader = bdfReaderFactory.createReader(in); BdfReader reader = bdfReaderFactory.createReader(in, canonical);
try { try {
BdfList list = reader.readList(); BdfList list = reader.readList();
if (!reader.eof()) throw new FormatException(); if (!reader.eof()) throw new FormatException();
@@ -328,7 +339,7 @@ class ClientHelperImpl implements ClientHelper {
@Override @Override
public BdfList toList(byte[] b) throws FormatException { public BdfList toList(byte[] b) throws FormatException {
return toList(b, 0, b.length); return toList(b, 0, b.length, true);
} }
@Override @Override
@@ -336,6 +347,12 @@ class ClientHelperImpl implements ClientHelper {
return toList(m.getBody()); return toList(m.getBody());
} }
@Override
public BdfList toList(Message m, boolean canonical) throws FormatException {
byte[] b = m.getBody();
return toList(b, 0, b.length, canonical);
}
@Override @Override
public BdfList toList(Author a) { public BdfList toList(Author a) {
return BdfList.of(a.getFormatVersion(), a.getName(), a.getPublicKey()); return BdfList.of(a.getFormatVersion(), a.getName(), a.getPublicKey());
@@ -361,7 +378,7 @@ class ClientHelperImpl implements ClientHelper {
public Author parseAndValidateAuthor(BdfList author) public Author parseAndValidateAuthor(BdfList author)
throws FormatException { throws FormatException {
checkSize(author, 3); checkSize(author, 3);
int formatVersion = author.getLong(0).intValue(); int formatVersion = author.getInt(0);
if (formatVersion != FORMAT_VERSION) throw new FormatException(); if (formatVersion != FORMAT_VERSION) throw new FormatException();
String name = author.getString(1); String name = author.getString(1);
checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH); checkLength(name, 1, MAX_AUTHOR_NAME_LENGTH);
@@ -472,8 +489,7 @@ class ClientHelperImpl implements ClientHelper {
if (element.size() != 2) { if (element.size() != 2) {
throw new FormatException(); throw new FormatException();
} }
list.add(new MailboxVersion(element.getLong(0).intValue(), list.add(new MailboxVersion(element.getInt(0), element.getInt(1)));
element.getLong(1).intValue()));
} }
// Sort the list of versions for easier comparison // Sort the list of versions for easier comparison
sort(list); sort(list);
@@ -486,7 +502,7 @@ class ClientHelperImpl implements ClientHelper {
try { try {
BdfDictionary meta = BdfDictionary meta =
getGroupMetadataAsDictionary(txn, contactGroupId); getGroupMetadataAsDictionary(txn, contactGroupId);
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); return new ContactId(meta.getInt(GROUP_KEY_CONTACT_ID));
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); // Invalid group metadata throw new DbException(e); // Invalid group metadata
} }

View File

@@ -18,12 +18,18 @@ class BdfReaderFactoryImpl implements BdfReaderFactory {
@Override @Override
public BdfReader createReader(InputStream in) { public BdfReader createReader(InputStream in) {
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE); DEFAULT_MAX_BUFFER_SIZE, true);
}
@Override
public BdfReader createReader(InputStream in, boolean canonical) {
return new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE, canonical);
} }
@Override @Override
public BdfReader createReader(InputStream in, int nestedLimit, public BdfReader createReader(InputStream in, int nestedLimit,
int maxBufferSize) { int maxBufferSize, boolean canonical) {
return new BdfReaderImpl(in, nestedLimit, maxBufferSize); return new BdfReaderImpl(in, nestedLimit, maxBufferSize, canonical);
} }
} }

View File

@@ -33,21 +33,24 @@ import static org.briarproject.bramble.util.StringUtils.fromUtf8;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
class BdfReaderImpl implements BdfReader { final class BdfReaderImpl implements BdfReader {
private static final byte[] EMPTY_BUFFER = new byte[0]; private static final byte[] EMPTY_BUFFER = new byte[0];
private final InputStream in; private final InputStream in;
private final int nestedLimit, maxBufferSize; private final int nestedLimit, maxBufferSize;
private final boolean canonical;
private boolean hasLookahead = false, eof = false; private boolean hasLookahead = false, eof = false;
private byte next; private byte next;
private byte[] buf = new byte[8]; private byte[] buf = new byte[8];
BdfReaderImpl(InputStream in, int nestedLimit, int maxBufferSize) { BdfReaderImpl(InputStream in, int nestedLimit, int maxBufferSize,
boolean canonical) {
this.in = in; this.in = in;
this.nestedLimit = nestedLimit; this.nestedLimit = nestedLimit;
this.maxBufferSize = maxBufferSize; this.maxBufferSize = maxBufferSize;
this.canonical = canonical;
} }
private void readLookahead() throws IOException { private void readLookahead() throws IOException {
@@ -188,13 +191,22 @@ class BdfReaderImpl implements BdfReader {
private short readInt16() throws IOException { private short readInt16() throws IOException {
readIntoBuffer(2); readIntoBuffer(2);
return (short) (((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF)); short value = (short) (((buf[0] & 0xFF) << 8) + (buf[1] & 0xFF));
if (canonical && value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
// Value could have been encoded as an INT_8
throw new FormatException();
}
return value;
} }
private int readInt32() throws IOException { private int readInt32() throws IOException {
readIntoBuffer(4); readIntoBuffer(4);
int value = 0; int value = 0;
for (int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8); for (int i = 0; i < 4; i++) value |= (buf[i] & 0xFF) << (24 - i * 8);
if (canonical && value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
// Value could have been encoded as an INT_16
throw new FormatException();
}
return value; return value;
} }
@@ -202,6 +214,11 @@ class BdfReaderImpl implements BdfReader {
readIntoBuffer(8); readIntoBuffer(8);
long value = 0; long value = 0;
for (int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8); for (int i = 0; i < 8; i++) value |= (buf[i] & 0xFFL) << (56 - i * 8);
if (canonical && value >= Integer.MIN_VALUE &&
value <= Integer.MAX_VALUE) {
// Value could have been encoded as an INT_32
throw new FormatException();
}
return value; return value;
} }
@@ -215,6 +232,31 @@ class BdfReaderImpl implements BdfReader {
hasLookahead = false; hasLookahead = false;
} }
@Override
public boolean hasInt() throws IOException {
if (!hasLookahead) readLookahead();
if (eof) return false;
return next == INT_8 || next == INT_16 || next == INT_32;
}
@Override
public int readInt() throws IOException {
if (!hasInt()) throw new FormatException();
hasLookahead = false;
if (next == INT_8) return readInt8();
if (next == INT_16) return readInt16();
return readInt32();
}
@Override
public void skipInt() throws IOException {
if (!hasInt()) throw new FormatException();
if (next == INT_8) skip(1);
else if (next == INT_16) skip(2);
else skip(4);
hasLookahead = false;
}
@Override @Override
public boolean hasDouble() throws IOException { public boolean hasDouble() throws IOException {
if (!hasLookahead) readLookahead(); if (!hasLookahead) readLookahead();
@@ -323,22 +365,11 @@ class BdfReaderImpl implements BdfReader {
private BdfList readList(int level) throws IOException { private BdfList readList(int level) throws IOException {
if (!hasList()) throw new FormatException(); if (!hasList()) throw new FormatException();
if (level > nestedLimit) throw new FormatException(); if (level > nestedLimit) throw new FormatException();
BdfList list = new BdfList();
readListStart();
while (!hasListEnd()) list.add(readObject(level + 1));
readListEnd();
return list;
}
@Override
public void readListStart() throws IOException {
if (!hasList()) throw new FormatException();
hasLookahead = false; hasLookahead = false;
} BdfList list = new BdfList();
while (!hasEnd()) list.add(readObject(level + 1));
@Override readEnd();
public boolean hasListEnd() throws IOException { return list;
return hasEnd();
} }
private boolean hasEnd() throws IOException { private boolean hasEnd() throws IOException {
@@ -347,11 +378,6 @@ class BdfReaderImpl implements BdfReader {
return next == END; return next == END;
} }
@Override
public void readListEnd() throws IOException {
readEnd();
}
private void readEnd() throws IOException { private void readEnd() throws IOException {
if (!hasEnd()) throw new FormatException(); if (!hasEnd()) throw new FormatException();
hasLookahead = false; hasLookahead = false;
@@ -361,7 +387,7 @@ class BdfReaderImpl implements BdfReader {
public void skipList() throws IOException { public void skipList() throws IOException {
if (!hasList()) throw new FormatException(); if (!hasList()) throw new FormatException();
hasLookahead = false; hasLookahead = false;
while (!hasListEnd()) skipObject(); while (!hasEnd()) skipObject();
hasLookahead = false; hasLookahead = false;
} }
@@ -380,35 +406,27 @@ class BdfReaderImpl implements BdfReader {
private BdfDictionary readDictionary(int level) throws IOException { private BdfDictionary readDictionary(int level) throws IOException {
if (!hasDictionary()) throw new FormatException(); if (!hasDictionary()) throw new FormatException();
if (level > nestedLimit) throw new FormatException(); if (level > nestedLimit) throw new FormatException();
BdfDictionary dictionary = new BdfDictionary();
readDictionaryStart();
while (!hasDictionaryEnd())
dictionary.put(readString(), readObject(level + 1));
readDictionaryEnd();
return dictionary;
}
@Override
public void readDictionaryStart() throws IOException {
if (!hasDictionary()) throw new FormatException();
hasLookahead = false; hasLookahead = false;
} BdfDictionary dictionary = new BdfDictionary();
String prevKey = null;
@Override while (!hasEnd()) {
public boolean hasDictionaryEnd() throws IOException { String key = readString();
return hasEnd(); if (canonical && prevKey != null && key.compareTo(prevKey) <= 0) {
} // Keys not unique and sorted
throw new FormatException();
@Override }
public void readDictionaryEnd() throws IOException { dictionary.put(key, readObject(level + 1));
prevKey = key;
}
readEnd(); readEnd();
return dictionary;
} }
@Override @Override
public void skipDictionary() throws IOException { public void skipDictionary() throws IOException {
if (!hasDictionary()) throw new FormatException(); if (!hasDictionary()) throw new FormatException();
hasLookahead = false; hasLookahead = false;
while (!hasDictionaryEnd()) { while (!hasEnd()) {
skipString(); skipString();
skipObject(); skipObject();
} }

View File

@@ -2,11 +2,13 @@ package org.briarproject.bramble.data;
import org.briarproject.bramble.api.Bytes; import org.briarproject.bramble.api.Bytes;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfWriter; import org.briarproject.bramble.api.data.BdfWriter;
import org.briarproject.nullsafety.NotNullByDefault; import org.briarproject.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -15,6 +17,7 @@ import java.util.Map.Entry;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.NotThreadSafe;
import static java.util.Collections.sort;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.bramble.data.Types.DICTIONARY; import static org.briarproject.bramble.data.Types.DICTIONARY;
import static org.briarproject.bramble.data.Types.END; import static org.briarproject.bramble.data.Types.END;
@@ -33,10 +36,11 @@ import static org.briarproject.bramble.data.Types.STRING_16;
import static org.briarproject.bramble.data.Types.STRING_32; import static org.briarproject.bramble.data.Types.STRING_32;
import static org.briarproject.bramble.data.Types.STRING_8; import static org.briarproject.bramble.data.Types.STRING_8;
import static org.briarproject.bramble.data.Types.TRUE; import static org.briarproject.bramble.data.Types.TRUE;
import static org.briarproject.bramble.util.StringUtils.UTF_8;
@NotThreadSafe @NotThreadSafe
@NotNullByDefault @NotNullByDefault
class BdfWriterImpl implements BdfWriter { final class BdfWriterImpl implements BdfWriter {
private final OutputStream out; private final OutputStream out;
@@ -113,7 +117,7 @@ class BdfWriterImpl implements BdfWriter {
@Override @Override
public void writeString(String s) throws IOException { public void writeString(String s) throws IOException {
byte[] b = s.getBytes("UTF-8"); byte[] b = s.getBytes(UTF_8);
if (b.length <= Byte.MAX_VALUE) { if (b.length <= Byte.MAX_VALUE) {
out.write(STRING_8); out.write(STRING_8);
out.write((byte) b.length); out.write((byte) b.length);
@@ -161,39 +165,33 @@ class BdfWriterImpl implements BdfWriter {
else if (o instanceof String) writeString((String) o); else if (o instanceof String) writeString((String) o);
else if (o instanceof byte[]) writeRaw((byte[]) o); else if (o instanceof byte[]) writeRaw((byte[]) o);
else if (o instanceof Bytes) writeRaw(((Bytes) o).getBytes()); else if (o instanceof Bytes) writeRaw(((Bytes) o).getBytes());
else if (o instanceof List) writeList((List) o); else if (o instanceof List) writeList((List<?>) o);
else if (o instanceof Map) writeDictionary((Map) o); else if (o instanceof Map) writeDictionary((Map<?, ?>) o);
else throw new FormatException(); else throw new FormatException();
} }
@Override
public void writeListStart() throws IOException {
out.write(LIST);
}
@Override
public void writeListEnd() throws IOException {
out.write(END);
}
@Override @Override
public void writeDictionary(Map<?, ?> m) throws IOException { public void writeDictionary(Map<?, ?> m) throws IOException {
out.write(DICTIONARY); out.write(DICTIONARY);
for (Entry<?, ?> e : m.entrySet()) { if (m instanceof BdfDictionary) {
if (!(e.getKey() instanceof String)) throw new FormatException(); // Entries are already sorted and keys are known to be strings
writeString((String) e.getKey()); for (Entry<String, Object> e : ((BdfDictionary) m).entrySet()) {
writeObject(e.getValue()); writeString(e.getKey());
writeObject(e.getValue());
}
} else {
// Check that keys are strings, write entries in canonical order
List<String> keys = new ArrayList<>(m.size());
for (Object k : m.keySet()) {
if (!(k instanceof String)) throw new FormatException();
keys.add((String) k);
}
sort(keys);
for (String key : keys) {
writeString(key);
writeObject(m.get(key));
}
} }
out.write(END); out.write(END);
} }
@Override
public void writeDictionaryStart() throws IOException {
out.write(DICTIONARY);
}
@Override
public void writeDictionaryEnd() throws IOException {
out.write(END);
}
} }

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.keyagreement; package org.briarproject.bramble.keyagreement;
import org.briarproject.bramble.api.data.BdfList;
import org.briarproject.bramble.api.data.BdfWriter; import org.briarproject.bramble.api.data.BdfWriter;
import org.briarproject.bramble.api.data.BdfWriterFactory; import org.briarproject.bramble.api.data.BdfWriterFactory;
import org.briarproject.bramble.api.keyagreement.Payload; import org.briarproject.bramble.api.keyagreement.Payload;
@@ -32,13 +33,14 @@ class PayloadEncoderImpl implements PayloadEncoder {
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
int formatIdAndVersion = (QR_FORMAT_ID << 5) | QR_FORMAT_VERSION; int formatIdAndVersion = (QR_FORMAT_ID << 5) | QR_FORMAT_VERSION;
out.write(formatIdAndVersion); out.write(formatIdAndVersion);
BdfList payload = new BdfList();
payload.add(p.getCommitment());
for (TransportDescriptor d : p.getTransportDescriptors()) {
payload.add(d.getDescriptor());
}
BdfWriter w = bdfWriterFactory.createWriter(out); BdfWriter w = bdfWriterFactory.createWriter(out);
try { try {
w.writeListStart(); // Payload start w.writeList(payload);
w.writeRaw(p.getCommitment());
for (TransportDescriptor d : p.getTransportDescriptors())
w.writeList(d.getDescriptor());
w.writeListEnd(); // Payload end
} catch (IOException e) { } catch (IOException e) {
// Shouldn't happen with ByteArrayOutputStream // Shouldn't happen with ByteArrayOutputStream
throw new AssertionError(e); throw new AssertionError(e);

View File

@@ -73,7 +73,7 @@ class PayloadParserImpl implements PayloadParser {
List<TransportDescriptor> recognised = new ArrayList<>(); List<TransportDescriptor> recognised = new ArrayList<>();
for (int i = 1; i < payload.size(); i++) { for (int i = 1; i < payload.size(); i++) {
BdfList descriptor = payload.getList(i); BdfList descriptor = payload.getList(i);
long transportId = descriptor.getLong(0); int transportId = descriptor.getInt(0);
if (transportId == TRANSPORT_ID_BLUETOOTH) { if (transportId == TRANSPORT_ID_BLUETOOTH) {
TransportId id = BluetoothConstants.ID; TransportId id = BluetoothConstants.ID;
recognised.add(new TransportDescriptor(id, descriptor)); recognised.add(new TransportDescriptor(id, descriptor));

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.mailbox; package org.briarproject.bramble.mailbox;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
@@ -11,12 +12,15 @@ import org.briarproject.bramble.api.mailbox.MailboxSettingsManager;
import org.briarproject.bramble.api.mailbox.MailboxStatus; import org.briarproject.bramble.api.mailbox.MailboxStatus;
import org.briarproject.bramble.api.mailbox.MailboxVersion; import org.briarproject.bramble.api.mailbox.MailboxVersion;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.util.Base32;
import org.briarproject.nullsafety.NotNullByDefault; import org.briarproject.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.GuardedBy;
@@ -26,6 +30,7 @@ import javax.inject.Inject;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
@@ -98,6 +103,22 @@ class MailboxManagerImpl implements MailboxManager {
return created; return created;
} }
@Override
public String convertBase32Payload(String base32Payload)
throws FormatException {
Pattern regex = Pattern.compile("(briar-mailbox://)?([a-z2-7]{104})");
Matcher matcher = regex.matcher(base32Payload);
if (!matcher.find()) throw new FormatException();
String base32 = matcher.group(2);
byte[] payloadBytes;
try {
payloadBytes = Base32.decode(base32, false);
} catch (IllegalArgumentException e) {
throw new FormatException();
}
return new String(payloadBytes, ISO_8859_1);
}
@Override @Override
public boolean checkConnection() { public boolean checkConnection() {
List<MailboxVersion> versions = null; List<MailboxVersion> versions = null;

View File

@@ -419,7 +419,7 @@ class LanTcpPlugin extends TcpPlugin {
private InetSocketAddress parseSocketAddress(BdfList descriptor) private InetSocketAddress parseSocketAddress(BdfList descriptor)
throws FormatException { throws FormatException {
byte[] address = descriptor.getRaw(1); byte[] address = descriptor.getRaw(1);
int port = descriptor.getLong(2).intValue(); int port = descriptor.getInt(2);
if (port < 1 || port > MAX_16_BIT_UNSIGNED) throw new FormatException(); if (port < 1 || port > MAX_16_BIT_UNSIGNED) throw new FormatException();
try { try {
InetAddress addr = InetAddress.getByAddress(address); InetAddress addr = InetAddress.getByAddress(address);

View File

@@ -201,7 +201,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) { for (Entry<TransportId, LatestUpdate> e : latest.entrySet()) {
BdfList message = clientHelper.getMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
e.getValue().messageId); e.getValue().messageId, false);
local.put(e.getKey(), parseProperties(message)); local.put(e.getKey(), parseProperties(message));
} }
return local; return local;
@@ -222,7 +222,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
if (latest != null) { if (latest != null) {
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
BdfList message = clientHelper.getMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId); latest.messageId, false);
p = parseProperties(message); p = parseProperties(message);
} }
return p == null ? new TransportProperties() : p; return p == null ? new TransportProperties() : p;
@@ -252,7 +252,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
local = new TransportProperties(); local = new TransportProperties();
} else { } else {
BdfList message = clientHelper.getMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId); latest.messageId, false);
local = parseProperties(message); local = parseProperties(message);
} }
storeLocalProperties(txn, c, t, local); storeLocalProperties(txn, c, t, local);
@@ -272,8 +272,8 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
remote = new TransportProperties(); remote = new TransportProperties();
} else { } else {
// Retrieve and parse the latest remote properties // Retrieve and parse the latest remote properties
BdfList message = BdfList message = clientHelper.getMessageAsList(txn,
clientHelper.getMessageAsList(txn, latest.messageId); latest.messageId, false);
remote = parseProperties(message); remote = parseProperties(message);
} }
// Merge in any discovered properties // Merge in any discovered properties
@@ -317,7 +317,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
changed = true; changed = true;
} else { } else {
BdfList message = clientHelper.getMessageAsList(txn, BdfList message = clientHelper.getMessageAsList(txn,
latest.messageId); latest.messageId, false);
TransportProperties old = parseProperties(message); TransportProperties old = parseProperties(message);
merged = new TransportProperties(old); merged = new TransportProperties(old);
for (Entry<String, String> e : p.entrySet()) { for (Entry<String, String> e : p.entrySet()) {

View File

@@ -27,7 +27,10 @@ class TransportPropertyValidator extends BdfMessageValidator {
TransportPropertyValidator(ClientHelper clientHelper, TransportPropertyValidator(ClientHelper clientHelper,
MetadataEncoder metadataEncoder, Clock clock) { MetadataEncoder metadataEncoder, Clock clock) {
super(clientHelper, metadataEncoder, clock); // Accept transport properties in non-canonical form
// TODO: Remove this after a reasonable migration period
// (added 2023-02-17)
super(clientHelper, metadataEncoder, clock, false);
} }
@Override @Override

View File

@@ -30,6 +30,7 @@ import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY; import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY;
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST; import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS; import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES; import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES;
@@ -126,6 +127,8 @@ class SyncRecordReaderImpl implements SyncRecordReader {
byte[] payload = nextRecord.getPayload(); byte[] payload = nextRecord.getPayload();
if (payload.length <= MESSAGE_HEADER_LENGTH) if (payload.length <= MESSAGE_HEADER_LENGTH)
throw new FormatException(); throw new FormatException();
if (payload.length > MAX_MESSAGE_LENGTH)
throw new FormatException();
// Validate timestamp // Validate timestamp
long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH); long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH);
if (timestamp < 0) throw new FormatException(); if (timestamp < 0) throw new FormatException();

View File

@@ -32,8 +32,7 @@ class SessionParserImpl implements SessionParser {
@Override @Override
public Session parseSession(BdfDictionary meta) throws FormatException { public Session parseSession(BdfDictionary meta) throws FormatException {
State state = State state = State.fromValue(meta.getInt(SESSION_KEY_STATE));
State.fromValue(meta.getLong(SESSION_KEY_STATE).intValue());
MessageId lastLocalMessageId = null; MessageId lastLocalMessageId = null;
byte[] lastLocalMessageIdBytes = byte[] lastLocalMessageIdBytes =
@@ -56,9 +55,9 @@ class SessionParserImpl implements SessionParser {
Long localTimestamp = meta.getOptionalLong(SESSION_KEY_LOCAL_TIMESTAMP); Long localTimestamp = meta.getOptionalLong(SESSION_KEY_LOCAL_TIMESTAMP);
KeySetId keySetId = null; KeySetId keySetId = null;
Long keySetIdLong = meta.getOptionalLong(SESSION_KEY_KEY_SET_ID); Integer keySetIdInt = meta.getOptionalInt(SESSION_KEY_KEY_SET_ID);
if (keySetIdLong != null) { if (keySetIdInt != null) {
keySetId = new KeySetId(keySetIdLong.intValue()); keySetId = new KeySetId(keySetIdInt);
} }
return new Session(state, lastLocalMessageId, localKeyPair, return new Session(state, lastLocalMessageId, localKeyPair,

View File

@@ -177,8 +177,8 @@ class TransportKeyAgreementManagerImpl extends BdfIncomingMessageHook
protected DeliveryAction incomingMessage(Transaction txn, Message m, protected DeliveryAction incomingMessage(Transaction txn, Message m,
BdfList body, BdfDictionary meta) BdfList body, BdfDictionary meta)
throws DbException, FormatException { throws DbException, FormatException {
MessageType type = MessageType.fromValue( MessageType type =
meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue()); MessageType.fromValue(meta.getInt(MSG_KEY_MESSAGE_TYPE));
TransportId t = new TransportId(meta.getString(MSG_KEY_TRANSPORT_ID)); TransportId t = new TransportId(meta.getString(MSG_KEY_TRANSPORT_ID));
if (LOG.isLoggable(INFO)) { if (LOG.isLoggable(INFO)) {
LOG.info("Received " + type + " message for " + t); LOG.info("Received " + type + " message for " + t);

View File

@@ -42,7 +42,7 @@ class TransportKeyAgreementValidator extends BdfMessageValidator {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException { BdfList body) throws FormatException {
MessageType type = MessageType.fromValue(body.getLong(0).intValue()); MessageType type = MessageType.fromValue(body.getInt(0));
if (type == KEY) return validateKeyMessage(m.getTimestamp(), body); if (type == KEY) return validateKeyMessage(m.getTimestamp(), body);
else if (type == ACTIVATE) return validateActivateMessage(body); else if (type == ACTIVATE) return validateActivateMessage(body);
else throw new AssertionError(); else throw new AssertionError();

View File

@@ -301,8 +301,8 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
BdfList cv = body.getList(i); BdfList cv = body.getList(i);
ClientId clientId = new ClientId(cv.getString(0)); ClientId clientId = new ClientId(cv.getString(0));
int majorVersion = cv.getLong(1).intValue(); int majorVersion = cv.getInt(1);
int minorVersion = cv.getLong(2).intValue(); int minorVersion = cv.getInt(2);
parsed.add(new ClientVersion(clientId, majorVersion, minorVersion)); parsed.add(new ClientVersion(clientId, majorVersion, minorVersion));
} }
return parsed; return parsed;
@@ -408,8 +408,8 @@ class ClientVersioningManagerImpl implements ClientVersioningManager,
throws FormatException { throws FormatException {
// Client ID, major version, minor version, active // Client ID, major version, minor version, active
ClientId clientId = new ClientId(clientState.getString(0)); ClientId clientId = new ClientId(clientState.getString(0));
int majorVersion = clientState.getLong(1).intValue(); int majorVersion = clientState.getInt(1);
int minorVersion = clientState.getLong(2).intValue(); int minorVersion = clientState.getInt(2);
boolean active = clientState.getBoolean(3); boolean active = clientState.getBoolean(3);
return new ClientState(clientId, majorVersion, minorVersion, active); return new ClientState(clientId, majorVersion, minorVersion, active);
} }

View File

@@ -43,9 +43,9 @@ class ClientVersioningValidator extends BdfMessageValidator {
checkSize(clientState, 4); checkSize(clientState, 4);
String clientId = clientState.getString(0); String clientId = clientState.getString(0);
checkLength(clientId, 1, MAX_CLIENT_ID_LENGTH); checkLength(clientId, 1, MAX_CLIENT_ID_LENGTH);
int majorVersion = clientState.getLong(1).intValue(); int majorVersion = clientState.getInt(1);
if (majorVersion < 0) throw new FormatException(); if (majorVersion < 0) throw new FormatException();
int minorVersion = clientState.getLong(2).intValue(); int minorVersion = clientState.getInt(2);
if (minorVersion < 0) throw new FormatException(); if (minorVersion < 0) throw new FormatException();
clientState.getBoolean(3); clientState.getBoolean(3);
} }

View File

@@ -56,7 +56,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE)); will(returnValue(timestamp - MAX_CLOCK_DIFFERENCE));
oneOf(clientHelper).toList(message.getBody()); oneOf(clientHelper).toList(message, true);
will(returnValue(body)); will(returnValue(body));
oneOf(metadataEncoder).encode(dictionary); oneOf(metadataEncoder).encode(dictionary);
will(returnValue(meta)); will(returnValue(meta));
@@ -86,7 +86,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp)); will(returnValue(timestamp));
oneOf(clientHelper).toList(shortMessage.getBody()); oneOf(clientHelper).toList(shortMessage, true);
will(returnValue(body)); will(returnValue(body));
oneOf(metadataEncoder).encode(dictionary); oneOf(metadataEncoder).encode(dictionary);
will(returnValue(meta)); will(returnValue(meta));
@@ -114,7 +114,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp)); will(returnValue(timestamp));
oneOf(clientHelper).toList(message.getBody()); oneOf(clientHelper).toList(message, true);
will(throwException(new FormatException())); will(throwException(new FormatException()));
}}); }});
@@ -126,7 +126,7 @@ public class BdfMessageValidatorTest extends ValidatorTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(clock).currentTimeMillis(); oneOf(clock).currentTimeMillis();
will(returnValue(timestamp)); will(returnValue(timestamp));
oneOf(clientHelper).toList(message.getBody()); oneOf(clientHelper).toList(message, true);
will(returnValue(body)); will(returnValue(body));
}}); }});

View File

@@ -546,7 +546,7 @@ public class ClientHelperImplTest extends BrambleMockTestCase {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
oneOf(bdfReaderFactory) oneOf(bdfReaderFactory)
.createReader(with(any(InputStream.class))); .createReader(with(any(InputStream.class)), with(true));
will(returnValue(bdfReader)); will(returnValue(bdfReader));
oneOf(bdfReader).readList(); oneOf(bdfReader).readList();
will(returnValue(list)); will(returnValue(list));

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.data; package org.briarproject.bramble.data;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -31,11 +32,14 @@ public class BdfReaderImplFuzzingTest extends BrambleTestCase {
buf[1] = 0x14; // Length 20 bytes buf[1] = 0x14; // Length 20 bytes
in.reset(); in.reset();
BdfReaderImpl r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, BdfReaderImpl r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE); DEFAULT_MAX_BUFFER_SIZE, true);
int length = r.readString().length(); try {
assertTrue(length >= 0); int length = r.readString().length();
assertTrue(length <= 20); assertTrue(length <= 20);
assertTrue(r.eof()); assertTrue(r.eof());
} catch (FormatException e) {
// Expected when bytes are not valid UTF-8
}
} }
} }
} }

View File

@@ -11,6 +11,7 @@ import java.io.ByteArrayInputStream;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE; import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT; import static org.briarproject.bramble.data.BdfReaderImpl.DEFAULT_NESTED_LIMIT;
import static org.briarproject.bramble.util.StringUtils.UTF_8;
import static org.briarproject.bramble.util.StringUtils.fromHexString; import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.bramble.util.StringUtils.getRandomString;
import static org.briarproject.bramble.util.StringUtils.toHexString; import static org.briarproject.bramble.util.StringUtils.toHexString;
@@ -88,6 +89,18 @@ public class BdfReaderImplTest extends BrambleTestCase {
assertTrue(r.eof()); assertTrue(r.eof());
} }
@Test(expected = FormatException.class)
public void testReadLong16CouldHaveBeenLong8Max() throws Exception {
setContents("22" + "007F");
r.readLong();
}
@Test(expected = FormatException.class)
public void testReadLong16CouldHaveBeenLong8Min() throws Exception {
setContents("22" + "FF80");
r.readLong();
}
@Test @Test
public void testSkipLong16() throws Exception { public void testSkipLong16() throws Exception {
setContents("22" + "0080"); setContents("22" + "0080");
@@ -106,6 +119,18 @@ public class BdfReaderImplTest extends BrambleTestCase {
assertTrue(r.eof()); assertTrue(r.eof());
} }
@Test(expected = FormatException.class)
public void testReadLong32CouldHaveBeenLong16Max() throws Exception {
setContents("24" + "00007FFF");
r.readLong();
}
@Test(expected = FormatException.class)
public void testReadLong32CouldHaveBeenLong16Min() throws Exception {
setContents("24" + "FFFF8000");
r.readLong();
}
@Test @Test
public void testSkipLong32() throws Exception { public void testSkipLong32() throws Exception {
setContents("24" + "00008000"); setContents("24" + "00008000");
@@ -124,13 +149,48 @@ public class BdfReaderImplTest extends BrambleTestCase {
assertTrue(r.eof()); assertTrue(r.eof());
} }
@Test(expected = FormatException.class)
public void testReadLong64CouldHaveBeenLong32Max() throws Exception {
setContents("28" + "000000007FFFFFFF");
r.readLong();
}
@Test(expected = FormatException.class)
public void testReadLong64CouldHaveBeenLong32Min() throws Exception {
setContents("28" + "FFFFFFFF80000000");
r.readLong();
}
@Test @Test
public void testSkipLong() throws Exception { public void testSkipLong64() throws Exception {
setContents("28" + "0000000080000000"); setContents("28" + "0000000080000000");
r.skipLong(); r.skipLong();
assertTrue(r.eof()); assertTrue(r.eof());
} }
@Test
public void testReadInt() throws Exception {
setContents("21" + "7F" + "21" + "80"
+ "22" + "7FFF" + "22" + "8000"
+ "24" + "7FFFFFFF" + "24" + "80000000");
assertEquals(Byte.MAX_VALUE, r.readInt());
assertEquals(Byte.MIN_VALUE, r.readInt());
assertEquals(Short.MAX_VALUE, r.readInt());
assertEquals(Short.MIN_VALUE, r.readInt());
assertEquals(Integer.MAX_VALUE, r.readInt());
assertEquals(Integer.MIN_VALUE, r.readInt());
assertTrue(r.eof());
}
@Test
public void testSkipInt() throws Exception {
setContents("21" + "7F" + "22" + "7FFF" + "24" + "7FFFFFFF");
r.skipInt();
r.skipInt();
r.skipInt();
assertTrue(r.eof());
}
@Test @Test
public void testReadDouble() throws Exception { public void testReadDouble() throws Exception {
// http://babbage.cs.qc.edu/IEEE-754/Decimal.html // http://babbage.cs.qc.edu/IEEE-754/Decimal.html
@@ -162,7 +222,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testReadString8() throws Exception { public void testReadString8() throws Exception {
String longest = getRandomString(Byte.MAX_VALUE); String longest = getRandomString(Byte.MAX_VALUE);
String longHex = toHexString(longest.getBytes("UTF-8")); String longHex = toHexString(longest.getBytes(UTF_8));
// "foo", the empty string, and 127 random letters // "foo", the empty string, and 127 random letters
setContents("41" + "03" + "666F6F" + "41" + "00" + setContents("41" + "03" + "666F6F" + "41" + "00" +
"41" + "7F" + longHex); "41" + "7F" + longHex);
@@ -186,7 +246,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testSkipString8() throws Exception { public void testSkipString8() throws Exception {
String longest = getRandomString(Byte.MAX_VALUE); String longest = getRandomString(Byte.MAX_VALUE);
String longHex = toHexString(longest.getBytes("UTF-8")); String longHex = toHexString(longest.getBytes(UTF_8));
// "foo", the empty string, and 127 random letters // "foo", the empty string, and 127 random letters
setContents("41" + "03" + "666F6F" + "41" + "00" + setContents("41" + "03" + "666F6F" + "41" + "00" +
"41" + "7F" + longHex); "41" + "7F" + longHex);
@@ -199,9 +259,9 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testReadString16() throws Exception { public void testReadString16() throws Exception {
String shortest = getRandomString(Byte.MAX_VALUE + 1); String shortest = getRandomString(Byte.MAX_VALUE + 1);
String shortHex = toHexString(shortest.getBytes("UTF-8")); String shortHex = toHexString(shortest.getBytes(UTF_8));
String longest = getRandomString(Short.MAX_VALUE); String longest = getRandomString(Short.MAX_VALUE);
String longHex = toHexString(longest.getBytes("UTF-8")); String longHex = toHexString(longest.getBytes(UTF_8));
// 128 random letters and 2^15 -1 random letters // 128 random letters and 2^15 -1 random letters
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex); setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
assertEquals(shortest, r.readString()); assertEquals(shortest, r.readString());
@@ -213,7 +273,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
public void testReadString16ChecksMaxLength() throws Exception { public void testReadString16ChecksMaxLength() throws Exception {
int maxBufferSize = Byte.MAX_VALUE + 1; int maxBufferSize = Byte.MAX_VALUE + 1;
String valid = getRandomString(Byte.MAX_VALUE + 1); String valid = getRandomString(Byte.MAX_VALUE + 1);
String validHex = toHexString(valid.getBytes("UTF-8")); String validHex = toHexString(valid.getBytes(UTF_8));
String invalidhex = validHex + "20"; String invalidhex = validHex + "20";
// 128 random letters, the same plus a space // 128 random letters, the same plus a space
setContents("42" + "0080" + validHex setContents("42" + "0080" + validHex
@@ -223,12 +283,20 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readString(); r.readString();
} }
@Test(expected = FormatException.class)
public void testReadString16CouldHaveBeenString8() throws Exception {
String longest = getRandomString(Byte.MAX_VALUE);
String longHex = toHexString(longest.getBytes(UTF_8));
setContents("42" + "007F" + longHex);
r.readString();
}
@Test @Test
public void testSkipString16() throws Exception { public void testSkipString16() throws Exception {
String shortest = getRandomString(Byte.MAX_VALUE + 1); String shortest = getRandomString(Byte.MAX_VALUE + 1);
String shortHex = toHexString(shortest.getBytes("UTF-8")); String shortHex = toHexString(shortest.getBytes(UTF_8));
String longest = getRandomString(Short.MAX_VALUE); String longest = getRandomString(Short.MAX_VALUE);
String longHex = toHexString(longest.getBytes("UTF-8")); String longHex = toHexString(longest.getBytes(UTF_8));
// 128 random letters and 2^15 - 1 random letters // 128 random letters and 2^15 - 1 random letters
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex); setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
r.skipString(); r.skipString();
@@ -239,7 +307,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testReadString32() throws Exception { public void testReadString32() throws Exception {
String shortest = getRandomString(Short.MAX_VALUE + 1); String shortest = getRandomString(Short.MAX_VALUE + 1);
String shortHex = toHexString(shortest.getBytes("UTF-8")); String shortHex = toHexString(shortest.getBytes(UTF_8));
// 2^15 random letters // 2^15 random letters
setContents("44" + "00008000" + shortHex); setContents("44" + "00008000" + shortHex);
assertEquals(shortest, r.readString()); assertEquals(shortest, r.readString());
@@ -250,7 +318,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
public void testReadString32ChecksMaxLength() throws Exception { public void testReadString32ChecksMaxLength() throws Exception {
int maxBufferSize = Short.MAX_VALUE + 1; int maxBufferSize = Short.MAX_VALUE + 1;
String valid = getRandomString(maxBufferSize); String valid = getRandomString(maxBufferSize);
String validHex = toHexString(valid.getBytes("UTF-8")); String validHex = toHexString(valid.getBytes(UTF_8));
String invalidHex = validHex + "20"; String invalidHex = validHex + "20";
// 2^15 random letters, the same plus a space // 2^15 random letters, the same plus a space
setContents("44" + "00008000" + validHex + setContents("44" + "00008000" + validHex +
@@ -260,10 +328,18 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readString(); r.readString();
} }
@Test(expected = FormatException.class)
public void testReadString32CouldHaveBeenString16() throws Exception {
String longest = getRandomString(Short.MAX_VALUE);
String longHex = toHexString(longest.getBytes(UTF_8));
setContents("44" + "00007FFF" + longHex);
r.readString();
}
@Test @Test
public void testSkipString32() throws Exception { public void testSkipString32() throws Exception {
String shortest = getRandomString(Short.MAX_VALUE + 1); String shortest = getRandomString(Short.MAX_VALUE + 1);
String shortHex = toHexString(shortest.getBytes("UTF-8")); String shortHex = toHexString(shortest.getBytes(UTF_8));
// 2^15 random letters, twice // 2^15 random letters, twice
setContents("44" + "00008000" + shortHex + setContents("44" + "00008000" + shortHex +
"44" + "00008000" + shortHex); "44" + "00008000" + shortHex);
@@ -275,7 +351,7 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testReadUtf8String() throws Exception { public void testReadUtf8String() throws Exception {
String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3"; String unicode = "\uFDD0\uFDD1\uFDD2\uFDD3";
String hex = toHexString(unicode.getBytes("UTF-8")); String hex = toHexString(unicode.getBytes(UTF_8));
// STRING_8 tag, "foo", the empty string, and the test string // STRING_8 tag, "foo", the empty string, and the test string
setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex); setContents("41" + "03" + "666F6F" + "41" + "00" + "41" + "0C" + hex);
assertEquals("foo", r.readString()); assertEquals("foo", r.readString());
@@ -348,6 +424,14 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readRaw(); r.readRaw();
} }
@Test(expected = FormatException.class)
public void testReadRaw16CouldHaveBeenRaw8() throws Exception {
byte[] longest = new byte[Byte.MAX_VALUE];
String longHex = toHexString(longest);
setContents("52" + "007F" + longHex);
r.readRaw();
}
@Test @Test
public void testSkipRaw16() throws Exception { public void testSkipRaw16() throws Exception {
byte[] shortest = new byte[Byte.MAX_VALUE + 1]; byte[] shortest = new byte[Byte.MAX_VALUE + 1];
@@ -385,6 +469,14 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readRaw(); r.readRaw();
} }
@Test(expected = FormatException.class)
public void testReadRaw32CouldHaveBeenRaw16() throws Exception {
byte[] longest = new byte[Short.MAX_VALUE];
String longHex = toHexString(longest);
setContents("54" + "00007FFF" + longHex);
r.readRaw();
}
@Test @Test
public void testSkipRaw32() throws Exception { public void testSkipRaw32() throws Exception {
byte[] shortest = new byte[Short.MAX_VALUE + 1]; byte[] shortest = new byte[Short.MAX_VALUE + 1];
@@ -434,25 +526,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readList(); r.readList();
} }
@Test
public void testReadListManually() throws Exception {
// A list containing 1, "foo", and null
setContents("60" + "21" + "01" +
"41" + "03" + "666F6F" +
"00" + "80");
r.readListStart();
assertFalse(r.hasListEnd());
assertEquals(1, r.readLong());
assertFalse(r.hasListEnd());
assertEquals("foo", r.readString());
assertFalse(r.hasListEnd());
assertTrue(r.hasNull());
r.readNull();
assertTrue(r.hasListEnd());
r.readListEnd();
assertTrue(r.eof());
}
@Test @Test
public void testSkipList() throws Exception { public void testSkipList() throws Exception {
// A list containing 1, "foo", and 128 // A list containing 1, "foo", and 128
@@ -465,9 +538,9 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testReadDictionary() throws Exception { public void testReadDictionary() throws Exception {
// A dictionary containing "foo" -> 123 and "bar" -> null // A dictionary containing "bar" -> null and "foo" -> 123
setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" + setContents("70" + "41" + "03" + "626172" + "00" +
"41" + "03" + "626172" + "00" + "80"); "41" + "03" + "666F6F" + "21" + "7B" + "80");
BdfDictionary dictionary = r.readDictionary(); BdfDictionary dictionary = r.readDictionary();
assertEquals(2, dictionary.size()); assertEquals(2, dictionary.size());
assertTrue(dictionary.containsKey("foo")); assertTrue(dictionary.containsKey("foo"));
@@ -517,26 +590,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
r.readDictionary(); r.readDictionary();
} }
@Test
public void testReadDictionaryManually() throws Exception {
// A dictionary containing "foo" -> 123 and "bar" -> null
setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" +
"41" + "03" + "626172" + "00" + "80");
r.readDictionaryStart();
assertFalse(r.hasDictionaryEnd());
assertEquals("foo", r.readString());
assertFalse(r.hasDictionaryEnd());
assertEquals(123, r.readLong());
assertFalse(r.hasDictionaryEnd());
assertEquals("bar", r.readString());
assertFalse(r.hasDictionaryEnd());
assertTrue(r.hasNull());
r.readNull();
assertTrue(r.hasDictionaryEnd());
r.readDictionaryEnd();
assertTrue(r.eof());
}
@Test @Test
public void testSkipDictionary() throws Exception { public void testSkipDictionary() throws Exception {
// A map containing "foo" -> 123 and "bar" -> null // A map containing "foo" -> 123 and "bar" -> null
@@ -557,10 +610,10 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test @Test
public void testNestedListWithinDepthLimit() throws Exception { public void testNestedListWithinDepthLimit() throws Exception {
// A list containing a list containing a list containing a list... // A list containing a list containing a list containing a list...
String lists = ""; StringBuilder lists = new StringBuilder();
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists += "60"; for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists.append("60");
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists += "80"; for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) lists.append("80");
setContents(lists); setContents(lists.toString());
r.readList(); r.readList();
assertTrue(r.eof()); assertTrue(r.eof());
} }
@@ -568,23 +621,25 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNestedListOutsideDepthLimit() throws Exception { public void testNestedListOutsideDepthLimit() throws Exception {
// A list containing a list containing a list containing a list... // A list containing a list containing a list containing a list...
String lists = ""; StringBuilder lists = new StringBuilder();
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists += "60"; for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists.append("60");
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists += "80"; for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) lists.append("80");
setContents(lists); setContents(lists.toString());
r.readList(); r.readList();
} }
@Test @Test
public void testNestedDictionaryWithinDepthLimit() throws Exception { public void testNestedDictionaryWithinDepthLimit() throws Exception {
// A dictionary containing a dictionary containing a dictionary... // A dictionary containing a dictionary containing a dictionary...
String dicts = ""; StringBuilder dicts = new StringBuilder();
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) {
dicts += "70" + "41" + "03" + "666F6F"; dicts.append("70").append("41").append("03").append("666F6F");
dicts += "11"; }
for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) dicts.append("11");
dicts += "80"; for (int i = 1; i <= DEFAULT_NESTED_LIMIT; i++) {
setContents(dicts); dicts.append("80");
}
setContents(dicts.toString());
r.readDictionary(); r.readDictionary();
assertTrue(r.eof()); assertTrue(r.eof());
} }
@@ -592,13 +647,15 @@ public class BdfReaderImplTest extends BrambleTestCase {
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testNestedDictionaryOutsideDepthLimit() throws Exception { public void testNestedDictionaryOutsideDepthLimit() throws Exception {
// A dictionary containing a dictionary containing a dictionary... // A dictionary containing a dictionary containing a dictionary...
String dicts = ""; StringBuilder dicts = new StringBuilder();
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) {
dicts += "70" + "41" + "03" + "666F6F"; dicts.append("70").append("41").append("03").append("666F6F");
dicts += "11"; }
for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) dicts.append("11");
dicts += "80"; for (int i = 1; i <= DEFAULT_NESTED_LIMIT + 1; i++) {
setContents(dicts); dicts.append("80");
}
setContents(dicts.toString());
r.readDictionary(); r.readDictionary();
} }
@@ -625,6 +682,6 @@ public class BdfReaderImplTest extends BrambleTestCase {
private void setContents(String hex, int maxBufferSize) private void setContents(String hex, int maxBufferSize)
throws FormatException { throws FormatException {
ByteArrayInputStream in = new ByteArrayInputStream(fromHexString(hex)); ByteArrayInputStream in = new ByteArrayInputStream(fromHexString(hex));
r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, maxBufferSize); r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT, maxBufferSize, true);
} }
} }

View File

@@ -0,0 +1,80 @@
package org.briarproject.bramble.data;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.data.BdfReader;
import org.briarproject.bramble.api.data.BdfWriter;
import org.briarproject.bramble.test.BrambleTestCase;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_MAX_BUFFER_SIZE;
import static org.briarproject.bramble.api.data.BdfReader.DEFAULT_NESTED_LIMIT;
import static org.briarproject.bramble.util.StringUtils.fromHexString;
import static org.briarproject.bramble.util.StringUtils.toHexString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class BdfReaderWriterIntegrationTest extends BrambleTestCase {
@Test
public void testConvertStringToCanonicalForm() throws Exception {
// 'foo' as a STRING_16 (not canonical, should be a STRING_8)
String hexIn = "42" + "0003" + "666F6F";
InputStream in = new ByteArrayInputStream(fromHexString(hexIn));
BdfReader r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE, false); // Accept non-canonical
String s = r.readString();
assertEquals("foo", s);
assertTrue(r.eof());
// Convert the string back to BDF
ByteArrayOutputStream out = new ByteArrayOutputStream();
BdfWriter w = new BdfWriterImpl(out);
w.writeString(s);
w.flush();
String hexOut = toHexString(out.toByteArray());
// The BDF should now be in canonical form
assertEquals("41" + "03" + "666F6F", hexOut);
}
@Test
public void testConvertDictionaryToCanonicalForm() throws Exception {
// A dictionary with keys in non-canonical order: 'foo' then 'bar'
String hexIn = "70" + "41" + "03" + "666F6F" + "21" + "01"
+ "41" + "03" + "626172" + "21" + "02" + "80";
InputStream in = new ByteArrayInputStream(fromHexString(hexIn));
BdfReader r = new BdfReaderImpl(in, DEFAULT_NESTED_LIMIT,
DEFAULT_MAX_BUFFER_SIZE, false); // Accept non-canonical
BdfDictionary d = r.readDictionary();
assertEquals(2, d.size());
assertTrue(r.eof());
// The entries should be returned in canonical order
Iterator<Entry<String, Object>> it = d.entrySet().iterator();
Entry<String, Object> first = it.next();
assertEquals("bar", first.getKey());
assertEquals(2L, first.getValue());
Entry<String, Object> second = it.next();
assertEquals("foo", second.getKey());
assertEquals(1L, second.getValue());
// Convert a non-canonical map to BDF (use LinkedHashMap so we know
// the entries will be iterated over in non-canonical order)
Map<String, Object> m = new LinkedHashMap<>();
m.put("foo", 1);
m.put("bar", 2);
ByteArrayOutputStream out = new ByteArrayOutputStream();
BdfWriter w = new BdfWriterImpl(out);
w.writeDictionary(m);
w.flush();
String hexOut = toHexString(out.toByteArray());
// The entries should be in canonical order: 'bar' then 'foo'
assertEquals("70" + "41" + "03" + "626172" + "21" + "02"
+ "41" + "03" + "666F6F" + "21" + "01" + "80", hexOut);
}
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.data; package org.briarproject.bramble.data;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.test.BrambleTestCase; import org.briarproject.bramble.test.BrambleTestCase;
import org.briarproject.bramble.util.StringUtils; import org.briarproject.bramble.util.StringUtils;
import org.junit.Test; import org.junit.Test;
@@ -168,9 +169,11 @@ public class BdfWriterImplTest extends BrambleTestCase {
@Test @Test
public void testWriteDictionary() throws IOException { public void testWriteDictionary() throws IOException {
// Use LinkedHashMap to get predictable iteration order // Add entries to dictionary in descending order - they should be
// output in ascending order. Use LinkedHashMap to get predictable
// iteration order
Map<String, Object> m = new LinkedHashMap<>(); Map<String, Object> m = new LinkedHashMap<>();
for (int i = 0; i < 4; i++) m.put(String.valueOf(i), i); for (int i = 3; i >= 0; i--) m.put(String.valueOf(i), i);
w.writeDictionary(m); w.writeDictionary(m);
// DICTIONARY tag, keys as strings and values as integers, END tag // DICTIONARY tag, keys as strings and values as integers, END tag
checkContents("70" + "41" + "01" + "30" + "21" + "00" + checkContents("70" + "41" + "01" + "30" + "21" + "00" +
@@ -180,30 +183,17 @@ public class BdfWriterImplTest extends BrambleTestCase {
} }
@Test @Test
public void testWriteDelimitedList() throws IOException { public void testWriteBdfDictionary() throws IOException {
w.writeListStart(); // Add entries to dictionary in descending order - they should be
w.writeLong(1); // output in ascending order
w.writeString("foo"); BdfDictionary d = new BdfDictionary();
w.writeLong(128); for (int i = 3; i >= 0; i--) d.put(String.valueOf(i), i);
w.writeListEnd(); w.writeDictionary(d);
// LIST tag, 1 as integer, "foo" as string, 128 as integer, END tag // DICTIONARY tag, keys as strings and values as integers, END tag
checkContents("60" + "21" + "01" + checkContents("70" + "41" + "01" + "30" + "21" + "00" +
"41" + "03" + "666F6F" + "41" + "01" + "31" + "21" + "01" +
"22" + "0080" + "80"); "41" + "01" + "32" + "21" + "02" +
} "41" + "01" + "33" + "21" + "03" + "80");
@Test
public void testWriteDelimitedDictionary() throws IOException {
w.writeDictionaryStart();
w.writeString("foo");
w.writeLong(123);
w.writeString("bar");
w.writeNull();
w.writeDictionaryEnd();
// DICTIONARY tag, "foo" as string, 123 as integer, "bar" as string,
// NULL tag, END tag
checkContents("70" + "41" + "03" + "666F6F" +
"21" + "7B" + "41" + "03" + "626172" + "00" + "80");
} }
@Test @Test

View File

@@ -1,5 +1,6 @@
package org.briarproject.bramble.mailbox; package org.briarproject.bramble.mailbox;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager; import org.briarproject.bramble.api.db.TransactionManager;
@@ -9,17 +10,23 @@ import org.briarproject.bramble.api.mailbox.event.OwnMailboxConnectionStatusEven
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations; import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.util.Base32;
import org.junit.Test; import org.junit.Test;
import java.io.IOException; import java.io.IOException;
import java.util.Locale;
import java.util.Random; import java.util.Random;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import static org.briarproject.bramble.util.StringUtils.ISO_8859_1;
import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS; import static org.briarproject.bramble.api.mailbox.MailboxConstants.CLIENT_SUPPORTS;
import static org.briarproject.bramble.test.TestUtils.getMailboxProperties; import static org.briarproject.bramble.test.TestUtils.getMailboxProperties;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
import static org.briarproject.bramble.test.TestUtils.hasEvent; import static org.briarproject.bramble.test.TestUtils.hasEvent;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class MailboxManagerImplTest extends BrambleMockTestCase { public class MailboxManagerImplTest extends BrambleMockTestCase {
@@ -125,4 +132,32 @@ public class MailboxManagerImplTest extends BrambleMockTestCase {
assertTrue(manager.checkConnection()); assertTrue(manager.checkConnection());
} }
@Test
public void testConvertBase32Payload() throws FormatException {
byte[] payload = getRandomBytes(65);
String base32payload = Base32.encode(payload).toLowerCase(Locale.ROOT);
String expected = new String(payload, ISO_8859_1);
try {
manager.convertBase32Payload("foo bar");
fail();
} catch (FormatException e) {
// expected
}
try { // doesn't work with shorter link
manager.convertBase32Payload("briar-mailbox://" +
base32payload.substring(0, base32payload.length() - 1));
fail();
} catch (FormatException e) {
// expected
}
// works with white-spaces
assertEquals(expected, manager.convertBase32Payload(
"foo bar briar-mailbox://" + base32payload + " foo bar"));
// even works without white-space at the end
assertEquals(expected, manager.convertBase32Payload(
"foo bar briar-mailbox://" + base32payload + "foobar"));
// even works without schema and extra chars at end
assertEquals(expected, manager.convertBase32Payload(
"foo bar " + base32payload + "foobar"));
}
} }

View File

@@ -217,13 +217,13 @@ public class LanTcpPluginTest extends BrambleTestCase {
// The plugin should have bound a socket and stored the port number // The plugin should have bound a socket and stored the port number
BdfList descriptor = kal.getDescriptor(); BdfList descriptor = kal.getDescriptor();
assertEquals(3, descriptor.size()); assertEquals(3, descriptor.size());
assertEquals(TRANSPORT_ID_LAN, descriptor.getLong(0).longValue()); assertEquals(TRANSPORT_ID_LAN, descriptor.getInt(0).intValue());
byte[] address = descriptor.getRaw(1); byte[] address = descriptor.getRaw(1);
InetAddress addr = InetAddress.getByAddress(address); InetAddress addr = InetAddress.getByAddress(address);
assertTrue(addr instanceof Inet4Address); assertTrue(addr instanceof Inet4Address);
assertFalse(addr.isLoopbackAddress()); assertFalse(addr.isLoopbackAddress());
assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress()); assertTrue(addr.isLinkLocalAddress() || addr.isSiteLocalAddress());
int port = descriptor.getLong(2).intValue(); int port = descriptor.getInt(2);
assertTrue(port > 0 && port < 65536); assertTrue(port > 0 && port < 65536);
// The plugin should be listening on the port // The plugin should be listening on the port
InetSocketAddress socketAddr = new InetSocketAddress(addr, port); InetSocketAddress socketAddr = new InetSocketAddress(addr, port);

View File

@@ -404,7 +404,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId); oneOf(clientHelper).getMessageAsList(txn, fooUpdateId, false);
will(returnValue(fooUpdate)); will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -471,7 +471,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup2.getId()); contactGroup2.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, fooUpdateId); oneOf(clientHelper).getMessageAsList(txn, fooUpdateId, false);
will(returnValue(fooUpdate)); will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -526,7 +526,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
contactGroup.getId()); contactGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, updateId); oneOf(clientHelper).getMessageAsList(txn, updateId, false);
will(returnValue(update)); will(returnValue(update));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -564,7 +564,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
oneOf(clientHelper).getMessageAsList(txn, updateId); oneOf(clientHelper).getMessageAsList(txn, updateId, false);
will(returnValue(update)); will(returnValue(update));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
@@ -695,7 +695,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(localGroupMessageMetadata)); will(returnValue(localGroupMessageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId); oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId,
false);
will(returnValue(oldUpdate)); will(returnValue(oldUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
oldPropertiesDict); oldPropertiesDict);
@@ -760,7 +761,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
oneOf(clientHelper).getMessageMetadataAsDictionary(txn, oneOf(clientHelper).getMessageMetadataAsDictionary(txn,
localGroup.getId()); localGroup.getId());
will(returnValue(localGroupMessageMetadata)); will(returnValue(localGroupMessageMetadata));
oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId); oneOf(clientHelper).getMessageAsList(txn, localGroupUpdateId,
false);
will(returnValue(oldUpdate)); will(returnValue(oldUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
oldPropertiesDict); oldPropertiesDict);
@@ -819,12 +821,12 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
localGroup.getId()); localGroup.getId());
will(returnValue(messageMetadata)); will(returnValue(messageMetadata));
// Retrieve and parse the latest local properties // Retrieve and parse the latest local properties
oneOf(clientHelper).getMessageAsList(txn, fooVersion999); oneOf(clientHelper).getMessageAsList(txn, fooVersion999, false);
will(returnValue(fooUpdate)); will(returnValue(fooUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
fooPropertiesDict); fooPropertiesDict);
will(returnValue(fooProperties)); will(returnValue(fooProperties));
oneOf(clientHelper).getMessageAsList(txn, barVersion3); oneOf(clientHelper).getMessageAsList(txn, barVersion3, false);
will(returnValue(barUpdate)); will(returnValue(barUpdate));
oneOf(clientHelper).parseAndValidateTransportProperties( oneOf(clientHelper).parseAndValidateTransportProperties(
barPropertiesDict); barPropertiesDict);

View File

@@ -6,13 +6,18 @@ import org.briarproject.bramble.api.UniqueId;
import org.briarproject.bramble.api.record.Record; import org.briarproject.bramble.api.record.Record;
import org.briarproject.bramble.api.record.RecordReader; import org.briarproject.bramble.api.record.RecordReader;
import org.briarproject.bramble.api.sync.Ack; import org.briarproject.bramble.api.sync.Ack;
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.MessageFactory;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.Offer; import org.briarproject.bramble.api.sync.Offer;
import org.briarproject.bramble.api.sync.Priority; import org.briarproject.bramble.api.sync.Priority;
import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.Request;
import org.briarproject.bramble.api.sync.SyncRecordReader; import org.briarproject.bramble.api.sync.SyncRecordReader;
import org.briarproject.bramble.api.sync.Versions; import org.briarproject.bramble.api.sync.Versions;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.PredicateMatcher;
import org.hamcrest.Matcher;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Test; import org.junit.Test;
@@ -23,12 +28,15 @@ import javax.annotation.Nullable;
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
import static org.briarproject.bramble.api.sync.RecordTypes.ACK; import static org.briarproject.bramble.api.sync.RecordTypes.ACK;
import static org.briarproject.bramble.api.sync.RecordTypes.MESSAGE;
import static org.briarproject.bramble.api.sync.RecordTypes.OFFER; import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY; import static org.briarproject.bramble.api.sync.RecordTypes.PRIORITY;
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST; import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS; import static org.briarproject.bramble.api.sync.RecordTypes.VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES; import static org.briarproject.bramble.api.sync.SyncConstants.PRIORITY_NONCE_BYTES;
import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION; import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
@@ -46,6 +54,38 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
private final SyncRecordReader reader = private final SyncRecordReader reader =
new SyncRecordReaderImpl(messageFactory, recordReader); new SyncRecordReaderImpl(messageFactory, recordReader);
@Test
public void testNoFormatExceptionIfMessageIsMinimumSize() throws Exception {
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH + 1));
expectCreateMessage(1);
reader.readMessage();
}
@Test(expected = FormatException.class)
public void testFormatExceptionIfMessageIsTooSmall() throws Exception {
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH));
reader.readMessage();
}
@Test
public void testNoFormatExceptionIfMessageIsMaximumSize() throws Exception {
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH
+ MAX_MESSAGE_BODY_LENGTH));
expectCreateMessage(MAX_MESSAGE_BODY_LENGTH);
reader.readMessage();
}
@Test(expected = FormatException.class)
public void testFormatExceptionIfMessageIsTooLarge() throws Exception {
expectReadRecord(createMessage(MESSAGE_HEADER_LENGTH
+ MAX_MESSAGE_BODY_LENGTH + 1));
reader.readMessage();
}
@Test @Test
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception { public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
expectReadRecord(createAck()); expectReadRecord(createAck());
@@ -158,6 +198,20 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
assertTrue(reader.eof()); assertTrue(reader.eof());
} }
private void expectCreateMessage(int bodyLength) {
MessageId messageId = new MessageId(getRandomId());
GroupId groupId = new GroupId(getRandomId());
long timestamp = System.currentTimeMillis();
context.checking(new Expectations() {{
Matcher<byte[]> matcher = new PredicateMatcher<>(byte[].class,
b -> b.length == MESSAGE_HEADER_LENGTH + bodyLength);
oneOf(messageFactory).createMessage(with(matcher));
will(returnValue(new Message(messageId, groupId, timestamp,
new byte[bodyLength])));
}});
}
private void expectReadRecord(@Nullable Record record) throws Exception { private void expectReadRecord(@Nullable Record record) throws Exception {
context.checking(new Expectations() {{ context.checking(new Expectations() {{
//noinspection unchecked //noinspection unchecked
@@ -167,6 +221,10 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
}}); }});
} }
private Record createMessage(int payloadLength) {
return new Record(PROTOCOL_VERSION, MESSAGE, new byte[payloadLength]);
}
private Record createAck() throws Exception { private Record createAck() throws Exception {
return new Record(PROTOCOL_VERSION, ACK, createPayload()); return new Record(PROTOCOL_VERSION, ACK, createPayload());
} }

View File

@@ -88,51 +88,58 @@ public class StringUtilsTest extends BrambleTestCase {
} }
@Test @Test
public void testFromUtf8AcceptsNullCharacterUsingStandardUtf8() { public void testFromUtf8AcceptsNullCharacterUsingStandardUtf8()
throws Exception {
// The UTF-8 encoding of the null character is valid // The UTF-8 encoding of the null character is valid
assertEquals("\u0000", StringUtils.fromUtf8(new byte[1])); byte[] utf8 = new byte[1];
String actual = StringUtils.fromUtf8(utf8);
assertEquals("\u0000", actual);
// When we convert back to UTF-8 we should get the original encoding
assertArrayEquals(utf8, StringUtils.toUtf8(actual));
} }
@Test @Test(expected = FormatException.class)
public void testFromUtf8RemovesNullCharacterUsingModifiedUtf8() { public void testFromUtf8RejectsNullCharacterUsingModifiedUtf8()
throws Exception {
// The modified UTF-8 encoding of the null character is not valid // The modified UTF-8 encoding of the null character is not valid
byte[] b = new byte[] { byte[] b = new byte[] {
(byte) 0xC0, (byte) 0x80, // Null character as modified UTF-8 (byte) 0xC0, (byte) 0x80, // Null character as modified UTF-8
(byte) 0xC8, (byte) 0x85 // U+0205 (byte) 0xC8, (byte) 0x85 // U+0205
}; };
// Conversion should ignore the invalid character and return the rest StringUtils.fromUtf8(b);
String expected = "\u0205";
assertEquals(expected, StringUtils.fromUtf8(b));
} }
@Test @Test
public void testFromUtf8AcceptsSupplementaryCharacterUsingStandardUtf8() { public void testFromUtf8AcceptsSupplementaryCharacterUsingStandardUtf8()
throws Exception {
// The UTF-8 encoding of a supplementary character is valid and should // The UTF-8 encoding of a supplementary character is valid and should
// be converted to a surrogate pair // be converted to a surrogate pair
byte[] b = new byte[] { byte[] utf8 = new byte[] {
(byte) 0xF0, (byte) 0x90, (byte) 0x90, (byte) 0x80, // U+10400 (byte) 0xF0, (byte) 0x90, (byte) 0x90, (byte) 0x80, // U+10400
(byte) 0xC8, (byte) 0x85 // U+0205 (byte) 0xC8, (byte) 0x85 // U+0205
}; };
String expected = "\uD801\uDC00\u0205"; // Surrogate pair String expected = "\uD801\uDC00\u0205"; // Surrogate pair
assertEquals(expected, StringUtils.fromUtf8(b)); String actual = StringUtils.fromUtf8(utf8);
assertEquals(expected, actual);
// When we convert back to UTF-8 we should get the original encoding
assertArrayEquals(utf8, StringUtils.toUtf8(actual));
} }
@Test @Test(expected = FormatException.class)
public void testFromUtf8RemovesSupplementaryCharacterUsingModifiedUtf8() { public void testFromUtf8RejectsSupplementaryCharacterUsingModifiedUtf8()
throws Exception {
// The CESU-8 or modified UTF-8 encoding of a supplementary character // The CESU-8 or modified UTF-8 encoding of a supplementary character
// is not valid // is not valid
byte[] b = new byte[] { byte[] utf8 = new byte[] {
(byte) 0xED, (byte) 0xA0, (byte) 0x81, // U+10400 as CSEU-8 (byte) 0xED, (byte) 0xA0, (byte) 0x81, // U+10400 as CSEU-8
(byte) 0xED, (byte) 0xB0, (byte) 0x80, (byte) 0xED, (byte) 0xB0, (byte) 0x80,
(byte) 0xC8, (byte) 0x85 // U+0205 (byte) 0xC8, (byte) 0x85 // U+0205
}; };
// Conversion should ignore the invalid character and return the rest StringUtils.fromUtf8(utf8);
String expected = "\u0205";
assertEquals(expected, StringUtils.fromUtf8(b));
} }
@Test @Test
public void testFromUtf8EmptyInput() { public void testFromUtf8EmptyInput() throws Exception {
assertEquals("", StringUtils.fromUtf8(new byte[0])); assertEquals("", StringUtils.fromUtf8(new byte[0]));
} }

View File

@@ -26,8 +26,8 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 31 targetSdkVersion 31
versionCode 10420 versionCode 10421
versionName "1.4.20" versionName "1.4.21"
applicationId "org.briarproject.briar.android" applicationId "org.briarproject.briar.android"
buildConfigField "String", "TorVersion", "\"$tor_version\"" buildConfigField "String", "TorVersion", "\"$tor_version\""

View File

@@ -5,16 +5,25 @@ import android.os.Bundle;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.activity.BriarActivity; import org.briarproject.briar.android.activity.BriarActivity;
import org.briarproject.briar.android.blog.RssImportResult.FileImportError;
import org.briarproject.briar.android.blog.RssImportResult.FileImportSuccess;
import org.briarproject.briar.android.blog.RssImportResult.UrlImportError;
import org.briarproject.briar.android.blog.RssImportResult.UrlImportSuccess;
import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener; import org.briarproject.briar.android.fragment.BaseFragment.BaseFragmentListener;
import org.briarproject.briar.android.fragment.ErrorFragment;
import org.briarproject.nullsafety.MethodsNotNullByDefault; import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault; import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import static androidx.fragment.app.FragmentManager.POP_BACK_STACK_INCLUSIVE;
import static org.briarproject.briar.android.util.UiUtils.showFragment;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
public class RssFeedActivity extends BriarActivity public class RssFeedActivity extends BriarActivity
@@ -45,21 +54,29 @@ public class RssFeedActivity extends BriarActivity
viewModel.getImportResult().observeEvent(this, this::onImportResult); viewModel.getImportResult().observeEvent(this, this::onImportResult);
} }
private void onImportResult(boolean result) { private void onImportResult(@Nullable RssImportResult result) {
if (result) { FragmentManager fm = getSupportFragmentManager();
FragmentManager fm = getSupportFragmentManager(); if (result instanceof UrlImportSuccess) {
if (fm.findFragmentByTag(RssFeedImportFragment.TAG) != null) { if (fm.findFragmentByTag(RssFeedImportFragment.TAG) != null) {
onBackPressed(); onBackPressed();
} }
} else { } else if (result instanceof UrlImportError) {
String url = viewModel.getUrlFailedImport(); String url = ((UrlImportError) result).url;
if (url == null) {
throw new AssertionError();
}
RssFeedImportFailedDialogFragment dialog = RssFeedImportFailedDialogFragment dialog =
RssFeedImportFailedDialogFragment.newInstance(url); RssFeedImportFailedDialogFragment.newInstance(url);
dialog.show(getSupportFragmentManager(), dialog.show(fm, RssFeedImportFailedDialogFragment.TAG);
RssFeedImportFailedDialogFragment.TAG); } else if (result instanceof FileImportSuccess) {
// pop stack back to before the initial import fragment
fm.popBackStackImmediate(RssFeedImportFragment.TAG,
POP_BACK_STACK_INCLUSIVE);
} else if (result instanceof FileImportError) {
// pop stack back to initial import fragment
fm.popBackStackImmediate(RssFeedImportFragment.TAG, 0);
// show error fragment
Fragment f = ErrorFragment.newInstance(
getString(R.string.blogs_rss_feeds_import_error));
String tag = ErrorFragment.TAG;
showFragment(fm, f, tag);
} }
} }
} }

View File

@@ -1,9 +1,13 @@
package org.briarproject.briar.android.blog; package org.briarproject.briar.android.blog;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
@@ -13,18 +17,27 @@ import android.widget.ProgressBar;
import org.briarproject.briar.R; import org.briarproject.briar.R;
import org.briarproject.briar.android.activity.ActivityComponent; import org.briarproject.briar.android.activity.ActivityComponent;
import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.BaseFragment;
import org.briarproject.briar.android.fragment.ProgressFragment;
import org.briarproject.briar.android.util.ActivityLaunchers.GetContentAdvanced;
import org.briarproject.briar.android.util.ActivityLaunchers.OpenDocumentAdvanced;
import org.briarproject.nullsafety.MethodsNotNullByDefault; import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault; import org.briarproject.nullsafety.ParametersNotNullByDefault;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import static android.os.Build.VERSION.SDK_INT;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE; import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard; import static org.briarproject.briar.android.util.UiUtils.hideSoftKeyboard;
import static org.briarproject.briar.android.util.UiUtils.launchActivityToOpenFile;
import static org.briarproject.briar.android.util.UiUtils.showFragment;
@MethodsNotNullByDefault @MethodsNotNullByDefault
@ParametersNotNullByDefault @ParametersNotNullByDefault
@@ -39,6 +52,15 @@ public class RssFeedImportFragment extends BaseFragment {
private Button importButton; private Button importButton;
private ProgressBar progressBar; private ProgressBar progressBar;
@RequiresApi(19)
private final ActivityResultLauncher<String[]> docLauncher =
registerForActivityResult(new OpenDocumentAdvanced(),
this::onFileChosen);
private final ActivityResultLauncher<String> contentLauncher =
registerForActivityResult(new GetContentAdvanced(),
this::onFileChosen);
@Override @Override
public void injectFragment(ActivityComponent component) { public void injectFragment(ActivityComponent component) {
component.inject(this); component.inject(this);
@@ -52,6 +74,7 @@ public class RssFeedImportFragment extends BaseFragment {
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
requireActivity().setTitle(getString(R.string.blogs_rss_feeds_import)); requireActivity().setTitle(getString(R.string.blogs_rss_feeds_import));
if (SDK_INT >= 19) setHasOptionsMenu(true);
View v = inflater.inflate(R.layout.fragment_rss_feed_import, View v = inflater.inflate(R.layout.fragment_rss_feed_import,
container, false); container, false);
@@ -92,11 +115,40 @@ public class RssFeedImportFragment extends BaseFragment {
return v; return v;
} }
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (SDK_INT >= 19) {
inflater.inflate(R.menu.rss_feed_import_actions, menu);
}
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_import_file && SDK_INT >= 19) {
launchActivityToOpenFile(requireContext(), docLauncher,
contentLauncher, "*/*");
return true;
}
return super.onOptionsItemSelected(item);
}
@Override @Override
public String getUniqueTag() { public String getUniqueTag() {
return TAG; return TAG;
} }
private void onFileChosen(@Nullable Uri uri) {
if (uri == null) return;
// show progress fragment
Fragment f = ProgressFragment.newInstance(
getString(R.string.blogs_rss_feeds_import_progress));
String tag = ProgressFragment.TAG;
showFragment(getParentFragmentManager(), f, tag);
// view model will import and change state that activity will react to
viewModel.importFeed(uri);
}
private void enableOrDisableImportButton() { private void enableOrDisableImportButton() {
String url = urlInput.getText().toString(); String url = urlInput.getText().toString();
importButton.setEnabled(viewModel.validateAndNormaliseUrl(url) != null); importButton.setEnabled(viewModel.validateAndNormaliseUrl(url) != null);

View File

@@ -1,6 +1,8 @@
package org.briarproject.briar.android.blog; package org.briarproject.briar.android.blog;
import android.app.Application; import android.app.Application;
import android.content.ContentResolver;
import android.net.Uri;
import android.util.Patterns; import android.util.Patterns;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
@@ -11,6 +13,10 @@ import org.briarproject.bramble.api.lifecycle.IoExecutor;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.system.AndroidExecutor; import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.android.blog.RssImportResult.FileImportError;
import org.briarproject.briar.android.blog.RssImportResult.FileImportSuccess;
import org.briarproject.briar.android.blog.RssImportResult.UrlImportError;
import org.briarproject.briar.android.blog.RssImportResult.UrlImportSuccess;
import org.briarproject.briar.android.viewmodel.DbViewModel; import org.briarproject.briar.android.viewmodel.DbViewModel;
import org.briarproject.briar.android.viewmodel.LiveEvent; import org.briarproject.briar.android.viewmodel.LiveEvent;
import org.briarproject.briar.android.viewmodel.LiveResult; import org.briarproject.briar.android.viewmodel.LiveResult;
@@ -20,6 +26,7 @@ import org.briarproject.briar.api.feed.FeedManager;
import org.briarproject.nullsafety.NotNullByDefault; import org.briarproject.nullsafety.NotNullByDefault;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
@@ -30,6 +37,7 @@ import java.util.logging.Logger;
import javax.inject.Inject; import javax.inject.Inject;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
@@ -52,11 +60,9 @@ class RssFeedViewModel extends DbViewModel {
private final MutableLiveData<LiveResult<List<Feed>>> feeds = private final MutableLiveData<LiveResult<List<Feed>>> feeds =
new MutableLiveData<>(); new MutableLiveData<>();
@Nullable
private volatile String urlFailedImport = null;
private final MutableLiveData<Boolean> isImporting = private final MutableLiveData<Boolean> isImporting =
new MutableLiveData<>(false); new MutableLiveData<>(false);
private final MutableLiveEvent<Boolean> importResult = private final MutableLiveEvent<RssImportResult> importResult =
new MutableLiveEvent<>(); new MutableLiveEvent<>();
@Inject @Inject
@@ -120,7 +126,7 @@ class RssFeedViewModel extends DbViewModel {
}); });
} }
LiveEvent<Boolean> getImportResult() { LiveEvent<RssImportResult> getImportResult() {
return importResult; return importResult;
} }
@@ -130,7 +136,6 @@ class RssFeedViewModel extends DbViewModel {
void importFeed(String url) { void importFeed(String url) {
isImporting.setValue(true); isImporting.setValue(true);
urlFailedImport = null;
ioExecutor.execute(() -> { ioExecutor.execute(() -> {
try { try {
Feed feed = feedManager.addFeed(url); Feed feed = feedManager.addFeed(url);
@@ -145,19 +150,38 @@ class RssFeedViewModel extends DbViewModel {
updated = feedList; updated = feedList;
} }
feeds.postValue(new LiveResult<>(updated)); feeds.postValue(new LiveResult<>(updated));
importResult.postEvent(true); importResult.postEvent(new UrlImportSuccess());
} catch (DbException | IOException e) { } catch (DbException | IOException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
urlFailedImport = url; importResult.postEvent(new UrlImportError(url));
importResult.postEvent(false);
} finally { } finally {
isImporting.postValue(false); isImporting.postValue(false);
} }
}); });
} }
@Nullable @UiThread
String getUrlFailedImport() { void importFeed(Uri uri) {
return urlFailedImport; ContentResolver contentResolver = getApplication().getContentResolver();
ioExecutor.execute(() -> {
try (InputStream is = contentResolver.openInputStream(uri)) {
Feed feed = feedManager.addFeed(is);
// Update the feed if it was already present
List<Feed> feedList = getList(feeds);
if (feedList == null) feedList = new ArrayList<>();
List<Feed> updated = updateListItems(feedList,
f -> f.equals(feed), f -> feed);
// Add the feed if it wasn't already present
if (updated == null) {
feedList.add(feed);
updated = feedList;
}
feeds.postValue(new LiveResult<>(updated));
importResult.postEvent(new FileImportSuccess());
} catch (IOException | DbException e) {
logException(LOG, WARNING, e);
importResult.postEvent(new FileImportError());
}
});
} }
} }

View File

@@ -0,0 +1,24 @@
package org.briarproject.briar.android.blog;
import org.briarproject.nullsafety.NotNullByDefault;
@NotNullByDefault
abstract class RssImportResult {
static class UrlImportSuccess extends RssImportResult {
}
static class UrlImportError extends RssImportResult {
final String url;
UrlImportError(String url) {
this.url = url;
}
}
static class FileImportSuccess extends RssImportResult {
}
static class FileImportError extends RssImportResult {
}
}

View File

@@ -0,0 +1,58 @@
package org.briarproject.briar.android.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.briarproject.briar.R;
import org.briarproject.nullsafety.MethodsNotNullByDefault;
import org.briarproject.nullsafety.ParametersNotNullByDefault;
import androidx.annotation.Nullable;
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class ProgressFragment extends BaseFragment {
public static final String TAG = ProgressFragment.class.getName();
private static final String PROGRESS_MSG = "progressMessage";
public static ProgressFragment newInstance(String message) {
ProgressFragment f = new ProgressFragment();
Bundle args = new Bundle();
args.putString(PROGRESS_MSG, message);
f.setArguments(args);
return f;
}
private String progressMessage;
@Override
public String getUniqueTag() {
return TAG;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = requireArguments();
progressMessage = args.getString(PROGRESS_MSG);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View v = inflater
.inflate(R.layout.fragment_progress, container, false);
TextView msg = v.findViewById(R.id.progressMessage);
msg.setText(progressMessage);
return v;
}
}

View File

@@ -145,19 +145,7 @@ public class MailboxStatusFragment extends Fragment {
@DrawableRes int iconRes; @DrawableRes int iconRes;
String title; String title;
String message = null; String message = null;
if (status.hasProblem(System.currentTimeMillis())) { if (status.getMailboxCompatibility() < 0) {
tintRes = R.color.briar_red_500;
title = getString(R.string.mailbox_status_failure_title);
iconRes = R.drawable.alerts_and_states_error;
showUnlinkWarning = false;
wizardButton.setVisibility(VISIBLE);
} else if (status.getAttemptsSinceSuccess() > 0) {
iconRes = R.drawable.ic_help_outline_white;
title = getString(R.string.mailbox_status_problem_title);
tintRes = R.color.briar_orange_500;
showUnlinkWarning = false;
wizardButton.setVisibility(VISIBLE);
} else if (status.getMailboxCompatibility() < 0) {
tintRes = R.color.briar_red_500; tintRes = R.color.briar_red_500;
if (status.getMailboxCompatibility() == API_CLIENT_TOO_OLD) { if (status.getMailboxCompatibility() == API_CLIENT_TOO_OLD) {
title = getString(R.string.mailbox_status_app_too_old_title); title = getString(R.string.mailbox_status_app_too_old_title);
@@ -172,6 +160,18 @@ public class MailboxStatusFragment extends Fragment {
iconRes = R.drawable.alerts_and_states_error; iconRes = R.drawable.alerts_and_states_error;
showUnlinkWarning = true; showUnlinkWarning = true;
wizardButton.setVisibility(GONE); wizardButton.setVisibility(GONE);
} else if (status.hasProblem(System.currentTimeMillis())) {
tintRes = R.color.briar_red_500;
title = getString(R.string.mailbox_status_failure_title);
iconRes = R.drawable.alerts_and_states_error;
showUnlinkWarning = false;
wizardButton.setVisibility(VISIBLE);
} else if (status.getAttemptsSinceSuccess() > 0) {
iconRes = R.drawable.ic_help_outline_white;
title = getString(R.string.mailbox_status_problem_title);
tintRes = R.color.briar_orange_500;
showUnlinkWarning = false;
wizardButton.setVisibility(VISIBLE);
} else { } else {
iconRes = R.drawable.ic_check_circle_outline; iconRes = R.drawable.ic_check_circle_outline;
title = getString(R.string.mailbox_status_connected_title); title = getString(R.string.mailbox_status_connected_title);

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_xlarge">
<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleLarge"
android:layout_width="@dimen/hero_square"
android:layout_height="@dimen/hero_square"
android:indeterminate="true"
app:layout_constraintBottom_toTopOf="@+id/progressMessage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.25"
app:layout_constraintVertical_chainStyle="packed"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/progressMessage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_xlarge"
android:gravity="center"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progress"
tools:text="@string/blogs_rss_feeds_import_progress" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_import_file"
android:icon="@drawable/ic_add_white"
android:title="@string/blogs_rss_feeds_import_title"
app:showAsAction="never"/>
</menu>

View File

@@ -104,7 +104,7 @@
<string name="bt_plugin_status_disabled">Briar е настроен да не използва Bluetooth</string> <string name="bt_plugin_status_disabled">Briar е настроен да не използва Bluetooth</string>
<!--Notifications--> <!--Notifications-->
<string name="reminder_notification_title">Отписани сте от Briar</string> <string name="reminder_notification_title">Отписани сте от Briar</string>
<string name="reminder_notification_text">Докоснете за повторно влизане.</string> <string name="reminder_notification_text">За да влезете, докоснете</string>
<string name="reminder_notification_channel_title">Напомняне за вход в Briar</string> <string name="reminder_notification_channel_title">Напомняне за вход в Briar</string>
<string name="reminder_notification_dismiss">Отказ</string> <string name="reminder_notification_dismiss">Отказ</string>
<string name="ongoing_notification_title">Вписани в Briar</string> <string name="ongoing_notification_title">Вписани в Briar</string>
@@ -235,6 +235,8 @@
<string name="qr_code_invalid">Кодът за QR е недействителен</string> <string name="qr_code_invalid">Кодът за QR е недействителен</string>
<string name="qr_code_too_old_1">Сканираният код за QR е от по-ранно издание на Briar.\n\nНека вашия контакт инсталира последното издание и да пробва отново.</string> <string name="qr_code_too_old_1">Сканираният код за QR е от по-ранно издание на Briar.\n\nНека вашия контакт инсталира последното издание и да пробва отново.</string>
<string name="qr_code_too_new_1">Сканираният код за QR е от по-ново издание на Briar.\n\nИнсталирайте последното издание и пробвайте отново.</string> <string name="qr_code_too_new_1">Сканираният код за QR е от по-ново издание на Briar.\n\nИнсталирайте последното издание и пробвайте отново.</string>
<string name="mailbox_qr_code_for_contact">Сканираният код за QR е от Briar Пощенска кутия.\n\nАко искате да свържете Пощенска кутия използвайте Настройки &gt; Пощенска кутия от менюто.</string>
<string name="qr_code_format_unknown">Сканираният код за QR не предназначен за добавяне на контакт в Briar.\n\nЗа тази цел използвайте кода, на екрана на контакта ви.</string>
<string name="camera_error">Грешка в камерата</string> <string name="camera_error">Грешка в камерата</string>
<string name="connecting_to_device">Свързване с устройство\u2026</string> <string name="connecting_to_device">Свързване с устройство\u2026</string>
<string name="authenticating_with_device">Удостоверяване с устройство\u2026</string> <string name="authenticating_with_device">Удостоверяване с устройство\u2026</string>
@@ -480,7 +482,6 @@
<string name="blogs_rss_feeds_import_button">Внасяне</string> <string name="blogs_rss_feeds_import_button">Внасяне</string>
<string name="blogs_rss_feeds_import_hint">рес на емисия</string> <string name="blogs_rss_feeds_import_hint">рес на емисия</string>
<string name="blogs_rss_feeds_import_error">Грешка при внасяне на емисията.</string> <string name="blogs_rss_feeds_import_error">Грешка при внасяне на емисията.</string>
<string name="blogs_rss_feeds_import_exists">Емисията вече е внесена.</string>
<string name="blogs_rss_feeds">Емисии на RSS</string> <string name="blogs_rss_feeds">Емисии на RSS</string>
<string name="blogs_rss_feeds_manage_imported">Внесена:</string> <string name="blogs_rss_feeds_manage_imported">Внесена:</string>
<string name="blogs_rss_feeds_manage_author">Автор:</string> <string name="blogs_rss_feeds_manage_author">Автор:</string>
@@ -591,7 +592,9 @@
<string name="mailbox_setup_download_link">Споделяне на препратка за изтегляне</string> <string name="mailbox_setup_download_link">Споделяне на препратка за изтегляне</string>
<string name="mailbox_setup_button_scan">Сканиране на кода за QR на пощенска кутия</string> <string name="mailbox_setup_button_scan">Сканиране на кода за QR на пощенска кутия</string>
<string name="permission_camera_qr_denied_body">Отказахте достъп до камерата, но достъп е необходим за сканиране на кодове за QR.\n\nОбмислете дали да не дадете разрешение.</string> <string name="permission_camera_qr_denied_body">Отказахте достъп до камерата, но достъп е необходим за сканиране на кодове за QR.\n\nОбмислете дали да не дадете разрешение.</string>
<string name="mailbox_setup_connecting">Свързване с Пощенска кутия…</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".--> <!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Може да отнеме %1s</string>
<string name="mailbox_setup_already_paired_title">Пощенската кутия е вече свързана</string> <string name="mailbox_setup_already_paired_title">Пощенската кутия е вече свързана</string>
<string name="mailbox_setup_already_paired_description">Прекъснете връзката с пощенската кутия от другото устройство и опитайте отново.</string> <string name="mailbox_setup_already_paired_description">Прекъснете връзката с пощенската кутия от другото устройство и опитайте отново.</string>
<string name="mailbox_setup_io_error_title">Грешка при свързване</string> <string name="mailbox_setup_io_error_title">Грешка при свързване</string>

View File

@@ -489,7 +489,6 @@ Així que l\'actualitzi li veureu una icona diferent .</string>
<string name="blogs_rss_feeds_import_button">Subscriu-me</string> <string name="blogs_rss_feeds_import_button">Subscriu-me</string>
<string name="blogs_rss_feeds_import_hint">Escriviu l\'URL del canal de notícies RSS</string> <string name="blogs_rss_feeds_import_hint">Escriviu l\'URL del canal de notícies RSS</string>
<string name="blogs_rss_feeds_import_error">Ens sap greu! S\'ha produït un error en subscriure-us al vostre canal de notícies.</string> <string name="blogs_rss_feeds_import_error">Ens sap greu! S\'ha produït un error en subscriure-us al vostre canal de notícies.</string>
<string name="blogs_rss_feeds_import_exists">Aquest canal ja s\'ha importat.</string>
<string name="blogs_rss_feeds">Canals RSS</string> <string name="blogs_rss_feeds">Canals RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importat:</string> <string name="blogs_rss_feeds_manage_imported">Importat:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -60,8 +60,8 @@
<string name="old_android_expiry_date_reached">Briar wird auf Android 4 nicht mehr unterstützt.\nBitte installiere Briar auf einem neueren Gerät.</string> <string name="old_android_expiry_date_reached">Briar wird auf Android 4 nicht mehr unterstützt.\nBitte installiere Briar auf einem neueren Gerät.</string>
<string name="old_android_delete_account">Du kannst auf die Schaltfläche unten tippen, um dein Konto von diesem Gerät zu löschen.</string> <string name="old_android_delete_account">Du kannst auf die Schaltfläche unten tippen, um dein Konto von diesem Gerät zu löschen.</string>
<string name="delete_account_button">Konto löschen</string> <string name="delete_account_button">Konto löschen</string>
<string name="startup_open_database">Datenbank wird entschlüsselt...</string> <string name="startup_open_database">Datenbank wird entschlüsselt</string>
<string name="startup_migrate_database">Datenbank wird aktualisiert...</string> <string name="startup_migrate_database">Datenbank wird aktualisiert</string>
<string name="startup_compact_database">Datenbank wird komprimiert…</string> <string name="startup_compact_database">Datenbank wird komprimiert…</string>
<!--Navigation Drawer--> <!--Navigation Drawer-->
<string name="nav_drawer_open_description">Navigationsleiste öffnen</string> <string name="nav_drawer_open_description">Navigationsleiste öffnen</string>
@@ -266,9 +266,9 @@
<string name="pending_contact_requests_snackbar">Es gibt ausstehende Kontaktanfragen</string> <string name="pending_contact_requests_snackbar">Es gibt ausstehende Kontaktanfragen</string>
<string name="pending_contact_requests">Ausstehende Kontaktanfragen</string> <string name="pending_contact_requests">Ausstehende Kontaktanfragen</string>
<string name="no_pending_contacts">Keine ausstehenden Kontakte</string> <string name="no_pending_contacts">Keine ausstehenden Kontakte</string>
<string name="waiting_for_contact_to_come_online">Warte auf Online-Aktivität des Kontakts ...</string> <string name="waiting_for_contact_to_come_online">Warte auf Online-Aktivität des Kontakts</string>
<string name="connecting">Verbinde…</string> <string name="connecting">Verbinde…</string>
<string name="adding_contact">Kontakt hinzufügen...</string> <string name="adding_contact">Kontakt hinzufügen</string>
<string name="adding_contact_failed">Hinzufügen von Kontakt ist fehlgeschlagen</string> <string name="adding_contact_failed">Hinzufügen von Kontakt ist fehlgeschlagen</string>
<string name="dialog_title_remove_pending_contact">Entfernung bestätigen</string> <string name="dialog_title_remove_pending_contact">Entfernung bestätigen</string>
<string name="dialog_message_remove_pending_contact">Dieser Kontakt befindet sich noch beim Hinzufügen. Wenn er jetzt entfernt wird, wird das Hinzufügen abgebrochen.</string> <string name="dialog_message_remove_pending_contact">Dieser Kontakt befindet sich noch beim Hinzufügen. Wenn er jetzt entfernt wird, wird das Hinzufügen abgebrochen.</string>
@@ -487,8 +487,9 @@
<string name="blogs_rss_feeds_import">RSS-Feed importieren</string> <string name="blogs_rss_feeds_import">RSS-Feed importieren</string>
<string name="blogs_rss_feeds_import_button">Importieren</string> <string name="blogs_rss_feeds_import_button">Importieren</string>
<string name="blogs_rss_feeds_import_hint">URL des RSS-Feeds eingeben</string> <string name="blogs_rss_feeds_import_hint">URL des RSS-Feeds eingeben</string>
<string name="blogs_rss_feeds_import_progress">RSS-Feed wird importiert…</string>
<string name="blogs_rss_feeds_import_error">Es tut uns Leid! Es gab einen Fehler beim Importieren deines Feeds.</string> <string name="blogs_rss_feeds_import_error">Es tut uns Leid! Es gab einen Fehler beim Importieren deines Feeds.</string>
<string name="blogs_rss_feeds_import_exists">Dieser Feed ist bereits importiert.</string> <string name="blogs_rss_feeds_import_title">Feed aus Datei importieren</string>
<string name="blogs_rss_feeds">RSS-Feeds</string> <string name="blogs_rss_feeds">RSS-Feeds</string>
<string name="blogs_rss_feeds_manage_imported">Importiert:</string> <string name="blogs_rss_feeds_manage_imported">Importiert:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>
@@ -729,7 +730,7 @@
<string name="dev_report_saved">Der Bericht wurde gespeichert. Er wird verschickt, wenn du dich das nächste Mal bei Briar anmeldest.</string> <string name="dev_report_saved">Der Bericht wurde gespeichert. Er wird verschickt, wenn du dich das nächste Mal bei Briar anmeldest.</string>
<string name="dev_report_error">Fehler: Senden des Reports fehlgeschlagen</string> <string name="dev_report_error">Fehler: Senden des Reports fehlgeschlagen</string>
<!--Sign Out--> <!--Sign Out-->
<string name="progress_title_logout">Von Briar abmelden...</string> <string name="progress_title_logout">Von Briar abmelden</string>
<!--Screen Filters & Tapjacking--> <!--Screen Filters & Tapjacking-->
<string name="screen_filter_title">Bildschirmüberlagerung erkannt</string> <string name="screen_filter_title">Bildschirmüberlagerung erkannt</string>
<string name="screen_filter_body">Eine andere App überlagert Briar. Um deine Sicherheit zu gewährleisten, reagiert Briar in diesem Fall nicht auf deine Eingaben.\n\nDie folgenden Apps könnten überlagern:\n\n%1$s</string> <string name="screen_filter_body">Eine andere App überlagert Briar. Um deine Sicherheit zu gewährleisten, reagiert Briar in diesem Fall nicht auf deine Eingaben.\n\nDie folgenden Apps könnten überlagern:\n\n%1$s</string>

View File

@@ -495,7 +495,6 @@
<string name="blogs_rss_feeds_import_button">Importar</string> <string name="blogs_rss_feeds_import_button">Importar</string>
<string name="blogs_rss_feeds_import_hint">Introduce la URL del canal RSS</string> <string name="blogs_rss_feeds_import_hint">Introduce la URL del canal RSS</string>
<string name="blogs_rss_feeds_import_error">¡Lo sentimos! Hubo un error importando tu canal.</string> <string name="blogs_rss_feeds_import_error">¡Lo sentimos! Hubo un error importando tu canal.</string>
<string name="blogs_rss_feeds_import_exists">Ese canal ya está importado.</string>
<string name="blogs_rss_feeds">Canales RSS</string> <string name="blogs_rss_feeds">Canales RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importado:</string> <string name="blogs_rss_feeds_manage_imported">Importado:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -510,7 +510,6 @@
<string name="blogs_rss_feeds_import_button">وارد کردن</string> <string name="blogs_rss_feeds_import_button">وارد کردن</string>
<string name="blogs_rss_feeds_import_hint">آدرس خوراک RSS را وارد کنید</string> <string name="blogs_rss_feeds_import_hint">آدرس خوراک RSS را وارد کنید</string>
<string name="blogs_rss_feeds_import_error">متاسفیم! وارد کردن خوراک شما با خطا مواجه شده است.</string> <string name="blogs_rss_feeds_import_error">متاسفیم! وارد کردن خوراک شما با خطا مواجه شده است.</string>
<string name="blogs_rss_feeds_import_exists">این خوراک وارد شده است.</string>
<string name="blogs_rss_feeds">خوراک های RSS</string> <string name="blogs_rss_feeds">خوراک های RSS</string>
<string name="blogs_rss_feeds_manage_imported">وارد شده:</string> <string name="blogs_rss_feeds_manage_imported">وارد شده:</string>
<string name="blogs_rss_feeds_manage_author">نویسنده:</string> <string name="blogs_rss_feeds_manage_author">نویسنده:</string>

View File

@@ -482,7 +482,6 @@
<string name="blogs_rss_feeds_import_button">Importer</string> <string name="blogs_rss_feeds_import_button">Importer</string>
<string name="blogs_rss_feeds_import_hint">Saisir lURL du fil RSS</string> <string name="blogs_rss_feeds_import_hint">Saisir lURL du fil RSS</string>
<string name="blogs_rss_feeds_import_error">Nous sommes désolés! Une erreur est survenue lors de limportation de votre fil.</string> <string name="blogs_rss_feeds_import_error">Nous sommes désolés! Une erreur est survenue lors de limportation de votre fil.</string>
<string name="blogs_rss_feeds_import_exists">Ce fil est déjà importé.</string>
<string name="blogs_rss_feeds">Fils RSS</string> <string name="blogs_rss_feeds">Fils RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importés :</string> <string name="blogs_rss_feeds_manage_imported">Importés :</string>
<string name="blogs_rss_feeds_manage_author">Auteur :</string> <string name="blogs_rss_feeds_manage_author">Auteur :</string>

View File

@@ -466,7 +466,6 @@
<string name="blogs_rss_feeds_import_button">Flytja inn</string> <string name="blogs_rss_feeds_import_button">Flytja inn</string>
<string name="blogs_rss_feeds_import_hint">Settu inn slóðina á RSS-streymið</string> <string name="blogs_rss_feeds_import_hint">Settu inn slóðina á RSS-streymið</string>
<string name="blogs_rss_feeds_import_error">Því miður! Það kom upp villa við að flytja inn streymið.</string> <string name="blogs_rss_feeds_import_error">Því miður! Það kom upp villa við að flytja inn streymið.</string>
<string name="blogs_rss_feeds_import_exists">Þegar er búið að flytja inn þetta streymi.</string>
<string name="blogs_rss_feeds">RSS-fréttastreymi</string> <string name="blogs_rss_feeds">RSS-fréttastreymi</string>
<string name="blogs_rss_feeds_manage_imported">Flutt inn:</string> <string name="blogs_rss_feeds_manage_imported">Flutt inn:</string>
<string name="blogs_rss_feeds_manage_author">Höfundur:</string> <string name="blogs_rss_feeds_manage_author">Höfundur:</string>

View File

@@ -501,8 +501,9 @@
<string name="blogs_rss_feeds_import">Importa RSS Feed</string> <string name="blogs_rss_feeds_import">Importa RSS Feed</string>
<string name="blogs_rss_feeds_import_button">Importa</string> <string name="blogs_rss_feeds_import_button">Importa</string>
<string name="blogs_rss_feeds_import_hint">Inserire l\'URL dell\'RSS feed</string> <string name="blogs_rss_feeds_import_hint">Inserire l\'URL dell\'RSS feed</string>
<string name="blogs_rss_feeds_import_progress">Importazione RSS Feed…</string>
<string name="blogs_rss_feeds_import_error">Ci dispiace! C\'è stato un errore nell\'importazione del tuo feed.</string> <string name="blogs_rss_feeds_import_error">Ci dispiace! C\'è stato un errore nell\'importazione del tuo feed.</string>
<string name="blogs_rss_feeds_import_exists">Quel flusso è già importato.</string> <string name="blogs_rss_feeds_import_title">Importa feed da file</string>
<string name="blogs_rss_feeds">Flussi RSS</string> <string name="blogs_rss_feeds">Flussi RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importato:</string> <string name="blogs_rss_feeds_manage_imported">Importato:</string>
<string name="blogs_rss_feeds_manage_author">Autore:</string> <string name="blogs_rss_feeds_manage_author">Autore:</string>

View File

@@ -1,13 +1,13 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<!--Setup--> <!--Setup-->
<string name="setup_title">Briar へようこそ</string> <string name="setup_title">Briarへようこそ</string>
<string name="setup_name_explanation">あなたのニックネームは、常に、あなたが投稿するコンテンツとともに表示されます。プロフィール作成後、編集はできません。</string> <string name="setup_name_explanation">あなたのニックネームは、常に、あなたが投稿するコンテンツとともに表示されます。プロフィール作成後、編集はできません。</string>
<string name="setup_next">次へ</string> <string name="setup_next">次へ</string>
<string name="setup_password_intro">パスワードを選択</string> <string name="setup_password_intro">パスワードを選択</string>
<string name="setup_password_explanation">Briar のアカウント情報はクラウドではなく、暗号化された端末に保存されます。アプリのアンインストールやパスワードを紛失した場合、アカウントへのアクセスとデータを回復する手段はありません。\n\n推測するのが難しい、長いパスワードを設定してください。ランダムな単語やランダムな10文字と数字と記号を組み合わせたものなどです。</string> <string name="setup_password_explanation">Briarのアカウント情報はクラウドではなく、暗号化された端末に保存されます。アプリのアンインストールやパスワードを紛失した場合、アカウントへのアクセスとデータを回復する手段はありません。\n\n推測するのが難しい、長いパスワードを設定してください。ランダムな単語やランダムな10文字と数字と記号を組み合わせたものなどです。</string>
<string name="dnkm_doze_intro">メッセージを受信するために、Briar はバックグラウンドで接続を維持する必要があります。</string> <string name="dnkm_doze_intro">メッセージを受信するために、Briarはバックグラウンドで接続を維持する必要があります。</string>
<string name="dnkm_doze_explanation">メッセージを受信するために、Briar はバックグラウンドで接続を維持する必要があります。 Briar が接続を維持できるように、バッテリーの最適化を無効にしてください。</string> <string name="dnkm_doze_explanation">メッセージを受信するために、Briarはバックグラウンドで接続を維持する必要があります。 Briarが接続を維持できるように、バッテリーの最適化を無効にしてください。</string>
<string name="choose_nickname">ニックネームを入力</string> <string name="choose_nickname">ニックネームを入力</string>
<string name="choose_password">パスワードを入力</string> <string name="choose_password">パスワードを入力</string>
<string name="confirm_password">確認のため再度パスワードを入力</string> <string name="confirm_password">確認のため再度パスワードを入力</string>
@@ -17,42 +17,42 @@
<string name="create_account_button">アカウントを作成</string> <string name="create_account_button">アカウントを作成</string>
<string name="more_info">詳細情報</string> <string name="more_info">詳細情報</string>
<string name="don_t_ask_again">次からは尋ねない</string> <string name="don_t_ask_again">次からは尋ねない</string>
<string name="dnkm_huawei_protected_text">下のボタンをタップして、「保護されたアプリ」画面で Briar が保護されていることを確認してください。</string> <string name="dnkm_huawei_protected_text">下のボタンをタップして、「保護されたアプリ」画面で Briarが保護されていることを確認してください。</string>
<string name="dnkm_huawei_protected_button">Briar を保護する</string> <string name="dnkm_huawei_protected_button">Briarを保護する</string>
<string name="dnkm_huawei_protected_help">Briar が保護されたアプリのリストに追加されていないと、Briar はバックグラウンドで実行することができません。</string> <string name="dnkm_huawei_protected_help">Briarが保護されたアプリのリストに追加されていないと、Briarはバックグラウンドで実行することができません。</string>
<string name="dnkm_huawei_app_launch_text">下のボタンをタップして「アプリの起動」画面を開き、Briar が「手動で管理する」に設定されていることを確認してください。</string> <string name="dnkm_huawei_app_launch_text">下のボタンをタップして「アプリの起動」画面を開き、Briarが「手動で管理する」に設定されていることを確認してください。</string>
<string name="dnkm_huawei_app_launch_help">「アプリ起動」画面で Briar を「手動で管理する」に設定していないと、バックグラウンドで動作させることができません。</string> <string name="dnkm_huawei_app_launch_help">「アプリ起動」画面で Briarを「手動で管理する」に設定していないと、バックグラウンドで動作させることができません。</string>
<string name="dnkm_xiaomi_text">バックグラウンドで実行するには、Briar を最近のアプリのリストにロックする必要があります。</string> <string name="dnkm_xiaomi_text">バックグラウンドで実行するには、Briarを最近のアプリのリストにロックする必要があります。</string>
<string name="dnkm_xiaomi_button">Briar を保護する</string> <string name="dnkm_xiaomi_button">Briarを保護する</string>
<string name="dnkm_xiaomi_help">Briar が最近のアプリのリストにロックされていないと、バックグラウンドで実行することができません。</string> <string name="dnkm_xiaomi_help">Briarが最近のアプリのリストにロックされていないと、バックグラウンドで実行することができません。</string>
<string name="dnkm_xiaomi_dialog_body_old">1. 最近使ったアプリのリスト(アプリスイッチャーともいう)を開いて下さい。\n\n2. Briar の画像を下にスワイプすると、南京錠のアイコンが表示されます。\n\n3. ロックされていない場合は、タップしてロックします。</string> <string name="dnkm_xiaomi_dialog_body_old">1. 最近使ったアプリのリスト(アプリスイッチャーともいう)を開いて下さい。\n\n2. Briarの画像を下にスワイプすると、南京錠のアイコンが表示されます。\n\n3. ロックされていない場合は、タップしてロックします。</string>
<string name="dnkm_warning_dozed_1">Briarはバックグラウンドで実行することができませんでした</string> <string name="dnkm_warning_dozed_1">Briarはバックグラウンドで実行できませんでした</string>
<!--Login--> <!--Login-->
<string name="enter_password">パスワード</string> <string name="enter_password">パスワード</string>
<string name="try_again">パスワードが間違っています。もう一度入力してください。</string> <string name="try_again">パスワードが間違っています。もう一度入力してください。</string>
<string name="dialog_title_cannot_check_password">パスワードを確認できません</string> <string name="dialog_title_cannot_check_password">パスワードを確認できません</string>
<string name="dialog_message_cannot_check_password">Briar がパスワードを確認することができませんでした。この問題を解決するには、端末の再起動を試してください。</string> <string name="dialog_message_cannot_check_password">Briarがパスワードを確認することができませんでした。この問題を解決するには、端末の再起動を試してください。</string>
<string name="sign_in_button">サインイン</string> <string name="sign_in_button">サインイン</string>
<string name="forgotten_password">パスワードを忘れました</string> <string name="forgotten_password">パスワードを忘れました</string>
<string name="dialog_title_lost_password">パスワードを紛失</string> <string name="dialog_title_lost_password">パスワードを紛失</string>
<string name="dialog_message_lost_password">Briar アカウントはクラウド上ではなく、暗号化さた上であなたの端末に保存さています。したがって、Briar はパスワードをリセットできません。アカウントを削除して、はじめからやり直しますか?\n\n注意あなたのID、連絡先、メッセージは永久に失われます。</string> <string name="dialog_message_lost_password">Briarアカウントはクラウド上ではなく、暗号化さた上であなたの端末に保存さています。したがって、Briarはパスワードをリセットできません。アカウントを削除して、はじめからやり直しますか\n\n注意あなたのID、連絡先、メッセージは永久に失われます。</string>
<string name="startup_failed_activity_title">Briar の起動に失敗しました</string> <string name="startup_failed_activity_title">Briarの起動に失敗</string>
<string name="startup_failed_clock_error">お使いの端末の時計が正しくないため、Briar は起動できませんでした。\n\n端末の時計を正しい時刻に設定してから、もう一度試してください。</string> <string name="startup_failed_clock_error">お使いの端末の時計が正しくないため、Briarは起動できませんでした。\n\n端末の時計を正しい時刻に設定してから、もう一度試してください。</string>
<string name="startup_failed_db_error">Briar は、あなたのアカウント、連絡先、メッセージを含むデータベースを開くことができませんでした。\n\nアプリを最新版にアップグレードしてもう一度お試しいただくか、パスワード入力画面で「パスワードを忘れました」を選択して新しいアカウントを設定してください。</string> <string name="startup_failed_db_error">Briarは、あなたのアカウント、連絡先、メッセージを含むデータベースを開くことができませんでした。\n\nアプリを最新版にアップグレードしてもう一度お試しいただくか、パスワード入力画面で「パスワードを忘れました」を選択して新しいアカウントを設定してください。</string>
<string name="startup_failed_data_too_old_error">あなたのアカウントは古いバージョンのアプリで作成されたもので、このバージョンでは開くことができません。\n\n古いバージョンを再インストールするか、パスワード入力画面で\'パスワードを忘れました\'を選択して新しいアカウントを設定する必要があります。</string> <string name="startup_failed_data_too_old_error">あなたのアカウントは古いバージョンのアプリで作成されたもので、このバージョンでは開くことができません。\n\n古いバージョンを再インストールするか、パスワード入力画面で\'パスワードを忘れました\'を選択して新しいアカウントを設定する必要があります。</string>
<string name="startup_failed_data_too_new_error">あなたのアカウントは、このアプリの新しいバージョンで作成されたもので、このバージョンでは開くことができません。\n\n最新版にアップグレードしてから、もう一度試してください。</string> <string name="startup_failed_data_too_new_error">あなたのアカウントは、このアプリの新しいバージョンで作成されたもので、このバージョンでは開くことができません。\n\n最新版にアップグレードしてから、もう一度試してください。</string>
<string name="startup_failed_service_error">Briar は、必要なコンポーネントを起動できませんでした。\n\nアプリの最新版にアップグレードしてから、もう一度試してください。</string> <string name="startup_failed_service_error">Briarは要求されたコンポーネントを起動できませんでした。\n\nアプリの最新版にアップグレードしてから、もう一度試してください。</string>
<plurals name="expiry_warning"> <plurals name="expiry_warning">
<item quantity="other">これは、Briar のテストバージョンです。 アカウントはあと%d日で期限切れになり、更新できません。</item> <item quantity="other">これは、Briarのテストバージョンです。 アカウントはあと%d日で期限切れになり、更新できません。</item>
</plurals> </plurals>
<plurals name="old_android_expiry_warning"> <plurals name="old_android_expiry_warning">
<item quantity="other">Android 4はサポートされなくなりました。Briar は(%d日後に)%s上での動作を停止します。新しい端末に Briar をインストールして、新しいアカウントを作成してください。</item> <item quantity="other">Android 4はサポートされなくなりました。Briarは(%d日後に)%s上での動作を停止します。新しい端末に Briarをインストールして、新しいアカウントを作成してください。</item>
</plurals> </plurals>
<string name="expiry_date_reached">このソフトウェアの有効期限が切れました。テストに参加してくださりありがとうございます!</string> <string name="expiry_date_reached">このソフトウェアの有効期限が切れました。テストに参加してくださりありがとうございます!</string>
<string name="download_briar">Briarの使用を続けるには、最新リリースをダウンロードしてください。</string> <string name="download_briar">Briarの使用を続けるには、最新リリースをダウンロードしてください。</string>
<string name="create_new_account">新しいアカウントを作成する必要があります。同じニックネームも使用できます。</string> <string name="create_new_account">新しいアカウントを作成する必要があります。同じニックネームも使用できます。</string>
<string name="download_briar_button">最新リリースをダウンロード</string> <string name="download_briar_button">最新リリースをダウンロード</string>
<string name="old_android_expiry_date_reached">BriarAndroid 4 では動作しなくなりました。\n新しい端末にBriarをインストールしてください。</string> <string name="old_android_expiry_date_reached">BriarAndroid 4では動作しなくなりました。\n新しい端末にBriarをインストールしてください。</string>
<string name="old_android_delete_account">下のボタンをタップして、この端末からあなたのアカウントを削除できます。</string> <string name="old_android_delete_account">下のボタンをタップして、この端末からあなたのアカウントを削除できます。</string>
<string name="delete_account_button">アカウントを削除</string> <string name="delete_account_button">アカウントを削除</string>
<string name="startup_open_database">データベースの復号化中…</string> <string name="startup_open_database">データベースの復号化中…</string>
@@ -69,36 +69,36 @@
<string name="lock_button">アプリをロック</string> <string name="lock_button">アプリをロック</string>
<string name="settings_button">設定</string> <string name="settings_button">設定</string>
<string name="sign_out_button">サインアウト</string> <string name="sign_out_button">サインアウト</string>
<string name="transports_onboarding_text">ここにタップすると、Briar があなたの連絡先に接続する方法を制御できます。</string> <string name="transports_onboarding_text">ここにタップすると、Briarがあなたの連絡先に接続する方法を制御できます。</string>
<!--Transports: Tor--> <!--Transports: Tor-->
<string name="transport_tor">インターネット</string> <string name="transport_tor">インターネット</string>
<string name="tor_device_status_online_wifi">電話機はWi-Fiでインターネットにアクセスできます</string> <string name="tor_device_status_online_wifi">電話機はWi-Fiでインターネットにアクセスできます</string>
<string name="tor_device_status_online_mobile">電話機はモバイル データでインターネットにアクセスできます</string> <string name="tor_device_status_online_mobile">電話機はモバイル データでインターネットにアクセスできます</string>
<string name="tor_device_status_offline">電話機がインターネットに接続できません</string> <string name="tor_device_status_offline">電話機がインターネットに接続できません</string>
<string name="tor_plugin_status_enabling">Briar はインターネットに接続中です…</string> <string name="tor_plugin_status_enabling">Briarはインターネットに接続中です…</string>
<string name="tor_plugin_status_active">Briar はインターネットに接続されました</string> <string name="tor_plugin_status_active">Briarはインターネットに接続されました</string>
<string name="tor_plugin_status_inactive">Briar はインターネットに接続できません</string> <string name="tor_plugin_status_inactive">Briarはインターネットに接続できません</string>
<string name="tor_plugin_status_disabled">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_mobile_data">Briarはモバイルデータを使用しないように設定されています</string>
<string name="tor_plugin_status_disabled_battery">Briar はバッテリー駆動時にインターネットを使用しないように設定されています</string> <string name="tor_plugin_status_disabled_battery">Briarはバッテリー駆動時にインターネットを使用しないように設定されています</string>
<string name="tor_plugin_status_disabled_country_blocked">Briar はこの国でインターネットを使わないように設定されています</string> <string name="tor_plugin_status_disabled_country_blocked">Briarはこの国でインターネットを使わないように設定されています</string>
<!--Transports: Wi-Fi--> <!--Transports: Wi-Fi-->
<string name="transport_lan">Wi-Fi</string> <string name="transport_lan">Wi-Fi</string>
<string name="transport_lan_long">同じ 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_on">電話機は Wi-Fi に接続されました</string>
<string name="lan_device_status_off">電話機はWi-Fiに接続されていません</string> <string name="lan_device_status_off">電話機はWi-Fiに接続されていません</string>
<string name="lan_plugin_status_enabling">BriarWi-Fi ネットワークに接続中です…</string> <string name="lan_plugin_status_enabling">BriarWi-Fiネットワークに接続中です…</string>
<string name="lan_plugin_status_active">BriarWi-Fi ネットワークに接続されました</string> <string name="lan_plugin_status_active">BriarWi-Fiネットワークに接続されました</string>
<string name="lan_plugin_status_inactive">BriarWi-Fi ネットワークに接続できません</string> <string name="lan_plugin_status_inactive">BriarWi-Fiネットワークに接続できません</string>
<string name="lan_plugin_status_disabled">BriarWi-Fi ネットワークを使用しないように設定されています</string> <string name="lan_plugin_status_disabled">BriarWi-Fiネットワークを使用しないように設定されています</string>
<!--Transports: Bluetooth--> <!--Transports: Bluetooth-->
<string name="transport_bt">Bluetooth</string> <string name="transport_bt">Bluetooth</string>
<string name="bt_device_status_on">携帯電話の Bluetooth はオンになっています</string> <string name="bt_device_status_on">携帯電話の Bluetooth はオンになっています</string>
<string name="bt_device_status_off">携帯電話の Bluetooth はオフにされました</string> <string name="bt_device_status_off">携帯電話の Bluetooth はオフにされました</string>
<string name="bt_plugin_status_enabling">BriarBluetooth に接続中です…</string> <string name="bt_plugin_status_enabling">BriarBluetoothに接続中です…</string>
<string name="bt_plugin_status_active">BriarBluetooth に接続しました</string> <string name="bt_plugin_status_active">BriarBluetoothに接続しました</string>
<string name="bt_plugin_status_inactive">BriarBluetooth に接続できません</string> <string name="bt_plugin_status_inactive">BriarBluetoothに接続できません</string>
<string name="bt_plugin_status_disabled">BriarBluetooth を使用しないように設定されています</string> <string name="bt_plugin_status_disabled">BriarBluetoothを使用しないように設定されています</string>
<!--Notifications--> <!--Notifications-->
<string name="reminder_notification_title">Briarからサインアウト</string> <string name="reminder_notification_title">Briarからサインアウト</string>
<string name="reminder_notification_text">タップして再ログインします。</string> <string name="reminder_notification_text">タップして再ログインします。</string>
@@ -323,6 +323,7 @@
<string name="connect_via_bluetooth_intro">Bluetooth接続が自動的に行われない場合は、この画面を使って手動で接続することができます。\n\nこの機能を利用するには、あなたの連絡先が近くにある必要があります。\n\nあなたと連絡先が同時に\"開始\"を押してください。</string> <string name="connect_via_bluetooth_intro">Bluetooth接続が自動的に行われない場合は、この画面を使って手動で接続することができます。\n\nこの機能を利用するには、あなたの連絡先が近くにある必要があります。\n\nあなたと連絡先が同時に\"開始\"を押してください。</string>
<string name="connect_via_bluetooth_already_discovering">既にBluetooth経由での接続を試行中です。すぐに再試行してください。</string> <string name="connect_via_bluetooth_already_discovering">既にBluetooth経由での接続を試行中です。すぐに再試行してください。</string>
<string name="connect_via_bluetooth_no_location_permission">位置情報の権限なくして続行不可能</string> <string name="connect_via_bluetooth_no_location_permission">位置情報の権限なくして続行不可能</string>
<string name="connect_via_bluetooth_no_bluetooth_permission">付近の端末の権限なくして続行不可能</string>
<string name="connect_via_bluetooth_start">Bluetooth経由で接続中…</string> <string name="connect_via_bluetooth_start">Bluetooth経由で接続中…</string>
<string name="connect_via_bluetooth_success">Bluetooth経由で接続に成功</string> <string name="connect_via_bluetooth_success">Bluetooth経由で接続に成功</string>
<string name="connect_via_bluetooth_error">Bluetooth経由で接続不可能。</string> <string name="connect_via_bluetooth_error">Bluetooth経由で接続不可能。</string>
@@ -348,9 +349,9 @@
<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_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">グループを脱退</string>
<string name="groups_leave_dialog_title">グループをやめる確認</string> <string name="groups_leave_dialog_title">グループをやめる確認</string>
<string name="groups_leave_dialog_message">このグループをやめてもよろしいですか?</string> <string name="groups_leave_dialog_message">このグループを脱退してもよろしいですか?</string>
<string name="groups_dissolve">グループを削除</string> <string name="groups_dissolve">グループを削除</string>
<string name="groups_dissolve_dialog_title">グループの削除の確認</string> <string name="groups_dissolve_dialog_title">グループの削除の確認</string>
<string name="groups_dissolve_dialog_message">このグループを削除してもよろしいですか?\n\nグループを削除すると、他のすべてのメンバーは会話を続けることができなくなり、最新のメッセージは受信できなくなります。</string> <string name="groups_dissolve_dialog_message">このグループを削除してもよろしいですか?\n\nグループを削除すると、他のすべてのメンバーは会話を続けることができなくなり、最新のメッセージは受信できなくなります。</string>
@@ -394,10 +395,10 @@
<string name="forum_new_message_hint">新しい投稿</string> <string name="forum_new_message_hint">新しい投稿</string>
<string name="forum_message_reply_hint">新しい返信</string> <string name="forum_message_reply_hint">新しい返信</string>
<string name="btn_reply">返信</string> <string name="btn_reply">返信</string>
<string name="forum_leave">フォーラムをやめる</string> <string name="forum_leave">フォーラムを脱退</string>
<string name="dialog_title_leave_forum">フォーラムをやめる確認</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="dialog_button_leave">脱退</string>
<string name="forum_left_toast">フォーラムをやめました</string> <string name="forum_left_toast">フォーラムをやめました</string>
<!--Forum Sharing--> <!--Forum Sharing-->
<string name="forum_share_button">フォーラムを共有</string> <string name="forum_share_button">フォーラムを共有</string>
@@ -416,6 +417,10 @@
<string name="forum_declined_toast">招待を辞退しました</string> <string name="forum_declined_toast">招待を辞退しました</string>
<string name="shared_by_format">%sによって共有されました。</string> <string name="shared_by_format">%sによって共有されました。</string>
<string name="forum_invitation_already_sharing">既に共有しています</string> <string name="forum_invitation_already_sharing">既に共有しています</string>
<string name="forum_invitation_already_invited">招待は既に送信しました</string>
<string name="forum_invitation_invite_received">招待は既に受信されました</string>
<string name="forum_invitation_not_supported">この連絡先によってサポートされていません</string>
<string name="forum_invitation_error">エラー。これはバグか、そうでなければ、あなたの誤りです</string>
<string name="forum_invitation_response_accepted_sent">%sからのフォーラムへの招待を受け入れました。</string> <string name="forum_invitation_response_accepted_sent">%sからのフォーラムへの招待を受け入れました。</string>
<string name="forum_invitation_response_declined_sent">%sからのフォーラムへの招待を辞退しました。</string> <string name="forum_invitation_response_declined_sent">%sからのフォーラムへの招待を辞退しました。</string>
<string name="forum_invitation_response_declined_auto">%sからのフォーラムへの招待は自動的に辞退されました。</string> <string name="forum_invitation_response_declined_auto">%sからのフォーラムへの招待は自動的に辞退されました。</string>
@@ -465,8 +470,9 @@
<string name="blogs_rss_feeds_import">RSSフィードをインポート</string> <string name="blogs_rss_feeds_import">RSSフィードをインポート</string>
<string name="blogs_rss_feeds_import_button">インポート</string> <string name="blogs_rss_feeds_import_button">インポート</string>
<string name="blogs_rss_feeds_import_hint">RSSフィードのURLを入力してください</string> <string name="blogs_rss_feeds_import_hint">RSSフィードのURLを入力してください</string>
<string name="blogs_rss_feeds_import_progress">RSSフィードをインポート中…</string>
<string name="blogs_rss_feeds_import_error">申し訳ありません! フィードのインポート中にエラーが発生しました。</string> <string name="blogs_rss_feeds_import_error">申し訳ありません! フィードのインポート中にエラーが発生しました。</string>
<string name="blogs_rss_feeds_import_exists">そのフィードは既にインポートされています。</string> <string name="blogs_rss_feeds_import_title">ファイルからフィードインポート</string>
<string name="blogs_rss_feeds">RSSフィード</string> <string name="blogs_rss_feeds">RSSフィード</string>
<string name="blogs_rss_feeds_manage_imported">インポート済み:</string> <string name="blogs_rss_feeds_manage_imported">インポート済み:</string>
<string name="blogs_rss_feeds_manage_author">著者:</string> <string name="blogs_rss_feeds_manage_author">著者:</string>
@@ -573,7 +579,7 @@
<string name="mailbox_setup_title">メールボックスのセットアップ</string> <string name="mailbox_setup_title">メールボックスのセットアップ</string>
<string name="mailbox_setup_intro">メールボックスはあなたがオフラインの間、連絡先があなたにメッセージを送信することを有効にします。メールボックスはあなたがオンラインになるまで、メッセージを受信し保管します。\n <string name="mailbox_setup_intro">メールボックスはあなたがオフラインの間、連絡先があなたにメッセージを送信することを有効にします。メールボックスはあなたがオンラインになるまで、メッセージを受信し保管します。\n
\n予備端末上にBriarのメールボックスアプリをインストールできます。それを電源とWi-Fiに接続し、常時オンラインにしてください。</string> \n予備端末上にBriarのメールボックスアプリをインストールできます。それを電源とWi-Fiに接続し、常時オンラインにしてください。</string>
<string name="mailbox_setup_download">最初に、Google PlayまたはBriarをダウンロードしたどこかで\"Briar Mailbox\"を検索して、他の端末上にメールボックスアプリをインストールします。\n <string name="mailbox_setup_download">最初に、Google PlayまたはBriarをダウンロードしたどこかで\"BriarMailbox\"を検索して、他の端末上にメールボックスアプリをインストールします。\n
\nそして、メールボックスアプリによって表示されるQRコードを読み取って、Briarとあなたのメールボックス結びつけます。</string> \nそして、メールボックスアプリによって表示されるQRコードを読み取って、Briarとあなたのメールボックス結びつけます。</string>
<string name="mailbox_setup_download_link">ダウンロードリンクを共有</string> <string name="mailbox_setup_download_link">ダウンロードリンクを共有</string>
<string name="mailbox_setup_button_scan">メールボックスのQRコードを読み取る</string> <string name="mailbox_setup_button_scan">メールボックスのQRコードを読み取る</string>
@@ -585,15 +591,15 @@
<string name="mailbox_qr_code_too_new">読み取ったQRコードは、新しいバージョンのBriarメールボックスから生じました。\n\nBriarを最新版にアップグレードしてから、もう一度お試しください。</string> <string name="mailbox_qr_code_too_new">読み取ったQRコードは、新しいバージョンのBriarメールボックスから生じました。\n\nBriarを最新版にアップグレードしてから、もう一度お試しください。</string>
<string name="contact_qr_code_for_mailbox">読み取ったQRコードは、Briarの連絡先を追加するためのものです。\n\n連絡先を追加したいならば、連絡先一覧に行き、+アイコンをタップしてください。</string> <string name="contact_qr_code_for_mailbox">読み取ったQRコードは、Briarの連絡先を追加するためのものです。\n\n連絡先を追加したいならば、連絡先一覧に行き、+アイコンをタップしてください。</string>
<string name="mailbox_setup_qr_code_wrong_description">読み取ったQRコードは、Briarメールボックスから生じたものではありません。メールボックス端末上のBriarメールボックスアプリを開き、提示されたQRコードを読み取ってください。</string> <string name="mailbox_setup_qr_code_wrong_description">読み取ったQRコードは、Briarメールボックスから生じたものではありません。メールボックス端末上のBriarメールボックスアプリを開き、提示されたQRコードを読み取ってください。</string>
<string name="mailbox_setup_already_paired_title">メールボックスは既に結びつけられています</string> <string name="mailbox_setup_already_paired_title">メールボックスは既にリンクされています</string>
<string name="mailbox_setup_already_paired_description">あなたの端末上のメールボックスの結びつけを解き、再試行してください。</string> <string name="mailbox_setup_already_paired_description">あなたの端末上のメールボックスのリンクを解き、再試行してください。</string>
<string name="mailbox_setup_io_error_title">接続できません</string> <string name="mailbox_setup_io_error_title">接続できません</string>
<string name="mailbox_setup_io_error_description">双方の端末がインターネットに接続されていることを確かにして、再試行してください。</string> <string name="mailbox_setup_io_error_description">双方の端末がインターネットに接続されていることを確かにして、再試行してください。</string>
<string name="mailbox_setup_assertion_error_title">メールボックスのエラー</string> <string name="mailbox_setup_assertion_error_title">メールボックスのエラー</string>
<string name="mailbox_setup_assertion_error_description">もし問題が続くのであれば、Briarアプリ経由で匿名データ付きのフィードバックを送信してください。</string> <string name="mailbox_setup_assertion_error_description">もし問題が続くのであれば、Briarアプリ経由で匿名データ付きのフィードバックを送信してください。</string>
<string name="mailbox_setup_camera_error_description">カメラにアクセスできません。端末を再起動してから、もう一度試してみてください。</string> <string name="mailbox_setup_camera_error_description">カメラにアクセスできません。端末を再起動してから、もう一度試してみてください。</string>
<string name="mailbox_setup_paired_title">接続済み</string> <string name="mailbox_setup_paired_title">接続済み</string>
<string name="mailbox_setup_paired_description">あなたのメールボックスはBriarとの結びつけられるのに成功しています。\n <string name="mailbox_setup_paired_description">あなたのメールボックスはBriarとのリンクに成功しています。\n
メールボックスを電源とW-Fiに接続して、常時オンラインにしてください。</string> メールボックスを電源とW-Fiに接続して、常時オンラインにしてください。</string>
<string name="tor_offline_title">オフライン</string> <string name="tor_offline_title">オフライン</string>
<string name="tor_offline_description">この端末がオンラインかつインターネットへの接続が許可されていること確かにしてください。\n <string name="tor_offline_description">この端末がオンラインかつインターネットへの接続が許可されていること確かにしてください。\n
@@ -633,7 +639,7 @@
<string name="mailbox_error_wizard_answer1_1">メールボックスの設定方法が表示される</string> <string name="mailbox_error_wizard_answer1_1">メールボックスの設定方法が表示される</string>
<string name="mailbox_error_wizard_answer1_2">QRコードが表示される</string> <string name="mailbox_error_wizard_answer1_2">QRコードが表示される</string>
<string name="mailbox_error_wizard_answer1_3">「メールボックスは実行中」と表示される</string> <string name="mailbox_error_wizard_answer1_3">「メールボックスは実行中」と表示される</string>
<string name="mailbox_error_wizard_answer1_4">デバイスがオフライン」と表示されます</string> <string name="mailbox_error_wizard_answer1_4">端末がオフライン」と表示されます</string>
<string name="mailbox_error_wizard_info1_1_1">以下のボタンでメールボックスのリンクを解除し、メールボックスの端末の指示に従って再度リンクしてください。</string> <string name="mailbox_error_wizard_info1_1_1">以下のボタンでメールボックスのリンクを解除し、メールボックスの端末の指示に従って再度リンクしてください。</string>
<string name="mailbox_error_wizard_info_1_1_2">以下のボタンでメールボックスのリンクを解除し、QRコードを読み取って再度リンクしてください。</string> <string name="mailbox_error_wizard_info_1_1_2">以下のボタンでメールボックスのリンクを解除し、QRコードを読み取って再度リンクしてください。</string>
<string name="mailbox_error_wizard_info1_1_3">以下のボタンを使用して、Briarとメールボックスの間での接続を確認してください。\n\n <string name="mailbox_error_wizard_info1_1_3">以下のボタンを使用して、Briarとメールボックスの間での接続を確認してください。\n\n
@@ -645,7 +651,7 @@
<string name="mailbox_error_wizard_info3">以下のボタンを使用してメールボックスをリンク解除してください。\n\n古いメールボックスをリンク解除した後、いつでも新しいメールボックスをセットアップできます。</string> <string name="mailbox_error_wizard_info3">以下のボタンを使用してメールボックスをリンク解除してください。\n\n古いメールボックスをリンク解除した後、いつでも新しいメールボックスをセットアップできます。</string>
<!--About--> <!--About-->
<string name="about_title">Tor Project について</string> <string name="about_title">Tor Project について</string>
<string name="briar_version">Briar バージョン: %s</string> <string name="briar_version">Briarバージョン: %s</string>
<string name="tor_version">Tor バージョン: %s</string> <string name="tor_version">Tor バージョン: %s</string>
<string name="links">リンク</string> <string name="links">リンク</string>
<string name="briar_website">\u2022 <a href="">ウェブサイト</a></string> <string name="briar_website">\u2022 <a href="">ウェブサイト</a></string>
@@ -777,7 +783,7 @@
<string name="hotspot_manual_site_address">アドレスURL</string> <string name="hotspot_manual_site_address">アドレスURL</string>
<string name="hotspot_qr_site">あなたの電話機はWi-Fiホットスポットを提供しています。ホットスポットに接続された人は、このQRコードを読み取って、Briarをダウンロードできます。</string> <string name="hotspot_qr_site">あなたの電話機はWi-Fiホットスポットを提供しています。ホットスポットに接続された人は、このQRコードを読み取って、Briarをダウンロードできます。</string>
<!--e.g. Download Briar 1.2.20--> <!--e.g. Download Briar 1.2.20-->
<string name="website_download_title_1">Briar %sをダウンロード</string> <string name="website_download_title_1">Briar%sをダウンロード</string>
<string name="website_download_intro_1">近くの誰かが、あなたとBriarを共有しました。</string> <string name="website_download_intro_1">近くの誰かが、あなたとBriarを共有しました。</string>
<string name="website_download_button">Briarをダウンロード</string> <string name="website_download_button">Briarをダウンロード</string>
<string name="website_download_outro">ダウンロードが完了した後に、ダウンロードしたファイルを開いて、インストールしてください。</string> <string name="website_download_outro">ダウンロードが完了した後に、ダウンロードしたファイルを開いて、インストールしてください。</string>

View File

@@ -477,7 +477,6 @@
<string name="blogs_rss_feeds_import_button">იმპორტი</string> <string name="blogs_rss_feeds_import_button">იმპორტი</string>
<string name="blogs_rss_feeds_import_hint">შეიყვანეთ RSS არხის URL</string> <string name="blogs_rss_feeds_import_hint">შეიყვანეთ RSS არხის URL</string>
<string name="blogs_rss_feeds_import_error">ვწუხვართ! არხის იმპორტირებისას შეცდომა წარმოიშვა.</string> <string name="blogs_rss_feeds_import_error">ვწუხვართ! არხის იმპორტირებისას შეცდომა წარმოიშვა.</string>
<string name="blogs_rss_feeds_import_exists">არხი უკვე იმპორტირებულია.</string>
<string name="blogs_rss_feeds">RSS არხები</string> <string name="blogs_rss_feeds">RSS არხები</string>
<string name="blogs_rss_feeds_manage_imported">იმპორტირებული:</string> <string name="blogs_rss_feeds_manage_imported">იმპორტირებული:</string>
<string name="blogs_rss_feeds_manage_author">ავტორი:</string> <string name="blogs_rss_feeds_manage_author">ავტორი:</string>

View File

@@ -313,6 +313,8 @@
<string name="duplicate_link_dialog_text_3">%1$s ir %2$s išsiuntė jums tą pačią nuorodą.\n\nGali būti, kad vienas iš šių asmenų bando sužinoti kas yra jūsų adresatų sąraše.\n\nNesakykite šiems asmenims, kad gavote tokią pačią nuorodą iš kito asmens.</string> <string name="duplicate_link_dialog_text_3">%1$s ir %2$s išsiuntė jums tą pačią nuorodą.\n\nGali būti, kad vienas iš šių asmenų bando sužinoti kas yra jūsų adresatų sąraše.\n\nNesakykite šiems asmenims, kad gavote tokią pačią nuorodą iš kito asmens.</string>
<string name="pending_contact_updated_toast">Laukiantis adresatas atnaujintas</string> <string name="pending_contact_updated_toast">Laukiantis adresatas atnaujintas</string>
<!--Peer trust levels--> <!--Peer trust levels-->
<string name="peer_trust_level_ourselves"></string>
<string name="peer_trust_level_stranger">Nepažįstamasis</string>
<!--Introductions--> <!--Introductions-->
<string name="introduction_onboarding_title">Supažindinkite savo adresatus</string> <string name="introduction_onboarding_title">Supažindinkite savo adresatus</string>
<string name="introduction_menu_item">Supažindinti</string> <string name="introduction_menu_item">Supažindinti</string>
@@ -442,6 +444,9 @@
<string name="forum_declined_toast">Pakvietimas atmestas</string> <string name="forum_declined_toast">Pakvietimas atmestas</string>
<string name="shared_by_format">Bendrina %s</string> <string name="shared_by_format">Bendrina %s</string>
<string name="forum_invitation_already_sharing">Jau bendrinama</string> <string name="forum_invitation_already_sharing">Jau bendrinama</string>
<string name="forum_invitation_already_invited">Pakvietimas jau išsiųstas</string>
<string name="forum_invitation_invite_received">Pakvietimas jau gautas</string>
<string name="forum_invitation_error">Klaida. Tai yra triktis ir ne jūsų kaltė</string>
<string name="forum_invitation_response_accepted_sent">Jūs priėmėte pakvietimą į forumą iš %s.</string> <string name="forum_invitation_response_accepted_sent">Jūs priėmėte pakvietimą į forumą iš %s.</string>
<string name="forum_invitation_response_declined_sent">Jūs atmetėte pakvietimą į forumą iš %s.</string> <string name="forum_invitation_response_declined_sent">Jūs atmetėte pakvietimą į forumą iš %s.</string>
<string name="forum_invitation_response_declined_auto">Pakvietimas į forumą nuo %s buvo automatiškai atmestas.</string> <string name="forum_invitation_response_declined_auto">Pakvietimas į forumą nuo %s buvo automatiškai atmestas.</string>
@@ -494,8 +499,9 @@
<string name="blogs_rss_feeds_import">Importuoti RSS kanalą</string> <string name="blogs_rss_feeds_import">Importuoti RSS kanalą</string>
<string name="blogs_rss_feeds_import_button">Importuoti</string> <string name="blogs_rss_feeds_import_button">Importuoti</string>
<string name="blogs_rss_feeds_import_hint">Įveskite RSS kanalo URL</string> <string name="blogs_rss_feeds_import_hint">Įveskite RSS kanalo URL</string>
<string name="blogs_rss_feeds_import_progress">Importuojamas RSS kanalas…</string>
<string name="blogs_rss_feeds_import_error">Atleiskite! Importuojant jūsų kanalą, įvyko klaida.</string> <string name="blogs_rss_feeds_import_error">Atleiskite! Importuojant jūsų kanalą, įvyko klaida.</string>
<string name="blogs_rss_feeds_import_exists">Tas kanalas jau yra importuotas.</string> <string name="blogs_rss_feeds_import_title">Importuoti kanalą iš failo</string>
<string name="blogs_rss_feeds">RSS kanalai</string> <string name="blogs_rss_feeds">RSS kanalai</string>
<string name="blogs_rss_feeds_manage_imported">Importuota:</string> <string name="blogs_rss_feeds_manage_imported">Importuota:</string>
<string name="blogs_rss_feeds_manage_author">Autorius:</string> <string name="blogs_rss_feeds_manage_author">Autorius:</string>
@@ -605,6 +611,7 @@
<string name="mailbox_setup_download_link">Bendrinti atsisiuntimo nuorodą</string> <string name="mailbox_setup_download_link">Bendrinti atsisiuntimo nuorodą</string>
<string name="mailbox_setup_button_scan">Skenuoti pašto dėžutės QR kodą</string> <string name="mailbox_setup_button_scan">Skenuoti pašto dėžutės QR kodą</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".--> <!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Tai gali užtrukti iki %1s</string>
<string name="mailbox_setup_already_paired_title">Pašto dėžutė jau susieta</string> <string name="mailbox_setup_already_paired_title">Pašto dėžutė jau susieta</string>
<string name="mailbox_setup_io_error_title">Nepavyko prisijungti</string> <string name="mailbox_setup_io_error_title">Nepavyko prisijungti</string>
<string name="mailbox_setup_io_error_description">Įsitikinkite, kad abu įrenginiai yra prisijungę prie interneto ir bandykite dar kartą.</string> <string name="mailbox_setup_io_error_description">Įsitikinkite, kad abu įrenginiai yra prisijungę prie interneto ir bandykite dar kartą.</string>
@@ -641,6 +648,7 @@
<string name="briar_changelog">\u2022 <a href="">Keitinių žurnalas</a></string> <string name="briar_changelog">\u2022 <a href="">Keitinių žurnalas</a></string>
<string name="briar_privacy_policy">\u2022 <a href="">Privatumo politika</a></string> <string name="briar_privacy_policy">\u2022 <a href="">Privatumo politika</a></string>
<!--Here translators can add their names or Transifex usernames(eg "Thanks to all the contributors at the Localization Lab, especially Tom, Matthew and Jerry")--> <!--Here translators can add their names or Transifex usernames(eg "Thanks to all the contributors at the Localization Lab, especially Tom, Matthew and Jerry")-->
<string name="translator_thanks">Dėkojame talkininkams iš Localization Lab, ypač Moo už vertimą į lietuvių kalbą</string>
<!--Conversation Settings--> <!--Conversation Settings-->
<string name="disappearing_messages_title">Išnykstančios žinutės</string> <string name="disappearing_messages_title">Išnykstančios žinutės</string>
<string name="disappearing_messages_explanation_long">Įjungus šį nustatymą, naujos žinutės <string name="disappearing_messages_explanation_long">Įjungus šį nustatymą, naujos žinutės

View File

@@ -460,7 +460,6 @@
<string name="blogs_rss_feeds_import_button">တင်သွင်းမည်</string> <string name="blogs_rss_feeds_import_button">တင်သွင်းမည်</string>
<string name="blogs_rss_feeds_import_hint">RSS သတင်းပို့စ်အလွှာ၏ URL ရိုက်ထည့်ပေးပါ</string> <string name="blogs_rss_feeds_import_hint">RSS သတင်းပို့စ်အလွှာ၏ URL ရိုက်ထည့်ပေးပါ</string>
<string name="blogs_rss_feeds_import_error">ဝမ်းနည်းပါသည်! သင့် သတင်းပို့စ်အလွှာအား တင်သွင်းရာတွင် ပျက်ကွက်မှု ဖြစ်ခဲ့ပါသည်။</string> <string name="blogs_rss_feeds_import_error">ဝမ်းနည်းပါသည်! သင့် သတင်းပို့စ်အလွှာအား တင်သွင်းရာတွင် ပျက်ကွက်မှု ဖြစ်ခဲ့ပါသည်။</string>
<string name="blogs_rss_feeds_import_exists">Feed ကို တင်ပို့ပြီး ဖြစ်သည်။</string>
<string name="blogs_rss_feeds">RSS သတင်းလွှာများ</string> <string name="blogs_rss_feeds">RSS သတင်းလွှာများ</string>
<string name="blogs_rss_feeds_manage_imported">တင်သွင်းထားသော</string> <string name="blogs_rss_feeds_manage_imported">တင်သွင်းထားသော</string>
<string name="blogs_rss_feeds_manage_author">စာရေးဆရာ -</string> <string name="blogs_rss_feeds_manage_author">စာရေးဆရာ -</string>

View File

@@ -477,7 +477,6 @@
<string name="blogs_rss_feeds_import_button">Importer</string> <string name="blogs_rss_feeds_import_button">Importer</string>
<string name="blogs_rss_feeds_import_hint">Skriv inn nettadresse for RSS-strøm</string> <string name="blogs_rss_feeds_import_hint">Skriv inn nettadresse for RSS-strøm</string>
<string name="blogs_rss_feeds_import_error">Vi beklager! Feil under importering av strøm.</string> <string name="blogs_rss_feeds_import_error">Vi beklager! Feil under importering av strøm.</string>
<string name="blogs_rss_feeds_import_exists">Den feed\'en er importert allerede</string>
<string name="blogs_rss_feeds">RSS-feed\'er</string> <string name="blogs_rss_feeds">RSS-feed\'er</string>
<string name="blogs_rss_feeds_manage_imported">Importert:</string> <string name="blogs_rss_feeds_manage_imported">Importert:</string>
<string name="blogs_rss_feeds_manage_author">Forfatter:</string> <string name="blogs_rss_feeds_manage_author">Forfatter:</string>

View File

@@ -244,6 +244,7 @@
<string name="menu_contact">Kontakt</string> <string name="menu_contact">Kontakt</string>
<!--Adding Contacts--> <!--Adding Contacts-->
<string name="add_contact_title">Dodaj kontakt w pobliżu</string> <string name="add_contact_title">Dodaj kontakt w pobliżu</string>
<string name="add_contact_error_two_way">Czy oboje skanowaliście nawzajem swoje kody QR?</string>
<string name="face_to_face">Musisz spotkać się z osobą którą chcesz dodać jako kontakt.\n\nTo uniemożliwi komukolwiek udawanie Ciebie lub czytanie Twoich wiadomości w przyszłości.</string> <string name="face_to_face">Musisz spotkać się z osobą którą chcesz dodać jako kontakt.\n\nTo uniemożliwi komukolwiek udawanie Ciebie lub czytanie Twoich wiadomości w przyszłości.</string>
<string name="continue_button">Kontynuuj</string> <string name="continue_button">Kontynuuj</string>
<string name="try_again_button">Spróbuj ponownie</string> <string name="try_again_button">Spróbuj ponownie</string>
@@ -259,6 +260,7 @@
<string name="authenticating_with_device">Autoryzowanie 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_title">Nie udało się połączyć z kontaktem</string>
<string name="connection_error_feedback">Jeśli problem będzie występować dalej, proszę <a href="feedback">wysłać opinię</a> aby pomóc nam ulepszyć aplikację.</string> <string name="connection_error_feedback">Jeśli problem będzie występować dalej, proszę <a href="feedback">wysłać opinię</a> aby pomóc nam ulepszyć aplikację.</string>
<string name="info_both_must_scan">Oboje musicie skanować nawzajem swoje kody QR</string>
<!--Adding Contacts Remotely--> <!--Adding Contacts Remotely-->
<string name="add_contact_remotely_title_case">Dodaj Kontakt na odległość</string> <string name="add_contact_remotely_title_case">Dodaj Kontakt na odległość</string>
<string name="add_contact_nearby_title">Dodaj kontakt w pobliżu</string> <string name="add_contact_nearby_title">Dodaj kontakt w pobliżu</string>
@@ -318,6 +320,7 @@
<string name="different_person_button">Inna osoba</string> <string name="different_person_button">Inna osoba</string>
<string name="duplicate_link_dialog_text_3">%1$si %2$s wysłał ci ten sam link.\n\nJeden z nich może próbować odkryć, kim są twoje kontakty.\n\nNie mów im, że otrzymałeś ten sam link od kogoś innego.</string> <string name="duplicate_link_dialog_text_3">%1$si %2$s wysłał ci ten sam link.\n\nJeden z nich może próbować odkryć, kim są twoje kontakty.\n\nNie mów im, że otrzymałeś ten sam link od kogoś innego.</string>
<string name="pending_contact_updated_toast">Oczekujący kontakt zaktualizowany</string> <string name="pending_contact_updated_toast">Oczekujący kontakt zaktualizowany</string>
<string name="info_both_must_enter_links">Oboje musicie dodać swoje linki</string>
<!--Peer trust levels--> <!--Peer trust levels-->
<string name="peer_trust_level_unverified">Niezweryfikowane kontakty</string> <string name="peer_trust_level_unverified">Niezweryfikowane kontakty</string>
<string name="peer_trust_level_verified">Zweryfikowane kontakty</string> <string name="peer_trust_level_verified">Zweryfikowane kontakty</string>
@@ -351,6 +354,7 @@
<string name="connect_via_bluetooth_intro">W przypadku gdy połączenia przez Bluetooth nie działają automatycznie, możesz użyć tego ekranu do połączenia ręcznego.\n\nTwój kontakt musi znajdować się w pobliżu, żeby to zadziałało.\n\nTy i Twój kontakt powinniście jednocześnie wcisnąć \"Start\".</string> <string name="connect_via_bluetooth_intro">W przypadku gdy połączenia przez Bluetooth nie działają automatycznie, możesz użyć tego ekranu do połączenia ręcznego.\n\nTwój kontakt musi znajdować się w pobliżu, żeby to zadziałało.\n\nTy i Twój kontakt powinniście jednocześnie wcisnąć \"Start\".</string>
<string name="connect_via_bluetooth_already_discovering">Próba połączenia przez Bluetooth jest już w trakcie. Spróbuj ponownie za chwilę.</string> <string name="connect_via_bluetooth_already_discovering">Próba połączenia przez Bluetooth jest już w trakcie. Spróbuj ponownie za chwilę.</string>
<string name="connect_via_bluetooth_no_location_permission">Nie można kontynuować bez dostępu do lokalizacji</string> <string name="connect_via_bluetooth_no_location_permission">Nie można kontynuować bez dostępu do lokalizacji</string>
<string name="connect_via_bluetooth_no_bluetooth_permission">Nie można kontynuować bez pozwolenia na urządzenia w pobliżu</string>
<string name="connect_via_bluetooth_start">Łączenie przez Bluetooth...</string> <string name="connect_via_bluetooth_start">Łączenie przez Bluetooth...</string>
<string name="connect_via_bluetooth_success">Udało się połączyć przez Bluetooth.</string> <string name="connect_via_bluetooth_success">Udało się połączyć przez Bluetooth.</string>
<string name="connect_via_bluetooth_error">Nie można się połączyć przez Bluetooth.</string> <string name="connect_via_bluetooth_error">Nie można się połączyć przez Bluetooth.</string>
@@ -453,6 +457,10 @@
<string name="forum_declined_toast">Zaproszenie odrzucone</string> <string name="forum_declined_toast">Zaproszenie odrzucone</string>
<string name="shared_by_format">Udostępnione przez %s</string> <string name="shared_by_format">Udostępnione przez %s</string>
<string name="forum_invitation_already_sharing">Już udostępnione</string> <string name="forum_invitation_already_sharing">Już udostępnione</string>
<string name="forum_invitation_already_invited">Wysłano już zaproszenie</string>
<string name="forum_invitation_invite_received">Odebrano już zaproszenie</string>
<string name="forum_invitation_not_supported">Nie obsługiwane przez ten kontakt</string>
<string name="forum_invitation_error">Błąd. Jest to błąd w naszej aplikacji, to nie twoja wina</string>
<string name="forum_invitation_response_accepted_sent">Przyjąłeś zaproszenie do forum od %s</string> <string name="forum_invitation_response_accepted_sent">Przyjąłeś zaproszenie do forum od %s</string>
<string name="forum_invitation_response_declined_sent">Odrzuciłeś zaproszenie do forum od %s</string> <string name="forum_invitation_response_declined_sent">Odrzuciłeś zaproszenie do forum od %s</string>
<string name="forum_invitation_response_declined_auto">Zaproszenie do forum od %s zostało automatycznie odrzucone.</string> <string name="forum_invitation_response_declined_auto">Zaproszenie do forum od %s zostało automatycznie odrzucone.</string>
@@ -505,8 +513,9 @@
<string name="blogs_rss_feeds_import">Zaimportuj kanał RSS</string> <string name="blogs_rss_feeds_import">Zaimportuj kanał RSS</string>
<string name="blogs_rss_feeds_import_button">Zaimportuj</string> <string name="blogs_rss_feeds_import_button">Zaimportuj</string>
<string name="blogs_rss_feeds_import_hint">Wprowadź adres URL do kanału RSS</string> <string name="blogs_rss_feeds_import_hint">Wprowadź adres URL do kanału RSS</string>
<string name="blogs_rss_feeds_import_progress">Importowanie kanału RSS…</string>
<string name="blogs_rss_feeds_import_error">Przepraszamy! Wystąpił błąd podczas importowania twojego kanału RSS</string> <string name="blogs_rss_feeds_import_error">Przepraszamy! Wystąpił błąd podczas importowania twojego kanału RSS</string>
<string name="blogs_rss_feeds_import_exists">Ten feed został już zaimportowany.</string> <string name="blogs_rss_feeds_import_title">Importuj kanał z pliku</string>
<string name="blogs_rss_feeds">Feedy RSS</string> <string name="blogs_rss_feeds">Feedy RSS</string>
<string name="blogs_rss_feeds_manage_imported">Zaimportowane:</string> <string name="blogs_rss_feeds_manage_imported">Zaimportowane:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>
@@ -618,7 +627,9 @@
<string name="mailbox_setup_download_link">Udostępnij łącze pobierania</string> <string name="mailbox_setup_download_link">Udostępnij łącze pobierania</string>
<string name="mailbox_setup_button_scan">Zeskanuj kod QR aplikacji Mailbox</string> <string name="mailbox_setup_button_scan">Zeskanuj kod QR aplikacji Mailbox</string>
<string name="permission_camera_qr_denied_body">Odmówiłeś dostępu do aparatu, ale zeskanowanie kodu QR wymaga użycia aparatu.\n\nRozważ przyznanie dostępu.</string> <string name="permission_camera_qr_denied_body">Odmówiłeś dostępu do aparatu, ale zeskanowanie kodu QR wymaga użycia aparatu.\n\nRozważ przyznanie dostępu.</string>
<string name="mailbox_setup_connecting">Łączenie się ze Skrzynką odbiorczą…</string>
<!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".--> <!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_connecting_info">Może to potrwać do %1s</string>
<string name="mailbox_setup_already_paired_title">Mailbox już podłączony</string> <string name="mailbox_setup_already_paired_title">Mailbox już podłączony</string>
<string name="mailbox_setup_already_paired_description">Odłącz Mailbox na drugim urządzeniu i spróbuj ponownie.</string> <string name="mailbox_setup_already_paired_description">Odłącz Mailbox na drugim urządzeniu i spróbuj ponownie.</string>
<string name="mailbox_setup_io_error_title">Nie udało się połączyć</string> <string name="mailbox_setup_io_error_title">Nie udało się połączyć</string>
@@ -756,11 +767,15 @@ Brak dostępu do aparatu. Spróbuj ponownie, może po ponownym uruchomieniu urz
<string name="permission_location_request_body">Aby odkryć urządzenia Bluetooth, Briar potrzebuje zezwolenia na dostęp do twojej lokalizacji.\n\nBriar nie przechowuje twojej lokalizacji ani nie udostępnia jej nikomu.</string> <string name="permission_location_request_body">Aby odkryć urządzenia Bluetooth, Briar potrzebuje zezwolenia na dostęp do twojej lokalizacji.\n\nBriar nie przechowuje twojej lokalizacji ani nie udostępnia jej nikomu.</string>
<string name="permission_camera_location_title">Kamera i lokalizacja</string> <string name="permission_camera_location_title">Kamera i lokalizacja</string>
<string name="permission_camera_location_request_body">Aby zeskanować kod QR, Briar potrzebuje dostępu do kamery.\n\nAby odkryć urządzenia Bluetooth, Briar potrzebuje zezwolenia na dostęp do Twojej lokalizacji.\n\nBriar nie przechowuje Twojej lokalizacji ani nie udostępnia jej nikomu.</string> <string name="permission_camera_location_request_body">Aby zeskanować kod QR, Briar potrzebuje dostępu do kamery.\n\nAby odkryć urządzenia Bluetooth, Briar potrzebuje zezwolenia na dostęp do Twojej lokalizacji.\n\nBriar nie przechowuje Twojej lokalizacji ani nie udostępnia jej nikomu.</string>
<string name="permission_camera_bluetooth_title">Aparat i urządzenia w pobliżu</string>
<string name="permission_camera_denied_body">Odmówiłeś dostępu do aparatu, lecz dodawanie kontaktów wymaga jego użycia.\n\nProszę rozważyć udzielenie dostępu do aparatu</string> <string name="permission_camera_denied_body">Odmówiłeś dostępu do aparatu, lecz dodawanie kontaktów wymaga jego użycia.\n\nProszę rozważyć udzielenie dostępu do aparatu</string>
<string name="permission_location_denied_body">Zabroniłeś dostępu do Twojej lokalizacji, ale Briar potrzebuje tego uprawnienia do wykrywania urządzeń Bluetooth.\n\nRozważ przyznanie tego dostępu.</string> <string name="permission_location_denied_body">Zabroniłeś dostępu do Twojej lokalizacji, ale Briar potrzebuje tego uprawnienia do wykrywania urządzeń Bluetooth.\n\nRozważ przyznanie tego dostępu.</string>
<string name="permission_location_setting_title">Ustawienia lokalizacji</string> <string name="permission_location_setting_title">Ustawienia lokalizacji</string>
<string name="permission_location_setting_body">Ustawienie lokalizacji urządzenia musi być włączone, aby można było znaleźć inne urządzenia przez Bluetooth. Włącz lokalizację, aby kontynuować. Później możesz ją ponownie wyłączyć.</string> <string name="permission_location_setting_body">Ustawienie lokalizacji urządzenia musi być włączone, aby można było znaleźć inne urządzenia przez Bluetooth. Włącz lokalizację, aby kontynuować. Później możesz ją ponownie wyłączyć.</string>
<string name="permission_location_setting_button">Włącz lokalizację</string> <string name="permission_location_setting_button">Włącz lokalizację</string>
<string name="permission_bluetooth_title">Pozwolenie do urządzeń w pobliżu</string>
<string name="permission_bluetooth_body">Aby korzystać z komunikacji Bluetooth, Briar potrzebuje uprawnień do znajdowania i łączenia się z pobliskimi urządzeniami.</string>
<string name="permission_bluetooth_denied_body">Odmówiono dostępu do pobliskich urządzeń, ale Briar potrzebuje tego uprawnienia, aby korzystać z Bluetooth.\n\nRozważ udzielenie dostępu.</string>
<string name="qr_code">Kod QR</string> <string name="qr_code">Kod QR</string>
<string name="show_qr_code_fullscreen">Pokaż QR na pełnym ekranie</string> <string name="show_qr_code_fullscreen">Pokaż QR na pełnym ekranie</string>
<!--App Locking--> <!--App Locking-->

View File

@@ -488,7 +488,6 @@
<string name="blogs_rss_feeds_import_button">Importar</string> <string name="blogs_rss_feeds_import_button">Importar</string>
<string name="blogs_rss_feeds_import_hint">Entre a URL do feed RSS</string> <string name="blogs_rss_feeds_import_hint">Entre a URL do feed RSS</string>
<string name="blogs_rss_feeds_import_error">Nós lamentamos! Houve um erro ao importar seu Feed.</string> <string name="blogs_rss_feeds_import_error">Nós lamentamos! Houve um erro ao importar seu Feed.</string>
<string name="blogs_rss_feeds_import_exists">Esse feed já foi importado.</string>
<string name="blogs_rss_feeds">Feeds RSS</string> <string name="blogs_rss_feeds">Feeds RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importado:</string> <string name="blogs_rss_feeds_manage_imported">Importado:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -446,6 +446,10 @@
<string name="forum_declined_toast">Invitația a fost refuzată</string> <string name="forum_declined_toast">Invitația a fost refuzată</string>
<string name="shared_by_format">Partajat de %s</string> <string name="shared_by_format">Partajat de %s</string>
<string name="forum_invitation_already_sharing">Deja partajat</string> <string name="forum_invitation_already_sharing">Deja partajat</string>
<string name="forum_invitation_already_invited">Invitație deja trimisă</string>
<string name="forum_invitation_invite_received">Invitație deja primită</string>
<string name="forum_invitation_not_supported">Nu este susținut de acest contact</string>
<string name="forum_invitation_error">Eroare. Aceasta este o eroare și nu este vina dumneavoastră</string>
<string name="forum_invitation_response_accepted_sent">Ați acceptat invitația la forum de la %s.</string> <string name="forum_invitation_response_accepted_sent">Ați acceptat invitația la forum de la %s.</string>
<string name="forum_invitation_response_declined_sent">Ați refuzat invitația la forum de la %s.</string> <string name="forum_invitation_response_declined_sent">Ați refuzat invitația la forum de la %s.</string>
<string name="forum_invitation_response_declined_auto">Invitația la forumu de la %s a fost refuzată automat.</string> <string name="forum_invitation_response_declined_auto">Invitația la forumu de la %s a fost refuzată automat.</string>
@@ -497,8 +501,9 @@
<string name="blogs_rss_feeds_import">Importați flux RSS</string> <string name="blogs_rss_feeds_import">Importați flux RSS</string>
<string name="blogs_rss_feeds_import_button">Importați</string> <string name="blogs_rss_feeds_import_button">Importați</string>
<string name="blogs_rss_feeds_import_hint">Introduceți adresa URL a fluxului RSS</string> <string name="blogs_rss_feeds_import_hint">Introduceți adresa URL a fluxului RSS</string>
<string name="blogs_rss_feeds_import_progress">Importarea RSS Feed…</string>
<string name="blogs_rss_feeds_import_error">Ne pare rău, dar a apărut o eroare la importarea fluxului dvs.</string> <string name="blogs_rss_feeds_import_error">Ne pare rău, dar a apărut o eroare la importarea fluxului dvs.</string>
<string name="blogs_rss_feeds_import_exists">Fluxul respectiv este deja importat.</string> <string name="blogs_rss_feeds_import_title">Importați feed din fișier</string>
<string name="blogs_rss_feeds">Fluxuri RSS</string> <string name="blogs_rss_feeds">Fluxuri RSS</string>
<string name="blogs_rss_feeds_manage_imported">Importat:</string> <string name="blogs_rss_feeds_manage_imported">Importat:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -462,7 +462,7 @@
<string name="forum_invitation_already_invited">Приглашение уже отправлено</string> <string name="forum_invitation_already_invited">Приглашение уже отправлено</string>
<string name="forum_invitation_invite_received">Приглашение уже получено</string> <string name="forum_invitation_invite_received">Приглашение уже получено</string>
<string name="forum_invitation_not_supported">Не поддерживается этим контактом</string> <string name="forum_invitation_not_supported">Не поддерживается этим контактом</string>
<string name="forum_invitation_error">Ошибка. Это программная ошибка, а не ваша вина</string> <string name="forum_invitation_error">Это ошибка программы. Вы тут ни причем.</string>
<string name="forum_invitation_response_accepted_sent">Вы приняли приглашение на форум от %s.</string> <string name="forum_invitation_response_accepted_sent">Вы приняли приглашение на форум от %s.</string>
<string name="forum_invitation_response_declined_sent">Вы отклонили приглашение на форум от %s.</string> <string name="forum_invitation_response_declined_sent">Вы отклонили приглашение на форум от %s.</string>
<string name="forum_invitation_response_declined_auto">Приглашение на форум от %s было отклонено автоматически.</string> <string name="forum_invitation_response_declined_auto">Приглашение на форум от %s было отклонено автоматически.</string>
@@ -515,8 +515,9 @@
<string name="blogs_rss_feeds_import">Импорт RSS-ленты</string> <string name="blogs_rss_feeds_import">Импорт RSS-ленты</string>
<string name="blogs_rss_feeds_import_button">Импорт</string> <string name="blogs_rss_feeds_import_button">Импорт</string>
<string name="blogs_rss_feeds_import_hint">Введите URL-адрес RSS-ленты</string> <string name="blogs_rss_feeds_import_hint">Введите URL-адрес RSS-ленты</string>
<string name="blogs_rss_feeds_import_progress">Импорт RSS-лент...</string>
<string name="blogs_rss_feeds_import_error">Мы сожалеем! Произошла ошибка при импорте ленты.</string> <string name="blogs_rss_feeds_import_error">Мы сожалеем! Произошла ошибка при импорте ленты.</string>
<string name="blogs_rss_feeds_import_exists">Эта лента уже импортирована.</string> <string name="blogs_rss_feeds_import_title">Импорт ленты из файла</string>
<string name="blogs_rss_feeds">RSS-ленты</string> <string name="blogs_rss_feeds">RSS-ленты</string>
<string name="blogs_rss_feeds_manage_imported">Импортирован:</string> <string name="blogs_rss_feeds_manage_imported">Импортирован:</string>
<string name="blogs_rss_feeds_manage_author">Автор:</string> <string name="blogs_rss_feeds_manage_author">Автор:</string>

View File

@@ -488,8 +488,9 @@ dhe smund të hapet me këtë version.\n\nJu lutemi, përmirësojeni me versi
<string name="blogs_rss_feeds_import">Importoni Prurje RSS</string> <string name="blogs_rss_feeds_import">Importoni Prurje RSS</string>
<string name="blogs_rss_feeds_import_button">Importo</string> <string name="blogs_rss_feeds_import_button">Importo</string>
<string name="blogs_rss_feeds_import_hint">Jepni URL-në e prurjes RSS</string> <string name="blogs_rss_feeds_import_hint">Jepni URL-në e prurjes RSS</string>
<string name="blogs_rss_feeds_import_progress">Po importohet Prurje RSS…</string>
<string name="blogs_rss_feeds_import_error">Na ndjeni! Pati një gabim me importimin e prurjes tuaj.</string> <string name="blogs_rss_feeds_import_error">Na ndjeni! Pati një gabim me importimin e prurjes tuaj.</string>
<string name="blogs_rss_feeds_import_exists">Ajo prurje është importuar tashmë.</string> <string name="blogs_rss_feeds_import_title">Importo prurje nga kartelë</string>
<string name="blogs_rss_feeds">Prurje RSS</string> <string name="blogs_rss_feeds">Prurje RSS</string>
<string name="blogs_rss_feeds_manage_imported">Të importuara:</string> <string name="blogs_rss_feeds_manage_imported">Të importuara:</string>
<string name="blogs_rss_feeds_manage_author">Autor:</string> <string name="blogs_rss_feeds_manage_author">Autor:</string>

View File

@@ -478,7 +478,6 @@ Vänlige installera Briar på en nyare enhet.</string>
<string name="blogs_rss_feeds_import_button">Importera</string> <string name="blogs_rss_feeds_import_button">Importera</string>
<string name="blogs_rss_feeds_import_hint">Skriv URL till RSS-flödet</string> <string name="blogs_rss_feeds_import_hint">Skriv URL till RSS-flödet</string>
<string name="blogs_rss_feeds_import_error">Tyvärr! Något gick fel när flödet skulle importeras.</string> <string name="blogs_rss_feeds_import_error">Tyvärr! Något gick fel när flödet skulle importeras.</string>
<string name="blogs_rss_feeds_import_exists">Det flödet importeras redan.</string>
<string name="blogs_rss_feeds">RSS-flöden</string> <string name="blogs_rss_feeds">RSS-flöden</string>
<string name="blogs_rss_feeds_manage_imported">Importerade:</string> <string name="blogs_rss_feeds_manage_imported">Importerade:</string>
<string name="blogs_rss_feeds_manage_author">Författare:</string> <string name="blogs_rss_feeds_manage_author">Författare:</string>

View File

@@ -482,7 +482,6 @@
<string name="blogs_rss_feeds_import_button">İçe Aktar</string> <string name="blogs_rss_feeds_import_button">İçe Aktar</string>
<string name="blogs_rss_feeds_import_hint">RSS beslemesi URL\'sini girin</string> <string name="blogs_rss_feeds_import_hint">RSS beslemesi URL\'sini girin</string>
<string name="blogs_rss_feeds_import_error">Üzgünüz! RSS beslemeniz içe aktarılırken bir hata oluştu.</string> <string name="blogs_rss_feeds_import_error">Üzgünüz! RSS beslemeniz içe aktarılırken bir hata oluştu.</string>
<string name="blogs_rss_feeds_import_exists">Bu besleme zaten içe aktarılmış.</string>
<string name="blogs_rss_feeds">RSS beslemeleri</string> <string name="blogs_rss_feeds">RSS beslemeleri</string>
<string name="blogs_rss_feeds_manage_imported">İçe Aktarıldı:</string> <string name="blogs_rss_feeds_manage_imported">İçe Aktarıldı:</string>
<string name="blogs_rss_feeds_manage_author">Yazar:</string> <string name="blogs_rss_feeds_manage_author">Yazar:</string>
@@ -594,9 +593,7 @@
<string name="mailbox_setup_download_link">İndirme Bağlantısını Paylaş</string> <string name="mailbox_setup_download_link">İndirme Bağlantısını Paylaş</string>
<string name="mailbox_setup_button_scan">Mailbox Karekodunu Tara</string> <string name="mailbox_setup_button_scan">Mailbox Karekodunu Tara</string>
<string name="permission_camera_qr_denied_body">Kameraya erişimi engellediniz, ancak Mailbox karekodunu taramak için kamerayı kullanmanız gerekiyor.\n\nLütfen erişim izni vermeyi düşünün.</string> <string name="permission_camera_qr_denied_body">Kameraya erişimi engellediniz, ancak Mailbox karekodunu taramak için kamerayı kullanmanız gerekiyor.\n\nLütfen erişim izni vermeyi düşünün.</string>
<string name="mailbox_setup_connecting">Bağlantı kuruluyor…</string> <!--This string is shown when connecting to a Mailbox for the first time. The placeholder will be replaced with a duration, e.g. "2 minutes".-->
<string name="mailbox_setup_qr_code_wrong_title">Yanlış Karekod</string>
<string name="mailbox_setup_qr_code_wrong_description">Taranan kod geçersiz. Lütfen Briar Mailbox uygulamasını Mailbox aygıtınızda açın ve gösterdiği Karekodu tarayın.</string>
<string name="mailbox_setup_already_paired_title">Mailbox zaten bağlanmış</string> <string name="mailbox_setup_already_paired_title">Mailbox zaten bağlanmış</string>
<string name="mailbox_setup_already_paired_description">Diğer aygıttan Mailbox bağlantısını kaldırın ve tekrar deneyin</string> <string name="mailbox_setup_already_paired_description">Diğer aygıttan Mailbox bağlantısını kaldırın ve tekrar deneyin</string>
<string name="mailbox_setup_io_error_title">Bağlantı kurulamıyor</string> <string name="mailbox_setup_io_error_title">Bağlantı kurulamıyor</string>

View File

@@ -505,7 +505,6 @@
<string name="blogs_rss_feeds_import_button">Імпортувати</string> <string name="blogs_rss_feeds_import_button">Імпортувати</string>
<string name="blogs_rss_feeds_import_hint">Введіть URL-посилання RSS-стрічки</string> <string name="blogs_rss_feeds_import_hint">Введіть URL-посилання RSS-стрічки</string>
<string name="blogs_rss_feeds_import_error">Нам шкода! Виникла помилка під час імпорту вашої стрічки.</string> <string name="blogs_rss_feeds_import_error">Нам шкода! Виникла помилка під час імпорту вашої стрічки.</string>
<string name="blogs_rss_feeds_import_exists">Цю стрічку вже імпортовано.</string>
<string name="blogs_rss_feeds">RSS-стрічки</string> <string name="blogs_rss_feeds">RSS-стрічки</string>
<string name="blogs_rss_feeds_manage_imported">Імпортовано:</string> <string name="blogs_rss_feeds_manage_imported">Імпортовано:</string>
<string name="blogs_rss_feeds_manage_author">Автор:</string> <string name="blogs_rss_feeds_manage_author">Автор:</string>

View File

@@ -473,8 +473,9 @@
<string name="blogs_rss_feeds_import">导入 RSS 订阅源</string> <string name="blogs_rss_feeds_import">导入 RSS 订阅源</string>
<string name="blogs_rss_feeds_import_button">导入</string> <string name="blogs_rss_feeds_import_button">导入</string>
<string name="blogs_rss_feeds_import_hint">输入 RSS 订阅源链接</string> <string name="blogs_rss_feeds_import_hint">输入 RSS 订阅源链接</string>
<string name="blogs_rss_feeds_import_progress">导入 RSS 订阅源中…</string>
<string name="blogs_rss_feeds_import_error">抱歉!导入订阅源时发生错误。</string> <string name="blogs_rss_feeds_import_error">抱歉!导入订阅源时发生错误。</string>
<string name="blogs_rss_feeds_import_exists">已经导入那个</string> <string name="blogs_rss_feeds_import_title">从文件导入</string>
<string name="blogs_rss_feeds">RSS源 </string> <string name="blogs_rss_feeds">RSS源 </string>
<string name="blogs_rss_feeds_manage_imported">已导入:</string> <string name="blogs_rss_feeds_manage_imported">已导入:</string>
<string name="blogs_rss_feeds_manage_author">作者:</string> <string name="blogs_rss_feeds_manage_author">作者:</string>

View File

@@ -423,6 +423,10 @@
<string name="forum_declined_toast">邀請已謝絕</string> <string name="forum_declined_toast">邀請已謝絕</string>
<string name="shared_by_format">由 %s 分享</string> <string name="shared_by_format">由 %s 分享</string>
<string name="forum_invitation_already_sharing">已在分享</string> <string name="forum_invitation_already_sharing">已在分享</string>
<string name="forum_invitation_already_invited">已發送邀請</string>
<string name="forum_invitation_invite_received">已收到邀請</string>
<string name="forum_invitation_not_supported">此聯絡人無法使用</string>
<string name="forum_invitation_error">出錯,出了點問題與您無關</string>
<string name="forum_invitation_response_accepted_sent">您接受了來自 %s的論壇邀請</string> <string name="forum_invitation_response_accepted_sent">您接受了來自 %s的論壇邀請</string>
<string name="forum_invitation_response_declined_sent">您謝絕了來自 %s的論壇邀請</string> <string name="forum_invitation_response_declined_sent">您謝絕了來自 %s的論壇邀請</string>
<string name="forum_invitation_response_declined_auto">來自%s論壇的邀請已自動拒絕</string> <string name="forum_invitation_response_declined_auto">來自%s論壇的邀請已自動拒絕</string>
@@ -473,7 +477,6 @@
<string name="blogs_rss_feeds_import_button">導入</string> <string name="blogs_rss_feeds_import_button">導入</string>
<string name="blogs_rss_feeds_import_hint">輸入 RSS 訂閱源鏈接</string> <string name="blogs_rss_feeds_import_hint">輸入 RSS 訂閱源鏈接</string>
<string name="blogs_rss_feeds_import_error">抱歉!導入訂閱源時發生錯誤。</string> <string name="blogs_rss_feeds_import_error">抱歉!導入訂閱源時發生錯誤。</string>
<string name="blogs_rss_feeds_import_exists">此來源已滙入</string>
<string name="blogs_rss_feeds">RSS 消息源</string> <string name="blogs_rss_feeds">RSS 消息源</string>
<string name="blogs_rss_feeds_manage_imported">已導入:</string> <string name="blogs_rss_feeds_manage_imported">已導入:</string>
<string name="blogs_rss_feeds_manage_author">作者:</string> <string name="blogs_rss_feeds_manage_author">作者:</string>

View File

@@ -519,7 +519,9 @@
<string name="blogs_rss_feeds_import">Import RSS Feed</string> <string name="blogs_rss_feeds_import">Import RSS Feed</string>
<string name="blogs_rss_feeds_import_button">Import</string> <string name="blogs_rss_feeds_import_button">Import</string>
<string name="blogs_rss_feeds_import_hint">Enter the URL of the RSS feed</string> <string name="blogs_rss_feeds_import_hint">Enter the URL of the RSS feed</string>
<string name="blogs_rss_feeds_import_progress">Importing RSS Feed…</string>
<string name="blogs_rss_feeds_import_error">We are sorry! There was an error importing your feed.</string> <string name="blogs_rss_feeds_import_error">We are sorry! There was an error importing your feed.</string>
<string name="blogs_rss_feeds_import_title">Import feed from file</string>
<string name="blogs_rss_feeds">RSS Feeds</string> <string name="blogs_rss_feeds">RSS Feeds</string>
<string name="blogs_rss_feeds_manage_imported">Imported:</string> <string name="blogs_rss_feeds_manage_imported">Imported:</string>
<string name="blogs_rss_feeds_manage_author">Author:</string> <string name="blogs_rss_feeds_manage_author">Author:</string>

View File

@@ -56,7 +56,7 @@ public class AttachmentReaderImpl implements AttachmentReader {
String contentType = meta.getString(MSG_KEY_CONTENT_TYPE); String contentType = meta.getString(MSG_KEY_CONTENT_TYPE);
if (!contentType.equals(h.getContentType())) if (!contentType.equals(h.getContentType()))
throw new NoSuchMessageException(); throw new NoSuchMessageException();
int offset = meta.getLong(MSG_KEY_DESCRIPTOR_LENGTH).intValue(); int offset = meta.getInt(MSG_KEY_DESCRIPTOR_LENGTH);
InputStream stream = new ByteArrayInputStream(body, offset, InputStream stream = new ByteArrayInputStream(body, offset,
body.length - offset); body.length - offset);
return new Attachment(h, stream); return new Attachment(h, stream);

View File

@@ -250,7 +250,7 @@ class AvatarManagerImpl implements AvatarManager, OpenDatabaseHook, ContactHook,
try { try {
BdfDictionary meta = BdfDictionary meta =
clientHelper.getGroupMetadataAsDictionary(txn, g); clientHelper.getGroupMetadataAsDictionary(txn, g);
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); return new ContactId(meta.getInt(GROUP_KEY_CONTACT_ID));
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }

View File

@@ -76,7 +76,7 @@ class AvatarValidator implements MessageValidator {
// 0.0: Message Type, Version, Content-Type // 0.0: Message Type, Version, Content-Type
checkSize(body, 3); checkSize(body, 3);
// Message Type // Message Type
long messageType = body.getLong(0); int messageType = body.getInt(0);
if (messageType != MSG_TYPE_UPDATE) throw new FormatException(); if (messageType != MSG_TYPE_UPDATE) throw new FormatException();
// Version // Version
long version = body.getLong(1); long version = body.getLong(1);

View File

@@ -487,7 +487,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
} }
private String getPostText(BdfList message) throws FormatException { private String getPostText(BdfList message) throws FormatException {
MessageType type = MessageType.valueOf(message.getLong(0).intValue()); MessageType type = MessageType.valueOf(message.getInt(0));
if (type == POST) { if (type == POST) {
// Type, text, signature // Type, text, signature
return message.getString(1); return message.getString(1);
@@ -621,7 +621,6 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
} }
private MessageType getMessageType(BdfDictionary d) throws FormatException { private MessageType getMessageType(BdfDictionary d) throws FormatException {
Long longType = d.getLong(KEY_TYPE); return MessageType.valueOf(d.getInt(KEY_TYPE));
return MessageType.valueOf(longType.intValue());
} }
} }

View File

@@ -167,6 +167,6 @@ class BlogPostFactoryImpl implements BlogPostFactory {
} }
private MessageType getType(BdfList body) throws FormatException { private MessageType getType(BdfList body) throws FormatException {
return MessageType.valueOf(body.getLong(0).intValue()); return MessageType.valueOf(body.getInt(0));
} }
} }

View File

@@ -72,7 +72,7 @@ class BlogPostValidator extends BdfMessageValidator {
BdfMessageContext c; BdfMessageContext c;
int type = body.getLong(0).intValue(); int type = body.getInt(0);
body.remove(0); body.remove(0);
switch (MessageType.valueOf(type)) { switch (MessageType.valueOf(type)) {
case POST: case POST:

View File

@@ -114,8 +114,8 @@ class MessageTrackerImpl implements MessageTracker {
try { try {
BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g); BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g);
return new GroupCount( return new GroupCount(
d.getLong(GROUP_KEY_MSG_COUNT, 0L).intValue(), d.getInt(GROUP_KEY_MSG_COUNT, 0),
d.getLong(GROUP_KEY_UNREAD_COUNT, 0L).intValue(), d.getInt(GROUP_KEY_UNREAD_COUNT, 0),
d.getLong(GROUP_KEY_LATEST_MSG, 0L) d.getLong(GROUP_KEY_LATEST_MSG, 0L)
); );
} catch (FormatException e) { } catch (FormatException e) {

View File

@@ -47,7 +47,7 @@ class IntroductionValidator extends BdfMessageValidator {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException { BdfList body) throws FormatException {
MessageType type = MessageType.fromValue(body.getLong(0).intValue()); MessageType type = MessageType.fromValue(body.getInt(0));
switch (type) { switch (type) {
case REQUEST: case REQUEST:

View File

@@ -59,8 +59,8 @@ class MessageParserImpl implements MessageParser {
@Override @Override
public MessageMetadata parseMetadata(BdfDictionary d) public MessageMetadata parseMetadata(BdfDictionary d)
throws FormatException { throws FormatException {
MessageType type = MessageType MessageType type =
.fromValue(d.getLong(MSG_KEY_MESSAGE_TYPE).intValue()); MessageType.fromValue(d.getInt(MSG_KEY_MESSAGE_TYPE));
byte[] sessionIdBytes = d.getOptionalRaw(MSG_KEY_SESSION_ID); byte[] sessionIdBytes = d.getOptionalRaw(MSG_KEY_SESSION_ID);
SessionId sessionId = SessionId sessionId =
sessionIdBytes == null ? null : new SessionId(sessionIdBytes); sessionIdBytes == null ? null : new SessionId(sessionIdBytes);

View File

@@ -72,7 +72,7 @@ class SessionParserImpl implements SessionParser {
@Override @Override
public Role getRole(BdfDictionary d) throws FormatException { public Role getRole(BdfDictionary d) throws FormatException {
return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue()); return Role.fromValue(d.getInt(SESSION_KEY_ROLE));
} }
@Override @Override
@@ -97,7 +97,7 @@ class SessionParserImpl implements SessionParser {
MessageId lastRemoteMessageId = MessageId lastRemoteMessageId =
getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID); getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID);
long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP); long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP);
GroupId groupId = getGroupId(d, SESSION_KEY_GROUP_ID); GroupId groupId = getGroupId(d);
Author author = getAuthor(d, SESSION_KEY_AUTHOR); Author author = getAuthor(d, SESSION_KEY_AUTHOR);
return new Introducee(sessionId, groupId, author, localTimestamp, return new Introducee(sessionId, groupId, author, localTimestamp,
lastLocalMessageId, lastRemoteMessageId); lastLocalMessageId, lastRemoteMessageId);
@@ -126,12 +126,10 @@ class SessionParserImpl implements SessionParser {
MessageId lastLocalMessageId = MessageId lastLocalMessageId =
getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID); getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID);
long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP); long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP);
PublicKey ephemeralPublicKey = PublicKey ephemeralPublicKey = getEphemeralPublicKey(d);
getEphemeralPublicKey(d, SESSION_KEY_EPHEMERAL_PUBLIC_KEY);
BdfDictionary tpDict = BdfDictionary tpDict =
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES); d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES);
PrivateKey ephemeralPrivateKey = PrivateKey ephemeralPrivateKey = getEphemeralPrivateKey(d);
getEphemeralPrivateKey(d, SESSION_KEY_EPHEMERAL_PRIVATE_KEY);
Map<TransportId, TransportProperties> transportProperties = Map<TransportId, TransportProperties> transportProperties =
tpDict == null ? null : clientHelper tpDict == null ? null : clientHelper
.parseAndValidateTransportPropertiesMap(tpDict); .parseAndValidateTransportPropertiesMap(tpDict);
@@ -147,8 +145,7 @@ class SessionParserImpl implements SessionParser {
Author remoteAuthor = getAuthor(d, SESSION_KEY_REMOTE_AUTHOR); Author remoteAuthor = getAuthor(d, SESSION_KEY_REMOTE_AUTHOR);
MessageId lastRemoteMessageId = MessageId lastRemoteMessageId =
getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID); getMessageId(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID);
PublicKey ephemeralPublicKey = PublicKey ephemeralPublicKey = getEphemeralPublicKey(d);
getEphemeralPublicKey(d, SESSION_KEY_EPHEMERAL_PUBLIC_KEY);
BdfDictionary tpDict = BdfDictionary tpDict =
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES); d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES);
Map<TransportId, TransportProperties> transportProperties = Map<TransportId, TransportProperties> transportProperties =
@@ -162,7 +159,7 @@ class SessionParserImpl implements SessionParser {
} }
private int getState(BdfDictionary d) throws FormatException { private int getState(BdfDictionary d) throws FormatException {
return d.getLong(SESSION_KEY_STATE).intValue(); return d.getInt(SESSION_KEY_STATE);
} }
private SessionId getSessionId(BdfDictionary d) throws FormatException { private SessionId getSessionId(BdfDictionary d) throws FormatException {
@@ -177,9 +174,8 @@ class SessionParserImpl implements SessionParser {
return b == null ? null : new MessageId(b); return b == null ? null : new MessageId(b);
} }
private GroupId getGroupId(BdfDictionary d, String key) private GroupId getGroupId(BdfDictionary d) throws FormatException {
throws FormatException { return new GroupId(d.getRaw(SESSION_KEY_GROUP_ID));
return new GroupId(d.getRaw(key));
} }
private Author getAuthor(BdfDictionary d, String key) private Author getAuthor(BdfDictionary d, String key)
@@ -193,23 +189,22 @@ class SessionParserImpl implements SessionParser {
if (d == null) return null; if (d == null) return null;
Map<TransportId, KeySetId> map = new HashMap<>(d.size()); Map<TransportId, KeySetId> map = new HashMap<>(d.size());
for (String key : d.keySet()) { for (String key : d.keySet()) {
map.put(new TransportId(key), map.put(new TransportId(key), new KeySetId(d.getInt(key)));
new KeySetId(d.getLong(key).intValue()));
} }
return map; return map;
} }
@Nullable @Nullable
private PublicKey getEphemeralPublicKey(BdfDictionary d, String key) private PublicKey getEphemeralPublicKey(BdfDictionary d)
throws FormatException { throws FormatException {
byte[] keyBytes = d.getOptionalRaw(key); byte[] keyBytes = d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PUBLIC_KEY);
return keyBytes == null ? null : new AgreementPublicKey(keyBytes); return keyBytes == null ? null : new AgreementPublicKey(keyBytes);
} }
@Nullable @Nullable
private PrivateKey getEphemeralPrivateKey(BdfDictionary d, String key) private PrivateKey getEphemeralPrivateKey(BdfDictionary d)
throws FormatException { throws FormatException {
byte[] keyBytes = d.getOptionalRaw(key); byte[] keyBytes = d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PRIVATE_KEY);
return keyBytes == null ? null : new AgreementPrivateKey(keyBytes); return keyBytes == null ? null : new AgreementPrivateKey(keyBytes);
} }
} }

View File

@@ -182,7 +182,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
try { try {
BdfDictionary metaDict = metadataParser.parse(meta); BdfDictionary metaDict = metadataParser.parse(meta);
// Message type is null for version 0.0 private messages // Message type is null for version 0.0 private messages
Long messageType = metaDict.getOptionalLong(MSG_KEY_MSG_TYPE); Integer messageType = metaDict.getOptionalInt(MSG_KEY_MSG_TYPE);
if (messageType == null) { if (messageType == null) {
incomingPrivateMessage(txn, m, metaDict, true, emptyList()); incomingPrivateMessage(txn, m, metaDict, true, emptyList());
} else if (messageType == PRIVATE_MESSAGE) { } else if (messageType == PRIVATE_MESSAGE) {
@@ -371,7 +371,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
try { try {
BdfDictionary meta = BdfDictionary meta =
clientHelper.getGroupMetadataAsDictionary(txn, g); clientHelper.getGroupMetadataAsDictionary(txn, g);
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); return new ContactId(meta.getInt(GROUP_KEY_CONTACT_ID));
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -381,7 +381,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
public ContactId getContactId(GroupId g) throws DbException { public ContactId getContactId(GroupId g) throws DbException {
try { try {
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(g); BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(g);
return new ContactId(meta.getLong(GROUP_KEY_CONTACT_ID).intValue()); return new ContactId(meta.getInt(GROUP_KEY_CONTACT_ID));
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -419,7 +419,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
if (meta == null) continue; if (meta == null) continue;
try { try {
// Message type is null for version 0.0 private messages // Message type is null for version 0.0 private messages
Long messageType = meta.getOptionalLong(MSG_KEY_MSG_TYPE); Integer messageType = meta.getOptionalInt(MSG_KEY_MSG_TYPE);
if (messageType != null && messageType != PRIVATE_MESSAGE) if (messageType != null && messageType != PRIVATE_MESSAGE)
continue; continue;
long timestamp = meta.getLong(MSG_KEY_TIMESTAMP); long timestamp = meta.getLong(MSG_KEY_TIMESTAMP);
@@ -453,7 +453,8 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
Map<MessageId, BdfDictionary> messages = Map<MessageId, BdfDictionary> messages =
clientHelper.getMessageMetadataAsDictionary(txn, g); clientHelper.getMessageMetadataAsDictionary(txn, g);
for (Entry<MessageId, BdfDictionary> entry : messages.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : messages.entrySet()) {
Long type = entry.getValue().getOptionalLong(MSG_KEY_MSG_TYPE); Integer type =
entry.getValue().getOptionalInt(MSG_KEY_MSG_TYPE);
if (type == null || type == PRIVATE_MESSAGE) if (type == null || type == PRIVATE_MESSAGE)
result.add(entry.getKey()); result.add(entry.getKey());
} }
@@ -527,7 +528,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
try { try {
BdfDictionary meta = BdfDictionary meta =
clientHelper.getMessageMetadataAsDictionary(txn, m); clientHelper.getMessageMetadataAsDictionary(txn, m);
Long messageType = meta.getOptionalLong(MSG_KEY_MSG_TYPE); Integer messageType = meta.getOptionalInt(MSG_KEY_MSG_TYPE);
if (messageType != null && messageType == PRIVATE_MESSAGE) { if (messageType != null && messageType == PRIVATE_MESSAGE) {
for (AttachmentHeader h : parseAttachmentHeaders(g, meta)) { for (AttachmentHeader h : parseAttachmentHeaders(g, meta)) {
try { try {
@@ -554,7 +555,7 @@ class MessagingManagerImpl implements MessagingManager, IncomingMessageHook,
int unreadCount = 0; int unreadCount = 0;
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
BdfDictionary meta = entry.getValue(); BdfDictionary meta = entry.getValue();
Long messageType = meta.getOptionalLong(MSG_KEY_MSG_TYPE); Integer messageType = meta.getOptionalInt(MSG_KEY_MSG_TYPE);
if (messageType == null || messageType == PRIVATE_MESSAGE) { if (messageType == null || messageType == PRIVATE_MESSAGE) {
msgCount++; msgCount++;
if (!meta.getBoolean(MSG_KEY_READ)) unreadCount++; if (!meta.getBoolean(MSG_KEY_READ)) unreadCount++;

View File

@@ -84,7 +84,7 @@ class PrivateMessageValidator implements MessageValidator {
context = validateLegacyPrivateMessage(m, list); context = validateLegacyPrivateMessage(m, list);
} else { } else {
// Private message or attachment // Private message or attachment
int messageType = list.getLong(0).intValue(); int messageType = list.getInt(0);
if (messageType == PRIVATE_MESSAGE) { if (messageType == PRIVATE_MESSAGE) {
if (!reader.eof()) throw new FormatException(); if (!reader.eof()) throw new FormatException();
context = validatePrivateMessage(m, list); context = validatePrivateMessage(m, list);

View File

@@ -63,7 +63,7 @@ class GroupMessageValidator extends BdfMessageValidator {
checkSize(body, 4, 6); checkSize(body, 4, 6);
// Message type (int) // Message type (int)
int type = body.getLong(0).intValue(); int type = body.getInt(0);
// Member (author) // Member (author)
BdfList memberList = body.getList(1); BdfList memberList = body.getList(1);

View File

@@ -366,7 +366,7 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
// parse the metadata // parse the metadata
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
BdfDictionary meta = entry.getValue(); BdfDictionary meta = entry.getValue();
if (meta.getLong(KEY_TYPE) == JOIN.getInt()) { if (meta.getInt(KEY_TYPE) == JOIN.getInt()) {
headers.add(getJoinMessageHeader(txn, g, entry.getKey(), headers.add(getJoinMessageHeader(txn, g, entry.getKey(),
meta, authorInfos)); meta, authorInfos));
} else { } else {
@@ -530,8 +530,7 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
BdfList body, BdfDictionary meta) BdfList body, BdfDictionary meta)
throws DbException, FormatException { throws DbException, FormatException {
MessageType type = MessageType type = MessageType.valueOf(meta.getInt(KEY_TYPE));
MessageType.valueOf(meta.getLong(KEY_TYPE).intValue());
switch (type) { switch (type) {
case JOIN: case JOIN:
handleJoinMessage(txn, m, meta); handleJoinMessage(txn, m, meta);
@@ -576,8 +575,8 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
.getMessageMetadataAsDictionary(txn, parentId); .getMessageMetadataAsDictionary(txn, parentId);
if (timestamp <= parentMeta.getLong(KEY_TIMESTAMP)) if (timestamp <= parentMeta.getLong(KEY_TIMESTAMP))
throw new FormatException(); throw new FormatException();
MessageType parentType = MessageType MessageType parentType =
.valueOf(parentMeta.getLong(KEY_TYPE).intValue()); MessageType.valueOf(parentMeta.getInt(KEY_TYPE));
if (parentType != POST) if (parentType != POST)
throw new FormatException(); throw new FormatException();
} }
@@ -592,8 +591,8 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
if (!getAuthor(meta).equals(getAuthor(previousMeta))) if (!getAuthor(meta).equals(getAuthor(previousMeta)))
throw new FormatException(); throw new FormatException();
// previous message must be a POST or JOIN // previous message must be a POST or JOIN
MessageType previousType = MessageType MessageType previousType =
.valueOf(previousMeta.getLong(KEY_TYPE).intValue()); MessageType.valueOf(previousMeta.getInt(KEY_TYPE));
if (previousType != JOIN && previousType != POST) if (previousType != JOIN && previousType != POST)
throw new FormatException(); throw new FormatException();
// track message and broadcast event // track message and broadcast event
@@ -641,8 +640,7 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
private Visibility getVisibility(BdfDictionary meta) private Visibility getVisibility(BdfDictionary meta)
throws FormatException { throws FormatException {
return Visibility return Visibility.valueOf(meta.getInt(GROUP_KEY_VISIBILITY));
.valueOf(meta.getLong(GROUP_KEY_VISIBILITY).intValue());
} }
} }

View File

@@ -712,9 +712,9 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
// get all sessions and their states // get all sessions and their states
Map<GroupId, DeletableSession> sessions = new HashMap<>(); Map<GroupId, DeletableSession> sessions = new HashMap<>();
for (BdfDictionary d : metadata.values()) { for (BdfDictionary d : metadata.values()) {
if (!sessionParser.isSession(d)) continue;
Session<?> session; Session<?> session;
try { try {
if (!sessionParser.isSession(d)) continue;
session = sessionParser.parseSession(g, d); session = sessionParser.parseSession(g, d);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
@@ -776,13 +776,12 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
// assign protocol messages to their sessions // assign protocol messages to their sessions
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
// skip all sessions, we are only interested in messages
BdfDictionary d = entry.getValue();
if (sessionParser.isSession(d)) continue;
// parse message metadata and skip messages not visible in UI // parse message metadata and skip messages not visible in UI
MessageMetadata m; MessageMetadata m;
try { try {
// skip all sessions, we are only interested in messages
BdfDictionary d = entry.getValue();
if (sessionParser.isSession(d)) continue;
m = messageParser.parseMetadata(d); m = messageParser.parseMetadata(d);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);

View File

@@ -56,7 +56,7 @@ class GroupInvitationValidator extends BdfMessageValidator {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException { BdfList body) throws FormatException {
MessageType type = MessageType.fromValue(body.getLong(0).intValue()); MessageType type = MessageType.fromValue(body.getInt(0));
switch (type) { switch (type) {
case INVITE: case INVITE:
return validateInviteMessage(m, body); return validateInviteMessage(m, body);

View File

@@ -71,8 +71,8 @@ class MessageParserImpl implements MessageParser {
@Override @Override
public MessageMetadata parseMetadata(BdfDictionary meta) public MessageMetadata parseMetadata(BdfDictionary meta)
throws FormatException { throws FormatException {
MessageType type = MessageType.fromValue( MessageType type =
meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue()); MessageType.fromValue(meta.getInt(MSG_KEY_MESSAGE_TYPE));
GroupId privateGroupId = GroupId privateGroupId =
new GroupId(meta.getRaw(MSG_KEY_PRIVATE_GROUP_ID)); new GroupId(meta.getRaw(MSG_KEY_PRIVATE_GROUP_ID));
long timestamp = meta.getLong(MSG_KEY_TIMESTAMP); long timestamp = meta.getLong(MSG_KEY_TIMESTAMP);

View File

@@ -15,7 +15,7 @@ interface SessionParser {
Role getRole(BdfDictionary d) throws FormatException; Role getRole(BdfDictionary d) throws FormatException;
boolean isSession(BdfDictionary d); boolean isSession(BdfDictionary d) throws FormatException;
Session parseSession(GroupId contactGroupId, BdfDictionary d) Session parseSession(GroupId contactGroupId, BdfDictionary d)
throws FormatException; throws FormatException;

View File

@@ -45,11 +45,11 @@ class SessionParserImpl implements SessionParser {
@Override @Override
public Role getRole(BdfDictionary d) throws FormatException { public Role getRole(BdfDictionary d) throws FormatException {
return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue()); return Role.fromValue(d.getInt(SESSION_KEY_ROLE));
} }
@Override @Override
public boolean isSession(BdfDictionary d) { public boolean isSession(BdfDictionary d) throws FormatException {
return d.getBoolean(SESSION_KEY_IS_SESSION, false); return d.getBoolean(SESSION_KEY_IS_SESSION, false);
} }
@@ -101,7 +101,7 @@ class SessionParserImpl implements SessionParser {
} }
private int getState(BdfDictionary d) throws FormatException { private int getState(BdfDictionary d) throws FormatException {
return d.getLong(SESSION_KEY_STATE).intValue(); return d.getInt(SESSION_KEY_STATE);
} }
private GroupId getPrivateGroupId(BdfDictionary d) throws FormatException { private GroupId getPrivateGroupId(BdfDictionary d) throws FormatException {

View File

@@ -64,8 +64,8 @@ abstract class MessageParserImpl<S extends Shareable>
@Override @Override
public MessageMetadata parseMetadata(BdfDictionary meta) public MessageMetadata parseMetadata(BdfDictionary meta)
throws FormatException { throws FormatException {
MessageType type = MessageType MessageType type =
.fromValue(meta.getLong(MSG_KEY_MESSAGE_TYPE).intValue()); MessageType.fromValue(meta.getInt(MSG_KEY_MESSAGE_TYPE));
GroupId shareableId = new GroupId(meta.getRaw(MSG_KEY_SHAREABLE_ID)); GroupId shareableId = new GroupId(meta.getRaw(MSG_KEY_SHAREABLE_ID));
long timestamp = meta.getLong(MSG_KEY_TIMESTAMP); long timestamp = meta.getLong(MSG_KEY_TIMESTAMP);
boolean local = meta.getBoolean(MSG_KEY_LOCAL); boolean local = meta.getBoolean(MSG_KEY_LOCAL);

View File

@@ -13,7 +13,7 @@ interface SessionParser {
BdfDictionary getAllSessionsQuery(); BdfDictionary getAllSessionsQuery();
boolean isSession(BdfDictionary d); boolean isSession(BdfDictionary d) throws FormatException;
Session parseSession(GroupId contactGroupId, BdfDictionary d) Session parseSession(GroupId contactGroupId, BdfDictionary d)
throws FormatException; throws FormatException;

View File

@@ -40,7 +40,7 @@ class SessionParserImpl implements SessionParser {
} }
@Override @Override
public boolean isSession(BdfDictionary d) { public boolean isSession(BdfDictionary d) throws FormatException {
return d.getBoolean(SESSION_KEY_IS_SESSION, false); return d.getBoolean(SESSION_KEY_IS_SESSION, false);
} }
@@ -54,7 +54,7 @@ class SessionParserImpl implements SessionParser {
} }
private int getState(BdfDictionary d) throws FormatException { private int getState(BdfDictionary d) throws FormatException {
return d.getLong(SESSION_KEY_STATE).intValue(); return d.getInt(SESSION_KEY_STATE);
} }
private GroupId getShareableId(BdfDictionary d) throws FormatException { private GroupId getShareableId(BdfDictionary d) throws FormatException {

View File

@@ -604,9 +604,9 @@ abstract class SharingManagerImpl<S extends Shareable>
// get all sessions and their states // get all sessions and their states
Map<GroupId, DeletableSession> sessions = new HashMap<>(); Map<GroupId, DeletableSession> sessions = new HashMap<>();
for (BdfDictionary d : metadata.values()) { for (BdfDictionary d : metadata.values()) {
if (!sessionParser.isSession(d)) continue;
Session session; Session session;
try { try {
if (!sessionParser.isSession(d)) continue;
session = sessionParser.parseSession(contactGroup, d); session = sessionParser.parseSession(contactGroup, d);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
@@ -668,13 +668,12 @@ abstract class SharingManagerImpl<S extends Shareable>
// assign protocol messages to their sessions // assign protocol messages to their sessions
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
// skip all sessions, we are only interested in messages
BdfDictionary d = entry.getValue();
if (sessionParser.isSession(d)) continue;
// parse message metadata and skip messages not visible in UI // parse message metadata and skip messages not visible in UI
MessageMetadata m; MessageMetadata m;
try { try {
// skip all sessions, we are only interested in messages
BdfDictionary d = entry.getValue();
if (sessionParser.isSession(d)) continue;
m = messageParser.parseMetadata(d); m = messageParser.parseMetadata(d);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);

View File

@@ -40,7 +40,7 @@ abstract class SharingValidator extends BdfMessageValidator {
@Override @Override
protected BdfMessageContext validateMessage(Message m, Group g, protected BdfMessageContext validateMessage(Message m, Group g,
BdfList body) throws FormatException { BdfList body) throws FormatException {
MessageType type = MessageType.fromValue(body.getLong(0).intValue()); MessageType type = MessageType.fromValue(body.getInt(0));
switch (type) { switch (type) {
case INVITE: case INVITE:
return validateInviteMessage(m, body); return validateInviteMessage(m, body);

View File

@@ -651,7 +651,7 @@ public class GroupMessageValidatorTest extends ValidatorTestCase {
MessageType type, BdfList member, MessageType type, BdfList member,
Collection<MessageId> dependencies) throws FormatException { Collection<MessageId> dependencies) throws FormatException {
BdfDictionary d = c.getDictionary(); BdfDictionary d = c.getDictionary();
assertEquals(type.getInt(), d.getLong(KEY_TYPE).intValue()); assertEquals(type.getInt(), d.getInt(KEY_TYPE).intValue());
assertEquals(message.getTimestamp(), assertEquals(message.getTimestamp(),
d.getLong(KEY_TIMESTAMP).longValue()); d.getLong(KEY_TIMESTAMP).longValue());
assertFalse(d.getBoolean(KEY_READ)); assertFalse(d.getBoolean(KEY_READ));