mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Initial commit with new directory structure.
This commit is contained in:
15
.classpath
Normal file
15
.classpath
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="ui"/>
|
||||||
|
<classpathentry kind="src" path="i18n"/>
|
||||||
|
<classpathentry kind="src" path="test"/>
|
||||||
|
<classpathentry kind="src" path="api"/>
|
||||||
|
<classpathentry kind="src" path="components"/>
|
||||||
|
<classpathentry kind="src" path="util"/>
|
||||||
|
<classpathentry kind="src" path="installer"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
|
||||||
|
<classpathentry kind="lib" path="lib/h2small-1.3.154.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/guice-3.0-no_aop.jar"/>
|
||||||
|
<classpathentry kind="lib" path="lib/javax.inject-1.jar"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
||||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/windows-jre
|
||||||
|
/Briar
|
||||||
|
/bin
|
||||||
17
.project
Normal file
17
.project
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>briar-prototype</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
12
.settings/org.eclipse.jdt.core.prefs
Normal file
12
.settings/org.eclipse.jdt.core.prefs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#Wed Apr 13 15:01:36 BST 2011
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||||
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.5
|
||||||
1
api/.gitignore
vendored
Normal file
1
api/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
3
api/build.xml
Normal file
3
api/build.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<project name='api' default='compile'>
|
||||||
|
<import file='../build-common.xml'/>
|
||||||
|
</project>
|
||||||
6
api/net/sf/briar/api/crypto/Password.java
Normal file
6
api/net/sf/briar/api/crypto/Password.java
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package net.sf.briar.api.crypto;
|
||||||
|
|
||||||
|
public interface Password {
|
||||||
|
|
||||||
|
char[] getPassword();
|
||||||
|
}
|
||||||
43
api/net/sf/briar/api/db/DatabaseComponent.java
Normal file
43
api/net/sf/briar/api/db/DatabaseComponent.java
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package net.sf.briar.api.db;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.sf.briar.api.protocol.AuthorId;
|
||||||
|
import net.sf.briar.api.protocol.Bundle;
|
||||||
|
import net.sf.briar.api.protocol.GroupId;
|
||||||
|
import net.sf.briar.api.protocol.Message;
|
||||||
|
|
||||||
|
public interface DatabaseComponent {
|
||||||
|
|
||||||
|
static final long MEGABYTES = 1024L * 1024L;
|
||||||
|
static final long GIGABYTES = 1024L * MEGABYTES;
|
||||||
|
|
||||||
|
static final long MAX_DB_SIZE = 2L * GIGABYTES;
|
||||||
|
static final long MIN_FREE_SPACE = 300L * MEGABYTES;
|
||||||
|
static final long CRITICAL_FREE_SPACE = 100L * MEGABYTES;
|
||||||
|
static final long MAX_BYTES_BETWEEN_SPACE_CHECKS = 5L * MEGABYTES;
|
||||||
|
static final long MAX_MS_BETWEEN_SPACE_CHECKS = 60L * 1000L; // 1 min
|
||||||
|
static final long BYTES_PER_SWEEP = 5L * MEGABYTES;
|
||||||
|
static final int CLEANER_SLEEP_MS = 1000; // 1 sec
|
||||||
|
static final int RETRANSMIT_THRESHOLD = 3;
|
||||||
|
|
||||||
|
void close() throws DbException;
|
||||||
|
|
||||||
|
void addLocallyGeneratedMessage(Message m) throws DbException;
|
||||||
|
|
||||||
|
void addNeighbour(NeighbourId n) throws DbException;
|
||||||
|
|
||||||
|
void generateBundle(NeighbourId n, Bundle b) throws DbException;
|
||||||
|
|
||||||
|
Rating getRating(AuthorId a) throws DbException;
|
||||||
|
|
||||||
|
Set<GroupId> getSubscriptions() throws DbException;
|
||||||
|
|
||||||
|
void receiveBundle(NeighbourId n, Bundle b) throws DbException;
|
||||||
|
|
||||||
|
void setRating(AuthorId a, Rating r) throws DbException;
|
||||||
|
|
||||||
|
void subscribe(GroupId g) throws DbException;
|
||||||
|
|
||||||
|
void unsubscribe(GroupId g) throws DbException;
|
||||||
|
}
|
||||||
14
api/net/sf/briar/api/db/DatabasePassword.java
Normal file
14
api/net/sf/briar/api/db/DatabasePassword.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package net.sf.briar.api.db;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.PARAMETER;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import com.google.inject.BindingAnnotation;
|
||||||
|
|
||||||
|
@BindingAnnotation
|
||||||
|
@Target({ PARAMETER })
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface DatabasePassword {}
|
||||||
10
api/net/sf/briar/api/db/DbException.java
Normal file
10
api/net/sf/briar/api/db/DbException.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package net.sf.briar.api.db;
|
||||||
|
|
||||||
|
public class DbException extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3706581789209939441L;
|
||||||
|
|
||||||
|
public DbException(Throwable t) {
|
||||||
|
super(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
api/net/sf/briar/api/db/NeighbourId.java
Normal file
30
api/net/sf/briar/api/db/NeighbourId.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package net.sf.briar.api.db;
|
||||||
|
|
||||||
|
public class NeighbourId {
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
public NeighbourId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getInt() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(o instanceof NeighbourId) return id == ((NeighbourId) o).id;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.valueOf(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
api/net/sf/briar/api/db/Rating.java
Normal file
5
api/net/sf/briar/api/db/Rating.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package net.sf.briar.api.db;
|
||||||
|
|
||||||
|
public enum Rating {
|
||||||
|
BAD, UNRATED, GOOD
|
||||||
|
}
|
||||||
5
api/net/sf/briar/api/db/Status.java
Normal file
5
api/net/sf/briar/api/db/Status.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package net.sf.briar.api.db;
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
NEW, SENT, SEEN
|
||||||
|
}
|
||||||
18
api/net/sf/briar/api/i18n/FontManager.java
Normal file
18
api/net/sf/briar/api/i18n/FontManager.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package net.sf.briar.api.i18n;
|
||||||
|
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public interface FontManager {
|
||||||
|
|
||||||
|
void initialize(Locale locale) throws IOException;
|
||||||
|
|
||||||
|
String[] getBundledFontFilenames();
|
||||||
|
|
||||||
|
Font getFontForLanguage(String language);
|
||||||
|
|
||||||
|
Font getUiFont();
|
||||||
|
|
||||||
|
void setUiFontForLanguage(String language);
|
||||||
|
}
|
||||||
33
api/net/sf/briar/api/i18n/I18n.java
Normal file
33
api/net/sf/briar/api/i18n/I18n.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package net.sf.briar.api.i18n;
|
||||||
|
|
||||||
|
import java.awt.ComponentOrientation;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public interface I18n {
|
||||||
|
|
||||||
|
String tr(String name);
|
||||||
|
|
||||||
|
Locale getLocale();
|
||||||
|
|
||||||
|
void setLocale(Locale locale);
|
||||||
|
|
||||||
|
void loadLocale() throws IOException;
|
||||||
|
|
||||||
|
void saveLocale() throws IOException;
|
||||||
|
|
||||||
|
void saveLocale(File dir) throws IOException;
|
||||||
|
|
||||||
|
ComponentOrientation getComponentOrientation();
|
||||||
|
|
||||||
|
void addListener(Listener l);
|
||||||
|
|
||||||
|
void removeListener(Listener l);
|
||||||
|
|
||||||
|
public interface Listener {
|
||||||
|
|
||||||
|
void localeChanged(Font uiFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
api/net/sf/briar/api/i18n/Stri18ng.java
Normal file
41
api/net/sf/briar/api/i18n/Stri18ng.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package net.sf.briar.api.i18n;
|
||||||
|
|
||||||
|
public class Stri18ng {
|
||||||
|
|
||||||
|
private static final String HTML_OPEN_LEFT = "<html><body align='left'>";
|
||||||
|
private static final String HTML_OPEN_RIGHT = "<html><body align='right'>";
|
||||||
|
private static final String HTML_CLOSE = "</body></html>";
|
||||||
|
private static final String PARAGRAPH = "<p><p>"; // Yes, two of them
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final I18n i18n;
|
||||||
|
|
||||||
|
public Stri18ng(String name, I18n i18n) {
|
||||||
|
this.name = name;
|
||||||
|
this.i18n = i18n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String tr() {
|
||||||
|
return i18n.tr(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String html() {
|
||||||
|
if(i18n.getComponentOrientation().isLeftToRight())
|
||||||
|
return HTML_OPEN_LEFT + i18n.tr(name) + HTML_CLOSE;
|
||||||
|
else return HTML_OPEN_RIGHT + i18n.tr(name) + HTML_CLOSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String html(String... paras) {
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
if(i18n.getComponentOrientation().isLeftToRight())
|
||||||
|
s.append(HTML_OPEN_LEFT);
|
||||||
|
else s.append(HTML_OPEN_RIGHT);
|
||||||
|
s.append(tr());
|
||||||
|
for(String para : paras) {
|
||||||
|
s.append(PARAGRAPH);
|
||||||
|
s.append(para);
|
||||||
|
}
|
||||||
|
s.append(HTML_CLOSE);
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
23
api/net/sf/briar/api/invitation/InvitationCallback.java
Normal file
23
api/net/sf/briar/api/invitation/InvitationCallback.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package net.sf.briar.api.invitation;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface InvitationCallback {
|
||||||
|
|
||||||
|
boolean isCancelled();
|
||||||
|
|
||||||
|
void copyingFile(File f);
|
||||||
|
|
||||||
|
void encryptingFile(File f);
|
||||||
|
|
||||||
|
void created(List<File> files);
|
||||||
|
|
||||||
|
void error(String message);
|
||||||
|
|
||||||
|
void notFound(File f);
|
||||||
|
|
||||||
|
void notDirectory(File f);
|
||||||
|
|
||||||
|
void notAllowed(File f);
|
||||||
|
}
|
||||||
16
api/net/sf/briar/api/invitation/InvitationParameters.java
Normal file
16
api/net/sf/briar/api/invitation/InvitationParameters.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package net.sf.briar.api.invitation;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public interface InvitationParameters {
|
||||||
|
|
||||||
|
boolean shouldCreateExe();
|
||||||
|
|
||||||
|
boolean shouldCreateJar();
|
||||||
|
|
||||||
|
char[] getPassword();
|
||||||
|
|
||||||
|
File getChosenLocation();
|
||||||
|
|
||||||
|
String[] getBundledFontFilenames();
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package net.sf.briar.api.invitation;
|
||||||
|
|
||||||
|
public interface InvitationWorkerFactory {
|
||||||
|
|
||||||
|
Runnable createWorker(InvitationCallback callback,
|
||||||
|
InvitationParameters parameters);
|
||||||
|
}
|
||||||
36
api/net/sf/briar/api/protocol/AuthorId.java
Normal file
36
api/net/sf/briar/api/protocol/AuthorId.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class AuthorId {
|
||||||
|
|
||||||
|
public static final int LENGTH = 32;
|
||||||
|
|
||||||
|
public static final AuthorId SELF = new AuthorId(new byte[] {
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
|
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
|
||||||
|
});
|
||||||
|
|
||||||
|
private final byte[] id;
|
||||||
|
|
||||||
|
public AuthorId(byte[] id) {
|
||||||
|
assert id.length == LENGTH;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(o instanceof AuthorId)
|
||||||
|
return Arrays.equals(id, ((AuthorId) o).id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
api/net/sf/briar/api/protocol/Batch.java
Normal file
13
api/net/sf/briar/api/protocol/Batch.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
|
||||||
|
public interface Batch {
|
||||||
|
|
||||||
|
public static final long CAPACITY = 1024L * 1024L;
|
||||||
|
|
||||||
|
public void seal();
|
||||||
|
BatchId getId();
|
||||||
|
long getSize();
|
||||||
|
Iterable<Message> getMessages();
|
||||||
|
void addMessage(Message m);
|
||||||
|
}
|
||||||
31
api/net/sf/briar/api/protocol/BatchId.java
Normal file
31
api/net/sf/briar/api/protocol/BatchId.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class BatchId {
|
||||||
|
|
||||||
|
public static final int LENGTH = 32;
|
||||||
|
|
||||||
|
private final byte[] id;
|
||||||
|
|
||||||
|
public BatchId(byte[] id) {
|
||||||
|
assert id.length == LENGTH;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(o instanceof BatchId)
|
||||||
|
return Arrays.equals(id, ((BatchId) o).id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
api/net/sf/briar/api/protocol/Bundle.java
Normal file
16
api/net/sf/briar/api/protocol/Bundle.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
|
||||||
|
public interface Bundle {
|
||||||
|
|
||||||
|
public void seal();
|
||||||
|
BundleId getId();
|
||||||
|
long getCapacity();
|
||||||
|
long getSize();
|
||||||
|
Iterable<BatchId> getAcks();
|
||||||
|
void addAck(BatchId b);
|
||||||
|
Iterable<GroupId> getSubscriptions();
|
||||||
|
void addSubscription(GroupId g);
|
||||||
|
Iterable<Batch> getBatches();
|
||||||
|
void addBatch(Batch b);
|
||||||
|
}
|
||||||
36
api/net/sf/briar/api/protocol/BundleId.java
Normal file
36
api/net/sf/briar/api/protocol/BundleId.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class BundleId {
|
||||||
|
|
||||||
|
public static final BundleId NONE = new BundleId(new byte[] {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
});
|
||||||
|
|
||||||
|
public static final int LENGTH = 32;
|
||||||
|
|
||||||
|
private final byte[] id;
|
||||||
|
|
||||||
|
public BundleId(byte[] id) {
|
||||||
|
assert id.length == LENGTH;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(o instanceof BundleId)
|
||||||
|
return Arrays.equals(id, ((BundleId) o).id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
api/net/sf/briar/api/protocol/GroupId.java
Normal file
31
api/net/sf/briar/api/protocol/GroupId.java
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class GroupId {
|
||||||
|
|
||||||
|
public static final int LENGTH = 32;
|
||||||
|
|
||||||
|
private final byte[] id;
|
||||||
|
|
||||||
|
public GroupId(byte[] id) {
|
||||||
|
assert id.length == LENGTH;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(o instanceof GroupId)
|
||||||
|
return Arrays.equals(id, ((GroupId) o).id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
api/net/sf/briar/api/protocol/Message.java
Normal file
13
api/net/sf/briar/api/protocol/Message.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
|
||||||
|
public interface Message {
|
||||||
|
|
||||||
|
MessageId getId();
|
||||||
|
MessageId getParent();
|
||||||
|
GroupId getGroup();
|
||||||
|
AuthorId getAuthor();
|
||||||
|
long getTimestamp();
|
||||||
|
int getSize();
|
||||||
|
byte[] getBody();
|
||||||
|
}
|
||||||
7
api/net/sf/briar/api/protocol/MessageFactory.java
Normal file
7
api/net/sf/briar/api/protocol/MessageFactory.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
public interface MessageFactory {
|
||||||
|
|
||||||
|
Message createMessage(MessageId id, MessageId parent, GroupId group,
|
||||||
|
AuthorId author, long timestamp, byte[] body);
|
||||||
|
}
|
||||||
36
api/net/sf/briar/api/protocol/MessageId.java
Normal file
36
api/net/sf/briar/api/protocol/MessageId.java
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package net.sf.briar.api.protocol;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class MessageId {
|
||||||
|
|
||||||
|
public static final MessageId NONE = new MessageId(new byte[] {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
});
|
||||||
|
|
||||||
|
public static final int LENGTH = 32;
|
||||||
|
|
||||||
|
private final byte[] id;
|
||||||
|
|
||||||
|
public MessageId(byte[] id) {
|
||||||
|
assert id.length == LENGTH;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytes() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if(o instanceof MessageId)
|
||||||
|
return Arrays.equals(id, ((MessageId) o).id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
api/net/sf/briar/api/setup/SetupCallback.java
Normal file
22
api/net/sf/briar/api/setup/SetupCallback.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package net.sf.briar.api.setup;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public interface SetupCallback {
|
||||||
|
|
||||||
|
boolean isCancelled();
|
||||||
|
|
||||||
|
void extractingFile(File f);
|
||||||
|
|
||||||
|
void copyingFile(File f);
|
||||||
|
|
||||||
|
void installed(File f);
|
||||||
|
|
||||||
|
void error(String message);
|
||||||
|
|
||||||
|
void notFound(File f);
|
||||||
|
|
||||||
|
void notDirectory(File f);
|
||||||
|
|
||||||
|
void notAllowed(File f);
|
||||||
|
}
|
||||||
10
api/net/sf/briar/api/setup/SetupParameters.java
Normal file
10
api/net/sf/briar/api/setup/SetupParameters.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package net.sf.briar.api.setup;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public interface SetupParameters {
|
||||||
|
|
||||||
|
File getChosenLocation();
|
||||||
|
|
||||||
|
String[] getBundledFontFilenames();
|
||||||
|
}
|
||||||
6
api/net/sf/briar/api/setup/SetupWorkerFactory.java
Normal file
6
api/net/sf/briar/api/setup/SetupWorkerFactory.java
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package net.sf.briar.api.setup;
|
||||||
|
|
||||||
|
public interface SetupWorkerFactory {
|
||||||
|
|
||||||
|
Runnable createWorker(SetupCallback callback, SetupParameters parameters);
|
||||||
|
}
|
||||||
38
build-common.xml
Normal file
38
build-common.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<project name='build-common' default='compile'>
|
||||||
|
<import file='dependencies.xml'/>
|
||||||
|
<property name='build' location='build'/>
|
||||||
|
<dirname property='build-common.root' file='${ant.file.build-common}'/>
|
||||||
|
<fileset id='third-party-jars' dir='${build-common.root}/lib'>
|
||||||
|
<include name='*.jar'/>
|
||||||
|
</fileset>
|
||||||
|
<path id='api-classes'>
|
||||||
|
<pathelement location='${build-common.root}/api/build'/>
|
||||||
|
</path>
|
||||||
|
<path id='component-classes'>
|
||||||
|
<pathelement location='${build-common.root}/components/build'/>
|
||||||
|
</path>
|
||||||
|
<path id='util-classes'>
|
||||||
|
<pathelement location='${build-common.root}/util/build'/>
|
||||||
|
</path>
|
||||||
|
<target name='clean'>
|
||||||
|
<delete dir='${build}'/>
|
||||||
|
</target>
|
||||||
|
<target name='compile'>
|
||||||
|
<mkdir dir='${build}'/>
|
||||||
|
<javac srcdir='net/sf/briar' destdir='${build}'
|
||||||
|
includeantruntime='false'>
|
||||||
|
<classpath>
|
||||||
|
<fileset refid='third-party-jars'/>
|
||||||
|
<path refid='api-classes'/>
|
||||||
|
<path refid='component-classes'/>
|
||||||
|
<path refid='util-classes'/>
|
||||||
|
</classpath>
|
||||||
|
</javac>
|
||||||
|
</target>
|
||||||
|
<target name='depend'>
|
||||||
|
<antcall target='depend.${ant.project.name}'/>
|
||||||
|
</target>
|
||||||
|
<target name='depend-clean'>
|
||||||
|
<antcall target='depend-clean.${ant.project.name}'/>
|
||||||
|
</target>
|
||||||
|
</project>
|
||||||
3
build.xml
Normal file
3
build.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<project name='all' default='compile'>
|
||||||
|
<import file='build-common.xml'/>
|
||||||
|
</project>
|
||||||
1
components/.gitignore
vendored
Normal file
1
components/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
3
components/build.xml
Normal file
3
components/build.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<project name='components' default='compile'>
|
||||||
|
<import file='../build-common.xml'/>
|
||||||
|
</project>
|
||||||
114
components/net/sf/briar/db/Database.java
Normal file
114
components/net/sf/briar/db/Database.java
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.sf.briar.api.db.DbException;
|
||||||
|
import net.sf.briar.api.db.NeighbourId;
|
||||||
|
import net.sf.briar.api.db.Rating;
|
||||||
|
import net.sf.briar.api.db.Status;
|
||||||
|
import net.sf.briar.api.protocol.AuthorId;
|
||||||
|
import net.sf.briar.api.protocol.BatchId;
|
||||||
|
import net.sf.briar.api.protocol.BundleId;
|
||||||
|
import net.sf.briar.api.protocol.GroupId;
|
||||||
|
import net.sf.briar.api.protocol.Message;
|
||||||
|
import net.sf.briar.api.protocol.MessageId;
|
||||||
|
|
||||||
|
interface Database<T> {
|
||||||
|
|
||||||
|
void open(boolean resume) throws DbException;
|
||||||
|
|
||||||
|
void close() throws DbException;
|
||||||
|
|
||||||
|
T startTransaction(String name) throws DbException;
|
||||||
|
|
||||||
|
void abortTransaction(T txn);
|
||||||
|
|
||||||
|
void commitTransaction(T txn) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write
|
||||||
|
void addBatchToAck(T txn, NeighbourId n, BatchId b) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write
|
||||||
|
void addNeighbour(T txn, NeighbourId n) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write, messages read
|
||||||
|
void addOutstandingBatch(T txn, NeighbourId n, BatchId b, Set<MessageId> sent) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write, messages read
|
||||||
|
Set<BatchId> addReceivedBundle(T txn, NeighbourId n, BundleId b) throws DbException;
|
||||||
|
|
||||||
|
// Locking: subscriptions write
|
||||||
|
void addSubscription(T txn, GroupId g) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write
|
||||||
|
void addSubscription(T txn, NeighbourId n, GroupId g) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write
|
||||||
|
void clearSubscriptions(T txn, NeighbourId n) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages read
|
||||||
|
boolean containsMessage(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
|
// Locking: subscriptions read
|
||||||
|
boolean containsSubscription(T txn, GroupId g) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages read
|
||||||
|
long getFreeSpace() throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages read
|
||||||
|
Message getMessage(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages read
|
||||||
|
Iterable<MessageId> getMessagesByAuthor(T txn, AuthorId a) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages read
|
||||||
|
Iterable<MessageId> getMessagesByParent(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours read
|
||||||
|
Set<NeighbourId> getNeighbours(T txn) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages read
|
||||||
|
Iterable<MessageId> getOldMessages(T txn, long size) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages read
|
||||||
|
MessageId getParent(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
|
// Locking: ratings read
|
||||||
|
Rating getRating(T txn, AuthorId a) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages read
|
||||||
|
int getSendability(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours read, messages read
|
||||||
|
Iterable<MessageId> getSendableMessages(T txn, NeighbourId n, long capacity) throws DbException;
|
||||||
|
|
||||||
|
// Locking: subscriptions read
|
||||||
|
Set<GroupId> getSubscriptions(T txn) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages write
|
||||||
|
boolean addMessage(T txn, Message m) throws DbException;
|
||||||
|
|
||||||
|
// Locking: ratings write
|
||||||
|
Rating setRating(T txn, AuthorId a, Rating r) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages write
|
||||||
|
void setSendability(T txn, MessageId m, int sendability) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours read, n write
|
||||||
|
Set<BatchId> removeBatchesToAck(T txn, NeighbourId n) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write, messages read
|
||||||
|
void removeLostBatch(T txn, NeighbourId n, BatchId b) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write, messages write
|
||||||
|
void removeMessage(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write
|
||||||
|
Set<MessageId> removeOutstandingBatch(T txn, NeighbourId n, BatchId b) throws DbException;
|
||||||
|
|
||||||
|
// Locking: subscriptions write, neighbours write, messages write
|
||||||
|
void removeSubscription(T txn, GroupId g) throws DbException;
|
||||||
|
|
||||||
|
// Locking: neighbours write, messages read
|
||||||
|
void setStatus(T txn, NeighbourId n, MessageId m, Status s) throws DbException;
|
||||||
|
}
|
||||||
209
components/net/sf/briar/db/DatabaseComponentImpl.java
Normal file
209
components/net/sf/briar/db/DatabaseComponentImpl.java
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
|
import net.sf.briar.api.db.DbException;
|
||||||
|
import net.sf.briar.api.db.NeighbourId;
|
||||||
|
import net.sf.briar.api.db.Rating;
|
||||||
|
import net.sf.briar.api.db.Status;
|
||||||
|
import net.sf.briar.api.protocol.AuthorId;
|
||||||
|
import net.sf.briar.api.protocol.Batch;
|
||||||
|
import net.sf.briar.api.protocol.Message;
|
||||||
|
import net.sf.briar.api.protocol.MessageId;
|
||||||
|
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
|
||||||
|
|
||||||
|
protected final Database<Txn> db;
|
||||||
|
protected final Provider<Batch> batchProvider;
|
||||||
|
|
||||||
|
private final Object spaceLock = new Object();
|
||||||
|
private final Object writeLock = new Object();
|
||||||
|
private long bytesStoredSinceLastCheck = 0L; // Locking: spaceLock
|
||||||
|
private long timeOfLastCheck = 0L; // Locking: spaceLock
|
||||||
|
private volatile boolean writesAllowed = true;
|
||||||
|
|
||||||
|
DatabaseComponentImpl(Database<Txn> db, Provider<Batch> batchProvider) {
|
||||||
|
this.db = db;
|
||||||
|
this.batchProvider = batchProvider;
|
||||||
|
startCleaner();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void expireMessages(long size) throws DbException;
|
||||||
|
|
||||||
|
// Locking: messages write
|
||||||
|
private int calculateSendability(Txn txn, Message m) throws DbException {
|
||||||
|
int sendability = 0;
|
||||||
|
// One point for a good rating
|
||||||
|
if(getRating(m.getAuthor()) == Rating.GOOD) sendability++;
|
||||||
|
// One point per sendable child (backward inclusion)
|
||||||
|
for(MessageId kid : db.getMessagesByParent(txn, m.getId())) {
|
||||||
|
Integer kidSendability = db.getSendability(txn, kid);
|
||||||
|
assert kidSendability != null;
|
||||||
|
if(kidSendability > 0) sendability++;
|
||||||
|
}
|
||||||
|
return sendability;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkFreeSpaceAndClean() throws DbException {
|
||||||
|
long freeSpace = db.getFreeSpace();
|
||||||
|
while(freeSpace < MIN_FREE_SPACE) {
|
||||||
|
// If disk space is critical, disable the storage of new messages
|
||||||
|
if(freeSpace < CRITICAL_FREE_SPACE) {
|
||||||
|
System.out.println("Critical cleanup");
|
||||||
|
writesAllowed = false;
|
||||||
|
} else {
|
||||||
|
System.out.println("Normal cleanup");
|
||||||
|
}
|
||||||
|
expireMessages(BYTES_PER_SWEEP);
|
||||||
|
Thread.yield();
|
||||||
|
freeSpace = db.getFreeSpace();
|
||||||
|
// If disk space is no longer critical, re-enable writes
|
||||||
|
if(freeSpace >= CRITICAL_FREE_SPACE && !writesAllowed) {
|
||||||
|
writesAllowed = true;
|
||||||
|
synchronized(writeLock) {
|
||||||
|
writeLock.notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: messages write, neighbours write
|
||||||
|
protected void removeMessage(Txn txn, MessageId id) throws DbException {
|
||||||
|
Integer sendability = db.getSendability(txn, id);
|
||||||
|
assert sendability != null;
|
||||||
|
if(sendability > 0) updateAncestorSendability(txn, id, false);
|
||||||
|
db.removeMessage(txn, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldCheckFreeSpace() {
|
||||||
|
synchronized(spaceLock) {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if(bytesStoredSinceLastCheck > MAX_BYTES_BETWEEN_SPACE_CHECKS) {
|
||||||
|
System.out.println(bytesStoredSinceLastCheck
|
||||||
|
+ " bytes stored since last check");
|
||||||
|
bytesStoredSinceLastCheck = 0L;
|
||||||
|
timeOfLastCheck = now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(now - timeOfLastCheck > MAX_MS_BETWEEN_SPACE_CHECKS) {
|
||||||
|
System.out.println((now - timeOfLastCheck)
|
||||||
|
+ " ms since last check");
|
||||||
|
bytesStoredSinceLastCheck = 0L;
|
||||||
|
timeOfLastCheck = now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startCleaner() {
|
||||||
|
Runnable cleaner = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
while(true) {
|
||||||
|
if(shouldCheckFreeSpace()) {
|
||||||
|
checkFreeSpaceAndClean();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Thread.sleep(CLEANER_SLEEP_MS);
|
||||||
|
} catch(InterruptedException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(Throwable t) {
|
||||||
|
// FIXME: Work out what to do here
|
||||||
|
t.printStackTrace();
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
new Thread(cleaner).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: messages write, neighbours write
|
||||||
|
protected boolean storeMessage(Txn txn, Message m, NeighbourId sender)
|
||||||
|
throws DbException {
|
||||||
|
boolean added = db.addMessage(txn, m);
|
||||||
|
// Mark the message as seen by the sender
|
||||||
|
MessageId id = m.getId();
|
||||||
|
if(sender != null) db.setStatus(txn, sender, id, Status.SEEN);
|
||||||
|
if(added) {
|
||||||
|
// Mark the message as unseen by other neighbours
|
||||||
|
for(NeighbourId n : db.getNeighbours(txn)) {
|
||||||
|
if(!n.equals(sender)) db.setStatus(txn, n, id, Status.NEW);
|
||||||
|
}
|
||||||
|
// Calculate and store the message's sendability
|
||||||
|
int sendability = calculateSendability(txn, m);
|
||||||
|
db.setSendability(txn, id, sendability);
|
||||||
|
if(sendability > 0) updateAncestorSendability(txn, id, true);
|
||||||
|
// Count the bytes stored
|
||||||
|
synchronized(spaceLock) {
|
||||||
|
bytesStoredSinceLastCheck += m.getSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: messages write
|
||||||
|
private int updateAncestorSendability(Txn txn, MessageId m,
|
||||||
|
boolean increment) throws DbException {
|
||||||
|
int affected = 0;
|
||||||
|
boolean changed = true;
|
||||||
|
while(changed) {
|
||||||
|
MessageId parent = db.getParent(txn, m);
|
||||||
|
if(parent.equals(MessageId.NONE)) break;
|
||||||
|
if(!db.containsMessage(txn, parent)) break;
|
||||||
|
Integer parentSendability = db.getSendability(txn, parent);
|
||||||
|
assert parentSendability != null;
|
||||||
|
if(increment) {
|
||||||
|
parentSendability++;
|
||||||
|
changed = parentSendability == 1;
|
||||||
|
if(changed) affected++;
|
||||||
|
} else {
|
||||||
|
assert parentSendability > 0;
|
||||||
|
parentSendability--;
|
||||||
|
changed = parentSendability == 0;
|
||||||
|
if(changed) affected++;
|
||||||
|
}
|
||||||
|
db.setSendability(txn, parent, parentSendability);
|
||||||
|
m = parent;
|
||||||
|
}
|
||||||
|
return affected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locking: messages write
|
||||||
|
protected void updateAuthorSendability(Txn txn, AuthorId a,
|
||||||
|
boolean increment) throws DbException {
|
||||||
|
int direct = 0, indirect = 0;
|
||||||
|
for(MessageId id : db.getMessagesByAuthor(txn, a)) {
|
||||||
|
int sendability = db.getSendability(txn, id);
|
||||||
|
if(increment) {
|
||||||
|
db.setSendability(txn, id, sendability + 1);
|
||||||
|
if(sendability == 0) {
|
||||||
|
direct++;
|
||||||
|
indirect += updateAncestorSendability(txn, id, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert sendability > 0;
|
||||||
|
db.setSendability(txn, id, sendability - 1);
|
||||||
|
if(sendability == 1) {
|
||||||
|
direct++;
|
||||||
|
indirect += updateAncestorSendability(txn, id, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println(direct + " messages affected directly, "
|
||||||
|
+ indirect + " indirectly");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void waitForPermissionToWrite() {
|
||||||
|
synchronized(writeLock) {
|
||||||
|
while(!writesAllowed) {
|
||||||
|
System.out.println("Waiting for permission to write");
|
||||||
|
try {
|
||||||
|
writeLock.wait();
|
||||||
|
} catch(InterruptedException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
components/net/sf/briar/db/DatabaseModule.java
Normal file
22
components/net/sf/briar/db/DatabaseModule.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import net.sf.briar.api.crypto.Password;
|
||||||
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
|
import net.sf.briar.api.db.DatabasePassword;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
public class DatabaseModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(Database.class).to(H2Database.class);
|
||||||
|
bind(DatabaseComponent.class).to(ReadWriteLockDatabaseComponent.class).in(Singleton.class);
|
||||||
|
bind(Password.class).annotatedWith(DatabasePassword.class).toInstance(new Password() {
|
||||||
|
public char[] getPassword() {
|
||||||
|
return "fixme fixme".toCharArray();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
70
components/net/sf/briar/db/H2Database.java
Normal file
70
components/net/sf/briar/db/H2Database.java
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import net.sf.briar.api.crypto.Password;
|
||||||
|
import net.sf.briar.api.db.DatabaseComponent;
|
||||||
|
import net.sf.briar.api.db.DatabasePassword;
|
||||||
|
import net.sf.briar.api.db.DbException;
|
||||||
|
import net.sf.briar.api.protocol.MessageFactory;
|
||||||
|
import net.sf.briar.util.FileUtils;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
class H2Database extends JdbcDatabase {
|
||||||
|
|
||||||
|
private final Password password;
|
||||||
|
private final File home;
|
||||||
|
private final String url;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
H2Database(MessageFactory messageFactory,
|
||||||
|
@DatabasePassword Password password) {
|
||||||
|
super(messageFactory, "BINARY(32)");
|
||||||
|
this.password = password;
|
||||||
|
home = new File(FileUtils.getBriarDirectory(), "Data/db/db");
|
||||||
|
url = "jdbc:h2:split:" + home.getPath()
|
||||||
|
+ ";CIPHER=AES;DB_CLOSE_ON_EXIT=false";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open(boolean resume) throws DbException {
|
||||||
|
super.open(resume, home.getParentFile(), "org.h2.Driver");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws DbException {
|
||||||
|
System.out.println("Closing database");
|
||||||
|
try {
|
||||||
|
super.closeAllConnections();
|
||||||
|
} catch(SQLException e) {
|
||||||
|
throw new DbException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getFreeSpace() throws DbException {
|
||||||
|
File dir = home.getParentFile();
|
||||||
|
long free = dir.getFreeSpace();
|
||||||
|
long used = getDiskSpace(dir);
|
||||||
|
long quota = DatabaseComponent.MAX_DB_SIZE - used;
|
||||||
|
long min = Math.min(free, quota);
|
||||||
|
System.out.println("Free space: " + min);
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Connection createConnection() throws SQLException {
|
||||||
|
Properties props = new Properties();
|
||||||
|
props.setProperty("user", "b");
|
||||||
|
char[] passwordArray = password.getPassword();
|
||||||
|
props.put("password", passwordArray);
|
||||||
|
try {
|
||||||
|
return DriverManager.getConnection(url, props);
|
||||||
|
} finally {
|
||||||
|
Arrays.fill(passwordArray, (char) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1204
components/net/sf/briar/db/JdbcDatabase.java
Normal file
1204
components/net/sf/briar/db/JdbcDatabase.java
Normal file
File diff suppressed because it is too large
Load Diff
497
components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java
Normal file
497
components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java
Normal file
@@ -0,0 +1,497 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
import net.sf.briar.api.db.DbException;
|
||||||
|
import net.sf.briar.api.db.NeighbourId;
|
||||||
|
import net.sf.briar.api.db.Rating;
|
||||||
|
import net.sf.briar.api.db.Status;
|
||||||
|
import net.sf.briar.api.protocol.AuthorId;
|
||||||
|
import net.sf.briar.api.protocol.Batch;
|
||||||
|
import net.sf.briar.api.protocol.BatchId;
|
||||||
|
import net.sf.briar.api.protocol.Bundle;
|
||||||
|
import net.sf.briar.api.protocol.GroupId;
|
||||||
|
import net.sf.briar.api.protocol.Message;
|
||||||
|
import net.sf.briar.api.protocol.MessageId;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Locks must always be acquired in alphabetical order. See the Database
|
||||||
|
* interface to find out which calls require which locks. Note: this
|
||||||
|
* implementation can allow writers to starve.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private final ReentrantReadWriteLock messageLock =
|
||||||
|
new ReentrantReadWriteLock(true);
|
||||||
|
private final ReentrantReadWriteLock neighbourLock =
|
||||||
|
new ReentrantReadWriteLock(true);
|
||||||
|
private final ReentrantReadWriteLock ratingLock =
|
||||||
|
new ReentrantReadWriteLock(true);
|
||||||
|
private final ReentrantReadWriteLock subscriptionLock =
|
||||||
|
new ReentrantReadWriteLock(true);
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ReadWriteLockDatabaseComponent(Database<Txn> db,
|
||||||
|
Provider<Batch> batchProvider) {
|
||||||
|
super(db, batchProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void expireMessages(long size) throws DbException {
|
||||||
|
messageLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("cleaner");
|
||||||
|
try {
|
||||||
|
for(MessageId m : db.getOldMessages(txn, size)) {
|
||||||
|
removeMessage(txn, m);
|
||||||
|
}
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws DbException {
|
||||||
|
messageLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
ratingLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
subscriptionLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
db.close();
|
||||||
|
} finally {
|
||||||
|
subscriptionLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
ratingLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNeighbour(NeighbourId n) throws DbException {
|
||||||
|
System.out.println("Adding neighbour " + n);
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("addNeighbour");
|
||||||
|
try {
|
||||||
|
db.addNeighbour(txn, n);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLocallyGeneratedMessage(Message m) throws DbException {
|
||||||
|
waitForPermissionToWrite();
|
||||||
|
messageLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
subscriptionLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("addLocallyGeneratedMessage");
|
||||||
|
try {
|
||||||
|
if(db.containsSubscription(txn, m.getGroup())) {
|
||||||
|
boolean added = storeMessage(txn, m, null);
|
||||||
|
assert added;
|
||||||
|
} else {
|
||||||
|
System.out.println("Not subscribed");
|
||||||
|
}
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
subscriptionLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rating getRating(AuthorId a) throws DbException {
|
||||||
|
ratingLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("getRating");
|
||||||
|
try {
|
||||||
|
Rating r = db.getRating(txn, a);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return r;
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
ratingLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRating(AuthorId a, Rating r) throws DbException {
|
||||||
|
messageLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
ratingLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("setRating");
|
||||||
|
try {
|
||||||
|
Rating old = db.setRating(txn, a, r);
|
||||||
|
// Update the sendability of the author's messages
|
||||||
|
if(r == Rating.GOOD && old != Rating.GOOD)
|
||||||
|
updateAuthorSendability(txn, a, true);
|
||||||
|
else if(r != Rating.GOOD && old == Rating.GOOD)
|
||||||
|
updateAuthorSendability(txn, a, false);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
ratingLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<GroupId> getSubscriptions() throws DbException {
|
||||||
|
subscriptionLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("getSubscriptions");
|
||||||
|
try {
|
||||||
|
HashSet<GroupId> subs = new HashSet<GroupId>();
|
||||||
|
for(GroupId g : db.getSubscriptions(txn)) subs.add(g);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return subs;
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
subscriptionLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribe(GroupId g) throws DbException {
|
||||||
|
System.out.println("Subscribing to " + g);
|
||||||
|
subscriptionLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("subscribe");
|
||||||
|
try {
|
||||||
|
db.addSubscription(txn, g);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
subscriptionLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribe(GroupId g) throws DbException {
|
||||||
|
System.out.println("Unsubscribing from " + g);
|
||||||
|
messageLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
subscriptionLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("unsubscribe");
|
||||||
|
try {
|
||||||
|
db.removeSubscription(txn, g);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
subscriptionLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateBundle(NeighbourId n, Bundle b) throws DbException {
|
||||||
|
System.out.println("Generating bundle for " + n);
|
||||||
|
// Ack all batches received from the neighbour
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("generateBundle:acks");
|
||||||
|
try {
|
||||||
|
int numAcks = 0;
|
||||||
|
for(BatchId ack : db.removeBatchesToAck(txn, n)) {
|
||||||
|
b.addAck(ack);
|
||||||
|
numAcks++;
|
||||||
|
}
|
||||||
|
System.out.println("Added " + numAcks + " acks");
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
// Add a list of subscriptions
|
||||||
|
subscriptionLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("generateBundle:subscriptions");
|
||||||
|
try {
|
||||||
|
int numSubs = 0;
|
||||||
|
for(GroupId g : db.getSubscriptions(txn)) {
|
||||||
|
b.addSubscription(g);
|
||||||
|
numSubs++;
|
||||||
|
}
|
||||||
|
System.out.println("Added " + numSubs + " subscriptions");
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
subscriptionLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
// Add as many messages as possible to the bundle
|
||||||
|
long capacity = b.getCapacity();
|
||||||
|
while(true) {
|
||||||
|
Batch batch = fillBatch(n, capacity);
|
||||||
|
if(batch == null) break; // No more messages to send
|
||||||
|
b.addBatch(batch);
|
||||||
|
capacity -= batch.getSize();
|
||||||
|
// If the batch is less than half full, stop trying - there may be
|
||||||
|
// more messages trickling in but we can't wait forever
|
||||||
|
if(batch.getSize() * 2 < Batch.CAPACITY) break;
|
||||||
|
}
|
||||||
|
b.seal();
|
||||||
|
System.out.println("Bundle sent, " + b.getSize() + " bytes");
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Batch fillBatch(NeighbourId n, long capacity) throws DbException {
|
||||||
|
messageLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
Set<MessageId> sent;
|
||||||
|
Batch b;
|
||||||
|
neighbourLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("fillBatch:read");
|
||||||
|
try {
|
||||||
|
capacity = Math.min(capacity, Batch.CAPACITY);
|
||||||
|
Iterator<MessageId> it =
|
||||||
|
db.getSendableMessages(txn, n, capacity).iterator();
|
||||||
|
if(!it.hasNext()) {
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return null; // No more messages to send
|
||||||
|
}
|
||||||
|
sent = new HashSet<MessageId>();
|
||||||
|
b = batchProvider.get();
|
||||||
|
while(it.hasNext()) {
|
||||||
|
MessageId m = it.next();
|
||||||
|
b.addMessage(db.getMessage(txn, m));
|
||||||
|
sent.add(m);
|
||||||
|
}
|
||||||
|
b.seal();
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
// Record the contents of the batch
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("fillBatch:write");
|
||||||
|
try {
|
||||||
|
assert !sent.isEmpty();
|
||||||
|
db.addOutstandingBatch(txn, n, b.getId(), sent);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return b;
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void receiveBundle(NeighbourId n, Bundle b) throws DbException {
|
||||||
|
System.out.println("Received bundle from " + n + ", "
|
||||||
|
+ b.getSize() + " bytes");
|
||||||
|
// Mark all messages in acked batches as seen
|
||||||
|
messageLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
int acks = 0, expired = 0;
|
||||||
|
for(BatchId ack : b.getAcks()) {
|
||||||
|
acks++;
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:acks");
|
||||||
|
try {
|
||||||
|
Iterable<MessageId> batch =
|
||||||
|
db.removeOutstandingBatch(txn, n, ack);
|
||||||
|
// May be null if the batch was empty or has expired
|
||||||
|
if(batch == null) {
|
||||||
|
expired++;
|
||||||
|
} else {
|
||||||
|
for(MessageId m : batch) {
|
||||||
|
// Don't re-create statuses for expired messages
|
||||||
|
if(db.containsMessage(txn, m))
|
||||||
|
db.setStatus(txn, n, m, Status.SEEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Received " + acks + " acks, " + expired
|
||||||
|
+ " expired");
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
// Update the neighbour's subscriptions
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:subscriptions");
|
||||||
|
try {
|
||||||
|
db.clearSubscriptions(txn, n);
|
||||||
|
int subs = 0;
|
||||||
|
for(GroupId g : b.getSubscriptions()) {
|
||||||
|
subs++;
|
||||||
|
db.addSubscription(txn, n, g);
|
||||||
|
}
|
||||||
|
System.out.println("Received " + subs + " subscriptions");
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
// Store the messages
|
||||||
|
int batches = 0;
|
||||||
|
for(Batch batch : b.getBatches()) {
|
||||||
|
batches++;
|
||||||
|
waitForPermissionToWrite();
|
||||||
|
messageLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
subscriptionLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:batch");
|
||||||
|
try {
|
||||||
|
int received = 0, stored = 0;
|
||||||
|
for(Message m : batch.getMessages()) {
|
||||||
|
received++;
|
||||||
|
if(db.containsSubscription(txn, m.getGroup())) {
|
||||||
|
if(storeMessage(txn, m, n)) stored++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Received " + received
|
||||||
|
+ " messages, stored " + stored);
|
||||||
|
db.addBatchToAck(txn, n, batch.getId());
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
subscriptionLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Received " + batches + " batches");
|
||||||
|
// Find any lost batches that need to be retransmitted
|
||||||
|
Set<BatchId> lost;
|
||||||
|
messageLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:findLost");
|
||||||
|
try {
|
||||||
|
lost = db.addReceivedBundle(txn, n, b.getId());
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
for(BatchId batch : lost) {
|
||||||
|
messageLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
neighbourLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:removeLost");
|
||||||
|
try {
|
||||||
|
System.out.println("Removing lost batch");
|
||||||
|
db.removeLostBatch(txn, n, batch);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
neighbourLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
messageLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
}
|
||||||
381
components/net/sf/briar/db/SynchronizedDatabaseComponent.java
Normal file
381
components/net/sf/briar/db/SynchronizedDatabaseComponent.java
Normal file
@@ -0,0 +1,381 @@
|
|||||||
|
package net.sf.briar.db;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
|
||||||
|
import net.sf.briar.api.db.DbException;
|
||||||
|
import net.sf.briar.api.db.NeighbourId;
|
||||||
|
import net.sf.briar.api.db.Rating;
|
||||||
|
import net.sf.briar.api.db.Status;
|
||||||
|
import net.sf.briar.api.protocol.AuthorId;
|
||||||
|
import net.sf.briar.api.protocol.Batch;
|
||||||
|
import net.sf.briar.api.protocol.BatchId;
|
||||||
|
import net.sf.briar.api.protocol.Bundle;
|
||||||
|
import net.sf.briar.api.protocol.GroupId;
|
||||||
|
import net.sf.briar.api.protocol.Message;
|
||||||
|
import net.sf.briar.api.protocol.MessageId;
|
||||||
|
|
||||||
|
class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Locks must always be acquired in alphabetical order. See the Database
|
||||||
|
* interface to find out which calls require which locks.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private final Object messageLock = new Object();
|
||||||
|
private final Object neighbourLock = new Object();
|
||||||
|
private final Object ratingLock = new Object();
|
||||||
|
private final Object subscriptionLock = new Object();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SynchronizedDatabaseComponent(Database<Txn> db,
|
||||||
|
Provider<Batch> batchProvider) {
|
||||||
|
super(db, batchProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void expireMessages(long size) throws DbException {
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
Txn txn = db.startTransaction("cleaner");
|
||||||
|
try {
|
||||||
|
for(MessageId m : db.getOldMessages(txn, size)) {
|
||||||
|
removeMessage(txn, m);
|
||||||
|
}
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws DbException {
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
synchronized(ratingLock) {
|
||||||
|
synchronized(subscriptionLock) {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNeighbour(NeighbourId n) throws DbException {
|
||||||
|
System.out.println("Adding neighbour " + n);
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
Txn txn = db.startTransaction("addNeighbour");
|
||||||
|
try {
|
||||||
|
db.addNeighbour(txn, n);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addLocallyGeneratedMessage(Message m) throws DbException {
|
||||||
|
waitForPermissionToWrite();
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
synchronized(subscriptionLock) {
|
||||||
|
Txn txn = db.startTransaction("addLocallyGeneratedMessage");
|
||||||
|
try {
|
||||||
|
if(db.containsSubscription(txn, m.getGroup())) {
|
||||||
|
boolean added = storeMessage(txn, m, null);
|
||||||
|
assert added;
|
||||||
|
} else {
|
||||||
|
System.out.println("Not subscribed");
|
||||||
|
}
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rating getRating(AuthorId a) throws DbException {
|
||||||
|
synchronized(ratingLock) {
|
||||||
|
Txn txn = db.startTransaction("getRating");
|
||||||
|
try {
|
||||||
|
Rating r = db.getRating(txn, a);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return r;
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRating(AuthorId a, Rating r) throws DbException {
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(ratingLock) {
|
||||||
|
Txn txn = db.startTransaction("setRating");
|
||||||
|
try {
|
||||||
|
Rating old = db.setRating(txn, a, r);
|
||||||
|
// Update the sendability of the author's messages
|
||||||
|
if(r == Rating.GOOD && old != Rating.GOOD)
|
||||||
|
updateAuthorSendability(txn, a, true);
|
||||||
|
else if(r != Rating.GOOD && old == Rating.GOOD)
|
||||||
|
updateAuthorSendability(txn, a, false);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<GroupId> getSubscriptions() throws DbException {
|
||||||
|
synchronized(subscriptionLock) {
|
||||||
|
Txn txn = db.startTransaction("getSubscriptions");
|
||||||
|
try {
|
||||||
|
HashSet<GroupId> subs = new HashSet<GroupId>();
|
||||||
|
for(GroupId g : db.getSubscriptions(txn)) subs.add(g);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return subs;
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribe(GroupId g) throws DbException {
|
||||||
|
System.out.println("Subscribing to " + g);
|
||||||
|
synchronized(subscriptionLock) {
|
||||||
|
Txn txn = db.startTransaction("subscribe");
|
||||||
|
try {
|
||||||
|
db.addSubscription(txn, g);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribe(GroupId g) throws DbException {
|
||||||
|
System.out.println("Unsubscribing from " + g);
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
synchronized(subscriptionLock) {
|
||||||
|
Txn txn = db.startTransaction("unsubscribe");
|
||||||
|
try {
|
||||||
|
db.removeSubscription(txn, g);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void generateBundle(NeighbourId n, Bundle b) throws DbException {
|
||||||
|
System.out.println("Generating bundle for " + n);
|
||||||
|
// Ack all batches received from the neighbour
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
Txn txn = db.startTransaction("generateBundle:acks");
|
||||||
|
try {
|
||||||
|
int numAcks = 0;
|
||||||
|
for(BatchId ack : db.removeBatchesToAck(txn, n)) {
|
||||||
|
b.addAck(ack);
|
||||||
|
numAcks++;
|
||||||
|
}
|
||||||
|
System.out.println("Added " + numAcks + " acks");
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add a list of subscriptions
|
||||||
|
synchronized(subscriptionLock) {
|
||||||
|
Txn txn = db.startTransaction("generateBundle:subscriptions");
|
||||||
|
try {
|
||||||
|
int numSubs = 0;
|
||||||
|
for(GroupId g : db.getSubscriptions(txn)) {
|
||||||
|
b.addSubscription(g);
|
||||||
|
numSubs++;
|
||||||
|
}
|
||||||
|
System.out.println("Added " + numSubs + " subscriptions");
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add as many messages as possible to the bundle
|
||||||
|
long capacity = b.getCapacity();
|
||||||
|
while(true) {
|
||||||
|
Batch batch = fillBatch(n, capacity);
|
||||||
|
if(batch == null) break; // No more messages to send
|
||||||
|
b.addBatch(batch);
|
||||||
|
capacity -= batch.getSize();
|
||||||
|
// If the batch is less than half full, stop trying - there may be
|
||||||
|
// more messages trickling in but we can't wait forever
|
||||||
|
if(batch.getSize() * 2 < Batch.CAPACITY) break;
|
||||||
|
}
|
||||||
|
b.seal();
|
||||||
|
System.out.println("Bundle sent, " + b.getSize() + " bytes");
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Batch fillBatch(NeighbourId n, long capacity) throws DbException {
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
Txn txn = db.startTransaction("fillBatch");
|
||||||
|
try {
|
||||||
|
capacity = Math.min(capacity, Batch.CAPACITY);
|
||||||
|
Iterator<MessageId> it =
|
||||||
|
db.getSendableMessages(txn, n, capacity).iterator();
|
||||||
|
if(!it.hasNext()) {
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return null; // No more messages to send
|
||||||
|
}
|
||||||
|
Batch b = batchProvider.get();
|
||||||
|
Set<MessageId> sent = new HashSet<MessageId>();
|
||||||
|
while(it.hasNext()) {
|
||||||
|
MessageId m = it.next();
|
||||||
|
b.addMessage(db.getMessage(txn, m));
|
||||||
|
sent.add(m);
|
||||||
|
}
|
||||||
|
b.seal();
|
||||||
|
// Record the contents of the batch
|
||||||
|
assert !sent.isEmpty();
|
||||||
|
db.addOutstandingBatch(txn, n, b.getId(), sent);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
return b;
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void receiveBundle(NeighbourId n, Bundle b) throws DbException {
|
||||||
|
System.out.println("Received bundle from " + n + ", "
|
||||||
|
+ b.getSize() + " bytes");
|
||||||
|
// Mark all messages in acked batches as seen
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
int acks = 0, expired = 0;
|
||||||
|
for(BatchId ack : b.getAcks()) {
|
||||||
|
acks++;
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:acks");
|
||||||
|
try {
|
||||||
|
Iterable<MessageId> batch =
|
||||||
|
db.removeOutstandingBatch(txn, n, ack);
|
||||||
|
// May be null if the batch was empty or has expired
|
||||||
|
if(batch == null) {
|
||||||
|
expired++;
|
||||||
|
} else {
|
||||||
|
for(MessageId m : batch) {
|
||||||
|
// Don't re-create statuses for expired messages
|
||||||
|
if(db.containsMessage(txn, m))
|
||||||
|
db.setStatus(txn, n, m, Status.SEEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Received " + acks + " acks, " + expired
|
||||||
|
+ " expired");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Update the neighbour's subscriptions
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:subscriptions");
|
||||||
|
try {
|
||||||
|
db.clearSubscriptions(txn, n);
|
||||||
|
int subs = 0;
|
||||||
|
for(GroupId g : b.getSubscriptions()) {
|
||||||
|
subs++;
|
||||||
|
db.addSubscription(txn, n, g);
|
||||||
|
}
|
||||||
|
System.out.println("Received " + subs + " subscriptions");
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Store the messages
|
||||||
|
int batches = 0;
|
||||||
|
for(Batch batch : b.getBatches()) {
|
||||||
|
batches++;
|
||||||
|
waitForPermissionToWrite();
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
synchronized(subscriptionLock) {
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:batch");
|
||||||
|
try {
|
||||||
|
int received = 0, stored = 0;
|
||||||
|
for(Message m : batch.getMessages()) {
|
||||||
|
received++;
|
||||||
|
if(db.containsSubscription(txn, m.getGroup())) {
|
||||||
|
if(storeMessage(txn, m, n)) stored++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Received " + received
|
||||||
|
+ " messages, stored " + stored);
|
||||||
|
db.addBatchToAck(txn, n, batch.getId());
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("Received " + batches + " batches");
|
||||||
|
// Find any lost batches that need to be retransmitted
|
||||||
|
Set<BatchId> lost;
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:findLost");
|
||||||
|
try {
|
||||||
|
lost = db.addReceivedBundle(txn, n, b.getId());
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(BatchId batch : lost) {
|
||||||
|
synchronized(messageLock) {
|
||||||
|
synchronized(neighbourLock) {
|
||||||
|
Txn txn = db.startTransaction("receiveBundle:removeLost");
|
||||||
|
try {
|
||||||
|
System.out.println("Removing lost batch");
|
||||||
|
db.removeLostBatch(txn, n, batch);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.gc();
|
||||||
|
}
|
||||||
|
}
|
||||||
99
components/net/sf/briar/i18n/FontManagerImpl.java
Normal file
99
components/net/sf/briar/i18n/FontManagerImpl.java
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
package net.sf.briar.i18n;
|
||||||
|
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.FontFormatException;
|
||||||
|
import java.awt.font.TextAttribute;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.FontManager;
|
||||||
|
import net.sf.briar.util.FileUtils;
|
||||||
|
|
||||||
|
public class FontManagerImpl implements FontManager {
|
||||||
|
|
||||||
|
private static final BundledFont[] BUNDLED_FONTS = {
|
||||||
|
new BundledFont("TibetanMachineUni.ttf", 14f, new String[] { "bo" }),
|
||||||
|
new BundledFont("Padauk.ttf", 14f, new String[] { "my" }),
|
||||||
|
};
|
||||||
|
|
||||||
|
private final Map<String, Font> fonts = new TreeMap<String, Font>();
|
||||||
|
|
||||||
|
private volatile Font defaultFont = null, uiFont = null;
|
||||||
|
|
||||||
|
public void initialize(Locale locale) throws IOException {
|
||||||
|
try {
|
||||||
|
ClassLoader loader = getClass().getClassLoader();
|
||||||
|
for(BundledFont bf : BUNDLED_FONTS) {
|
||||||
|
InputStream in = loader.getResourceAsStream(bf.filename);
|
||||||
|
if(in == null) {
|
||||||
|
File root = FileUtils.getBriarDirectory();
|
||||||
|
File file = new File(root, "Data/" + bf.filename);
|
||||||
|
in = new FileInputStream(file);
|
||||||
|
}
|
||||||
|
Font font = Font.createFont(Font.TRUETYPE_FONT, in);
|
||||||
|
font = font.deriveFont(bf.size);
|
||||||
|
for(String language : bf.languages) fonts.put(language, font);
|
||||||
|
}
|
||||||
|
} catch(FontFormatException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
defaultFont = getFont("Sans", 12f);
|
||||||
|
assert defaultFont != null; // FIXME: This is failing on Windows
|
||||||
|
setUiFontForLanguage(locale.getLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Font getFont(String name, float size) {
|
||||||
|
Map<TextAttribute, Object> attr = new HashMap<TextAttribute, Object>();
|
||||||
|
attr.put(TextAttribute.FAMILY, name);
|
||||||
|
attr.put(TextAttribute.SIZE, Float.valueOf(size));
|
||||||
|
return Font.getFont(attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getBundledFontFilenames() {
|
||||||
|
String[] names = new String[BUNDLED_FONTS.length];
|
||||||
|
for(int i = 0; i < BUNDLED_FONTS.length; i++)
|
||||||
|
names[i] = BUNDLED_FONTS[i].filename;
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Font getFontForLanguage(String language) {
|
||||||
|
assert defaultFont != null;
|
||||||
|
Font font = fonts.get(language);
|
||||||
|
return font == null ? defaultFont : font;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Font getUiFont() {
|
||||||
|
return uiFont;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUiFontForLanguage(String language) {
|
||||||
|
uiFont = getFontForLanguage(language);
|
||||||
|
Enumeration<Object> keys = UIManager.getDefaults().keys();
|
||||||
|
while(keys.hasMoreElements()) {
|
||||||
|
Object key = keys.nextElement();
|
||||||
|
if(UIManager.getFont(key) != null) UIManager.put(key, uiFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class BundledFont {
|
||||||
|
|
||||||
|
private final String filename;
|
||||||
|
private final float size;
|
||||||
|
private final String[] languages;
|
||||||
|
|
||||||
|
BundledFont(String filename, float size, String[] languages) {
|
||||||
|
this.filename = filename;
|
||||||
|
this.size = size;
|
||||||
|
this.languages = languages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
152
components/net/sf/briar/i18n/I18nImpl.java
Normal file
152
components/net/sf/briar/i18n/I18nImpl.java
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
package net.sf.briar.i18n;
|
||||||
|
|
||||||
|
import java.awt.ComponentOrientation;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.MissingResourceException;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.FontManager;
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.util.FileUtils;
|
||||||
|
|
||||||
|
public class I18nImpl implements I18n {
|
||||||
|
|
||||||
|
private static final String[] uiManagerKeys = {
|
||||||
|
"FileChooser.acceptAllFileFilterText",
|
||||||
|
"FileChooser.cancelButtonText",
|
||||||
|
"FileChooser.cancelButtonToolTipText",
|
||||||
|
"FileChooser.detailsViewButtonAccessibleName",
|
||||||
|
"FileChooser.detailsViewButtonToolTipText",
|
||||||
|
"FileChooser.directoryOpenButtonText",
|
||||||
|
"FileChooser.directoryOpenButtonToolTipText",
|
||||||
|
"FileChooser.fileAttrHeaderText",
|
||||||
|
"FileChooser.fileDateHeaderText",
|
||||||
|
"FileChooser.fileNameHeaderText",
|
||||||
|
"FileChooser.fileNameLabelText",
|
||||||
|
"FileChooser.fileSizeHeaderText",
|
||||||
|
"FileChooser.filesOfTypeLabelText",
|
||||||
|
"FileChooser.fileTypeHeaderText",
|
||||||
|
"FileChooser.helpButtonText",
|
||||||
|
"FileChooser.helpButtonToolTipText",
|
||||||
|
"FileChooser.homeFolderAccessibleName",
|
||||||
|
"FileChooser.homeFolderToolTipText",
|
||||||
|
"FileChooser.listViewButtonAccessibleName",
|
||||||
|
"FileChooser.listViewButtonToolTipText",
|
||||||
|
"FileChooser.lookInLabelText",
|
||||||
|
"FileChooser.newFolderErrorText",
|
||||||
|
"FileChooser.newFolderToolTipText",
|
||||||
|
"FileChooser.openButtonText",
|
||||||
|
"FileChooser.openButtonToolTipText",
|
||||||
|
"FileChooser.openDialogTitleText",
|
||||||
|
"FileChooser.saveButtonText",
|
||||||
|
"FileChooser.saveButtonToolTipText",
|
||||||
|
"FileChooser.saveDialogTitleText",
|
||||||
|
"FileChooser.saveInLabelText",
|
||||||
|
"FileChooser.updateButtonText",
|
||||||
|
"FileChooser.updateButtonToolTipText",
|
||||||
|
"FileChooser.upFolderAccessibleName",
|
||||||
|
"FileChooser.upFolderToolTipText",
|
||||||
|
"OptionPane.cancelButtonText",
|
||||||
|
"OptionPane.noButtonText",
|
||||||
|
"OptionPane.yesButtonText",
|
||||||
|
"ProgressMonitor.progressText"
|
||||||
|
};
|
||||||
|
|
||||||
|
private final Object bundleLock = new Object();
|
||||||
|
private final ClassLoader loader = I18n.class.getClassLoader();
|
||||||
|
private final Set<Listener> listeners = new HashSet<Listener>();
|
||||||
|
private final FontManager fontManager;
|
||||||
|
|
||||||
|
private volatile Locale locale = Locale.getDefault();
|
||||||
|
private volatile ResourceBundle bundle = null;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public I18nImpl(FontManager fontManager) {
|
||||||
|
this.fontManager = fontManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String tr(String name) {
|
||||||
|
loadResourceBundle();
|
||||||
|
return bundle.getString(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadResourceBundle() {
|
||||||
|
if(bundle == null) {
|
||||||
|
synchronized(bundleLock) {
|
||||||
|
if(bundle == null) {
|
||||||
|
bundle = ResourceBundle.getBundle("i18n", locale, loader);
|
||||||
|
for(String key : uiManagerKeys) {
|
||||||
|
try {
|
||||||
|
UIManager.put(key, bundle.getString(key));
|
||||||
|
} catch(MissingResourceException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Locale getLocale() {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocale(Locale locale) {
|
||||||
|
fontManager.setUiFontForLanguage(locale.getLanguage());
|
||||||
|
Font uiFont = fontManager.getUiFont();
|
||||||
|
synchronized(bundleLock) {
|
||||||
|
this.locale = locale;
|
||||||
|
bundle = null;
|
||||||
|
synchronized(listeners) {
|
||||||
|
for(Listener l : listeners) l.localeChanged(uiFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadLocale() throws IOException {
|
||||||
|
File root = FileUtils.getBriarDirectory();
|
||||||
|
Scanner s = new Scanner(new File(root, "Data/locale.cfg"));
|
||||||
|
if(s.hasNextLine()) locale = new Locale(s.nextLine());
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveLocale() throws IOException {
|
||||||
|
saveLocale(FileUtils.getBriarDirectory());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveLocale(File dir) throws IOException {
|
||||||
|
File localeCfg = new File(dir, "locale.cfg");
|
||||||
|
FileOutputStream out = new FileOutputStream(localeCfg);
|
||||||
|
PrintStream print = new PrintStream(out);
|
||||||
|
print.println(locale);
|
||||||
|
print.flush();
|
||||||
|
print.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ComponentOrientation getComponentOrientation() {
|
||||||
|
return ComponentOrientation.getOrientation(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(Listener l) {
|
||||||
|
l.localeChanged(fontManager.getUiFont());
|
||||||
|
synchronized(listeners) {
|
||||||
|
listeners.add(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(Listener l) {
|
||||||
|
synchronized(listeners) {
|
||||||
|
listeners.remove(l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
components/net/sf/briar/i18n/I18nModule.java
Normal file
16
components/net/sf/briar/i18n/I18nModule.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package net.sf.briar.i18n;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.FontManager;
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
public class I18nModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(FontManager.class).to(FontManagerImpl.class).in(Singleton.class);
|
||||||
|
bind(I18n.class).to(I18nImpl.class).in(Singleton.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
components/net/sf/briar/invitation/InvitationModule.java
Normal file
13
components/net/sf/briar/invitation/InvitationModule.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package net.sf.briar.invitation;
|
||||||
|
|
||||||
|
import net.sf.briar.api.invitation.InvitationWorkerFactory;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
|
||||||
|
public class InvitationModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(InvitationWorkerFactory.class).to(InvitationWorkerFactoryImpl.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
104
components/net/sf/briar/invitation/InvitationWorker.java
Normal file
104
components/net/sf/briar/invitation/InvitationWorker.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package net.sf.briar.invitation;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.sf.briar.api.invitation.InvitationCallback;
|
||||||
|
import net.sf.briar.api.invitation.InvitationParameters;
|
||||||
|
import net.sf.briar.util.FileUtils;
|
||||||
|
|
||||||
|
class InvitationWorker implements Runnable {
|
||||||
|
|
||||||
|
private final InvitationCallback callback;
|
||||||
|
private final InvitationParameters parameters;
|
||||||
|
|
||||||
|
InvitationWorker(final InvitationCallback callback,
|
||||||
|
InvitationParameters parameters) {
|
||||||
|
this.callback = callback;
|
||||||
|
this.parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
File dir = parameters.getChosenLocation();
|
||||||
|
assert dir != null;
|
||||||
|
if(!dir.exists()) {
|
||||||
|
callback.notFound(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!dir.isDirectory()) {
|
||||||
|
callback.notDirectory(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!dir.canWrite()) {
|
||||||
|
callback.notAllowed(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<File> files = new ArrayList<File>();
|
||||||
|
try {
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
File invitationDat = createInvitationDat(dir);
|
||||||
|
files.add(invitationDat);
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
if(parameters.shouldCreateExe()) {
|
||||||
|
File briarExe = createBriarExe(dir);
|
||||||
|
files.add(briarExe);
|
||||||
|
}
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
if(parameters.shouldCreateJar()) {
|
||||||
|
File briarJar = createBriarJar(dir);
|
||||||
|
files.add(briarJar);
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
callback.error(e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
callback.created(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
private File createInvitationDat(File dir) throws IOException {
|
||||||
|
char[] password = parameters.getPassword();
|
||||||
|
assert password != null;
|
||||||
|
File invitationDat = new File(dir, "invitation.dat");
|
||||||
|
callback.encryptingFile(invitationDat);
|
||||||
|
// FIXME: Create a real invitation
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch(InterruptedException ignored) {
|
||||||
|
}
|
||||||
|
Arrays.fill(password, (char) 0);
|
||||||
|
FileOutputStream out = new FileOutputStream(invitationDat);
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
new Random().nextBytes(buf);
|
||||||
|
out.write(buf, 0, buf.length);
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
return invitationDat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File createBriarExe(File dir) throws IOException {
|
||||||
|
File f = new File(dir, "briar.exe");
|
||||||
|
copyInstaller(f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File createBriarJar(File dir) throws IOException {
|
||||||
|
File f = new File(dir, "briar.jar");
|
||||||
|
copyInstaller(f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyInstaller(File dest) throws IOException {
|
||||||
|
File root = FileUtils.getBriarDirectory();
|
||||||
|
File src = new File(root, "Data/setup.dat");
|
||||||
|
if(!src.exists() || !src.isFile())
|
||||||
|
throw new IOException("File not found: " + src.getPath());
|
||||||
|
callback.copyingFile(dest);
|
||||||
|
FileUtils.copy(src, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package net.sf.briar.invitation;
|
||||||
|
|
||||||
|
import net.sf.briar.api.invitation.InvitationCallback;
|
||||||
|
import net.sf.briar.api.invitation.InvitationParameters;
|
||||||
|
import net.sf.briar.api.invitation.InvitationWorkerFactory;
|
||||||
|
|
||||||
|
class InvitationWorkerFactoryImpl implements InvitationWorkerFactory {
|
||||||
|
|
||||||
|
public Runnable createWorker(InvitationCallback callback,
|
||||||
|
InvitationParameters parameters) {
|
||||||
|
return new InvitationWorker(callback, parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
components/net/sf/briar/protocol/BatchImpl.java
Normal file
40
components/net/sf/briar/protocol/BatchImpl.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package net.sf.briar.protocol;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.sf.briar.api.protocol.Batch;
|
||||||
|
import net.sf.briar.api.protocol.BatchId;
|
||||||
|
import net.sf.briar.api.protocol.Message;
|
||||||
|
|
||||||
|
class BatchImpl implements Batch {
|
||||||
|
|
||||||
|
private final List<Message> messages = new ArrayList<Message>();
|
||||||
|
private BatchId id = null;
|
||||||
|
private long size = 0L;
|
||||||
|
|
||||||
|
public void seal() {
|
||||||
|
System.out.println("FIXME: Calculate batch ID");
|
||||||
|
byte[] b = new byte[BatchId.LENGTH];
|
||||||
|
new Random().nextBytes(b);
|
||||||
|
id = new BatchId(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BatchId getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterable<Message> getMessages() {
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMessage(Message m) {
|
||||||
|
messages.add(m);
|
||||||
|
size += m.getSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
63
components/net/sf/briar/protocol/MessageImpl.java
Normal file
63
components/net/sf/briar/protocol/MessageImpl.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package net.sf.briar.protocol;
|
||||||
|
|
||||||
|
import net.sf.briar.api.protocol.AuthorId;
|
||||||
|
import net.sf.briar.api.protocol.GroupId;
|
||||||
|
import net.sf.briar.api.protocol.Message;
|
||||||
|
import net.sf.briar.api.protocol.MessageId;
|
||||||
|
|
||||||
|
class MessageImpl implements Message {
|
||||||
|
|
||||||
|
private final MessageId id, parent;
|
||||||
|
private final GroupId group;
|
||||||
|
private final AuthorId author;
|
||||||
|
private final long timestamp;
|
||||||
|
private final byte[] body;
|
||||||
|
|
||||||
|
public MessageImpl(MessageId id, MessageId parent, GroupId group,
|
||||||
|
AuthorId author, long timestamp, byte[] body) {
|
||||||
|
this.id = id;
|
||||||
|
this.parent = parent;
|
||||||
|
this.group = group;
|
||||||
|
this.author = author;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageId getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageId getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupId getGroup() {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthorId getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return body.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return o instanceof MessageImpl && id.equals(((MessageImpl)o).id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
20
components/net/sf/briar/protocol/ProtocolModule.java
Normal file
20
components/net/sf/briar/protocol/ProtocolModule.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package net.sf.briar.protocol;
|
||||||
|
|
||||||
|
import net.sf.briar.api.protocol.Batch;
|
||||||
|
import net.sf.briar.api.protocol.Message;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
|
||||||
|
public class ProtocolModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(Message.class).to(MessageImpl.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
Batch createBatch() {
|
||||||
|
return new BatchImpl();
|
||||||
|
}
|
||||||
|
}
|
||||||
13
components/net/sf/briar/setup/SetupModule.java
Normal file
13
components/net/sf/briar/setup/SetupModule.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package net.sf.briar.setup;
|
||||||
|
|
||||||
|
import net.sf.briar.api.setup.SetupWorkerFactory;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
|
||||||
|
public class SetupModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(SetupWorkerFactory.class).to(SetupWorkerFactoryImpl.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
157
components/net/sf/briar/setup/SetupWorker.java
Normal file
157
components/net/sf/briar/setup/SetupWorker.java
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
package net.sf.briar.setup;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.security.CodeSource;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.setup.SetupCallback;
|
||||||
|
import net.sf.briar.api.setup.SetupParameters;
|
||||||
|
import net.sf.briar.util.FileUtils;
|
||||||
|
import net.sf.briar.util.OsUtils;
|
||||||
|
import net.sf.briar.util.ZipUtils;
|
||||||
|
|
||||||
|
class SetupWorker implements Runnable {
|
||||||
|
|
||||||
|
private static final String MAIN_CLASS =
|
||||||
|
"net.sf.briar.ui.invitation.InvitationMain";
|
||||||
|
private static final int EXE_HEADER_SIZE = 62976;
|
||||||
|
|
||||||
|
private final SetupCallback callback;
|
||||||
|
private final SetupParameters parameters;
|
||||||
|
private final I18n i18n;
|
||||||
|
private final ZipUtils.Callback unzipCallback;
|
||||||
|
|
||||||
|
SetupWorker(final SetupCallback callback, SetupParameters parameters,
|
||||||
|
I18n i18n) {
|
||||||
|
this.parameters = parameters;
|
||||||
|
this.callback = callback;
|
||||||
|
this.i18n = i18n;
|
||||||
|
unzipCallback = new ZipUtils.Callback() {
|
||||||
|
public void processingFile(File f) {
|
||||||
|
callback.extractingFile(f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
File dir = parameters.getChosenLocation();
|
||||||
|
assert dir != null;
|
||||||
|
if(!dir.exists()) {
|
||||||
|
callback.notFound(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!dir.isDirectory()) {
|
||||||
|
callback.notDirectory(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String[] list = dir.list();
|
||||||
|
if(list == null || !dir.canWrite()) {
|
||||||
|
callback.notAllowed(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(list.length != 0) {
|
||||||
|
dir = new File(dir, "Briar");
|
||||||
|
if(!dir.exists() && !dir.mkdir()) {
|
||||||
|
callback.notAllowed(dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File data = new File(dir, "Data");
|
||||||
|
if(!data.exists() && !data.mkdir()) {
|
||||||
|
callback.notAllowed(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
File jar = getJar();
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
copyInstaller(jar, data);
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
extractFiles(jar, data, "^jre/.*|.*\\.jar$|.*\\.ttf$");
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
createLaunchers(dir);
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
i18n.saveLocale(data);
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
jar.deleteOnExit();
|
||||||
|
} catch(IOException e) {
|
||||||
|
callback.error(e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(callback.isCancelled()) return;
|
||||||
|
callback.installed(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getJar() throws IOException {
|
||||||
|
CodeSource c = FileUtils.class.getProtectionDomain().getCodeSource();
|
||||||
|
File jar = new File(c.getLocation().getPath());
|
||||||
|
assert jar.exists();
|
||||||
|
if(!jar.isFile()) throw new IOException("Not running from a jar");
|
||||||
|
return jar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyInstaller(File jar, File dir) throws IOException {
|
||||||
|
File dest = new File(dir, "setup.dat");
|
||||||
|
callback.copyingFile(dest);
|
||||||
|
FileUtils.copy(jar, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void extractFiles(File jar, File dir, String regex)
|
||||||
|
throws IOException {
|
||||||
|
FileInputStream in = new FileInputStream(jar);
|
||||||
|
in.skip(EXE_HEADER_SIZE);
|
||||||
|
ZipUtils.unzipStream(in, dir, regex, unzipCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createLaunchers(File dir) throws IOException {
|
||||||
|
createWindowsLauncher(dir);
|
||||||
|
File mac = createMacLauncher(dir);
|
||||||
|
File lin = createLinuxLauncher(dir);
|
||||||
|
if(!OsUtils.isWindows()) {
|
||||||
|
String[] chmod = { "chmod", "u+x", mac.getName(), lin.getName() };
|
||||||
|
ProcessBuilder p = new ProcessBuilder(chmod);
|
||||||
|
p.directory(dir);
|
||||||
|
p.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private File createWindowsLauncher(File dir) throws IOException {
|
||||||
|
File launcher = new File(dir, "run-windows.vbs");
|
||||||
|
PrintStream out = new PrintStream(new FileOutputStream(launcher));
|
||||||
|
out.print("Set Shell = CreateObject(\"WScript.Shell\")\r\n");
|
||||||
|
out.print("Shell.Run \"Data\\jre\\bin\\javaw -ea -cp Data\\* "
|
||||||
|
+ MAIN_CLASS + "\", 0\r\n");
|
||||||
|
out.print("Set Shell = Nothing\r\n");
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
return launcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: If this pops up a terminal window, the Mac launcher may need
|
||||||
|
// to be a jar
|
||||||
|
private File createMacLauncher(File dir) throws IOException {
|
||||||
|
File launcher = new File(dir, "run-mac.command");
|
||||||
|
PrintStream out = new PrintStream(new FileOutputStream(launcher));
|
||||||
|
out.print("#!/bin/sh\n");
|
||||||
|
out.print("cd \"$(dirname \"$0\")\"\n");
|
||||||
|
out.print("java -ea -cp 'Data/*' " + MAIN_CLASS + "\n");
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
return launcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File createLinuxLauncher(File dir) throws IOException {
|
||||||
|
File launcher = new File(dir, "run-linux.sh");
|
||||||
|
PrintStream out = new PrintStream(new FileOutputStream(launcher));
|
||||||
|
out.print("#!/bin/sh\n");
|
||||||
|
out.print("cd \"$(dirname \"$0\")\"\n");
|
||||||
|
out.print("java -ea -cp 'Data/*' " + MAIN_CLASS + "\n");
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
return launcher;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
components/net/sf/briar/setup/SetupWorkerFactoryImpl.java
Normal file
23
components/net/sf/briar/setup/SetupWorkerFactoryImpl.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package net.sf.briar.setup;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.setup.SetupCallback;
|
||||||
|
import net.sf.briar.api.setup.SetupParameters;
|
||||||
|
import net.sf.briar.api.setup.SetupWorkerFactory;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
public class SetupWorkerFactoryImpl implements SetupWorkerFactory {
|
||||||
|
|
||||||
|
private final I18n i18n;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public SetupWorkerFactoryImpl(I18n i18n) {
|
||||||
|
this.i18n = i18n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Runnable createWorker(SetupCallback callback,
|
||||||
|
SetupParameters parameters) {
|
||||||
|
return new SetupWorker(callback, parameters, i18n);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
dependencies.xml
Normal file
42
dependencies.xml
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<project name='dependencies' default='depend.all'>
|
||||||
|
|
||||||
|
<dirname property='depend.root' file='${ant.file.dependencies}'/>
|
||||||
|
|
||||||
|
<target name='depend.all' depends='depend.components, depend.ui'>
|
||||||
|
</target>
|
||||||
|
<target name='depend.api'>
|
||||||
|
<ant dir='${depend.root}/api' inheritAll='false'/>
|
||||||
|
</target>
|
||||||
|
<target name='depend.components' depends='depend.api, depend.util'>
|
||||||
|
<ant dir='${depend.root}/components' inheritAll='false'/>
|
||||||
|
</target>
|
||||||
|
<target name='depend.ui' depends='depend.api, depend.util'>
|
||||||
|
<ant dir='${depend.root}/ui' inheritAll='false'/>
|
||||||
|
</target>
|
||||||
|
<target name='depend.util'>
|
||||||
|
<ant dir='${depend.root}/util' inheritAll='false'/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name='depend-clean.all'
|
||||||
|
depends='depend-clean.components, depend-clean.ui'>
|
||||||
|
</target>
|
||||||
|
<target name='depend-clean.api'>
|
||||||
|
<ant dir='${depend.root}/api' target='clean'
|
||||||
|
inheritAll='false'/>
|
||||||
|
</target>
|
||||||
|
<target name='depend-clean.components'
|
||||||
|
depends='depend-clean.api, depend-clean.util'>
|
||||||
|
<ant dir='${depend.root}/components' target='clean'
|
||||||
|
inheritAll='false'/>
|
||||||
|
</target>
|
||||||
|
<target name='depend-clean.ui'
|
||||||
|
depends='depend-clean.api, depend-clean.util'>
|
||||||
|
<ant dir='${depend.root}/ui' target='clean'
|
||||||
|
inheritAll='false'/>
|
||||||
|
</target>
|
||||||
|
<target name='depend-clean.util'>
|
||||||
|
<ant dir='${depend.root}/util' target='clean'
|
||||||
|
inheritAll='false'/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
</project>
|
||||||
BIN
i18n/Padauk.ttf
Normal file
BIN
i18n/Padauk.ttf
Normal file
Binary file not shown.
BIN
i18n/TibetanMachineUni.ttf
Normal file
BIN
i18n/TibetanMachineUni.ttf
Normal file
Binary file not shown.
73
i18n/i18n.properties
Normal file
73
i18n/i18n.properties
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
BACK=Back
|
||||||
|
NEXT=Next
|
||||||
|
CANCEL=Cancel
|
||||||
|
FINISH=Finish
|
||||||
|
|
||||||
|
YES=Yes
|
||||||
|
NO=No
|
||||||
|
UNKNOWN=Unknown
|
||||||
|
|
||||||
|
CANCELLING=Cancelling, please wait...
|
||||||
|
|
||||||
|
ENCRYPTING_FILE=Encrypting file:
|
||||||
|
EXTRACTING_FILE=Extracting file:
|
||||||
|
COPYING_FILE=Copying file:
|
||||||
|
|
||||||
|
DIRECTORY_NOT_FOUND=The chosen folder was not found:
|
||||||
|
FILE_NOT_DIRECTORY=The chosen location is not a folder:
|
||||||
|
DIRECTORY_NOT_ALLOWED=You do not have permission to use the chosen folder:
|
||||||
|
|
||||||
|
WINDOWS=Windows
|
||||||
|
MAC=Macintosh
|
||||||
|
LINUX=Linux
|
||||||
|
|
||||||
|
ENTER_PASSWORD=Enter password:
|
||||||
|
CONFIRM_PASSWORD=Confirm password:
|
||||||
|
|
||||||
|
INVITATION_TITLE=Create Invitation
|
||||||
|
INVITATION_INTRO=\
|
||||||
|
This wizard will guide you through the process of inviting a new contact to \
|
||||||
|
join Briar. <p><p>\
|
||||||
|
The wizard will create some files that you must give to your contact. <p><p>\
|
||||||
|
You will also be asked to choose a password, which your contact will use to \
|
||||||
|
unlock the invitation.
|
||||||
|
INVITATION_EXISTING_USER=Does your contact already use Briar?
|
||||||
|
INVITATION_OPERATING_SYSTEM=What kind of computer does your contact use?
|
||||||
|
INVITATION_PASSWORD=\
|
||||||
|
Please choose a password for the invitation. <p><p>\
|
||||||
|
Your contact will need this password to unlock the invitation. <p><p>\
|
||||||
|
It is very important that you DO NOT send this password across the internet \
|
||||||
|
or by SMS.
|
||||||
|
INVITATION_LOCATION_TEXT=\
|
||||||
|
Please choose where to save the invitation files. <p><p>\
|
||||||
|
It is recommended to save them on a removable device such as a USB stick. \
|
||||||
|
Alternatively, you can send them to your contact by Bluetooth. <p><p>\
|
||||||
|
Please press Next to choose a location.
|
||||||
|
INVITATION_LOCATION_TITLE=Save Invitation Files
|
||||||
|
INVITATION_PROGRESS_BEGIN=Preparing to create invitation...
|
||||||
|
INVITATION_CREATED=The following files have been created:
|
||||||
|
INVITATION_GIVE_TO_CONTACT=\
|
||||||
|
Please give these files and the password to your contact.
|
||||||
|
INVITATION_ERROR=An error occurred while creating the invitation:
|
||||||
|
INVITATION_ABORTED=The invitation could not be not created.
|
||||||
|
|
||||||
|
SETUP_TITLE=Setup
|
||||||
|
SETUP_LANGUAGE=\
|
||||||
|
Welcome to the setup program for Briar, a secure news and discussion \
|
||||||
|
network. <p><p>\
|
||||||
|
Please choose a language and press Next to begin the installation.
|
||||||
|
SETUP_ALREADY_INSTALLED=Are you already a user of Briar?
|
||||||
|
SETUP_INSTRUCTIONS=\
|
||||||
|
To accept the person who sent you this invitation as a contact, please open \
|
||||||
|
the invitation.dat file in Briar by selecting File > Open from the menu, or \
|
||||||
|
by dragging the file onto the Briar window.
|
||||||
|
SETUP_LOCATION_TEXT=\
|
||||||
|
It is recommended to install Briar on a removable device such as a USB \
|
||||||
|
stick. <p><p>\
|
||||||
|
Please press Next to choose the folder where Briar will be installed.
|
||||||
|
SETUP_LOCATION_TITLE=Choose Folder
|
||||||
|
SETUP_PROGRESS_BEGIN=Preparing to install...
|
||||||
|
SETUP_INSTALLED=Briar has been installed in the following folder:
|
||||||
|
SETUP_UNINSTALL=To uninstall Briar, simply delete the folder.
|
||||||
|
SETUP_ERROR=An error occurred while installing:
|
||||||
|
SETUP_ABORTED=The installation could not be completed.
|
||||||
2
i18n/i18n_bo.properties
Normal file
2
i18n/i18n_bo.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Note: It seems to be necessary to insert a zero-width space (\u200b) after
|
||||||
|
# every inter-word dot (\u0f0b) to allow line-breaking.
|
||||||
37
installer/net/sf/briar/ui/setup/SetupMain.java
Normal file
37
installer/net/sf/briar/ui/setup/SetupMain.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package net.sf.briar.ui.setup;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.FontManager;
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.setup.SetupParameters;
|
||||||
|
import net.sf.briar.api.setup.SetupWorkerFactory;
|
||||||
|
import net.sf.briar.i18n.FontManagerImpl;
|
||||||
|
import net.sf.briar.i18n.I18nImpl;
|
||||||
|
import net.sf.briar.setup.SetupWorkerFactoryImpl;
|
||||||
|
import net.sf.briar.util.OsUtils;
|
||||||
|
|
||||||
|
public class SetupMain {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
if(OsUtils.isWindows() || OsUtils.isMac())
|
||||||
|
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||||
|
|
||||||
|
FontManager fontManager = new FontManagerImpl();
|
||||||
|
I18n i18n = new I18nImpl(fontManager);
|
||||||
|
SetupWorkerFactory workerFactory = new SetupWorkerFactoryImpl(i18n);
|
||||||
|
SetupWizard wizard = new SetupWizard(i18n);
|
||||||
|
new LanguagePanel(wizard, fontManager, i18n);
|
||||||
|
new AlreadyInstalledPanel(wizard, i18n);
|
||||||
|
new InstructionsPanel(wizard, i18n);
|
||||||
|
LocationPanel locationPanel = new LocationPanel(wizard, i18n);
|
||||||
|
SetupParameters parameters =
|
||||||
|
new SetupParametersImpl(locationPanel, fontManager);
|
||||||
|
new SetupWorkerPanel(wizard, workerFactory, parameters, i18n);
|
||||||
|
|
||||||
|
fontManager.initialize(Locale.getDefault());
|
||||||
|
wizard.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
lib/guice-3.0-no_aop.jar
Normal file
BIN
lib/guice-3.0-no_aop.jar
Normal file
Binary file not shown.
BIN
lib/h2small-1.3.154.jar
Normal file
BIN
lib/h2small-1.3.154.jar
Normal file
Binary file not shown.
2
lib/installer.manifest
Normal file
2
lib/installer.manifest
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Main-Class: net.sf.briar.ui.setup.SetupMain
|
||||||
|
|
||||||
BIN
lib/javax.inject-1.jar
Normal file
BIN
lib/javax.inject-1.jar
Normal file
Binary file not shown.
7
lib/setup.vbs
Normal file
7
lib/setup.vbs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Set Shell = CreateObject("WScript.Shell")
|
||||||
|
Shell.Run "briar.tmp\jre\bin\javaw -ea -jar briar.exe", 0, true
|
||||||
|
Set Shell = Nothing
|
||||||
|
Set Fso = CreateObject("Scripting.FileSystemObject")
|
||||||
|
Fso.DeleteFolder "briar.tmp"
|
||||||
|
Set Fso = Nothing
|
||||||
|
|
||||||
BIN
lib/unzipsfx.exe
Executable file
BIN
lib/unzipsfx.exe
Executable file
Binary file not shown.
25
make-installer.sh
Executable file
25
make-installer.sh
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#FIXME: Replace this with an ant script
|
||||||
|
|
||||||
|
rm -rf temp briar.zip
|
||||||
|
mkdir temp
|
||||||
|
cd bin
|
||||||
|
for dir in api/i18n api/setup i18n setup util ui/setup ui/wizard
|
||||||
|
do
|
||||||
|
mkdir -p ../temp/net/sf/briar/$dir
|
||||||
|
cp net/sf/briar/$dir/*.class ../temp/net/sf/briar/$dir
|
||||||
|
done
|
||||||
|
jar cf ../temp/main.jar net *.properties
|
||||||
|
cd ..
|
||||||
|
cp i18n/*.properties i18n/*.ttf temp
|
||||||
|
cp lib/*.jar temp
|
||||||
|
cp -r windows-jre temp/jre
|
||||||
|
cp lib/setup.vbs temp
|
||||||
|
mkdir temp/META-INF
|
||||||
|
cp lib/installer.manifest temp/META-INF/MANIFEST.MF
|
||||||
|
cd temp
|
||||||
|
echo '$AUTORUN$>start /b briar.tmp\\setup.vbs' | zip -z -r ../briar.zip META-INF net jre *.jar *.properties *.ttf setup.vbs
|
||||||
|
cd ..
|
||||||
|
cat lib/unzipsfx.exe briar.zip > briar.exe
|
||||||
|
rm -rf temp briar.zip
|
||||||
1
ui/.gitignore
vendored
Normal file
1
ui/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
3
ui/build.xml
Normal file
3
ui/build.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<project name='ui' default='compile'>
|
||||||
|
<import file='../build-common.xml'/>
|
||||||
|
</project>
|
||||||
94
ui/net/sf/briar/ui/invitation/ExistingUserPanel.java
Normal file
94
ui/net/sf/briar/ui/invitation/ExistingUserPanel.java
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
package net.sf.briar.ui.invitation;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.GridLayout;
|
||||||
|
|
||||||
|
import javax.swing.ButtonGroup;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JRadioButton;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.Wizard;
|
||||||
|
import net.sf.briar.ui.wizard.WizardPanel;
|
||||||
|
|
||||||
|
class ExistingUserPanel extends WizardPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8536392615847105689L;
|
||||||
|
|
||||||
|
private final Stri18ng question, yes, no, unknown;
|
||||||
|
private final JLabel label;
|
||||||
|
private final JRadioButton yesButton, noButton, unknownButton;
|
||||||
|
|
||||||
|
ExistingUserPanel(Wizard wizard, I18n i18n) {
|
||||||
|
super(wizard, "ExistingUser");
|
||||||
|
question = new Stri18ng("INVITATION_EXISTING_USER", i18n);
|
||||||
|
yes = new Stri18ng("YES", i18n);
|
||||||
|
no = new Stri18ng("NO", i18n);
|
||||||
|
unknown = new Stri18ng("UNKNOWN", i18n);
|
||||||
|
label = new JLabel(question.html());
|
||||||
|
Dimension d = wizard.getPreferredSize();
|
||||||
|
label.setPreferredSize(new Dimension(d.width - 50, 50));
|
||||||
|
label.setVerticalAlignment(SwingConstants.TOP);
|
||||||
|
add(label);
|
||||||
|
yesButton = new JRadioButton(yes.tr());
|
||||||
|
noButton = new JRadioButton(no.tr());
|
||||||
|
unknownButton = new JRadioButton(unknown.tr());
|
||||||
|
ButtonGroup group = new ButtonGroup();
|
||||||
|
group.add(yesButton);
|
||||||
|
group.add(noButton);
|
||||||
|
group.add(unknownButton);
|
||||||
|
unknownButton.setSelected(true);
|
||||||
|
JPanel buttonPanel = new JPanel(new GridLayout(3, 1));
|
||||||
|
buttonPanel.add(yesButton);
|
||||||
|
buttonPanel.add(noButton);
|
||||||
|
buttonPanel.add(unknownButton);
|
||||||
|
add(buttonPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void localeChanged(Font uiFont) {
|
||||||
|
label.setText(question.html());
|
||||||
|
label.setFont(uiFont);
|
||||||
|
yesButton.setText(yes.tr());
|
||||||
|
yesButton.setFont(uiFont);
|
||||||
|
noButton.setText(no.tr());
|
||||||
|
noButton.setFont(uiFont);
|
||||||
|
unknownButton.setText(unknown.tr());
|
||||||
|
unknownButton.setFont(uiFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void display() {
|
||||||
|
wizard.setBackButtonEnabled(true);
|
||||||
|
wizard.setNextButtonEnabled(true);
|
||||||
|
wizard.setFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
wizard.showPanel("Intro");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
if(shouldCreateInstaller()) wizard.showPanel("OperatingSystem");
|
||||||
|
else wizard.showPanel("Password");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cancelButtonPressed() {
|
||||||
|
wizard.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldCreateInstaller() {
|
||||||
|
return !yesButton.isSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
42
ui/net/sf/briar/ui/invitation/IntroPanel.java
Normal file
42
ui/net/sf/briar/ui/invitation/IntroPanel.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package net.sf.briar.ui.invitation;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.TextPanel;
|
||||||
|
import net.sf.briar.ui.wizard.Wizard;
|
||||||
|
|
||||||
|
class IntroPanel extends TextPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 2428034340183141779L;
|
||||||
|
|
||||||
|
IntroPanel(Wizard wizard, I18n i18n) {
|
||||||
|
super(wizard, "Intro", new Stri18ng("INVITATION_INTRO", i18n));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void display() {
|
||||||
|
wizard.setBackButtonEnabled(false);
|
||||||
|
wizard.setNextButtonEnabled(true);
|
||||||
|
wizard.setFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
wizard.showPanel("ExistingUser");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cancelButtonPressed() {
|
||||||
|
wizard.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
ui/net/sf/briar/ui/invitation/InvitationParametersImpl.java
Normal file
50
ui/net/sf/briar/ui/invitation/InvitationParametersImpl.java
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
package net.sf.briar.ui.invitation;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.FontManager;
|
||||||
|
import net.sf.briar.api.invitation.InvitationParameters;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
class InvitationParametersImpl implements InvitationParameters {
|
||||||
|
|
||||||
|
private final ExistingUserPanel existingUserPanel;
|
||||||
|
private final OperatingSystemPanel osPanel;
|
||||||
|
private final PasswordPanel passwordPanel;
|
||||||
|
private final LocationPanel locationPanel;
|
||||||
|
private final FontManager fontManager;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
InvitationParametersImpl(ExistingUserPanel existingUserPanel,
|
||||||
|
OperatingSystemPanel osPanel, PasswordPanel passwordPanel,
|
||||||
|
LocationPanel locationPanel, FontManager fontManager) {
|
||||||
|
this.existingUserPanel = existingUserPanel;
|
||||||
|
this.osPanel = osPanel;
|
||||||
|
this.passwordPanel = passwordPanel;
|
||||||
|
this.locationPanel = locationPanel;
|
||||||
|
this.fontManager = fontManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldCreateExe() {
|
||||||
|
return existingUserPanel.shouldCreateInstaller()
|
||||||
|
&& osPanel.shouldCreateExe();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldCreateJar() {
|
||||||
|
return existingUserPanel.shouldCreateInstaller()
|
||||||
|
&& osPanel.shouldCreateJar();
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] getPassword() {
|
||||||
|
return passwordPanel.getPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getChosenLocation() {
|
||||||
|
return locationPanel.getChosenDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getBundledFontFilenames() {
|
||||||
|
return fontManager.getBundledFontFilenames();
|
||||||
|
}
|
||||||
|
}
|
||||||
19
ui/net/sf/briar/ui/invitation/InvitationWizard.java
Normal file
19
ui/net/sf/briar/ui/invitation/InvitationWizard.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package net.sf.briar.ui.invitation;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.Wizard;
|
||||||
|
|
||||||
|
class InvitationWizard extends Wizard {
|
||||||
|
|
||||||
|
private static final int WIDTH = 400, HEIGHT = 300;
|
||||||
|
|
||||||
|
InvitationWizard(I18n i18n) {
|
||||||
|
super(i18n, new Stri18ng("INVITATION_TITLE", i18n), WIDTH, HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display() {
|
||||||
|
showPanel("Intro");
|
||||||
|
super.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
123
ui/net/sf/briar/ui/invitation/InvitationWorkerPanel.java
Normal file
123
ui/net/sf/briar/ui/invitation/InvitationWorkerPanel.java
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package net.sf.briar.ui.invitation;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.api.invitation.InvitationCallback;
|
||||||
|
import net.sf.briar.api.invitation.InvitationParameters;
|
||||||
|
import net.sf.briar.api.invitation.InvitationWorkerFactory;
|
||||||
|
import net.sf.briar.ui.wizard.Wizard;
|
||||||
|
import net.sf.briar.ui.wizard.WorkerPanel;
|
||||||
|
import net.sf.briar.util.StringUtils;
|
||||||
|
|
||||||
|
class InvitationWorkerPanel extends WorkerPanel implements InvitationCallback {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3668512976295525240L;
|
||||||
|
|
||||||
|
private static final int MAX_LINE_LENGTH = 40;
|
||||||
|
|
||||||
|
private final InvitationWorkerFactory workerFactory;
|
||||||
|
private final InvitationParameters parameters;
|
||||||
|
private final Stri18ng copying, encrypting, created, giveToContact;
|
||||||
|
private final Stri18ng aborted, error, notFound, notDir, notAllowed;
|
||||||
|
|
||||||
|
InvitationWorkerPanel(Wizard wizard, InvitationWorkerFactory workerFactory,
|
||||||
|
InvitationParameters parameters, I18n i18n) {
|
||||||
|
super(wizard, "InvitationWorker",
|
||||||
|
new Stri18ng("INVITATION_PROGRESS_BEGIN", i18n),
|
||||||
|
new Stri18ng("CANCELLING", i18n));
|
||||||
|
this.workerFactory = workerFactory;
|
||||||
|
this.parameters = parameters;
|
||||||
|
copying = new Stri18ng("COPYING_FILE", i18n);
|
||||||
|
encrypting = new Stri18ng("ENCRYPTING_FILE", i18n);
|
||||||
|
created = new Stri18ng("INVITATION_CREATED", i18n);
|
||||||
|
giveToContact = new Stri18ng("INVITATION_GIVE_TO_CONTACT", i18n);
|
||||||
|
aborted = new Stri18ng("INVITATION_ABORTED", i18n);
|
||||||
|
error = new Stri18ng("INVITATION_ERROR", i18n);
|
||||||
|
notFound = new Stri18ng("DIRECTORY_NOT_FOUND", i18n);
|
||||||
|
notDir = new Stri18ng("FILE_NOT_DIRECTORY", i18n);
|
||||||
|
notAllowed = new Stri18ng("DIRECTORY_NOT_WRITABLE", i18n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
wizard.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelled() {
|
||||||
|
wizard.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finished() {
|
||||||
|
wizard.setFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Runnable getWorker() {
|
||||||
|
return workerFactory.createWorker(this, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancelled.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyingFile(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = copying.html(path);
|
||||||
|
displayProgress(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encryptingFile(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = encrypting.html(path);
|
||||||
|
displayProgress(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void created(List<File> files) {
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
for(File f : files) {
|
||||||
|
if(s.length() > 0) s.append("<br>");
|
||||||
|
s.append(StringUtils.tail(f.getPath(), MAX_LINE_LENGTH));
|
||||||
|
}
|
||||||
|
String filenames = s.toString();
|
||||||
|
String html = created.html(filenames, giveToContact.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void error(String message) {
|
||||||
|
String html = error.html(message, aborted.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notFound(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = notFound.html(path, aborted.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notDirectory(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = notDir.html(path, aborted.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notAllowed(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = notAllowed.html(path, aborted.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
ui/net/sf/briar/ui/invitation/LocationPanel.java
Normal file
20
ui/net/sf/briar/ui/invitation/LocationPanel.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package net.sf.briar.ui.invitation;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.DirectoryChooserPanel;
|
||||||
|
import net.sf.briar.ui.wizard.Wizard;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
class LocationPanel extends DirectoryChooserPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 3788640725729516888L;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
LocationPanel(Wizard wizard, I18n i18n) {
|
||||||
|
super(wizard, "Location", "Password", "InvitationWorker",
|
||||||
|
new Stri18ng("INVITATION_LOCATION_TITLE", i18n),
|
||||||
|
new Stri18ng("INVITATION_LOCATION_TEXT", i18n), i18n);
|
||||||
|
}
|
||||||
|
}
|
||||||
105
ui/net/sf/briar/ui/invitation/OperatingSystemPanel.java
Normal file
105
ui/net/sf/briar/ui/invitation/OperatingSystemPanel.java
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package net.sf.briar.ui.invitation;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.GridLayout;
|
||||||
|
|
||||||
|
import javax.swing.ButtonGroup;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JRadioButton;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.Wizard;
|
||||||
|
import net.sf.briar.ui.wizard.WizardPanel;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
class OperatingSystemPanel extends WizardPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8370132633634629466L;
|
||||||
|
|
||||||
|
private final Stri18ng question, windows, mac, linux, unknown;
|
||||||
|
private final JLabel questionLabel;
|
||||||
|
private final JRadioButton windowsButton, macButton, linuxButton;
|
||||||
|
private final JRadioButton unknownButton;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
OperatingSystemPanel(Wizard wizard, I18n i18n) {
|
||||||
|
super(wizard, "OperatingSystem");
|
||||||
|
question = new Stri18ng("INVITATION_OPERATING_SYSTEM", i18n);
|
||||||
|
windows = new Stri18ng("WINDOWS", i18n);
|
||||||
|
mac = new Stri18ng("MAC", i18n);
|
||||||
|
linux = new Stri18ng("LINUX", i18n);
|
||||||
|
unknown = new Stri18ng("UNKNOWN", i18n);
|
||||||
|
questionLabel = new JLabel(question.html());
|
||||||
|
Dimension d = wizard.getPreferredSize();
|
||||||
|
questionLabel.setPreferredSize(new Dimension(d.width - 50, 50));
|
||||||
|
questionLabel.setVerticalAlignment(SwingConstants.TOP);
|
||||||
|
add(questionLabel);
|
||||||
|
windowsButton = new JRadioButton(windows.tr());
|
||||||
|
macButton = new JRadioButton(mac.tr());
|
||||||
|
linuxButton = new JRadioButton(linux.tr());
|
||||||
|
unknownButton = new JRadioButton(unknown.tr());
|
||||||
|
ButtonGroup group = new ButtonGroup();
|
||||||
|
group.add(windowsButton);
|
||||||
|
group.add(macButton);
|
||||||
|
group.add(linuxButton);
|
||||||
|
group.add(unknownButton);
|
||||||
|
unknownButton.setSelected(true);
|
||||||
|
JPanel buttonPanel = new JPanel(new GridLayout(4, 1));
|
||||||
|
buttonPanel.add(windowsButton);
|
||||||
|
buttonPanel.add(macButton);
|
||||||
|
buttonPanel.add(linuxButton);
|
||||||
|
buttonPanel.add(unknownButton);
|
||||||
|
add(buttonPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void localeChanged(Font uiFont) {
|
||||||
|
questionLabel.setText(question.html());
|
||||||
|
questionLabel.setFont(uiFont);
|
||||||
|
windowsButton.setText(windows.tr());
|
||||||
|
windowsButton.setFont(uiFont);
|
||||||
|
macButton.setText(mac.tr());
|
||||||
|
macButton.setFont(uiFont);
|
||||||
|
linuxButton.setText(linux.tr());
|
||||||
|
linuxButton.setFont(uiFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void display() {
|
||||||
|
wizard.setBackButtonEnabled(true);
|
||||||
|
wizard.setNextButtonEnabled(true);
|
||||||
|
wizard.setFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
wizard.showPanel("ExistingUser");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
wizard.showPanel("Password");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cancelButtonPressed() {
|
||||||
|
wizard.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldCreateExe() {
|
||||||
|
return windowsButton.isSelected() || unknownButton.isSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldCreateJar() {
|
||||||
|
return !windowsButton.isSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
135
ui/net/sf/briar/ui/invitation/PasswordPanel.java
Normal file
135
ui/net/sf/briar/ui/invitation/PasswordPanel.java
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
package net.sf.briar.ui.invitation;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.event.KeyAdapter;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPasswordField;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.Wizard;
|
||||||
|
import net.sf.briar.ui.wizard.WizardPanel;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
public class PasswordPanel extends WizardPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -1012132977732308293L;
|
||||||
|
|
||||||
|
private final ExistingUserPanel existingUserPanel;
|
||||||
|
private final Stri18ng intro, enterPassword, confirmPassword;
|
||||||
|
private final JLabel introLabel, enterPasswordLabel, confirmPasswordLabel;
|
||||||
|
private final JPasswordField password1, password2;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
PasswordPanel(Wizard wizard, ExistingUserPanel existingUserPanel,
|
||||||
|
I18n i18n) {
|
||||||
|
super(wizard, "Password");
|
||||||
|
this.existingUserPanel = existingUserPanel;
|
||||||
|
intro = new Stri18ng("INVITATION_PASSWORD", i18n);
|
||||||
|
enterPassword = new Stri18ng("ENTER_PASSWORD", i18n);
|
||||||
|
confirmPassword = new Stri18ng("CONFIRM_PASSWORD", i18n);
|
||||||
|
introLabel = new JLabel(intro.html());
|
||||||
|
Dimension d = wizard.getPreferredSize();
|
||||||
|
introLabel.setPreferredSize(
|
||||||
|
new Dimension(d.width - 50, d.height - 140));
|
||||||
|
introLabel.setVerticalAlignment(SwingConstants.TOP);
|
||||||
|
add(introLabel);
|
||||||
|
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEADING));
|
||||||
|
enterPasswordLabel = new JLabel(enterPassword.tr());
|
||||||
|
enterPasswordLabel.setPreferredSize(
|
||||||
|
new Dimension((d.width - 60) / 2, 20));
|
||||||
|
password1 = new JPasswordField();
|
||||||
|
password1.addKeyListener(new KeyAdapter() {
|
||||||
|
@Override
|
||||||
|
public void keyReleased(KeyEvent e) {
|
||||||
|
checkPasswords();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
password1.setPreferredSize(new Dimension((d.width - 60) / 2, 20));
|
||||||
|
panel1.add(enterPasswordLabel);
|
||||||
|
panel1.add(password1);
|
||||||
|
add(panel1);
|
||||||
|
JPanel panel2 = new JPanel(new FlowLayout(FlowLayout.LEADING));
|
||||||
|
confirmPasswordLabel = new JLabel(confirmPassword.tr());
|
||||||
|
confirmPasswordLabel.setPreferredSize(
|
||||||
|
new Dimension((d.width - 60) / 2, 20));
|
||||||
|
password2 = new JPasswordField();
|
||||||
|
password2.addKeyListener(new KeyAdapter() {
|
||||||
|
@Override
|
||||||
|
public void keyReleased(KeyEvent e) {
|
||||||
|
checkPasswords();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
password2.setPreferredSize(new Dimension((d.width - 60) / 2, 20));
|
||||||
|
panel2.add(confirmPasswordLabel);
|
||||||
|
panel2.add(password2);
|
||||||
|
add(panel2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void localeChanged(Font uiFont) {
|
||||||
|
introLabel.setText(intro.html());
|
||||||
|
introLabel.setFont(uiFont);
|
||||||
|
enterPasswordLabel.setText(enterPassword.tr());
|
||||||
|
enterPasswordLabel.setFont(uiFont);
|
||||||
|
confirmPasswordLabel.setText(confirmPassword.tr());
|
||||||
|
confirmPasswordLabel.setFont(uiFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPasswords() {
|
||||||
|
wizard.setNextButtonEnabled(passwordsMatch());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean passwordsMatch() {
|
||||||
|
char[] p1 = password1.getPassword();
|
||||||
|
char[] p2 = password2.getPassword();
|
||||||
|
assert p1 != null && p2 != null;
|
||||||
|
boolean ok = p1.length > 3 && p2.length > 3 && Arrays.equals(p1, p2);
|
||||||
|
Arrays.fill(p1, (char) 0);
|
||||||
|
Arrays.fill(p2, (char) 0);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void display() {
|
||||||
|
wizard.setBackButtonEnabled(true);
|
||||||
|
wizard.setNextButtonEnabled(false);
|
||||||
|
wizard.setFinished(false);
|
||||||
|
password1.setText("");
|
||||||
|
password2.setText("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
if(existingUserPanel.shouldCreateInstaller())
|
||||||
|
wizard.showPanel("OperatingSystem");
|
||||||
|
else wizard.showPanel("ExistingUser");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
wizard.showPanel("Location");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cancelButtonPressed() {
|
||||||
|
wizard.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] getPassword() {
|
||||||
|
if(passwordsMatch()) return password1.getPassword();
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
ui/net/sf/briar/ui/invitation/UiInvitationModule.java
Normal file
32
ui/net/sf/briar/ui/invitation/UiInvitationModule.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package net.sf.briar.ui.invitation;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.FontManager;
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.invitation.InvitationParameters;
|
||||||
|
import net.sf.briar.api.invitation.InvitationWorkerFactory;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
public class UiInvitationModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {}
|
||||||
|
|
||||||
|
@Provides @Singleton
|
||||||
|
InvitationWizard getInvitationWizard(I18n i18n, FontManager fontManager,
|
||||||
|
InvitationWorkerFactory workerFactory) {
|
||||||
|
InvitationWizard wizard = new InvitationWizard(i18n);
|
||||||
|
new IntroPanel(wizard, i18n);
|
||||||
|
ExistingUserPanel userPanel = new ExistingUserPanel(wizard, i18n);
|
||||||
|
OperatingSystemPanel osPanel = new OperatingSystemPanel(wizard, i18n);
|
||||||
|
PasswordPanel passwordPanel =
|
||||||
|
new PasswordPanel(wizard, userPanel, i18n);
|
||||||
|
LocationPanel locationPanel = new LocationPanel(wizard, i18n);
|
||||||
|
InvitationParameters parameters = new InvitationParametersImpl(
|
||||||
|
userPanel, osPanel, passwordPanel, locationPanel, fontManager);
|
||||||
|
new InvitationWorkerPanel(wizard, workerFactory, parameters, i18n);
|
||||||
|
return wizard;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
ui/net/sf/briar/ui/setup/AlreadyInstalledPanel.java
Normal file
95
ui/net/sf/briar/ui/setup/AlreadyInstalledPanel.java
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package net.sf.briar.ui.setup;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.GridLayout;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
import javax.swing.ButtonGroup;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JRadioButton;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.WizardPanel;
|
||||||
|
|
||||||
|
class AlreadyInstalledPanel extends WizardPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 7908954905165031678L;
|
||||||
|
|
||||||
|
private final Stri18ng question, yes, no;
|
||||||
|
private final JLabel label;
|
||||||
|
private final JRadioButton yesButton, noButton;
|
||||||
|
|
||||||
|
AlreadyInstalledPanel(SetupWizard wizard, I18n i18n) {
|
||||||
|
super(wizard, "AlreadyInstalled");
|
||||||
|
question = new Stri18ng("SETUP_ALREADY_INSTALLED", i18n);
|
||||||
|
yes = new Stri18ng("YES", i18n);
|
||||||
|
no = new Stri18ng("NO", i18n);
|
||||||
|
label = new JLabel(question.html());
|
||||||
|
Dimension d = wizard.getPreferredSize();
|
||||||
|
label.setPreferredSize(new Dimension(d.width - 50, 50));
|
||||||
|
label.setVerticalAlignment(SwingConstants.TOP);
|
||||||
|
add(label);
|
||||||
|
yesButton = new JRadioButton(yes.tr());
|
||||||
|
yesButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
AlreadyInstalledPanel.this.wizard.setNextButtonEnabled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
noButton = new JRadioButton(no.tr());
|
||||||
|
noButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
AlreadyInstalledPanel.this.wizard.setNextButtonEnabled(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ButtonGroup group = new ButtonGroup();
|
||||||
|
group.add(yesButton);
|
||||||
|
group.add(noButton);
|
||||||
|
JPanel buttonPanel = new JPanel(new GridLayout(2, 1));
|
||||||
|
buttonPanel.add(yesButton);
|
||||||
|
buttonPanel.add(noButton);
|
||||||
|
add(buttonPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void localeChanged(Font uiFont) {
|
||||||
|
label.setText(question.html());
|
||||||
|
label.setFont(uiFont);
|
||||||
|
yesButton.setText(yes.tr());
|
||||||
|
yesButton.setFont(uiFont);
|
||||||
|
noButton.setText(no.tr());
|
||||||
|
noButton.setFont(uiFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void display() {
|
||||||
|
wizard.setBackButtonEnabled(true);
|
||||||
|
wizard.setNextButtonEnabled(yesButton.isSelected() || noButton.isSelected());
|
||||||
|
wizard.setFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
wizard.showPanel("Language");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
if(yesButton.isSelected()) wizard.showPanel("Instructions");
|
||||||
|
else if(noButton.isSelected()) wizard.showPanel("Location");
|
||||||
|
else assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cancelButtonPressed() {
|
||||||
|
wizard.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
ui/net/sf/briar/ui/setup/InstructionsPanel.java
Normal file
41
ui/net/sf/briar/ui/setup/InstructionsPanel.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package net.sf.briar.ui.setup;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.TextPanel;
|
||||||
|
|
||||||
|
class InstructionsPanel extends TextPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8730283083962607067L;
|
||||||
|
|
||||||
|
InstructionsPanel(SetupWizard wizard, I18n i18n) {
|
||||||
|
super(wizard, "Instructions", new Stri18ng("SETUP_INSTRUCTIONS", i18n));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void display() {
|
||||||
|
wizard.setBackButtonEnabled(true);
|
||||||
|
wizard.setNextButtonEnabled(false);
|
||||||
|
wizard.setFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
wizard.showPanel("AlreadyInstalled");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cancelButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
140
ui/net/sf/briar/ui/setup/LanguagePanel.java
Normal file
140
ui/net/sf/briar/ui/setup/LanguagePanel.java
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
package net.sf.briar.ui.setup;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import javax.swing.JComboBox;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JList;
|
||||||
|
import javax.swing.ListCellRenderer;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.FontManager;
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.WizardPanel;
|
||||||
|
|
||||||
|
class LanguagePanel extends WizardPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 6692353522360807409L;
|
||||||
|
|
||||||
|
// FIXME: Does this have to be hardcoded?
|
||||||
|
// Not static because we want the fonts to be loaded first
|
||||||
|
private final Language english = new Language("English", "en");
|
||||||
|
private final Language[] languages = new Language[] {
|
||||||
|
new Language("\u0627\u0644\u0639\u0631\u0628\u064a\u0629", "ar"),
|
||||||
|
new Language("\u0f60\u0f51\u0f72\u0f60\u0f72\u0f0b\u0f66\u0f90\u0f7c\u0f62\u0f0d", "bo"),
|
||||||
|
new Language("\u4e2d\u6587\uff08\u7b80\u4f53\uff09", "cn"),
|
||||||
|
english,
|
||||||
|
new Language("\u0641\u0627\u0631\u0633\u06cc", "fa"),
|
||||||
|
new Language("\u05e2\u05d1\u05e8\u05d9\u05ea", "he"),
|
||||||
|
new Language("\u65e5\u672c\u8a9e", "ja"),
|
||||||
|
new Language("\ud55c\uad6d\uc5b4", "ko"),
|
||||||
|
new Language("\u1006\u102f\u102d\u1010\u1032\u1037", "my"),
|
||||||
|
new Language("\u0420\u0443\u0441\u0441\u043a\u0438\u0439", "ru"),
|
||||||
|
new Language("Igpay Atinlay", "pg"),
|
||||||
|
new Language("\u0e44\u0e17\u0e22", "th"),
|
||||||
|
new Language("Ti\u1ebfng Vi\u1ec7t", "vi"),
|
||||||
|
};
|
||||||
|
|
||||||
|
private final FontManager fontManager;
|
||||||
|
private final Stri18ng language;
|
||||||
|
private final JLabel label;
|
||||||
|
private final JComboBox comboBox;
|
||||||
|
|
||||||
|
LanguagePanel(SetupWizard wizard, FontManager fontManager,
|
||||||
|
final I18n i18n) {
|
||||||
|
super(wizard, "Language");
|
||||||
|
this.fontManager = fontManager;
|
||||||
|
language = new Stri18ng("SETUP_LANGUAGE", i18n);
|
||||||
|
label = new JLabel(language.html());
|
||||||
|
Dimension d = wizard.getPreferredSize();
|
||||||
|
label.setPreferredSize(new Dimension(d.width - 50, d.height - 120));
|
||||||
|
label.setVerticalAlignment(SwingConstants.TOP);
|
||||||
|
add(label);
|
||||||
|
comboBox = new JComboBox();
|
||||||
|
for(Language l : languages) comboBox.addItem(l);
|
||||||
|
comboBox.setRenderer(new LanguageRenderer());
|
||||||
|
comboBox.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
Language l = (Language) comboBox.getSelectedItem();
|
||||||
|
i18n.setLocale(new Locale(l.code));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
add(comboBox);
|
||||||
|
comboBox.setSelectedItem(english);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void localeChanged(Font uiFont) {
|
||||||
|
label.setText(language.html());
|
||||||
|
label.setFont(uiFont);
|
||||||
|
comboBox.setFont(uiFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void display() {
|
||||||
|
wizard.setBackButtonEnabled(false);
|
||||||
|
wizard.setNextButtonEnabled(true);
|
||||||
|
wizard.setFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
wizard.showPanel("AlreadyInstalled");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cancelButtonPressed() {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Language {
|
||||||
|
|
||||||
|
private final String name, code;
|
||||||
|
|
||||||
|
Language(String name, String code) {
|
||||||
|
this.name = name;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LanguageRenderer extends JLabel implements ListCellRenderer {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 8562749521807769004L;
|
||||||
|
|
||||||
|
LanguageRenderer() {
|
||||||
|
setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
setVerticalAlignment(SwingConstants.CENTER);
|
||||||
|
setPreferredSize(new Dimension(100, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getListCellRendererComponent(JList list, Object value,
|
||||||
|
int index, boolean isSelected, boolean cellHasFocus) {
|
||||||
|
Language language = (Language) value;
|
||||||
|
setText(language.name);
|
||||||
|
setFont(fontManager.getFontForLanguage(language.code));
|
||||||
|
if(isSelected) {
|
||||||
|
setBackground(list.getSelectionBackground());
|
||||||
|
setForeground(list.getSelectionForeground());
|
||||||
|
} else {
|
||||||
|
setBackground(list.getBackground());
|
||||||
|
setForeground(list.getForeground());
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
ui/net/sf/briar/ui/setup/LocationPanel.java
Normal file
16
ui/net/sf/briar/ui/setup/LocationPanel.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package net.sf.briar.ui.setup;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.DirectoryChooserPanel;
|
||||||
|
|
||||||
|
public class LocationPanel extends DirectoryChooserPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -8831098591612528860L;
|
||||||
|
|
||||||
|
LocationPanel(SetupWizard wizard, I18n i18n) {
|
||||||
|
super(wizard, "Location", "AlreadyInstalled", "SetupWorker",
|
||||||
|
new Stri18ng("SETUP_LOCATION_TITLE", i18n),
|
||||||
|
new Stri18ng("SETUP_LOCATION_TEXT", i18n), i18n);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
ui/net/sf/briar/ui/setup/SetupParametersImpl.java
Normal file
25
ui/net/sf/briar/ui/setup/SetupParametersImpl.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package net.sf.briar.ui.setup;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.FontManager;
|
||||||
|
import net.sf.briar.api.setup.SetupParameters;
|
||||||
|
|
||||||
|
class SetupParametersImpl implements SetupParameters {
|
||||||
|
|
||||||
|
private final LocationPanel locationPanel;
|
||||||
|
private final FontManager fontManager;
|
||||||
|
|
||||||
|
SetupParametersImpl(LocationPanel locationPanel, FontManager fontManager) {
|
||||||
|
this.locationPanel = locationPanel;
|
||||||
|
this.fontManager = fontManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getChosenLocation() {
|
||||||
|
return locationPanel.getChosenDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getBundledFontFilenames() {
|
||||||
|
return fontManager.getBundledFontFilenames();
|
||||||
|
}
|
||||||
|
}
|
||||||
19
ui/net/sf/briar/ui/setup/SetupWizard.java
Normal file
19
ui/net/sf/briar/ui/setup/SetupWizard.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package net.sf.briar.ui.setup;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.ui.wizard.Wizard;
|
||||||
|
|
||||||
|
public class SetupWizard extends Wizard {
|
||||||
|
|
||||||
|
private static int WIDTH = 400, HEIGHT = 300;
|
||||||
|
|
||||||
|
SetupWizard(I18n i18n) {
|
||||||
|
super(i18n, new Stri18ng("SETUP_TITLE", i18n), WIDTH, HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display() {
|
||||||
|
showPanel("Language");
|
||||||
|
super.display();
|
||||||
|
}
|
||||||
|
}
|
||||||
116
ui/net/sf/briar/ui/setup/SetupWorkerPanel.java
Normal file
116
ui/net/sf/briar/ui/setup/SetupWorkerPanel.java
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package net.sf.briar.ui.setup;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
import net.sf.briar.api.setup.SetupCallback;
|
||||||
|
import net.sf.briar.api.setup.SetupParameters;
|
||||||
|
import net.sf.briar.api.setup.SetupWorkerFactory;
|
||||||
|
import net.sf.briar.ui.wizard.WorkerPanel;
|
||||||
|
import net.sf.briar.util.StringUtils;
|
||||||
|
|
||||||
|
class SetupWorkerPanel extends WorkerPanel implements SetupCallback {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 6596714579098160155L;
|
||||||
|
|
||||||
|
private static final int MAX_LINE_LENGTH = 40;
|
||||||
|
|
||||||
|
private final SetupWorkerFactory workerFactory;
|
||||||
|
private final SetupParameters parameters;
|
||||||
|
private final Stri18ng extracting, copying, installed, uninstall;
|
||||||
|
private final Stri18ng aborted, error, notFound, notDir, notAllowed;
|
||||||
|
|
||||||
|
SetupWorkerPanel(SetupWizard wizard, SetupWorkerFactory workerFactory,
|
||||||
|
SetupParameters parameters, I18n i18n) {
|
||||||
|
super(wizard, "SetupWorker",
|
||||||
|
new Stri18ng("SETUP_PROGRESS_BEGIN", i18n),
|
||||||
|
new Stri18ng("CANCELLING", i18n));
|
||||||
|
this.workerFactory = workerFactory;
|
||||||
|
this.parameters = parameters;
|
||||||
|
extracting = new Stri18ng("EXTRACTING_FILE", i18n);
|
||||||
|
copying = new Stri18ng("COPYING_FILE", i18n);
|
||||||
|
installed = new Stri18ng("SETUP_INSTALLED", i18n);
|
||||||
|
uninstall = new Stri18ng("SETUP_UNINSTALL", i18n);
|
||||||
|
aborted = new Stri18ng("SETUP_ABORTED", i18n);
|
||||||
|
error = new Stri18ng("SETUP_ERROR", i18n);
|
||||||
|
notFound = new Stri18ng("DIRECTORY_NOT_FOUND", i18n);
|
||||||
|
notDir = new Stri18ng("FILE_NOT_DIRECTORY", i18n);
|
||||||
|
notAllowed = new Stri18ng("DIRECTORY_NOT_WRITABLE", i18n);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelled() {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finished() {
|
||||||
|
wizard.setFinished(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Runnable getWorker() {
|
||||||
|
return workerFactory.createWorker(this, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancelled.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void extractingFile(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = extracting.html(path);
|
||||||
|
displayProgress(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyingFile(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = copying.html(path);
|
||||||
|
displayProgress(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void installed(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = installed.html(path, uninstall.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void error(String message) {
|
||||||
|
String html = error.html(message, aborted.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notFound(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = notFound.html(path, aborted.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notDirectory(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = notDir.html(path, aborted.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notAllowed(File f) {
|
||||||
|
String path = StringUtils.tail(f.getPath(), MAX_LINE_LENGTH);
|
||||||
|
String html = notAllowed.html(path, aborted.tr());
|
||||||
|
done(html);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
ui/net/sf/briar/ui/setup/UiSetupModule.java
Normal file
30
ui/net/sf/briar/ui/setup/UiSetupModule.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package net.sf.briar.ui.setup;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.FontManager;
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.setup.SetupParameters;
|
||||||
|
import net.sf.briar.api.setup.SetupWorkerFactory;
|
||||||
|
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
|
public class UiSetupModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {}
|
||||||
|
|
||||||
|
@Provides @Singleton
|
||||||
|
SetupWizard getSetupWizard(I18n i18n, FontManager fontManager,
|
||||||
|
SetupWorkerFactory workerFactory) {
|
||||||
|
SetupWizard wizard = new SetupWizard(i18n);
|
||||||
|
new LanguagePanel(wizard, fontManager, i18n);
|
||||||
|
new AlreadyInstalledPanel(wizard, i18n);
|
||||||
|
new InstructionsPanel(wizard, i18n);
|
||||||
|
LocationPanel locationPanel = new LocationPanel(wizard, i18n);
|
||||||
|
SetupParameters parameters =
|
||||||
|
new SetupParametersImpl(locationPanel, fontManager);
|
||||||
|
new SetupWorkerPanel(wizard, workerFactory, parameters, i18n);
|
||||||
|
return wizard;
|
||||||
|
}
|
||||||
|
}
|
||||||
73
ui/net/sf/briar/ui/wizard/DirectoryChooserPanel.java
Normal file
73
ui/net/sf/briar/ui/wizard/DirectoryChooserPanel.java
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package net.sf.briar.ui.wizard;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
|
||||||
|
public class DirectoryChooserPanel extends TextPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 6692353522360807409L;
|
||||||
|
|
||||||
|
private final String prevId, nextId;
|
||||||
|
private final Stri18ng title;
|
||||||
|
private final I18n i18n;
|
||||||
|
private volatile File chosenDirectory = null;
|
||||||
|
|
||||||
|
protected DirectoryChooserPanel(Wizard wizard, String id, String prevId,
|
||||||
|
String nextId, Stri18ng title, Stri18ng text, I18n i18n) {
|
||||||
|
super(wizard, id, text);
|
||||||
|
this.prevId = prevId;
|
||||||
|
this.nextId = nextId;
|
||||||
|
this.title = title;
|
||||||
|
this.i18n = i18n;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void display() {
|
||||||
|
wizard.setBackButtonEnabled(true);
|
||||||
|
wizard.setNextButtonEnabled(true);
|
||||||
|
wizard.setFinished(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void backButtonPressed() {
|
||||||
|
wizard.showPanel(prevId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void nextButtonPressed() {
|
||||||
|
JFileChooser chooser;
|
||||||
|
String home = System.getProperty("user.home");
|
||||||
|
if(home == null) chooser = new JFileChooser();
|
||||||
|
else chooser = new JFileChooser(home);
|
||||||
|
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||||
|
chooser.setDialogTitle(title.tr());
|
||||||
|
chooser.setComponentOrientation(i18n.getComponentOrientation());
|
||||||
|
int result = chooser.showSaveDialog(this);
|
||||||
|
if(result == JFileChooser.APPROVE_OPTION) {
|
||||||
|
File dir = chooser.getSelectedFile();
|
||||||
|
assert dir != null;
|
||||||
|
assert dir.exists();
|
||||||
|
assert dir.isDirectory();
|
||||||
|
chosenDirectory = dir;
|
||||||
|
wizard.showPanel(nextId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cancelButtonPressed() {
|
||||||
|
wizard.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finishButtonPressed() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getChosenDirectory() {
|
||||||
|
return chosenDirectory;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
ui/net/sf/briar/ui/wizard/TextPanel.java
Normal file
32
ui/net/sf/briar/ui/wizard/TextPanel.java
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package net.sf.briar.ui.wizard;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
|
||||||
|
public abstract class TextPanel extends WizardPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -3046102503813671049L;
|
||||||
|
|
||||||
|
private final Stri18ng text;
|
||||||
|
private final JLabel label;
|
||||||
|
|
||||||
|
protected TextPanel(Wizard wizard, String id, Stri18ng text) {
|
||||||
|
super(wizard, id);
|
||||||
|
this.text = text;
|
||||||
|
label = new JLabel(text.html());
|
||||||
|
Dimension d = wizard.getPreferredSize();
|
||||||
|
label.setPreferredSize(new Dimension(d.width - 50, d.height - 80));
|
||||||
|
label.setVerticalAlignment(SwingConstants.TOP);
|
||||||
|
add(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void localeChanged(Font uiFont) {
|
||||||
|
label.setText(text.html());
|
||||||
|
label.setFont(uiFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
179
ui/net/sf/briar/ui/wizard/Wizard.java
Normal file
179
ui/net/sf/briar/ui/wizard/Wizard.java
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
package net.sf.briar.ui.wizard;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.CardLayout;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.Insets;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.swing.Box;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
|
||||||
|
public class Wizard implements I18n.Listener {
|
||||||
|
|
||||||
|
private final I18n i18n;
|
||||||
|
private final Stri18ng title, back, next, cancel, finish;
|
||||||
|
private final Map<String, WizardPanel> panels;
|
||||||
|
private final JPanel cardPanel;
|
||||||
|
private final CardLayout cardLayout;
|
||||||
|
private final JButton backButton, nextButton, cancelButton;
|
||||||
|
private final JFrame frame;
|
||||||
|
private final Object finishedLock = new Object();
|
||||||
|
private WizardPanel currentPanel = null;
|
||||||
|
private volatile boolean finished = false;
|
||||||
|
|
||||||
|
public Wizard(I18n i18n, Stri18ng title, int width, int height) {
|
||||||
|
this.i18n = i18n;
|
||||||
|
this.title = title;
|
||||||
|
back = new Stri18ng("BACK", i18n);
|
||||||
|
next = new Stri18ng("NEXT", i18n);
|
||||||
|
cancel = new Stri18ng("CANCEL", i18n);
|
||||||
|
finish = new Stri18ng("FINISH", i18n);
|
||||||
|
panels = new HashMap<String, WizardPanel>();
|
||||||
|
cardPanel = new JPanel();
|
||||||
|
cardPanel.setBorder(new EmptyBorder(new Insets(5, 10, 5, 10)));
|
||||||
|
cardLayout = new CardLayout();
|
||||||
|
cardPanel.setLayout(cardLayout);
|
||||||
|
|
||||||
|
backButton = new JButton(back.tr());
|
||||||
|
backButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
backButtonPressed();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nextButton = new JButton(next.tr());
|
||||||
|
nextButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
nextButtonPressed();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cancelButton = new JButton(cancel.tr());
|
||||||
|
cancelButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
closeButtonPressed();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
JPanel buttonPanel = new JPanel();
|
||||||
|
buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING));
|
||||||
|
buttonPanel.setBorder(new EmptyBorder(new Insets(5, 10, 5, 10)));
|
||||||
|
buttonPanel.add(backButton);
|
||||||
|
buttonPanel.add(Box.createHorizontalStrut(10));
|
||||||
|
buttonPanel.add(nextButton);
|
||||||
|
buttonPanel.add(Box.createHorizontalStrut(30));
|
||||||
|
buttonPanel.add(cancelButton);
|
||||||
|
|
||||||
|
frame = new JFrame(title.tr());
|
||||||
|
frame.setPreferredSize(new Dimension(width, height));
|
||||||
|
frame.setResizable(false);
|
||||||
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
closeButtonPressed();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
frame.getContentPane().add(cardPanel, BorderLayout.CENTER);
|
||||||
|
frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void localeChanged(Font uiFont) {
|
||||||
|
backButton.setText(back.tr());
|
||||||
|
backButton.setFont(uiFont);
|
||||||
|
nextButton.setText(next.tr());
|
||||||
|
nextButton.setFont(uiFont);
|
||||||
|
synchronized(finishedLock) {
|
||||||
|
if(finished) cancelButton.setText(finish.tr());
|
||||||
|
else cancelButton.setText(cancel.tr());
|
||||||
|
}
|
||||||
|
cancelButton.setFont(uiFont);
|
||||||
|
frame.setTitle(title.tr());
|
||||||
|
for(WizardPanel panel : panels.values()) panel.localeChanged(uiFont);
|
||||||
|
frame.applyComponentOrientation(i18n.getComponentOrientation());
|
||||||
|
SwingUtilities.updateComponentTreeUI(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void display() {
|
||||||
|
assert currentPanel != null;
|
||||||
|
i18n.addListener(this);
|
||||||
|
frame.pack();
|
||||||
|
frame.setLocationRelativeTo(null); // Centre of the screen
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
i18n.removeListener(this);
|
||||||
|
frame.setVisible(false);
|
||||||
|
frame.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerPanel(String id, WizardPanel panel) {
|
||||||
|
assert currentPanel == null;
|
||||||
|
WizardPanel old = panels.put(id, panel);
|
||||||
|
assert old == null;
|
||||||
|
cardPanel.add(id, panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showPanel(String id) {
|
||||||
|
currentPanel = panels.get(id);
|
||||||
|
assert currentPanel != null;
|
||||||
|
cardLayout.show(cardPanel, id);
|
||||||
|
currentPanel.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackButtonEnabled(boolean enabled) {
|
||||||
|
backButton.setEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNextButtonEnabled(boolean enabled) {
|
||||||
|
nextButton.setEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFinished(boolean finished) {
|
||||||
|
synchronized(finishedLock) {
|
||||||
|
this.finished = finished;
|
||||||
|
if(finished) {
|
||||||
|
nextButton.setEnabled(false);
|
||||||
|
cancelButton.setText(finish.tr());
|
||||||
|
} else cancelButton.setText(cancel.tr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return frame.getPreferredSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void backButtonPressed() {
|
||||||
|
assert SwingUtilities.isEventDispatchThread();
|
||||||
|
assert currentPanel != null;
|
||||||
|
currentPanel.backButtonPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nextButtonPressed() {
|
||||||
|
assert SwingUtilities.isEventDispatchThread();
|
||||||
|
assert currentPanel != null;
|
||||||
|
currentPanel.nextButtonPressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeButtonPressed() {
|
||||||
|
assert SwingUtilities.isEventDispatchThread();
|
||||||
|
assert currentPanel != null;
|
||||||
|
cancelButton.setEnabled(false);
|
||||||
|
synchronized(finishedLock) {
|
||||||
|
if(finished) currentPanel.finishButtonPressed();
|
||||||
|
else currentPanel.cancelButtonPressed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
ui/net/sf/briar/ui/wizard/WizardPanel.java
Normal file
27
ui/net/sf/briar/ui/wizard/WizardPanel.java
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package net.sf.briar.ui.wizard;
|
||||||
|
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.I18n;
|
||||||
|
|
||||||
|
public abstract class WizardPanel extends JPanel implements I18n.Listener {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 8657047449339969485L;
|
||||||
|
|
||||||
|
protected final Wizard wizard;
|
||||||
|
|
||||||
|
protected WizardPanel(Wizard wizard, String id) {
|
||||||
|
this.wizard = wizard;
|
||||||
|
wizard.registerPanel(id, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void display();
|
||||||
|
|
||||||
|
protected abstract void backButtonPressed();
|
||||||
|
|
||||||
|
protected abstract void nextButtonPressed();
|
||||||
|
|
||||||
|
protected abstract void cancelButtonPressed();
|
||||||
|
|
||||||
|
protected abstract void finishButtonPressed();
|
||||||
|
}
|
||||||
90
ui/net/sf/briar/ui/wizard/WorkerPanel.java
Normal file
90
ui/net/sf/briar/ui/wizard/WorkerPanel.java
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package net.sf.briar.ui.wizard;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JProgressBar;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
|
import net.sf.briar.api.i18n.Stri18ng;
|
||||||
|
|
||||||
|
public abstract class WorkerPanel extends WizardPanel {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -3761407066345183330L;
|
||||||
|
|
||||||
|
private final Stri18ng starting, cancelling;
|
||||||
|
private final JLabel label;
|
||||||
|
private final JProgressBar progress;
|
||||||
|
private final AtomicBoolean started;
|
||||||
|
|
||||||
|
protected final AtomicBoolean cancelled;
|
||||||
|
|
||||||
|
protected WorkerPanel(Wizard wizard, String id, Stri18ng starting,
|
||||||
|
Stri18ng cancelling) {
|
||||||
|
super(wizard, id);
|
||||||
|
this.starting = starting;
|
||||||
|
this.cancelling = cancelling;
|
||||||
|
label = new JLabel(starting.html());
|
||||||
|
Dimension d = wizard.getPreferredSize();
|
||||||
|
label.setPreferredSize(new Dimension(d.width - 50, d.height - 120));
|
||||||
|
label.setVerticalAlignment(SwingConstants.TOP);
|
||||||
|
add(label);
|
||||||
|
progress = new JProgressBar();
|
||||||
|
progress.setIndeterminate(true);
|
||||||
|
progress.setPreferredSize(new Dimension(d.width - 50, 20));
|
||||||
|
add(progress);
|
||||||
|
started = new AtomicBoolean(false);
|
||||||
|
cancelled = new AtomicBoolean(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void localeChanged(Font uiFont) {
|
||||||
|
label.setText(starting.html());
|
||||||
|
label.setFont(uiFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void cancelled();
|
||||||
|
|
||||||
|
public abstract void finished();
|
||||||
|
|
||||||
|
protected abstract Runnable getWorker();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void display() {
|
||||||
|
if(!started.getAndSet(true)) {
|
||||||
|
wizard.setBackButtonEnabled(false);
|
||||||
|
wizard.setNextButtonEnabled(false);
|
||||||
|
wizard.setFinished(false);
|
||||||
|
new Thread(getWorker()).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cancelButtonPressed() {
|
||||||
|
if(!cancelled.getAndSet(true)) {
|
||||||
|
wizard.setBackButtonEnabled(false);
|
||||||
|
wizard.setNextButtonEnabled(false);
|
||||||
|
label.setText(cancelling.html());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void displayProgress(final String message) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
label.setText("<html>" + message + "</html>");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void done(final String message) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
progress.setVisible(false);
|
||||||
|
label.setText("<html>" + message + "</html>");
|
||||||
|
finished();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
98
unzip60.patch
Normal file
98
unzip60.patch
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
diff -Bbur unzip60/process.c unzip60-briar/process.c
|
||||||
|
--- unzip60/process.c 2009-03-06 01:25:10.000000000 +0000
|
||||||
|
+++ unzip60-briar/process.c 2011-04-18 16:03:46.000000000 +0100
|
||||||
|
@@ -370,15 +370,8 @@
|
||||||
|
G.zipfn));
|
||||||
|
}
|
||||||
|
#ifdef CHEAP_SFX_AUTORUN
|
||||||
|
- if (G.autorun_command[0] && !uO.qflag) { /* NO autorun without prompt! */
|
||||||
|
- Info(slide, 0x81, ((char *)slide, LoadFarString(AutorunPrompt),
|
||||||
|
- FnFilter1(G.autorun_command)));
|
||||||
|
- if (fgets(G.answerbuf, 9, stdin) != (char *)NULL
|
||||||
|
- && toupper(*G.answerbuf) == 'Y')
|
||||||
|
+ /* MJR 2011-04-18: Allow autorun without prompt. */
|
||||||
|
system(G.autorun_command);
|
||||||
|
- else
|
||||||
|
- Info(slide, 1, ((char *)slide, LoadFarString(NotAutoRunning)));
|
||||||
|
- }
|
||||||
|
#endif /* CHEAP_SFX_AUTORUN */
|
||||||
|
|
||||||
|
#else /* !SFX */
|
||||||
|
diff -Bbur unzip60/unzip.c unzip60-briar/unzip.c
|
||||||
|
--- unzip60/unzip.c 2009-04-16 19:26:52.000000000 +0100
|
||||||
|
+++ unzip60-briar/unzip.c 2011-06-18 11:23:26.000000000 +0100
|
||||||
|
@@ -358,7 +358,8 @@
|
||||||
|
# else
|
||||||
|
static ZCONST char Far UnzipSFXBanner[] =
|
||||||
|
# endif
|
||||||
|
- "UnZipSFX %d.%d%d%s of %s, by Info-ZIP (http://www.info-zip.org).\n";
|
||||||
|
+ /* MJR 2011-04-18: Modified banner as required by license. */
|
||||||
|
+ "This self-extractor is based on UnZipSFX by Info-ZIP.\nThis is NOT an official release and it is NOT supported by Info-ZIP.\n";
|
||||||
|
# ifdef SFX_EXDIR
|
||||||
|
static ZCONST char Far UnzipSFXOpts[] =
|
||||||
|
"Valid options are -tfupcz and -d <exdir>; modifiers are -abjnoqCL%sV%s.\n";
|
||||||
|
@@ -1236,6 +1237,11 @@
|
||||||
|
Info(slide, 0x401, ((char *)slide, LoadFarString(NotExtracting)));
|
||||||
|
#endif /* ?(SFX && !SFX_EXDIR) */
|
||||||
|
|
||||||
|
+#ifdef SFX
|
||||||
|
+ /* MJR 2011-06-18: Self-extract to this directory. This is a hack. */
|
||||||
|
+ uO.exdir = "briar.tmp";
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#ifdef UNICODE_SUPPORT
|
||||||
|
/* set Unicode-escape-all if option -U used */
|
||||||
|
if (uO.U_flag == 1)
|
||||||
|
@@ -1903,10 +1909,9 @@
|
||||||
|
|
||||||
|
#ifdef SFX
|
||||||
|
/* print our banner unless we're being fairly quiet */
|
||||||
|
+ /* MJR 2011-04-18: Removed unused arguments from modified banner. */
|
||||||
|
if (uO.qflag < 2)
|
||||||
|
- Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner),
|
||||||
|
- UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
|
||||||
|
- LoadFarStringSmall(VersionDate)));
|
||||||
|
+ Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner)));
|
||||||
|
#ifdef BETA
|
||||||
|
/* always print the beta warning: no unauthorized distribution!! */
|
||||||
|
Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(BetaVersion), "\n",
|
||||||
|
@@ -1925,6 +1930,12 @@
|
||||||
|
|
||||||
|
*pargc = argc;
|
||||||
|
*pargv = argv;
|
||||||
|
+
|
||||||
|
+#ifdef SFX
|
||||||
|
+ /* MJR 2011-04-18: SFX should always overwrite without prompting */
|
||||||
|
+ uO.overwrite_all = 2;
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
return PK_OK;
|
||||||
|
|
||||||
|
} /* end function uz_opts() */
|
||||||
|
@@ -1976,9 +1987,8 @@
|
||||||
|
__GDEF
|
||||||
|
int error;
|
||||||
|
{
|
||||||
|
- Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner),
|
||||||
|
- UZ_MAJORVER, UZ_MINORVER, UZ_PATCHLEVEL, UZ_BETALEVEL,
|
||||||
|
- LoadFarStringSmall(VersionDate)));
|
||||||
|
+ /* MJR 2011-04-18: Removed unused arguments from modified banner. */
|
||||||
|
+ Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXBanner)));
|
||||||
|
Info(slide, error? 1 : 0, ((char *)slide, LoadFarString(UnzipSFXOpts),
|
||||||
|
SFXOPT1, LOCAL));
|
||||||
|
#ifdef BETA
|
||||||
|
diff -Bbur unzip60/win32/Makefile.gcc unzip60-briar/win32/Makefile.gcc
|
||||||
|
--- unzip60/win32/Makefile.gcc 2008-08-09 17:03:30.000000000 +0100
|
||||||
|
+++ unzip60-briar/win32/Makefile.gcc 2011-06-18 11:18:38.000000000 +0100
|
||||||
|
@@ -262,8 +262,10 @@
|
||||||
|
unzip$(EXE): $(OBJU) $(LIBBZIP2)
|
||||||
|
$(LD) $(LDFLAGS) $(LDVER) $(OBJU) $(LD_BZ2LIB) $(LDLIBS)
|
||||||
|
|
||||||
|
+# MJR 2011-06-18: Added -mwindows flag to suppress terminal window.
|
||||||
|
+
|
||||||
|
unzipsfx$(EXE): $(OBJX) $(LIBBZIP2X)
|
||||||
|
- $(LD) $(LDFLAGS) $(LDVER) $(OBJX) $(LDLIBS)
|
||||||
|
+ $(LD) $(LDFLAGS) $(LDVER) $(OBJX) $(LDLIBS) -mwindows
|
||||||
|
|
||||||
|
funzip$(EXE): $(OBJF)
|
||||||
|
$(LD) $(LDFLAGS) $(LDVER) $(OBJF) $(LDLIBS)
|
||||||
1
util/.gitignore
vendored
Normal file
1
util/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
3
util/build.xml
Normal file
3
util/build.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<project name='util' default='compile'>
|
||||||
|
<import file='../build-common.xml'/>
|
||||||
|
</project>
|
||||||
90
util/net/sf/briar/util/FileUtils.java
Normal file
90
util/net/sf/briar/util/FileUtils.java
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package net.sf.briar.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.CodeSource;
|
||||||
|
|
||||||
|
public class FileUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the directory where Briar is installed.
|
||||||
|
*/
|
||||||
|
public static File getBriarDirectory() {
|
||||||
|
CodeSource c = FileUtils.class.getProtectionDomain().getCodeSource();
|
||||||
|
File f = new File(c.getLocation().getPath());
|
||||||
|
assert f.exists();
|
||||||
|
if(f.isFile()) {
|
||||||
|
// Running from a jar - return the jar's grandparent
|
||||||
|
try {
|
||||||
|
f = f.getCanonicalFile().getParentFile().getParentFile();
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Running from Eclipse
|
||||||
|
try {
|
||||||
|
f = new File(f.getCanonicalFile().getParentFile(), "Briar");
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
f.mkdir();
|
||||||
|
}
|
||||||
|
assert f.exists();
|
||||||
|
assert f.isDirectory();
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a temporary file.
|
||||||
|
*/
|
||||||
|
public static File createTempFile() throws IOException {
|
||||||
|
String rand = String.valueOf(1000 + (int) (Math.random() * 9000));
|
||||||
|
return File.createTempFile(rand, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the contents of the source file to the destination file.
|
||||||
|
*/
|
||||||
|
public static void copy(File src, File dest) throws IOException {
|
||||||
|
FileInputStream in = new FileInputStream(src);
|
||||||
|
copy(in, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the contents of the input stream to the destination file.
|
||||||
|
*/
|
||||||
|
public static void copy(InputStream in, File dest) throws IOException {
|
||||||
|
FileOutputStream out = new FileOutputStream(dest);
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int i;
|
||||||
|
while((i = in.read(buf, 0, buf.length)) != -1) out.write(buf, 0, i);
|
||||||
|
in.close();
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the source file or directory to the destination directory.
|
||||||
|
*/
|
||||||
|
public static void copyRecursively(File src, File dest, Callback callback)
|
||||||
|
throws IOException {
|
||||||
|
assert dest.exists();
|
||||||
|
assert dest.isDirectory();
|
||||||
|
dest = new File(dest, src.getName());
|
||||||
|
if(src.isDirectory()) {
|
||||||
|
dest.mkdir();
|
||||||
|
for(File f : src.listFiles()) copyRecursively(f, dest, callback);
|
||||||
|
} else {
|
||||||
|
if(callback != null) callback.processingFile(dest);
|
||||||
|
copy(src, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Callback {
|
||||||
|
|
||||||
|
void processingFile(File f);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
util/net/sf/briar/util/OsUtils.java
Normal file
18
util/net/sf/briar/util/OsUtils.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package net.sf.briar.util;
|
||||||
|
|
||||||
|
public class OsUtils {
|
||||||
|
|
||||||
|
private static final String os = System.getProperty("os.name");
|
||||||
|
|
||||||
|
public static boolean isWindows() {
|
||||||
|
return os.indexOf("Windows") != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMac() {
|
||||||
|
return os.indexOf("Mac OS") != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isLinux() {
|
||||||
|
return os.indexOf("Linux") != -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
util/net/sf/briar/util/StringUtils.java
Normal file
14
util/net/sf/briar/util/StringUtils.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package net.sf.briar.util;
|
||||||
|
|
||||||
|
public class StringUtils {
|
||||||
|
|
||||||
|
public static String head(String s, int length) {
|
||||||
|
if(s.length() > length) return s.substring(0, length) + "...";
|
||||||
|
else return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String tail(String s, int length) {
|
||||||
|
if(s.length() > length) return "..." + s.substring(s.length() - length);
|
||||||
|
else return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
78
util/net/sf/briar/util/ZipUtils.java
Normal file
78
util/net/sf/briar/util/ZipUtils.java
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package net.sf.briar.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipInputStream;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
public class ZipUtils {
|
||||||
|
|
||||||
|
public static void copyToZip(String path, File file, ZipOutputStream zip)
|
||||||
|
throws IOException {
|
||||||
|
assert file.isFile() : file.getAbsolutePath();
|
||||||
|
zip.putNextEntry(new ZipEntry(path));
|
||||||
|
FileInputStream in = new FileInputStream(file);
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int i;
|
||||||
|
while((i = in.read(buf, 0, buf.length)) != -1) zip.write(buf, 0, i);
|
||||||
|
in.close();
|
||||||
|
zip.closeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void copyToZipRecursively(String path, File dir,
|
||||||
|
ZipOutputStream zip, Callback callback) throws IOException {
|
||||||
|
assert dir.isDirectory();
|
||||||
|
for(File child : dir.listFiles()) {
|
||||||
|
String childPath = extendPath(path, child.getName());
|
||||||
|
if(child.isDirectory()) {
|
||||||
|
copyToZipRecursively(childPath, child, zip, callback);
|
||||||
|
} else {
|
||||||
|
if(callback != null) callback.processingFile(child);
|
||||||
|
copyToZip(childPath, child, zip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String extendPath(String path, String name) {
|
||||||
|
if(path == null || path.equals("")) return name;
|
||||||
|
else return path + "/" + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unzipStream(InputStream in, File dir, String regex,
|
||||||
|
Callback callback) throws IOException {
|
||||||
|
String path = dir.getCanonicalPath();
|
||||||
|
ZipInputStream zip = new ZipInputStream(in);
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
ZipEntry entry;
|
||||||
|
while((entry = zip.getNextEntry()) != null) {
|
||||||
|
String name = entry.getName();
|
||||||
|
if(name.matches(regex)) {
|
||||||
|
File file = new File(path + "/" + name);
|
||||||
|
if(callback != null) callback.processingFile(file);
|
||||||
|
if(entry.isDirectory()) {
|
||||||
|
file.mkdirs();
|
||||||
|
} else {
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
FileOutputStream out = new FileOutputStream(file);
|
||||||
|
int i;
|
||||||
|
while((i = zip.read(buf, 0, buf.length)) > 0) {
|
||||||
|
out.write(buf, 0, i);
|
||||||
|
}
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zip.closeEntry();
|
||||||
|
}
|
||||||
|
zip.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Callback {
|
||||||
|
|
||||||
|
void processingFile(File f);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user